这篇文章是 DPDK(Data Plane Development Kit)的入门指南,主要介绍如何编译、安装并使用 DPDK。
为了系统性的学习 DPDK,以下是一些推荐文档:
- 入门指南:介绍如何安装和配置 DPDK,旨在帮助用户快速上手
 - 编程指南:
- 软件架构及如何使用(实例介绍),特别是在Linux环境中的用法
 - DPDK 的主要内容,系统构建(包括可以在 DPDK 根目录 Makefile 中来构建工具包和应用程序的命令)及应用移植细则
 - 软件里已使用的、以及在新开发中需要考虑的一些优化
 
 - API参考:提供有关 DPDK 功能、数据结构和其他编程结构的详细信息
 - 示例程序用户指南:描述了一组示例程序。每个章节描述了一个用例,展示了具体的功能,并提供了有关如何编译、运行和使用的说明。
 
系统要求
对大多数平台,使用基本的 DPDK 功能无需对 BIOS 进行特殊设置。然而,对于 HPET 定时器和电源管理功能,以及为了获得 40G 网卡上小包处理的高性能,则可能需要更改 BIOS 设置。可以参阅官方文档 Enabling Additional Functionality 以获取更为详细的信息。
编译DPDK
工具集
- GNU make
 - coreutils: cmp, sed, grep, arch 等
 - gcc: 4.9以上的版本适用于所有的平台,CentOS 上通过 
yum -y install gcc - libc 头文件,通常打包成 gcc-multilib
 - 构建Linux内核模块所需要的头文件和源文件
 - 在64位系统上编译32位软件包额外需要的软件为:
- glibc.i686, libgcc.i686, libstdc++.i686 及 glibc-devel.i686, 适用于Intel的i686/x86_64;
 - glibc.ppc64, libgcc.ppc64, libstdc++.ppc64 及 glibc-devel.ppc64 适用于 IBM ppc_64;
 
 - Python, 2.7+ or 3.2+版本, 用于运行DPDK软件包中的各种帮助脚本
 
编译 DPDK
首先,首先获取 DPDK 源码文件,解压文件并进入到 DPDK 源文件根目录下。这里使用的是 DPDK 19.11.12。
1  | wget https://fast.dpdk.org/rel/dpdk-19.11.12.tar.xz  | 
1  | tar xJf dpdk-19.11.12.tar.xz  | 
DPDK源文件由几个目录组成:
- lib: DPDK 库文件
 - drivers: DPDK 轮询驱动源文件
 - app: DPDK 应用程序 (自动测试)源文件
 - examples: DPDK 应用例程
 - config, buildtools, mk: 框架相关的makefile、脚本及配置文件
 
DPDK目标环境安装
DPDK 目标文件的格式为:
1  | ARCH-MACHINE-EXECENV-TOOLCHAIN  | 
其中:
- ARCH 可以是:i686, x86_64, ppc_64
 - MACHINE 可以是:native, power8
 - EXECENV 可以是:linuxapp, bsdapp
 - TOOLCHAIN 可以是:gcc, icc
 
我的系统信息如下:
1  | #uname -a  | 
因此按照如下方式生成目标文件(可以在 dpdk 源码目录的 /config 目录下找到所有支持的目标,不能使用defconfig_前缀):
1  | make install T=x86_64-native-linuxapp-gcc  | 
构建过程中,遇到了如下问题:
- 没有 
numa.h头文件 
1  | /root/dpdk/dpdk-stable-19.11.12/lib/librte_eal/linux/eal/eal_memory.c:32:10: fatal error: numa.h: No such file or directory  | 
解决方法:
1  | yum -y install numactl-devel  | 
浏览安装的 DPDK target
一旦目标文件创建,它就包含了 构建客户应用程序 所需的 DPDK 环境的所有库,包括轮询驱动程序和头文件。 此外,build/app 目录下也生成了 test 和 testpmd 应用程序,可以用于测试。 还有一个kmod目录,存放可能需要加载的内核模块。
运行 DPDK 程序
在运行 DPDK 应用程序之前,有一些前置条件。
UIO 功能
首先需要将合适的 uio 模块加载到当前内核中,多数情况下,Linux 内核包含了标准的 uio_pci_generic 模块,可以提供 uio 能力。使用如下方式加载 uio_pci_generic 模块:
1  | modprobe uio_pci_generic  | 
DPDK 提供了一个 igb_uio 模块,可以在 kmod 目录下找到。对于不支持中断的设备,例如虚拟功能设备(VF)设备,必须使用 igb_uio 来代替 uio_pci_generic 模块。加载 igb_uio 模块:
1  | modprobe uio  | 
由于DPDK 1.7版本提供 VFIO 支持,所以,对于支持 VFIO 的平台,可以使用 UIO,也可以不用。如果选择使用 VFIO,需要加载 VFIO 模块。
加载 VFIO 模块
当 DPDK 程序选择使用 VFIO 时,需要加载 vfio-pci 模块:
1  | modprobe vfio-pci  | 
要使用 VFIO,需要满足一些条件:
- 内核必须支持 VFIO, Linux 内核从 3.6.0 版本之后就一直包含 VFIO 模块,通常是默认存在的
 - BIOS 必须支持,并配置为使用 IO 虚拟化(如 Intel® VT-d)
 - 为了保证非特权用户运行 DPDK 时能够正确操作 VFIO,还应设置正确的权限。这可以通过 DPDK 的配置脚本 dpdk-setup.sh(位于 usertools 目录内)来实现
 
