导航:首页 > 源码编译 > dpdk2011应用程序编译

dpdk2011应用程序编译

发布时间:2023-06-02 16:43:45

Ⅰ dpdk-pktgen简单使用

这一步之前,DPDK环境已塔好,pktgen已编译成功,网卡已绑定成功等一系列初始化工作已完成。

命令行参数:-P 和 -m 这两个参数是必要的!

./app/build/pktgen [EAL options] -- \

                            [-h] [-P] [-G] [-T] [-f cmd_file] \

                            [-l log_file] [-s P:PCAP_file] [-m ]

  -s P:  file    PCAP packet stream file, 'P' is the port number  -f filename  Command file (.pkt) to execute or a Lua script (.lua) file 

-l          filename  Write log to filename 写日志

-P         Enable PROMISCUOUS mode on all ports 开启混杂模式,必须要的参数 

-g          address  Optional IP address and port number default is (localhost:0x5606)

If -g is used that enable socket support as a server application

-G          Enable socket support using default server values localhost:0x5606 

-N          Enable NUMA support 

-T          Enable the color output 输出颜色 

--crc-strip  Strip CRC on all ports

-h Display the help information

参数中,最复杂的是 -m <string>

-m  <string> 配置端口到逻辑核的映射关系,使用类似BNF类语法.映射的逻辑核要与 [EAL options]中的逻辑核要一致。

如下,也可以用 {} 来代替 [].

[EAL options]里的参数与DPDK基本一样,主要是配置逻辑核掩码和内存通道数。这里不详解。以上是命令行参数,下面介绍运漏姿行时参数。

详细可参考官网中的资料: pktgen运行时参数

Pktgen:/> help #有帮助提示

这里只介绍最常用的命嫌银令,最常用的配置就是MAC,IPv4|IPv6|ARP,TCP|UDP|ICMP,SPORT|DPORT,PROTO,SEQ等

这些配置可以用 set命令来完成。

除了set命令,常用的还有显示主页面,page 0  | page main

加载和保存 .lua脚本的配置信息  load | save <path-to-file>

启动/结束发包:start | stop <portlist>.

其实不用刻意去记命令怎么使用,按两次Tab键会有命令使用的提示。我现在用的是版本是3.1.2,最新版已到了3.5.0,所以一些配置命令会有些不一样,比如配置ip时,<portlist>的顺序就不一样。以上配置是基于最新版来的,如果在实际中发现按上面的命令不对,请先确认是否为最新版.其实只要大致记住一些命令就行,实际使用时可以按两次Tab键就会有提示,也可以把配置保存成.lua文件,下一次运行时候,直接加载就不用再配置了。由于对lua脚本不太熟,关于lua脚本的使用,等使用熟悉了再来深入讨论一些功能。最后,放一张运行时候的图来压压惊。。。芹搜宴

运行命令:./app/app/x86_64-native-linuxapp-gcc/pktgen -l 1-4 -n 4 -- -P -T -m "[1:2].0,[3:4].1"

祝大家生活愉快。

Ⅱ dpdk源码中未定义的宏是如何在编译时期生成的

它不可能“生成”,磨轮还是需要你指定的,具体对于这些宏如虚肢何指定 要看它编译命令,但是一般编译器可以通过编译环境、差游世命令行参数等方式来定义宏

Ⅲ DPDK PKTGEN使用

PKTGEN有两种形式,一种是直接由linux系统自带的内核模块进行发包(也就是略过协议栈,直接控制发包),另一种是依赖于dpdk的pktgen也就是本文主要讲的,需要进行稍微复杂的编译

modprobe pktgen
在/proc/net/pktgen看到以下文件:
kpktgend_0 kpktgend_1 kpktgend_2 kpktgend_3 pgctrl
其中kpktgen_*的多少是根据你的CPU的个数决定的,如我的机子的CPU数目为4,则有四个此文件皮宴。
通卜迹过命令cat /proc/net/pktgen/pgctrl可以型握并查看pktgen的版本等信息:

