DPDK — 安裝部署

目錄

環境

  • Intel x86

  • CentOS7

    • NUMA node >= 1
    • Memory >= 4GB
    • NICs >= 2
    • Kernel >= 2.6.33(支持 UIO、HUGETLBFS、PROC_PAGE_MONITOR)

NOTE:對大多數平臺,使用基本的 DPDK 功能無需對 BIOS 進行特殊設置。然而,對於 HPET(High Precision Event Timer,高精度定時器,到時了會產生中斷)定時器和電源管理功能,以及爲了獲得 40G 網卡上小包處理的高性能,則可能需要更改 BIOS 設置。查看是否開啓了 HPET:

grep hpet /proc/timer_list

軟件依賴

  • Kernel
    • kernel.x86_64:包含所有內核源代碼。
    • kernel-devel:如果某個程序需要內核提供的一些功能,它就需要內核的 C header 來編譯程序,這個時候就需要使用到 kernel-devel 了。例如:NVIDIA 的顯卡驅動需要編譯一個放在內核裏面運行的模塊,編譯這個模塊就需要內核的 heade r文件才能順利完成。另外,kernel-devel 不光只是 C Header 文件,它還有內核的配置文件,以及其他的開發用的資料。
    • kernel-headers:提供內核的信息,包含內核的頭文件、Kconfig 和 Makefile,是內核對外的一個接口,當需要向內核提供兼容的功能模塊時,就需要提供內核的信息。所以,在安裝驅動時往往也需要 kernel-header。
$ yum install kernel-devel kernel-headers kernel.x86_64 -y

$ uname -a ; rpm -qa kernel\* | sort
Linux c-dev 3.10.0-957.12.2.el7.x86_64 #1 SMP Tue May 14 21:24:32 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
kernel-3.10.0-1127.el7.x86_64
kernel-3.10.0-957.12.2.el7.x86_64
kernel-devel-3.10.0-1127.el7.x86_64
kernel-headers-3.10.0-1127.el7.x86_64
kernel-tools-3.10.0-957.12.2.el7.x86_64
kernel-tools-libs-3.10.0-957.12.2.el7.x86_64

注意,上述看見有兩個不同版本的 Kernel,首先需要確定當前 Kernel 的版本是一致的。否則會出現 make: *** /lib/modules/3.10.0-957.12.2.el7.x86_64/build: 沒有那個文件或目錄。 停止。 的錯誤:

$ uname -r
3.10.0-957.12.2.el7.x86_64
$ ls /usr/src/kernels/
3.10.0-1127.el7.x86_64

卸載 kernel-3.10.0-957.12.2.el7.x86_64 並重啓:

rpm -e kernel-3.10.0-957.12.2.el7.x86_64

再次查看:

$ uname -r
3.10.0-1127.el7.x86_64
$ ls /usr/src/kernels/
3.10.0-1127.el7.x86_64
  • libpcap 網絡數據包捕獲函數庫(A system-independent interface for user-level packet capture):
  • libpcap-devel 用於編譯和使用基於 libcap 的輪詢模式驅動程序。默認情況下,該驅動程序被禁用,可以通過在構建時修改配置文件 CONFIG_RTE_LIBRTE_PMD_PCAP=y 來開啓。
$ yum install -y libpcap.x86_64 libpcap-devel.x86_64
  • NUMA Tools
$ yum install numactl-devel.x86_64 numactl-libs.x86_64 -y
  • lspci
$ yum install pciutils -y
  • ifconfig
$ yum install net-tools.x86_64 -y
  • C/C++ 編譯器
$ yum install gcc gcc-c++ -y

安裝

DPDK 支持使用 dpdk-setup.sh 腳本和手動編譯兩者方式進行安裝, dpdk-setup.sh 可以完成下列工作:

  • 構建 DPDK 庫
  • 加載/卸載 DPDK IGB_UIO 內核模塊
  • 加載/卸載 VFIO 內核模塊
  • 加載/卸載 DPDK KNI 內核模塊
  • 創建/刪除 NUMA 或 non-NUMA 平臺的 hugepages
  • 查看網絡端口狀態和預留給 DPDK 應用程序使用的端口
  • 設置非 root 用戶使用 VFIO 的權限
  • 運行 test 和 testpmd 應用程序
  • 查看 meminfo 中的 hugepages
  • 列出在 /mnt/huge 中的 hugepages
  • 刪除內置的 DPDK 庫
  • 對於其中一個 EAL Target,一旦完成了這些步驟,用戶就可以編譯自己的在 EAL 庫中鏈接的應用程序來創建 DPDK 映像。

