重庆城乡规划和建设局网站,上海优化关键词的公司,宝安区建设局网站,wordpress 分页列表PORT HOTPLUG FRAMEWORK
端口热插拔框架为DPDK应用程序提供在运行时附加和分离端口的能力。由于该框架依赖于PMD实现#xff0c;PMD无法处理的端口超出了该框架的范围。此外#xff0c;在从DPDK应用程序分离端口后#xff0c;该框架不提供从系统中移除设备的方法。对于由物…PORT HOTPLUG FRAMEWORK
端口热插拔框架为DPDK应用程序提供在运行时附加和分离端口的能力。由于该框架依赖于PMD实现PMD无法处理的端口超出了该框架的范围。此外在从DPDK应用程序分离端口后该框架不提供从系统中移除设备的方法。对于由物理网卡支持的端口内核需要支持PCI热插拔功能。
26.1 概述
端口热插拔框架的基本要求包括
使用端口热插拔框架的DPDK应用程序必须管理自己的端口。端口热插拔框架的实现允许DPDK应用程序管理端口。例如当DPDK应用程序调用端口附加函数时将返回已附加的端口号。DPDK应用程序还可以通过端口号分离端口。附加或分离物理设备端口需要内核支持。要附加新的物理设备端口首先设备将在内核中被用户空间驱动I/O框架识别。然后DPDK应用程序可以调用端口热插拔函数来附加端口。对于分离步骤相反。分离之前端口必须停止和关闭。DPDK应用程序在分离端口之前必须调用 rte_eth_dev_stop() 和 rte_eth_dev_close() API。这些函数将启动PMD的最终化序列。该框架不影响传统的DPDK应用程序行为。如果未调用端口热插拔函数则所有传统的DPDK应用程序仍可在不进行修改的情况下正常工作。
26.2 端口热插拔API概述
附加端口 rte_eth_dev_attach() API将端口附加到DPDK应用程序并返回已附加的端口号。在调用API之前设备应该被用户空间驱动I/O框架识别。该API接收类似“0000:01:00.0”这样的PCI地址或者类似“eth_pcap0,ifaceeth0”这样的虚拟设备名称。对于虚拟设备名称格式与DPDK的一般“–vdev”选项相同。分离端口 rte_eth_dev_detach() API从DPDK应用程序分离端口并返回分离设备的PCI地址或设备的虚拟设备名称。
26.3 参考
“testpmd”支持端口热插拔框架。
26.4 限制
端口热插拔API不具备线程安全性。该框架仅在Linux下可用不支持BSD。要分离端口端口应由igb_uio管理的设备支持。不支持VFIO。并非所有PMD都支持分离功能。要了解PMD是否支持分离请搜索PMD实现中的“RTE_PCI_DRV_DETACHABLE”标志。如果PMD中定义了该标志则支持分离功能。
SOURCE ORGANIZATION
此部分描述了DPDK框架中源代码的组织结构。
27.1 Makefiles 和 Config
注意在下面的描述中RTE_SDK 是一个环境变量指向解压缩tar包的基本目录。请参阅构建系统提供的有用变量的描述了解其他变量的说明。 DPDK库和应用程序提供的 Makefiles 位于 $(RTE_SDK)/mk。 Config 模板位于 $(RTE_SDK)/config。这些模板描述了每个目标启用的选项。配置文件还包含许多DPDK库的可启用和禁用项包括调试选项。用户应查看配置文件并熟悉其中的选项。配置文件还用于创建一个头文件该头文件将位于新的构建目录中。
27.2 Libraries
库位于 $(RTE_SDK)/lib 的子目录中。按照惯例我们将提供应用程序接口API的代码称为库。通常它会生成一个存档文件.a但内核模块也应该放在同一个目录下。 lib 目录包含
lib
-- librte_cmdline # command line interface helper
-- librte_distributor # packet distributor
-- librte_eal # environment abstraction layer
-- librte_ether # generic interface to poll mode driver
-- librte_hash # hash library
-- librte_ip_frag # IP fragmentation library
-- librte_ivshmem # QEMU IVSHMEM library
-- librte_kni # kernel NIC interface
-- librte_kvargs # argument parsing library
-- librte_lpm # longest prefix match library
-- librte_malloc # malloc-like functions
-- librte_mbuf # packet and control mbuf manipulation library
-- librte_mempool # memory pool manager (fixedsized objects)
-- librte_meter # QoS metering library
-- librte_net # various IP-related headers
-- librte_pmd_bond # bonding poll mode driver
-- librte_pmd_e1000 # 1GbE poll mode drivers (igb and em)
-- librte_pmd_fm10k # Host interface PMD driver for FM10000 Series
-- librte_pmd_ixgbe # 10GbE poll mode driver
-- librte_pmd_i40e # 40GbE poll mode driver
-- librte_pmd_mlx4 # Mellanox ConnectX-3 poll mode driver
-- librte_pmd_pcap # PCAP poll mode driver
-- librte_pmd_ring # ring poll mode driver
-- librte_pmd_virtio # virtio poll mode driver
-- librte_pmd_vmxnet3 # VMXNET3 poll mode driver
-- librte_pmd_xenvirt # Xen virtio poll mode driver
-- librte_power # power management library
-- librte_ring # software rings (act as lockless FIFOs)
-- librte_sched # QoS scheduler and dropper library
-- librte_timer # timer library27.3 Applications
应用程序是包含 main() 函数的源代码。它们位于 $(RTE_SDK)/app 和 $(RTE_SDK)/examples 目录中。 app 目录包含用于测试DPDK的示例应用程序自动测试。 examples 目录包含展示如何使用库的示例应用程序。
app
-- chkincs # test prog to check include depends
-- test # autotests, to validate DPDK features
-- test-pmd # test and bench poll mode driver examples
examples
-- cmdline # Example of using cmdline library
-- dpdk_qat # Example showing integration with Intel QuickAssist
-- exception_path # Sending packets to and from Linux Ethernet device (TAP)
-- helloworld # Helloworld basic example
-- ip_reassembly # Example showing IP Reassembly
-- ip_fragmentation # Example showing IPv4 Fragmentation
-- ipv4_multicast # Example showing IPv4 Multicast
-- kni # Kernel NIC Interface example
-- l2fwd # L2 Forwarding example with and without SR-IOV
-- l3fwd # L3 Forwarding example
-- l3fwd-power # L3 Forwarding example with power management
-- l3fwd-vf # L3 Forwarding example with SR-IOV
-- link_status_interrupt # Link status change interrupt example
-- load_balancer # Load balancing across multiple cores/sockets
-- multi_process # Example applications with multiple DPDK processes
-- qos_meter # QoS metering example
-- qos_sched # QoS scheduler and dropper example
-- timer # Example of using librte_timer library
-- vmdq_dcb # Intel 82599 Ethernet Controller VMDQ and DCB receiving
-- vmdq # Example of VMDQ receiving
-- vhost # Example of userspace vhost and switch注意实际的 examples 目录可能包含除上述示例之外的其他示例应用程序。请查看最新的DPDK源文件以了解详情。
DEVELOPMENT KIT BUILD SYSTEM
DPDK需要一个构建系统来进行编译等活动。本部分描述了DPDK框架中使用的约束和机制。
该框架有两个用例 • 编译DPDK库和示例应用程序该框架生成特定的二进制库、包含文件和示例应用程序。 • 使用已安装的二进制DPDK编译外部应用程序或库。
28.1 构建开发套件二进制
以下提供了如何构建DPDK二进制的详细信息。
28.1.1 构建目录概念
在安装后会创建一个构建目录结构。每个构建目录包含包含文件、库和应用程序
~/DPDK$ ls
app MAINTAINERS
config Makefile
COPYRIGHT mk
doc scripts
examples lib
tools x86_64-native-linuxapp-gcc
x86_64-native-linuxapp-icc i686-native-linuxapp-gcc
i686-native-linuxapp-icc
...
~/DEV/DPDK$ ls i686-native-linuxapp-gcc
app build hostapp include kmod lib Makefile
~/DEV/DPDK$ ls i686-native-linuxapp-gcc/app/
cmdline_test dump_cfg test testpmd
cmdline_test.map dump_cfg.map test.map
testpmd.map
~/DEV/DPDK$ ls i686-native-linuxapp-gcc/lib/
libethdev.a librte_hash.a librte_mbuf.a librte_pmd_ixgbe.a
librte_cmdline.a librte_lpm.a librte_mempool.a librte_ring.a
librte_eal.a librte_malloc.a librte_pmd_e1000.a librte_timer.a
~/DEV/DPDK$ ls i686-native-linuxapp-gcc/include/
arch rte_cpuflags.h rte_memcpy.h
cmdline_cirbuf.h rte_cycles.h rte_memory.h
cmdline.h rte_debug.h rte_mempool.h
cmdline_parse_etheraddr.h rte_eal.h rte_memzone.h
cmdline_parse.h rte_errno.h rte_pci_dev_ids.h
cmdline_parse_ipaddr.h rte_ethdev.h rte_pci.h
cmdline_parse_num.h rte_ether.h rte_per_lcore.h
cmdline_parse_portlist.h rte_fbk_hash.h rte_prefetch.h
cmdline_parse_string.h rte_hash_crc.h rte_random.h
cmdline_rdline.h rte_hash.h rte_ring.h
cmdline_socket.h rte_interrupts.h rte_rwlock.h
cmdline_vt100.h rte_ip.h rte_sctp.h
exec-env rte_jhash.h rte_spinlock.h
rte_alarm.h rte_launch.h rte_string_fns.h
rte_atomic.h rte_lcore.h rte_tailq.h
rte_branch_prediction.h rte_log.h rte_tcp.h
rte_byteorder.h rte_lpm.h rte_timer.h
rte_common.h rte_malloc.h rte_udp.h
rte_config.h rte_mbuf.h构建目录特定于配置包括架构 执行环境 工具链。可以有多个构建目录共享相同的源文件但具有不同的配置。 例如要使用默认配置模板config/defconfig_x86_64-linuxapp创建一个名为my_sdk_build_dir的新构建目录可以执行以下操作
cd ${RTE_SDK}
make config Tx86_64-native-linuxapp-gcc Omy_sdk_build_dir这将创建一个新的 my_sdk_build_dir 目录。 之后我们可以通过执行以下操作进行编译
cd my_sdk_build_dir
make这相当于
make Omy_sdk_build_dirmy_sdk_build_dir 的内容是
28.2 编译外部应用程序
由于DPDK本质上是一个开发套件最终用户的首要目标将是使用此SDK创建应用程序。要编译一个应用程序用户必须设置 RTE_SDK 和 RTE_TARGET 环境变量。
export RTE_SDK/opt/DPDK
export RTE_TARGETx86_64-native-linuxapp-gcc
cd /path/to/my_app对于新应用程序用户必须创建自己的Makefile其中包含一些.mk文件如 ${RTE_SDK}/mk/rte.vars.mk 和 ${RTE_SDK}/mk/rte.app.mk。这在构建您自己的应用程序中有描述。 根据在Makefile中定义的或作为环境变量定义的选择的目标架构、机器、执行环境、工具链应用程序和库将使用适当的.h文件进行编译并链接适当的.a文件。这些文件位于 ${RTE_SDK}/arch-machine-execenv-toolchain 中内部由 ${RTE_BIN_SDK} 引用。 要编译他们的应用程序用户只需调用 make。编译结果将位于 /path/to/my_app/build 目录中。 示例应用程序位于 examples 目录中。
28.3 Makefile描述
28.3.1 DPDK Makefile 的通用规则
在DPDK中Makefiles 总是遵循相同的方案
在开头包含 $(RTE_SDK)/mk/rte.vars.mk。定义 RTE 构建系统的特定变量。包含特定的 $(RTE_SDK)/mk/rte.XYZ.mk其中 XYZ 可以是 app、lib、extapp、extlib、obj、gnuconfigure 等取决于您想构建的对象类型。请参见下面的Makefile类型。包含用户定义的规则和变量。
以下是一个非常简单的外部应用程序Makefile示例
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.mk28.3.2 Makefile 类型
根据用户Makefile末尾包含的 .mk 文件不同Makefile 将具有不同的作用。请注意不可能在同一个Makefile中构建库和应用程序。对此用户必须创建两个单独的Makefile可能位于两个不同的目录中。 无论如何用户Makefile中必须尽快包含 rte.vars.mk 文件。
应用程序 这些Makefiles生成二进制应用程序。 • rte.app.mk在开发套件框架中的应用程序 • rte.extapp.mk外部应用程序 • rte.hostapp.mk开发套件框架中的主机应用程序
库 生成 .a 库。 • rte.lib.mk开发套件框架中的库 • rte.extlib.mk外部库 • rte.hostlib.mk开发套件框架中的主机库
安装 • rte.install.mk不构建任何内容仅用于在安装目录中创建链接或复制文件。这对包含开发套件框架中的文件很有用。
内核模块 • rte.module.mk在开发套件框架中构建内核模块。
对象 • rte.obj.mk对象聚合将多个 .o 合并为一个在开发套件框架中。 • rte.extobj.mk对象聚合将多个 .o 合并为一个在开发套件框架外部。
其他 • rte.doc.mk开发套件框架中的文档 • rte.gnuconfigure.mk构建基于 configure 的应用程序。 • rte.subdir.mk在开发套件框架中构建多个目录。
28.3.3 构建系统提供的有用变量
• RTE_SDKDPDK源文件的绝对路径。在编译开发套件时该变量由框架自动设置。如果编译外部应用程序则必须由用户定义为环境变量。 • RTE_SRCDIR源文件根目录的路径。在编译开发套件时RTE_SRCDIR RTE_SDK。在编译外部应用程序时该变量指向外部应用程序源文件的根目录。 • RTE_OUTPUT写入输出文件的路径。通常是 $(RTE_SRCDIR)/build但可以通过 make 命令行中的 O 选项进行覆盖。 • RTE_TARGET标识正在构建的目标的字符串。格式为架构-机器-执行环境-工具链。在编译SDK时目标由配置文件.config的构建系统推导出来。在构建外部应用程序时用户必须在Makefile中或作为环境变量指定。 • RTE_SDK_BIN引用 ( R T E S D K ) / (RTE_SDK)/ (RTESDK)/(RTE_TARGET)。 • RTE_ARCH定义架构i686、x86_64。与 CONFIG_RTE_ARCH 相同但字符串周围没有双引号。 • RTE_MACHINE定义机器。与 CONFIG_RTE_MACHINE 相同但字符串周围没有双引号。 • RTE_TOOLCHAIN定义工具链gcc、icc。与 CONFIG_RTE_TOOLCHAIN 相同但字符串周围没有双引号。 • RTE_EXEC_ENV定义执行环境linuxapp。与 CONFIG_RTE_EXEC_ENV 相同但字符串周围没有双引号。 • RTE_KERNELDIR该变量包含用于编译内核模块的内核源文件的绝对路径。内核头文件必须与将在目标机器运行应用程序的机器上使用的头文件相同。默认情况下该变量设置为 /lib/modules/$(shell uname -r)/build这在目标机器也是构建机器时是正确的。
28.3.4 只能在Makefile中设置/覆盖的变量
VPATH: 构建系统将搜索源文件的路径列表。默认情况下RTE_SRCDIR 将包含在 VPATH 中。CFLAGS: 用于C编译的标志。用户应该使用 来追加此变量中的数据。LDFLAGS: 用于链接的标志。用户应该使用 来追加此变量中的数据。ASFLAGS: 用于汇编的标志。用户应该使用 来追加此变量中的数据。CPPFLAGS: 用于给C预处理器传递标志仅在汇编 .S 文件时有用。用户应该使用 来追加此变量中的数据。LDLIBS: 在应用程序中要链接的库列表例如-L /path/to/libfoo -lfoo。用户应该使用 来追加此变量中的数据。SRC-y: 应用程序、库或对象Makefile中源文件的列表.c、.S 或 .o如果源文件是二进制文件。这些源文件必须从 VPATH 中获取。INSTALL-y-$(INSTPATH): 要安装到 $(INSTPATH) 的文件列表。这些文件必须从 VPATH 中获取并将被复制到 ( R T E O U T P U T ) / (RTE_OUTPUT)/ (RTEOUTPUT)/(INSTPATH)。几乎可以在任何 RTE Makefile 中使用。SYMLINK-y-$(INSTPATH): 要安装到 $(INSTPATH) 的文件列表。这些文件必须从 VPATH 中获取并将以符号链接的方式链接到 ( R T E O U T P U T ) / (RTE_OUTPUT)/ (RTEOUTPUT)/(INSTPATH)。几乎可以在任何 DPDK Makefile 中使用。PREBUILD: 在主要构建之前执行的先决条件操作的列表。用户应该使用 来追加此变量中的数据。POSTBUILD: 在主要构建之后执行的操作的列表。用户应该使用 来追加此变量中的数据。PREINSTALL: 在安装之前执行的先决条件操作的列表。用户应该使用 来追加此变量中的数据。POSTINSTALL: 在安装之后执行的操作的列表。用户应该使用 来追加此变量中的数据。PRECLEAN: 在清理之前执行的先决条件操作的列表。用户应该使用 来追加此变量中的数据。POSTCLEAN: 在清理之后执行的操作的列表。用户应该使用 来追加此变量中的数据。DEPDIR-y: 仅在开发套件框架中使用指定当前目录的构建是否依赖于另一个目录的构建。这是为了正确支持并行构建。
28.3.5 只能由用户在命令行中设置/覆盖的变量
一些变量可用于配置构建系统的行为。这些变量在“Development Kit Root Makefile Help”和“External Application/Library Makefile Help”中有文档记录。
WERROR_CFLAGS: 默认情况下此变量设置为取决于编译器的特定值。鼓励用户按照以下方式使用此变量CFLAGS $(WERROR_CFLAGS)这避免了根据编译器icc 或 gcc使用不同情况。此外此变量可以从命令行覆盖以便在测试目的时绕过标志。
28.3.6 可在Makefile或命令行中设置/覆盖的变量
CFLAGS_my_file.o: 用于 my_file.c 的 C 编译的特定标志。LDFLAGS_my_app: 在链接 my_app 时添加的特定标志。NO_AUTOLIBS: 如果设置框架提供的库将不会自动包含在 LDLIBS 变量中。EXTRA_CFLAGS: 在编译时将此变量的内容追加到 CFLAGS 之后。EXTRA_LDFLAGS: 在链接时将此变量的内容追加到 LDFLAGS 之后。EXTRA_ASFLAGS: 在汇编时将此变量的内容追加到 ASFLAGS 之后。EXTRA_CPPFLAGS: 在汇编文件上使用 C 预处理器时将此变量的内容追加到 CPPFLAGS 之后。
29.1 配置目标
配置目标需要指定目标的名称使用 Tmytarget 参数是必需的。可用的目标列表位于 $(RTE_SDK)/config去掉 defconfig_ 前缀。 配置目标还支持指定输出目录的名称使用 Omybuilddir。这是一个可选参数默认输出目录是 build。
Config 创建一个构建目录并从模板生成配置。在新的构建目录中也创建一个 Makefile。 示例make config Omybuild Tx86_64-native-linuxapp-gcc29.2 构建目标
构建目标支持指定输出目录的名称使用 Omybuilddir。默认输出目录是 build。 all, build 或仅 make 在之前由 make config 创建的输出目录中构建 DPDK。 示例 make Omybuildclean 清除使用 make build 创建的所有对象。 示例 make clean Omybuild%_sub 仅构建一个子目录而不管理其他目录的依赖关系。 示例 make lib/librte_eal_sub Omybuild%_clean 仅清除一个子目录。 示例 make lib/librte_eal_clean Omybuild29.3 安装目标 Install 构建 DPDK 二进制文件。实际上这会将每个支持的目标构建到单独的目录中。每个目录的名称是目标的名称。可以选择性地使用 Tmytarget 指定要安装的目标名称。目标名称可以包含通配符 * 字符。可用的目标列表位于 $(RTE_SDK)/config删除 defconfig_ 前缀。 示例 make install Tx86_64-*Uninstall 移除已安装的目标目录。
29.4 测试目标 test 启动指定使用 Omybuilddir 的构建目录的自动测试。这是可选的默认输出目录是 build。 示例 make test Omybuildtestall 启动所有已安装目标目录在 make install 之后的自动测试。可以选择性地使用 Tmytarget 指定要测试的目标名称。目标名称可以包含通配符 * 字符。可用的目标列表位于 $(RTE_SDK)/config删除 defconfig_ 前缀。 示例 make testall, make testall Tx86_64-*29.5 文档目标
doc 生成 Doxygen 文档API、html 和 pdf。doc-api-html 生成 html 格式的 Doxygen API 文档。doc-guides-html 生成 html 格式的指南文档。doc-guides-pdf 生成 pdf 格式的指南文档。
29.6 依赖目标 depdirs 此目标在 make config 时隐式调用。通常情况下除非在 Makefiles 中更新了 DEPDIRS-y 变量否则无需用户调用它。它将生成文件 $(RTE_OUTPUT)/.depdirs。 示例 make depdirs Omybuilddepgraph 此命令生成依赖关系的 dot 图。它可以用于调试循环依赖问题或者只是了解依赖关系。 示例 make depgraph Omybuild /tmp/graph.dot dotty /tmp/graph.dot29.7 其他目标
help 显示此帮助信息。
29.8 其他有用的命令行变量
以下变量可以在命令行上指定
V 启用详细构建显示完整的编译命令行和一些中间命令。D 启用依赖项调试。这提供了一些有关为何构建或不构建目标的有用信息。EXTRA_CFLAGS, EXTRA_LDFLAGS, EXTRA_ASFLAGS, EXTRA_CPPFLAGS 追加特定的编译、链接或汇编标志。CROSS 指定一个交叉工具链头部它将作为前缀用于所有 gcc/binutils 应用程序。这仅在使用 gcc 时有效。
29.9 在构建目录中使用 Make
在 SDK 根目录 $(RTE_SDK) 中调用了上述所有目标。可以在构建目录内部运行相同的 Makefile 目标。例如以下命令
cd $(RTE_SDK)
make config Omybuild Tx86_64-native-linuxapp-gcc
make Omybuild等同于
cd $(RTE_SDK)
make config Omybuild Tx86_64-native-linuxapp-gcc
cd mybuild
# 现在不需要再指定 O now
make
29.10 编译调试版本
要在 DPDK 和示例应用程序中包含调试信息并将优化级别设置为 0 进行编译应在编译之前设置 EXTRA_CFLAGS 环境变量如下所示
export EXTRA_CFLAGS-O0 -g然后可以以通常的方式编译 DPDK 以及任何用户或示例应用程序。例如
make install Tx86_64-native-linuxapp-gcc
make -C examples/theapp
扩展 DPDK
本章描述了开发人员如何扩展 DPDK 以提供新的库、新的目标或支持新的目标。
30.1 示例添加一个新库 libfoo
要向 DPDK 中添加新库请按照以下步骤进行
添加新的配置选项 for f in config/*; do \echo CONFIG_RTE_LIBFOOy $f; done1、创建带有源代码的新目录
mkdir ${RTE_SDK}/lib/libfoo
touch ${RTE_SDK}/lib/libfoo/foo.c
touch ${RTE_SDK}/lib/libfoo/foo.h
2、在 libfoo 中添加 foo() 函数
void foo(void)
{
}
在 foo.h 中声明
extern void foo(void);
3、更新 lib/Makefile
vi ${RTE_SDK}/lib/Makefile
添加
DIRS-$(CONFIG_RTE_LIBFOO) libfoo
4、为此库创建新的 Makefile从 mempool Makefile 派生
cp ${RTE_SDK}/lib/librte_mempool/Makefile ${RTE_SDK}/lib/libfoo/
vi ${RTE_SDK}/lib/libfoo/Makefile
替换
librte_mempool - libfoo
rte_mempool - foo
5、更新 mk/DPDK.app.mk
如果启用了该选项则在 LDLIBS 变量中添加 -lfoo。这将在链接 DPDK 应用程序时自动包含此标志。 6、使用新库构建 DPDK
cd ${RTE_SDK}
make config Tx86_64-native-linuxapp-gcc
make
7、检查库的安装情况
ls build/lib
ls build/include
30.1.1 示例在测试应用程序中使用 libfoo 测试应用程序用于验证 DPDK 的所有功能。一旦您添加了一个库就应该在测试应用程序中添加一个新的测试用例。
应添加一个新的 test_foo.c 文件其中包括 foo.h 并从 test_foo() 中调用 foo() 函数。当测试通过时test_foo() 函数应返回 0。Makefile、test.h 和 commands.c 也必须进行更新以处理新的测试用例。测试报告生成autotest.py 是一个用于生成测试报告的脚本位于 ${RTE_SDK}/doc/rst/test_report/autotests 目录中。还需要更新此脚本。如果 libfoo 属于新的测试系列则必须更新 ${RTE_SDK}/doc/rst/test_report/test_report.rst 中的链接。使用更新后的测试应用程序构建 DPDK以下仅显示特定目标
cd ${RTE_SDK}
make config Tx86_64-native-linuxapp-gcc
make
构建你自己的应用程序
31.1 在开发工具包目录中编译示例应用程序
当编译示例应用程序例如hello world时必须导出以下变量RTE_SDK 和 RTE_TARGET。
~/DPDK$ cd examples/helloworld/
~/DPDK/examples/helloworld$ export RTE_SDK/home/user/DPDK
~/DPDK/examples/helloworld$ export RTE_TARGETx86_64-native-linuxapp-gcc
~/DPDK/examples/helloworld$ make
CC main.o
LD helloworld
INSTALL-APP helloworld
INSTALL-MAP helloworld.map
默认情况下二进制文件生成在 build 目录下
~/DPDK/examples/helloworld$ ls build/app
helloworld helloworld.map
31.2 在开发工具包之外构建你自己的应用程序
将示例应用程序Hello World复制到一个新目录作为开发的起点
~$ cp -r DPDK/examples/helloworld my_rte_app
~$ cd my_rte_app/
~/my_rte_app$ export RTE_SDK/home/user/DPDK
~/my_rte_app$ export RTE_TARGETx86_64-native-linuxapp-gcc
~/my_rte_app$ make
CC main.o
LD helloworld
INSTALL-APP helloworld
INSTALL-MAP helloworld.map
自定义 Makefile
31.3.1 应用程序 Makefile
提供的 Hello World 示例应用程序的默认 Makefile 是一个很好的起点。 它包含以下内容
在开头包含了 $(RTE_SDK)/mk/rte.vars.mk 在结尾包含了 $(RTE_SDK)/mk/rte.extapp.mk 用户需要定义一些变量 APP包含应用程序的名称。 SRCS-y源文件列表.c.S。
31.3.2 库 Makefile
同样也可以以相同的方式构建一个库
在开头包含 $(RTE_SDK)/mk/rte.vars.mk。 在结尾包含 $(RTE_SDK)/mk/rte.extlib.mk。 唯一的区别是 APP 应该替换为 LIB其中包含库的名称。例如libfoo.a。
31.3.3 自定义 Makefile 操作
一些变量可以被定义来自定义 Makefile 操作。以下是最常见的变量。有关详细信息请参阅“开发工具包构建系统”章节中的“Makefile 描述”部分。
VPATH构建系统搜索源文件的路径列表。默认情况下RTE_SRCDIR 将包含在 VPATH 中。CFLAGS_my_file.o对 my_file.c 进行 C 编译的特定标志。CFLAGS用于 C 编译的标志。LDFLAGS用于链接的标志。CPPFLAGS用于向 C 预处理器提供标志的标志仅在汇编 .S 文件时有用。LDLIBS要链接的库列表例如-L /path/to/libfoo - lfoo。NO_AUTOLIBS如果设置则框架提供的库不会自动包含在 LDLIBS 变量中。 请根据需要自行添加翻译或额外说明。
外部应用程序/库的 Makefile 帮助
外部应用程序或库应包含来自 RTE_SDK 中的特定 Makefile位于 mk 目录中。这些 Makefile 是
${RTE_SDK}/mk/rte.extapp.mk构建应用程序${RTE_SDK}/mk/rte.extlib.mk构建静态库${RTE_SDK}/mk/rte.extobj.mk构建对象.o
32.1 先决条件
必须定义以下变量
${RTE_SDK}指向 DPDK 的根目录。${RTE_TARGET}引用用于编译的目标例如x86_64-native-linuxapp-gcc。
32.2 构建目标
构建目标支持指定输出目录的名称使用 Omybuilddir。这是可选的默认输出目录为 build。
all“nothing”仅表示 make 在指定的输出目录中构建应用程序或库。 示例
make Omybuildclean 清理使用 make build 创建的所有对象。 示例
make clean Omybuild
32.3 帮助目标
help 显示此帮助信息。
32.4 其他有用的命令行变量
以下变量可以在命令行指定
S 指定源文件所在的目录。默认情况下它是当前目录。M 指定一旦创建输出目录后要调用的 Makefile。默认情况下它使用 $(S)/Makefile。V 启用详细构建显示完整的编译命令行和一些中间命令。D 启用依赖关系调试。这提供了一些关于为什么需要重建目标的有用信息。 EXTRA_CFLAGS、EXTRA_LDFLAGS、EXTRA_ASFLAGS、EXTRA_CPPFLAGS 追加特定的编译、链接或汇编标志。CROSS 指定一个用于所有 gcc/binutils 应用程序的交叉工具链标头。这仅在使用 gcc 时有效。
32.5 从其他目录运行 Make
可以通过指定输出目录和源目录来从另一个目录运行 Makefile。例如
export RTE_SDK/path/to/DPDK
export RTE_TARGETx86_64-native-linuxapp-icc
make -f /path/to/my_app/Makefile S/path/to/my_app O/path/to/build_dir
33.1 引言
以下部分描述了 DPDK 中使用的优化以及新应用程序应考虑的优化方法。
它们还强调了在使用 DPDK 开发应用程序时应该和不应该使用的对性能影响较大的编码技术。
最后它们介绍了使用英特尔的性能分析器进行应用程序分析以优化软件的方法。
编写高效代码
本章提供了一些使用 DPDK 开发高效代码的技巧。欲获取更多通用信息请参考英特尔® 64 和 IA-32 架构优化参考手册这是编写高效代码的宝贵参考资料。
34.1 内存
本节描述了在 DPDK 环境中开发应用程序时的一些关键内存注意事项。
34.1.1 内存拷贝在数据平面不要使用libc
在 DPDK 中通过 Linux* 应用环境可以使用许多 libc 函数这可以简化应用程序的移植和配置平面的开发。然而许多这些函数并非为性能而设计。像 memcpy() 或 strcpy() 这样的函数不应该在数据平面中使用。对于拷贝小结构体最好使用编译器可以优化的更简单的技术。建议参考英特尔出版的 VTune™ Performance Analyzer Essentials 出版物获取建议。
对于频繁调用的特定函数最好提供一个自制的经过优化的函数应该声明为 static inline。
DPDK API 提供了一个经过优化的 rte_memcpy() 函数。
34.1.2 内存分配
libc 的其他函数如 malloc()提供了一种灵活的方式来分配和释放内存。在某些情况下使用动态分配是必要的但不建议在数据平面中使用类似 malloc 的函数因为管理碎片化的堆可能成本高昂而且分配器可能没有针对并行分配进行优化。
如果确实需要在数据平面中进行动态分配最好使用固定大小对象的内存池。这个 API 由 librte_mempool 提供。这个数据结构提供了一些增加性能的服务如对象的内存对齐、无锁访问对象、NUMA 感知、批量获取/放置和每个 lcore 的缓存。rte_malloc() 函数使用了与内存池类似的概念。
34.1.3 并发访问相同的内存区域
多个 lcore 对同一内存区域的读写访问操作可能会产生大量数据缓存未命中这是非常昂贵的。通常可以使用每个 lcore 变量例如统计数据。针对此问题至少有两种解决方案
使用 RTE_PER_LCORE 变量。请注意在这种情况下lcore X 上的数据对于 lcore Y 不可用。使用结构体表每个 lcore 一个。在这种情况下每个结构体必须缓存对齐。
如果同一缓存行中没有读写变量那么只读变量可以在多个 lcore 之间共享而不会造成性能损失。
34.1.4 NUMA
在 NUMA 系统上最好访问本地内存因为远程内存访问速度较慢。在 DPDK 中memzone、ring、rte_malloc 和 mempool API 提供了在特定套接字上创建池的方法。
有时复制数据以优化速度可能是个好主意。对于经常访问的只读变量把它们仅保留在一个套接字中应该不是问题因为数据将存在于缓存中。
34.1.5 跨内存通道分配
现代内存控制器具有多个内存通道可以并行加载或存储数据。根据内存控制器及其配置内存分布在通道上的方式各不相同。每个通道都有带宽限制这意味着如果所有内存访问操作都只在第一个通道上进行可能会存在潜在的瓶颈。
默认情况下内存池库将对象的地址分布在内存通道之间。
34.2 lcore 之间的通信
为了在 lcore 之间提供基于消息的通信建议使用 DPDK ring API它提供了无锁环实现。
这个环支持批量和突发访问意味着可以使用一个昂贵的原子操作从环中读取多个元素参见第 5 章“环库”。使用批量访问操作可以极大地提高性能。
出队消息的代码算法可能类似于以下内容
#define MAX_BULK 32
while (1) {/* Process as many elements as can be dequeued. */count rte_ring_dequeue_burst(ring, obj_table, MAX_BULK);if (unlikely(count 0))continue;my_process_bulk(obj_table, count);
}34.3 PMD 驱动程序
DPDK Poll Mode DriverPMD也能以批量/突发模式工作允许在发送或接收函数的每次调用中对一些代码进行因式分解。 避免部分写入。当 PCI 设备通过 DMA 写入系统内存时如果写操作是在完整的缓存行上而不是部分缓存行上成本就会较低。在 PMD 代码中已经采取了尽可能避免部分写入的措施。
34.3.1 降低数据包延迟
传统上吞吐量和延迟之间存在权衡。一个应用程序可以调整以实现高吞吐量但平均数据包的端到端延迟通常会增加。同样地该应用程序可以调整以实现平均较低的端到端延迟但代价是较低的吞吐量。 为了实现更高的吞吐量DPDK 试图通过批量处理每个数据包的成本来聚合。以 testpmd 应用程序为例可以在命令行上将批量大小设置为 16也是默认值。这允许应用程序一次从 PMD 请求 16 个数据包。然后testpmd 应用程序立即尝试传输所有接收到的数据包即在本例中为所有 16 个数据包。 在网络端口的相应 TX 队列的尾指针更新之前数据包不会被传输。在调整以实现高吞吐量时这种行为是可取的因为对 RX 和 TX 队列的尾指针更新的成本可以分摊到 16 个数据包上有效地隐藏了相对较慢的 MMIO 写入 PCIe* 设备的成本。然而当调整以实现低延迟时这并不理想因为第一个接收到的数据包必须等待其他 15 个数据包也被接收。在所有 16 个数据包都被传输进行处理之前它无法被传输因为网卡在 TX 尾指针更新之前不知道传输数据包。 为了在系统负载较重的情况下始终实现低延迟应用程序开发人员应避免批量处理数据包。testpmd 应用程序可以从命令行配置为使用批量值为 1。这将允许一次处理一个数据包提供较低的延迟但代价是较低的吞吐量。
34.4 锁和原子操作
原子操作意味着在指令之前添加一个锁前缀导致处理器在执行下一条指令期间断言 LOCK# 信号。在多核环境中这对性能有很大影响。 通过避免在数据平面中使用锁机制可以提高性能。通常可以用其他解决方案代替比如每个 lcore 变量。此外某些锁定技术比其他技术更高效。例如读-拷贝-更新RCU算法经常可以取代简单的读写锁。
34.5 编码注意事项
34.5.1 内联函数
小函数可以在头文件中声明为 static inline。这避免了调用指令的成本以及相关的上下文保存。然而这种技术并不总是高效的它取决于许多因素包括编译器。
34.5.2 分支预测
英特尔® C/C 编译器icc/gcc 内置的辅助函数 likely() 和 unlikely() 允许开发人员指示代码分支可能被执行或不会被执行。例如
if (likely(x 1))
do_stuff();34.6 设置目标CPU类型
DPDK通过DPDK配置文件中的CONFIG_RTE_MACHINE选项支持针对CPU微架构的特定优化。优化程度取决于编译器针对特定微架构的优化能力因此尽可能使用最新的编译器版本是可取的。 如果编译器版本不支持特定的功能集例如Intel® AVX指令集则构建过程会优雅地降级到编译器支持的最新功能集。 由于构建和运行时目标可能不相同因此生成的二进制文件还包含一个在main()函数之前运行的平台检查检查当前机器是否适合运行该二进制文件。 除了编译器优化之外一组预处理器定义会自动添加到构建过程中不考虑编译器版本。这些定义对应于目标CPU应该能够支持的指令集。例如为任何支持SSE4.2的处理器编译的二进制文件将定义RTE_MACHINE_CPUFLAG_SSE4_2从而为不同平台启用编译时代码路径选择。
对应用程序进行性能分析
英特尔处理器提供性能计数器来监视事件。英特尔提供的一些工具可用于对应用程序进行性能分析和基准测试。参阅英特尔出版的《VTune性能分析器Essentials》获取更多信息。 对于DPDK应用程序这仅限于Linux*应用程序环境中进行。 通过事件计数器应该监控的主要情况包括
缓存未命中分支错误预测DTLB未命中长延迟指令和异常 有关应用程序分析的详细信息请参阅英特尔性能分析指南。
术语表
ACL: 访问控制列表 (Access Control List)API: 应用程序编程接口 (Application Programming Interface)ASLR: Linux* 内核地址空间布局随机化 (Linux* kernel Address-Space Layout Randomization)BSD: 伯克利软件发行版 (Berkeley Software Distribution)Clr: 清除 (Clear)CIDR: 无类域间路由 (Classless Inter-Domain Routing)Control Plane: 控制平面涉及数据包路由和提供起点或终点。Core: 核心如果处理器支持超线程则一个核心可能包含多个逻辑核心或线程。Core Components: DPDK 提供的一组库包括 eal、ring、mempool、mbuf、timers 等。CPU: 中央处理器 (Central Processing Unit)CRC: 循环冗余校验 (Cyclic Redundancy Check)ctrlmbuf: 携带控制数据的 mbuf。Data Plane: 与控制平面相对应在网络架构中用于转发数据包的层。这些层必须高度优化以获得良好性能。DIMM: 双列直插内存模块 (Dual In-line Memory Module)Doxygen: DPDK 中用于生成 API 参考的文档生成器。DPDK: 数据平面开发工具包 (Data Plane Development Kit)DRAM: 动态随机存取存储器 (Dynamic Random Access Memory)EAL: 环境抽象层 (Environment Abstraction Layer)为应用程序和库隐藏环境细节的通用接口。提供的服务包括开发工具包加载和启动、核心亲和/分配过程、系统内存分配/描述、PCI 总线访问、分区间通信。FIFO: 先进先出 (First In First Out)FPGA: 现场可编程门阵列 (Field Programmable Gate Array)GbE: 千兆以太网 (Gigabit Ethernet)HW: 硬件 (Hardware)HPET: 高精度事件定时器 (High Precision Event Timer)在 x86 平台上提供精确的时间参考。ID: 标识符 (Identifier)IOCTL: 输入/输出控制 (Input/Output Control)I/O: 输入/输出 (Input/Output)IP: 互联网协议 (Internet Protocol)IPv4: 互联网协议版本 4 (Internet Protocol version 4)IPv6: 互联网协议版本 6 (Internet Protocol version 6)lcore: 处理器的逻辑执行单元有时称为硬件线程。KNI: 内核网络接口 (Kernel Network Interface)L1: 第一层 (Layer 1)L2: 第二层 (Layer 2)L3: 第三层 (Layer 3)L4: 第四层 (Layer 4)LAN: 局域网 (Local Area Network)LPM: 最长前缀匹配 (Longest Prefix Match)master lcore: 执行主()函数并启动其他 lcore 的执行单元。mbuf: 一种用于内部携带消息主要是网络数据包的数据结构。名称来源于 BSD 栈。要了解数据包缓冲区或 mbuf 的概念请参阅《TCP/IP 详解》第 2 卷实现。MESI: 修改Modified、互斥Exclusive、共享Shared、失效InvalidCPU 缓存一致性协议MTU: 最大传输单元 (Maximum Transfer Unit)NIC: 网络接口卡 (Network Interface Card)OOO: 指令在 CPU 流水线内的乱序执行 (Out Of Order)NUMA: 非一致性内存访问 (Non-uniform Memory Access)PCI: 外设连接接口 (Peripheral Connect Interface)PHY: OSI 模型的物理层的缩写。pktmbuf: 携带网络数据包的 mbuf。PMD: 轮询模式驱动程序 (Poll Mode Driver)QoS: 服务质量 (Quality of Service)RCU: 读-拷贝-更新算法 (Read-Copy-Update)用于替代简单读写锁。Rd: 读取 (Read)RED: 随机早期检测 (Random Early Detection)RSS: 接收端缩放 (Receive Side Scaling)RTE: 运行时环境 (Run Time Environment)为快速数据包处理提供了一个快速简单的框架作为 Linux* 应用程序的轻量环境并使用轮询模式驱动程序PMD来提高速度。Rx: 接收 (Reception)Slave lcore: 不是主 lcore 的任何 lcore。Socket: 物理 CPU包含多个核心。SLA: 服务等级协议 (Service Level Agreement)srTCM: 单速三色标记 (Single Rate Three Color Marking)SRTD: 调度器往返延迟 (Scheduler Round Trip Delay)SW: 软件 (Software)Target: 在 DPDK 中目标是架构、机器、执行环境和工具链的组合。例如i686-native-linuxapp-gcc。TCP: 传输控制协议 (Transmission Control Protocol)TC: 流量类别 (Traffic Class)TLB: 转换查找缓冲区 (Translation Lookaside Buffer)TLS: 线程本地存储 (Thread Local Storage)trTCM: 双速三色标记 (Two Rate Three Color Marking)TSC: 时间戳计数器 (Time Stamp Counter)Tx: 传输 (Transmission)TUN/TAP: TUN 和 TAP 是虚拟网络内核设备。VLAN: 虚拟局域网 (Virtual Local Area Network)Wr: 写入 (Write)WRED: 加权随机早期检测 (Weighted Random Early Detection)WRR: 加权轮询 (Weighted Round Robin)
术语表续
Figures Fig. 2.1: 核心组件架构Fig. 3.1: 在Linux应用程序环境中的EAL初始化Fig. 4.1: malloc堆和malloc库中的malloc元素示例Fig. 5.1: 环形结构Fig. 5.2: 入队第一步Fig. 5.3: 入队第二步Fig. 5.4: 入队最后一步Fig. 5.5: 出队最后一步Fig. 5.6: 出队第二步Fig. 5.7: 出队最后一步Fig. 5.8: 多消费者入队第一步Fig. 5.9: 多消费者入队第二步Fig. 5.10: 多消费者入队第三步Fig. 5.11: 多消费者入队第四步Fig. 5.12: 多消费者入队最后一步Fig. 5.13: 32位模数索引 - 示例1Fig. 5.14: 32位模数索引 - 示例2Fig. 6.1: 两个通道和四排DIMM示例Fig. 6.2: 三个通道和两个双排DIMM示例Fig. 6.3: 存储器中的mempool及其关联的环
术语表续 Figures Fig. 7.1: 一个片段的mbufFig. 7.2: 三个片段的mbufFig. 18.1: DPDK多进程示例应用程序中的内存共享Fig. 19.1: DPDK KNI应用程序的组件Fig. 19.2: 通过mbufs进行的KNI数据包流Fig. 19.3: vHost-net架构概览Fig. 19.4: KNI流量流向Fig. 21.1: 具有QoS支持的复杂数据包处理流水线Fig. 21.2: 分层调度器块内部结构图Fig. 21.3: 每个端口的调度层次结构Fig. 21.4: 每个端口的内部数据结构Fig. 21.5: 分层调度器Enqueue操作的预取管道Fig. 21.6: 分层调度器Dequeue操作的管道预取状态机Fig. 21.7: DPDK Dropper的高级块图Fig. 21.8: Dropper的流程Fig. 21.9: Dropper中的数据流示例Fig. 21.10: 给定RED配置的数据包丢失概率Fig. 21.11: 使用因子1蓝曲线和因子2红曲线计算的初始丢包概率和实际丢包概率 Tables Table 21.1: 实施QoS的数据包处理流水线Table 21.2: 数据包处理流水线使用的基础结构块Table 21.3: 端口调度层次结构Table 21.4: 每个端口的调度器内部数据结构Table 21.5: 以太网帧开销字段Table 21.6: 令牌桶通用操作Table 21.7: 令牌桶通用参数Table 21.8: 令牌桶持久数据结构Table 21.9: 令牌桶操作Table 21.10: Subport/Pipe流量类别上限执行持久数据结构Table 21.11: Subport/Pipe流量类别上限执行操作Table 21.12: 加权轮询WRRTable 21.13: Subport流量类别过订阅Table 21.14: 每个流量类别上限执行周期开始时从子端口级别到成员Pipe的水印传播Table 21.15: 水印计算Table 21.16: RED配置参数Table 21.17: 替代方法的相对性能Table 21.18: 对应于RED配置文件的RED配置
术语表续 Figures Fig. 24.1: 网络处理流水线示例其中输入端口0和1通过表0和1连接到输出端口0、1和2Fig. 24.2: 数据包处理上下文中哈希表操作的步骤序列Fig. 24.3: 可配置键大小哈希表的数据结构Fig. 24.4: 关键查找操作的桶搜索流水线可配置键大小哈希表Fig. 24.5: 8字节键哈希表的数据结构Fig. 24.6: 16字节键哈希表的数据结构 Tables Table 24.1: 端口类型Table 24.2: 20端口抽象接口Table 24.3: 表类型Table 24.5: 适用于所有哈希表类型的通用配置参数Table 24.6: 适用于可扩展桶哈希表的特定配置参数Table 24.7: 适用于预计算键签名哈希表的特定配置参数Table 24.8: 用于可配置键大小哈希表的主要大型数据结构数组Table 24.9: 桶数组条目的字段描述可配置键大小哈希表Table 24.10: 桶搜索流水线阶段描述可配置键大小哈希表Table 24.11: Match、Match_Many和Match_Pos的查找表Table 24.12: Match、Match_Many和Match_Pos的折叠查找表Table 24.13: 用于8字节和16字节键大小哈希表的主要大型数据结构数组Table 24.14: 桶数组条目的字段描述8字节和16字节键哈希表Table 24.15: 桶搜索流水线阶段描述8字节和16字节键哈希表Table 24.16: 下一跳操作已保留Table 24.17: 用户动作示例