注:也有使用insmod的,和modprobe的区别是:比如需要安装b模块,但是b依赖于a模块,因此使用insmod安装就需要先安装a模块再安装b模块;如果使用modprobe的话,就可以直接安装b模块,默认将安装a模块
基本上设置完成后就可以进行测试,要查看是否有流量,可以使用ifstat,tcpmp工具查看,使用应用层的抓包工具是无法看到的

关键参数介绍

参数中,最复杂的是 -m <string>
-m <string> 配置端口到逻辑核的映射关系,使用类似BNF类语法.映射的逻辑核要与 [EAL options]中的逻辑核要一致。

运行命令 ./app/x86_64-native-linuxapp-gcc/pktgen -l 0-2 -n 3 -- -P -m "[1].0, [2].1"

官方的default.cfg内容如下:

需要修改的地方有三处:

修改完后即可执行。

图中port1和port2已经有明显区别,收包数相差100个包
用pkggen再发1000个包

Ⅳ DPDK ACL算法介绍

DPDK提供了三种classify算法:最长匹配LPM、精确匹配(Exact Match)和通配符匹配(ACL)。

其中的ACL算法,本质是步长为8的Multi-Bit Trie,即每次可匹配一个字节。一般来说步长为n时,Trie中每个节点的出边为2^n,但DPDK在生成run-time structures时,采用DFA/QRANGE/SINGLE这几种不同的方式进行数据结构的压缩,有效去除了冗余的出边。本文将为大家介绍ACL算法的基本原理,主要内容包括:trie树的构造、运行时的node array生成和匹配原理。对于ACL接口的使用,参考DPDK的官方文档即可。

ACL规则主要面向的是IP流量中的五元组信息,即IP/PORT/PROTO,算法在这个基础上进行了抽象,提供了三种类型的匹配区域:

熟悉这三种类型的使用后,完全可以用它们去匹配网络报文的其它区域,甚至将其应用到其它场景中。

具体来说,rte_acl_field_def有5个成员:type、size、field_index、input_index、offset。
如果要深入理解算法,可以思考这几个字段的意义,或者换个角度来看:

对于规则的定义,要注意如下两点:

比如定义了5个field,那么请给出每一个的具体定义:

像field[1]中IP和mask都为0,表示匹配所有的IP地址;field[3]中range由0到65535,表示匹配所有。类似这样的全匹配一定要显示的定义出来,因为如果不明确定义,这些字段的值取决于编译器的,最后编译的ACL规则很可能与原有设想存在偏差。

如果在规则中,对于某个field不进行限制,对于不同type的field,规则书写时有一定差异:
对于BITMASK和MASK类型,全0代表匹配所有,如上例中的field[0]、field[1];
对于RANGE,则按照上述field[3]中的形式定义。

规则定义好后,会转换为trie树并最终合并到一起。
实际处理过程中,build_trie函数会自底向上的将rule中的每个field转换为node,然后将这些node合并生成这条rule的trie,最后将这个trie与已有的trie进行merge,最终生成整个rule set的trie。

tire由node组成,其主要数据成员如下:

node中values成员用于记录匹配信息,ptrs则用于描述node的出边,用于指向转换后的node。

values采用bitmap进行压缩,其数据结构为struct rte_acl_bitset values; 一个byte取值范围是[0,255],可通过256个bit位来进行对应,并实现byte值的快速查找:即通过第x位的bit值是否为1来判断是否包含数值x(0 <= x < 256)。

num_ptrs用于描述出边数目,ptrs即为实际的出边,它记录了其匹配值values和匹配后的节点指针。
match_flag和mrt则用于记录匹配结果,trie树中叶子节点一定是记录匹配结果的节点。

trie树其详细结构比较复杂,这里将其结构进行简化,如下所示:

上图的trie树有4个node,通过ptrs进行指向,values字段为匹配值的bitmap表示,为了表述的简洁,后续会采用simple的方式进行描述。
在trie simple中,实心节点表示匹配节点,边上的数字代表匹配值(为便于阅读,采用实际值而不再是bitmap形式),…代表其它匹配值。

不同type的field,转换为node的方式会有所不同。
目前提供的3种类型:BITMASK描述一个byte的匹配,支持mask模式;MASK用于描述4个byte的匹配,支持mask模式;RANGE描述2个byte的匹配,此时mask表示上限。
field到node的转换,见build_trie中的for循环,具体转换函数则参考:

对于BITMASK,如{.value.u8 = 6, .mask_range.u8 = 0xff,},它最后的转换形式如下:

构造field的node时,总会在结尾添加一个空的end节点,最后一个field除外(它是match node)。在for循环中每完成了一个field的解析后,会将其合并到root中,从而生成这个rule的trie。
合并前,也会先构造一个空的end node(见build_trie函数中,while循环下的root创建),让它与field构成的node头合并,因为不相交,所以merge时会将匹配信息合并到end node并释放原有的头,并将field链的end节点返回(保存到end_prev中),下次合并时,就用此end节点与新的node头合并。
循环遍历完所有的field后,这些node就串联起来了,构成这个rule的trie。

对于多个rule,每次构造完成后会merge到整体的trie中。
这里详细介绍下merge算法原理,其实仔细阅读acl_merge_trie函数的注释即可。

对于node A和node B的merge, acl_merge_trie函数返回一个节点,这个节点指向它们路径的交集。
这里给出三个例子用于展示merge前后的变化。为了减少状态点,构造rte_acl_field_def如下:

示例1:

acl_rules[1]为trie A,acl_rules[0]对应trie B,最终trie B合并到trie A上,具体如下:

1和1’合并时,因为level为0,所以1’直接合并到1中;
4和4’合并时,因为节点无交集,所以创建新节点c1(node 4的拷贝),并将4'上的边拷贝到c1中。

示例2,rule类别相同,但优先级不同:

acl_rules[1]为trie A,acl_rules[0]对应trie B,最终trie B合并到trie A上,具体如下:

6和6’是match node,类别相同,且6的优先级为2大于6’的优先级。
6和6’合并时,直接返回6。而前面创建的新节点,如d1,已包含5’的所有边(非ACL_INTERSECT_B),所以最终返回5,free d1。
同理依次往上回溯,a4,b3,c2,也依次被释放,最终merge的trie即为原来的trie A。

示例3,rule类别不同,优先级相同:

acl_rules[1]为trie A,acl_rules[0]对应trie B,最终trie B合并到trie A上,具体如下:

6和6’是match node,因为类别不同,所以最终创建了新node e1,这也导致示例3和示例2最终merge结果的不同。

合并是一个递归的过程,逆向思考构造过程会有助于理解算法。另外,在build_trie之前会sort_rule,匹配范围更大的rule会放到前面优先构造trie,个人为这样node A包含node B的概率更大,这可能也是merge时创建的node C是A的拷贝而不是B的拷贝的原因,因为这样出现ACL_INTERSECT_B的概率相对较低。

一些说明:

trie树构造完成后,会将其由指针跳转的形式转换为等效的数组索引形式,即node array,既可让匹配数据更紧凑,也可提高匹配算法的效率。
采用node array的方式进行状态点的压缩是很常见的优化方式,比如snort里面的ac算法(acsmx.c):

笔者也曾经做过类似的优化,通过将出边由指针方式修改为索引方式,整个匹配tree的内存占用只需要原来的1/5。
将指针方式转换为node array形式是优化的第一步,对于Next[256]出边又可以采用多种压缩方式,比如snort中新的ac算法(acsmx2.c),就采用了Sparse rows和Banded rows等多种压缩方式,但其原理是将出边进行映射转换,本质上还是做DFA状态跳转。

