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,歡迎大家一起交流學習,請關注、點贊、在看吧,不定期分享技術干活哦。