這裏我們使用後一種安裝方式,可以更深入的理解 DPDK 安裝的內容。

  1. 設置大頁內存
# NUMA 架構
$ echo 1024 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages
# 非 NUMA 架構
# echo 1024 >/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

# 掛載大頁內存,給 DPDK 使用。
$ mkdir /mnt/huge
$ chmod 777 /mnt/huge
# 臨時掛載
mount -t hugetlbfs nodev /mnt/huge
# 永久掛載 vi /etc/fstab
huge /mnt/huge hugetlbfs defaults 0 0

$ cat /proc/meminfo | grep Huge
AnonHugePages:      6144 kB
HugePages_Total:    1024
HugePages_Free:     1024
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
  1. 獲取 DPDK 代碼
$ cd /opt
$ wget http://fast.dpdk.org/rel/dpdk-18.08.tar.gz  
$ tar -zxvf dpdk-18.08.tar.gz
$ cd dpdk-18.08
$ ll
總用量 76
drwxrwxr-x  8 root root   150 8月  10 2018 app
drwxr-xr-x  7 root root   119 5月   7 23:42 build
drwxrwxr-x  3 root root   242 8月  10 2018 buildtools
drwxrwxr-x  4 root root  4096 8月  10 2018 config
drwxrwxr-x  3 root root  4096 8月  10 2018 devtools
drwxrwxr-x  5 root root    97 8月  10 2018 doc
drwxrwxr-x 11 root root   162 8月  10 2018 drivers
drwxrwxr-x 49 root root  4096 8月  10 2018 examples
-rw-rw-r--  1 root root   291 8月  10 2018 GNUmakefile
drwxrwxr-x  4 root root    69 8月  10 2018 kernel
drwxrwxr-x 45 root root  4096 8月  10 2018 lib
drwxrwxr-x  2 root root   105 8月  10 2018 license
-rw-rw-r--  1 root root 34749 8月  10 2018 MAINTAINERS
-rw-rw-r--  1 root root   136 8月  10 2018 Makefile
-rw-rw-r--  1 root root  2386 8月  10 2018 meson.build
-rw-rw-r--  1 root root  1393 8月  10 2018 meson_options.txt
drwxrwxr-x  8 root root  4096 8月  10 2018 mk
drwxrwxr-x  2 root root    23 8月  10 2018 pkg
-rw-rw-r--  1 root root   510 8月  10 2018 README
drwxrwxr-x  7 root root   121 8月  10 2018 test
drwxrwxr-x  2 root root   113 8月  10 2018 usertools
  • lib:DPDK 庫文件
  • drivers:DPDK 輪詢驅動源文件
  • app:DPDK 應用程序(自動測試)源文件
  • examples:DPDK 應用例程
  • config, buildtools, mk:框架相關的 Makefile、腳本及配置文件
  1. 設置環境變量
# vi dpdk.rc
export RTE_SDK=/opt/dpdk-18.08
export RTE_TARGET=x86_64-native-linuxapp-gcc
export DPDK_BUILD=${DPDK_DIR}/${RTE_TARGET}
export LD_LIBRARY_PATH=${RTE_SDK}/${RTE_TARGET}/lib:/usr/local/lib:/usr/lib:

NOTE:以下兩個環節變量在每次運行 DPDK 示例程序的時候都需要加載,因爲示例程序的 Makefile 裏面定義了。

  • RTE(Run-Time Environment)
  • RTE_SDK:指向 DPDK 的安裝目錄。
  • RTE_TARGET:指向 DPDK 目標環境目錄。
  1. 編譯安裝
source dpdk.rc
cd /opt/dpdk-18.08/
make config T=$RTE_TARGET
make
make install T=$RTE_TARGET
  • 其中 T(Target)的描述格式爲:
ARCH-MACHINE-EXECENV-TOOLCHAIN
# ARCH = i686, x86_64, ppc_64
# MACHINE = native, ivshmem, power8
# EXECENV = linuxapp, bsdapp
# TOOLCHAIN = gcc, icc
  • 編譯完成之後生成了環境目錄 x86_64-native-linuxapp-gcc:
$ cd ${RTE_SDK}/${RTE_TARGET}/
$ ll
總用量 24
drwxr-xr-x 2 root root  305 5月   7 23:53 app
drwxr-xr-x 7 root root   75 5月   7 23:52 build
drwxr-xr-x 4 root root 8192 5月   7 23:52 include
drwxr-xr-x 2 root root   42 5月   7 23:49 kmod
drwxr-xr-x 2 root root 4096 5月   7 23:52 lib
-rw-r--r-- 1 root root  313 5月   7 23:47 Makefile
  1. 加載內核模塊:要運行 DPDK 應用程序,需要將合適的 UIO 模塊線加載到內核中,UIO 包括:uio_pci_generic、uio、igb_uio、vfio_pci。

