Linux環境下DPDK入門
Release 17.02.0
目錄
Linux環境下DPDK入門... 1
1 引言... 2
2 資料集... 2
3 系統需求... 2
3.1 x86平台的先決條件BIOS設置... 2
3.2 編譯DPDK. 3
3.3 運行DPDK程序... 3
4 編譯DPDK源碼... 5
4.1 安裝DPDK和瀏覽源碼... 5
4.2 安裝DPDK目標(target)開發環境... 6
4.3 瀏覽安裝好的DPDK環境target. 6
4.4 加載DPDK用戶態IO模塊... 7
4.5 加載VFIO模塊... 7
4.6 從內核模塊綁定和解綁網卡... 7
5 編譯和運行例子程序... 8
5.1 編譯例子程序... 8
5.2 運行例子程序... 9
5.2.1 程序使用的邏輯核... 9
5.2.2 程序使用的大頁內存... 10
5.3 其它例子程序... 10
5.4 其它的測試程序... 10
6 開啟其它功能... 10
6.1 高精度定時器(HPET)功能... 10
6.1.1 BIOS支持... 10
6.1.2 linux內核支持... 11
6.2 非root用戶運行DPDK程序... 11
6.3 電源管理和省電功能... 11
6.4 使用DPDK的CPU親和性減少上下文切換的開銷... 12
6.5 加載DPDK KNI內核模塊... 12
6.6 使用linux IOMMU透傳來在INTEL VT-d虛擬化環境下運行DPDK. 12
6.7 40G網口高性能小包處理... 12
6.7.1 使用16個字節的RX描述符... 12
6.7.2 高性能和報文時延間的均衡... 12
7 快速安裝啟動腳本... 12
7.1 腳本結構... 13
7.2 用例... 13
7.3 應用程序... 15
8 怎么在intel平台上獲得網卡的最好性能... 17
8.1 硬件和內存需求... 17
8.1.1 網卡需求... 18
8.1.2 BIOS設置... 18
8.1.3 Linux內核啟動參數... 18
8.2 運行DPDK前的配置... 18
8.3 獲取intel網卡的最好性能例子... 19
1 引言
文檔是安裝配置DPDK操作說明,旨在幫助客戶快速上手和運行程序。文檔介紹了在linux開發環境下如何編譯和運行DPDK程序,但是並不深入細節。
之前曾經嘗試着翻譯來着,當時因為要離職,一時興起就想着翻譯,翻譯的太爛,現在重新翻譯,一方面是方便新入職的同事能夠快速入門,另外一方面是現在工作的需要,還有一方面是學習KVM想休息一下,看內存那塊弄得頭昏腦脹,而且后面的例子會涉及到虛擬話那塊的。下一個將翻譯樣例那本書(以及在自己機器上運行可能遇到的問題),同時會參雜着介紹開發者手冊中的一些個人理解。
2 資料集
下面列出了所有DPDK文檔資料的建議讀取順序:
l 版本說明:提供了各個版本相關的信息,包括支持的特性,限制,修復的bug,出現的問題等等。也對頻繁提到的問題以FAQ的方式做了回答。
l 入門手冊(本文的):講述了如何安裝配置DPDK;意在幫助開發者快速上手和運行程序。
l 開發者手冊:
n 軟件架構和(通過例子)在linux環境下使用它
n DPDK的內容包括構建系統(包括在DPDK根目錄下構建開發環境和程序使用的命令)和移植程序指南。
n 在已有軟件和要新開發的軟件中需要考慮到的優化。
還提供了一個專有術語表。
l API索引:提供了DPDK函數,數據結構和其它開發用到的結構體的詳細信息。
l 范例用戶手冊:介紹了一系列的范例程序。每一個章節介紹一個程序,展示程序的特殊功能,說明如何編譯,運行和使用范例程序。
3 系統需求
本章介紹了編譯DPDK需要的安裝包。
注意:如果DPDK要運行在intel 89xx系統通訊芯片平台,請翻閱對應該系列的linux入門手冊。
3.1 x86平台的先決條件BIOS設置
對於主流的平台,使用DPDK的基本功能並不需要專門的BIOS設置,然而,對於額外的功能像HPET(高精度定時器),電量管理功能,以及在40G網卡上高性能小包處理,需要修改BIOS設置。修改設置的詳細信息見第六章。
3.2 編譯DPDK
需要的工具:
注意:已經在Fedora18上測試運行過,在其它系統上安裝命令和需要的安裝包可能不一樣,要知道其它版本linux發行版測試詳細的細節,請查看DPDK版本說明。
l GNU make
l coreutils:cmp,sed,grep,arch,等等。
l gcc:4.9版本或者是所有平台帶的更新的版本。在一些gcc版本中,很多特殊的編譯標志和鏈接標志默認是打開的,會影響到性能(比如,-fstatck-protector)。請查閱對應版本的文檔和執行gcc –dumpspecs。
l libc hreaders,通常打包成gcc-multilib(intel 64位架構上是glibc-devel.i686/libc6-dev-i386;glibc-devel.x86_64/libc6-dev,IBM power架構則是glibc-devel.ppc64)
l 編譯內核模塊需要的內核頭文件和源文件(kernel-devel.x86_64;kernel-devel.ppc64)
l 在64位機器上編譯32位程序而外需要的庫:
n glibc.i686, libgcc.i686, libstdc++.i686 and glibc-devel.i686 for Intel i686/x86_64;
n glibc.ppc64, libgcc.ppc64, libstdc++.ppc64 and glibc-devel.ppc64 for IBM ppc_64;
注意:x86_x32 ABI庫旨在ubuntu13.10以上版本或者最新Debian版本上支持。只支持gcc4.9+版本。
l python,要使用dpdk安裝包中各種幫助腳本必需的python版本2.7+或者是3.2+。
其它的工具:
l intel編譯器icc:需要安裝額外的庫。在編譯器安裝文檔看中icc安裝說明。
l IBM powerlinux高級工具鏈:這是一系列的開源開發工具和運行時庫,能夠讓用戶用到IBM最新的power硬件特性。要安裝的話看IBM的官方安裝文檔。
l libpcap頭文件和庫(libpcap-devel)編譯和使用基於libpcap的輪詢驅動。這個驅動默認是禁用的,可以通過修改編譯時的配置文件參數CONFIG_RTE_LIBRTE_PMD_PCAP=y來打開。
l libarchive頭文件和庫在單元測試用打開源文件用到。
3.3 運行DPDK程序
要運行DPDK程序,在目的機器上需要一些定制化的東西。
3.3.1系統軟件
要求:
l 內核版本>=2.6.34:通過命令uname –r查看內核版本號
l glibc>=2.7(要用到cpuset特性):可以通過命令ldd –version命令查看gcc版本號
l 內核配置
在Fedora操作系統和其它通用發行版,例如Ubuntu,紅帽企業版linux,發行商提供的內核配置基本可以跑絕大多數DPDK程序。
對於在其它內核上構建DPDK,下面幾個選項需要能支持:
n UIO(用戶態IO)
n HUGETLBFS(大頁內存)
n PROC_PAGE_MONITOR支持
n HPET和HPET_MMAP配置項必須打開,如果用到HPET,具體細節看第六章。
3.3.2在linux環境下使用大頁內存
對於大的報文內存池內存分配,大頁內存是必須的。(前一章說過運行的內核必須支持大頁內存)。使用大頁內存來分配,即使是小部分頁要用到,性能也能夠得到提升。減少了TLBmiss,對應就減少了虛擬地址轉物理地址的時間。使用小頁4K內存頁,很高頻率的TLBmiss發生會導致性能低下。
申請大頁給DPDK使用
大頁內存的分配最好是在系統啟動時或者是盡量在系統啟動后越早越好,這樣可以減少分配的物理內存頁物理地址碎片化。申請大頁內存需要在內核啟動時傳遞一個命令行參數。
對於2MB內存頁,分配1024個2MB內存頁參數如下:
hugepages=1024
其它尺寸的大內存頁,例如1G頁,必須指定申請的內存頁個數和默認內存頁的大小。例如分配4個1G的內存頁,需要指定的參數如下:
default_hugepagesz=1G hugepagesz=1G hugepages=4
注意:大頁內存的尺寸是CPU支持的大小來決定的。intel的機器上通過查看CPU flags來查看支持的大頁內存尺寸。比如pse 代表支持2MB的內存頁,pdpe1gb代表支持1G內存頁。在IBM power架構機器上,支持大頁內存尺寸為16MB和16GB。
注意:對於64位的應用,如果平台支持,建議使用1G內存頁。
在雙插槽的NUMA系統中,申請的大頁內存一般會平均在兩個socket上分配(假定兩個socket都有足夠的內存)。
可以看linux內核源碼樹中Documentation/kernel-parameters.txt獲取更多內核選項的細節。
備選項:
對於2M的頁,可以在系統啟動后申請分配。echo想要分配的大頁內存頁個數到/sys/devices目錄下的nr_hugepages文件。對於單NUMA(非NUMA)節點的系統,如下命令所示(假設需要1024個2M頁):
echo 1024 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
在一個NUMA機器上,分別在不同node上分配指定數目的內存頁:
echo 1024 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages
echo 1024 > /sys/devices/system/node/node1/hugepages/hugepages-2048kB/nr_hugepages
注意:1G的內存頁在系統啟動后是無法申請。
DPDK使用大頁
一旦申請到大頁內存,要想其被DPDK使用到,執行以下步驟:
mkdir /mnt/huge
mount -t hugetlbfs nodev /mnt/huge
要想是掛載即使是重啟也永久有效,需要把下面一行加到/etc/fstab文件中:
nodev /mnt/huge hugetlbfs defaults 0 0
1GB內存頁,必須在掛載的時候將內存頁的大小作為參數指定:
nodev /mnt/huge_1GB hugetlbfs pagesize=1GB 0 0
3.3.3LINUX環境下Xen Domain0支持
現有的內存管理基於linux內核的大頁機制。在Xen虛擬機管理器上,大頁內存對非特權域(DomainU)的支持意味着DPDK在客戶機上可以像普通機器上一樣跑。
然而,特權域(domain0)並不支持大頁內存。需要插入新的內核模塊rte_dom0_mm以便繞過這個限制來申請和映射大頁內存,通過ioctl來申請,mmap來映射。
開啟DPDK對Xen Dom0支持
默認情況下,Xen Dom0模式支持在DPDK的build配置文件中是禁用的。要想支持Xen Dom0,配置項CONFIG_RTE_LIBRTE_XEN_DOM0需要在編譯時改成y。
此外,配置項CONFIG_RTE_EAL_ALLOW_INV_SOCKET_ID也必須置成y,以防萬一收到錯誤的socket ID。
加載rte_dom0_mm模塊
要在Xen Dom0中跑dpdk程序,rte_dom0_mm模塊必須帶上rsv_memsize參數加載到運行的內核中。可以在編譯的DPDK目標目錄的子目錄中找到該模塊。該模塊的加載如下使用insmod命令(假設當前處於DPDK編譯的目標目錄下):
sudo insmod kmod/rte_dom0_mm.ko rsv_memsize=X
X的值可以大於4095MB。
配置DPDK使用的內存
在rte_dom0_mm.ko模塊加載完成后,用戶必須配置DPDK使用的內存。將需要的內存大小echo到/sys/devices/目錄下的memsize文件中即可。使用如下命令(假設需要2048MB內存):
echo 2048 > /sys/kernel/mm/dom0-mm/memsize-mB/memsize
用戶也可以檢查已經使用了多少內存:
cat /sys/kernel/mm/dom0-mm/memsize-mB/memsize_rsvd
Xen Dom0不支持NUMA配置,所以參數--socket-mem對於Xen Dom0是無效的。
注意:內存大小值不能超過rsv_memsize值。
在Xen Domain0中運行DPDK程序
要跑DPDK程序需要額外提供一個命令行參數--xen-dom0。
4 編譯DPDK源碼
注意:本章寫的部分安裝過程也可以通過后續<快速安裝腳本>一章中描述的腳本實現。
4.1 安裝DPDK和瀏覽源碼
首先,解壓壓縮包並移動到解壓的DPDK源碼目錄:
tar xJf dpdk-<version>.tar.xz
cd dpdk-<version>
DPDK包含以下幾個子目錄:
l lib:DPDK庫的源碼
l drivers:DPDK輪詢驅動的源碼
l app:DPDK應用程序的源碼(自動化測試)
l examples:DPDK應用程序樣例源碼
l config,buildtools,mk:框架相關的Makefiles,腳本和配置文件
4.2 安裝DPDK目標(target)開發環境
DPDK target格式是:
ARCH-MACHINE-EXECENV-TOOLCHAIN
詳解:
l ARCH 可以是:i686,x86_64,ppc_64
l MACHINE 可以是:native,power8
l EXECENV 可以是:linuxapp,bsdapp
l TOOLCHAIN 可以是:gcc,icc
將要被安裝的target環境取決於要安裝的機器上的包是32位還是64位。可以編譯產生的target在DPDK/config目錄下定義了。不要用defconfig_前綴,就是編譯的時候不要帶上這個前綴。
注意:配置文件是RTE_MACHINE下的最優配置集合。在配置文件中,RTE_MACHINE被定義為native,意味着這是針對本機環境下最佳優化的編譯。對於這些設置的更多信息,可以采用的值,看DPDK開發者手冊。
當使用ICC編譯器時,下面的命令分別對應32位和64位環境使用。注意這個shell腳本更新$PATH環境變量,因此換個會話就失效了。編譯安裝的目錄可能是不同的:
source /opt/intel/bin/iccvars.sh intel64
source /opt/intel/bin/iccvars.sh ia32
安裝和生成target,在DPDK的根目錄下使用make install T=<target> 命令。
例如,使用icc編譯64位target:
make install T=x86_64-native-linuxapp-icc
使用gcc編譯32位的:
make install T=i686-native-linuxapp-gcc
只是做創建target的准備,而不是編譯,例如,在編譯之前需要手動修改配置文件的,使用命令make config T=<target>:
make config T=x86_64-native-linuxapp-gcc
警告:
任何內核模塊,比如igb_uio,kni等,必須編譯時的內核和要運行時的內核一致。如果DPDK不是在編譯產生的目標機器上運行, RTE_KERNELDIR環境變量必須指向要運行target機器對應內核版本。
一旦目標環境創建完成,用戶可能需要進入目標環境目錄,修改源碼並重新編譯。用戶也可能修改編譯時的DPDK配置項,通過編輯build目錄下的.config文件(這個文件是從頂層目錄的config目錄下defconfig文件拷貝到本地來的):
cd x86_64-native-linuxapp-gcc
vi .config
make
此外,make clean命令可以清除所有之前編譯留下的文件。
4.3 瀏覽安裝好的DPDK環境target
一旦target創建完成就包含所有的苦,包括輪詢驅動,和用戶程序編譯需要的DPDK環境頭文件。此外,test和testpmd程序在build/app目錄下創建完成,可用於測試。kmod目錄下包含需要加載到內核中的幾個內核模塊。
4.4 加載DPDK用戶態IO模塊
運行DPDK程序,一個合適的uio模塊需要加載到運行中的內核。在很多例子中,標准的uio_pci_generic LINUX內核模塊可以提供用戶態驅動能力。該模塊加載如下:
sudo modprobe uio_pci_generic
和上述不同的是,DPDK提供了igb_uio模塊來實現(在kmod目錄下):
sudo modprobe uio
sudo insmod kmod/igb_uio.ko
注意:對於缺乏對傳統中斷支持的設備,比如VF設備,igb_uio模塊可能需要被uio_pci_generic替換掉。
在DPDK1.7之前版本提供了對VFIO的支持,在支持VFIO的平台上UIO就不是必須的了。
4.5 加載VFIO模塊
使用VFIO的DPDK應用程序,vfiopci模塊必須加載:
sudo modprobe vfio-pci
需要注意的是要使用VFIO,你的內核必須支持才行。VFIO內核模塊在LINUX內核3.6.0版本之后就囊括經來了,默認是有的。然而,請翻閱linux發行版文檔確定一下。
使用VFIO,BIOS和內核都必須支持,BIOS需要打開支持虛擬化的配置選項(例如Intel® VT-d).
在非特權用戶下運行DPDK程序,要正確的操作VFIO,需要建立正確的權限設置。這個可以通過DPDK安裝腳本實現(dpdk-setup.sh,位於usertools目錄下)
4.6 從內核模塊綁定和解綁網卡
在1.4版本,DPDK程序不再自動解綁所有支持DPDK的網口,當網口綁定在內核驅動上且正在運行時。取而代之的是,DPDK程序在運行前,必須將使用的所有網口綁定到uio_pci_generic,igb_uio或者是vfio-pci模塊上。任何linux控制下的網口將被DPDK輪詢驅動忽略,不能被DPDK程序使用。
警告:DPDK默認不再在啟動時自動解綁內核驅動管理的網口。任何PDDK程序使用的網口必須在程序運行前解除linux控制,綁定到對應的驅動上(uio_pci_generic,igb_uio或者是vfio-pci).
將綁定到DPDK的網口解綁並交給linux控制,可以使用usertool子目錄下的dpdk_nic_bind.py腳本。這個腳本可以展示當前系統中所有網口的狀態,可以將其從不同的內核模塊間解綁和綁定,包括uio和vfio模塊。下面是使用腳本的例子。要想獲取腳本的全部使用描述和參數,可以帶上—help或者是—usage參數啟動腳本。注意,uio或者是vfio內核模塊需要在運行dpdk-nic-bind.py腳本之前加載到內核中。
查看系統中所有網口的狀態:
./usertools/dpdk-devbind.py --status
Network devices using DPDK-compatible driver
============================================
0000:82:00.0 '82599EB 10-GbE NIC' drv=uio_pci_generic unused=ixgbe
0000:82:00.1 '82599EB 10-GbE NIC' drv=uio_pci_generic unused=ixgbe
Network devices using kernel driver
===================================
0000:04:00.0 'I350 1-GbE NIC' if=em0 drv=igb unused=uio_pci_generic *Active*
0000:04:00.1 'I350 1-GbE NIC' if=eth1 drv=igb unused=uio_pci_generic
0000:04:00.2 'I350 1-GbE NIC' if=eth2 drv=igb unused=uio_pci_generic
0000:04:00.3 'I350 1-GbE NIC' if=eth3 drv=igb unused=uio_pci_generic
Other network devices
=====================
<none>
綁定設備eth1,“04:00.1”到uio_pci_generic驅動上:
./usertools/dpdk-devbind.py --bind=uio_pci_generic 04:00.1
或者是:
./usertools/dpdk-devbind.py --bind=uio_pci_generic eth1
恢復設備82:00.0到原始的內核驅動上:
./usertools/dpdk-devbind.py --bind=ixgbe 82:00.0
5 編譯和運行例子程序
本章講的是怎么在DPDK環境下編譯和運行程序。也指出了樣例程序保存在哪里。
注意:本章寫的部分安裝過程也可以通過后續<快速安裝腳本>一章中描述的腳本實現。
5.1 編譯例子程序
DPDK目標環境目錄創建完成(例如x86_64-native-linuxapp-gcc),就包含了創建一個dpdk應用程序需要的庫和頭文件。
當在linux DPDK環境下編譯程序,下面兩個環境遍歷必須export:
l RTE_SDK 指向DPDK編譯安裝目錄即target所在目錄
l RTE_TARGET 指向DPDK target目錄名
下面展示的是運行在linux DPDK環境下的例子helloworld。可以在$RTE_SDK/examples目錄下找到。
目錄下包含main.c文件,默認編譯生成的二進制文件在build目錄下:
cd examples/helloworld/
export RTE_SDK=$HOME/DPDK
export RTE_TARGET=x86_64-native-linuxapp-gcc
make
CC main.o
LD helloworld
INSTALL-APP helloworld
INSTALL-MAP helloworld.map
ls build/app
helloworld helloworld.map
注意:在上面的例子中,helloworld是在DPDK框架目錄中,為了保證DPDK框架的完整性,可以把helloworld移動到外部。在下面的例子中,helloworld被拷貝到一個新目錄中重新編譯。
export RTE_SDK=/home/user/DPDK
cp -r $(RTE_SDK)/examples/helloworld my_rte_app
cd my_rte_app/
export RTE_TARGET=x86_64-native-linuxapp-gcc
make
CC main.o
LD helloworld
INSTALL-APP helloworld
INSTALL-MAP helloworld.map
5.2 運行例子程序
警告:必須在運行DPDK程序前安裝好UIO驅動和大頁內存。
警告:任何進程使用的網口在程序啟動之前必須綁定到適當的內核模塊上,如之前<從內核模塊上綁定和解綁網卡>章節所述。
程序必須鏈接DPDK target環境EAL(環境抽象層)庫,這個庫提供了每一個DPDK程序通用的選項。
下面是可以傳遞給EAL的參數列表:
./rte-app -c COREMASK [-n NUM] [-b <domain:bus:devid.func>] \
[--socket-mem=MB,...] [-m MB] [-r NUM] [-v] [--file-prefix] \
[--proc-type <primary|secondary|auto>] [-- xen-dom0]
EAL參數如下:
l -c COREMASK:要使用CPU core16進制掩碼。注意core編號在不同的平台不一樣,需要事先確定好。
l -n NUM:每個處理器socket的內存通道數
l -b <domain:bus:devid.func>:網口黑名單,EAL不能使用的PCI設備(可以同時存在多個-b選項)
l --socket-mem:在指定socket上分配大頁內存
l -m MB:指定分配大大頁內存數,不限處理器的socket。加以使用—socket-mem代替這個參數。
l -r NUM:內存的rank數
l -v:顯示程序版本號
l --huge-dir:大頁內存的掛載點
l --file-prefix:大頁內存文件的前綴
l --proc-type:進程類型
l --xen-dom0:支持程序在Xen Domain0中非大頁內存下運行
l --vmware-tsc-map:使用VMware TSC代替本地的RDTSC
l --base-virtaddr :指定虛擬地址的基址
l --vfio-intr:指定VFIO使用的中斷類型(如果不是用VFIO則無效)
-c是必須的,其它都是可選的。
運行例子程序(假設該平台每個處理器socket有4個內存通道,有4個cpu核,且程序都使用上):
./helloworld -c f -n 4
注意:--proc-type和—file-prefix EAL參數用於DPDK多進程。可以查閱DPDK范例程序一書中多進程章節和DPDK開發手冊獲取更多細節。
5.2.1 程序使用的邏輯核
CPU核掩碼參數是DPDK程序必須帶上的。掩碼的每個bit位代表linux顯示的每個邏輯核的編號。不同的平台之間,邏輯核編號和邏輯核編號與NUMA socket的映射關系是不同的,所以建議在選在使用核之前先弄清楚該平台的核分布。
在初始化DPDK 環境抽象層時,會打印出要使用的邏輯核以及其所在的socket。這些信息也可以通過查看/proc/cpuinfo文件來知道,例如,執行 cat /proc/cpuinfo。每個邏輯核的物理ID屬性表明其屬於哪個CPU socket。
注意:邏輯核分布視圖可以通過使用linux工具lstopo獲取。在Fedora系統中,可以使用下面的命令安裝使用:
sudo yum install hwloc
./lstopo
警告:邏輯核的分布在不同的主板上是不一樣的,在選擇使用的核之前要檢查一下。
5.2.2 程序使用的大頁內存
運行DPDK程序,建議大頁內存用多少就分配多少。如果沒有傳入-m或者是—socket-mem參數,DPDK程序在啟動時自動完成。
如果實際使用的內存超過了傳入參數值指定的值,程序將失敗並退出。然而,如果用戶要申請使用的內存小於預先分配的內存大小,特別是使用了-m選項時,程序自身也會失敗。假定系統在socket0和socket1上各預先分配有1024個2MB內存頁,用戶請求使用128MB內存,64個頁可能不符合要求:
l 內核給予應用程序分配的大頁內存都在socket1上。這種情況下,如果應用程序試圖在socket0上創建一個對象,比如一個無鎖隊列或者是內存池,程序會失敗。要避免這種問題,建議使用—socket-mem選項代替-m選項。
l 那些大頁內存在物理上是分布在各處的,然而DPDK EAL試圖分配在物理地址上連續的一段內存,而可能現有的內存頁不是連續的,這種情形下,應用程序無法申請大的內存池而失敗。
socket-mem選項可以在指定的socket上分配指定大小的內存頁。要想做到這個,就得在這個選項后面接上要在各個socket上分配內存大小,例如:--socket-mem=0,512,就是在socket1上分配512MB內存。同理,在4socket的系統中,只在socket0和2上各分配1GB內存:--socket-mem=1024,0,1024。某一個CPUsocket上沒有內存分配,那么就不需要顯式的引用,例如前面socket3就是。如果不能在指定的socket上分配到足夠的內存,EAL初始化失敗。
5.3 其它例子程序
其它的例子程序在$RTE_SDK./example目錄下。這些程序的編譯和運行方式與本文中之前章節介紹的差不多。此外,可以查閱DPDK范例程序手冊,該手冊介紹了在編譯和執行程序時的特殊命令參數,以及代碼的說明。
5.4 其它的測試程序
另外,有兩個額外的測試程序在DPDK庫創建的時候編譯出來。源碼在DPDK/app目錄下,名為test和testpmd。DPDK目標庫創建完成,那么就可以在build/app目錄中找到。
l test程序提供了DPDK各種函數的特定測試。
l testpmd程序提供了一些不同的報文吞吐測試和特性,例如如何使用intel82599萬兆網卡的Flow Director(引流)特性。
6 開啟其它功能
6.1 高精度定時器(HPET)功能
6.1.1 BIOS支持
要使用HPET必須BIOS中支持,否則默認采用TSC。一般情況下,在系統啟動的時候按F2鍵可以進入BIOS。用戶可以開啟HPET選項。在intel的Crystal Forest平台BIOS上,路徑是Advanced -> PCH-IO Configuration -> High Precision Timer -> (Change from Disabled to Enabled if necessary).
在已經啟動的系統中,下面的命令可以查看HPET是否開啟:
grep hpet /proc/timer_list
如果返回為空,那么必須重啟機器並在BIOS中開啟HPET(重復上述的指令)。
6.1.2 linux內核支持
DPDK通過將時間戳計數器映射到處理器地址空間來利用平台的HPET,如此需要HPET_MMAP內核配置項支持。
警告:在Fedora系統和其他通用linux發行版,例如ubuntu,HPET_MMAP內核選項是默認關閉的。帶此參數重新編譯內核,請查閱發行版文檔了解相關操作。
在DPDK中使用HPET
默認情況下,DPDK編譯配置文件中HPET選項是關閉的。要使用HPET,CONFIG_RTE_LIBEAL_USE_HPET配置項必須改成y,需要在編譯時修改參數。
程序使用rte_get_hpet_cycles()和rte_get_hpet_hz()接口調用,在程序初始化時調用rte_eal_hpet_init()接口來將HPET作為rte_timer庫的默認時間源。這個接口將確保HPET可用,如果不可用則返回錯誤值。例如,如果HPET_MMAP內核不支持。那么程序可以針對支持或者是不支持而決定采取什么動作。
注意:如果程序需要時間API,但是HPET不支持,建議采用rte_get_timer_cycles()和rte_get_timer_hz()接口代替HPET接口。這個通用接口既可以使用TSC,也可以使用HPET作為時間源,取決於是否在程序啟動是調用rte_eal_hpet_init()接口,如果調用了的話,系統是否支持。
6.2 非root用戶運行DPDK程序
盡管程序通過DPDK能夠直接使用網口和硬件資源,但是這些程序如果是作為普通用戶而不是root用戶,那么需要做一些小的權限調整。要實現這個,下面這些linux系統文件的所有者和權限必須調整,以便普通linux用戶也能在使用DPDK的時候訪問它們:
l 所有的大頁內存掛載點目錄,例如/mnt/huge
l 在/dev目錄下的用戶態IO設備文件,/dev/uio0,/dev/uio1,等等。
l 用戶態IO系統文件配置和資源文件,例如uio0:
/sys/class/uio/uio0/device/config
/sys/class/uio/uio0/device/resource
l 如果要使用HPET,文件/dev/hpet
注意:在一些linux系統上安裝時,/dev/hugepages會默認作為大頁內存的掛載點創建。
6.3 電源管理和省電功能
如果要使用DPDK的電源管理功能,那么必須在平台BIOS中開啟增強型INTEL SpeedStep(步進?)技術開關。否則,系統文件/sys/devices/system/cpu/cpu0/cpufreq不會存在,且基於CPU主頻調節的電源管理就無法使用。查閱相關的BIOS文檔確定這些設置如何訪問。
例如,在一些INTEL平台BIOS是不一致的,增強型INTEL SpeedStep技術的路徑是:
Advanced
-> Processor Configuration
-> Enhanced Intel SpeedStep® Tech
此外,要開啟電源管理C3和C6也一樣要打開。C3和C6在同樣的BIOS平台:
Advanced
-> Processor Configuration
-> Processor C3 Advanced
-> Processor Configuration
-> Processor C6
6.4 使用DPDK的CPU親和性減少上下文切換的開銷
當一些線程被DPDK程序使用時,這些線程每一個會被固定到系統中的一個邏輯核心上(一個線程對應一個邏輯核心),對於linux調度器來說,也有可能會在這些核心上運行其他任務。為了阻止調度器將其他任務調度到DPDK使用的核心上,需要使用內核參數isolcpus來將這些核心從Linux調度器中隔離開來.
例如,DPDK程序使用邏輯核性2,4,6運行程序,下面的這個選項需要加到內核啟動參數中:
isolcpus=2,4,6
6.5 加載DPDK KNI內核模塊
要運行DPDK KNI例子程序,需要額外加載一個內核模塊(kni模塊)到運行的linux內核中。可以在DPDK target目錄下的kmod目錄中找到。同理如加載igb_uio模塊,加載kni也是通過ismod命令來(假設我們當前處於DPDK target目錄下):
insmod kmod/rte_kni.ko
6.6 使用linux IOMMU透傳來在INTEL VT-d虛擬化環境下運行DPDK
要在linxu內核中開啟intel VT-d,一系列的內核配置項需要設置:
l IOMMU_SUPPORT
l IOMMU_API
l INTEL_IOMMU
此外,要在intel VT-d虛擬化環境下運行DPDK,當使用igb_uio驅動時,必須設置內核參數iommu=pt。這個是主機中DMAR(DMA Remapping(DMA地址重映射)透傳的結果。INTEL_IOMMU_DEFAULT_ON在內核中也沒有設置,內核參數inte_iommu=on必須使用。這可以確保intel IOMMU按照期望被初始化。
請注意,使用igb_uio驅動時必須使用iommu=pt參數,而vfio-pci驅動則是使用iommu=pt和iommu=on二者都可以運行。
6.7 40G網口高性能小包處理
在最新版本的固件鏡像中,性能增強的問題解決了,固件更新可以獲取更高的性能。用戶需要檢查本地的intel網卡驅動版本。用戶需要查閱DPDK版本說明文檔確定這個版本對應的網卡i40E驅動版本。
6.7.1 使用16個字節的RX描述符
i40e輪詢驅動支持16和32字節的RX描述符大小,而16個字節的能夠提供更高的小包處理性能。需要在配置文件中修改CONFIG_RTE_LIBRTE_I40E_16BYTE_RX_DESC參數為使用16個字節的RX描述符。
6.7.2 高性能和報文時延間的均衡
由於硬件設計的原因,每個報文描述符的回寫需要在網卡內產生一個中斷信號。最小的中斷間隔需要在編譯時修改配置文件中的CONFIG_RTE_LIBRTE_I40E_ITR_INTERVAL參數。盡管有默認配置,用戶可以根據自己的實際情況,看是更在乎性能還是時延來調優這個參數。
7 快速安裝啟動腳本
dpdk-setup.sh腳本,在usertools子目錄下,可以幫助用戶執行下面的任務:
l 編譯DPDK庫
l 插入和移走DPDK IGB_UIO內核模塊
l 插入和移走VFIO內核模塊
l 插入和移走DPDK KNI內核模塊
l 創建和刪除NUMA和非NUMA下的大頁內存
l 網口狀態試圖展示和分配網口給DPDK程序使用
l 為使用VFIO的非特權用戶分配權限
l 運行test和testpmd程序
l 展示在meminfo中的大頁信息
l 列出/mnt/huge中的大頁
l 刪除創建的DPDK庫
7.1 腳本結構
dpdk-setup.sh腳本是用戶按照用戶的執行命令邏輯順序來組織起來的一系列的步驟。每一個步每一步都提供了一些提示信息幫助用戶完成要求的任務。下面是每一步的簡單概述。
step 1:編譯DPDK庫
最開始,用戶必須選擇一個DPDK target,匹配類型和編譯選項,以便生成正確的庫。
用戶必須按照前面章節所述,將所有需要的庫,模塊,更新和編譯需要的東西安裝好。
step2:安裝環境
用戶配置DPDK程序運行所需的linux環境。大頁內存的建立。任何已存的大頁內存會被移除。DPDK用到的內核模塊也在這步中插入,DPDK程序使用的網卡接口也綁定到對應的模塊。
step3:運行程序
用戶可能需要在上面步驟完成后運行test程序。test程序允許執行一系列的DPDK功能測試。testpmd支持收發包相關的測試。
step4:檢查系統
這步提供了一些工具來檢查系統的大頁內存狀態。
step5:系統還原
最后一步是恢復系統到原有的狀態。
7.2 用例
下面是一些使用dpdk-setup.sh腳本的用例。這個腳本應該使用source命令來運行。
警告:腳本需要在root權限下運行。
source usertools/dpdk-setup.sh
------------------------------------------------------------------------
RTE_SDK exported as /home/user/rte
------------------------------------------------------------------------
Step 1: Select the DPDK environment to build
------------------------------------------------------------------------
[1] i686-native-linuxapp-gcc
[2] i686-native-linuxapp-icc
[3] ppc_64-power8-linuxapp-gcc
[4] x86_64-native-bsdapp-clang
[5] x86_64-native-bsdapp-gcc
[6] x86_64-native-linuxapp-clang
[7] x86_64-native-linuxapp-gcc
[8] x86_64-native-linuxapp-icc
------------------------------------------------------------------------
Step 2: Setup linuxapp environment
------------------------------------------------------------------------
[11] Insert IGB UIO module
[12] Insert VFIO module
[13] Insert KNI module
[14] Setup hugepage mappings for non-NUMA systems
[15] Setup hugepage mappings for NUMA systems
[16] Display current Ethernet device settings
[17] Bind Ethernet device to IGB UIO module
[18] Bind Ethernet device to VFIO module
[19] Setup VFIO permissions
------------------------------------------------------------------------
Step 3: Run test application for linuxapp environment
------------------------------------------------------------------------
[20] Run test application ($RTE_TARGET/app/test)
[21] Run testpmd application in interactive mode ($RTE_TARGET/app/testpmd)
------------------------------------------------------------------------
Step 4: Other tools
------------------------------------------------------------------------
[22] List hugepage info from /proc/meminfo
------------------------------------------------------------------------
Step 5: Uninstall and system cleanup
------------------------------------------------------------------------
[23] Uninstall all targets
[24] Unbind NICs from IGB UIO driver
[25] Remove IGB UIO module
[26] Remove VFIO module
[27] Remove KNI module
[28] Remove hugepage mappings
[29] Exit Script
選項:
下面是展示選擇創建x86_64-native-linuxapp-gcc DPDK庫的例子:
Option: 9
================== Installing x86_64-native-linuxapp-gcc
Configuration done
== Build lib
...
Build complete
RTE_TARGET exported as x86_64-native-linuxapp-gcc
下面是展示插入DPDK UIO驅動的例子:
Option: 25
Unloading any existing DPDK UIO module
Loading DPDK UIO module
下面的選擇是展示創建NUMA系統下的大頁內存。分別在兩個node上各分配1024個2MB內存頁。那么程序就需要系統-m 4096參數來訪問這兩塊內存。(如果沒有提供-m參數,那么程序會自動執行)。
注意:如果提示移除臨時文件,輸入y。
Option: 15
Removing currently reserved hugepages
mounting /mnt/huge and removing directory
Input the number of 2MB pages for each node
Example: to have 128MB of hugepages available per node,
enter '64' to reserve 64 * 2MB pages on each node
Number of pages for node0: 1024
Number of pages for node1: 1024
Reserving hugepages
Creating /mnt/huge and mounting as hugetlbfs
下面是展示選擇加載test程序到一個邏輯核上運行:
Option: 20
Enter hex bitmask of cores to execute test app on
Example: to execute app on cores 0 to 7, enter 0xff
bitmask: 0x01
Launching app
EAL: coremask set to 1
EAL: Detected lcore 0 on socket 0
...
EAL: Master core 0 is ready (tid=1b2ad720)
RTE>>
7.3 應用程序
一旦用戶運行dpdk-setup.sh腳本,編譯EAL庫,建立好大頁內存(加入使用的是linxu EAL目標),用戶可能接着會去編譯和運行自己的程序或者是例子程序。
在/examples目錄下的例子提供了解DPDK操作的好的起點。下面的命令展示了helloworld程序是怎么編譯和運行的。如同上述章節建議的,<程序使用的邏輯核心>,邏輯核心在平台上的分布應該在選擇程序使用的邏輯核掩碼時確定好。
cd helloworld/
make
CC main.o
LD helloworld
INSTALL-APP helloworld
INSTALL-MAP helloworld.map
sudo ./build/app/helloworld -c 0xf -n 3
[sudo] password for rte:
EAL: coremask set to f
EAL: Detected lcore 0 as core 0 on socket 0
EAL: Detected lcore 1 as core 0 on socket 1
EAL: Detected lcore 2 as core 1 on socket 0
EAL: Detected lcore 3 as core 1 on socket 1
EAL: Setting up hugepage memory...
EAL: Ask a virtual area of 0x200000 bytes
EAL: Virtual area found at 0x7f0add800000 (size = 0x200000)
EAL: Ask a virtual area of 0x3d400000 bytes
EAL: Virtual area found at 0x7f0aa0200000 (size = 0x3d400000)
EAL: Ask a virtual area of 0x400000 bytes
EAL: Virtual area found at 0x7f0a9fc00000 (size = 0x400000)
EAL: Ask a virtual area of 0x400000 bytes
EAL: Virtual area found at 0x7f0a9f600000 (size = 0x400000)
EAL: Ask a virtual area of 0x400000 bytes
EAL: Virtual area found at 0x7f0a9f000000 (size = 0x400000)
EAL: Ask a virtual area of 0x800000 bytes
EAL: Virtual area found at 0x7f0a9e600000 (size = 0x800000)
EAL: Ask a virtual area of 0x800000 bytes
EAL: Virtual area found at 0x7f0a9dc00000 (size = 0x800000)
EAL: Ask a virtual area of 0x400000 bytes
EAL: Virtual area found at 0x7f0a9d600000 (size = 0x400000)
EAL: Ask a virtual area of 0x400000 bytes
EAL: Virtual area found at 0x7f0a9d000000 (size = 0x400000)
EAL: Ask a virtual area of 0x400000 bytes
EAL: Virtual area found at 0x7f0a9ca00000 (size = 0x400000)
EAL: Ask a virtual area of 0x200000 bytes
EAL: Virtual area found at 0x7f0a9c600000 (size = 0x200000)
EAL: Ask a virtual area of 0x200000 bytes
EAL: Virtual area found at 0x7f0a9c200000 (size = 0x200000)
EAL: Ask a virtual area of 0x3fc00000 bytes
EAL: Virtual area found at 0x7f0a5c400000 (size = 0x3fc00000)
EAL: Ask a virtual area of 0x200000 bytes
EAL: Virtual area found at 0x7f0a5c000000 (size = 0x200000)
EAL: Requesting 1024 pages of size 2MB from socket 0
EAL: Requesting 1024 pages of size 2MB from socket 1
EAL: Master core 0 is ready (tid=de25b700)
EAL: Core 1 is ready (tid=5b7fe700)
EAL: Core 3 is ready (tid=5a7fc700)
EAL: Core 2 is ready (tid=5affd700)
hello from core 1
hello from core 2
hello from core 3
hello from core 0
8 怎么在intel平台上獲得網卡的最好性能
本章是在INTEL平台上DPDK程序獲得高性能的一步步引導。
8.1 硬件和內存需求
要最好的性能最好是使用intel至強系列服務器,例如Ivy Bridge,Haswell或者是更新的架構的服務器。
確保每一個內存通道至少有一個內存DIMM插入,且內存的大小至少4GB。注意:這個在性能上有最直接的影響。
你可以檢查內存配置通過dmidecode命令,如下:
dmidecode -t memory | grep Locator
Locator: DIMM_A1
Bank Locator: NODE 1
Locator: DIMM_A2
Bank Locator: NODE 1
Locator: DIMM_B1
Bank Locator: NODE 1
Locator: DIMM_B2
Bank Locator: NODE 1
...
Locator: DIMM_G1
Bank Locator: NODE 2
Locator: DIMM_G2
Bank Locator: NODE 2
Locator: DIMM_H1
Bank Locator: NODE 2
Locator: DIMM_H2
Bank Locator: NODE 2
上面的輸出展示了總共8個內存通道,每個通道有2個DIMM。
也可以通過dmidecode命令確定內存的頻率:
dmidecode -t memory | grep Speed
Speed: 2133 MHz
Configured Clock Speed: 2134 MHz
Speed: Unknown
Configured Clock Speed: Unknown
Speed: 2133 MHzConfigured Clock Speed: 2134 MHz
Speed: Unknown
...
Speed: 2133 MHz
Configured Clock Speed: 2134 MHz
Speed: Unknown
Configured Clock Speed: Unknown
Speed: 2133 MHz
Configured Clock Speed: 2134 MHz
Speed: Unknown
Configured Clock Speed: Unknown
上述輸出表明內存為2133MHz的DDR4內存。和前面的信息結合起來可以確定每個內存通道有一根內存條。
8.1.1 網卡需求
使用DPDK支持的高端網卡,比如INTEL XL710 40GBE。
確保每一個網卡刷入了最新版本的固件。
使用PCIe Gen3插槽,例如Gen3 x8或者是Gen3 x16,因為PCIe Gen2插槽無法提供足夠的寬帶,2X10Gbe或者是更高。可以通過使用lspci命令檢查PCI插槽的使用信息:
lspci -s 03:00.1 -vv | grep LnkSta
LnkSta: Speed 8GT/s, Width x8, TrErr- Train- SlotClk+ DLActive- ...
LnkSta2: Current De-emphasis Level: -6dB, EqualizationComplete+ ...
當擦汗如網卡到PCI插槽時總要檢查說明信息,例如CPU0或者是CPU1連接到的是哪個socket上。
多考慮一下NUMA。如果你使用2個或者是更多的不同的網口,最好確保這些網卡在同樣的CPU socket上。如何確定看下面的例子。
8.1.2 BIOS設置
下面是推薦的BIOS設置項。不同的平台上可能有不同的BIOS名稱,所以下面主要是作為參考:
- 考慮重新設置所有的BIOS默認配置
- 禁用所有的省電選項,例如:電源性能優化(Power performance tuning),CPU P-State,CPU C3 Report and CPU C6 Report。
- CPU Power and Performace策略選擇 Performance。
- 禁用Tuibo Boost以確保性能隨着核數的增長線性增加
- 設置內存頻率為可用的最高數,而不是auto。
- 當測試網卡的物理功能時,禁用所有的虛擬化選項,在需要使用VFIO是打開VT-d。
8.1.3 Linux內核啟動參數
下面是GRUB啟動參數建議設置:
- 使用默認的grub文件作為啟動點。
- 通過grub配置申請1G大小的內存頁。例如申請8個1GB內存頁:
default_hugepagesz=1G hugepagesz=1G hugepages=8
- 跟你DPDK程序需要使用CPU核心,例如:
isolcpus=2,3,4,5,6,7,8
- 要使用VFIO,把下面的作為額外的grub參數:
iommu=pt intel_iommu=on
8.2 運行DPDK前的配置
- 編譯DPDK target,分配大頁內存。看前面的章節。
下面的shell命令有助於編譯和配置DPDK。
# Build DPDK target.
cd dpdk_folder
make install T=x86_64-native-linuxapp-gcc -j
# Get the hugepage size.
awk '/Hugepagesize/ {print $2}' /proc/meminfo
# Get the total huge page numbers.
awk '/HugePages_Total/ {print $2} ' /proc/meminfo
# Unmount the hugepages.
umount `awk '/hugetlbfs/ {print $2}' /proc/mounts`
# Create the hugepage mount folder.
mkdir -p /mnt/huge
# Mount to the specific folder.
mount -t hugetlbfs nodev /mnt/huge
- 使用DPDK的cpu_layout腳本檢查CPU分布:
cd dpdk_folder
usertools/cpu_layout.py
- 檢查網卡ID和所屬的Socket ID:
# List all the NICs with PCI address and device IDs.
lspci -nn | grep Eth
舉例說明,假設輸出是這樣的:
82:00.0 Ethernet [0200]: Intel XL710 for 40GbE QSFP+ [8086:1583]
82:00.1 Ethernet [0200]: Intel XL710 for 40GbE QSFP+ [8086:1583]
85:00.0 Ethernet [0200]: Intel XL710 for 40GbE QSFP+ [8086:1583]
85:00.1 Ethernet [0200]: Intel XL710 for 40GbE QSFP+ [8086:1583]
檢查PCI設備所述的NUMA節點ID:
cat /sys/bus/pci/devices/0000\:xx\:00.x/numa_node
通常情況下,0x:00.x是位於socket0上,8x:00.x位於socket1上。注意:為了獲得更高的性能,確保cpu核心和網卡在同樣的socket上。例如上面的85:00.0在socket1上,那么它被socket1上的核心使用能獲得最好的性能。
- 綁定測試網口到DPDK支持的驅動上,例如igb_uio。例如,綁定兩個短褲到DPDK驅動並檢查狀態:
# Bind ports 82:00.0 and 85:00.0 to dpdk driver
./dpdk_folder/usertools/dpdk-devbind.py -b igb_uio 82:00.0 85:00.0
# Check the port driver status
./dpdk_folder/usertools/dpdk-devbind.py –status
查看dpdk-devbind.py –help獲取更多細節。
8.3 獲取intel網卡的最好性能例子
下面是運行DPDK3層轉發例子:l3fwd程序,使用intel服務器平台和intelXL710網卡獲的高性能。對於特殊的40GbE午那個卡的配置請查閱i40e網卡手冊。
這個例子展示的是在兩個INTELXL710 40GbE網口下獲得的最好性能。
- 插入兩個intelXL710網卡到機器上,且使用每個網卡的一個網口以獲取更高的性能,使用兩個網卡是因為一個PCIe Gen3插槽不能提供2個40G端口的80G的帶寬去求,而兩個不同的PCIe Gen3 x8插槽則可以,那么就客服了這個限制。引用上面的網卡狀態輸出,我們可以選擇82:00.0和85:00.0作為測試網口:
82:00.0 Ethernet [0200]: Intel XL710 for 40GbE QSFP+ [8086:1583]
85:00.0 Ethernet [0200]: Intel XL710 for 40GbE QSFP+ [8086:1583]
- 連接端口到對應的發包設備上。為了高性能的測試,最好使用一個專門的硬件發包器。
- 檢查PCI設備的NUMA節點ID(socket id),獲取杜英的socketID上的核心編號。在這個例子中,82:00.0和85:00.0均在socket1上,本平台的socket上的核心是18-35和54-71。注意:不要使用在同一個物理核心上的2個邏輯核心(例如:core18有兩個邏輯核心,core18和core54),取而代之的是,使用在不同物理核心上的邏輯核辛(例如core18和core19)。
- 綁定兩個端口到igb_uio。
- 對於XL710 40G網口,至少需要2組兩個隊列以獲取最好的性能,即每個端口要兩個隊列。每組端口需要一個CPU核心做報文的收發。
- DPDK程序l3fwd將用於性能測試,使用兩個端口直接轉發。使用默認的lpm(最長前綴匹配)模式編譯l3fwd程序。
- 運行l3fwd程序的命令行參數如下:
./l3fwd -c 0x3c0000 -n 4 -w 82:00.0 -w 85:00.0 \
-- -p 0x3 --config '(0,0,18),(0,1,19),(1,0,20),(1,1,21)'
這代表着程序使用core18轉發port0的隊列0,core19轉發port0的隊列1,core20轉發port1的隊列0,core21轉發port1的隊列1。
- 配置發包器的流量
a) 在發包器上創建一個流
b) 設置以太網II類型為0x8000