linux資料包接收過程
最近發現瞭解linux內資料包的傳輸機制很有必要,首先總結一下接收過程。資料包從hostA向hostB發包,如下圖所示:
一. linux中包的傳輸過程
(1). 驅動載入並初始化
(2). 資料包到達網絡卡(網絡卡中的緩衝區或佇列)
(3). 包通過DMA拷貝到核心記憶體中的環形緩衝區中(環形緩衝區中的記憶體區域是驅動進行分配和對映的,分配後驅動會將記憶體地址和大小告訴網絡卡NIC;若沒有分配好的記憶體,包可能會丟失;傳輸前要通過CRC檢查包是否有效;若網絡卡支援硬體層多佇列,此時每個佇列會對應一個單獨的記憶體區域,多個CPU可以處理這些資料;若支援packet steering,資料也會多個CPU)。現在大多數的網絡卡都會使用DMA來傳輸資料包
(4). 產生硬中斷來讓系統知道一個包已經在記憶體中了
(5). 驅動通過Ksoftirqd程序通過呼叫NAPI poll函式將包從環形緩衝區中取出(函式用於監控多個事件,在一個迴圈中)。Ksoftirqd程序執行在系統中的每個CPU中,它們在boot時就被註冊了。NAPI poll函式在裝置驅動初始化時被註冊
(6). 將資料傳輸到網路層(IP層),資料格式為skb,便於繼續進行處理;網路層檢查包是否有效,然後檢查乙太網報頭,刪除乙太網報頭並將包傳送到IP層
(7). IP層通過檢查IP頭校驗,檢查包是否有效。判斷是否需要IP route。刪除IP頭部,將包傳送到TCP 層
(8). TCP層會檢查包是否有效。搜尋與包連線的TCP控制塊,搜尋到連線後,它用該協議來處理包。如果它收到新的資料,則將資料拷貝或傳送到receive socketbuffer
(9). 資料被協議層送到接收緩衝區,socket可以到達
資料包從底層傳到上層的過程中,會逐漸拆包,如下圖所示:
二. RQ和Softirq
這裡還要解釋一下IRQ和Softirq
1. IRQ
當一個數據幀通過DMA被寫到RAM,網絡卡怎樣通知系統資料已經準備好被處理了呢?傳統方法中,一個網絡卡會產生一箇中斷請求(IRQ),代表資料已經到達了。IRQ有三種類型:MSI-X,MSI以及合法IRQ。如果需要傳輸的資料量很大,將會導致有大量的IRQ產生。產生越多的IRQ,其他任務可分配到越少的CPU時間,因此會佔據大量的CPU時間。
NAPI能夠減少IRQ的數量,NAPI讓裝置驅動在驅動初始化時註冊一個poll函式,這個函式能夠被NAPI呼叫。網路裝置驅動中NAPI的使用是這樣的:
(1). NAPI在初始的時候是off狀態,驅動enable它。
(2). 一個數據包到達,網絡卡通過DMA將其傳輸到記憶體中
(3). 一個IRQ由網絡卡產生,IRQ handler由驅動產生
(4). 驅動會通過softirq(軟中斷請求)喚醒NAPI子系統。此時會在一個單獨的執行執行緒中呼叫驅動註冊poll函式收包。
(5). 驅動通過NAPI disable後面的IRQ,這通過NAPI子系統來處理包,無須裝置中斷。
(6). 一旦完成工作,NAPI子系統被disable,IRQ被重新enable
(7). 回到步驟2重新執行2. Softirq
Linux核心中的Softirq系統是一個機制,能夠執行中斷handler上下文外的程式。Softirq在驅動中實現。Softirq很重要,硬體中斷可能會在中斷handler的一部分或全部的過程中被disable。中斷disable時間越長,越可能錯過一些重要事件。Softirq能夠儘可能減少在irq handler裡做的事情,使irq handler儘快返回。把大部分可以延遲做得事情放在softirq裡做。從而儘快完成任務和enable中斷。Softirq系統可以被想象為一系列核心執行緒(每個CPU一個softirq),能夠執行不同softirq事件註冊的handler函式。
參考文獻:
[1] https://blog.packagecloud.io/eng/2016/06/22/monitoring-tuning-linux-networking-stack-receiving-data/#ip-protocol-layer
[2] http://www.cubrid.org/blog/dev-platform/understanding-tcp-ip-network-stack/
[3] http://www.cnblogs.com/sammyliu/p/5225623.html