1.DPDK 简介
DPDK(Data Plane Development Kit)是数据平面开发工具包,由用于加速在各种CPU架构上运行的数据包处理的库组成。
DPDK需要一定的网卡硬件支持,以Intel为例,支持以下网卡:
e1000 (82540, 82545, 82546)
e1000e (82571, 82572, 82573, 82574, 82583, ICH8, ICH9, ICH10, PCH, PCH2, I217, I218, I219)
igb (82575, 82576, 82580, I210, I211, I350, I354, DH89xx)
ixgbe (82598, 82599, X520, X540, X550)
i40e (X710, XL710, X722, XXV710)
ice (E810)
fm10k (FM10420)
ipn3ke (PAC N3000)
ifc (IFC)
完整的网卡支持列表可在官网查询:
http://core.dpdk.org/supported/
在Linux上部署DPDK有两种方式,一种是通过命令行依次进行配置,编译,驱动加载等;另一种是通过DPDK的脚本进行快捷配置和编译。
通过命令行的方式部署,可配置项更多,可以获得更佳的性能,对DPDK的工作环境也能有更好的熟悉;通过脚本方式部署步骤较少,较简单。
通过脚本部署的教程请移步:
在Linux(CentOS)上部署DPDK------脚本方式
2.DPDK 环境
该章节的内容参照自官网的DPDK System Requirements。
2.1 编译所需的工具和库
- GNU:
make
。 - coreutils:
cmp
,sed
,grep
,arch
, etc. - gcc: versions 4.9 或更新版本。
- libc headers, 即
glibc-devel.x86_64
(以64位数Intel平台为例)。 - Linux kernel headers or sources required to build kernel modules. (
kernel - devel.x86_64
;kernel - devel.ppc64
) - 若需要在64位操作系统上编译32位软件,还需要以下工具:
-
glibc.i686
,libgcc.i686
,libstdc++.i686
andglibc-devel.i686
for Intel i686/x86_64; -
glibc.ppc64
,libgcc.ppc64
,libstdc++.ppc64
andglibc-devel.ppc64
for IBM ppc_64;
-
这里需要注意的是kernel-devel
的版本要匹配内核的版本,可以通过uname -r
查看内核版本号,并通过yum info kernel-devel
查看已安装或支持的kernel-devel
版本号。这里查看到我的centos已经预装了kernel-devel
,版本与kernel版本一致:
uname -r
3.10.0-862.el7.x86_64
yum info kernel-devel
已安装的软件包
名称 :kernel-devel
架构 :x86_64
版本 :3.10.0
发布 :862.el7
大小 :37 M
源 :installed
kernel头文件的路径位于/usr/lib/modules/$kernel-version/kernel
2.2 运行环境
- Kernel version >= 3.16
- glibc >= 2.7 (for features related to cpuset)
- Kernel configuration,centos提供的配置可运行大多数DPDK应用。
2.3 设置Hugepages
Hugepages是DPDK用于提升性能的重要手段。 通过使用Hugepages,可以降低内存页数,减少TLB页表数量,增加TLB hit率。
在Linux上设置Hugepages有两种方式:
- 修改Kernel cmdline(推荐)
- 修改sysfs节点
2.3.1 修改Kernel cmdline(推荐)
通过修改kernel command line可以在kernel初始化时传入Hugepages相关参数并进行配置。
具体的操作步骤如下:
- 修改grub文件
修改/etc/default/grub
文件,在GRUB_CMDLINE_LINUX
中加入如下配置:
该配置表示默认的hugepages的大小为1G,设置的hugepages大小为1G,hugepages的页数为4页,即以4个1G页面的形式保留4G的hugepages内存default_hugepagesz=1G hugepagesz=1G hugepages=4
修改后的grub文件示例如下:GRUB_TIMEOUT=5 GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)" GRUB_DEFAULT=saved GRUB_DISABLE_SUBMENU=true GRUB_TERMINAL_OUTPUT="console" GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap default_hugepagesz=1G hugepagesz=1G hugepages=4 rhgb quiet" GRUB_DISABLE_RECOVERY="true"
- 编译grub配置文件
可以通过命令grub2-mkconfig -o /boot/grub2/grub.cfg
- 重启
通过reboot
命令重启,随后可以通过cat /proc/cmdline
查看kernel的command line是否包含之前的配置。
也可以通过cat /proc/meminfo | grep Huge
命令查看是否设置成功,若设置成功可以看到如下配置:HugePages_Total: 4 HugePages_Free: 4 Hugepagesize: 1048576 kB
DPDK官方建议,64位的应用应配置1GB hugepages。
这种配置方式的优点是可以在系统开机时即配置预留好hugepages,避免系统运行起来后产生内存碎片;另外,对于较大的例如1G pages,是不支持在系统运行起来后配置的,只能通过kernel cmdline的方式进行配置。
注:对于双插槽的NUMA系统(dual-socket NUMA system),预留的hugepages会被均分至两个socket,可以通过lscpu
查看CPU信息:
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 4
On-line CPU(s) list: 0-3
Thread(s) per core: 1
Core(s) per socket: 4
socket(s): 1
NUMA node(s): 1
可见测试主机使用的是单socket的NUMA系统。
2.3.2 修改sysfs节点
对于2 MB页面,还可以选择在系统启动后进行分配。 这是通过修改 /sys/devices/
中的nr_hugepages
节点来实现的。 对于单节点系统,若需要1024个页面,可使用如下命令:
echo 1024 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
在NUMA机器上,页面的需要明确分配在不同的node上(若只有一个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
这种配置方式的优点是配置简单,无需编译、重启,但是无法配置1GB这样的大hugepages。
2.3.3 DPDK使用Hugepages
预留好Hugepages之后,想要让DPDK使用预留的Hugepages,需要进行下述操作:
mkdir /mnt/huge
mount -t hugetlbfs nodev /mnt/huge
可以将这个挂载点添加到/etc/fstab
中,这样可以永久生效,即重启后也仍然可以生效:
nodev /mnt/huge hugetlbfs defaults 0 0
对于1GB pages,在/etc/fstab
中必须指定page size作为mount选项。
nodev /mnt/huge_1GB hugetlbfs pagesize=1GB 0 0
添加上面这样一行内容至/etc/fstab
后并重启,可以通过df -a
看到挂载成功:
nodev 0 0 0 - /mnt/huge_1GB
3.DPDK 编译
该章节的内容参照自官网的DPDK build。
3.1 下载DPDK代码
可从官网下载最新的稳定版或开发版的DPDK代码DPDK代码下载。
然后解压缩:
tar xJf dpdk-<version>.tar.xz
cd dpdk-<version>
其中DPDK的代码包含如下部分:
- lib: Source code of DPDK libraries
- drivers: Source code of DPDK poll-mode drivers
- app: Source code of DPDK applications (automatic tests)
- examples: Source code of DPDK application examples
- config, buildtools, mk: Framework-related makefiles, scripts and configuration
3.2 编译和安装
想要编译和安装DPDK,需要在DPDK的顶层目录运行下面运行make install T=<target>
;或者可以首选运行make config T=<target>
来进行配置,随后运行make
来编译。
这里的target
的格式为:
ARCH-MACHINE-EXECENV-TOOLCHAIN
其中:
-
ARCH
可以是:i686
,x86_64
,ppc_64
,arm64
-
MACHINE
可以是:native
,power8
,armv8a
-
EXECENV
可以是:linux
,freebsd
-
TOOLCHAIN
可以是:gcc
,icc
这里我们使用gcc来编译64位DPDK,这里最初按照官网的guide使用linux
编译报错,后改用linuxapp
:
make install T=x86_64-native-linuxapp-gcc
在编译的过程中,若出现头文件缺失可通过yum
进行安装。
编译完成后,target环境会在DPDK顶层目录以x86_64-native-linuxapp-gcc
为文件名创建,若需要修改配置重新编译,可通过修改target目录下的.config
文件再重新编译:
cd x86_64-native-linuxapp-gcc
vi .config
make
4.DPDK 驱动加载
该章节的内容参照自官网的DPDK Linux Drivers。
不同的PMD需要不同的内核驱动程序才能正常工作。 取决于正在使用的PMD,应加载相应的内核驱动程序并绑定到网络端口。
4.1 UIO
UIO(Userspace I/O)是运行在用户空间的I/O技术。Linux系统中一般的驱动设备都是运行在内核空间,而在用户空间用应用程序调用即可。
而UIO则是将驱动的很少一部分运行在内核空间,而在用户空间实现驱动的绝大多数功能。
在许多情况下,Linux内核中包含的标准uio_pci_generic模块可以提供uio功能。 可以使用以下命令加载此模块:
sudo modprobe uio_pci_generic
除了Linux内核中包含的标准uio_pci_generic模块,DPDK也提供了一个可替代的igb_uio模块,可以在kmod
路径中找到。可以通过以下方法加载igb_uio模块。
sudo modprobe uio
sudo insmod kmod/igb_uio.ko
如果用于DPDK的设备绑定为uio_pci_generic内核模块,需要确保IOMMU已禁用或passthrough。 以intel x86_64系统为例,可以在的GRUB_CMDLINE_LINUX
中添加intel_iommu = off
或intel_iommu = on iommu = pt
。
4.2 VFIO(推荐)
VFIO与UIO相比,它更加强大和安全,依赖于IOMMU。 要使用VFIO,需要:
- Linix kernel version>=3.6.0
- 内核和BIOS必须支持并配置为使用IO virtualization(例如Intel®VT-d)。
在确认硬件配置支持的情况下,要使用VFIO驱动绑定到NIC必须先使能iommu,否则会导致绑定失败。具体的现象就是查看或修改sysfs节点/sys/bus/pci/drivers/vfio-pci/bind
出现io错误,以及dmesg中出现:
vfio-pci: probe of 0000:05:00.0 failed with error -22
使能iommu的方法也是修改kernel的command line将iommu=pt intel_iommu=on
传入,具体步骤:
- 修改grub文件
修改/etc/default/grub
文件,在GRUB_CMDLINE_LINUX
中加入如下配置:iommu=pt intel_iommu=on
- 编译grub配置文件
可以通过命令grub2-mkconfig -o /boot/grub2/grub.cfg
- 重启
通过reboot
命令重启,随后可以通过cat /proc/cmdline
查看kernel的command line是否包含之前的配置。
iommu配置成功后,dmesg中会有iommu配置group的log,可以通过dmesg | grep iommu
查看:
[ 0.594500] iommu: Adding device 0000:05:00.0 to group 18
[ 0.594512] iommu: Adding device 0000:06:00.0 to group 19
即表示iommu使能成功。
随后需要调用modprobe
来加载VFIO的驱动:
sudo modprobe vfio-pci
4.3 驱动绑定NIC
上述的UIO和VFIO驱动可以加载一项,也可以全都加载。但是在驱动绑定NIC的时候,只能选择一种驱动绑定到NIC,这里采用VFIO驱动。
可以调用dpdk路径下的usertools/dpdk-devbind.py
实用脚本来进行VFIO驱动与NIC绑定,需要注意的是使用这个脚本进行绑定(bind)动作时是需要root权限的。
可以调用脚本传入--status
查看当前的网络端口的状态:
python usertools/dpdk-devbind.py --status
Network devices using kernel driver
===================================
0000:03:00.0 'I210 Gigabit Network Connection 1533' if=enp3s0 drv=igb unused=vfio-pci *Active*
0000:04:00.0 'I210 Gigabit Network Connection 1533' if=enp4s0 drv=igb unused=vfio-pci *Active*
0000:05:00.0 'I210 Gigabit Network Connection 1533' if=enp5s0 drv=igb unused=vfio-pci
0000:06:00.0 'I210 Gigabit Network Connection 1533' if=enp6s0 drv=igb unused=vfio-pci
可以看到,当前NIC的状态都是Network devices using kernel driver
,使用的是kernel的igb驱动drv=igb
。
随后可以调用脚本传入--bind
将网卡05:00.0
,也就是enp5s0
绑定到VFIO驱动:
python usertools/dpdk-devbind.py --bind=vfio-pci 05:00.0
再次调用脚本传入--status
,可以看到:
Network devices using DPDK-compatible driver
============================================
0000:05:00.0 'I210 Gigabit Network Connection 1533' drv=vfio-pci unused=igb
Network devices using kernel driver
===================================
0000:03:00.0 'I210 Gigabit Network Connection 1533' if=enp3s0 drv=igb unused=vfio-pci *Active*
0000:04:00.0 'I210 Gigabit Network Connection 1533' if=enp4s0 drv=igb unused=vfio-pci *Active*
0000:06:00.0 'I210 Gigabit Network Connection 1533' if=enp6s0 drv=igb unused=vfio-pci
设备05:00.0
已经配置为drv=vfio-pci
,若想要恢复为kernel默认的igb驱动,则可以继续调用脚本:
python usertools/dpdk-devbind.py --bind=igb 05:00.0
至此,DPDK的部署就算完成了,接下来可以尝试编译和运行
基于DPDK的简单应用了。
基于DPDK的简单应用编译与运行方法可以查看:
编译和运行DPDK示例程序