4. 转发模式详解:io-forward、mac-forward、flowgen、rxonly、txonly 模式原理与适用场景
testpmd 的转发模式决定了数据包在网卡端口之间的处理与传递方式。理解每种模式的内部数据流、内存操作和 CPU 开销,是进行性能调优和丢包分析的基础。本章将深入剖析五种核心转发模式:io-forward、mac-forward、flowgen、rxonly 和 txonly。
4.1 转发模式总览与选择矩阵
下表从数据流方向、是否修改 MAC、是否生成包、CPU 开销和典型场景五个维度,对五种模式进行横向对比:
| 模式 | 数据流方向 | MAC 修改 | 包生成 | CPU 开销 | 典型场景 |
|---|---|---|---|---|---|
| io-forward | RX → TX (同端口/异端口) | 不修改 | 否 | 低 | 纯转发性能基准测试 |
| mac-forward | RX → TX (异端口) | 交换源/目的 MAC | 否 | 中 | 二层交换机行为模拟 |
| flowgen | RX → TX + 软件生成流 | 按流表修改 | 是 (控制流) | 高 | 流表压力与老化测试 |
| rxonly | RX → 丢弃 | 不适用 | 否 | 最低 | 纯接收性能、驱动稳定性 |
| txonly | 软件生成 → TX | 构造时设定 | 是 | 低 | 纯发送性能、线速测试 |
调优提示: 在测试网卡极限 PPS 时,优先使用 io-forward 或 rxonly/txonly 组合,避免 MAC 地址重写或流表查询带来的额外 CPU 周期开销。
4.2 io-forward:纯 I/O 转发模式
io-forward 是 testpmd 默认且最轻量的转发模式。其核心逻辑是:从 RX 描述符环收到 mbuf,不经任何修改,直接将其送入同一端口或指定端口的 TX 描述符环。
4.2.1 原理与数据流
- 零拷贝:mbuf 指针直接从 RX 队列传递到 TX 队列,不涉及数据内容拷贝。
- 无 MAC 重写:以太网帧头保持原样,源 MAC 和目的 MAC 均不修改。
- 端口映射:支持
--nb-cores和--rxq/--txq配置,每个 lcore 处理一组 RX/TX 队列对。
关键代码路径(简化):
static void pkt_burst_io_forward(struct fwd_stream *fs) {
uint16_t nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue,
fs->rx_pkts, nb_pkt_per_burst);
if (unlikely(nb_rx == 0))
return;
uint16_t nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
fs->rx_pkts, nb_rx);
/* 处理未成功发送的包(回退或丢弃) */
if (unlikely(nb_tx < nb_rx))
fs->fwd_dropped += (nb_rx - nb_tx);
}
4.2.2 内联 SVG:io-forward 数据流架构
4.2.3 适用场景
- 网卡 PPS 基准测试:消除软件开销,测量网卡和 PCIe 总线的极限吞吐。
- 驱动稳定性验证:长时间运行 io-forward,观察是否有描述符泄漏或硬件挂死。
- 多队列负载均衡测试:配合 RSS 配置,验证流量是否均匀分布在多个 RX 队列上。
4.3 mac-forward:二层 MAC 重写转发
mac-forward 模拟二层交换机的行为。它在转发前会交换以太网帧的源 MAC 和目的 MAC 地址,确保对端设备能够正确回复。
4.3.1 原理与数据流
- MAC 重写:将接收到的帧的源 MAC 写入目的 MAC 字段,将本端口的 MAC 写入源 MAC 字段。
- 端口隔离:默认只在两个不同端口之间转发(如 port 0 ↔ port 1),避免环路。
- FDB 查询:可选启用软件 FDB(转发数据库),根据目的 MAC 查找出端口。
性能陷阱: mac-forward 模式下,每个包都需要进行 12 字节的 MAC 地址拷贝(6 字节源 + 6 字节目的),在 64 字节小包场景下,这会增加约 10%-15% 的每包 CPU 开销。如果测试纯转发性能,应使用 io-forward。
4.3.2 内联 SVG:mac-forward MAC 重写流程
4.3.3 适用场景
- 二层转发功能验证:测试 DPDK 应用作为透明网桥或交换机的行为。
- MAC 学习/老化测试:配合
--eth-peer参数,验证 FDB 表项的正确性。 - 环路避免测试:结合 STP(生成树协议)模拟,验证端口阻塞逻辑。
4.4 flowgen:流生成与转发混合模式
flowgen 是一种混合模式,它在接收流量并转发的同时,还会在软件层面主动生成新的数据流,用于测试流表容量和老化机制。
4.4.1 原理与数据流
- 双路径:一路处理 RX 收到的包(类似 mac-forward),另一路周期性地从软件构造新包注入 TX。
- 流表操作:每个生成的流对应一个唯一的 5 元组,可配置流表大小和老化时间。
- CPU 密集型:需要维护定时器、流表哈希表和包构造逻辑,CPU 开销显著高于其他模式。
启动示例:
./dpdk-testpmd -l 0-3 -n 4 -- -i --forward-mode=flowgen \
--flowgen-rxq=2 --flowgen-txq=2 \
--flowgen-flows=1024 --flowgen-rate=1000
上述命令启动 1024 条流,每条流每秒发送 1000 个包。
4.4.2 内联 SVG:flowgen 双路径架构
4.4.3 适用场景
- 流表容量压力测试:验证硬件或软件流表在满载时的转发性能。
- 老化机制验证:配置短老化时间,观察流表条目是否被正确回收。
- 控制面与数据面交互测试:模拟控制面下发流表,数据面按流表转发。
4.5 rxonly:纯接收模式
rxonly 模式只从网卡接收数据包,然后立即释放 mbuf,不进行任何转发或发送操作。
4.5.1 原理与数据流
- 接收即释放:调用
rte_eth_rx_burst后,遍历所有收到的 mbuf 并调用rte_pktmbuf_free。 - 无 TX 路径:不初始化 TX 队列,节省内存和 PCIe 带宽。
- 统计计数:仅累加接收计数和字节数,不进行任何协议解析。
调试技巧: 当怀疑丢包发生在 TX 侧时,使用 rxonly 模式可以隔离问题。如果 rxonly 下接收计数与发包器一致,说明 RX 路径正常,问题出在 TX 或转发逻辑。
5.5.2 适用场景
- 网卡接收性能极限测试:测量网卡在无软件处理开销下的最大接收 PPS。
- 驱动 RX 路径稳定性测试:长时间运行,检查描述符泄漏或 RX 中断异常。
- 丢包问题定位:作为对比基准,判断丢包是发生在 RX 还是 TX 阶段。
4.6 txonly:纯发送模式
txonly 模式不接收任何数据包,完全由软件构造数据包并通过 TX 队列发送出去。
4.6.1 原理与数据流
- 包构造:在转发循环中,调用
rte_pktmbuf_alloc分配 mbuf,然后填充以太网头、IP 头、UDP 头等。 - 速率控制:支持
--txonly-multi-flow和--txonly-pps参数控制发送速率和流数量。 - 无 RX 路径:不初始化 RX 队列,减少中断和 DMA 开销。
构造包示例(UDP 包):
struct rte_mbuf *pkt = rte_pktmbuf_alloc(mpool);
if (pkt) {
pkt->data_len = 64; // 64 字节小包
pkt->pkt_len = 64;
char *data = rte_pktmbuf_mtod(pkt, char *);
/* 填充以太网头 */
memcpy(data, ð_hdr, sizeof(eth_hdr));
/* 填充 IP 头 */
memcpy(data + sizeof(eth_hdr), &ip_hdr, sizeof(ip_hdr));
/* 填充 UDP 头 */
memcpy(data + sizeof(eth_hdr) + sizeof(ip_hdr), &udp_hdr, sizeof(udp_hdr));
}
4.6.2 内联 SVG:txonly 包构造与发送流程
4.6.3 适用场景
- 网卡发送性能极限测试:测量网卡在无接收干扰下的最大发送 PPS。
- 线速测试:配合流量分析仪,验证网卡是否能够达到线速(如 10G/25G/100G)。
- 包构造逻辑验证:测试不同包大小、协议组合下的发送稳定性。
4.7 模式选择决策树
在实际调试中,可以根据以下决策树快速选择正确的转发模式:
4.8 本章小结
- io-forward 是最轻量的纯转发模式,适合性能基准测试。
- mac-forward 模拟二层交换机,适合功能验证。
- flowgen 是混合模式,用于流表压力和老化测试。
- rxonly 和 txonly 分别用于隔离接收和发送路径的问题。
- 选择模式时,应根据测试目标(性能/功能/稳定性)和是否需要修改包内容来决定。
常见误区: 不要使用 mac-forward 或 flowgen 来测量网卡的极限 PPS,它们的额外 CPU 开销会掩盖硬件性能。始终使用 io-forward 或 rxonly/txonly