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;
}
关键步骤:
  1. rte_eal_init():解析命令行参数,初始化大页内存、CPU亲和性、PCI设备扫描等。
  2. RTE_LCORE_FOREACH:遍历所有可用的逻辑核,打印问候信息。
  3. 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/下的配置是否足够。
helloworld 程序执行流程 main() 入口 rte_eal_init() RTE_LCORE_FOREACH rte_eal_cleanup() EAL 初始化内容 • 大页内存分配 • CPU 亲和性设置 • PCI 设备扫描

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,直接发送,实现零拷贝。
l2fwd 二层转发流程 网卡端口0 网卡端口1 rte_eth_rx_burst rte_eth_tx_burst MAC地址表 转发决策

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:端口连通性测试
  1. 启动testpmd:dpdk-testpmd -l 0-1 -n 4 -- -i
  2. 启动转发:start
  3. 观察统计:show port stats all
  4. 检查TX/RX包数是否持续增长,确认链路正常。
场景2:吞吐量测试
  1. 设置转发模式:set fwd mac
  2. 设置包长:set txpkts 64
  3. 启动转发:start tx_first(先发送再统计)
  4. 查看吞吐量:show port stats all,关注“Throughput”字段。
注意事项:
  • testpmd默认使用“io forward”模式,该模式只收不发,需要手动切换为“mac”或“csum”模式才能转发。
  • 如果端口没有link up,请检查网线连接或使用port start 0手动启动端口。
  • 测试性能时,建议使用--txd=1024 --rxd=1024参数增加描述符数量。
testpmd 交互式架构 用户交互层 CLI 命令解析 转发引擎 统计模块 PMD 驱动层(轮询模式) 网卡硬件(端口0) 网卡硬件(端口1)

4.4 本章小结

通过helloworld、l2fwd和testpmd三个示例,我们完成了DPDK从环境验证到实际转发再到交互测试的完整闭环。这些基础能力将直接应用于后续章节中VPP的集成部署——例如,使用testpmd验证网卡性能基线,利用l2fwd的逻辑理解VPP的转发图(graph node)机制。

实践建议:在物理机或虚拟机中依次运行这三个示例,观察输出和统计信息。尝试修改l2fwd的MAC表为静态表项,验证转发正确性。使用testpmd的set fwd mac模式对比与l2fwd的性能差异。