Chinaunix首页 | 论坛 | 博客
  • 博客访问: 818728
  • 博文数量: 264
  • 博客积分: 592
  • 博客等级: 中士
  • 技术积分: 1574
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-24 22:02
文章分类

全部博文(264)

文章存档

2019年(2)

2018年(1)

2017年(1)

2016年(4)

2015年(14)

2014年(57)

2013年(88)

2012年(97)

分类: LINUX

2014-02-12 15:27:14

转:http://blog.csdn.net/nerdx/article/details/12289997
  1. //  网桥设备驱动程序的hard_start_xmit函数  
  2.   
  3. //  函数主要任务:  
  4. //      1.广播或多播地址,在所有端口上扩散  
  5. //      2.存在转发项,在指定端口上发送  
  6. //      3.没有找到转发项,在所有端口上扩散  
  7. 1.1 int br_dev_xmit(struct sk_buff *skb, struct net_device *dev)  
  8. {  
  9.     struct net_bridge *br = netdev_priv(dev);  
  10.     const unsigned char *dest = skb->data;  
  11.     struct net_bridge_fdb_entry *dst;  
  12.     //更新网桥设备的统计信息  
  13.     br->statistics.tx_packets++;  
  14.     br->statistics.tx_bytes += skb->len;  
  15.     //更新l2头位置  
  16.     skb->mac.raw = skb->data;  
  17.     skb_pull(skb, ETH_HLEN);  
  18.   
  19.     rcu_read_lock();  
  20.     if (dest[0] & 1)//l2地址的第一个字节的第一位为1,则为多播地址   
  21.         br_flood_deliver(br, skb, 0);//在所有端口上发送此报文  
  22.     else if ((dst = __br_fdb_get(br, dest)) != NULL)//如果转发数据中存在目标地址的记录  
  23.         br_deliver(dst->dst, skb);//通过与目标地址相关的端口发送  
  24.     else  
  25.         br_flood_deliver(br, skb, 0);  
  26.   
  27.     rcu_read_unlock();  
  28.     return 0;  
  29. }  
  30.   
  31. //  在所有端口扩散skb  
  32. //  参数:__packet_hook, __br_deliver  
  33.   
  34. //  调用路径:br_dev_xmit->br_flood_deliver->br_flood  
  35. 1.3 static void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone,  
  36.     void (*__packet_hook)(const struct net_bridge_port *p,   
  37.                   struct sk_buff *skb))  
  38. {  
  39.     struct net_bridge_port *p;  
  40.     struct net_bridge_port *prev;  
  41.     //指示是否复制一份skb,br_dev_xmit->br_flood_deliver->br_flood此调用路径clone=0  
  42.     if (clone) {  
  43.         struct sk_buff *skb2;  
  44.   
  45.         if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {  
  46.             br->statistics.tx_dropped++;  
  47.             return;  
  48.         }  
  49.   
  50.         skb = skb2;  
  51.     }  
  52.   
  53.     prev = NULL;  
  54.     //遍历所有的端口  
  55.     list_for_each_entry_rcu(p, &br->port_list, list) {  
  56.         if (should_deliver(p, skb)) {//skb的输出设备非此端口,并且此端口处于转发模式  
  57.             if (prev != NULL) {//在第一次运行时,prev=NULL,直接复制prev=p  
  58.                 struct sk_buff *skb2;  
  59.   
  60.                 if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {//克隆sk_buff,共享packet data  
  61.                     br->statistics.tx_dropped++;  
  62.                     kfree_skb(skb);  
  63.                     return;  
  64.                 }  
  65.   
  66.                 __packet_hook(prev, skb2);//调用__br_deliver,执行一系列的netfilter调用点,最后由dev_queue_xmit完成传输  
  67.             }  
  68.   
  69.             prev = p;  
  70.         }  
  71.     }  
  72.   
  73.     if (prev != NULL) {  
  74.         __packet_hook(prev, skb);//对最后一个端口调用__br_deliver  
  75.         return;  
  76.     }  
  77.   
  78.     kfree_skb(skb);  
  79. }  
  80.   
  81. //  在网桥端口传输  
  82. //  调用路径:br_flood->hook->br_dev_queue_push_xmit  
  83. 1.6 int br_dev_queue_push_xmit(struct sk_buff *skb)  
  84. {  
  85.     if (skb->len > skb->dev->mtu)//如果skb的长度大于出口设备的mtu,则直接丢弃封包   
  86.         kfree_skb(skb);  
  87.     else {  
  88.         skb_push(skb, ETH_HLEN);  
  89.         dev_queue_xmit(skb);//输出  
  90.     }  
  91.   
  92.     return 0;  
  93. }  
  94.   
  95. //  判断端口是否应该发送数据帧  
  96. //  端口发送数据帧的条件:  
  97. //      1.skb的入口设备非此端口  
  98. //      2.端口处于转发模式  
  99. 1.7 static inline int should_deliver(const struct net_bridge_port *p,   
  100.                  const struct sk_buff *skb)  
  101. {  
  102.     if (skb->dev == p->dev ||//skb的接收端口为此端口  
  103.         p->state != BR_STATE_FORWARDING)//端口非转发模式  
  104.         return 0;  
  105.   
  106.     return 1;  
  107. }  
  108.   
  109.   
  110. //  网桥入口数据帧处理  
  111. //  调用路径:netif_receive_skb->handle_bridge  
  112. //  
  113. //  由网桥接收入口数据的条件:  
  114. //      1. 入口设备非回环地址  
  115. //      2. 入口设备为网桥端口  
  116. 2.1 static __inline__ int handle_bridge(struct sk_buff **pskb,  
  117.                     struct packet_type **pt_prev, int *ret)  
  118. {  
  119.     struct net_bridge_port *port;  
  120.   
  121.     if ((*pskb)->pkt_type == PACKET_LOOPBACK ||  
  122.         (port = rcu_dereference((*pskb)->dev->br_port)) == NULL)//如果设备为网桥的端口,则dev->br_port为网桥端口控制块  
  123.         return 0;  
  124.   
  125.     if (*pt_prev) {  
  126.         *ret = deliver_skb(*pskb, *pt_prev);  
  127.         *pt_prev = NULL;  
  128.     }   
  129.     //此设备为网桥的端口  
  130.     return br_handle_frame_hook(port, pskb);  
  131. }  
  132.   
  133.   
  134. //  网桥处理入口流量  
  135. //  参数:  
  136. //      p,接收到此入口流量的端口  
  137. //      pskb, 入口数据帧  
  138. //  
  139. //  返回值:  
  140. //      0,网桥没有处理此pskb,netif_receive_skb继续处理pskb  
  141. //      1,网桥已经处理此pskb,netif_receive_skb无需继续处理此pskb  
  142. //  
  143. //  调用路径 : netif_receive_skb->handle_bridge->br_handle_frame  
  144. //    
  145. //  函数主要任务:  
  146. //      1.检查分包合法性:  
  147. //          1.1 接收端口开启状态  
  148. //          1.2 源地址非多播或广播地址  
  149. //      2.向转发数据库添加转发项  
  150. //      3.识别配置bpdu,处理配置bpdu  
  151. //      4.决定入口流量被路由还是桥接  
  152. //      5.如果数据帧需要被桥接,则由桥接处理程序继续处理。  
  153.   
  154. //  注:  
  155. //      1.只有转发态(BR_STATE_FORWARDING),学习态(BR_STATE_LEARNING)的网桥端口,可以向转发数据库添加转发项。  
  156. //      2.bpdu的识别办法:以太网帧的目的地址为[0x01, 0x80, 0xc2, 0x00, 0x00, 0x00]  
  157. //      3.决定入口流量被路由还是桥接,通过ebtable_broute决定  
  158. //      4.只有转发态(BR_STATE_FORWARDING)的网桥端口,可以处理普通入口流量。  
  159.               
  160. 2.2 int br_handle_frame(struct net_bridge_port *p, struct sk_buff **pskb)  
  161. {  
  162.     struct sk_buff *skb = *pskb;  
  163.     const unsigned char *dest = eth_hdr(skb)->h_dest;  
  164.   
  165.     if (p->state == BR_STATE_DISABLED)//端口被关闭  
  166.         goto err;  
  167.   
  168.     if (eth_hdr(skb)->h_source[0] & 1)//源地址为广播地址,说明错误  
  169.         goto err;  
  170.   
  171.     if (p->state == BR_STATE_LEARNING ||//如果当前端口处于学习状态,或者转发状态  
  172.         p->state == BR_STATE_FORWARDING)  
  173.         br_fdb_insert(p->br, p, eth_hdr(skb)->h_source, 0);//在转发数据库中添加一条新转发项,或者更新现有的转发项  
  174.   
  175.     if (p->br->stp_enabled &&//网桥的stp协议开启  
  176.         !memcmp(dest, bridge_ula, 5) &&//网桥组播地址的前5个字节  
  177.         !(dest[5] & 0xF0)) {//bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 },通过入口帧的目标地址识别bpdu数据帧  
  178.         if (!dest[5]) {  
  179.             NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,   
  180.                 NULL, br_stp_handle_bpdu);//入口bpdu的数据帧,可以被任何端口接收,只要这个端口没有通过管理性手段关闭  
  181.             return 1;  
  182.         }  
  183.     }  
  184.   
  185.     else if (p->state == BR_STATE_FORWARDING) {//当前端口处于转发状态,一个封包是被路由还是桥接,通过br_should_route_hook函数决定  
  186.         if (br_should_route_hook) {//在ebtable_broute模块中被设置  
  187.             if (br_should_route_hook(pskb))   
  188.                 return 0;  
  189.             skb = *pskb;  
  190.             dest = eth_hdr(skb)->h_dest;  
  191.         }  
  192.   
  193.         if (!memcmp(p->br->dev->dev_addr, dest, ETH_ALEN))//目标地址为本地  
  194.             skb->pkt_type = PACKET_HOST;  
  195.   
  196.         NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,  
  197.             br_handle_frame_finish);//默认情况下,被绑定的设备所接收到的网络流量会分配给它的指定网桥  
  198.         return 1;  
  199.     }  
  200.   
  201. err:  
  202.     kfree_skb(skb);  
  203.     return 1;  
  204. }  
  205.   
  206. //  桥接入口流量  
  207.   
  208. //  调用路径: br_handle_frame->br_handle_frame_finish  
  209.   
  210. //  函数主要任务:  
  211. //      1.网桥端口均处于混杂模式,向网桥本地接收模块传递一份此数据帧  
  212. //      2.多播或广播目的地址,在除接收端口外的所有端口,扩散此入口数据帧,退出  
  213. //      3.如果,数据帧目的地址为本机,向网桥本地接收模块传递一份此数据帧,退出  
  214. //      4.否则,如果网桥知道能到达目的地址的输出端口,从输出端口发送此数据帧,退出  
  215. //      5.否则,如果网桥不知道使用哪个输出端口,向所有端口扩散,退出  
  216. 2.3 int br_handle_frame_finish(struct sk_buff *skb)  
  217. {  
  218.     const unsigned char *dest = eth_hdr(skb)->h_dest;  
  219.     struct net_bridge_port *p = skb->dev->br_port;  
  220.     struct net_bridge *br = p->br;  
  221.     struct net_bridge_fdb_entry *dst;  
  222.     int passedup = 0;  
  223.   
  224.     if (br->dev->flags & IFF_PROMISC) {//设备处于混杂模式  
  225.         struct sk_buff *skb2;  
  226.   
  227.         skb2 = skb_clone(skb, GFP_ATOMIC);//复制一份sk_buff,共享packet data  
  228.         if (skb2 != NULL) {  
  229.             passedup = 1;  
  230.             br_pass_frame_up(br, skb2);//向上层协议传递skb  
  231.         }  
  232.     }  
  233.   
  234.     if (dest[0] & 1) {//以太网多播地址  
  235.         br_flood_forward(br, skb, !passedup);//从各个端口扩散此skb  
  236.         if (!passedup)  
  237.             br_pass_frame_up(br, skb);//如果处于混杂模式,则已经向上传递了一份skb  
  238.         goto out;  
  239.     }  
  240.   
  241.     dst = __br_fdb_get(br, dest);//非多播地址的skb,查询转发数据库  
  242.     if (dst != NULL && dst->is_local) {//本地地址  
  243.         if (!passedup)  
  244.             br_pass_frame_up(br, skb);//向上层协议传递一份skb,由于网桥端口为混杂模式,之前会传递一份,所以此处不会再传递  
  245.         else  
  246.             kfree_skb(skb);  
  247.         goto out;  
  248.     }  
  249.   
  250.     if (dst != NULL) {  
  251.         br_forward(dst->dst, skb);//非本地地址,从通往目标地址的端口发送此skb  
  252.         goto out;  
  253.     }  
  254.   
  255.     br_flood_forward(br, skb, 0);//非以太网多播,没有明确的出口设备,从所有端口上扩散  
  256.   
  257. out:  
  258.     return 0;  
  259. }  
  260.   
  261. //  网桥向本地传递流量  
  262. //  调用路径:br_handle_frame_finish->br_pass_frame_up  
  263.   
  264. //  函数主要任务:  
  265. //      1.skb->dev设置为网桥设备,为skb重新走一遍netif_receive_skb  
  266.   
  267. //  注:网桥端口处于混杂模式,所有数据帧均会向上传递,并且一个数据帧,只会向本机传递一次。  
  268. 2.4 static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)  
  269. {  
  270.     struct net_device *indev;  
  271.   
  272.     //增加统计数据  
  273.     br->statistics.rx_packets++;  
  274.     br->statistics.rx_bytes += skb->len;  
  275.   
  276.     indev = skb->dev;  
  277.     skb->dev = br->dev;//修改接收此skb的设备为网桥设备  
  278.   
  279.     NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,  
  280.             br_pass_frame_up_finish);  
  281. }  
  282.   
  283. //  网桥向本地传递流量  
  284. //      使用积压设备的方式  
  285. //  调用路径:br_pass_frame_up->br_pass_frame_up_finish  
  286. 2.5 static int br_pass_frame_up_finish(struct sk_buff *skb)  
  287. {  
  288.     //挂载积压设备到poll_list,skb到input_pkt_queueu, 触发接收软中断  
  289.     netif_rx(skb);  
  290.     return 0;  
  291. }  
阅读(838) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~