网络端口绑定/解绑
从版本 1.4 开始,DPDK 应用程序不再自动解除所有网络端口与原先内核驱动模块的绑定关系。相反,DPDK程序在运行前,需要将所要使用的端口绑定到 uio_pci_generic, igb_uio 或 vfio-pci 模块上。任何 Linux 内核本身控制的端口无法被 DPDK PMD 驱动所使用。
可以通过脚本 dpdk-devbind.py 将网络端口从内核解绑,并绑定到 uio_pci_generic, igb_uio 或 vfio-pci 模块供 DPDK 使用。
首先查看系统中所有网络接口的状态:
1  | # ./usertools/dpdk-devbind.py --status  | 
为了将 eth1 绑定到内核模块 igb_uio,首先需要将该接口 shutdown,否则会报如下错误:
1  | # ./usertools/dpdk-devbind.py --bind=igb_uio 03:00.0  | 
shutdown eth1 后,再次绑定成功,可以看到 eth1 已经绑定到 igb_uio,可供 DPDK 使用:
1  | # ip link set eth1 down  | 
使用 Hugepages
用于数据包缓冲区的大型内存池分配需要 Hugepages 支持。通过使用大页分配,程序需要更少的页面,性能增加,因为较少的 TLB 减少了将虚拟页面地址翻译成物理页面地址所需的时间。如果没有大页,标准大小 4k 的页面会导致频繁的 TLB miss,性能下降。
在系统启动后,可以通过如下命令分配 1024 个 2MB 页面:
1  | echo 1024 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages  | 
对于 Numa 设备中,分配应该指定在哪个节点上:
1  | echo 1024 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages  | 
对于 1G 页面,系统启动之后无法预留页面内存。只能在系统引导时预留大页,此时需要给 Linux 内核命令行参数传递一个参数,例如预留 4 个 1G 大小页面:
1  | default_hugepagesz=1G hugepagesz=1G hugepages=4  | 
预留 hugepage 内存之后,为了使内存可用于 DPDK,需要执行以下步骤:
1  | mkdir /mnt/huge  | 
将以下命令下入 /etc/fstab 文件后,挂载点可以在重启后仍然生效:
1  | nodev /mnt/huge hugetlbfs defaults 0 0  | 
编译 DPDK 应用程序
当一个 DPDK 目标环境创建完成时(如 x86_64-native-linuxapp-gcc),它包含编译一个应用程序所需要的全部库和头文件。接下来以 DPDK 自带的 helloworld 作为示例,演示如何编译并运行 DPDK 应用程序
按照如下步骤编译 helloworld:
1  | cd examples/helloworld/  | 
这里,RTE_SDK 指向DPDK安装目录,RTE_TARGET 为 DPDK target。make 编译成功后,可以看到当前目录下生成了 build 目录,以及对应的应用程序:
1  | # ls build/app/  | 
运行 DPDK 应用程序
运行之前,确保 UIO 驱动和 hugepage 都已经设置完成。DPDK 应用程序使用了 DPDK 目标环境的环境抽象层(EAL)库,该库为所有 DPDK 应用程序都提供了通用的选项,每个选项的具体作用可以通过 ./app -help 的方式查看,这里重点介绍 2 个选项:
-c COREMASK:指定 DPDK 程序所运行的 CPU 核的掩码,掩码的每个位对应于 Linux 提供的 core ID。可以通过读取 /proc/cpuinfo 来获取系统中的所有 core 信息-m或--socket-mem:指定应用程序使用的 Hugepage 内存(socket-mem 选项可以为特定的插槽请求特定大小的内存)。如果没有指定,DPDK 启动时会自动指定
这里我们直接运行 helloworld 程序,可以看到程序运行正常:
1  | [root@kube-master examples]# ./helloworld/build/app/helloworld  | 
额外说明
- 可以通过 DPDK 里的 
usertools/dpdk-setup.sh来简化 DPDK 环境的安装、测试等工作。这里为了熟悉 DPDK,没有使用该工具