2013年8月14日 星期三

Network Interface Packet Reception

網路界面驅動程式有兩種接收封包的方式 -- 中斷驅動和 NAPI。傳統是用中斷驅動,在中斷服務程式裡接收封包,但封包量大時會有中斷次數太多而效能變差的問題。NAPI (意思是 New API) 改成中斷服務程式只通知有封包,Kernel 再排程一次接收多個封包來提昇效能。

中斷驅動方式
  • 收到 frame 呼叫中斷服務程式
  • 在中斷服務程式通常依封包大小 dev_alloc_skb() 取得 sk_buff 放入封包,struct net_device *dev 指到網路界面、辨別 protocol (什麼時候用到?)、填寫ip_summed 等參數,最後呼叫 netif_rx()。
  • 每個處理器有個 softnet_data,netif_rx() 將 sk_buff 放到執行中斷處理器的 softnet_data 的 input_pkt_queue。如果原本 input_pkt_queue 是空的,執行netif_rx_schedule() 將 backlog_dev 加到 softnet_data 的 poll_list 並啟用 NET_RX_SOFTIRQ。如果 input_pkt_queue 大於 netdev_max_backlog 表示滿了,則 drop 並回傳 NET_RX_DROP,可知道壅塞程度。
  • 技巧:預先以最大封包為考量取得 skb,讓封包直接接收到 skb。change_mtu() 可知道最大封包大小。
NAPI 用 polling 方式接收封包,底層需要有數個封包的 buffer 放新進封包,當已知有封包進來的情況下,kernel 才擇時去執行 net_device 的 poll 函數並一次將 buffer 中的全部封包接收。這段時間如有新封包再進來,不需要再通知 kernel。當封包流量大時,例如每秒幾千個封包,可以大大減少中斷的次數,降低 kernel 分心。
  • 初始化:net_device 設 poll 函數及 weight,weight 說明界面的重要度,不可超過可 buffer 封包的數目。
  • 封包進來的中斷呼叫 netif_rx_schedule() 就好,kernel 會排程用 poll 去取封包。
  • poll 函數一次最多接收 budget 或 quota 個封包,一樣呼叫 dev_alloc_skb() 取得 skb,放進收到的封包,設定 skb dev、protocol、ip_summed 等參數,但最後是呼叫 netif_receive_skb()。如果接收的封包都處理了,呼叫 netif_rx_complete(),並啟用中斷。
NAPI 有另一個好處,需要拋棄封包時,也可以在收進 kernel 之前就處理掉。例如網路子系統壅塞,可以只收額定的封包。

NAPI 還有更新的改進,從 net_device 獨立出 napi_struct 資料結構,改由驅動程式提供。好處是一個界面可以有多個 napi_struct 來對應硬體支援 multiple receive queues。此外使用的函數也大多不同,如下表:
\中斷驅動NAPINew NAPI
初始化-
  • 登記 net_device poll 函數
  • netif_napi_add() 加入一個 napi_struct 並登記 poll 函數
  • napi_enable
中斷服務程式dev_alloc_skb()
複製封包、設定參數
netif_rx
netif_rx_schedule()napi_schedule()
接收封包dev_alloc_skb()
複製封包、設定參數
netif_receive_skb
buffer 處理完畢-netif_rx_complete()napi_complete()
結束使用--napi_disable()
netif_napi_del()
註:skb 可以事先準備,在初始化時就 dev_alloc_skb

參考:
  1. LDD3 ch17
  2. Newer, newer NAPI
  3. 每個接收封包會在 netif_rx() 或 netif_receive_skb() 執行 netpoll_rx() 一次。
  4. Understanding the Linux Kernel, 3rd Edition 的 4.7 Softirqs and Tasklets (說明 softirq)
相關文章
延伸閱讀
  • Linux Network Scaling: Receiving Packets
    • RSS (Receive Side Scaling)
    • RPS (Receive Packet Steering)
    • RFS (Receive Flow Steering)
    • aRFS (Accelerated Receive Flow Steering)
  • Linux network stack, Packet ingress flow, NAPI interruption coalescence, zero-copy (DMA, mmap())
最後更新 20200721

沒有留言:

張貼留言

SIP header Via

所有 SIP 訊息 都要有 Via,縮寫 v。一開始的 UAC 和後續途經的每個 proxy 都會疊加一個 Via 放傳送的位址,依序作為回應的路徑。 格式 sent-protocol sent-by [ ;branch= branch ][ ; 參數 ...] s...