针对2616网桥工作流程.docx
- 文档编号:25791900
- 上传时间:2023-06-14
- 格式:DOCX
- 页数:14
- 大小:18.39KB
针对2616网桥工作流程.docx
《针对2616网桥工作流程.docx》由会员分享,可在线阅读,更多相关《针对2616网桥工作流程.docx(14页珍藏版)》请在冰豆网上搜索。
针对2616网桥工作流程
针对2.6.16(网桥工作流程)
参考了独孤九贱大侠的文章,针对2.6.16代码。
零.STP的几个状态:
.Block:
阻断状态,接收但不转发数据。
.Listening:
侦听状态,不转发数据,可以收发BPDU,执行选举rootbridge,rootport,designateport等动作。
.Learning:
学习状态,不转发数据,开始学习MAC,为数据转发作准备,所以称之为Learning状态
.Forward:
转发状态,转发数据。
.Disable:
禁用状态,既不参与STP计算,也不转发数据。
一.首先是Bridge注册过程:
staticint__initbr_init(void)
{
br_fdb_init();
#ifdefCONFIG_BRIDGE_NETFILTER
if(br_netfilter_init())
return1;
#endif
brioctl_set(br_ioctl_deviceless_stub);
/*数据包的处理函数注册为br_handle_frame*/
br_handle_frame_hook=br_handle_frame;
br_fdb_get_hook=br_fdb_get;
br_fdb_put_hook=br_fdb_put;
register_netdevice_notifier(&br_device_notifier);
return0;
}
二.网桥处理函数
intbr_handle_frame(structnet_bridge_port*p,structsk_buff**pskb)
{
structsk_buff*skb=*pskb;
constunsignedchar*dest=eth_hdr(skb)->h_dest;
if(p->state==BR_STATE_DISABLED)
gotoerr;
if(!
is_valid_ether_addr(eth_hdr(skb)->h_source))
gotoerr;
/*
网桥打开了STP功能,
是否为网桥组播地址,PS:
bridge_ula定义为{0x01,0x80,0xc2,0x00,0x00,0x00},只比较前5个字段,
为什么第5个字段要和0XF0比较,就不知道了(01-80-c2-00-00-F0?
?
?
)
*/
if(p->br->stp_enabled&&
!
memcmp(dest,bridge_ula,5)&&
!
(dest[5]&0xF0)){
if(!
dest[5]){
/*涉及到STP功能的数据包都交给函数br_stp_handle_bpdu来处理*/
NF_HOOK(PF_BRIDGE,NF_BR_LOCAL_IN,skb,skb->dev,
NULL,br_stp_handle_bpdu);
return1;
}
gotoerr;
}
/*如果端口处于Learning或Forwarding状态时,要记录从端口通过的数据包的源MAC地址,以updateCAM表*/
if(p->state==BR_STATE_FORWARDING||p->state==BR_STATE_LEARNING){
if(br_should_route_hook){
if(br_should_route_hook(pskb))
return0;
skb=*pskb;
dest=eth_hdr(skb)->h_dest;
}
if(!
compare_ether_addr(p->br->dev->dev_addr,dest))
skb->pkt_type=PACKET_HOST;
/*在br_handle_frame中更新CAM表*/
NF_HOOK(PF_BRIDGE,NF_BR_PRE_ROUTING,skb,skb->dev,NULL,
br_handle_frame_finish);
return1;
}
err:
kfree_skb(skb);
return1;
}
三.接下来我们首先分析更新CAM表的函数
br_handle_frame_finish,在第4小节再分析STP的处理函数br_stp_handle_bpdu
intbr_handle_frame_finish(structsk_buff*skb)
{
constunsignedchar*dest=eth_hdr(skb)->h_dest;
structnet_bridge_port*p=rcu_dereference(skb->dev->br_port);
structnet_bridge*br;
structnet_bridge_fdb_entry*dst;
intpassedup=0;
if(!
p||p->state==BR_STATE_DISABLED)
gotodrop;
/*
insertintoforwardingdatabaseafterfilteringtoavoidspoofing
使用数据包的源MAC地址来更新CAM表
*/
br=p->br;
br_fdb_update(br,p,eth_hdr(skb)->h_source);
if(p->state==BR_STATE_LEARNING)
gotodrop;
/*
如果网桥的虚拟网卡处于混杂模式,那么每个接收到的数据包都需要克隆一份送到AF_PACKET协议处理*/
if(br->dev->flags&IFF_PROMISC){
structsk_buff*skb2;
skb2=skb_clone(skb,GFP_ATOMIC);
if(skb2!
=NULL){
passedup=1;
br_pass_frame_up(br,skb2);
}
}
/*
目的MAC为广播或多播,则需要向本机的上层协议栈传送这个数据包,这里有一个标志变量passedup用于表示是否传送过了,如果已传送过,那就算了
*/
if(is_multicast_ether_addr(dest)){
br_flood_forward(br,skb,!
passedup);
if(!
passedup)
br_pass_frame_up(br,skb);
gotoout;
}
dst=__br_fdb_get(br,dest);
if(dst!
=NULL&&dst->is_local){
if(!
passedup)
br_pass_frame_up(br,skb);
else
kfree_skb(skb);
gotoout;
}
if(dst!
=NULL){
br_forward(dst->dst,skb);
gotoout;
}
/*CAM表中没有,只能flood了。
。
。
。
*/
br_flood_forward(br,skb,0);
out:
return0;
drop:
kfree_skb(skb);
gotoout;
}
四.在介绍br_stp_handle_bpdu
这个函数之前,我们首先来看一下内核中用来表示一个BPDU的数据结构是什么--br_config_bpdu
structbr_config_bpdu
{
unsignedtopology_change:
1;/*拓扑改变标志*/
unsignedtopology_change_ack:
1;/*拓扑改变回应标志*/
bridge_idroot;/*根ID,用于会聚后的网桥网络中,所有配置BPDU中的该字段都应该具有相同值(同VLAN),又可分为两个BID子字段:
网桥优先级和网桥MAC地址*/introot_path_cost;/*路径开销,通向有根网桥(RootBridge)的所有链路的积累资本*/
bridge_idbridge_id;/*创建当前BPDU的网桥BID*/
port_idport_id;/*端口ID,每个端口值都是唯一的*/
intmessage_age;/*记录RootBridge生成当前BPDU起源信息的所消耗时间*/
intmax_age;/*保存BPDU的最长时间,也反映了拓朴变化通知(TopologyChangeNotification)过程中的网桥表生存时间情况*/
inthello_time;/*周期性配置BPDU间的时间*/
intforward_delay;/*用于在Listening和Learning状态的时间,也反映了拓朴变化通知(TopologyChangeNotification)过程中的时间情况*/
};
五.BPDU处理函数br_stp_handle_bpdu
intbr_stp_handle_bpdu(structsk_buff*skb)
{
structnet_bridge_port*p=rcu_dereference(skb->dev->br_port);
structnet_bridge*br;
unsignedchar*buf;
if(!
p)
gotoerr;
br=p->br;
spin_lock(&br->lock);
if(p->state==BR_STATE_DISABLED||!
(br->dev->flags&IFF_UP))
gotoout;
/*
insertintoforwardingdatabaseafterfilteringtoavoidspoofing
根据BPDU中的MAC地址来更新CAM表
*/
br_fdb_update(br,p,eth_hdr(skb)->h_source);
if(!
br->stp_enabled)
gotoout;
/*needatleastthe802andSTPheaders*/
if(!
pskb_may_pull(skb,sizeof(header)+1)||
memcmp(skb->data,header,sizeof(header)))
gotoout;
buf=skb_pull(skb,sizeof(header));
if(buf[0]==BPDU_TYPE_CONFIG){
structbr_config_bpdubpdu;
if(!
pskb_may_pull(skb,32))
gotoout;
/*
802.3数据包格式:
目的地址|源地址|长度|DSAP|SSAP|cntl|org_code|类型|数据
6621113238~1492
*/
buf=skb->data;//跳过了数据字段的6个字节,buf指向了类型字段
/*
STP的数据包不是以太网格式的,而是802.3格式的,
*/
bpdu.topology_change=(buf[1]&0x01)?
1:
0;
bpdu.topology_change_ack=(buf[1]&0x80)?
1:
0;
bpdu.root.prio[0]=buf[2];
bpdu.root.prio[1]=buf[3];
bpdu.root.addr[0]=buf[4];
bpdu.root.addr[1]=buf[5];
bpdu.root.addr[2]=buf[6];
bpdu.root.addr[3]=buf[7];
bpdu.root.addr[4]=buf[8];
bpdu.root.addr[5]=buf[9];
bpdu.root_path_cost=
(buf[10]
(buf[11]
(buf[12]
buf[13];
bpdu.bridge_id.prio[0]=buf[14];|CRC4
bpdu.bridge_id.prio[1]=buf[15];
bpdu.bridge_id.addr[0]=buf[16];
bpdu.bridge_id.addr[1]=buf[17];
bpdu.bridge_id.addr[2]=buf[18];
bpdu.bridge_id.addr[3]=buf[19];
bpdu.bridge_id.addr[4]=buf[20];
bpdu.bridge_id.addr[5]=buf[21];
bpdu.port_id=(buf[22]
bpdu.message_age=br_get_ticks(buf+24);//0
bpdu.max_age=br_get_ticks(buf+26);//20
bpdu.hello_time=br_get_ticks(buf+28);//2
bpdu.forward_delay=br_get_ticks(buf+30);//15
/*若是收到了configbpdu,则调用下面的函数*/
br_received_config_bpdu(p,&bpdu);
}
/*若是拓扑变化通知TCN,则调用下面的函数*/
elseif(buf[0]==BPDU_TYPE_TCN){
br_received_tcn_bpdu(p);
}
out:
spin_unlock(&br->lock);
err:
kfree_skb(skb);
return0;
六.数据结构
在处理BPDU之前,我们先来看一下net_bridge和net_bridge_port这两个数据结构,这两个是很重要的数据结构,如果不理解这两个结构,后面的分析就很难进行了。
structnet_bridge
{
spinlock_tlock;
structlist_headport_list;
structnet_device*dev;
structnet_device_statsstatistics;
spinlock_thash_lock;
structhlist_headhash[BR_HASH_SIZE];
structlist_headage_list;
unsignedlongfeature_mask;
/*STP*/
bridge_iddesignated_root;//网络中根桥的ID
bridge_idbridge_id;//网桥本身的ID
u32root_path_cost;//?
?
?
unsignedlongmax_age;
unsignedlonghello_time;
unsignedlongforward_delay;
unsignedlongbridge_max_age;
unsignedlongageing_time;
unsignedlongbridge_hello_time;
unsignedlongbridge_forward_delay;
u16root_port;
unsignedcharstp_enabled;
unsignedchartopology_change;
unsignedchartopology_change_detected;
structtimer_listhello_timer;
structtimer_listtcn_timer;
structtimer_listtopology_change_timer;
structtimer_listgc_timer;
structkobjectifobj;
};
-------------------
structnet_bridge_port
{
structnet_bridge*br;
structnet_device*dev;
structlist_headlist;
/*STP*/
u8priority;
u8state;
u16port_no;
unsignedchartopology_change_ack;
unsignedcharconfig_pending;
port_idport_id;//端口的ID,在从端口发出的BPDU中,会将这个端口的ID存入BPDU中
port_iddesignated_port;
bridge_iddesignated_root;
bridge_iddesignated_bridge;
u32path_cost;
u32designated_cost;
structtimer_listforward_delay_timer;
structtimer_listhold_timer;
structtimer_listmessage_age_timer;
structkobjectkobj;
structwork_structcarrier_check;
structrcu_headrcu;
};
七.config_bpdu的处理函数--br_received_config_bpdu
voidbr_received_config_bpdu(structnet_bridge_port*p,structbr_config_bpdu*bpdu)
{
structnet_bridge*br;
intwas_root;
br=p->br;
was_root=br_is_root_bridge(br);
if(br_supersedes_port_info(p,bpdu)){//第八部分介绍
br_record_config_information(p,bpdu);
br_configuration_update(br);
br_port_state_selection(br);
if(!
br_is_root_bridge(br)&&was_root){
del_timer(&br->hello_timer);
if(br->topology_change_detected){
del_timer(&br->topology_change_timer);
br_transmit_tcn(br);
mod_timer(&br->tcn_timer,
jiffies+br->bridge_hello_time);
}
}
if(p->port_no==br->root_port){
br_record_config_timeout_values(br,bpdu);
br_config_bpdu_generation(br);
if(bpdu->topology_change_ack)
br_topology_change_acknowledged(br);
}
}
elseif(br_is_designated_port(p)){
br_reply(p);
}
}
八.br_supersedes_port_info(p,bpdu)
这个函数,就是把包中的值,同先前指定的对应值进行判断和比较,经确定是否需要更新/*calledunderbridgelock*/
/*如果要更新则返回1,不然返回0*/
staticintbr_supersedes_port_info(structnet_bridge_port*p,structbr_config_bpdu*bpdu){
intt;
/*收到的BPDU的rootID和当前交换机端口上记录的rootID进行比较*/
t=memcmp(&bpdu->root,&p->designated_root,8);
if(t
return1;
elseif(t>0)
return0;
/*若相等,则往下*/
if(bpdu->root_path_cost
designated_cost)
return1;
elseif(bpdu->root_path_cost>p->designated_cost)
return0;
t=memcmp(&bpdu->bridge_id,&p->designated_bridge,8);
if(t
return1;
elseif(t>0)
return0;
if(memcmp(&bpdu->bridge_id,&p->br->bridge_id,8))
return1;
if(bpdu->port_iddesignated_port)
return1;
return0;
}
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 针对 2616 工作 流程