linux 网络协议栈(链路层)

1.int netif_receive_skb(struct sk_buff *skb),该函数是网络设备驱动到链路层协议栈的接口函数,该函数最后会调用__netif_receive_skb_core函数,下面主要介绍函数流程

1.1

  list_for_each_entry_rcu(ptype, &ptype_all, list) {  //遍历ptype_all,如果有则做相应处理,例如raw socket和tcpdump实现  
        if (pt_prev)  
            ret = deliver_skb(skb, pt_prev, orig_dev);  
        pt_prev = ptype;  
    } 

主要遍历ptype_all链表的所有成员,然后执行成员里的处理函数,PF_PACKETsocket和tcpdump等实现都在这里了

1.2

rx_handler = rcu_dereference(skb->dev->rx_handler);   
     if (rx_handler) {  
         if (pt_prev) {  
             ret = deliver_skb(skb, pt_prev, orig_dev);  
             pt_prev = NULL;  
         }  
//根据处理结果,判断接下来对数据包如何进一步处理。  
         switch (rx_handler(&skb)) {  
//数据包已成功接收,不需要再处理  
         case RX_HANDLER_CONSUMED:  
             ret = NET_RX_SUCCESS;  
             goto unlock;  
//当rx_handler改变过skb->dev时,在接收回路中再一次处理。  
         case RX_HANDLER_ANOTHER:  
             goto another_round;  
//不使用匹配的方式,精确传递。  
         case RX_HANDLER_EXACT:  
             deliver_exact = true;  
//忽略rx_handler的影响。  
         case RX_HANDLER_PASS:  
             break;  
        default:  
             BUG();  
         }  
     }  

 可以看到这里首先从设备结构net_device中获取其rx_handler指针,该指针在网卡的混杂模式下指向一个处理函数叫做br_handle_frame,即网桥的处理流程

1.3

    if (likely(!deliver_exact)) {  
        deliver_ptype_list_skb(skb, &pt_prev, orig_dev, type,   //根据全局定义的协议处理报文  
                       &ptype_base[ntohs(type) &  
                           PTYPE_HASH_MASK]);  
    }

这里是从链路层进入上层的地方

 

链路层和上层连接主要通过:ptype_all  ptype_base两链表

(1)    ptype_all管理的协议主要用于分析目的,它接收所有到达第3层协议的数据包。
(2)    ptype_base管理正常的3层协议,仅接收具有正确协议标志符的数据包,例如,Internet的0x0800。

linux 网络协议栈(链路层)_第1张图片

这个目前支持的协议类型:其中ETH_P_IP, ETH_P_ARP, ETH_P_8021Q,  是我们比较关注的

linux 网络协议栈(链路层)_第2张图片

2. 下面介绍桥处理:br_handle_frame

先上一张图

linux 网络协议栈(链路层)_第3张图片

2.

首先根据dev->br_port判断收到报文的接口是否加入某个桥,如果加入则该报文进入桥处理。

桥处理首先判断该报文是否是 stp协议,如果是stp报文,则判断是否stp开启,如果开启,进去stp处理流程,如果,没有则不处理。

如果报文不是stp协议,则判断目的mac是否是网桥下的某个接口的mac,如果是则把in_dev改成网桥自己,然后重新走一遍协议栈,然后这个报文被送进网络层进行路由。如果目的mac不是网桥下的接口的mac,直接进行二层转发。

 上面讲到进行三层路由,如果路由的目的ip任然是一个网桥,在调用dev_queue_xmit发送的时候,因为出接口是网桥,则会被br_dev_xmit接管,然后进行二层转发,找到实际出接口,再次调用dev_queue_xmit发送。

 

你可能感兴趣的:(linux)