1引言
本文檔主要包含INTEL DPDK安裝和配置說明。目的是讓用戶快速的開發和運行程序。文檔描述了如何在不深入細節的情況下在linux應用開發環境上編譯和運行一個DPDK應用程序。
1.1文檔總覽
以下是DPDK文檔列表,建議按照文檔順序閱讀:
- Release Note:提供版本特有信息,包括支持的型號,限制,修正的問題,一直的問題等等。也提供一些在常見問題解答中被頻繁問道的問題的大案。
- 入門指導(Getting Started Guide(本文檔)):描述怎么安裝和配置DPDK,目的是讓用戶快速開發和運行軟件。
- 開發手冊(Programmer's Guide):描述:
- 軟件架構和如何在linux環境下運行一個DPDK范例程序
- DPDK的內容,開發系統(包括如何在DPDK根目錄下使用的編譯Makefile的指令來編譯開發庫和運用程序)和移植一個應用程序參考
- 軟件優化和需要在新的開發環境考慮的問題。
- 也提供了關鍵詞匯表:
- API手冊:提供了DPDK上的函數,數據結構和其它編程結構的詳細信息。
- 范例使用手冊(Sample Application User Guide):描述了一系列的范例程序,每個章節都描述了一個有特殊功能的示例,提供了編譯,運行和使用示例的操作指南。
注意:以上文檔都可以從DPDK源碼包的同一個位置上分別下載。
2系統必備條件
本章講的是編譯DPDK源碼包必須具有的環境。
注意:如果DPDK要用到intel的89XX系列的網卡平台上,請先翻閱89xx網卡系列的入門手冊。
2.1X86上BIOS先決條件
對於主要的平台,沒有什么特別的BIOS設置才能用DPDK的基本功能。然而總有例外的,對於HPET高精度時鍾,能源管理功能,在40g網卡上高性能的小包收發,BIOS設置需要改一下。請看第5章(其它功能的開啟)來獲取需要做哪些更改的信息。
2.2編譯DPDK
注意:測試是在Fedora18上,編譯安裝指令在其它系統上可能不一樣。在其它linux發行版本上的測試細節請參閱DPDKrelease note。
- GNU make
- coreutils:cmp,sed,grep,arch
- gcc:在686/x86_64平台上得大於等於4.5.x版本,對於ppc_64 和x86_x32程序,建議用4.8.x版本。一些特殊的編譯標識和連接標示默認是打開的,會影響到性能(例如-fsatckprotector),請參閱你所使用版本的說明文檔和使用gcc -dumpspecs來查看。
- c庫:intel的架構上要求glibc-devel.i686 / libc6-dev-i386; glibc-devel.x86_64 for 64-bit,ibm power架構則要求glibc-devel.ppc64 for 64 bit
- linux內核源碼庫頭文件用於編譯內核模塊:kernel-devel.x86_64,kernel - devel.ppc64
- 另外32位和64位編譯環境需要的包有:glibc.i686, libgcc.i686, libstdc++.i686 and glibc-devel.i686 for Intel i686/x86_64;glibc.ppc64, libgcc.ppc64, libstdc++.ppc64 and glibc-devel.ppc64 for IBM ppc_64;
注意:x86_32應用程序接口只支持最新的debian發行版和13.10以上版本的unbuntu。唯一支持的gcc版本是4.8+。
注意:python需要2.6或者是2.7,在dpdk安裝包中有各種各樣的幫助腳本。
可選的工具:
- intel C++編譯器(icc)。需要安裝一些其它的庫,自己看編譯器安裝的說明文檔吧,這個版本已經在icc 12.1上測過
- IBM powerLinux工具鏈。這是一系列的開源開發工具和能夠用到power最新linux硬件特征的動態庫,要安裝的話看ibm的官方文檔
- 編譯和使用基於libpcap庫的輪詢驅動需要libpcap頭文件和庫(libpcap-devel)。驅動默認是不能用的,要用的話需要在編譯時設置config文件中的CONFIG_RTE_LIBRTE_PMD_PCAP=y
2.3運行DPDK程序
要運行dpdk程序,在目標機器上需要一些本地化要求。
2.3.1系統軟件
要求:
- 內核版本 >= 2.6.33
當前在使用的內核版本可以通過以下命令獲取:
uname -r
對於在更早的內核版本上使用DPDK需要的補丁細節,可以看DPDK的Release Notes中的DPDK FAQ。也要注意redhat 6.2和6.3使用的2.6.32內核版本需要用到所有必須得補丁。
- glibc >= 2.7(因為cpuset相關的操作)
c庫版本可以通過使用ldd -version命令獲取,一個命令使用結果例子如下:
# ldd --version
ldd (GNU libc) 2.14.90
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.
- 內核配置
在fedora os和其它普通的linux發行版,例如ubuntu,或者是紅帽企業版linux,供應商提供的內核配置可以跑大部分DPDK應用。
對於其它內核版本,要使用DPDK必須使一下選項能支持:
-
- UIO支持
- HUGETLBFS(大頁內存用到的庫)
- PROC_PAGE_MONITOR支持
- 要使用HPET就要求HPET和HPET_MMAP配置項能支持。看5.1章《高精度定時器(HPET)功能》細節。
2.3.2在linux上使用大頁內存
對於要緩存報文的超大內存池的內存分配必須用hugepage,(HUGETLBFS選項在當前允許的內核上必須是支持的,入2.3所說的)使用大頁來分配內存,即使只使用少數頁面,性能也是能夠得到提升的。因為用到更少的頁表緩沖條目(TLBs,高速翻譯緩存),可以減少翻譯虛擬地址到物理地址的時間,如果不用大頁,那么用4k的頁較高的TLB丟失率會降低性能。實際上還有一個好處就是不會被交換到磁盤上去。
獲取DPDK使用的大頁內存
分配大頁內存最好是在系統啟動時或者是在啟動后盡早,以便於申請的內存減少碎片,即內存在物理上盡量是連續的。在內核啟動時獲取大頁內存,需要將一個參數傳遞給內核。
對於2m的頁,僅僅只需要將大頁選項發送給內核。例如,申請1024個2m的頁:
hugepages=1024
對於其它尺寸的大頁內存,例如1g的頁,頁大小必須明確的指定,也能設置系統的默認大頁內存大小。例如申請4g大小的大內存通過4個1g內存頁的形式,需要將以下選項發給內核:
default_hugepagesz=1G hugepagesz=1G hugepages=4
注意:在intel的架構機器上cpu支持的大頁內存的尺寸取決於CPU標識(這些標示可以通過查看/proc/cpuinfo獲取),如果pse存在,那么2m頁支持,pdpe1gb存在,則1g頁支持。在IBM power架構的機器上,支持16M和16G的頁。
注意:64位機器,交付時如果平台支持那天生就支持1g頁了。
對於2個socket的NUMA系統,申請的大頁內存數在系統啟動時一般是從兩個socket上平均分配(假定兩個socket上都有足夠的內存),如上,4g就是一個socket上分出2g內存。
可以看內核源碼樹的Documentation/kernel-parameter.txt文件獲取更多的內核選項細節。
可選項:
2m的頁也可以在系統啟動后申請,通過echo 內存頁數目到/sys/devices/目錄下的文件nr_hugepages中。對於單node的系統,使用一下命令獲取1024個2m內存頁:
echo 1024 > /sys/kernel/mm/hugepages/hugepages_2048kb/nr_huge
在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的大內存頁是不可能在系統啟動之后申請分配的。
2.3.3 linux環境下Xen Domain0支持
當前的內存管理基於linux內核的大內存頁機制,在Xen虛擬機監視器上,大頁支持無特權賬戶意味着DPDK程序是作為一個普通用戶態程序運行。
然而,Domain0不支持大頁的,解決這個限制需要,內核模塊rte_dom0_mm加入,使得可以通過IOCTL和MMAP來分配和映射內存。
在DPDK中打開Xen Dom0模式
默認情況下,Xen Dom0在DPDK配置文件中是關閉的,要支持Xen Dom0就需要改變配置項CONFIG_RTE_LIBRTE_XEN_DOM0的值為y,那這個功能在編譯時就是打開的。
此外,CONFIG_RTE_EAL_ALLOW_INV_SOCKET_ID選項也應該設為y,避免萬一收到錯誤的socket id。
加載DPDK rte_dom0_mm模塊
在Xen Dom0上跑DPDK程序,rte_dom0_mm模塊必須帶着參數rsv_memsize選項加載入運行中的內核中。模塊可以在DPDK目錄下的子目錄kmod中找到,加載時使用insmod命令,像下面一樣操作(假設我們當前處於DPDK的根目錄下):
sudo insmod kmod/rte_dom0_mm.ko rsc_memsize=X
X的值可以大於4096(MB)
配置DPDK使用的內存
在加載完rte_dom0_mm.ko內核模塊后,用戶必須配置DPDK使用的內存大小。通過echo 內存頁數目到/sys/devices/目錄下的內存大小配置文件中。使用如下命令(假設需要2048MB內存):
echo 2048 >/sys/kernel/mm/dom0_mm/memsize-mB/memsize
用戶也可以檢查當前已經使用了多少內存:
cat /sys/kernel/mm/dom0-mm/memsize-mB/memsize_revd
Xen Domain0不支持NUMA配置,所以–socket-mem選項對它來說是沒用的。
注意:內存大小值不能大於rsv_memsize值
在Xen Domain0上跑DPDK程序
要在Xen Domain0上跑DPDK程序,必須帶上額外的選項–xen-dom0
3編譯DPDK源碼包
3.1安裝DPDK和查看源碼
首先,解壓壓縮包並進入DPDK目錄:
user@host:~$ unzip DPDK-<version>.zip
user@host:~$ cd DPDK-<version>
user@host:~/DPDK-<version>$ ls
app/ config/ drivers/ examples/ lib/ LICENSE.GPL LICENSE.LGPL Makefile mk/ sc
解壓的DPDK目錄下有幾個子目錄:
- lib:DPDK庫源碼
- drivers:DPDK PMD源碼
- app:DPDK程序源碼(自動化測試用)
- examples:DPDK應用程序范例源碼
- config,tools,scripts,mk:框架相關的makefile文件,腳本,配置文件等。
3.2在目標機器環境下安裝DPDK
安裝DPDK的結果格式如下(就是在當前目錄下回出現一個新目錄,目錄名格式):
ARCH-MACHINE-EXECENV-TOOLCHAIN
- ARCH:i686, x86_64, ppc_64
- MACHINE:native, ivshmem, power8
- EXECENV:linuxapp,bsdapp
- TOOCHAIN:gcc,icc
我在redhat上的是x86_64-native-linuxapp-gcc(intel的ICC編譯器沒用過...,據說在intel的機器上,用icc性能高一些)
生成的文件取決於32/64位安裝包和機器上的編譯器。能實現的結果可以在DPDK/config中看到。defconfig_ prefix沒必要用到。
注意:提供的配置文件是根據RTE_MACHINE優化的最優選項集,在配置文件中,RTE_MACHINE配置項
被設為native,意味着編譯軟件會自動匹配編譯的平台。要看更多關於設置和可能值的詳細星系,請看DPDK Programmers Guide
當使用intel的C++編譯器icc,需要針對64位和32位系統分別執行下面的命令。注意shell腳本更新了PATH環境變量,因此在同一個會話中不需要再執行了。另外,確認編譯的安裝目錄因為目錄可能不一樣:
source /opt/intel/bin/iccvars.sh intel64
source /opt/intel/bin/iccvars.sh ia32
安裝和編譯,在DPDK根目錄下執行make install T=<target>命令。
例如,用icc編譯64位系統,執行:
make install T=x86_64-native-linuxapp-icc
用gcc編譯32位系統,命令如下:
make install T=i686-native-linuxapp-gcc
用gcc編譯64位系統:
make install T=x86_64*gcc
同時使用gcc和icc編譯64位系統:
make install T=x86_64-*
注意:通配符*表示可以同時生成多個結果。
准備編譯而不是編譯它,例如,配置被改變了需要在編譯前make一下,使用make config T=<target>命令:make config T=x86_64-native-linuxapp-gcc
提示:任意一個使用到的內核模塊,如igb_uio,rte,必須在目標機器上同一個運行的內核上編譯。如果你的DPDK不是要裝在本機,那么編譯前需要將RTE_KERNELDIR指向需要安裝的機器的內核版本的一個拷貝。
暈:忘了保存了........,再來一遍
一旦環境配置好了,那么進入配置的目錄修改代碼並編譯。用戶如果要修改編譯時的配置,那么修改安裝目錄下的.config文件。它是安裝根目錄下的config目錄中的defconfig文件的一個拷貝。
cd x86_64-native-linuxapp-gcc
vi .config
make
此外,make clean命令可以清除之前編譯產生的文件,以便重新編譯。
3.3查看安裝完成的DPDK環境目錄
一旦編譯完成,那么這個DPDK環境目錄包含所有的庫文件,PMD,所有DPDK應用程序需要用到了DPDK頭文件。此外,測試程序和測試PMD程序在對應的build/app目錄下,可以用來測試。當前的kmod目錄下需要被加載到內核中的木塊。
$ ls x86_64-native-linuxapp-gcc
app build hostapp include kmod lib Makefile
3.4加載內核模塊實現DPDK用戶態IO
跑dpdk程序,對應匹配的uio模塊需要加載到運行的內核中。很多情況下,linux內核已經有的uio_pci_generic模塊可以提供uio能力,可以通過以下命令加載:
sudo modprobe uio_pci_generic
相對這個正式的方式,DPDK還提供kmod子目錄下的igb_uio模塊實現這個功能。加載如下:
sudo modprobe uio
sudoi insmod kmod/igb_uio.ko
注意:對於一些缺乏對中斷支持的設備,例如虛擬設備(VF),igb_uio需要用來替換uio_pci_generic。
從DPDK1.7以上版本提供VFIO支持以后,對於使用VFIO的平台來說,用不用uio就無所謂了。
3.5在家VFIO模塊
運行一個使用VFIO的程序,vfio-pci模塊必須加載:
sudo modprobe vfio-pci
當然要使用VFIO,內核也必須支持才行。自動3.6.0內核版本以來都包含有VFIO模塊且默認都是加載的,但是最好是看看對應使用的linux發行版本的說明文檔以防萬一。
哎,用VFIO,內核和BIOS都必須支持且被配置使用IO virtualization(例如 intel@VT-d(bios里面的一個選項)
對於非root用戶在跑dpdk程序時,應該賦予相應的權限操作VFIO。可以通過DPDK腳本來實現(在tools目錄下,名字是setup.sh)
3.6綁定和解綁網卡從內核模塊
自從dpdk1.4版本起,dpdk程序不再需要自動的解綁所有支持dpdk且內核驅動正在用的網卡。取而代之的是,dpdk程序要用到的網卡必須在程序運行前綁定到uio_pci_generic, igb_uio或者vfio-pci模塊。在linux內核驅動控制下的網卡都會被dpdk的pmd忽略,也不會被程序使用。
提示:dpdk將,也是默認,不再在啟動時自動從linux內核驅動解綁每個網卡。任意一個要被dpdk用到的網卡必須在程序運行前先從linux控制下解綁然后綁定到對應的uio_pci_generic, igb_uio or vfio-pci。
綁定網卡到uio_pci_generic, igb_uio or vfio-pci供dpdk使用,以及將網卡返回給linux系統控制,tools子目錄下叫dpdk_nic_bind.py腳本可以提供該功能。這個腳本可以列出當前系統內所有網卡的狀態信息,也可以從不同linux驅動綁定或者解綁網卡,包括uio和vfio模塊。下面是一些展示腳本如何使用的例子。對於腳本完整的功能和參數介紹可以通過使用腳本帶上-help或者是-usage參數。要注意的是使用dpdk_nic_bind.py腳本前需要將uio或者是vfio加載到內核中。
提示:對於使用VFIO的設備會有一些限制。主要歸結於IOMMU分組如何工作。任何虛擬設備就其本身而言都可以使用VFIO,但是對於物理設備要求綁定到VFIO,或者是其中一些綁定到VFIO而另外的不綁定到任何東西上。
如果你的設備是在一個PCI-to-PCI網橋之后,網橋將作為設備的IOMMU組的一部分。所以當設備在網橋之后工作於VFIO,網橋驅動也必須與網橋PCI設備解綁。
提示:任何用戶可以使用腳本查看網卡狀態,解綁和綁定網卡,但是需要root權限。
上面這個xen啊,vfio啊,不是很懂,翻譯的不是很清楚,也可能翻譯錯了,想搞明白還是看原文吧。
看系統內網卡的狀態:
root@host:DPDK# ./tools/dpdk_nic_bind.py --status
Network devices using DPDK-compatible driver
============================================
0000:82:00.0 '82599EB 10-Gigabit SFI/SFP+ Network Connection' drv=uio_pci_generic unused=ixgbe
0000:82:00.1 '82599EB 10-Gigabit SFI/SFP+ Network Connection' drv=uio_pci_generic unused=ixgbe
Network devices using kernel driver
===================================
0000:04:00.0 'I350 Gigabit Network Connection' if=em0 drv=igb unused=uio_pci_generic *Active*
0000:04:00.1 'I350 Gigabit Network Connection' if=eth1 drv=igb unused=uio_pci_generic
0000:04:00.2 'I350 Gigabit Network Connection' if=eth2 drv=igb unused=uio_pci_generic
0000:04:00.3 'I350 Gigabit Network Connection' if=eth3 drv=igb unused=uio_pci_generic
Other network devices
=====================
<none>
綁定網卡eth1,04:00.1(eth1的pci號),到uio_pci_generic驅動:
root@host:DPDK# ./tools/dpdk_nic_bind.py --bind=uio_pci_generic 04:00.1
或者是用這種方式:
root@host:DPDK# ./tools/dpdk_nic_bind.py --bind=uio_pci_generic eth1
恢復設備82:00.0,綁定到原有的內核驅動:
root@host:DPDK# ./tools/dpdk_nic_bind.py --bind=ixgbe 82:00.0
4編譯和運行范例程序
本章介紹了如何編譯和在DPDK環境下運行程序,也指示了范例程序存在哪里。
注意:本章的部分內容可以在第6章描述的使用安裝腳本后操作。
4.1編譯范例程序
一旦DPDK環境創建完成(例如x86_64-nativelinuxapp-gcc),包含開發程序需要的所有的DPDK庫和頭文件。
當在linux下編譯一個基於dpdk的程序,下面的兩個參數要被導出:
RTE_SDK:指向DPDK安裝目錄
RTE_TARGET:指向DPDK目的環境目錄,就是編譯dpdk產生的目錄,例如x86_64-nativelinuxapp-gcc
下面是創建helloworld程序的例子,這個是在dpdk linux環境在運行的。這個例子可以在${RTE_SDK}/examples目錄下找到。
這個目錄包含一個main.c文件。這個文件和dpdk目錄下的庫結合,調用各種初始化dpdk環境的函數,然后加載每個core的入口函數(分發程序)運行。(這個我自己明白但是翻譯的不清楚,實際就是在dpdk線程上運行一個入口函數,在函數內再根據所在的邏輯核配置跑對應的功能,入rx,tx,fp)。默認編譯產生的可執行二進制文件在build目錄下。
user@host:~/DPDK$ cd examples/helloworld/
user@host:~/DPDK/examples/helloworld$ export RTE_SDK=$HOME/DPDK
user@host:~/DPDK/examples/helloworld$ export RTE_TARGET=x86_64-native-linuxapp-gcc
user@host:~/DPDK/examples/helloworld$ make
CC main.o
LD helloworld
INSTALL-APP helloworld
INSTALL-MAP helloworld.map
user@host:~/DPDK/examples/helloworld$ ls build/app
helloworld helloworld.map
注意:在上面的例子中,helloworld是在dpdk目錄框架下。然而也有可能它不再dpdk目錄下以保證dpdk的完整。在下面的例子中,helloworl程序就是從dpdk目錄下將helloworld拷貝到一個新的目錄下:
user@host:~$ export RTE_SDK=/home/user/DPDK
user@host:~$ cp -r $(RTE_SDK)/examples/helloworld my_rte_app
user@host:~$ cd my_rte_app/
user@host:~$ export RTE_TARGET=x86_64-native-linuxapp-gcc
user@host:~/my_rte_app$ make
CC main.o
LD helloworld
INSTALL-APP helloworld
INSTALL-MAP helloworld.map
4.2運行一個范例程序
提示:uio驅動和大頁內存必須在程序運行前設置。
提示:每個程序使用的網卡必須綁定到內核對應的驅動,實際就是我們家在到內核的dpdk內核模塊,如igb_uio等,如3.5所寫的,這個動作也要在程序運行前執行。
程序是和dpdk目標環境下的環境抽象層庫連接,后者提供了每個dpdk程序通用的一些選項。
下面是需要提供給eal的參數列表:
./rte-app -c COREMASK -n NUM [-b <domain:bus:devid.func>] [--socket-mem=MB,...] [-m MB] [-r NUM]
EAL選項如下:
- -c coremask:16進制的要運行的邏輯核位掩碼。注意在不同的平台之間core編號可能不同,需要預先確定好。
- -n NUM:每個處理器插槽的內存通道數
- -b <domain:bus:devid.func>:網卡黑名單,阻止EAL使用的特殊的PCI設備,支持多個-b選項
- -use-device:只使用特殊的網卡設備,可以使用逗號分割的<[domain:]bus:devid.func>值來指定。不能喝-b一起用
- -socket-mem:從特定的socket上分配大頁內存
- -m MB:從大頁分配內存數,不區分是那個socket。建議用-socket-mem代替這個選項
- -r NUM:內存rank數(說實話,查了那么多資料,還是對這個不是很清楚啊)
- -v:在啟動時顯示版本信息
- -huge-dir:大頁內存掛在的目錄
- -file-prefix:用於大頁文件的前綴名
- -proc-type:The type of process instance進程類型(主/備吧,我猜的沒有用過多進程的)
- -xen-dom0:支持程序在Xen Domain0上不使用大頁運行
- -vmware-tsc-map:使用VMvare的TSC代替本地的RDTSC
- -base-virtaddr:特定的虛擬基地址
- -vfio-intr:VFIO使用的特定的中斷類型(即使VFIO不使用也沒有影響)
-n和-c是必須得,其它都是可選項
拷貝可執行程序到目的機器上,如下運行程序(假設每個socket有4個內存通道,使用0-3核跑該程序):
user@target:~$ ./helloworld -c f -n 4
注意:選項-proc-type和-file-prefix EAL用於跑多個dpdk程序,可以看《dpdk范例程序使用手冊》中的多進程范例程序一章和dpdk開發手冊獲取更多細節。
4.2.1程序使用的邏輯核
對於dpdk程序,參數coremask是必須有的。每個bit的掩碼都對應linxu展示的邏輯核編號。這些邏輯核編號對應具體得NUMA上的物理核心,不同的平台會不同,建議在不同的平台上運行不同的例子要考慮選擇使用的core的分布。
運行dpdk程序初始化EAL時,會將使用的邏輯核和對應的socket打印出來。這些信息也可用通過查看/proc/cpuinfo來獲取,例如,執行 cat /proc/cpuinfo,顯示的physical id表明了每個核所屬的cpu插槽。這個在我們弄明白邏輯核和socket的映射關系時很有用。
注意:更多的邏輯核分布的拓撲結構視圖可以通過使用lstopo獲取。在Fedora上,該命令可能安裝了,像這樣運行:
sudo yum install hwloc
./lstopo
提示:在不同的主板上布局不同,邏輯核的分布也會不同,我們需要在選取程序使用的邏輯核之前檢查一下
4.2.2程序使用的大頁內存
在程序運行時,使用分配的數量的大頁內存(就是你分配多少就用多少了,而不是按需去整),這是在沒有指定參數-m和-socket-mem時程序在啟動時自動執行的。
如果程序使用-m和-socket-mem指定具體的內存數超出時,程序就會掛掉。然而,程序要求使用的內存比分配保留的大頁內存數小,特別是用-m選項指定時,程序也可能會掛掉。原有如下:假設現在系統在socket0和socket1上各有1024個2M的大內存頁。如果用戶申請使用128M內存,那64個頁可能不滿足以下限制:
- 內核只在soket1上給程序分配了大頁內存。萬一程序想要在socket0上創建一個對象,例如隊列或者是mempool,程序會報錯。要避免這個錯誤建議使用-socket-mem選項代替-m選項。(就是-m是內核隨機分配的內存,不知道在哪個socket上,而-socket-mem是指定socket,我們創建隊列,mempool是需要指定使用內存的socke,如果這個socket上內存不足就會報錯退出)
- 這些內存頁可能在物理內存上隨機的分布在任意一個地方,而dpdk EAL試圖分配一個在物理上連續的內存塊。在這些物理頁不連續時,萬一程序想要申請一段很大的mempool是灰報錯。
-socket-mem選擇用於在特定的socket上申請指定數目的內存頁。使用-socket-mem帶上每個socket申請的內存數實現。例如,使用-socket-mem=0,512,意味着只在socket1上分配512m內存。同樣的,在4個socket的機器上,從socket0和socket2上分配各1g內存,參數應該是-socket-mem=1024,0,1024.在其它沒有明確指定的cpusocket上不會分配內存,如socket3.如果dpdk在每個socket上不能申請到足夠的內存,EAL就會初始化失敗。
4.3其它的范例程序
其它的例子程序在${RTE_SDK}/examples目錄下。這些程序的創建和運行與本手冊中其它章節描述的差不多。另外就是看《dpdk范例程序使用手冊》看具體每個程序的描述信息,編譯和執行時的特殊指令,以及一些代碼的注釋說明。
4.4另外的測試程序
除此之外,有兩個程序在庫創建時也創建了。源文件在DPDK/app下,在測試和測試pmd時調用。可以在庫創建完成后,在build/app下找到。
測試程序提供了DPDK各種功能的多種測試。
PMD測試程序提供了一些不同的包收發測試和像如何使用INTEL® 82599萬兆網卡的FLow Director這類特征的例子。
5打開其它功能
5.1高精度時鍾功能HPET
5.1.1BIOS支持
要使用HPET那么平台的BIOS必須是支持的,否則使用默認的TSC。一般情況下,開機時按F2可以進入bios設置。用戶可以選擇HPET選項。在intel的Crystal Forest平台的BIOS上,路徑是Advanced -> PCH-IOConfiguration -> High Precision Timer -> (Change fromDisabled to Enabled if necessary).
在系統重啟后,用下面的指令確認是否打開HPET:
# grep hpet /proc/timer_list
如果沒啥返回,HPET在BIOS上肯定打開了,每次在重啟后執行上述命令。
5.1.2linux內核支持
dpdk使用平台的HPET通過映射時間戳計時器到用戶地址空間,諸如此類的,就需要內核的HPET_MMAP選項打開。
提示:在Fedora上,和其它的注入unbuntu發現版上,HPET的內核選項默認是關閉的。在將選項修改后在編譯內核,請通過查看發行版文檔來獲取確切的指令。
5.1.3在DPDK中打開HPET
默認情況下,DPDK的配置文件中HPET支持選項是禁用的。要使用HPET,那么CONFIG_RTE_LIBEAL_USE_HPET選項需要設置成y,會在編譯時使用HPET配置。
應用程序要使用rte_get_hpet_cycles() 和rte_get_hpet_hz()這兩個接口,使用HPET最為rte_timer庫的默認時間源。API rte_eal_hpet_init()需要在程序初始化時調用。這個API的調用確認HPET是可以使用,返回錯誤值則說明不能用。例如,如果內核的HPET_MMAP是關閉的。程序可以決定采取什么動作,如果HPET在運行時不能用。
注意:程序要使用時間API,但是明確HPET是不能用時,建議使用rte_get_timer_cycles() and rte_get_timer_hz()代替HPET相關的API。這兩個API使用的不是TSC就是HPET,取決於程序是否調用了rte_eal_hpet_init(),做了就看系統是否在運行時支持了。
5.2非root權限下運行dpdk程序
盡管基於dpdk的程序能直接使用到網卡和其它硬件資源,只需要一點小的權限調整即可跑起來而不是作為root用戶使用。要實現這些,文件的所有者或者是權限要調整以便確保linux用戶賬號能夠使用dpdk程序:
- 作為大頁掛在點服務的目錄,例如:/mnt/huge
- 在/dev下用戶態io設備文件,例如:/dev/uio0,/dev/uio1等等
- 用戶態io sysfs配置和源文件,例如uio0:/sys/class/uio/uio0/device/config /sys/class/uio/uio0/device/resource*
- 如果使用了HPET,/dev/hpet
注意:在一些安裝的linux上,會默認創建一個大頁的掛載點/dev/hugepages
5.3電量管理和省電功能
要用到dpdk的電源管理功能就要求該平台的bios支持增強型intel SpeedStep®技術,否則,sys文件/sys/devices/system/cpu/cpu0/cpufreq就不會存在且cpu平率調整的電源管理也不恩能夠用。查閱相關的bIOS文檔看如何實現吧
舉例說明,在一些intel平台上,Enhanced IntelSpeedStep® Technology在BIOS的路徑是:
Advanced->Processor Configuration->Enhanced Intel SpeedStep® Tech
此外,為了電源管理C3和C6也需要打開。C3和C6路徑如下:Advanced->Processor Configuration->Processor C3 Advanced->ProcessorConfiguration-> Processor C6
5.4使用linux的cpu核心隔離來減少上下文切換的開銷
當DPDK程序線程固定在系統的摸一個核上運行時,linux調度器可能會將其它的任務調度到該核上運行。為了防止其它負載調度到dpdk使用的核上,需要使用linux內核參數isolcpus來將這些核從linux調度器中隔離開。
例如,如果dpdk程序跑在邏輯核2,4,6上,下面的這個參數需要加到內核選項(就是那個grub文件)中:
isolcpus=2,4,6
5.5 加載kni模塊
要跑dpdk KNI例子程序,需要額外加載一個模塊kni。在dpdk編譯目錄下的kmod中,和加載igb_uio一樣,使用ismod加載:
#insmod kmod/rte_kni.ko
注意:請看DPDK范例使用手冊的KNI示例章節。
5.6通過intel的VT-d虛擬化技術實現IOMMU直接傳輸跑dpdk
要讓linux內核支持intel® VT-d,需要打開以下內核選項:
• IOMMU_SUPPORT
• IOMMU_API
• INTEL_IOMMU
此外,要跑使用intel VT-d技術的dpdk程序,在使用igb_uio驅動時必須帶上iommu=pt參數。這會讓直接內存訪問重新映射。如果內核參數NTEL_IOMMU_DEFAULT_ON沒有設置,那么內核參數intel_iommu=on也必須使用。這是為了確保intel IOMMU按照預期初始化。
請注意當強制在igb_uio,vfio-pci驅動上使用iommu=pt,確實可以同時使用iommu=pt and iommu=on。
5.740g網卡上小包的高性能處理
最新版本的固件鏡像解決了性能增強的問題,固件更新可以獲取更高的處理性能。跟本地的intel工程師聯系固件更新。支持固件版本FVL3E的基本驅動將在下一個dpdk版本中整合到一起,當前能用到的版本是4.2.6
5.7.1 打開Extended Tag和設置Max Read Request Size
PCI的extended_tag和max_read_request_size對40g網卡的小包處理性能有巨大的影響。打開extended_tag和設置max_read_request_size為小尺寸例如128字節會對小包的處理性能提升有恆大的幫助。
- 大部分可以在BIOS啟動時設置
- 對於其它BIOS,PCI配置可以通過使用命令setpci,或者是dpdk配置文件的特殊配置
- pci設備的地址0xa8處bit7:5處用於設置max_read_request_size,而0xa8處的第八個bit用於開啟關閉extended_tag。可以用lspci和setpci來讀取讀取0xa8對應的值然后回寫修改的值。
- 在一般的linux配置文件中,下面的配置項要zuo修改:
CONFIG_RTE_PCI_CONFIG
CONFIG_RTE_PCI_EXTENDED_TAG
CONFIG_RTE_PCI_MAX_READ_REQUEST_SIZE
5.7.2 使用16字節大小的rx描述符
i40e的PMD支持16和32字節大小rx描述符,16個字節可以在小包處理性能上提供幫助。要使用16字節的需要修改配置文件中的配置項CONFIG_RTE_LIBRTE_I40E_16BYTE_RX_DESC。
5.7.3高性能和包延遲權衡
由於硬件設計的原因,每個包描述符的回寫是需要網卡內部的中斷型號來實現。最小時間間隔的中斷信號可以通過配置文件的CONFIG_RTE_LIBRTE_I40E_ITR_INTERVAL配置,編譯生效。盡管有默認配置,用戶可以考慮性能或者是包處理延遲來調整這個參數。
6快速啟動腳本
tools目錄下的setup.sh腳本可以幫助用戶完成以下任務:
- 創建dpdk庫
- 裝載和卸載dpdk igb_uio內核模塊
- 裝載和卸載VFIO內核模塊
- 裝載和卸載dpdk KNI內核模塊
- 創建和刪除NUMA或非NUMA下的大頁
- 網絡端口狀態視圖和分配dpdk使用的端口
- 賦予非特權用戶使用VFIO的權限
- 運行測試程序和測試pmd程序
- 查看內存的大頁信息
- 顯示/mnt/huge的大頁列表
- 移除創建的dpdk庫
那些步驟完成后,用戶需要編譯自己的程序並連接創建的dpdk EAL庫。
6.1腳本的使用
setup.sh腳本可以暗轉給一定的順序使用,每一步都給說明方便用戶完成想要的任務。下面是每一步驟的簡短說明:
step1:創建dpdk庫
最開始,用戶表虛選擇需要創建的dpdk目標類型和創建庫是用到的編譯選項。
用戶必須先有所有的鏈接庫,模塊,更新和編譯安裝,如前面章節中介紹的。
step2:安裝環境
用戶配置linux系統環境以支持運行dpdk程序。大頁可以在numa或非numa系統中建立。任何存在的大頁都會被弄走。要用到的內核模塊也會在這是插入,dpdk用的網卡端口也會綁定到這個模塊。
step3:運行程序
一旦上述步驟完成,用戶可能要運行測試程序。測試程序允許用戶運行一系列的dpdk功能測試。testpmd測試程序則是測試收發包。
step4:檢查系統
這一步提供一些工具查看大頁的狀態信息
step:系統還原
最后一步是將系統還原到初始的狀態。
6.2用例
下面的步驟是展示如何使用setup.sh腳本。腳本的運行需要使用source命令,執行前腳本的一些選項提示用到的值。
提示:setup.sh腳本要運行在root權限下。
user@host:~/rte$ source tools/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-ivshmem-linuxapp-gcc
[5] x86_64-ivshmem-linuxapp-icc
[6] x86_64-native-bsdapp-clang
[7] x86_64-native-bsdapp-gcc
[8] x86_64-native-linuxapp-clang
[9] x86_64-native-linuxapp-gcc
[10] 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
Option:
下面是創建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驅動的示例:(感覺不對,25應該按上面說的是卸載驅動啊,2.1沒用過,等后面翻譯開發手冊時再試試吧)
Option: 25
Unloading any existing DPDK UIO module
Loading DPDK UIO module
在numa系統中創建大頁的示范。在每個node上分配1024個2m內存頁。結果就是程序應該在啟動時帶上-m 4096參數使用這些內存(實際上即使不提供-m選項,dpdk程序也會自動使用這些內存)
注意:如果顯示提示用戶刪除臨時文件,輸入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
下面是加載測試程序在一個核上跑的示例:
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>>
6.3應用程序
一旦用戶setup.sh腳本運行過,EAL創建了,大頁也搞好了。就可以創建和運行自己的程序了或者是提供的例子程序。
下面是運行/exaples下的helloword程序示例,使用的是0-3核:
rte@rte-desktop:~/rte/examples$ cd helloworld/
rte@rte-desktop:~/rte/examples/helloworld$ make
CC main.o
LD helloworld
INSTALL-APP helloworld
INSTALL-MAP helloworld.map
rte@rte-desktop:~/rte/examples/helloworld$ 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