Linux 網卡收包流程如下
網卡收到數據包
將數據包從網卡硬件緩存移動到服務器內存中(DMA方式,不經過CPU)
通過硬中斷通知CPU處理
CPU通過軟中斷通知內核處理
經過TCP/IP協議棧處理
應用程序通過read()從socket buffer讀取數據
網卡丟包
我們先看下ifconfig的輸出:
# ifconfig eth0 eth0: flags=4163mtu 1500 inet 10.5.224.27 netmask 255.255.255.0 broadcast 10.5.224.255 inet6 fe80::5054fea4:44ae prefixlen 64 scopeid 0x20 ether 52:54:00:a4:44:ae txqueuelen 1000 (Ethernet) RX packets 9525661556 bytes 10963926751740 (9.9 TiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 8801210220 bytes 12331600148587 (11.2 TiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0Copy
登錄系統底層,檢查管理網網卡收發是否存在持續增長的errors包,使用命令:
# watch -n 1 "ifconfig eth0" # watch -n 1 ip -s link show eth0 說明:watch可以將命令的輸出結果輸出到標準輸出設備,多用于周期性執行命令/定時執行命令,-n或-interval來指定間隔的時間,缺省每2秒運行一下程序;eth1為網卡名稱。
正常的
異常的
RX(receive) 代表接收報文, TX(transmit) 表示發送報文。
RX errors: 表示總的收包的錯誤數量,這包括 too-long-frames 錯誤,Ring Buffer 溢出錯誤,crc 校驗錯誤,幀同步錯誤,fifo overruns 以及 missed pkg 等等。
RX dropped: 表示數據包已經進入了 Ring Buffer,但是由于內存不夠等系統原因,導致在拷貝到內存的過程中被丟棄。
RX overruns: 表示 fifo 的 overruns,由于 Ring Buffer(aka Driver Queue) 傳輸的 IO 大于 kernel 能夠處理的 IO 導致的,而 Ring Buffer 則是指在發起 IRQ 請求之前的那塊 buffer。很明顯,overruns 的增大意味著數據包沒到 Ring Buffer 就被網卡物理層給丟棄了,CPU 無法及時的處理中斷是造成 Ring Buffer 滿的原因之一,可能原因是因為 interruprs 分布的不均勻,沒有做 affinity 而造成的丟包。
RX frame: 表示 misaligned 的 frames。
dropped 與 overruns 的區別:
dropped,表示這個數據包已經進入到網卡的接收緩存 fifo 隊列,并且開始被系統中斷處理準備進行數據包拷貝(從網卡緩存 fifo 隊列拷貝到系統內存),但由于此時的系統原因(比如內存不夠等)導致這個數據包被丟掉,即這個數據包被 Linux 系統丟掉。
overruns,表示這個數據包還沒有被進入到網卡的接收緩存 fifo 隊列就被丟掉,因此此時網卡的 fifo 是滿的。為什么 fifo 會是滿的?因為系統繁忙,來不及響應網卡中斷,導致網卡里的數據包沒有及時的拷貝到系統內存, fifo 是滿的就導致后面的數據包進不來,即這個數據包被網卡硬件丟掉。所以,如果遇到 overruns 非0,需要檢測cpu負載與cpu中斷情況。
環形隊列Ring Buffer溢出
當網卡的緩存區(ring buffer)設置的太小。網絡數據包到達(生產)的速率快于內核處理(消費)的速率時, Ring Buffer 很快會被填滿,新來的數據包將被丟棄。
通過 ethtool 或 /proc/net/dev 可以查看因Ring Buffer滿而丟棄的包統計
[root@xxx ~]# ethtool -S ens2 | grep fifo rx_fifo_errors: 0 tx_fifo_errors: 0 [root@xxx ~]# cat /proc/net/dev | grep ens2 ens2: 659229 8107 0 0 0 0 0 0 249827 2833 0 0 0 0 0 0
可以通過ethtool 設置ring buffer 的緩沖區大小
# 修改網卡eth0接收與發送硬件緩存區大小 $ ethtool -G eth0 rx 4096 tx 4096 Pre-set maximums: RX: 4096 RX Mini: 0 RX Jumbo: 0 TX: 4096 Current hardware settings: RX: 4096 RX Mini: 0 RX Jumbo: 0 TX: 4096
中斷過程中的問題
什么是中斷
中斷有兩種:一種硬中斷;一種軟中斷。硬中斷是由硬件產生的,比如,像磁盤,網卡,鍵盤;軟中斷是由當前正在運行的進程所產生的。
硬中斷,是一種由硬件產生的電信號直接發送到中斷控制器上,然后由中斷控制器向 CPU 發送信號,CPU 檢測到該信號后,會中斷當前的工作轉而去處理中斷。然后,處理器會通知內核已經產生中斷,這樣內核就會對這個中斷進行適當的處理。
當網卡收到數據包時會產生中斷請求(硬中斷)通知到 CPU,CPU 會中斷當前正在運行的任務,然后通知內核有新數據包,內核調用中斷處理程序(軟中斷)進行響應,把數據包從網卡緩存及時拷貝到內存,否則會因為緩存溢出被丟棄。剩下的處理和操作數據包的工作就會交給軟中斷。
什么是多隊列網卡
當網卡不斷的接收數據包,就會產生很多中斷,一個中斷請求只能被一個CPU處理, 而現在的機器都是用多個CPU,同時只有一個 CPU 去處理 Ring Buffer 數據會很低效,這個時候就產生了叫做 Receive Side Scaling(RSS) 或者叫做 multiqueue 的機制來處理這個問題, 這就是為啥需要多隊列的原因。
RSS(Receive Side Scaling)是網卡的硬件特性,實現了多隊列。通過多隊列網卡驅動加載,獲取網卡型號,得到網卡的硬件 queue 的數量,并結合 CPU 核的數量,最終通過 Sum=Min(網卡 queue,CPU core)得出所要激活的網卡 queue 數量。
NIC 收到 Frame 的時候能通過 Hash Function 來決定 Frame 該放在哪個 Ring Buffer 上,觸發的 IRQ 也可以通過操作系統或者手動配置 IRQ affinity 將 IRQ 分配到多個 CPU 上。這樣 IRQ 能被不同的 CPU 處理,從而做到 Ring Buffer 上的數據也能被不同的 CPU 處理,從而提高數據的并行處理能力。
RSS 除了會影響到 NIC 將 IRQ 發到哪個 CPU 之外,不會影響別的邏輯。
什么是RPS
Receive Packet Steering(RPS) 是在 NIC 不支持 RSS 時候在軟件中實現 RSS 類似功能的機制。其好處就是對 NIC 沒有要求,任何 NIC 都能支持 RPS,但缺點是 NIC 收到數據后 DMA 將數據存入的還是一個 Ring Buffer,NIC 觸發 IRQ 還是發到一個 CPU,還是由這一個 CPU 調用 driver 的 poll 來將 Ring Buffer 的數據取出來。RPS 是在單個 CPU 將數據從 Ring Buffer 取出來之后才開始起作用,它會為每個 Packet 計算 Hash 之后將 Packet 發到對應 CPU 的 backlog 中,并通過 Inter-processor Interrupt(IPI) 告知目標 CPU 來處理 backlog。后續 Packet 的處理流程就由這個目標 CPU 來完成。從而實現將負載分到多個 CPU 的目的。通常如果開啟了RPS會加重所有 CPU 的負擔.
IRQ 中斷請求 親和綁定
/proc/interrupts 文件中可以看到各個 CPU 上的中斷情況。
/proc/irq/[irq_num]/smp_affinity_list 可以查看指定中斷當前綁定的 CPU。
可以通過配置 IRQ affinity 指定 IRQ 由哪個 CPU 來處理中斷, 先通過 /proc/interrupts 找到 IRQ 號之后,將希望綁定的 CPU 號寫入 /proc/irq/IRQ_NUMBER/smp_affinity,寫入的是 16 進制的 bit mask。比如看到隊列 rx_0 對應的中斷號是 41 那就執行:
echo 6 > /proc/irq/41/smp_affinity 6 表示的是 CPU2 和 CPU1
0 號 CPU 的掩碼是 0x1 (0001),1 號 CPU 掩碼是 0x2 (0010),2 號 CPU 掩碼是 0x4 (0100),3 號 CPU 掩碼是 0x8 (1000) 依此類推。
softirq 數統計
通過 /proc/softirqs 能看到每個 CPU 上 softirq 數量統計:
cat /proc/softirqs CPU0 CPU1 HI: 1 0 TIMER: 1650579324 3521734270 NET_TX: 10282064 10655064 NET_RX: 3618725935 2446 BLOCK: 0 0 BLOCK_IOPOLL: 0 0 TASKLET: 47013 41496 SCHED: 1706483540 1003457088 HRTIMER: 1698047 11604871 RCU: 4218377992 3049934909
NET_RX 表示網卡收到包時候觸發的 softirq,一般看這個統計是為了看看 softirq 在每個 CPU 上分布是否均勻,不均勻的話可能就需要做一些調整。比如上面看到 CPU0 和 CPU1 兩個差距很大,原因是這個機器的 NIC 不支持 RSS,沒有多個 Ring Buffer。開啟 RPS 后就均勻多了。
如何開啟RPS
RPS 默認是關閉的,當機器有多個 CPU 并且通過 softirqs 的統計 /proc/softirqs 發現 NET_RX 在 CPU 上分布不均勻或者發現網卡不支持 mutiqueue 時,就可以考慮開啟 RPS。
開啟 RPS 需要調整 /sys/class/net/DEVICE_NAME/queues/QUEUE/rps_cpus 的值。比如執行:
echo f > /sys/class/net/eth0/queues/rx-0/rps_cpus
表示的含義是處理網卡 eth0 的 rx-0 隊列的 CPU 數設置為 f 。即設置有 15 個 CPU 來處理 rx-0 這個隊列的數據,如果你的 CPU 數沒有這么多就會默認使用所有 CPU 。
netdev_max_backlog調優
netdev_max_backlog 是內核從 NIC 收到包后,交由協議棧(如 IP、TCP )處理之前的緩沖隊列, 通過softnet_stat可以確定是否發生了netdev backlog隊列溢出
[root@xxx ~]# cat /proc/net/softnet_stat 000000bf 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000028 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 000000c7 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000031 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 000021d8 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000929 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
C#復制全屏
每一行代表每個 CPU 核的狀態統計,從 CPU0 依次往下。 每一列代表一個 CPU 核的各項統計:第一列代表中斷處理程序收到的包總數;第二列即代表由于 netdev_max_backlog 隊列溢出而被丟棄的包總數。 第3列表示軟中斷一次取走netdev_budget個數據包,或取數據包時間超過2ms的次數。 第4~8列固定為0,沒有意義。 第9列表示發送數據包時,對應的隊列被鎖住的次數。
netdev_max_backlog 的默認值是 1000,我們可以修改內核參數來調優:
sysctl -w net.core.netdev_max_backlog=2000
鏈接:https://www.cnblogs.com/OpenSourceSite/p/18121680
-
Linux
+關注
關注
87文章
11459瀏覽量
212787 -
網卡
+關注
關注
4文章
323瀏覽量
27846
原文標題:Linux之網絡排錯
文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
hyper 網卡,hyper 網卡的實操流程,hyper-v批量管理工具的使用指南

快速入門!RNDIS網卡實現USB上網~

Linux運維必備技能:手把手教你用tcpdump精準抓包
為什么你的網卡工作會不正常?(上)

RZ T2H PCIe裸機程序開發和Linux下的配置介紹

linux網卡配置文件
ubuntu ping 開發板存在嚴重的丟包情況,請問該怎么解決?
怎么在Linux上劃分VLAN

網卡的演進和應用

服務器網卡和普通網卡區別
【免費分享】嵌入式Linux開發板【入門+項目,應用+底層】資料包一網打盡,附教程/視頻/源碼...

千兆網卡的概述與應用

評論