Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2762187
  • 博文数量: 79
  • 博客积分: 30130
  • 博客等级: 大将
  • 技术积分: 2608
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-22 14:58
个人简介

博所搬至http://xiaogr.com

文章存档

2015年(2)

2009年(3)

2008年(56)

2007年(18)

分类: LINUX

2007-10-25 18:47:13

OK。到这里为止,网桥的配置已经讲述完了。我们来看一下网桥是怎么对数据包进行处理的

网桥对接收数据的处理:

回到本章的开始的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_typePACKET_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_actionptype_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()

接着分析一下此函数

struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br,

                                                 const unsigned char *addr)

{

         struct hlist_node *h;

         struct net_bridge_fdb_entry *fdb;

         //遍历对应MAC哈希项中的fdb

         hlist_for_each_entry_rcu(fdb, h, &br->hash[br_mac_hash(addr)], hlist) {

                   if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) {

                            if (unlikely(has_expired(br, fdb)))

                                     break;

                            return fdb;

                   }

         }

 

         return NULL;

}

这个函数非常容易,首先取得目的MAC对应的哈希项。然后再遍历里面的数据,查看是否含有目的地址的项。如果是送给本机的数据包,则传至上层协议,如不是,则需要转发。关于上层怎么处理,以及如何转发。请在后续章节中讨论。

 

阅读(3976) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~