DPDK学习1 -- DPDK环境搭建和测试helloword

官方文档请访问http://dpdk.org/,这里面很多干货


DPDK(Intel Data Plane Development Kit)是Intel提供的数据平面开发工具集,专注于网络应用中数据包的高性能处理。DPDK应用程序运行在用户空间,利用自身提供的数据平面库来收发数据包,绕过了Linux内核协议栈对数据包处理过程。DPDK其实也是网络开发框架和开发库、高效数据结构、众多Linux系统优化方法的合集。
 

网络设备(路由器、交换机、媒体网关、SBC、PS网关等)需要在瞬间进行大量的报文收发,因此在传统的网络设备上,往往能够看到专门的NP(Network Process)处理器,有的用FPGA,有的用ASIC。这些专用器件通过内置的硬件电路(或通过编程形成的硬件电路)高效转发报文,只有需要对报文进行深度处理的时候才需要CPU干涉。

但在公有云、NFV等应用场景下,基础设施以CPU为运算核心,往往不具备专用的NP处理器,操作系统也以通用Linux为主,网络数据包的收发处理路径如下图所示:

在虚拟化环境中,路径则会更长

由于包处理任务存在内核态与用户态的切换,以及多次的内存拷贝,系统消耗变大,以CPU为核心的系统存在很大的处理瓶颈。为了提升在通用服务器(COTS)的数据包处理效能,Intel推出了服务于IA(Intel Architecture)系统的DPDK技术。

DPDK是Data Plane Development Kit的缩写。简单说,DPDK应用程序运行在操作系统的User Space,利用自身提供的数据面库进行收发包处理,绕过了Linux内核态协议栈,以提升报文处理效率。

DPDK是一组lib库和工具包的集合。最简单的架构描述如下图所示:

上图蓝色部分是DPDK的主要组件(更全面更权威的DPDK架构可以参考Intel官网),简单解释一下:

  • PMD:Pool Mode Driver,轮询模式驱动,通过非中断,以及数据帧进出应用缓冲区内存的零拷贝机制,提高发送/接受数据帧的效率
  • 流分类:Flow Classification,为N元组匹配和LPM(最长前缀匹配)提供优化的查找算法
  • 环队列:Ring Queue,针对单个或多个数据包生产者、单个数据包消费者的出入队列提供无锁机制,有效减少系统开销
  • MBUF缓冲区管理:分配内存创建缓冲区,并通过建立MBUF对象,封装实际数据帧,供应用程序使用
  • EAL:Environment Abstract Layer,环境抽象(适配)层,PMD初始化、CPU内核和DPDK线程配置/绑定、设置HugePage大页内存等系统初始化

这么说可能还有一点点抽象,再总结一下DPDK的核心思想:

  • 用户态模式的PMD驱动,去除中断,避免内核态和用户态内存拷贝,减少系统开销,从而提升I/O吞吐能力
  • 用户态有一个好处,一旦程序崩溃,不至于导致内核完蛋,带来更高的健壮性
  • HugePage,通过更大的内存页(如1G内存页),减少TLB(Translation Lookaside Buffer,即快表) Miss,Miss对报文转发性能影响很大
  • 多核设备上创建多线程,每个线程绑定到独立的物理核,减少线程调度的开销。同时每个线程对应着独立免锁队列,同样为了降低系统开销
  • 向量指令集,提升CPU流水线效率,降低内存等待开销

下图简单描述了DPDK的多队列和多线程机制:

DPDK将网卡接收队列分配给某个CPU核,该队列收到的报文都交给该核上的DPDK线程处理。存在两种方式将数据包发送到接收队列之上:

RSS(Receive Side Scaling,接收方扩展)机制:根据关键字,比如根据UDP的四元组<srcIP><dstIP><srcPort><dstPort>进行哈希
Flow Director机制:可设定根据数据包某些信息进行精确匹配,分配到指定的队列与CPU核
当网络数据包(帧)被网卡接收后,DPDK网卡驱动将其存储在一个高效缓冲区中,并在MBUF缓存中创建MBUF对象与实际网络包相连,对网络包的分析和处理都会基于该MBUF,必要的时候才会访问缓冲区中的实际网络包

 

