天天看點

網卡驅動收發包過程圖解

網卡

網卡工作在實體層和資料鍊路層,主要由PHY/MAC晶片、Tx/Rx FIFO、DMA等組成,其中網線通過變壓器接PHY晶片、PHY晶片通過MII接MAC晶片、MAC晶片接PCI總線

PHY晶片主要負責:CSMA/CD、模數轉換、編解碼、串并轉換

MAC晶片主要負責:

1. 比特流和幀的轉換:7位元組的前導碼Preamble和1位元組的幀首定界符SFD

2. CRC校驗

3. Packet Filtering:L2 Filtering、VLAN Filtering、Manageability / Host Filtering

Intel的千兆網卡以82575/82576為代表、萬兆網卡以82598/82599為代表

收發包過程圖

ixgbe_adapter包含ixgbe_q_vector數組(一個ixgbe_q_vector對應一個中斷),ixgbe_q_vector包含napi_struct

硬中斷函數把napi_struct加入CPU的poll_list,軟中斷函數net_rx_action()周遊poll_list,執行poll函數

網卡驅動收發包過程圖解

發包過程

網卡驅動收發包過程圖解

1、網卡驅動建立tx descriptor ring(一緻性DMA記憶體),将tx descriptor ring的總線位址寫入網卡寄存器TDBA

2、協定棧通過dev_queue_xmit()将sk_buff下送網卡驅動

3、網卡驅動将sk_buff放入tx descriptor ring,更新TDT

4、DMA感覺到TDT的改變後,找到tx descriptor ring中下一個将要使用的descriptor

5、DMA通過PCI總線将descriptor的資料緩存區複制到Tx FIFO

6、複制完後,通過MAC晶片将資料包發送出去

7、發送完後,網卡更新TDH,啟動硬中斷通知CPU釋放資料緩存區中的資料包

Tx Ring Buffer

收包過程

網卡驅動收發包過程圖解

1、網卡驅動建立rx descriptor ring(一緻性DMA記憶體),将rx descriptor ring的總線位址寫入網卡寄存器RDBA

2、網卡驅動為每個descriptor配置設定sk_buff和資料緩存區,流式DMA映射資料緩存區,将資料緩存區的總線位址儲存到descriptor

3、網卡接收資料包,将資料包寫入Rx FIFO

4、DMA找到rx descriptor ring中下一個将要使用的descriptor

5、整個資料包寫入Rx FIFO後,DMA通過PCI總線将Rx FIFO中的資料包複制到descriptor的資料緩存區

6、複制完後,網卡啟動硬中斷通知CPU資料緩存區中已經有新的資料包了,CPU執行硬中斷函數:

  • NAPI(以e1000網卡為例):e1000_intr() -> __napi_schedule() -> __raise_softirq_irqoff(NET_RX_SOFTIRQ)
  • 非NAPI(以dm9000網卡為例):dm9000_interrupt() -> dm9000_rx() -> netif_rx() -> napi_schedule() -> __napi_schedule() -> __raise_softirq_irqoff(NET_RX_SOFTIRQ)

7、ksoftirqd執行軟中斷函數net_rx_action():

  • NAPI(以e1000網卡為例):net_rx_action() -> e1000_clean() -> e1000_clean_rx_irq() -> e1000_receive_skb() -> netif_receive_skb()
  • 非NAPI(以dm9000網卡為例):net_rx_action() -> process_backlog() -> netif_receive_skb()

8、網卡驅動通過netif_receive_skb()将sk_buff上送協定棧

Rx Ring Buffer

軟體(SW)向從next_to_use開始的N個descriptor補充sk_buff,next_to_use += N,tail = next_to_use - 1(設定網卡寄存器RDT)

硬體(HW)向從head開始的M個descriptor的sk_buff複制資料包并設定DD,head += M

SW将從next_to_clean的開始的L個sk_buff移出Rx Ring Buffer交給協定棧,next_to_clean += L,向從next_to_use開始的L個descriptor補充sk_buff,next_to_use += L,tail = next_to_use - 1

注意:每次補充完sk_buff以後,tail、next_to_use、next_to_clean三者都是緊挨着的

網卡驅動收發包過程圖解

中斷上下部

網卡驅動收發包過程圖解

do_IRQ()是CPU處理硬中斷的總入口,在do_IRQ()中調用硬中斷函數

網卡驅動收發包過程圖解

netif_rx()

在netif_rx()中把skb加入CPU的softnet_data

網卡驅動收發包過程圖解

RSS + FDIR

FDIR(Flow Director)的優先級高于RSS(Receive Side Scaling)

RSS通過計算包的五元組(sip、sport、dip、dport、protocol)的hash并取餘,得到隊列的index,然後将包放入這個隊列,實作了資料包在各個隊列之間的負載均衡,不過RSS不能保證回包也落在同一個隊列上

對稱hash(sip/sport和dip/dport交換後hash不變)可以部分解決該問題,但是對于一些需要做NAT的裝置(比如負載均衡)就失效了,FDIR可以完全解決該問題,參見https://tech.meituan.com/MGW.html

網卡驅動收發包過程圖解

--------------------- 

原文:https://blog.csdn.net/hz5034/article/details/79794615?utm_source=copy 

繼續閱讀