官方文檔查看地址:
http://doc.dpdk.org/guides/sample_app_ug/kernel_nic_interface.html
PDF下載地址:
https://www.intel.com/content/www/us/en/embedded/technology/packet-processing/dpdk/dpdk-sample-applications-user-guide.html
本篇難度係數:
翻譯:☆☆☆☆☆
理解:★★☆☆☆
14.內核NIC接口示例應用程序
內核NIC接口(KNI)是一種DPDK控制平面解決方案,允許用戶空間應用程序與內核網絡堆棧交換數據包。爲實現此目的,DPDK用戶空間應用程序使用IOCTL調用來請求在Linux *內核中創建KNI虛擬設備。IOCTL調用提供接口信息和DPDK的物理地址空間,由KNI內核可加載模塊重新映射到內核地址空間,該模塊將信息保存到虛擬設備上下文。DPDK爲每個分配的設備創建用於數據包入口和出口到內核模塊的FIFO隊列。
KNI內核可加載模塊是標準網絡驅動程序,在接收到IOCTL調用後,訪問DPDK的FIFO隊列以從/向DPDK用戶空間應用程序接收/發送數據包。FIFO隊列包含指向DPDK中數據包的指針。這個:
- 提供更快的機制來與內核網絡堆棧連接並消除系統調用
- 使用標準Linux *用戶空間網絡工具(tcpdump,ftp等)爲DPDK提供便利
- 消除對數據包的copy_to_user和copy_from_user操作。
內核NIC接口示例應用程序是一個簡單的示例,演示如何使用DPDK創建數據包通過Linux *內核的路徑。這是通過爲每個DPDK端口創建一個或多個內核網絡設備來完成的。該應用程序允許使用標準Linux工具(ethtool,ifconfig,tcpdump)與DPDK端口以及DPDK應用程序和Linux *內核之間的數據包交換。
內核NIC接口示例應用程序要求將KNI內核模塊rte_kni
加載到內核中。有關加載內核模塊的更多信息,請參閱 內核NIC接口rte_kni
。
14.1 概述
內核NIC接口示例應用程序kni爲每個物理NIC端口分配一個或多個KNI接口。對於每個物理NIC端口, kni在用戶空間中使用兩個DPDK線程; 一個線程從端口讀取並寫入相應的KNI接口,另一個線程從KNI接口讀取並將未修改的數據寫入物理NIC端口。
建議爲每個物理網卡端口配置一個KNI接口。應用程序可以爲每個物理NIC端口配置多個KNI接口以進行性能測試,或者可以在將來與VMDq支持一起使用。
通過內核NIC接口應用程序的數據包流如下圖所示。
圖14.1 內核NIC應用程序包流
如果使用-m
命令行標誌啓用鏈接監視,則會啓動一個額外的pthread,它將檢查每個物理NIC端口的鏈接狀態,並將更新相應KNI接口的運營商狀態以匹配物理NIC端口的狀態。這意味着當以太網鏈路斷開時,KNI接口將自動禁用,並在以太網鏈路啓動時啓用。
如果啓用了鏈接監視,rte_kni
則應加載內核模塊,以便將默認運營商狀態設置爲off。這確保了KNI接口時,纔會啓用後, 相應的NIC端口的以太網鏈路已達到銜接狀態。
如果未啓用鏈接監視,rte_kni
則應加載內核模塊,並將默認運營商狀態 設置爲on。這在 啓用KNI接口時將KNI接口的載波狀態設置爲on,而不考慮相應NIC端口的實際鏈路狀態。這對於在環回模式下進行測試很有用,其中NIC端口可能沒有物理連接到任何東西。
14.2 編譯應用程序
要編譯示例應用程序,請參閱編譯示例應用程序(http://doc.dpdk.org/guides/sample_app_ug/compiling.html)。
該應用程序位於examples/kni
子目錄中。
注意
此應用程序僅用作Linux。
14.3 運行kni示例應用程序
kni示例應用程序需要大量的命令行選項:
KNI [EAL選項] - -p PORTMASK --config = “(端口,lcore_rx,lcore_tx [,lcore_kthread,...])[,(端口,lcore_rx,lcore_tx [,lcore_kthread,...])]”[ -P] [-m]
例如:
-
-p PORTMASK
:
要配置的端口的十六進制位掩碼。 -
--config="(port,lcore_rx,lcore_tx[,lcore_kthread,...])[,(port,lcore_rx,lcore_tx[,lcore_kthread,...])]"
:
決定Rx和Tx DPDK任務的哪些核心,以及(可選)KNI內核線程爲每個物理端口綁定的內核。 -
-P
:
可選標誌,用於將所有端口設置爲混雜模式,以便無論數據包的以太網MAC目標地址如何都可以接收數據包。如果沒有此選項,則只接受以太網MAC目標地址設置爲端口以太網地址的數據包。 -
-m
:
可選標誌,用於監視和更新以太網載波狀態。設置此選項後,將啓動一個線程,該線程將定期檢查物理以太網端口的以太網鏈路狀態,並設置相應KNI網絡接口的載波狀態以匹配它。這意味着當以太網鏈路關閉時,KNI接口將自動禁用,並在以太網鏈路啓動時啓用。
有關運行應用程序和環境抽象層(EAL)選項的一般信息,請參閱“ DPDK入門指南”。
EAL選項的-c coremask
或-l corelist
參數必須包含lcore_rx和lcore_tx爲每個端口指定的lcore,但不需要包含lcore_kthread指定的lcore,因爲這些核心用於將內核線程固定在rte_kni
內核模塊中。
--config
參數必須包含一組(port,lcore_rx,lcore_tx,[lcore_kthread,…])值,用於-p PORTMASK
參數中指定的每個物理端口。
可選的lcore_kthread
lcore ID參數--config
可以爲每個物理端口指定零,一次或多次。
如果沒有指定lcore_kthread
的lcore ID ,則將爲物理端口創建一個KNI接口port,並且KNI內核線程將沒有特定的核心關聯。
如果爲其指定了一個或多個lcore ID lcore_kthread,則將爲指定的每個lcore ID創建一個KNI接口,該接口綁定到物理端口 port。如果rte_kni內核模塊以多內核線程模式加載,則將爲每個KNI接口創建一個內核線程並綁定到指定的內核。如果rte_kni 內核模塊以單內核線程 模式加載,則只爲所有KNI接口啓動一個內核線程。內核線程將綁定到lcore_kthread指定的第一個lcore ID。
14.3.1 示例配置
以下命令將首先以多內核線程模式加載rte_kni
內核模塊 。在kni
隨後的應用程序使用兩個端口開始; 端口0使用lcore 4作爲Rx任務,lcore 6作爲Tx任務,並將創建單個KNI接口 vEth0_0
,內核線程綁定到lcore 8.端口1使用lcore 5作爲Rx任務,lcore 7作爲Tx任務,並將vEth1_0
使用綁定到lcore 9的內核線程創建單個KNI接口。
# rmmod rte_kni
# insmod kmod/rte_kni.ko kthread_mode=multiple
# ./build/kni -l 4-7 -n 4 -- -P -p 0x3 -m --config="(0,4,6,8),(1,5,7,9)"
以下示例完全相同,只是每個物理端口指定了一個額外的lcore_kthread
核心。在這種情況下,kni將創建四個KNI接口:vEth0_0/ vEth0_1綁定到物理端口0和 vEth1_0/ vEth1_1綁定到物理端口1。
每個接口的內核線程將綁定如下:
vEth0_0
- 綁定到lcore 8號。vEth0_1
- 綁定到lcore 10號。vEth1_0
- 綁定到lcore 9號。vEth1_1
- 綁定到lcore 11號
# rmmod rte_kni
# insmod kmod/rte_kni.ko kthread_mode=multiple
# ./build/kni -l 4-7 -n 4 -- -P -p 0x3 -m --config="(0,4,6,8,10),(1,5,7,9,11)"
下面的示例可用於測試kni測試應用程序和rte_kni內核模塊之間的接口。
在本例中,rte_kni內核模塊以單內核線程模式加載,啓用了環回模式,並將默認載波狀態設置爲on,以便使用KNI接口時不必連接相應的物理NIC端口。
爲端口0創建一個KNI接口vEth0_0,爲端口1創建一個KNI接口vEth1_0。
由於rte_kni是在“單內核線程”模式下加載的,所以一個內核線程被綁定到lcore 8。
由於沒有使用物理NIC端口,可以通過不向kni指定-m標誌來禁用鏈路監控:
# rmmod rte_kni
# insmod kmod/rte_kni.ko lo_mode=lo_mode_fifo carrier=on
# ./build/kni -l 4-7 -n 4 -- -P -p 0x3 --config="(0,4,6,8),(1,5,7,9)"
14.4 KNI操作
一旦啓動kni應用程序,用戶可以使用普通的Linux命令,好像他們是任何其它Linux的網絡界面來管理KNI接口。
啓用KNI接口並分配IP地址:
# ifconfig vEth0_0 192.168.0.1
顯示KNI接口配置和統計信息:
# ifconfig vEth0_0
用戶還可以通過向kni 應用程序發送USR1和USR2信號來檢查和重置應用程序內的數據包統計信息:
# 打印統計
# kill -SIGUSR1 `pidof kni`
# 清除統計
# kill -SIGUSR2 `pidof kni`
轉儲網絡流量:
# tcpdump -i vEth0_0
普通的Linux命令也可用於更改與KNI接口對應的物理網卡使用的MAC地址和MTU大小。但是,如果爲物理端口配置了多個KNI接口,則這些命令僅適用於該端口的第一個KNI接口。
更改MAC地址:
# ifconfig vEth0_0 hw ether 0C:01:02:03:04:08
更改MTU大小:
#ifconfig vEth0_0 MTU 1450
如果編譯DPDK CONFIG_RTE_KNI_KMOD_ETHTOOL=y並使用Intel NIC,則用戶可以在KNI接口上使用ethtool,就像它是普通的Linux內核接口一樣。
顯示NIC寄存器:
# ethtool -d vEth0_0
關閉kni應用程序後,將從Linux內核中刪除所有KNI接口。
14.5 說明
以下部分提供了一些代碼說明。
14.5.1 初始化
mbuf池,驅動程序和隊列的設置類似於L2轉發示例應用程序(在實際和虛擬化環境中)中完成的設置。此外,根據命令行參數爲每個配置的端口分配一個或多個內核NIC接口。
用於爲特定端口分配內核NIC接口的代碼位於函數kni_alloc
中。
此示例應用程序獨有的初始化過程中的另一個步驟是每個端口與RX,TX和內核線程的lcores的關聯。
- 一個lcore從端口讀取並寫入相關的一個或多個KNI設備
- 從一個或多個KNI設備讀取並寫入端口的另一個核心
- 用於逐個固定內核線程的其他lcores
這是通過使用kni_port_params_array[]
由端口ID索引的數組來完成的。代碼在函數parse_config中。
14.5.2 數據包轉發
初始化步驟完成後,將在每個lcore上運行main_loop()函數。此函數首先針對用戶提供的lcore_rx和lcore_tx檢查lcore_id,以查看此lcore是讀取內核NIC接口還是寫入內核NIC接口。
對於從NIC端口讀取並寫入內核NIC接口(kni_ingress)的情況,數據包接收與L2轉發示例應用程序中的相同(請參閱接收,處理和傳輸數據包(http://doc.dpdk.org/guides/sample_app_ug/l2_forward_real_virtual.html#l2-fwd-app-rx-tx-packets))。通過將mbuf發送到內核NIC接口來完成數據包傳輸rte_kni_tx_burst()。在內核成功複製mbuf後,KNI庫自動釋放mbuf。
對於從內核NIC接口讀取並寫入物理NIC端口(kni_egress)的另一種情況,通過從內核NIC接口讀取mbuf來檢索數據包rte_kni_rx_burst()。數據包傳輸與L2轉發示例應用程序中的相同(請參閱接收,處理和傳輸數據包)。