0、依赖安装

在dpdk编译过程中,由于一些依赖项的限制,dpdk在纯净的系统上安装需要花一些功夫。

yum makecache
yum install -y gcc gcc-c++  kernel-devel kernel-headers kernel.x86_64 net-tools
yum install -y numactl-devel.x86_64 numactl-libs.x86_64
yum install -y libpcap.x86_64 libpcap-devel.x86_64
yum install -y pciutils

ubuntu

  • 所需依赖合集

    更新软件

  • 更新软件源中的所有软件列表:# sudo apt-get update
  • 更新软件:# sudo apt-get upgrade

GNU make

  • 一种构建工具,控制应用程序源代码的可执行代码和其他部分代码生成。
  • 安装:# sudo apt-get install make

Coreutils

  • GNU 下的一个软件包,包含ls等常用命令
  • 安装:# sudo apt-get install coreutils

gcc

  • GNU下的编译器套件,版本需要>=4.9
  • 版本检测:# gcc -v

libc headers

  • Linux ANSIC 的函数库
  • 打包安装:# sudo apt-get install gcc-multilib

Linux Kernel header or sources

  • Kernel-devel.×86_64
  • Kernel-devel.ppc64
  • apt-get install linux-kernel-headers kernel-package

NUMA

  • 安装:
  • # sudo apt-get install numactl
  • # sudo apt-get install libnuma-dev

python

  • 版本2.7+ or 3.2+
  • 安装:# sudo apt-get install python
  • 检测是否安装成功:# python
  • 退出python:# exit()

Kernel version >=3.2

  • 版本检测:# uname -r

glibc

  • 版本大于等于2.7
  • 版本检测:# ldd --version

libpcap

  • 网络数据包捕获函数库
  • 下载:http://www.tcpdump.org 找到libpcap并下载
  • 解压:# tar zxvf libpcap
  • # sudo apt-get install build-essential
  • # sudo apt-get install m4
  • # sudo apt-get install flex
  • # sudo apt-get install bison
  • # ./configure
  • # make
  • # sudo make install

 

1、DPDK下载与测试

源码设置,在虚拟机终端从dpdk官方直接git clone最新的代码: 

git clone git://dpdk.org/dpdk

进入dpdk目录;编辑一个环境变量文件,然后source;

export RTE_SDK=`pwd`  
export RTE_TARGET=x86_64-native-linuxapp-gcc  

然后执行:

make config T=x86_64-native-linuxapp-gcc
make install T=x86_64-native-linuxapp-gcc
//make install T=x86_64-native-linuxapp-gcc DESTDIR=/usr/local

等编译OK后,执行一些准备工作:

#!/bin/sh

cat /proc/meminfo | grep Huge

HUGEPGSZ=`cat /proc/meminfo  | grep Hugepagesize | cut -d : -f 2 | tr -d ' '`

bind_nic(){
    ifconfig $1 down  
    ${RTE_SDK}/usertools/dpdk-devbind.py --bind=igb_uio $1 
}

#
echo "Loading DPDK UIO module"  
/sbin/lsmod | grep -s uio > /dev/null
if [ $? -ne 0 ] ; then
	modinfo uio > /dev/null
	if [ $? -eq 0 ]; then
		modprobe uio
	fi
fi
insmod ${RTE_SDK}/${RTE_TARGET}/kmod/igb_uio.ko     

#   
echo "Creating /mnt/huge and mounting as hugetlbfs"
sudo mkdir -p /mnt/huge

grep -s '/mnt/huge' /proc/mounts > /dev/null
if [ $? -ne 0 ] ; then
	sudo mount -t hugetlbfs nodev /mnt/huge
fi

#
echo "@@@@@Reserving hugepages"	
#echo 1024 > /sys/kernel/mm/hugepages/hugepages-${HUGEPGSZ}/nr_hugepages 
echo > .echo_tmp
for d in /sys/devices/system/node/node? ; do
	node=$(basename $d)
	echo -n "Number of pages for $node: "
	read Pages
	echo "echo $Pages > $d/hugepages/hugepages-${HUGEPGSZ}/nr_hugepages" >> .echo_tmp
