
简介《DPDK Testpmd 应用》是一份面向DPDK开发者和网络性能测试工程师的用户指南系统讲解基于DPDK的testpmd示例程序。该应用既能测试Packet Forwarding模式下的转发性能也能访问Flow Director等NIC硬件特性同时可作为使用DPDK SDK构建完整应用的参考样例。文档从编译环境与选项入手说明如何通过make、gcc及-m64等选项指定目标平台与架构随后详解EAL与testpmd两类命令行参数以及运行时函数中帮助、控制、显示、配置、端口、链路绑定、寄存器、过滤等各类功能的用途。内容还串联了DPDK的EAL、Packet Framework、NIC Poll Mode Driver三大核心架构便于读者在操作中理解数据包处理流程。资源为单一PDF文件大小仅137KB轻量易携适合随查随用。目前已有599人学习下载适合希望从官方示例入手快速掌握testpmd使用及NIC特性开发的读者。1. 这份 PDF 没讲透的 Testpmd它到底是工具还是黑匣子《DPDK Testpmd 应用》.pdf 这个名字看起来很正式但真正拿到手你会发现它就是一本命令速查手册告诉你 rte 提示符下能敲哪些指令。可实际做网卡性能验证的人心里都清楚testpmd 远不是“输入几条命令看结果”那么简单。它是 DPDK 自带的二三层转发测试工具不需要写业务代码用 PMD 轮询模式直接收发报文能快速测出一块网卡在 DPDK 下的吞吐、丢包、队列分布和多核扩展性。适合三种人刚入门想跑通 DPDK 环境的新手、要选型网卡的性能测试工程师、排查 PMD 或驱动问题的底层开发者。但这东西的黑匣子成分不低同样的命令不同内核、不同大页配置、不同 NUMA 拓扑跑出来的数据可能完全对不上。所以这篇不只讲命令更会把参数逻辑、统计口径和常见翻车点一并拆开。2. 为什么所有 DPDK 性能测试都从 Testpmd 开始原理与选型理由Testpmd 本质上是 DPDK 自带的一个应用示例它把rte_eth_rx_burst和rte_eth_tx_burst这一对收发接口封装成交互命令让你不写一行 C 代码就能看到网卡在轮询模式下的真实表现。DPDK 绕过了内核协议栈应用进程直接通过 PMD 驱动操作网卡硬件队列中断、软中断、协议栈处理都被丢掉所以 testpmd 测出来的数字很接近硬件和驱动本身的上限。选 testpmd 做第一轮验证理由非常直接零编码不需要懂 DPDK API 细节参数覆盖全面从描述符环深度到每核队列数都能调支持交互模式跑起来之后可以动态切换转发模式自带的统计命令足够看出基本问题。相比之下l2fwd 和 l3fwd 也是官方示例但它们带了 MAC 学习和路由查找逻辑测出来的吞吐不能直接代表网卡底层能力。一旦性能不达标用 testpmd 能把问题快速定位到“网卡硬件、PMD 驱动、PCIe 环境”这三层而不是业务代码。2.1 Testpmd 在 DPDK 生态里的位置PMD、队列与转发模型理解 testpmd 的关键是搞清它启动时替你做完了什么。一个普通 DPDK 应用要自己调用rte_eal_init、rte_eth_dev_configure、rte_eth_rx_queue_setup这一串 API 来初始化端口和队列testpmd 把这些步骤全部吸收成了命令行参数然后默认配置好一个或多个端口每个端口配好收发队列等待你指定转发行为。PMD 是轮询模式驱动工作线程在一个逻辑核上循环调用接收函数搬包没有中断打断它所以单核也能跑出很高的包率。testpmd 的路径非常短网卡 DMA 把报文写进内存PMD 从描述符环里取指针应用根据转发模式决定原样发出还是改完 MAC 再发。这里要记住几个 testpmd 里的术语port 对应物理网口或虚拟设备queue 是收发队列需要绑到具体的核mbuf 是报文缓冲区默认 2048 字节。转发模式行为适用场景io forward原样接收再发出纯二层线速测试mac forward改写目的 MAC 后发出对接交换机或对端设备txonly只发送不接收配合外部工具产生流量rxonly只接收不发送配合对端打流验证收包flowgen生成多流随机包模拟多会话压力第一次跑通建议先用 mac forward因为大多数网卡转发时并不会强制校验目的 MAC但后续接交换机时包的目的 MAC 不合法会被直接丢弃提前用 mac 模式能少踩一个坑。2.2 用最小命令跑通第一个 Testpmd 转发常见做法是先把两个物理网口绑定到 vfio-pci 或 igb_uio 驱动然后启动 testpmd。下面这条命令是我最常用的最小启动方式# 两个物理口都绑定到 vfio-pci 后启动 testpmd dpdk-testpmd -l 0-1 \ -a 0000:01:00.0 -a 0000:01:00.1 \ -- --i --rxd512 --txd512 --burst32 --nb-cores1-l 0-1表示允许使用的 CPU 逻辑核是 0 和 1-a指定 PCI 设备这里绑了两个网口--之后是 testpmd 自己的参数--i表示进入交互模式否则 testpmd 初始化完就会退出。--rxd和--txd指定收发描述符环的大小默认 512 够用高吞吐场景再往上调。--burst32表示每次调用 PMD 收发接口最多搬 32 个包。启动后在rte提示符下依次输入set fwd mac start show port stats allset fwd mac切换转发模式start才真正让转发线程跑起来不执行 start 的话 testpmd 不会收发任何包。show port stats all输出两个端口的收发包计数看到 RX 和 TX 都在增长说明这条链路已经通了。如果要退出并把网卡归还内核驱动输入quit再用dpdk-devbind.py -u 0000:01:00.0解绑这也是最容易被人漏掉的一步。2.3 看懂 testpmd 的交互界面rte 提示符下的常用命令testpmd 的交互界面不是 Linux shell很多命令只能在rte下输入。常用命令大致分四类查看配置、切换行为、启停转发、清理统计。help列出当前版本所有命令show config rxtx查看收发队列和描述符环的实际配置set fwd io / mac / txonly / rxonly切换处理行为set txpkts 64,128,256设置发送包长序列set burst 64运行中调整批量收发包数量start和stop控制转发线程clear port stats all清空所有统计计数port stop 0和port start 0单独停启某个物理口。刚开始容易搞混的一点是show config rxtx显示出来的值可能和你启动时参数不一致这时以命令输出为准。比如想看--rxd是否生效一条show config rxtx就能验证不要在rte外面用 shell 猜。另一个习惯是先clear port stats all再开始测试否则上一轮的 drop 数会叠加到当前结果里数据完全没法对照。3. 把 Testpmd 用到性能测试参数与场景跑通不是目的把板卡性能测明白才是。Testpmd 的价值在于你可以用同一套工具测出不同参数组合下的收发上限快速找到转发瓶颈。这里最容易掉进去的坑是照搬网上的“最佳配置”实际上每块网卡的队列数、PCIe 带宽和 NUMA 拓扑都不一样参数必须按自己的硬件去调。3.1 “打包”参数burst、txd/rxd、mbuf 这些值到底怎么调性能测试时最先要调的就是下面这组参数。以我自己的经验这些值不是越大越好也不是越小越好而是要看包长和测试目标。参数含义常见取值说明--burst每次 PMD 调用收发的包数32 / 64过小指令开销大过大会造成延迟抖动--rxd/--txd收发描述符环深度512 / 1024决定队列缓存能力太小容易丢包--mbuf-sizembuf 缓冲区长2048 / 4096大包场景必须增大否则跨 segment--nb-cores参与转发的核数1 / 2 / 4多核要结合队列数一起看--rxq/--txq每端口队列数1-8需要 RSS 支撑才会均匀分摊测 64 字节小包极限时我一般会把--burst设在 32描述符环 1024因为小包本身就考验每秒包数过大的 burst 会造成描述符环瞬间占满或耗尽测 1518 字节大包时--mbuf-size4096是必须的否则一个完整报文要拆成两个 mbuf内存和指针操作都多一倍开销。下面是双核两队列的常用组合# 双口双核每口两个队列适合做转发基准测试 dpdk-testpmd -l 0-3 \ -a 0000:01:00.0 -a 0000:01:00.1 \ -- --i --nb-cores2 --rxq2 --txq2 \ --rxd1024 --txd1024 --burst32 --mbuf-size4096这个组合里两个转发核分别绑定两个队列rxq2和txq2让 RSS 能把进来的流量散到两个队列上。mbuf-size4096保证 1518 字节的大包不跨段描述符环 1024 给高速转发留足余量。测试大包时如果跑到一半发现 RX-dropped 一直在涨优先检查是不是mbuf-size不够而不是先怀疑丢包统计有误。3.2 用 testpmd 模拟不同包长和流表iperf 之外的另一种打流法很多人习惯用 iperf 测吞吐但 iperf 走的是 TCP/UDP 协议栈测不出网卡在二层小包下的极限。Testpmd 的 txonly 模式可以直接从端口发出指定长度报文快速看不同包长下的 PPS 拐点。命令如下set fwd txonly set txpkts 64 starttxonly表示只发不收网卡会持续按照当前速率发包。set txpkts 64是指发出 64 字节的以太网帧这里不包含 CRC 字段。如果要模拟多种包长混发用逗号分隔会按序列轮询比如set txpkts 64,128,256。这样测出来的数据比 iperf 更接近线卡转发能力。不过要注意txonly 模式自身不校验对端是否收到包它只负责把包发出去。要判断是否有丢包必须在另一个端口或另一台设备上用 rxonly 或真实对端收包统计。所以我一般把 txonly 当“不含协议栈的打流器”用配合对端的 rx 计数来判断链路质量而不是把它当独立测吞吐的工具。3.3 从吞吐到延迟io forward 与 mac forward 怎么选吞吐测试选转发模式核心看你要模拟什么场景。io forward 的动作最轻收进来原样从另一个口发出去适合测一台机器两个网口之间的纯转发上限误差最小。mac forward 在转发前改写了目的 MAC 地址多了一轮内存写操作但换取的是与真实交换机对接时报文能被正常二层转发。如果两块网卡背靠背直连建议用 io forward避免改 MAC 之后对端网卡因为 MAC 不匹配把包丢掉造成假丢包。如果中间隔着交换机必须用 mac forward否则交换机的 MAC 表学习不到源地址报文会被丢弃。还有一类测试需要关注 5tuple 模式它按五元组查表转发适合验证 ACL 规则或分流策略但它不是性能测试首选因为其中包含查表逻辑结果和硬件 FDB 能力绑定。延迟方面testpmd 本身不是高精度时延工具它没有硬件时间戳机制交互命令里的show latency只能看转发进程内部的平均值。要做符合体感的时延测试还是要用 ptp 或支持硬件时间戳的网卡。我的习惯是先用 io forward 看极限吞吐再切 mac forward 看真实场景下的回落幅度两个数据都记录。4. Testpmd 避坑指南我踩过的五个典型翻车现场Testpmd 跑不起来或者数据不可信绝大多数情况不是 DPDK 本身的问题而是环境、参数和统计口径在作怪。下面这五条都是我实际踩过或帮别人排查过的坑按“现象→原因→解决”写清楚。4.1 现象跑 testpmd 时网卡断连控制台卡死现象启动 testpmd 后物理网卡指示灯灭掉正在进行测试的会话直接断开有时候控制台也无响应。原因网卡被 DPDK 接管内核驱动被解绑但是当前机器上可能同时有 NetworkManager 或内核网络栈在操作这张卡。另外一个常见的情况是把自己正在用的管理口也绑给了 DPDK测试一开始整个网络管理面就断了。解决绑定前先用dpdk-devbind.py -s看清设备列表确认目标网卡不是管理口绑定到 vfio-pci 后不要对这张卡做任何内核网络配置。已经卡死只能通过带外管理或串口重启所以开工前第一件事就是物理隔离测试网口和管理网口。4.2 现象大包吞吐上不去小包却正常现象64 字节小包能跑到线速1518 字节大包反而不到理论吞吐甚至出现丢包。原因mbuf-size默认只有 2048 字节1518 字节的包加上 VLAN 头和头部开销后超过单个 mbuf 容量PMD 会把报文拆分到多个 segment接收描述符环消耗速度加快吞吐直接降下来。另一种可能是 PCIe 带宽不足多网卡同时跑满时总线成为瓶颈。解决启动 testpmd 时把--mbuf-size改成 4096确保整包落在同一个 mbuf 里。如果这样还没提升用dmesg看有没有 PCIe 带宽告警同时跑两个口时要算链路总带宽是否超过了 PCIe 插槽的实际能力。4.3 现象NUMA 架构下开多队列性能反而下降现象--nb-cores从 1 加到 2吞吐不但没有翻倍反而下降drop 数开始增加。原因网卡所在的 NUMA node 和转发核不在同一个 socketDMA 写内存落在远端节点内存访问延迟变高或者 RSS 哈希没有把流量均匀散到两个队列出现一个核满负载、另一个核空闲。解决先用lscpu和dpdk-devbind.py -s确认网卡挂在哪个 socket把-l参数限定在同一 socket 的核上。同时用--socket-mem只给网卡所在节点分配大页内存比如--socket-mem1024。如果两个队列对应两个核检查show port stats all里两个队列的收包是否均匀不均匀就在网卡侧调整 RSS 哈希配置。4.4 现象改了 txd/rxd 数值不生效跑起来还是默认值现象启动命令行写了--rxd2048 --txd2048show config rxtx显示的还是 512。原因参数位置写错了--rxd必须放在--之后才属于 testpmd 参数或者虽然写对了但启动后又在交互模式下用了port config修改而没有执行port stop和port start配置没有真正重新加载。解决把参数写进启动命令的--后面然后启动后马上show config rxtx确认。如果运行中要改描述符环先port stop 0再执行port config 0 rxd 2048和port config 0 txd 2048最后port start 0让新配置生效。4.5 现象想用 testpmd 发特定流但不知道从哪下手现象需要构造带指定源 IP、目的 IP、端口号的报文在 testpmd 交互界面里翻遍 help 也没找到入口。原因testpmd 的核心定位是“转发测试”不是“报文构造器”它写报文的命令极其有限只能控制长度和少量字段。解决set txpkts只能控制包长构造复杂头部就换 pktgen-dpdk它用 Lua 脚本定义 IP、MAC、端口范围比 testpmd 灵活得多。testpmd 的活是准确接收并统计这些流量两者分工不要混。硬要在 testpmd 里拼报文只会浪费一下午。5. 把这份 PDF 消化成自己的排查手册日志、统计与自动化这份中文 PDF 适合当命令字典但真正要提高效率得把 testpmd 的输出变成可比较的数据。很多 DPDK 性能测试翻车不是命令不对而是统计读错、环境不固定、全靠手敲。这一章就说清楚统计怎么看、流量生成器怎么配合以及怎么把跑测试变成一键脚本。5.1 testpmd 的统计信息怎么读rx/tx 计数与 drop 的区分show port stats all的输出字段不少但关键看这几个RX-packets 代表从物理口收到的报文数RX-dropped 代表驱动已经接手但因为队列满或描述符不够而被丢弃的报文TX-packets 代表发出去的报文数TX-dropped 代表发送时因队列满丢弃的包Missed 表示网卡 DMA 已经把包写进内存但 PMD 没来得及取走队列又被新包覆盖掉的数目。判断一个转发测试有没有丢包不能只看 TX-packets 涨没涨。正确方式是在 io forward 模式下入口端口的 RX-packets 和出口端口的 TX-packets 应该基本一致差值就是丢包同时看 Missed 是否为 0只要 Missed 有数字就说明 CPU 和队列的匹配已经瓶颈了。身边见过不止一个人拿着 TX 的 pps 数据当吞吐结果一看 RX-dropped 高得离谱那种数据拿去选型基本没有参考价值。所以每轮测试之前先执行clear port stats all清掉上一轮残留的计数不然叠加出来的 drop 会把好板卡也“测成”不合格。5.2 用 pktgen 与 testpmd 配合做更接近现实的压测Testpmd 转发能力强但它不适合构造复杂流量。真实场景里要用多 IP、多 MAC、混合包长的流去压被测网卡我会在 testpmd 对端启动 pktgen-dpdk 来打流。pktgen 同样是基于 DPDK 的流量生成器用 Lua 脚本可以灵活定义报文字段。# 启动 pktgen两个核映射到两个端口执行脚本 pktgen -l 0-3 -a 0000:01:00.0 -- -P -m 1.0, 2.0 -f test_pktgen.lua-P表示启动后直接开启所有端口-m 1.0, 2.0的意思是核 1 对应端口 0、核 2 对应端口 1-f指定 Lua 脚本脚本里可以设置包长范围、源和目的 IP 变化的步长、MAC 队列数等。对端 testpmd 用 io forward 或 mac forward 做转发两边打开统计最终对比 pktgen 发出的包数和 testpmd 收到的包数。这种组合比单纯 testpmd txonly 更接近现网流量特征也更容易暴露 RSS 不均和队列深度不够的问题。5.3 写一个简单的自动化脚本跑多轮测试并收集结果跑性能测试最忌讳手敲命令和肉眼读输出因为多轮之间间隔不同、统计时间不同出来的数据根本没有对比价值。下面是我常用的一种自动化方式用 Python 启动 testpmd通过标准输入发送控制命令然后抓取输出并解析统计import subprocess import re import time def run_testpmd_case(): cmd [ dpdk-testpmd, -l, 0-1, -a, 0000:01:00.0, -a, 0000:01:00.1, --, -i, --nb-cores1, --burst32, --rxd512, --txd512 ] p subprocess.Popen(cmd, textTrue, stdinsubprocess.PIPE, stdoutsubprocess.PIPE) # 等待初始化完成再启动转发 time.sleep(2) p.stdin.write(start\n) p.stdin.flush() # 持续转发 10 秒 time.sleep(10) # 抓取统计然后停止并退出 p.stdin.write(show port stats all\nstop\nquit\n) p.stdin.flush() output, _ p.communicate(timeout10) # 按端口分块解析出来方便后续计算和对比 blocks re.split(r###### Port (\d) ######, output) stats {} for i in range(1, len(blocks), 2): port_id int(blocks[i]) body blocks[i 1] rx re.search(rRX-packets: (\d), body) tx re.search(rTX-packets: (\d), body) missed re.search(rRX-missed: (\d), body) stats[port_id] { rx: int(rx.group(1)) if rx else 0, tx: int(tx.group(1)) if tx else 0, missed: int(missed.group(1)) if missed else 0, } return stats if __name__ __main__: result run_testpmd_case() print(result)这个脚本里的time.sleep(2)是等待 testpmd 完成 EAL 初始化实际环境如果设备多可以调到 3 秒。communicate(timeout10)用来等 testpmd 在 quit 之后正常退出防止进程挂住。解析部分按Port 0、Port 1分块不会把两个口的数混在一起。多轮测试时我会把每轮参数、输出、环境信息写进一个 CSV 或者日志文件比如记录--rxd --txd --burst和/proc/meminfo里的 HugePages 剩余量。这样调参后对比才有迹可循。脚本里还可以继续加循环和随机种子但核心是先保住每轮之间的统计干净。6. 进阶技巧把 Testpmd 的转发结果变成可比较的数据6.1 用脚本解析 testpmd 输出自动计算吞吐和丢包率有了上一章的原始统计下一步是计算两个关键指标吞吐和丢包率。吞吐可以用固定时间窗口内RX-packets的增量除以秒数得到丢包率则要同时看RX-dropped和RX-missed计算方式为(RX-dropped RX-missed) / RX-packets * 100%。注意不要把 TX 端丢包混进来因为发送丢包是另一层原因混合在一起会把问题搞乱。6.2 常见误用把 testpmd 当网络设备用Testpmd 不做任何路由和协议处理不回应 ARP不处理 VLAN也没有流量表。生产业务流量不要直接往 testpmd 上塞它只是用来验证底层网卡和驱动能力的工具。真要跑业务用 l3fwd、ovs-dpdk 或者自己写的转发程序testpmd 的数据只代表“网卡行不行”不代表“业务行不行”。6.3 我的习惯固定环境变量清空统计记录大页内存我最早做网卡选型时连着三天的数据都对不上后来发现是每轮测试之间 hugepage 被其他进程吃掉了一部分mbuf 被迫落在不同 NUMA 节点上结果吞吐差了好几个点。从那以后我每次跑 testpmd 之前都会执行一次clear port stats all并在输出文件头记录/proc/meminfo里的 HugePages_Free 数量、dpdk-devbind.py -s的设备列表、以及内核启动参数里是否隔离了测试核。有了这些环境快照跑出来的数据即使过了几个月翻出来也能一眼判断还能不能用。这也是我把这份 PDF 消化成自己的排查手册后养成的最重要的一个习惯。希望帮到你。本文还有配套的精品资源点击获取