分享

linux协议栈之链路层上的数据传输(网桥对数据的处理)

 enchen008 2012-04-10
经讲述完了。我们来看一下网桥是怎么对数据包进行处理的
网桥对接收数据的处理:
回到本章的开始的handle_bridge函数,会调用br_handle_frame_hook进行接收数据的处理
在网桥的初始化代码中,把br_handle_frame_hook赋值为了br_handle_frame
没错,这就是网桥的处理函数。跟进个函数
nt br_handle_frame(struct net_bridge_port *p, struct sk_buff **pskb)
{
struct sk_buff *skb = *pskb;
//目的mac地址
const unsigned char *dest = eth_hdr(skb)->h_dest;

//端口禁用
if (p->state == BR_STATE_DISABLED)
goto err;

//源mac 为多播或者广播,丢弃
//FF.XX.XX.XX.XX.XX形式
if (eth_hdr(skb)->h_source[0] & 1)
goto err;

//如果状态为学习或者转发,则学习源mac 更新CAM 表
if (p->state == BR_STATE_LEARNING ||
p->state == BR_STATE_FORWARDING)
// br_fdb_insert函数我们在前面已经分析过了
br_fdb_insert(p->br, p, eth_hdr(skb)->h_source, 0);

//stp 的处理,stp-enabled 是否启用stp 协议
//bridge_ula stp使用的多播mac地址
if (p->br->stp_enabled &&
!memcmp(dest, bridge_ula, 5) &&
!(dest[5] & 0xF0)) {
if (!dest[5]) {
NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,
NULL, br_stp_handle_bpdu);
return 1;
}
}

else if (p->state == BR_STATE_FORWARDING) {
//在初始化中,并末对br_should_route_hook进行赋值
//所以br_should_route_hook为假
if (br_should_route_hook) {
if (br_should_route_hook(pskb))
return 0;
skb = *pskb;
dest = eth_hdr(skb)->h_dest;
}

//目的地址与桥地址相同。则传与上层处理
//置skb->pkt_type = PACKET_HOST
if (!memcmp(p->br->dev->dev_addr, dest, ETH_ALEN))
skb->pkt_type = PACKET_HOST;
//网桥在NF_BR_PRE_ROUTING点上的netfiter处理
NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
br_handle_frame_finish);
return 1;
}

err:
kfree_skb(skb);
return 1;
}
在这个函数里,进行相关的入口判断之后,会把当前数据包的源MAC与接口对应更新到CAM表中,更新函数br_fdb_insert()在前面已经分析过了,不太明白的可以倒过去看下,不过注意了,这是不是做为静态项插入的。
接着判断包是不是传给本机的,如果是,则置包的pkt_type为PACKET_HOST
关于NF_HOOK()宏,我们在以后的netfiter中有专题分析。这是我们只要知道,正常的数据包会流进br_handle_frame_finish()进行处理
/* note: already called with rcu_read_lock (preempt_disabled) */
int br_handle_frame_finish(struct sk_buff *skb)
{
//取得目的MAC地址
const unsigned char *dest = eth_hdr(skb)->h_dest;
struct net_bridge_port *p = skb->dev->br_port;
struct net_bridge *br = p->br;
struct net_bridge_fdb_entry *dst;
int passedup = 0;

//混杂模式
/*如果网桥的虚拟网卡处于混杂模式,那么每个接收到的数据包都需要克隆一份
送到AF_PACKET协议处理体(网络软中断函数net_rx_action中ptype_all链的处理)。*/

if (br->dev->flags & IFF_PROMISC) {
struct sk_buff *skb2;

skb2 = skb_clone(skb, GFP_ATOMIC);
if (skb2 != NULL) {
passedup = 1;
br_pass_frame_up(br, skb2);
}
}

//目的mac 为多播或者广播,则需要传至上层进行处理
//passedup为传送标志,为1 时表示已经上传过了
if (dest[0] & 1) {
br_flood_forward(br, skb, !passedup);
if (!passedup)
br_pass_frame_up(br, skb);
goto out;
}


//查询CAM 表
dst = __br_fdb_get(br, dest);

//到本机的? 传至上层协议处理
if (dst != NULL && dst->is_local) {
if (!passedup)
br_pass_frame_up(br, skb);
else
kfree_skb(skb);
goto out;
}

//不是本机的数据,则转发
if (dst != NULL) {
br_forward(dst->dst, skb);
goto out;
}

//如果查询不到,在其它端口上都发送此包
br_flood_forward(br, skb, 0);

out:
return 0;
}
在这里函数里,通过查找CAM表,取得发送端口,如果当前CAM表里没有到目的MAC的端口,则在其它端口上都发送此数据包。
在这个函数里,我们看到,查询CAM表的函数为:__br_fdb_get()


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章