4、DPDK基础示例:helloworld程序、l2fwd转发示例、testpmd交互工具
本章是DPDK实战的起点。通过三个经典示例——helloworld(验证环境)、l2fwd(二层转发)和testpmd(交互式流量测试),你将掌握DPDK应用从初始化、内存管理到数据包收发的基本流程。这些示例是后续集成VPP用户态协议栈的基石。
学习目标:
- 理解DPDK EAL(环境抽象层)的初始化过程。
- 掌握内存池(mempool)与mbuf的创建与使用。
- 学会使用l2fwd实现基本的二层转发逻辑。
- 熟练运用testpmd进行端口配置、流量收发与性能测试。
4.1 helloworld程序:DPDK环境验证
helloworld是DPDK的“入门仪式”,它不涉及网络收发,只验证EAL初始化、CPU亲和性设置和日志系统是否正常工作。
4.1.1 核心代码解析
#include <rte_eal.h>
#include <rte_lcore.h>
#include <rte_debug.h>
int main(int argc, char **argv) {
int ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_panic("Cannot init EAL\n");
unsigned lcore_id;
RTE_LCORE_FOREACH(lcore_id) {
printf("Hello from core %u\n", lcore_id);
}
rte_eal_cleanup();
return 0;
}
关键步骤:
rte_eal_init():解析命令行参数,初始化大页内存、CPU亲和性、PCI设备扫描等。RTE_LCORE_FOREACH:遍历所有可用的逻辑核,打印问候信息。rte_eal_cleanup():释放EAL资源。
4.1.2 编译与运行
| 步骤 | 命令 | 说明 |
|---|---|---|
| 1. 设置环境变量 | export RTE_SDK=/path/to/dpdk |
指向DPDK源码目录 |
| 2. 设置目标架构 | export RTE_TARGET=x86_64-native-linuxapp-gcc |
根据编译环境选择 |
| 3. 编译示例 | make -C examples/helloworld |
生成可执行文件 |
| 4. 运行 | ./build/helloworld -l 0-3 -n 4 |
使用核0-3,4个内存通道 |
常见问题:如果运行报错“EAL: Cannot allocate memory”,请检查大页内存是否已挂载(
mount -t hugetlbfs nodev /mnt/huge)以及/sys/kernel/mm/hugepages/下的配置是否足够。
4.2 l2fwd转发示例:二层交换核心
l2fwd(Layer 2 Forwarding)是一个完整的二层转发程序。它从网卡接收数据包,根据目的MAC地址查找转发表,然后从对应端口转发出去。这是理解DPDK数据面处理逻辑的最佳起点。
4.2.1 程序架构
- 初始化阶段:EAL初始化、创建内存池(mempool)、初始化网卡端口(rte_eth_dev_configure)、设置RX/TX队列。
- 转发阶段:主循环中,每个核从自己的RX队列批量收包(rte_eth_rx_burst),解析MAC地址,查表后从对应TX队列发送(rte_eth_tx_burst)。
- MAC地址学习:l2fwd简化了学习过程,通常使用静态MAC表或直接广播。
4.2.2 关键数据结构
| 数据结构 | 类型 | 作用 |
|---|---|---|
rte_mempool |
内存池 | 预分配固定大小的mbuf,避免运行时动态分配 |
rte_mbuf |
报文缓冲区 | 存储数据包内容、元数据(长度、端口、VLAN等) |
rte_eth_dev |
网卡设备 | 代表一个物理或虚拟网卡端口 |
l2fwd_mac_table |
自定义 | MAC地址到端口的映射表(简化实现) |
4.2.3 核心转发循环
static void l2fwd_main_loop(void) {
struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
unsigned lcore_id = rte_lcore_id();
uint16_t port;
while (1) {
// 从所有绑定的端口收包
for (port = 0; port < nb_ports; port++) {
if (port_queue[lcore_id][port].rx_queue_id == INVALID_QUEUE_ID)
continue;
uint16_t nb_rx = rte_eth_rx_burst(port, 0, pkts_burst, MAX_PKT_BURST);
if (unlikely(nb_rx == 0))
continue;
// 处理每个收到的包
for (uint16_t i = 0; i < nb_rx; i++) {
struct rte_mbuf *m = pkts_burst[i];
uint16_t dst_port = get_dst_port(m); // 查MAC表
rte_eth_tx_burst(dst_port, 0, &m, 1); // 转发
}
}
}
}
性能要点:
- 使用
rte_eth_rx_burst批量收包,减少函数调用开销。 - 每个核处理固定的端口队列,避免锁竞争。
- 转发前不修改mbuf,直接发送,实现零拷贝。
4.3 testpmd交互工具:网络功能测试利器
testpmd是DPDK自带的交互式数据面测试工具,支持端口配置、流量生成、转发测试、统计查看等功能。它不需要编写代码,即可快速验证网卡功能和性能。
4.3.1 启动testpmd
# 基本启动命令(使用2个核,2个端口)
./build/app/dpdk-testpmd -l 0-1 -n 4 -- -i --portmask=0x3
# 参数说明:
# -l 0-1:使用逻辑核0和1
# -n 4:4个内存通道
# -- -i:交互模式
# --portmask=0x3:启用端口0和1
4.3.2 常用交互命令
| 命令 | 功能 | 示例 |
|---|---|---|
show port info all |
显示所有端口信息 | 查看MAC地址、驱动、速率 |
start |
启动转发 | 开始收发包 |
stop |
停止转发 | 停止后查看统计 |
show port stats all |
显示端口统计 | 收发包数量、错误、丢弃 |
set fwd mac |
设置转发模式为MAC转发 | 类似l2fwd |
set fwd io |
设置转发模式为IO转发 | 只收不发,用于测试RX |
set txpkts 64,128,256 |
设置发送包长序列 | 用于混合包长测试 |
4.3.3 典型测试场景
场景1:端口连通性测试
- 启动testpmd:
dpdk-testpmd -l 0-1 -n 4 -- -i - 启动转发:
start - 观察统计:
show port stats all - 检查TX/RX包数是否持续增长,确认链路正常。
场景2:吞吐量测试
- 设置转发模式:
set fwd mac - 设置包长:
set txpkts 64 - 启动转发:
start tx_first(先发送再统计) - 查看吞吐量:
show port stats all,关注“Throughput”字段。
注意事项:
- testpmd默认使用“io forward”模式,该模式只收不发,需要手动切换为“mac”或“csum”模式才能转发。
- 如果端口没有link up,请检查网线连接或使用
port start 0手动启动端口。 - 测试性能时,建议使用
--txd=1024 --rxd=1024参数增加描述符数量。
4.4 本章小结
通过helloworld、l2fwd和testpmd三个示例,我们完成了DPDK从环境验证到实际转发再到交互测试的完整闭环。这些基础能力将直接应用于后续章节中VPP的集成部署——例如,使用testpmd验证网卡性能基线,利用l2fwd的逻辑理解VPP的转发图(graph node)机制。
实践建议:在物理机或虚拟机中依次运行这三个示例,观察输出和统计信息。尝试修改l2fwd的MAC表为静态表项,验证转发正确性。使用testpmd的
set fwd mac模式对比与l2fwd的性能差异。