NOTE:在多數情況下,Linux 內核包含了標準的 uio_pci_generic 模塊就可以提供 UIO 能力。區別於 uio_pci_generic ,DPDK 代碼庫還提供了 igb_uio 模塊。需要注意的是,對於一下不支持傳統中斷機制的設備,例如:VF 設備,就必須使用 igb_uio 來替代 uio_pci_generic 模塊。在 DPDK 1.7 版本還提供 VFIO 的支持,所以,對於支持 VFIO 的平臺,可選擇使用 UIO,也可以不用。還需要注意的是,若使用 VFIO,首先平臺的內核版本必須支持 VFIO 功能。 Linux 內核從 3.6.0 版本之後就包含了 VFIO 模塊,通常是默認存在的。此外,要使用 VFIO,內核和 BIOS 都必須支持,並配置爲啓用 IO 虛擬化,例如:Intel® VT-d。爲了保證非特權用戶運行 DPDK 時能夠正確操作 VFIO,則還應設置正確的權限。這可以通過 DPDK 的配置腳本(dpdk-setup.sh)來完成。

# Loading Modules to Enable Userspace IO for DPDK 
$ cd ${RTE_SDK}/${RTE_TARGET}/kmod/
# 加載 UIO Framework 內核模塊
$ modprobe uio
# 加載 igb_uio 內核驅動程序模塊
$ insmod igb_uio.ko
# modprobe uio_pci_generic
# modprobe vfio-pci

$ lsmod | grep uio
igb_uio                13542  0
uio                    19338  1 igb_uio
  1. 綁定 NIS(網卡要使用 DPDK,必須將網卡綁定到 igb_uio 內核模塊)
$ cd ${RTE_SDK}/usertools/

# 查看當前網卡綁定的驅動狀態
$ ./dpdk-devbind.py --status
Network devices using DPDK-compatible driver
============================================
<none>

Network devices using kernel driver
===================================
0000:00:03.0 'Virtio network device 1000' if=eth0 drv=virtio-pci unused=virtio_pci *Active*
0000:00:08.0 'Virtio network device 1000' if=eth1 drv=virtio-pci unused=virtio_pci

Other Network devices
=====================
<none>


# 首先 DOWN 掉需要綁定 DPDK 驅動的網卡,否知綁定不成功。
$ ifconfig eth1 down 
 
 # 把網卡從原驅動 e1000e 上解綁,要使用 DPDK,必須將網卡綁定到 igb_uio 模塊。
$ ./dpdk-devbind.py --bind=igb_uio 00:08.0

# 再次查看
# ./dpdk-devbind.py --status-dev net
Network devices using DPDK-compatible driver
============================================
0000:00:08.0 'Virtio network device 1000' drv=igb_uio unused=virtio_pci

Network devices using kernel driver
===================================
0000:00:03.0 'Virtio network device 1000' if=eth0 drv=virtio-pci unused=virtio_pci,igb_uio *Active*

Other Network devices
=====================
<none>


$ ls -l /dev/uio* -l
crw------- 1 root root 243, 0 5月   8 00:18 /dev/uio0
$ ls -l /sys/class/uio/uio0/maps/
總用量 0
drwxr-xr-x 2 root root 0 5月   8 00:19 map0
drwxr-xr-x 2 root root 0 5月   8 00:19 map1

# 如想修改回普通網卡模式,則使用如下命令
# ./dpdk-devbind.py -b e1000 00:08.0
# ifconfig ens33 up

NOTE:被 DPDK 接管後的網卡在操作系統層面是看不見的:

$ ip l
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether fa:16:3e:91:5b:97 brd ff:ff:ff:ff:ff:ff

測試

hellowrold

編譯運行 hellowrold 程序

$ cd ${RTE_SDK}/examples/helloworld
$ make

$ ./build/helloworld
EAL: Detected 8 lcore(s)
EAL: Detected 1 NUMA nodes
EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: No free hugepages reported in hugepages-1048576kB
EAL: Probing VFIO support...
EAL: WARNING: cpu flags constant_tsc=yes nonstop_tsc=no -> using unreliable clock cycles !
EAL: PCI device 0000:00:03.0 on NUMA socket -1
EAL:   Invalid NUMA socket, default to 0
EAL:   probe driver: 1af4:1000 net_virtio
EAL: PCI device 0000:00:08.0 on NUMA socket -1
EAL:   Invalid NUMA socket, default to 0
EAL:   probe driver: 1af4:1000 net_virtio
hello from core 1
hello from core 2
hello from core 3
hello from core 4
hello from core 5
hello from core 6
hello from core 7
hello from core 0

