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_allptype_base两链表
(1) ptype_all管理的协议主要用于分析目的,它接收所有到达第3层协议的数据包。
(2) ptype_base管理正常的3层协议,仅接收具有正确协议标志符的数据包,例如,Internet的0x0800。
这个目前支持的协议类型:其中ETH_P_IP, ETH_P_ARP, ETH_P_8021Q, 是我们比较关注的
2. 下面介绍桥处理:br_handle_frame
先上一张图
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发送。