DPDK2.1 linux上开发入门手册

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

原文地址:https://www.cnblogs.com/ding-linux-coder/p/4900400.html