通过源码安装dpdk并运行examples (by quqi99)

Posted quqi99

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了通过源码安装dpdk并运行examples (by quqi99)相关的知识,希望对你有一定的参考价值。

作者:张华 发表于:2021-08-11
版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明

前言

2016年通过源码安装过dpdk,但过时了,见: https://blog.csdn.net/quqi99/article/details/51087955/
通过juju安装dpdk请参考此网页搜索dpdk字眼: https://blog.csdn.net/quqi99/article/details/116893909

本文是在ubuntu 20.04上通过dpdk安装源码并运行例子。目前,已经通过meson取代了Makefile,这是最大的区别。注意:meson不能通过apt安装,只能通过pip3安装。

ubuntu@saha:/bak/linux/dpdk$ cat Makefile 
.PHONY: all
all:
	@echo "To build DPDK please use meson and ninja as described at"
	@echo "    https://core.dpdk.org/doc/quick-start/"

实验机器

使用支持DPDK网卡的机器即可。如果无此硬件,也可使用QEMU/KVM来搭建DPDK实验平台[1], 我这里使用的是:

ubuntu@saha:~$ lspci -nnn |grep -i 'eth' |grep '02:00.1'
02:00.1 Ethernet controller [0200]: Broadcom Inc. and subsidiaries NetXtreme BCM5719 Gigabit Ethernet PCIe [14e4:1657] (rev 01)

Bios设置

一般地,按如下设置打开大页和iommu即可。

ubuntu@saha:~$ cat /proc/cmdline 
BOOT_IMAGE=/boot/vmlinuz-4.15.0-151-generic root=UUID=cd6e46ab-dc09-414b-ab22-dd9709bf1712 ro console=ttyS1 transparent_hugepage=never hugepagesz=1G hugepages=16 default_hugepagesz=1G iommu=pt intel_iommu=on

注意:1G大页不能在系统启动后设置大小(对于2M大页则可以在系统启动之后再通过nr_hugepages设置):

mkdir -p /dev/hugepages
mountpoint -q /dev/hugepages || mount -t hugetlbfs nodev /dev/hugepages
echo 64 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages

其他的,如需HPET(高精度事件定时器)功能支持,还需要在BIOS,Kernel,DPDK中打开HPET相关的配置 - 见[2].
此外,内核对大页的支持,默认就是打开的:

$ sudo grep -i HUGETLB /boot/config-$(uname -r)
CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
CONFIG_CGROUP_HUGETLB=y
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y

通过meson源码安装

参考: 
https://core.dpdk.org/doc/quick-start/
https://doc.dpdk.org/guides/prog_guide/build-sdk-meson.html

sudo mkdir -p /bak/linux && sudo chown -R $USER /bak/linux/ && cd /bak/linux
git clone https://github.com/DPDK/dpdk.git
ubuntu@saha:/bak/linux/dpdk$ tree -L 1 .
.
├── ABI_VERSION
├── MAINTAINERS
├── Makefile
├── README
├── VERSION
├── app
├── buildtools
├── config
├── devtools
├── doc
├── drivers
├── examples
├── kernel
├── lib
├── license
├── meson.build
├── meson_options.txt
└── usertools

DPDK源文件由几个目录组成:

  • lib: DPDK 库文件
  • drivers: DPDK 轮询驱动源文件
  • app: DPDK 应用程序 (自动测试)源文件
  • examples: DPDK 应用例程
  • config, buildtools, mk: 框架相关的makefile、脚本及配置文件

下载了源码之后,如果想要igb_uio驱动的话,还要:

第一步,编辑meson_options.txt文件将enable_kmods改成true, 
option('enable_kmods', type: 'boolean', value: true, description:
       'build kernel modules')
第二步,驱动补充
cd /bak/linux/
git clone http://dpdk.org/git/dpdk-kmods
cd dpdk-kmods/linux/igb_uio
make
sudo modprobe uio_pci_generic
sudo insmod igb_uio.ko

下面的makefile方式是过时的老方式,列在这里以利于比较。

sudo apt install linux-headers-$(uname -r) libpcap-dev -y
cd dpdk
make config T=x86_64-native-linuxapp-gcc