done
sh .echo_tmp
rm -f .echo_tmp

#
echo "Bind interface" 
ifconfig -a
 
${RTE_SDK}/usertools/dpdk-devbind.py --status
bind_nic ens5
bind_nic ens6

cat /proc/meminfo | grep Huge

2、编译helloword

进入helloword的目录,执行make

[root@CC build]# ./helloworld 
EAL: Detected 5 lcore(s)
EAL: Detected 1 NUMA nodes
EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: No available hugepages reported in hugepages-1048576kB
EAL: Probing VFIO support...
EAL: WARNING: cpu flags constant_tsc=yes nonstop_tsc=no -> using unreliable clock cycles !
EAL: PCI device 0000:00:03.0 on NUMA socket -1
EAL:   Invalid NUMA socket, default to 0
EAL:   probe driver: 8086:100e net_e1000_em
EAL: PCI device 0000:00:04.0 on NUMA socket -1
EAL:   Invalid NUMA socket, default to 0
EAL:   probe driver: 8086:100e net_e1000_em
EAL: PCI device 0000:00:05.0 on NUMA socket -1
EAL:   Invalid NUMA socket, default to 0
EAL:   probe driver: 8086:100e net_e1000_em
EAL: PCI device 0000:00:06.0 on NUMA socket -1
EAL:   Invalid NUMA socket, default to 0
EAL:   probe driver: 8086:100e net_e1000_em
EAL: PCI device 0000:00:07.0 on NUMA socket -1
EAL:   Invalid NUMA socket, default to 0
EAL:   probe driver: 8086:100e net_e1000_em
hello from core 1
hello from core 2
hello from core 3
hello from core 0
hello from core 4

3、helloworld例子

     这个是最简单的使用dpdk开发套件的例程。

     源码分析: 

#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <sys/queue.h>
//以上头开发环境glibc的相关头文件
#include <rte_memory.h>
#include <rte_memzone.h>
#include <rte_launch.h>
#include <rte_eal.h>
#include <rte_per_lcore.h>
#include <rte_lcore.h>
#include <rte_debug.h>
/*以上为dpdk自己编写的一些公共库头文件,如内存池、线程、抽象环境等工具,DPDK有自己的开发风格,适应之。*/
static int
lcore_hello(__attribute__((unused)) void *arg)/* 此处有一个字节对齐操作,此处不做详细分析。*/
{
 
    unsigned lcore_id;
    lcore_id = rte_lcore_id(); //获取逻辑核编号,并输出逻辑核id,返回,线程退出。
    printf("hello from core %u\n", lcore_id);
    return 0;
}
 
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");
 
    /* 每个从逻辑核调用回调函数lcore_hello输出相关信息。 */
    RTE_LCORE_FOREACH_SLAVE(lcore_id) {
        rte_eal_remote_launch(lcore_hello, NULL, lcore_id);
    }
 
    /* 再次调用主逻辑核输出相关信息。 */
    lcore_hello(NULL);
    /* 等待所有从逻辑核调用返回,相当于主线程阻塞等待。*/
    rte_eal_mp_wait_lcore();
    return 0;
}
 
Makefile:
#判断相关环境变量是否设置
ifeq ($(RTE_SDK),)
$(error "Please define RTE_SDK environment variable")
endif
 
# 默认的平台目标
RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
include $(RTE_SDK)/mk/rte.vars.mk
 
# binary name
APP = helloworld
 
# all source are stored in SRCS-y
SRCS-y := main.c
 
CFLAGS += -O3
CFLAGS += $(WERROR_FLAGS)
 
include $(RTE_SDK)/mk/rte.extapp.mk

1.带参数运行 -l 

2.带参数运行 -l --master-lcore

选项解释
[root@dev build]# ./helloworld --help
EAL: Detected lcore 0 as core 0 on socket 0
EAL: Detected lcore 1 as core 1 on socket 0
EAL: Support maximum 128 logical core(s) by configuration.
EAL: Detected 2 lcore(s)

Usage: ./helloworld [options]