DPDK对边的压缩方式与上述类似,不过它优化的粒度更细,不同type的node有不同的压缩方式:

比如在示例三中,node 1为DFA节点(根节点强制使用DFA方式),2、3、a5、b4、c3、d2为QRANGE,4、5为SINGLE,6、e1为MATCH。
2、3、a5、b4虽然在图上仅有一条有效边,但它不为SINGLE,因为对于无效的匹配其实也会有出边,所以它的真实出边数目并不唯一,只有像4、5这类全匹配节点才是真正的SINGLE节点。

在构造node array前,会调用acl_calc_counts_indices函数更新node的node type,fanout等信息。
node type依据其fanout值决定,fanout计算见acl_count_fanout函数,其原理是:

比如对于示例3中的d2节点:

fanout计算完成后,若其值为1则为SINGLE节点,(1, 5]为QRANGE节点,(5, 256]为DFA节点。
注意:对于trie树的root节点,不论fanout值为多少,会强制将其构造为DFA节点,且其fanout值会重新计算。

type和fanout计算完成后,会统计各类节点数目,信息保存在acl_calc_counts_indices传入的counts参数中,随后rte_acl_gen依据这些信息将整块的node array内存分配出来,其布局大致如下:

Data indexes中用于保存在rte_acl_field_def中定义的offset;
Results对应match node,用于保存匹配结果。
Trans table包含整个匹配过程中的跳转点:

静态将整块node array分配完成后,就需要依据trie 树的node信息填充Trans table和Results了,具体过程见acl_gen_node函数;Data indexes的填充则在acl_set_data_indexes中完成。

2.2中的内存布局大致描绘了各种类型节点的分布情况,DFAs内部由一个一个的DFA节点组成,QUADs和SINGLEs也一样,都是由相同类型的节点构成。
对于每一个节点,其结构则类似如下形式:

DFA节点的fanout一般为4,出边数为fanout*RTE_ACL_DFA_GR64_SIZE;(图中画的为fanout为4的情况,256条出边)
QUAD节点的fanout不超过5,即为节点的出边数不超过5;(图中画的为fanout为4的情况)
SINGLE节点只有一个出边;
图中的trans即为这个节点的出边,它本质是一个uint64的数据结构,通过trans和input信息即可计算得到下一个节点的index,从而实现匹配跳转。trans中不同bit位包含着丰富的信息,具体见acl.h中的说明即可。

高32位对于不同类型的节点有不同的解释:

低32位:

在实际处理过程中,通过高32位与input_byte计算得到index,与低32位中的addr,即可快速定位到下一个trans:trans_table + (addr+index)。
这里的处理其实与传统的DFA跳转差别很大,传统处理时,next = node[‘input’],跳转到下一个节点,然后采用next[‘input’]进行跳转和匹配,即使有数据结构的压缩,跳转目标仍是状态点。但DPDK中,跳转时直接采用trans_table + (addr+index),直接找到了状态点的边(trans),而不是到状态点。

跳转表具体构建时,采用acl_gen_node函数完成:

匹配的过程与跳转表的构建其实是互为一体的,如何构建跳转表就决定了如何进行匹配。

在2.3节,对于跳转的形式已进行了说明,具体可阅读rte_acl_classify_scalar函数:跳转时直接采用trans_table + (addr+index),直接找到了状态点的边(trans),而不是到状态点。

对于具体的匹配过程,还有一点需要注意,即GET_NEXT_4BYTES的使用,每次匹配时候都会去4BTYTES进行匹配,这也是为什么定义input fields时要求4字节连续。比如我在dpdk-dev邮件组中问的这个 问题 。

解决4字节连续,可以通过定义相同的input_index来解决,比如像邮件中提到的设置sport/dport的input_index相同,这是因为data indexes的构造取决于input_index,见acl_build_index函数;同时field_index不同、input_index相同时可避免对field区间的优化(如果优化,将某个field去掉了,这时4字节匹配会失效)。邮件中的问题,正是因为field[3]被优化掉后,4字节连续匹配出现问题。

