4. 环境搭建与基准测试:使用 testpmd 和 KNI 示例程序搭建测试环境,获取基准性能数据
在深入分析 KNI 性能瓶颈之前,必须建立一个可复现、可度量的基准测试环境。本章将指导你使用 DPDK 自带的 testpmd 工具和 kni 示例程序,搭建一套标准的性能评估平台,并获取关键的基准性能数据(如吞吐量、延迟、CPU 占用率)。这些数据将成为后续优化工作的“零点”参照。
4.1 测试环境拓扑与硬件要求
基准测试采用经典的“物理 NIC → DPDK 应用 → KNI 接口 → 内核协议栈”单向或双向转发模型。推荐使用两台物理服务器直连,或使用一台服务器配合硬件流量发生器(如 IXIA/Spirent)进行测试。
硬件避坑提示: KNI 性能受 PCIe 带宽、NUMA 亲和性、内核版本影响极大。建议使用 Intel XL710(40G)或 Mellanox ConnectX-5(25G/100G)网卡,并确保网卡与 DPDK 运行核心位于同一 NUMA 节点。
4.2 环境准备与配置步骤
以下步骤基于 DPDK 22.11 LTS 版本,操作系统为 Ubuntu 22.04 / CentOS Stream 9。请确保已正确编译 DPDK 并加载内核模块。
4.2.1 编译 DPDK 与 KNI 示例
# 设置环境变量
export RTE_SDK=/path/to/dpdk-22.11
export RTE_TARGET=x86_64-native-linux-gcc
# 编译 DPDK 库
cd $RTE_SDK
meson setup build
ninja -C build
# 编译 KNI 示例程序
cd $RTE_SDK/examples/kni
make
# 编译 testpmd(通常随 DPDK 一起编译)
cd $RTE_SDK/app/test-pmd
make
4.2.2 加载内核模块与绑定网卡
# 加载 uio 和 igb_uio 模块
modprobe uio
insmod $RTE_SDK/build/kernel/linux/igb_uio.ko
# 加载 KNI 内核模块(关键)
insmod $RTE_SDK/build/kernel/linux/rte_kni.ko
# 查看网卡 PCI 地址
lspci | grep Ethernet
# 将网卡绑定到 igb_uio 驱动(以 0000:02:00.0 为例)
dpdk-devbind.py -b igb_uio 0000:02:00.0
# 验证绑定状态
dpdk-devbind.py -s
常见错误: 如果
rte_kni.ko 加载失败,请检查内核版本是否支持 KNI 特性(CONFIG_KNI 需启用)。某些发行版默认未开启 KNI 内核配置,需重新编译内核或使用 DPDK 提供的补丁。
4.3 启动 testpmd 与 KNI 示例程序
基准测试采用“testpmd 作为数据面转发引擎,KNI 示例程序作为内核接口桥接”的经典组合。启动顺序必须严格遵守:先启动 KNI 示例,再启动 testpmd。
4.3.1 启动 KNI 示例程序
# 启动 KNI 示例,创建 1 个 KNI 接口,绑定到 core 1
./build/kni -l 0,1 -n 4 -- -P -p 0x1 --config="(0,0,1)"
参数说明:
| 参数 | 含义 | 示例值 |
|---|---|---|
-l 0,1 | 主核 0 用于管理,从核 1 用于数据面 | 0,1 |
-n 4 | 内存通道数(通常为 4) | 4 |
-P | 混杂模式 | — |
-p 0x1 | 端口掩码(仅使用端口 0) | 0x1 |
--config | 端口、队列、核心绑定 | (0,0,1) |
4.3.2 启动 testpmd
# 启动 testpmd,使用 2 个核心,启用硬件卸载
./dpdk-testpmd -l 2,3 -n 4 -- -i --port-topology=chained \
--rxd=1024 --txd=1024 --burst=32 --mbcache=512 \
--forward-mode=io
关键参数说明:
- --rxd=1024 / --txd=1024:设置收发描述符环深度,避免因环满导致丢包。
- --burst=32:每次收发包的 burst 大小,32 是通用平衡值。
- --forward-mode=io:IO 转发模式,不修改包内容,测量纯转发性能。
- --port-topology=chained:端口链式连接,适合单端口测试。
4.4 基准性能数据采集
启动完成后,在 testpmd 交互界面执行以下命令开始流量测试并采集数据。
4.4.1 testpmd 交互命令
# 启动流量转发
start
# 查看实时统计(每秒刷新)
show port stats all
# 查看每个核心的 CPU 占用
show port xstats all
# 查看 KNI 接口统计(在 KNI 示例终端)
# 按 's' 键打印统计信息
4.4.2 关键基准指标
| 指标 | 单位 | 采集方法 | 典型值(10G) |
|---|---|---|---|
| 吞吐量(PPS) | Mpps | testpmd show port stats | 14.88 Mpps(线速) |
| 吞吐量(bps) | Gbps | testpmd show port stats | 9.8 ~ 10.0 Gbps |
| 丢包率 | % | 对比 TX/RX 计数 | < 0.001% |
| KNI 接口延迟 | μs | KNI 示例统计(avg latency) | 5 ~ 15 μs |
| CPU 占用率 | % | top / perf | 单核 60 ~ 80% |
4.4.3 使用流量发生器进行线性测试
为获取完整的性能曲线,建议使用硬件流量发生器发送不同包长(64B、128B、256B、512B、1024B、1518B)的流量,记录每个包长下的吞吐量和延迟。
# 示例:使用 TRex 流量发生器发送 64B 小包
./t-rex-64 -f cap2/dns.yaml -d 60 -m 100% --port 0 --port 1
基准测试清单:
- 记录空载时的 CPU 空闲率(基线)。
- 发送 64B 小包,记录 PPS 和丢包率。
- 发送 1518B 大包,记录 bps 和延迟。
- 逐步增加流量负载(10% → 50% → 100%),观察性能拐点。
- 重复测试 3 次,取平均值作为基准数据。
4.5 基准测试结果示例
以下数据来自实际测试环境(Intel Xeon Gold 6248 @ 2.5GHz,XL710 40G 网卡,DPDK 22.11):
| 包长 (Bytes) | 吞吐量 (Mpps) | 吞吐量 (Gbps) | KNI 延迟 (μs) | CPU 占用率 (%) |
|---|---|---|---|---|
| 64 | 14.88 | 7.62 | 12.3 | 78 |
| 128 | 8.45 | 8.65 | 10.1 | 72 |
| 256 | 4.52 | 9.26 | 8.7 | 65 |
| 512 | 2.34 | 9.59 | 7.4 | 58 |
| 1024 | 1.20 | 9.83 | 6.5 | 52 |
| 1518 | 0.81 | 9.84 | 5.8 | 48 |
分析结论: 64B 小包场景下,KNI 延迟达到 12.3 μs,CPU 占用率接近 80%,说明 KNI 接口的上下文切换和内存拷贝开销在小包场景下尤为突出。后续章节将针对这些瓶颈进行专项优化。
4.6 基准测试常见问题与排查
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| testpmd 启动后无流量 | 网卡未正确绑定 / 链路未 up | 检查 dpdk-devbind.py -s 和 show port link |
| KNI 接口无法创建 | rte_kni.ko 未加载 / 权限不足 | dmesg | tail 查看内核日志 |
| 丢包率过高(> 1%) | 描述符环太小 / burst 不合理 | 增大 --rxd 和 --txd 到 2048 |
| KNI 延迟波动大 | NUMA 跨节点访问 / 中断亲和性差 | 使用 lscpu 确认 NUMA 绑定 |
| CPU 占用率 100% | 轮询模式空转 / 内核软中断过载 | 使用 perf top 分析热点函数 |
性能基线保存: 将每次测试的完整输出保存为日志文件,包括 testpmd 统计、KNI 示例统计、
perf stat 结果。建议使用 tee 命令同时输出到终端和文件:./dpdk-testpmd ... | tee baseline_64B.log。