如果出現 hello from core X 則說明 DPDK 安裝成功。下面分析一下 helloworld 的代碼:

/* SPDX-License-Identifier: BSD-3-Clause
 * Copyright(c) 2010-2014 Intel Corporation
 */

#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <sys/queue.h>

#include <rte_memory.h>
#include <rte_launch.h>
#include <rte_eal.h>
#include <rte_per_lcore.h>
#include <rte_lcore.h>
#include <rte_debug.h>

static int
lcore_hello(__attribute__((unused)) void *arg)
{
	unsigned lcore_id;
	lcore_id = rte_lcore_id();
	printf("hello from core %u\n", lcore_id);
	return 0;
}

int
main(int argc, char **argv)
{
	int ret;
	unsigned lcore_id;

	ret = rte_eal_init(argc, argv);
	if (ret < 0)
		rte_panic("Cannot init EAL\n");

	/* call lcore_hello() on every slave lcore */
	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
		rte_eal_remote_launch(lcore_hello, NULL, lcore_id);
	}

	/* call it on master lcore too */
	lcore_hello(NULL);

	rte_eal_mp_wait_lcore();
	return 0;
}
  1. 調用 rte_eal_init() 初始化 EAL(Environment Abstraction Layer,環境抽象層)。EAL 在每一個 slave lcore 上都創建一個線程,並進行綁核。所以你會發現當前的 CPU Cores 都是跑滿的。
    在這裏插入圖片描述
  2. 再調用 RTE_LCORE_FOREACH_SLAVE() 遍歷分配給 DPDK 的所有 slave lcore,然後調用 rte_eal_mp_remote_launch() 註冊回調函數 lcore_hello() 進行打印 hello from core X
  3. 在 master lcore 上調用 lcore_hello()。
  4. rte_eal_mp_wait_lcore 等待所有的 slave lcore 退出,然後自己再退出。

還可以通過 -c 選型來指定 lcore mask:

# 1
$ ./build/helloworld -c 1 | grep hello
hello from core 0

# 10
$ ./build/helloworld -c 2 | grep hello
hello from core 1

# 11
$ ./build/helloworld -c 3 | grep hello
hello from core 1
hello from core 0

# 100
$ ./build/helloworld -c 4 | grep hello
hello from core 2

# 101
$ ./build/helloworld -c 5 | grep hello
hello from core 2
hello from core 0

# 110
$ ./build/helloworld -c 6 | grep hello
hello from core 1
hello from core 2

coremask 參數可以使用指定的 lcore 來運行 DPDK 應用程序,是一個十六進制的掩碼,掩碼的每個位對應於 Linux 提供的 lcore ID。在指定 lcpu mask 參數之前,需要了解平臺的 CPU 佈局,可以通過 hwloc 來查看:

yum install hwloc -y

在這裏插入圖片描述
如果沒有圖形化界面則使用指令:

$ lstopo-no-graphics
Machine (16GB)
  Package L#0 + L3 L#0 (16MB) + L2 L#0 (4096KB) + L1d L#0 (32KB) + L1i L#0 (32KB) + Core L#0 + PU L#0 (P#0)
  Package L#1 + L3 L#1 (16MB) + L2 L#1 (4096KB) + L1d L#1 (32KB) + L1i L#1 (32KB) + Core L#1 + PU L#1 (P#1)
  Package L#2 + L3 L#2 (16MB) + L2 L#2 (4096KB) + L1d L#2 (32KB) + L1i L#2 (32KB) + Core L#2 + PU L#2 (P#2)
  Package L#3 + L3 L#3 (16MB) + L2 L#3 (4096KB) + L1d L#3 (32KB) + L1i L#3 (32KB) + Core L#3 + PU L#3 (P#3)
  Package L#4 + L3 L#4 (16MB) + L2 L#4 (4096KB) + L1d L#4 (32KB) + L1i L#4 (32KB) + Core L#4 + PU L#4 (P#4)
  Package L#5 + L3 L#5 (16MB) + L2 L#5 (4096KB) + L1d L#5 (32KB) + L1i L#5 (32KB) + Core L#5 + PU L#5 (P#5)
  Package L#6 + L3 L#6 (16MB) + L2 L#6 (4096KB) + L1d L#6 (32KB) + L1i L#6 (32KB) + Core L#6 + PU L#6 (P#6)
  Package L#7 + L3 L#7 (16MB) + L2 L#7 (4096KB) + L1d L#7 (32KB) + L1i L#7 (32KB) + Core L#7 + PU L#7 (P#7)
  Misc(MemoryModule)
  HostBridge L#0
    PCI 8086:7010
      Block(Removable Media Device) L#0 "sr0"
    PCI 1013:00b8
    PCI 1af4:1000
    PCI 1af4:1004
    PCI 1af4:1000

