linux网络协议栈分析笔记2-网桥1

这一章主要看网桥的处理。
网桥是一种2层网络互连设备,而不是一种网络协议。它在协议结构上并没有占有一席之地,因此不能通过向协议栈注册协议的方式来申请网桥数据包的处理。

skb = handle_bridge(skb, &pt_prev, &ret, orig_dev);

static inline struct sk_buff *handle_bridge(struct sk_buff *skb,
                             struct packet_type **pt_prev, int *ret,
                             struct net_device *orig_dev)
{
     struct net_bridge_port *port;

     if (skb->pkt_type == PACKET_LOOPBACK ||                 如果该数据包产生于本机,而目标同时为本机
         (port = rcu_dereference(skb->dev->br_port)) == NULL)      如果该数据包的输入接口不是网桥接口
          return skb;                                           以上两种情况都需要让上层协议进行处理

     if (*pt_prev) {
          *ret = deliver_skb(skb, *pt_prev, orig_dev);
          *pt_prev = NULL;
     }

     return   br_handle_frame_hook(port, skb);           网桥处理函数
}

-> br_handle_frame_hook()        br_handle_frame_hook =   br_handle_frame;      br.c    br_init()
  ->br_handle_frame()
         is_valid_ether_addr()  校验是否是有效的以太网地址
         skb_share_check()        skb是共享的话,拷贝一份
           if (skb->protocol == htons(ETH_P_PAUSE))       如果是Pause帧,则丢弃
           if (p->br->stp_enabled == BR_NO_STP && dest[5] == 0)       STP关闭,则转发

           switch (p->state) {
               case BR_STATE_FORWARDING:
                    rhook = rcu_dereference(br_should_route_hook);
                    rhook(skb);
               如果该接口处于Forwarding状态,并且该报文必需要走L3层   进行转发,则直接返回,让代码(2)进行处理。br_should_route_hook                                 钩子函数在ebtable里面设置为ebt_broute函数,它根据用户的规则来决定该报文是否要能通过L3来转发
               case BR_STATE_LEARNING:
                    skb->pkt_type = PACKET_HOST;   设置为送到本机类型报文。
                     br_handle_frame_finish();
             }
-> br_handle_frame_finish()
      ->br_fdb_update()         源地址学习           (bf_fdb.c     转发数据库管理模块)
          ->is_multicast_ether_addr()   如果该报文是一个L2多播报文(如arp请求),那么它应该转发到该网桥的所有接口
          ->dst = __br_fdb_get(br, dest)  查MAC-端口映射表 得到出接口dst
          -> br_pass_frame_up()     完成发往本机的工作
          -> br_forward(dst->dst, skb);     由br_forward函数从dst所指向的端口将该报文发出去
          -> br_flood_forward(br, skb);    此报文是广播或组播报文,由br_flood_forward函数把报文向所有端口转发出去。  
-> br_pass_frame_up()           完成发往本机的工作
     indev = skb->dev;
     skb->dev = brdev;
     ->netif_receive_skb()
          br->dev是一个虚拟的网络设备,这是网桥局域网通往本机的必经之道请注意,br->dev是本机和网桥相连的接口。当报文经网桥处理后,发现该报文应该发往本机,那就使用netif_receive_skb函数将该报文向上层协议投递。并且要将skb->dev设置为本机接口即br->dev,并且所有数据在它的入口接口indev的驱动中已处理完毕,因此可直接通知上层协议来处理。
-> br_forward(dst->dst, skb);          由br_forward函数从dst所指向的端口将该报文发出去
 ->should_deliver(to, skb)    Should_deliver函数来测试是否应将该包转发出去,它由出口端的状态和报文的入口端口信息来决定
          return (((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) &&          p->state == BR_STATE_FORWARDING);
               1) 入口端口和出口端口不能相同,如果是相同的话,那么源主机和目标主机在同一端口的子网段中,也即源主机和目标主机在同一
                 广播域里面目标主机和网桥都会同时收到该报文,因此网桥无需多此一举。   
               2) 如果出口端口的状态不是Forwarding,则不能转发出去。如果一个网桥没有启用STP功能,并且网络接口的状态为UP,那么它网
                 桥端口的状态为Forwarding。如果启用STP,每个端口都有一个严格的状态,规定那些端口在什么情况下才能成为Forwarding状          
                 态,否则容易造成环路,产生网络风暴。 
 ->__br_forward()
      ->br_forward_finish()
            ->br_dev_queue_push_xmit()
                  ->skb_push(skb, ETH_HLEN);
                  ->dev_queue_xmit(skb);
->br_flood_forward(br, skb);         由br_flood_forward函数把报文向所有端口转发出去。
       ->br_flood(br, skb, __br_forward);        把__br_forward函数作为回调函数,依次遍网桥的所有出口端,调用__br_forward函数将该报
                                                       文转发出去。一个广播报文从某一端口进入,应该其余的端口都应该转发出去,但入口端口就不需要了
               ->list_for_each_entry_rcu(p, &br->port_list, list)     即__br_forward()
下一章分析转发数据库模块,即二层MAC-端口转发表处理模块

你可能感兴趣的:(linux网络协议栈分析笔记2-网桥1)