4. 初始化
圖 1 網(wǎng)絡(luò)設(shè)備在 packet 到達(dá)并需要處理時(shí),通常會(huì)觸發(fā)一個(gè) IRQ。IRQ 處理函數(shù)是在很高的優(yōu)先級(jí)下執(zhí)行的,一般會(huì)阻塞其他 IRQs 的觸發(fā)(譯者注:often blocks additional IRQs from being generated。個(gè)人覺得原文這里并不準(zhǔn)確,中斷上下文中關(guān)中往往只是讓 CPU 不響應(yīng)中斷,而不是讓其他設(shè)備直接不發(fā)出中斷)。故而,設(shè)備驅(qū)動(dòng)中的 IRQ 處理函數(shù)必須越快越好,并將比較耗時(shí)的工作挪到中斷上下文之外去執(zhí)行,這就是為啥會(huì)有軟中斷系統(tǒng)。
linux 內(nèi)核軟中斷系統(tǒng)支持在設(shè)備驅(qū)動(dòng)的中斷上下文之外處理工作。網(wǎng)絡(luò)設(shè)備場(chǎng)景下,軟中斷系統(tǒng)用作處理 incoming packets。內(nèi)核在 boot 階段做軟中斷系統(tǒng)的初始化。 圖 1 對(duì)應(yīng)前文“軟中斷”一節(jié),展示的是軟中斷系統(tǒng)及其 per-CPU 內(nèi)核線程的初始化。 軟中斷系統(tǒng)的初始化流程如下:
spawn_ksoftirqd(kernel/softirq.c)調(diào)用 smpboot_register_percpu_thread(kernel/smpboot.c)創(chuàng)建軟中斷內(nèi)核線程(每個(gè) CPU 一個(gè))。如代碼所示,run_ksoftirqd 作為 smp_hotplug_thread 的 thread_fn,會(huì)在一個(gè) loop 中被執(zhí)行。
ksoftirqd 線程會(huì)在 run_ksoftirqd 中運(yùn)行其 processing loop。
隨后,創(chuàng)建 softnet_data 數(shù)據(jù)結(jié)構(gòu)(前文“struct softnet_data 數(shù)據(jù)結(jié)構(gòu)初始化”一節(jié)),每個(gè) CPU 一個(gè)。此數(shù)據(jù)結(jié)構(gòu)包含在網(wǎng)絡(luò)數(shù)據(jù)處理時(shí)所需要的重要信息。另外還有一個(gè) poll_list,下文會(huì)說。設(shè)備驅(qū)動(dòng)調(diào)用 napi_schedule 或其他 NAPI APIs,將 NAPI poll 數(shù)據(jù)結(jié)構(gòu)添加至 poll_list 上。
net_dev_init 調(diào)用 open_softirq 向軟中斷系統(tǒng)注冊(cè) NET_RX_SOFTIRQ 軟中斷,被注冊(cè)的軟中斷處理函數(shù)是 net_rx_action(前文“軟中斷處理函數(shù)初始化”一節(jié))。軟中斷內(nèi)核線程會(huì)調(diào)用此函數(shù)來處理 packets。
圖 1 中的第 5 - 8 步與數(shù)據(jù)的到達(dá)有關(guān),下一節(jié)會(huì)說。
5. 數(shù)據(jù)到達(dá)
圖 2 數(shù)據(jù)從網(wǎng)絡(luò)上來了(前文“數(shù)據(jù)到達(dá)”一節(jié))! 網(wǎng)絡(luò)數(shù)據(jù)到達(dá) NIC 時(shí),NIC 會(huì)通過 DMA 將 packet 數(shù)據(jù)寫入 RAM。igb 網(wǎng)絡(luò)驅(qū)動(dòng)會(huì)在 RAM 中構(gòu)建一個(gè) ring buffer,其指向接收到的 packets。值得注意的是,有些 NIC 支持 "multiqueue",這些 NIC 可以使用多個(gè)處理器來處理 incoming 網(wǎng)絡(luò)數(shù)據(jù)(前文“準(zhǔn)備從網(wǎng)絡(luò)接收數(shù)據(jù)”一節(jié))。
簡化起見,圖 2 只畫了一個(gè) ring buffer,但取決于 NIC 以及硬件配置,你的系統(tǒng)可能使用的是多個(gè)隊(duì)列。 下面流程的細(xì)節(jié)參閱前文“數(shù)據(jù)到達(dá)”一節(jié)。 我們來過一遍數(shù)據(jù)接收流程:
數(shù)據(jù)從網(wǎng)絡(luò)到達(dá) NIC。
NIC 通過 DMA 將網(wǎng)絡(luò)數(shù)據(jù)寫入 RAM。
NIC 觸發(fā)一個(gè) IRQ。
執(zhí)行設(shè)備驅(qū)動(dòng)注冊(cè)的 IRQ 處理函數(shù)(前文“中斷處理”一節(jié))。
NIC 清除 IRQ,這樣新 packet 到來時(shí)可以繼續(xù)觸發(fā) IRQs。
調(diào)用 napi_schedule 拉起 NAPI 軟中斷 poll loop(前文“NAPI 與 napi_schedule”一節(jié))。
napi_schedule 的調(diào)用觸發(fā)了 圖 1 中的 5 - 8 步。如后面所見,NAPI 軟中斷 poll loop 拉起的原理,就是翻轉(zhuǎn)一個(gè) bit 域,并向 poll_list 上添加一個(gè)數(shù)據(jù)結(jié)構(gòu)。napi_schedule 沒干什么其他事,這就是驅(qū)動(dòng)將處理工作轉(zhuǎn)交給軟中斷系統(tǒng)的原理。
繼續(xù)分析 圖 1,對(duì)照?qǐng)D中相應(yīng)的數(shù)字:
驅(qū)動(dòng)調(diào)用 napi_schedule 將驅(qū)動(dòng)的 NAPI poll 數(shù)據(jù)結(jié)構(gòu)添加至當(dāng)前 CPU 的 poll_list 上。
軟中斷 pending bit 會(huì)被置上,如此該 CPU 上的 ksoftirqd 線程知曉有 packets 需要處理。
執(zhí)行 run_ksoftirqd 函數(shù)(在 ksoftirqd 內(nèi)核線程的 loop 中執(zhí)行)。
調(diào)用 __do_softirq 檢查是否有 pending 的 bit 域,以此確認(rèn)是否有 pending 的軟中斷,進(jìn)而調(diào)用 pending 軟中斷的處理函數(shù):net_rx_action,該函數(shù)干了所有的 incoming 網(wǎng)絡(luò)數(shù)據(jù)處理的臟活。
需要注意的是,軟中斷內(nèi)核線程執(zhí)行的是 net_rx_action,而不是設(shè)備驅(qū)動(dòng)的 IRQ 處理函數(shù)。
6. 網(wǎng)絡(luò)數(shù)據(jù)處理的開始
圖 3 至此開始數(shù)據(jù)的處理。net_rx_action 函數(shù)(在 ksoftirqd 內(nèi)核線程中調(diào)用)會(huì)執(zhí)行當(dāng)前 CPU poll_list 上注冊(cè)的 NAPI poll 數(shù)據(jù)結(jié)構(gòu)。poll 數(shù)據(jù)結(jié)構(gòu)的注冊(cè)一般有兩種情況:
設(shè)備驅(qū)動(dòng)調(diào)用 napi_schedule。
Receive Packet Steering 場(chǎng)景(前文“Receive Packet Steering(RPS)”一節(jié))下使用 Inter-processor Interrupt。
我們將從 poll_list 獲取驅(qū)動(dòng) NAPI 數(shù)據(jù)結(jié)構(gòu)的流程串起來(下一節(jié)會(huì)講 RPS 是怎么通過 IPIs 注冊(cè) NAPI 數(shù)據(jù)結(jié)構(gòu)的)。 圖 3 流程在前文有詳細(xì)拆解過,總結(jié)一下就是:
net_rx_action poll 檢查 NAPI poll list 中的 NAPI 數(shù)據(jù)結(jié)構(gòu)。
校驗(yàn) budget 及消耗的時(shí)間,以確保軟中斷不會(huì)霸占 CPU。
調(diào)用注冊(cè)的 poll 函數(shù)(前文“NAPI poll 函數(shù)及權(quán)重”一節(jié))。本文場(chǎng)景下,igb 驅(qū)動(dòng)注冊(cè)的是 igb_poll 函數(shù)。
驅(qū)動(dòng)的 poll 函數(shù)收取 RAM ring buffer 中的 packets(前文“NAPI poll”一節(jié))。
packets 進(jìn)一步給到 napi_gro_receive,其可能會(huì)進(jìn)一步被 Generic Receive Offloading 處理(前文“Generic Receive Offloading(GRO)”一節(jié))。
packets 要么被 GRO 處理,這樣整個(gè)調(diào)用鏈也就結(jié)束了;要么 packets 通過 net_receive_skb 進(jìn)一步給到上層協(xié)議棧。
下面會(huì)講 net_receive_skb 是怎么實(shí)現(xiàn) Receive Packet Steering,也就是在多個(gè) CPUs 之間分發(fā) packet 的。
7. 網(wǎng)絡(luò)數(shù)據(jù)的進(jìn)一步處理
圖 4 從 netif_receive_skb 開始繼續(xù)網(wǎng)絡(luò)數(shù)據(jù)的處理,數(shù)據(jù)的具體路徑取決于是否使能了 Receive Packet Steering(RPS)。一個(gè)“開箱即用”的 linux 內(nèi)核(譯者注:意思就是通用的發(fā)行版)默認(rèn)是不使能 RPS 的,如果你想用 RPS,就必須顯式地配置及使能之。
RPS 禁能的情況下(前文“禁能 RPS 場(chǎng)景(默認(rèn)配置)”一節(jié)),對(duì)應(yīng) 圖 4 中的如下數(shù)字:
1. netif_receive_skb 將數(shù)據(jù)給到 __netif_receive_core。
6. __netif_receive_core 將數(shù)據(jù)給到系統(tǒng)中可能存在的 taps(前文“packet tap 投遞”一節(jié))(比如 PCAP,https://www.tcpdump.org/manpages/pcap.3pcap.html)。
7. __netif_receive_core 將數(shù)據(jù)給到協(xié)議層注冊(cè)的 handlers(前文“協(xié)議層投遞”一節(jié))。大多數(shù)情況下,此 handler 是 IPv4 協(xié)議棧所注冊(cè)的 ip_rcv 函數(shù)。
RPS 使能的情況下(前文“使能 RPS 場(chǎng)景”一節(jié)):
netif_receive_skb 將數(shù)據(jù)給到 enqueue_to_backlog。
packets 會(huì)被送到 per-CPU 的輸入隊(duì)列上以待后續(xù)處理。
將遠(yuǎn)端 CPU 的 NAPI 數(shù)據(jù)結(jié)構(gòu)添加至該遠(yuǎn)端 CPU 的 poll_list 上,并向該 CPU 發(fā)一個(gè) IPI,進(jìn)而喚醒遠(yuǎn)端 CPU 上的軟中斷內(nèi)核線程(如果其并未在運(yùn)行的話)。
當(dāng)遠(yuǎn)端 CPU 上的 ksoftirqd 內(nèi)核線程運(yùn)行起來后,其處理模式與上一節(jié)中的相同,不同之處是,注冊(cè)進(jìn)來的 poll 函數(shù)是 process_backlog,該函數(shù)會(huì)從當(dāng)前(譯者注:本 CPU) CPU 的輸入隊(duì)列收取 packets。
packets 進(jìn)一步給到 __net_receive_skb_core。
__net_receive_skb_core 將數(shù)據(jù)給到系統(tǒng)中可能存在的 taps(前文“packet tap 投遞”一節(jié))(比如 PCAP)。
__net_receive_skb_core 將數(shù)據(jù)給到協(xié)議層注冊(cè)的 handlers(前文“協(xié)議層投遞”一節(jié))。大多數(shù)情況下,此 handler 是 IPv4 協(xié)議棧所注冊(cè)的 ip_rcv 函數(shù)。
8. 協(xié)議棧及用戶 sockets
數(shù)據(jù)接下來要走的路徑是:協(xié)議棧、netfilter、Berkeley Packet Filters,最終到達(dá)用戶 socket。 雖然代碼路徑挺長的,但是邏輯是直白清晰的。 網(wǎng)絡(luò)數(shù)據(jù)路徑更詳細(xì)地拆解見前文“協(xié)議層注冊(cè)”一節(jié)。下面是 high level 的簡要總結(jié):
IPv4 協(xié)議層通過 ip_rcv 收取 packets。
會(huì)做 netfilter 以及路由優(yōu)化。
目標(biāo)是本機(jī)的數(shù)據(jù),會(huì)進(jìn)一步給到更 high level 的協(xié)議層,比如 UDP。
UDP 協(xié)議層通過 udp_rcv 收取 packets,并通過 udp_queue_rcv_skb 及 sock_queue_rcv 將數(shù)據(jù)入隊(duì)到用戶 socket 的接收 buffer 中。在入隊(duì)到接收 buffer 之前,會(huì)做 Berkeley Packet Filters。
值得注意的是,netfilter 在這個(gè)過程中會(huì)被調(diào)用多次,具體位置參考前文的詳細(xì)拆解(前文“協(xié)議層注冊(cè)”一節(jié))。
9. 總結(jié)
linux 網(wǎng)絡(luò)棧極其復(fù)雜,涉及到的系統(tǒng)很多。如果要監(jiān)控這個(gè)復(fù)雜的系統(tǒng)就必須得搞清楚這些系統(tǒng)之間是怎么交互的,以及對(duì)某一系統(tǒng)配置的調(diào)整,會(huì)如何影響到其他系統(tǒng)。本文作為前文的補(bǔ)充,試圖把這些問題梳理的更清晰易懂一些。
審核編輯:劉清
-
cpu
+關(guān)注
關(guān)注
68文章
10911瀏覽量
213152 -
Linux系統(tǒng)
+關(guān)注
關(guān)注
4文章
596瀏覽量
27526 -
IRQ
+關(guān)注
關(guān)注
0文章
16瀏覽量
10804 -
中斷系統(tǒng)
+關(guān)注
關(guān)注
1文章
96瀏覽量
61079
原文標(biāo)題:圖解之 linux 網(wǎng)絡(luò)棧監(jiān)控及調(diào)優(yōu):數(shù)據(jù)接收
文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
深度解析Linux網(wǎng)絡(luò)路徑及sk_buff struct 數(shù)據(jù)結(jié)構(gòu)
![深度解析<b class='flag-5'>Linux</b><b class='flag-5'>網(wǎng)絡(luò)</b>路徑及sk_buff struct <b class='flag-5'>數(shù)據(jù)</b>結(jié)構(gòu)](https://file.elecfans.com/web1/M00/CB/E1/pIYBAF-RLQ2Aa1OcAAN6CtpJiSg788.png)
Linux網(wǎng)絡(luò)棧原理與實(shí)現(xiàn)
基于全HDD aarch64服務(wù)器的Ceph性能調(diào)優(yōu)實(shí)踐總結(jié)
infosphere CDC 性能調(diào)優(yōu)及MC性能指標(biāo)監(jiān)控
![infosphere CDC 性能<b class='flag-5'>調(diào)</b><b class='flag-5'>優(yōu)</b>及MC性能指標(biāo)<b class='flag-5'>監(jiān)控</b>](https://file.elecfans.com/web2/M00/49/AD/pYYBAGKhvE2AQmCjAABMYnEt5ak341.png)
機(jī)器學(xué)習(xí)如何調(diào)優(yōu)數(shù)據(jù)庫
![機(jī)器學(xué)習(xí)如何<b class='flag-5'>調(diào)</b><b class='flag-5'>優(yōu)</b><b class='flag-5'>數(shù)據(jù)</b>庫](https://file1.elecfans.com//web2/M00/A6/DE/wKgZomUMQPqAUrCDAAASXDmfMDQ541.gif)
如何對(duì)電機(jī)進(jìn)行調(diào)優(yōu)?調(diào)優(yōu)的好處是什么?
Linux網(wǎng)絡(luò)包接收過程的監(jiān)控與調(diào)優(yōu)
Linux查看資源使用情況和性能調(diào)優(yōu)常用的命令
Linux用電功耗調(diào)優(yōu)的筆記分享
Linux性能調(diào)優(yōu)常見工具和堆棧解析
![<b class='flag-5'>Linux</b>性能<b class='flag-5'>調(diào)</b><b class='flag-5'>優(yōu)</b>常見工具和堆棧解析](https://file1.elecfans.com/web2/M00/8B/A9/wKgaomSc4k-AZtY8AABKf0ewwI0500.png)
Linux網(wǎng)絡(luò)技術(shù)棧的相關(guān)知識(shí)
![<b class='flag-5'>Linux</b><b class='flag-5'>網(wǎng)絡(luò)</b>技術(shù)<b class='flag-5'>棧</b>的相關(guān)知識(shí)](https://file1.elecfans.com/web2/M00/95/22/wKgZomTmwfKAMWT2AAAzpRD3428798.png)
jvm調(diào)優(yōu)參數(shù)
jvm調(diào)優(yōu)主要是調(diào)哪里
jvm調(diào)優(yōu)工具有哪些
Linux網(wǎng)絡(luò)協(xié)議棧的實(shí)現(xiàn)
![<b class='flag-5'>Linux</b><b class='flag-5'>網(wǎng)絡(luò)</b>協(xié)議<b class='flag-5'>棧</b>的實(shí)現(xiàn)](https://file1.elecfans.com/web2/M00/06/C6/wKgaombfpT-AeVQcAACjr17dpiQ190.png)
評(píng)論