linux網絡數據包的網卡驅動收發包過程(六)

網卡

網卡工作在物理層和數據鏈路層,主要由PHY/MAC芯片、Tx/Rx FIFO、DMA等組成,其中網線通過變壓器接PHY芯片、PHY芯片通過MII接MAC芯片、MAC芯片接PCI總線

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

MAC芯片主要負責:

  • 比特流和幀的轉換:7字節的前導碼Preamble和1字節的幀首定界符SFD
  • CRC校驗
  • 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

SW將sk_buff掛載到從next_to_use開始的N個descriptor,next_to_use += N,tail = next_to_use(寫網卡寄存器TDT)

HW使用DMA讀從head開始的M個descriptor的sk_buff,發送成功後回寫DD(Descriptor Done),head += M

SW將從next_to_clean的開始的L個sk_buff移出Tx Ring Buffer並清理,next_to_clean += L

注意:每次掛載完sk_buff後,tail和next_to_use指向同一個descriptor
在這裏插入圖片描述

收包過程

在這裏插入圖片描述
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(寫網卡寄存器RDT)

HW寫Frame到從head開始的M個descriptor的sk_buff,寫完後回寫EOP(End of Packet),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

注意:每次補充完sk_buff後,tail和next_to_use指向同一個sk_buff

在這裏插入圖片描述

中斷上下部

在這裏插入圖片描述

do_IRQ()

do_IRQ()是CPU處理硬中斷的總入口

// 在e1000_request_irq()中註冊硬中斷,中斷函數爲e1000_intr()
irq_handler_t handler = e1000_intr;
err = request_irq(adapter->pdev->irq, handler, irq_flags, netdev->name,
                  netdev);

// 在net_dev_init()中註冊軟中斷,中斷函數爲net_rx_action()
open_softirq(NET_RX_SOFTIRQ, net_rx_action);
 
// 在e1000_probe()中註冊napi的poll函數爲e1000_clean()
netif_napi_add(netdev, &adapter->napi, e1000_clean, 64);
 
// 在net_dev_init()中註冊非napi的poll函數爲process_backlog()
queue->backlog.poll = process_backlog;

netif_rx()

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

int netif_rx(struct sk_buff *skb)
{
   struct softnet_data *queue;
   unsigned long flags;
 
   /* if netpoll wants it, pretend we never saw it */
   if (netpoll_rx(skb))
      return NET_RX_DROP;
 
   if (!skb->tstamp.tv64)
      net_timestamp(skb);
 
   /*
    * The code is rearranged so that the path is the most
    * short when CPU is congested, but is still operating.
    */
   local_irq_save(flags);
   queue = &__get_cpu_var(softnet_data); // 得到CPU的softnet_data
 
   __get_cpu_var(netdev_rx_stat).total++;
   if (queue->input_pkt_queue.qlen <= netdev_max_backlog) { // 若隊列長度不大於netdev_max_backlog
      if (queue->input_pkt_queue.qlen) { // 若隊列長度非0,表示queue->backlog已被加入poll_list
enqueue:
         __skb_queue_tail(&queue->input_pkt_queue, skb); // 將skb加入隊列尾部
         local_irq_restore(flags);
         return NET_RX_SUCCESS;
      }
 
      napi_schedule(&queue->backlog); // 調度queue->backlog
      goto enqueue; // 將skb加入隊列尾部
   }
 
   __get_cpu_var(netdev_rx_stat).dropped++;
   local_irq_restore(flags);
 
   kfree_skb(skb);
   return NET_RX_DROP;
}

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章