zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    电子科技大学实验中学PK赛(二)比赛题解
    伊苏比的梦幻之旅(三)比赛题解
    电子科技大学实验中学PK赛(一)比赛题解
    伊苏比的梦幻之旅(二)比赛题解
    伊苏比的梦幻之旅(一)比赛题解
    The Solution of UESTC 2016 Summer Training #1 Div.2 Problem C
    The Solution of UESTC 2016 Summer Training #1 Div.2 Problem B
    c++11 多线程间共享数据 <c++ concurrency in action>
    c++11 多线程 2<<c++ concurrency in action>>
    c++11 多线程 1<<c++ concurrency in action>>
  • 原文地址:https://www.cnblogs.com/ding-linux-coder/p/4900400.html
Copyright © 2011-2022 走看看