对于运行’make config’时的T参数,官网给出的编译平台规范是ARCH-MACHINE-EXECENV-TOOLCHAIN

  • ARCH can be: i686, x86_64, ppc_64
  • MACHINE can be: native, ivshmem, power8
  • EXECENV can be: linuxapp, bsdapp
  • TOOLCHAIN can be: gcc, icc

然后就是使用meson编译了,

# ./autogen.sh && ./configure && make && sudo make install
# meson build && ninja -C build && sudo ninja -C build install
# 通过apt方式安装meson的版本太老会导致这个错误"ERROR: Unknown type feature"
sudo apt install python3 python3-pip -y
pip3 install rust setuptools_rust meson ninja pwntools
~/.local/bin/meson -v
cat << EOF | tee -a ~/.bashrc
export PATH=~/.local/bin:$PATH
EOF
source ~/.bashrc
# Build libraries, drivers and test applications.
# meson build
# To include the examples as part of the build, replace the meson command with:
meson -Dexamples=all -Dbuildtype=debug -Denable_trace_fp=true build
#ninja -C build install
sudo /home/ubuntu/.local/bin/ninja -C build install

'ninjia install’除了将可执行文件安装到/usr/local/bin目录外,还会安装:

  • headers -> /usr/local/include
  • libraries -> /usr/local/lib/x86_64-linux-gnu/dpdk/
  • drivers -> /usr/local/lib64/dpdk/drivers
  • libdpdk.pc -> /usr/local/lib/x86_64-linux-gnu/pkgconfig

想要重新配置的话,加’–reconfigure’参数:

meson --reconfigure -Dexamples=all -Dbuildtype=debug -Denable_trace_fp=true build

也可以添加更多的配置参数:

CC=clang meson -Dmax_lcores=128 -Dmachine=sandybridge -Ddisable_drivers=net/af_xdp,net/dpaa -Dexamples=l3fwd,l2fwd -Dwerror=false build2021
ninja -C build2021

主要配置参数如下:

meson的这些参数可以通过"meson configure"查看,例如:

meson configure -Dbuildtype=debug
meson configure -Denable_trace_fp=true

也可以查看meson_options.txt文件。

Run Examples

build/examples
$ sudo ./dpdk-helloworld -c 3 -n 4
EAL: Detected 32 lcore(s)
EAL: Detected 2 NUMA nodes
EAL: Detected static linkage of DPDK
EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: Selected IOVA mode 'VA'
EAL: VFIO support initialized
EAL: DPDK is running on a NUMA system, but is compiled without NUMA support.
EAL: This will have adverse consequences for performance and usability.
EAL: Please use --legacy-mem option, or recompile with NUMA support.
TELEMETRY: No legacy callbacks, legacy socket not created
hello from core 1
hello from core 0

选项描述如下:

  • -c COREMASK: 要运行的内核的十六进制掩码。注意,平台之间编号可能不同,需要事先确定
  • -n NUM: 每个处理器插槽的内存通道数目
  • -b domain:bus:devid.func: 端口黑名单,避免EAL使用指定的PCI设备。
  • –use-device: 仅使用指定的以太网设备。使用逗号分隔 [domain:]bus:devid.func 值,不能与 -b 选项一起使用。
  • –socket-mem: 从特定插槽上的hugepage分配内存。
  • -m MB: 内存从hugepage分配,不管处理器插槽。建议使用 --socket-mem 而非这个选项。
  • -r NUM: 内存数量。
  • -v: 显示启动时的版本信息。
  • –huge-dir: 挂载hugetlbfs的目录。
  • –file-prefix: 用于hugepage文件名的前缀文本。
  • –proc-type: 程序实例的类型。
  • –xen-dom0: 支持在Xen Domain0上运行,但不具有hugetlbfs的程序。
  • –vmware-tsc-map: 使用VMware TSC 映射而不是本地RDTSC。
  • –base-virtaddr: 指定基本虚拟地址。
  • –vfio-intr: 指定要由VFIO使用的中断类型。(如果不支持VFIO,则配置无效)。

编写第一个helloworld dpdk程序

