网卡驱动收发包过程图解
網卡
網卡工作在物理層和數據鏈路層,主要由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
總結
以上是生活随笔為你收集整理的网卡驱动收发包过程图解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何使用迭代器Iterator与增强fo
- 下一篇: 基于Proteus的51单片机超声波测距