谈谈Linux网络协议以及网络栈结构( 二 )


skb_queue为系统底层与应用程序之间一个接口 。所有接收到的同类报文都会被挂到这个队列上,然后由协议栈上层接口来取 。
5、 协议上层接口通过系统调用获取skb 。代码位于net模块下:
sys_recv()
sys_recvfrom()
sock_recvmsg()
__sock_recvmsg()
udp_recvmsg()或者tcp_recvmsg()
__skb_recv_datagram()
ip_cmsg_recv()
从skb接收队列skb_queue收包
 
某项目中的代码
1. 驱动driver使用NAPI方式,从硬件queue中收包
2. 调用netif_receiv_skb()函数,上交收到的报文
这个项目支持NAPT,因此会在该函数中直接调用NAPT回调做NAT,而对于非NAPT印射的报文,进行如下处理:
先遍历ptype_all链表,list_for_each_entry_rcu(),最终调用packet_type.func()
编译内核时选上BRIDGE,则会执行网桥模块br_handle_frame_hook(skb),源文件为bridge/br.c
网桥模块的初始化pkt_type为PACKET_HOST或者PACKET_OTHERHOST
如果编译内核时选上了mac_VLAN模块,则会执行macvlan_handle_frame_hook
初始化为PACKET_BROADCAST、PACKET_MULTICAST、PACKET_HOST
最后一步,判断type==skb->protocol,会查询链表,找到匹配的protocol钩子并且调用 。
3. Skb的释放时机
如果是合法报文,放入接收队列,在用户系统调用取包时释放,否则在netif_receiv_skb()函数中释放 。
 
802.1q协议模块实现
带802.1qTAG的模块有自己单独的协议类型,一般是0x8100 。使用前面说的packet_list操作接口注册一个新的packet_type挂到链表中,这样,所有带TAG的报文会被转发到802.1q的接口上 。
应用程序里,每调用vconfig创建一个VLAN,就会创建一个新的net device,这个虚拟扩展的net device会在原来物理的net device上面工作,将VLAN对应的报文都转移到虚拟net device的收发接口上 。
new_dev = alloc_netdev(sizeof(struct vlan_dev_info), name,vlan_setup);




推荐阅读