mkdir examples/mytest && cd examples/mytest
cat << EOF | tee meson.build
project('hello', 'c')
dpdk = dependency('libdpdk')
sources = files('main.c')
executable('hello', sources, dependencies: dpdk)
EOF
cp ../helloworld/main.c .
export RTE_SDK=/bak/linux/dpdk
export PKG_CONFIG_PATH=/usr/local/lib/x86_64-linux-gnu
export LD_LIBRARY_PATH=/usr/local/lib/x86_64-linux-gnu
sudo apt install numactl libnuma-dev re2c make cmake pkg-config -y
pkg-config --version
meson build
ninja -C build
sudo ./build/hello

ubuntu@saha:/bak/linux/dpdk/examples/mytest$ cat main.c 
/* 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>

/* Launch a function on lcore. 8< */
static int
lcore_hello(__rte_unused void *arg)
{
	unsigned lcore_id;
	lcore_id = rte_lcore_id();
	printf("hello from core %u\\n", lcore_id);
	return 0;
}
/* >8 End of launching function on lcore. */

/* Initialization of Environment Abstraction Layer (EAL). 8< */
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");
	/* >8 End of initialization of Environment Abstraction Layer */

	/* Launches the function on each lcore. 8< */
	RTE_LCORE_FOREACH_WORKER(lcore_id) {
		/* Simpler equivalent. 8< */
		rte_eal_remote_launch(lcore_hello, NULL, lcore_id);
		/* >8 End of simpler equivalent. */
	}

	/* call it on main lcore too */
	lcore_hello(NULL);
	/* >8 End of launching the function on each lcore. */

	rte_eal_mp_wait_lcore();

	/* clean up the EAL */
	rte_eal_cleanup();

	return 0;
}

如何debug它呢?

上面的dpdk程序如何使用gdb来debug呢?

meson --reconfigure -Dbuildtype=debug -Denable_trace_fp=true build
ninja -C build
sudo cgdb ./build/hello -c 1

运行例子中的l3fwd

让我们继续运行examples中的l3fwd程序。它是一个l3转发所以一般得两个机器两个网卡,但我们这里只有单机器单网卡, 我们就测试自发自收吧。

首先,通过dpdk-devbind.py确认只有一个dpdk网卡( 之前我们安装过dpdk deb,所以有:/usr/share/dpdk/usertools/dpdk-devbind.py, 我们现在又通过源码安装的dpdk, 所以又有:/usr/local/bin/dpdk-devbind.py):

$ lshw -C network -businfo |grep 02:00.1
WARNING: you should run this program as super-user.
pci@0000:02:00.1                  network    NetXtreme BCM5719 Gigabit Ethernet PCIe
ubuntu@saha:~$ /usr/local/bin/dpdk-devbind.py --status |grep 02:00.1
0000:02:00.1 'NetXtreme BCM5719 Gigabit Ethernet PCIe 1657' drv=vfio-pci unused=tg3,igb_uio,uio_pci_generic

我们这里只有0000:02:00.1一个网卡。正常情况下测试l3fwd得两台机器多个网卡吧。这里我们只有一台机器一个dpdk网卡那就只能测试一个网口的自发自收了。

l3fwd -cff -n 4 -- -p0x1 -P --config=“(0,0,1),(0,1,2),(0,2,3),(0,3,4)”
  • -p0x1, 表示只有一个dpdk网卡,如果有两个的话应该是-p0x3
  • -cff, ff=11,11, 这是掩码,所以就是只充许编号为 0,1,2,3的cpu核. 又例如如果只允许4和5的cpu的话就是0x30。现实中具体绑定到哪个cpu还得考虑numa. 另外,这里可以使用-c来使用掩码,还可以使用-l直接指定如:-l 1-4 。另外,注意:core 0 is usually master lcore所以一般不用0
  • –config, 因为这里只有一个dpdk网卡也就是只有一个port, 一个port开收发两个队列,并将队列绑定到cpu核, 这样就是(0,0,1),(0,1,2). 但是这个单网卡是自发自收,继续用这个port再开两个队列模拟收:(0,2,3),(0,3,4).
    examples这块仍然可以使用makefile来编译:
