中斷驅動方式
- 收到 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() 可知道最大封包大小。
- 初始化: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 還有更新的改進,從 net_device 獨立出 napi_struct 資料結構,改由驅動程式提供。好處是一個界面可以有多個 napi_struct 來對應硬體支援 multiple receive queues。此外使用的函數也大多不同,如下表:
| \ | 中斷驅動 | NAPI | New NAPI |
|---|---|---|---|
| 初始化 | - |
|
|
| 中斷服務程式 | 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() |
參考:
- LDD3 ch17
- Newer, newer NAPI
- 每個接收封包會在 netif_rx() 或 netif_receive_skb() 執行 netpoll_rx() 一次。
- 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())
沒有留言:
張貼留言