Linux网桥源码的实现.docx
- 文档编号:2947819
- 上传时间:2022-11-16
- 格式:DOCX
- 页数:20
- 大小:27.64KB
Linux网桥源码的实现.docx
《Linux网桥源码的实现.docx》由会员分享,可在线阅读,更多相关《Linux网桥源码的实现.docx(20页珍藏版)》请在冰豆网上搜索。
Linux网桥源码的实现
Linux网桥源码的实现
1、调用
在src/net/core/dev.c的软中断函数staticvoidnet_rx_action(structsoftirq_action*h)中(line1479)
#ifdefined(CONFIG_BRIDGE)||defined(CONFIG_BRIDGE_MODULE)
if(skb->dev->br_port!
=NULL&&
br_handle_frame_hook!
=NULL){
handle_bridge(skb,pt_prev);
dev_put(rx_dev);
continue;
}
#endif
如果定义了网桥或网桥模块,则由handle_bridge函数处理skb->dev->br_port:
接收该数据包的端口是网桥端口组的一员,如果接收当前数据包的接口不是网桥的某一物理端口,则其值为NULL;
br_handle_frame_hook:
定义了网桥处理函数这段代码将数据包进行转向,转向的后的处理函数是钩子函数br_handle_frame_hook,在此之前,handle_bridge函数还要处理一些其它的事情:
static__inline__inthandle_bridge(structsk_buff*skb,
structpacket_type*pt_prev)
{
intret=NET_RX_DROP;
if(pt_prev){
if(!
pt_prev->data)
ret=deliver_to_old_ones(pt_prev,skb,0);
else{
atomic_inc(&skb->users);
ret=pt_prev->func(skb,skb->dev,pt_prev);
}
}
br_handle_frame_hook(skb);
returnret;
}
pt_prev用于在共享SKB的时候提高效率,handle_bridge函数最后将控制权交由到了br_handle_frame_hook的手上。
2、钩子函数的注册
br_handle_frame_hook用于网桥的处理,在网桥的初始化函数中(net/bridge/br.c):
staticint__initbr_init(void)
{
printk(KERN_INFO"NET4:
EthernetBridge008forNET4.0\n");
br_handle_frame_hook=br_handle_frame;
br_ioctl_hook=br_ioctl_deviceless_stub;
#ifdefined(CONFIG_ATM_LANE)||defined(CONFIG_ATM_LANE_MODULE)
br_fdb_get_hook=br_fdb_get;
br_fdb_put_hook=br_fdb_put;
#endif
register_netdevice_notifier(&br_device_notifier);
return0;
}
初始化函数中指明了钩子函数实际上指向的是br_hanlde_frame
3、br_handle_frame(br_input.c)
/*网桥处理函数*/
voidbr_handle_frame(structsk_buff*skb)
{
structnet_bridge*br;
unsignedchar*dest;
structnet_bridge_port*p;
/*获取目的MAC地址*/
dest=skb->mac.ethernet->h_dest;
/*skb->dev->br_port用于指定接收该数据包的端口,若不是属于网桥的端口,则为NULL*/
p=skb->dev->br_port;
if(p==NULL) /*端口不是网桥组端口中*/
gotoerr_nolock;
/*本端口所属的网桥组*/
br=p->br;
/*加锁,因为在转发中需要读CAM表,所以必须加读锁,避免在这个过程中另外的内核控制路径(如多处理机上另外一个CPU上的系统调用)修改CAM表*/
read_lock(&br->lock);
if(skb->dev->br_port==NULL) /*前面判断过的*/
gotoerr;
/*br->dev是网桥的虚拟网卡,如果它未UP,或网桥DISABLED,p->state实际上是桥的当前端口的STP计算判断后的状态*/
if(!
(br->dev.flags&IFF_UP)||
p->state==BR_STATE_DISABLED)
gotoerr;
/*源MAC地址为255.X.X.X,即源MAC是多播或广播,丢弃之*/
if(skb->mac.ethernet->h_source[0]&1)
gotoerr;
/*众所周之,网桥之所以是网桥,比HUB更智能,是因为它有一个MAC-PORT的表,这样转发数据就不用广播,而查表定端口就可以了
每次收到一个包,网桥都会学习其来源MAC,添加进这个表。
Linux中这个表叫CAM表(这个名字是其它资料上看的)。
如果桥的状态是LEARNING或FORWARDING(学习或转发),则学习该包的源地址skb->mac.ethernet->h_source,
将其添加到CAM表中,如果已经存在于表中了,则更新定时器,br_fdb_insert完成了这一过程*/
if(p->state==BR_STATE_LEARNING||
p->state==BR_STATE_FORWARDING)
br_fdb_insert(br,p,skb->mac.ethernet->h_source,0);
/*
*STP协议的BPDU包的目的MAC采用的是多播目标MAC地址:
*01-80-c2-00-00-00(Bridge_group_addr:
网桥组多播地址),这里先判断网桥是否
*开启了STP(由用户层来控制,如brctl),如果开启了,则比较目的地址前5位
*是否与多播目标MAC地址相同:
*(!
memcmp(dest,bridge_ula,5)
*如果相同,如果地址第6位非空
*!
(dest[5]&0xF0))
*那么这确定是一个STP的BPDU包,则跳转到handle_special_frame,将处理权
*将给函数br_stp_handle_bpdu
*/
if(br->stp_enabled&&
!
memcmp(dest,bridge_ula,5)&&
!
(dest[5]&0xF0))
gotohandle_special_frame;
/*处理钩子函数,然后转交br_handle_frame_finish函数继续处理*/
if(p->state==BR_STATE_FORWARDING){
NF_HOOK(PF_BRIDGE,NF_BR_PRE_ROUTING,skb,skb->dev,NULL,
br_handle_frame_finish);
read_unlock(&br->lock);
return;
}
err:
read_unlock(&br->lock);
err_nolock:
kfree_skb(skb);
return;
handle_special_frame:
if(!
dest[5]){
br_stp_handle_bpdu(skb);
return;
}
kfree_skb(skb);
}
可见,这个函数中有三个重要的地方:
1、地址学习:
br_fdb_insert
2、STP的处理:
br_stp_handle_bpdu
3、br_handle_frame_finish,我们还没有查CAM表,转发数据呢……
我们先来看网桥的进一步处理br_handle_frame_finish,地址学习等内容,后面再来分析。
4、br_handle_frame_finish
staticintbr_handle_frame_finish(structsk_buff*skb)
{
structnet_bridge*br;
unsignedchar*dest;
structnet_bridge_fdb_entry*dst;
structnet_bridge_port*p;
intpassedup;
/*前面基本相同*/
dest=skb->mac.ethernet->h_dest;
p=skb->dev->br_port;
if(p==NULL)
gotoerr_nolock;
br=p->br;
read_lock(&br->lock);
if
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Linux 源码 实现