在特定的场合还必须通过指定.size为32来解决,即使type类型为BITMASK,见DPDK的ACL文档中关于 tos示例的说明 。

另外再说下field_index,前面提出一个问题:field_index是否多余?
答案是不多余,因为算法中会对field进行优化,如果不指定field_index字段,这个优化就无法进行了,具体的优化处理见acl_rule_stats函数。
优化过程中要进行input_index的判断,这是因为相同的input_index可以有多个field,但其中只有某个field是completely wild时应避免进行优化。只有相同input_index的所有field都是completely wild时,才应该将这个field优化掉。

上面的一系列说明,都是针对GET_NEXT_4BYTES每次匹配四个字节的匹配进行的补充说明。

匹配的具体过程,这里用图形的方式进行简要说明,为了能有多种类型的node,这里构造规则如下:

trie树如下所述:

对应的node array如下图所示:

假设输入数据为:proto 16, ip 192.12.8.8,则transition跳转方式如上图红线所示:

注意:node array中indexes、DFA0和idle省略了。

关于trie树相关的理论知识参考 这里 。

本文主要介绍了DPDK的ACL算法,详细描述了如何由规则生成trie,并将trie转换为node array的过程,在文末通过示例介绍了具体的匹配过程。文章旨在介绍ACL算法的基本思路,希望对大家能有所帮助。

Ⅳ 编译和运行DPDK示例程序

DPDK(Data Plane Development Kit)是数据平面开发工具包,由用于加速在各种CPU架构上运行的数据包处理的库组成。

在Linux上部署DPDK的方法请参考:
在Linux(CentOS)上部署DPDK------命令行方式

该章节的内容参照自官网的 DPDK build sample apps

当DPDK的target环境创建好后(例如 x86_64-native-linuxapp-gcc ), x86_64-native-linuxapp-gcc 目录中会包含编译应用程序的库和头文件。

在编译DPDK应用程序之前,首先需要指定两个环境变量:

在DPDK的 examples 路径下面有许多示例应用,这里以其中的 helloworld 为例进行编译:

DPDK的 examples 路径下面的应用均可以通过这种方式编译,也可以直接在 examples 路径下面运行 make ,将这些应用全都编译好。

在运行应用程序之前,需要确保:

DPDK应用程序与DPDK target环境的环境抽象层EAL(Environmental Abstraction Layer )库相关联,该库提供了一些通用于每个DPDK应用程序的选项。

EAL的详细配置请参照: DPDK EAL参数

可按照下列参数运行 ./helloworld :

其中 -l 命令指定cpu cores list是EAL必须的配置;若没有指定 --socket-mem ,则默认会按照预留的hugepages size来分配。

Ⅵ 在虚拟机编译运行dpvs

修改:PKG_CONFIG_PATH应该谨唯悄是*.pc所在目录,祥渣如下设置即可。
export PKG_CONFIG_PATH=/root/dpvs/dpdk/dpdklib/lib/x86_64-linux-gnu/pkgconfig

修改:安装libnuma-dev即可。apt install libnuma-dev

修改:src/Makefile 中加上 -Wno-address-of-packed-member
CFLAGS += -Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -Wno-address-of-packed-member -mcmodel=medium

修改:src/Makefile 中加上 -Wno-packed-not-aligned
CFLAGS += -Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -Wno-address-of-packed-member -Wno-packed-not-aligned -mcmodel=medium

修改:注山困释掉下面两行

修改:安装 apt-get install libpopt-dev

修改:修改dpip的makefile,添加CFLAGS += $(DEFS) -Wno-address-of-packed-member

Ⅶ DPDK编程指南(翻译)( 三十一)

DPDK 需要一个构建系统用于编译等操作。 本节介绍 DPDK 框架中使用的约束和机制。

这个框架有两个使用场景:

以下提供了如何构建DPDK二进制文件。

