官方文檔查看地址:
http://doc.dpdk.org/guides/prog_guide/kernel_nic_interface.html
PDF下載地址:
https://www.intel.com/content/www/us/en/embedded/technology/packet-processing/dpdk/dpdk-programmers-guide.html
本篇難度係數:
翻譯:☆☆☆☆☆
理解:★★☆☆☆
34. 內核網卡接口
DPDK內核網卡接口(KNI:Kernel NIC Interface)允許用戶空間應用程序訪問Linux*控制平面。
使用DPDK KNI的好處如下:
- 比現有的Linux TUN/TAP接口更快(通過消除系統調用和
copy_to_user()/copy_from_user()
操作)。 - 允許使用標準的Linux net工具(如ethtool、ifconfig和tcpdump)管理DPDK端口。
- 允許與內核網絡堆棧的接口。
使用DPDK內核NIC接口的應用程序的組件如圖34.2所示。
圖34.2 DPDK KNI應用程序的組件 Fig. 34.2 Components of a DPDK KNI Application
34.1DPDK KNI內核模塊
KNI內核可加載模塊rte_kni爲DPDK應用程序提供內核接口。
加載rte_kni
模塊後,它將創建一個設備/dev/kni, DPDK KNI API函數使用該設備來控制內核模塊並與內核模塊通信。
rte_kni內核模塊包含幾個可選參數,可以在加載模塊時指定這些參數來控制其行爲:
# modinfo rte_kni.ko
<snip>
parm: lo_mode: KNI loopback mode (default=lo_mode_none):
lo_mode_none Kernel loopback disabled
lo_mode_fifo Enable kernel loopback with fifo
lo_mode_fifo_skb Enable kernel loopback with fifo and skb buffer
(charp)
parm: kthread_mode: Kernel thread mode (default=single):
single Single kernel thread mode enabled.
multiple Multiple kernel thread mode enabled.
(charp)
parm: carrier: Default carrier state for KNI interface (default=off):
off Interfaces will be created with carrier state set to off.
on Interfaces will be created with carrier state set to on.
(charp)
在沒有任何可選參數的情況下加載rte_kni內核模塊是DPDK應用程序將數據包進出內核網絡堆棧的典型方式。在沒有任何參數的情況下,僅爲內核端接收數據包的所有KNI設備創建一個內核線程,禁用環回模式,並將KNI接口的默認載波狀態設置爲off。
# insmod kmod/rte_kni.ko
34.1.1環回模式
測試時,可以通過指定lo_mode
參數,在loopback模式下加載rte_kni
內核模塊:
# insmod kmod/rte_kni.ko lo_mode=lo_mode_fifo
lo_mode_fifo
loopback選項將在內核空間中循環回ring入/出隊列操作。
# insmod kmod/rte_kni.ko lo_mode=lo_mode_fifo_skb
lo_mode_fifo_skb
loopback選項將回ring入/出隊列操作和內核空間中的sk緩衝區副本。
如果沒有指定lo_mode
參數,則禁用環回模式。
34.1.2內核線程模式
爲了提供性能的靈活性,可以使用kthread_mode
參數加載rte_kni
內核模塊。rte_kni
內核模塊支持兩個選項:“單內核線程”模式和“多內核線程”模式。
啓用單內核線程模式如下:
# insmod kmod/rte_kni.ko kthread_mode=single
此模式將僅爲所有KNI接口創建一個內核線程,以便在內核端接收數據。默認情況下,這個內核線程不綁定到任何特定的內核,但是當創建第一個KNI接口時,用戶可以通過在struct rte_kni_conf
中設置core_id
和force_bind
參數來爲這個內核線程設置核心關聯:
爲了獲得最佳性能,內核線程應該綁定到與應用程序中使用的DPDK lcore相同套接字中的CPU核心。
還可以將KNI內核模塊配置爲爲DPDK應用程序創建的每個KNI接口啓動單獨的內核線程。啓用多內核線程模式如下:
# insmod kmod/rte_kni.ko kthread_mode=multiple
該模式將爲每個KNI接口創建一個單獨的內核線程,以便在內核端接收數據。創建每個KNI接口時,可以通過在struct rte_kni_conf中設置core_id和force_bind參數來指定每個kni_thread內核線程的核心關聯性。
如果主機系統上有足夠的未使用內核可用,多內核線程模式可以提供可伸縮的更高性能。
如果沒有指定kthread_mode
參數,則使用“單內核線程”模式。
34.1.3默認的載體(載波?)狀態
rte_kni內核模塊創建的KNI接口的默認載波狀態在加載模塊時通過載波選項進行控制。
如果指定載波=off,內核模塊將在啓用接口管理時關閉接口的載波狀態。DPDK應用程序可以使用rte_kni_update_link()函數設置KNI接口的載波狀態。這對於DPDK應用程序非常有用,因爲DPDK應用程序要求KNI接口的載波狀態反映相應物理NIC端口的實際鏈路狀態。
如果指定carrier=on
,內核模塊將在啓用接口管理時自動將接口的載波狀態設置爲up。這對於DPDK應用程序非常有用,這些應用程序使用KNI接口作爲一個純虛擬接口,它不對應於任何物理硬件,並且不希望使用rte_kni_update_link()
顯式地設置接口的載波狀態。在NIC端口可能沒有物理連接到任何東西的環回模式下進行測試也非常有用。
將默認載波狀態設爲on:
# insmod kmod/rte_kni.ko carrier=on
要將默認載波狀態設置爲off:
# insmod kmod/rte_kni.ko carrier=off
如果沒有指定載波參數,KNI接口的默認載波狀態將被設置爲off。
34.2創建和刪除KNI
在創建任何KNI接口之前,必須將rte_kni內核模塊加載到內核中,並使用rte_kni_init()
函數進行配置。
KNI接口由DPDK應用程序通過rte_kni_alloc()
函數動態創建。
struct rte_kni_conf
結構包含一些字段,允許用戶指定接口名稱、設置MTU大小、設置顯式或隨機的MAC地址,並控制內核Rx線程的關聯性(單線程和多線程模式)。默認情況下,KNI示例示例從匹配的設備獲取MTU,在KNI PMD的情況下,它是從mbuf緩衝區長度派生的。
struct rte_kni_ops
結構包含指向處理rte_kni
內核模塊請求的函數的指針。當KNI接口由應用程序外部的控制命令或函數操作時,這些函數允許DPDK應用程序執行操作。
例如,DPDK應用程序可能希望在用戶啓用/禁用帶有ip link set [up|down] dev <ifaceX>
的KNI接口時啓用/禁用物理NIC端口。DPDK應用程序可以爲config_network_if
註冊一個回調函數,當接口管理狀態發生更改時將調用這個回調函數。
目前有四個回調函數可供用戶註冊應用程序功能:
- config_network_if:
當KNI接口的管理狀態發生更改時調用。例如,當用戶運行ip link set [up|down] dev <ifaceX>
。 - change_mtu:
當用戶更改KNI接口的MTU大小時調用。例如,當用戶運行ip link set [up|down] dev <ifaceX>
- config_mac_address:
當用戶更改KNI接口的MAC地址時調用。例如,當用戶運行ip link set [up|down] dev <ifaceX>
時。如果用戶將這個回調函數設置爲NULL,但是將port_id
字段設置爲-1以外的值,那麼將調用rte_kni
庫kni_config_mac_address()
中的一個默認回調處理程序,它將在指定的port_id
上調用rte_eth_dev_default_mac_addr_set()
。
爲了運行這些回調,應用程序必須定期調用rte_kni_handle_request()
函數。任何已註冊的用戶回調函數都將直接從rte_kni_handle_request()
中調用,因此必須注意防止死鎖和不阻塞任何DPDK fastpath任務。通常,使用這些回調的DPDK應用程序需要創建一個單獨的線程或輔助進程來定期調用rte_kni_handle_request()
。
使用rte_kni_release()
的DPDK應用程序可以刪除KNI接口。當/dev/kni
設備關閉時,所有未顯式刪除的KNI接口都將被刪除,要麼使用rte_kni_close()
顯式刪除,要麼在DPDK應用程序關閉時刪除。
34.3.DPDK mbuf Flow
爲了最小化內核空間中運行的DPDK代碼量,mbuf mempool只在用戶空間中管理。內核模塊將知道mbuf,但是所有mbuf分配和自由操作將只由DPDK應用程序處理。
Fig. 34.3給出了數據包雙向發送的典型場景。
Fig. 34.3 Packet Flow via mbufs in the DPDK KNI
34.4用例:入口
在DPDK RX端,mbuf由PMD在RX線程上下文中分配。這個線程將在rx_q FIFO中對mbuf進行排隊。KNI線程將輪詢rx_q的所有KNI活動設備。如果mbuf退出隊列,它將被轉換爲sk_buff並通過netif_rx()發送到網絡堆棧。離開隊列的mbuf必須被釋放,因此在free_q FIFO中返回相同的指針。
在同一個主循環中,RX線程輪詢這個FIFO,並在退出隊列後釋放mbuf。
34.5用例:出口
爲了使數據包退出,DPDK應用程序必須首先對幾個mbuf進行排隊,以便在內核端創建一個mbuf緩存。
通過調用kni_net_tx()
回調函數,可以從Linux網絡堆棧接收數據包。mbuf被排出隊列(由於緩存而不用等待),並填充來自sk_buff的數據。然後釋放sk_buff,並在tx_q FIFO中發送mbuf。
DPDK TX線程退出mbuf隊列,並通過rte_eth_tx_burst()
將其發送到PMD。然後將mbuf放回緩存中。
34.6. Ethtool
Ethtool是一個特定於linux的工具,在內核中有相應的支持,每個網絡設備必須爲支持的操作註冊自己的回調。當前的實現使用igb/ixgbe修改後的Linux驅動程序來支持ethtool。在i40e和VMs (VF或EM設備)中不支持Ethtool。