Linux 网络--TCP协议收包流程(NAPI机制)
平台环境简介:
宿主机: ubuntu18.04
Linux内核源码版本: Linux-4.15
网卡驱动: Intel e1000 (ubuntu 虚拟机默认网卡驱动)
协议:TCP协议,本文分析收包过程
本文以 Linux4.15 内核版本对TCP协议的网络数据包接收处理过程进行分析。
NAPI机制引入
New API(NAPI)是 Linux 上采用的一种提高网络处理效率的技术,它的核心概念就是不采用中断的方式读取数据,而代之以首先采用中断唤醒数据接收的服务程序,然后 POLL 的方法来轮询数据。随着网络的接收速度的增加,NIC 触发的中断能做到不断减少,目前 NAPI 技术已经在网卡驱动层和网络层得到了广泛的应用,驱动层次上已经有 E1000 系列网卡,RTL8139 系列网卡,3c50X 系列等主流的网络适配器都采用了这个技术,而在网络层次上,NAPI 技术已经完全被应用到了著名的netif_rx 函数中间,并且提供了专门的 POLL 方法--process_backlog 来处理轮询的方法;根据实验数据表明采用NAPI技术可以大大改善短长度数据包接收的效率,减少中断触发的时间。
OSI七层模式和TCP/IP四层模型
进入正题前,我们先重温一下TCP/IP模型以及对应Linux系统的各部分功能。
数据包流转
函数调用流程 您粘贴的区域不支持图片插入。
1.系统调用
应用程序调用read()
阻塞等待读取网络数据,通过sk_wait_data()
进行阻塞,当有数据到来时,触发等待队列,调用skb_copy_datagram_msg()
进行数据拷贝。具体函数调用流程如下所示:
=>read() 系统调用
=>vfs_read()
=>new_sync_read()
=>call_read_iter()
=>sock_recvmsg() 进入sock接收
=>sock_recvmsg_nosec()
=>inet_recvmsg()
=>tcp_recvmsg() 阻塞,进入tcp协议栈
=>sk_wait_data() 等待数据到来
=>skb_copy_datagram_msg() 数据来了拷贝
2.网卡中断处理函数
当网卡收到数据时,通过e1000网卡驱动绑定的 e1000_intr()
中断函数进行处理,因为e1000网卡支持NAPI机制,所以进入__napi_schedule()
进行触发,将当前节点加入napi_poll链表并触发软中断进入 NAPI处理 。中断函数的调用流程如下所示:
=> irqreturn_t e1000_intr(int irq, void *data) 中断处理函数
=> __napi_schedule(&adapter->napi) 调度NAPI
=> ____napi_schedule() NAPI调度
=>list_add_tail(&napi->poll_list,&sd->poll_list);添加到poll链表
=>__raise_softirq_irqoff(NET_RX_SOFTIRQ); 触发软中断
3.NAPI处理
=> invoke_softirq() 软中断
=> __do_softirq()
=> net_rx_action()
=> napi_poll() 执行NAPI机制
=> e1000_clean()
=> e1000_clean_rx_irq()
=> e1000_copybreak() 拷贝数据
=>e1000_alloc_rx_skb() 申请skb内存
=>dma_sync_single_for_cpu() 同步DMA数据
=>skb_put_data() 拷贝DMA数据到SKB
=> e1000_receive_skb()
=> napi_gro_receive()
=> napi_skb_finish()
=> netif_receive_skb_internal()
=> __netif_receive_skb()
=> __netif_receive_skb_core()
=> ip_rcv() 进入网络层
=> ip_rcv_finish()
=> dst_input()
=> ip_local_deliver()
=> ip_local_deliver_finish()
=> tcp_v4_rcv()
=> tcp_v4_do_rcv()
=> tcp_rcv_established()
=> sk_data_ready() 唤醒等待队列
=> tcp_add_backlog()
=> release_sock()唤醒
总结
注: 不同的Linux内核版本,可能函数名不太一样,但是总体流程是一样的,可参考进行分析。
通过对网络收包过程的梳理,让我们对Linux网络数据包的流转有一定的概念,在需要分析源码的时候能找到对应位置进行分析。
我是小C,欢迎大家一起交流学习,请关注、点赞、在看吧,不定期分享技术干活哦。