也可以使用 DPDK 自帶的 CPU layout 工具:

$ cd ${RTE_SDK}/usertools/

$ ./cpu_layout.py
======================================================================
Core and Socket Information (as reported by '/sys/devices/system/cpu')
======================================================================

cores =  [0]
sockets =  [0, 1, 2, 3, 4, 5, 6, 7]

       Socket 0    Socket 1    Socket 2    Socket 3    Socket 4    Socket 5    Socket 6    Socket 7
       --------    --------    --------    --------    --------    --------    --------    --------
Core 0 [0]         [1]         [2]         [3]         [4]         [5]         [6]         [7]

PMD 測試

Run testpmd application in interactive mode ($RTE_TARGET/app/testpmd).

$ cd ${RTE_SDK}/build/app/

$ ./testpmd -l 3,0,2 --socket-mem 1024  --log-level=8 -- -i
EAL: Detected 8 lcore(s)
EAL: Detected 1 NUMA nodes
EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: No free hugepages reported in hugepages-1048576kB
EAL: Probing VFIO support...
EAL: WARNING: cpu flags constant_tsc=yes nonstop_tsc=no -> using unreliable clock cycles !
EAL: PCI device 0000:00:03.0 on NUMA socket -1
EAL:   Invalid NUMA socket, default to 0
EAL:   probe driver: 1af4:1000 net_virtio
EAL: PCI device 0000:00:08.0 on NUMA socket -1
EAL:   Invalid NUMA socket, default to 0
EAL:   probe driver: 1af4:1000 net_virtio
Interactive-mode selected
testpmd: create a new mbuf pool <mbuf_pool_socket_0>: n=163456, size=2176, socket=0
testpmd: preferred mempool ops selected: ring_mp_mc

Warning! port-topology=paired and odd forward ports number, the last port will pair with itself.

Configuring Port 0 (socket 0)
Port 0: FA:16:3E:7C:CE:C0
Checking link statuses...
Done

testpmd> set nbcore 2
Number of forwarding cores set to 2

testpmd> show config fwd
io packet forwarding - ports=1 - cores=1 - streams=1 - NUMA support enabled, MP over anonymous pages disabled
Logical Core 2 (socket 0) forwards packets on 1 streams:
  RX P=0/Q=0 (socket 0) -> TX P=0/Q=0 (socket 0) peer=02:00:00:00:00:00

testpmd> show config cores
List of forwarding lcores:  2  3

testpmd> start
io packet forwarding - ports=1 - cores=1 - streams=1 - NUMA support enabled, MP over anonymous pages disabled
Logical Core 2 (socket 0) forwards packets on 1 streams:
  RX P=0/Q=0 (socket 0) -> TX P=0/Q=0 (socket 0) peer=02:00:00:00:00:00

  io packet forwarding packets/burst=32
  nb forwarding cores=2 - nb forwarding ports=1
  port 0: RX queue number: 1 Tx queue number: 1
    Rx offloads=0x1000 Tx offloads=0x0
    RX queue: 0
      RX desc=0 - RX free threshold=0
      RX threshold registers: pthresh=0 hthresh=0  wthresh=0
      RX Offloads=0x0
    TX queue: 0
      TX desc=0 - TX free threshold=0
      TX threshold registers: pthresh=0 hthresh=0  wthresh=0
      TX offloads=0x0 - TX RS bit threshold=0

testpmd> show port stats all

  ######################## NIC statistics for port 0  ########################
  RX-packets: 0          RX-missed: 0          RX-bytes:  0
  RX-errors: 0
  RX-nombuf:  0
  TX-packets: 0          TX-errors: 0          TX-bytes:  0

  Throughput (since last show)
  Rx-pps:            0
  Tx-pps:            0
  ############################################################################

testpmd> stop
Telling cores to stop...
Waiting for lcores to finish...

  ---------------------- Forward statistics for port 0  ----------------------
  RX-packets: 0              RX-dropped: 0             RX-total: 0
  TX-packets: 0              TX-dropped: 0             TX-total: 0
  ----------------------------------------------------------------------------

  +++++++++++++++ Accumulated forward statistics for all ports+++++++++++++++
  RX-packets: 0              RX-dropped: 0             RX-total: 0
  TX-packets: 0              TX-dropped: 0             TX-total: 0
  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Done.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章