cd /bak/linux/dpdk/examples/l3fwd
export RTE_SDK=/bak/linux/dpdk
export RTE_TARGET=x86_64-native-linuxapp-gcc
export EXTRA_CFLAGS="-ggdb -ffunction-sections -O0"
make
ls /bak/linux/dpdk/examples/l3fwd/build/l3fwd

最终运行它:

sudo /bak/linux/dpdk/examples/l3fwd/build/l3fwd -cff -n 4 -- -p0x1 -P --config="(0,0,1),(0,1,2),(0,2,3),(0,3,4)"
sudo /bak/linux/dpdk/examples/l3fwd/build/l3fwd -l 1-4 -n 4 -- -p0x1 -P --config="(0,0,1),(0,1,2),(0,2,3),(0,3,4)"

但是它会报这个错:

port 0 is not present on the board
EAL: Error - exiting with code: 1
  Cause: check_port_config failed

难道是因为0000:02:00.1这块网卡与1-4这些cpu核不在同一个NUMA上吗?这个网卡在numa0上, 1-4这些cpu核也在numa0上(core 0 is usually master lcore)。所以不是这个原因

$ lspci -nnn |grep Eth |grep 02:00.1
02:00.1 Ethernet controller [0200]: Broadcom Inc. and subsidiaries NetXtreme BCM5719 Gigabit Ethernet PCIe [14e4:1657] (rev 01)
$ cat /sys/bus/pci/devices/0000\\:02\\:00.1/numa_node 
0
$ lscpu |grep NUMA
NUMA node(s):        2
NUMA node0 CPU(s):   0-7,16-23
NUMA node1 CPU(s):   8-15,24-31

因为还在初始阶段也无法调试:

(gdb) b check_port_config
(gdb) r
sudo cgdb /bak/linux/dpdk/examples/l3fwd/build/l3fwd -l 1-4 -- -p0x1 -L --config="(0,0,1),(0,1,2),(0,2,3),(0,3,4)"

大页也在:

$ cat /proc/meminfo |grep HugePages_
HugePages_Total:      16
HugePages_Free:        5
HugePages_Rsvd:        0
HugePages_Surp:        0
$ grep Hugepagesize /proc/meminfo
Hugepagesize:    1048576 kB

换一下用户态驱动,从vifo-pci(有iommu支持)换到uio_pci_generic或igb_uio, 错误依旧:

sudo dpdk-devbind.py -u 0000:02:00.1  #/sys/bus/pci/drivers/vfio-pci/unbind
sudo dpdk-devbind.py -b uio_pci_generic 0000:02:00.1
sudo dpdk-devbind.py --status

检查代码,‘is not present on the board’来自rte_eth_dev_is_valid_port

        if (!rte_eth_dev_is_valid_port(portid)) {
                        printf("port %u is not present on the board\\n", portid);
                        return -1;
                }
                
int rte_eth_dev_is_valid_port(uint16_t port_id)
{
        if (port_id >= RTE_MAX_ETHPORTS ||
            (rte_eth_devices[port_id].state == RTE_ETH_DEV_UNUSED))
                return 0;
        else
                return 1;
}

根据网页(https://chenong.github.io/2017/04/25/dpdk-bind-I210-PCI-error/)的说法,很可能跟博通的这款网卡(NetXtreme BCM5719 ,14e4:1657)有关.
不管怎样,这里的步骤是没有问题的,就不再此问题上继续折腾了。另外,这篇文章可参考:https://www.freesion.com/article/7073504096/

Reference

[1] https://www.sdnlab.com/community/article/dpdk/908
[2] https://dpdk-docs.readthedocs.io/en/latest/linux_gsg/enable_func.html#enabling-additional-functionality
[3] https://feishujun.blog.csdn.net/article/details/113665380
[4] https://cxyzjd.com/article/u012570105/82594089

以上是关于通过源码安装dpdk并运行examples (by quqi99)的主要内容,如果未能解决你的问题,请参考以下文章

(WIP) DPDK理论学习(by quqi99)

dpdk example之link_status_interrupt尝鲜

DPDK+Pktgen 高速发包测试

DPDK — Userspace PMD 源码分析

DPDK — Userspace PMD 源码分析

运行DPDK KNI示例的问题