安装之后,将创建一个构建目录结构。 每个构件目录包含文件、库和应用程序。

构建目录特定于配置的体系结构、执行环境、工具链。 可以存在几个构建目录共享源码,但是配置不一样的情况。

例如,要使用配置模板 config/defconfig_x86_64-linuxapp 创建一个名为 my_sdk_build_dir 的构建目录,我们使用如下命令:

这会创建一个新的 new my_sdk_build_dir 目录,之后,我们可以使用如下的命令进行编译:

相当于:

目录 my_sdk_build_dir 的内容是:

请参阅 Development Kit Root Makefile Help 获取更详细的信息。

由于DPDK本质上是一个开发工具包,所以最终用户的第一个目标就搜此是使用这个SDK创建新的应用程序。 要编译应用程序,用户必须设置 RTE_SDK 和 RTE_TARGET 环境变量。

对于一个新的应用程序,用户必须创建新的 Makefile 并包含指定的 .mk 文件,如 ${RTE_SDK}/mk/rte.vars.mk 和 ${RTE_SDK}/mk/rte.app.mk。 这部分内容描述请参考 Building Your Own Application .

根据 Makefile 所选定的目标(架构、机器、执行环境、工具链)或环境变量,应用程序和库将使用适当的h头文件进行编译,并和适当的a库链接。 这些文件位于 ${RTE_SDK}/arch-machine-execenv-toolchain,由 ${RTE_BIN_SDK} 内部引用。

为了编译应用程序猛袜,用户只需要调用make命令。编译结果将置于 /path/to/my_app/build 目录。

示例应用程序在example目录中提供。

在DPDK中,Makefiles始终遵循相同的方案:

根据Makefile最后包含的 .mk 文件,Makefile将具有不同的角色。 注意到,并不能在同一个Makefile文件中同时编译库和应用程序。 因此,用户必须创建两个独立的Makefile文件,最好是置于两个不同的目录中。

无论如何,rte.vars.mk 文件必须包含用户Makefile。

这些 Makefiles 生成一个二进制应用程序。

创建一个 .a 库。

app/dpdk-pmdinfogen

dpdk-pmdinfogen 扫描各种总所周知的符号名称对象文件。这些目标文件由各种宏定义,用于导出关于pmd文件的硬件支持和使用的重要信息。 例如宏定义:

创建以下的符号:

将被 dpdk-pmdinfogen 扫描。使用这个虚拟系,可以从目标文件中导出其他相关位信息,并用于产生硬件支持描述, 然后 dpdk-pmdinfogen 按照以下格式编码成 json 格式的字符串:

然后可以通过外部工具搜索这些字符串,以确定给定库或应用程序的硬件支持。

一些变量可以用来配置构建系统的行为。在文件 Development Kit Root Makefile Help 及 External Application/Library Makefile Help 中有描述。

这避免了根据编译器(icc或gcc)使用不同世知迅的情况。而且,这个变量可以从命令行覆盖,这允许绕过标志用于测试目的。

阅读全文

与dpdk2011应用程序编译相关的资料

热点内容
打真军香港电影 浏览:617
汇款app原理是什么 浏览:170
法国电影一个偷画 浏览:879
店长的h命令必须服从 浏览:94
cad填充命令是什么 浏览:870
java引用类型值类型 浏览:240
徐锦江叶子楣方唐镜 浏览:59
可以在线看片的网站 浏览:133
小米加密兔手机壁纸 浏览:613
2019程序员笔记本 浏览:477
武大小孩子厉害的电影有哪些 浏览:35
找一个可以看的网址 浏览:79
四个字的国外电影,小孩儿 浏览:411
推荐看片网站 浏览:652
主角叫林飞的小说是什么 浏览:683
闲置服务器能干什么工作 浏览:949
asdr q-2299123 浏览:987
中国最大尺度古装电影 浏览:695
电影和电视播放器 浏览:113
樱桃小说by小花喵 浏览:514