DPDK Pktgen+Docker搭建VNF环境及验证

作者简介:文殊博,北京邮电大学未来网络理论与应用实验室(FNL)研究生

一、简介及参考文献

​本文主要是搭建一个基于DPDK的VNF开发实验环境,利用docker和vhost-user摆脱DPDK的硬件约束,方便在一台机器上进行VNF的开发和测试。但是,DPDK的PMD对不同网卡的特性支持差异很大,所以不能完全以这种环境下的运行结果为准。接下来会先介绍环境的配置过程然后搭建一个简单的拓扑,最后会对DPDK的testpmd应用中最简单的iofwd转发引擎中关键部分进行简单说明。

  • NFV(Network Funciton Virtualization, 网络功能虚拟化)旨在通过标准化设备替代现存的专用IT设备,以降低CapEX和OpEX并提供更高的灵活性。更详细内容的可以查看ETSI发布的NFV白皮书或OPNFV提供的相关内容
  • DPDK是intel开发的开源高性能数据平面开发工具集。它提供了在通用处理器上进行快速包处理的库和驱动,这种特性非常适合NFV。更详细内容的内容可以查看DPDK官方文档
  • pktgen即packet generator,以下都特指pktgen-dpdk。这是一款基于DPDK的强大的流量产生工具。更详细的内容可以查看pktgen官方文档
  • Docker是一款简单易用的容器管理工具。由于容器本身启停快、体积小等、
  • 特点,容器化也成为了NFV的趋势之一。更详细内容可以查看Docker官方文档
  • vhost-user是实现在用户态的vhost,相比virtio和vhost需要内核支撑,vhost-user可以完全工作在用户态。vhost-user通过socket文件和共享内存来完成数据的传递。更详细内容可以查看QEMU关于vhost-user的介绍

二、环境配置

2.1 DPDK的安装

  1. 下载DPDK源码,并配置安装所需环境变量。
  2. 配置DPDK

    这里由于要是用Vhost-user驱动,修改使得文件中CONFIG_RTE_LIBRTE_VHOST=y。如果需要连接其他驱动的网卡,也要确认其他驱动相关设置正确。
  3. 安装DPDK

2.2 hugepages的配置

      本实验中由于我们需要使用virtio-user这种连接方式,由于实现时的一些限制导致使用vhost-user时同时最多只能使用8个hugepages无论2M还是1G大小的hugepagesize。所以这里必须使用1G大小的hugepagesize同时最多分配8个。

2.3 Pktgen的安装

      pktgen的安装依赖于DPDK,安装前确保RTE_SDK和RTE_TARGET环境变量设置正确。

2.4 Docker的安装

国内连接Docker官方仓库非常不稳定,经常404无法获取镜像。推荐使用阿里云提供的Docker镜像仓库。在其中的管理中心——Docker Hub镜像站点中有完整的Docker安装和加速器配置过程。以下从其中复制出的简单安装过程。

安装完成后可以简单测试。

正确安装的话,可以进入一个最简单的容器环境中,Ctrl+D可以退出。

三、简单的拓扑搭建

3.1 拓扑

预建立的简单拓扑如下

testpmd是DPDK提供的一个通过数据包转发进行DPDK测试的工具,也是一个非常好的DPDK应用开发示例。如果想进行简单的DPDK开发实验推荐修改$RTE_SDK/app/test-pmd/iofwd.c后编译testpmd应用,之后在同一目录$RTE_SDK/app/test-pmd/下可以找到下编译后的testpmd应用。

pktgen运行在主机中,testpmd运行在容器中,两个应用之间通过建立的socket文件以及vhost-user进行通信,相当于虚拟网卡。

3.2 启动容器

通过Dockerfile创建一个DPDK的Docker镜像。

首先创建一个Dockerfile。

使用创建的Dockerfile建立Docker镜像.

运行容器

这里运行一个使用刚刚建立的dpdk镜像的容器。

3.3 启动应用

在容器中运行testpmd

在主机上运行pktgen
注意,pktgen一定要在与pktgen.lua文件同一目录下运行,即pktgen的文件夹中运行。

3.4 简单实验

在pktgen中设置速率为10%,更具体的速率设置可以通过tx_cycles设置。端口0共发送100个包,端口1发送200个。

在testpmd中查看端口状态,可以看到端口0接收100个包发出200个,与预期一致:

四、简单分析iofwd.c代码

因为这段代码非常简单,这里只介绍几个关键点帮助快速理解。由于DPDK库非常庞大复杂,阅读源码时推荐通过ctags、YCM等类似工具帮助阅读。

RTE_TEST_PMD_RECORD_CORE_CYCLES

      相关的内容用于统计每条转发流处理消耗的时钟周期,

rte_rdtsc()

      函数用于通过RDTSC或VMWARE TSC map读取时钟周期信息。与

RTE_TEST_PMD_RECORD_BURST_STATS

      相关的内容用于统计每条转发流接收和发送时burst(处理时的一组数据包)的情况。这里的接收端口和发送端口等参数已经在

config.c

      文件中设置过,更详细的过程可以看到其中的

simple_fwd_config_setup()

      函数以及其他模式下的相关设置函数。

rte_eth_rx_burst()

      函数用于从指定端口和队列中读取数据包。会一次读入很多个数据包(取决于端口排队情况),称为burst。

rte_eth_rx_burst()

      这个API在同步和异步包处理环境下都针对burst做了非常多的优化,性能非常高。但是,这个函数为了降低额外开销不提供任何错误提示。所以当上层应用多次尝试都接收到0返回值时应该检查设备运行状态。

rte_eth_tx_burst()

      函数用于从指定端口和队列处发送数据包。同接收一样,会一次把一个burst的数据放入到发送队列。同时,

rte_eth_tx_burst()

      这个函数会透明地释放掉先前发送的数据包占用的内存。

likely()

unlikely()

      函数是常用的优化方式,是GCC內建函数

__builtin_expect()

      的宏。通过提高条件分支预测准确性提高cache命中率从而提升程序性能。由于现代CPU都通过预读机制提升性能,而由于分支造成的转跳会导致pipeline flushing,这会降低程序性能。通过为编译器提供分支预测信息可以让编译结果中可能性更大的代码紧跟分支判断部分减少转跳。从理解代码逻辑的角度上这两个函数可以完全忽略。更详细的内容可以参考这篇

官方解释

      代码的最后定义的

io_fwd_engine

      相当于注册了一种新的转发引擎,可以在

testpmd.h

      文件中找到结构体定义,在

testpmd.c

      中看到对转发引擎的选择和使用。在理解了iofwd中的关键部分之后,就可以在其基础上参考DPDK的

API文档

    进行基础性的实验。当然这只是一个最简单的进行DPDK实验的方式。一个更加全面、有代表性的DPDK示例应用可以参考examples目录下的l3fwd。


  • 本站原创文章仅代表作者观点,不代表SDNLAB立场。所有原创内容版权均属SDNLAB,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用,转载须注明来自 SDNLAB并附上本文链接。 本站中所有编译类文章仅用于学习和交流目的,编译工作遵照 CC 协议,如果有侵犯到您权益的地方,请及时联系我们。
  • 本文链接https://www.sdnlab.com/20112.html
分享到:
相关文章
条评论

登录后才可以评论

SDNLAB君 发表于17-11-10
1