EAL common options:
  -c COREMASK         逻辑核16进制掩码
  -l CORELIST         列出运行时逻辑核列表           
                      参数格式 <c1>[-c2][,c3[-c4],...]
                      where c1, c2, etc are core indexes between 0 and 128
  --lcores COREMAP    映射逻辑核到物理逻辑核集合中
                      The argument format is
                            '<lcores[@cpus]>[<,lcores[@cpus]>...]'
                      lcores and cpus list are grouped by '(' and ')'
                      Within the group, '-' is used for range separator,
                      ',' is used for single number separator.
                      '( )' can be omitted for single element group,
                      '@' can be omitted if cpus and lcores have the same value
  --master-lcore ID   指定主线程逻辑核id
  -n CHANNELS         指定内存通道数
  -m MB               指定内存分配 (类似 --socket-mem)
  -r RANKS            Force number of memory ranks (don't detect) 强制内存参数
  -b, --pci-blacklist 将PCI网络设备列入黑名单,防止EAL环境使用这些PCI设备,参数格式为<domain:bus:devid.func>
  -w, --pci-whitelist 将PCI网络设备列入白名单,仅仅用指定的PCI设备,参数格式为<[domain:]bus:devid.func>
  --vdev              添加一块虚拟设备,这个参数格式为 <driver><id>[,key=val,...]
                      (例如: --vdev=eth_pcap0,iface=eth2).
  -d LIB.so|DIR       添加驱动活驱动目录(can be used multiple times)
  --vmware-tsc-map    Use VMware TSC map instead of native RDTSC
  --proc-type         进程的类型 (primary|secondary|auto)
  --syslog            设定syslog日志
  --log-level         设定默认日志级别
  -v                  启动时显示版本信息
  -h, --help          This help

EAL options for DEBUG use only: 调试
  --huge-unlink       在初始化后去掉大页面文件连接
  --no-huge           用 malloc 代替 hugetlbfs
  --no-pci            关闭 PCI
  --no-hpet           关闭 HPET
  --no-shconf         不共享配置(mmap'd files)

EAL Linux options: 选项
  --socket-mem        内存分配
  --huge-dir          大页面挂载目录
  --file-prefix       页表文件前缀
  --base-virtaddr     虚拟地址基址
  --create-uio-dev    Create /dev/uioX (usually done by hotplug)
  --vfio-intr         Interrupt mode for VFIO (legacy|msi|msix)
  --xen-dom0          Support running on Xen dom0 without hugetlbfs</span>

 

项目makefile的修改
使用dpdk库的项目,无须将makefile修改为dpdk自带的应用程序的makefile风格,可以继续使用项目自己的makefile。
但是,需要对项目的makefile做出如下修改。


编译选项,增加如下内容。
-march=native -DRTE_CACHE_LINE_SIZE=64\
-I/usr/local/include/dpdk/  -include rte_config.h

链接选项,增加如下内容。
-L/usr/local/lib -Wl,--whole-archive \
-lrte_distributor -lrte_reorder -lrte_pipeline -lrte_table -lrte_port \
-lrte_timer -lrte_hash -lrte_jobstats -lrte_lpm -lrte_power \
-lrte_acl -lrte_meter -lrte_sched -lm -lrt -lrte_vhost \
-Wl,--start-group -lrte_kvargs -lrte_mbuf -lrte_mbuf_offload -lrte_ip_frag \
-lethdev -lrte_cryptodev -lrte_mempool -lrte_ring -lrte_eal \
-lrte_cmdline -lrte_cfgfile -lrte_pmd_bond -lrte_pmd_vmxnet3_uio \
-lrte_pmd_virtio -lrte_pmd_cxgbe -lrte_pmd_enic -lrte_pmd_i40e \
-lrte_pmd_fm10k -lrte_pmd_ixgbe -lrte_pmd_e1000 \
-lrte_pmd_ring -lrte_pmd_af_packet -lrte_pmd_null -lrt -lm -ldl \
-Wl,--end-group -Wl,--no-whole-archive
 

总结
     有些细节没去认真的分析,细节部分前面也进行了一些理论学习,后面的学习目标是:快速上手,熟悉使用,学习设计思想。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值