DPDK 基础使用:从 EAL 初始化到 RX/TX 队列收发数据
标签:DPDK rte_mbuf rte_mempool 收发队列
课程的 receive.c、send.c 与 echo.c 建立了最小收发闭环:初始化 EAL,创建 mbuf 内存池,配置端口队列,轮询接收,解析以太网帧并组包发送。
1. 初始化顺序不能乱
rte_eal_init
-> rte_pktmbuf_pool_create
-> rte_eth_dev_configure
-> rte_eth_rx_queue_setup / rte_eth_tx_queue_setup
-> rte_eth_dev_start
-> rte_eth_rx_burst <-> rte_eth_tx_burst
EAL 负责解析 DPDK 参数、初始化大页内存和逻辑核环境。端口启动前,RX/TX 描述符环必须就绪。
if (rte_eal_init(argc, argv) < 0)
rte_exit(EXIT_FAILURE, "EAL init failed\n");
struct rte_mempool *pool = rte_pktmbuf_pool_create(
"MBUF_POOL", NUM_MBUFS, MBUF_CACHE_SIZE, 0,
RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
if (pool == NULL)
rte_exit(EXIT_FAILURE, "mempool create failed\n");
NUM_MBUFS 在课程中常取 2^n - 1。rte_ring 的容量管理与 2 的幂相关,具体值仍应由队列数、突发大小和内存预算确定。
2. 配置端口与队列
struct rte_eth_conf port_conf = {0};
rte_eth_dev_configure(port_id, 1, 1, &port_conf);
rte_eth_rx_queue_setup(port_id, 0, 1024,
rte_eth_dev_socket_id(port_id), NULL, pool);
rte_eth_tx_queue_setup(port_id, 0, 1024,
rte_eth_dev_socket_id(port_id), NULL);
rte_eth_dev_start(port_id);
一个队列对应一组描述符。多队列网卡可将队列、中断(若使用)和 lcore 进行 CPU 亲和性规划;本课程先以单队列把数据路径跑通。
3. 从队列取包并解析
rte_eth_rx_burst 一次取一批 rte_mbuf,没有数据时返回 0。这也是 DPDK 轮询模型的核心。
struct rte_mbuf *mbufs[BURST_SIZE];
uint16_t n = rte_eth_rx_burst(port_id, 0, mbufs, BURST_SIZE);
for (uint16_t i = 0; i < n; i++) {
struct rte_ether_hdr *eth =
rte_pktmbuf_mtod(mbufs[i], struct rte_ether_hdr *);
if (eth->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
struct rte_ipv4_hdr *ip = rte_pktmbuf_mtod_offset(
mbufs[i], struct rte_ipv4_hdr *, sizeof(*eth));
/* 按 ip->next_proto_id 继续分发 */
}
rte_pktmbuf_free(mbufs[i]);
}
rte_pktmbuf_mtod 取得数据首地址;rte_pktmbuf_mtod_offset 在同一 mbuf 上按字节偏移解释下一个协议头。任何分支处理结束后都要明确释放或转交 mbuf 所有权。
4. 组包与发送
发送方向相反:从内存池申请 mbuf,追加实际数据空间,填充协议头,最后批量入 TX 队列。
struct rte_mbuf *tx = rte_pktmbuf_alloc(pool);
char *buf = rte_pktmbuf_append(tx, pkt_len);
if (buf == NULL) {
rte_pktmbuf_free(tx);
return -ENOMEM;
}
/* 填充 Ethernet/IP/UDP 或 ICMP 数据 */
uint16_t sent = rte_eth_tx_burst(port_id, 0, &tx, 1);
if (sent < 1)
rte_pktmbuf_free(tx);
注意:data_len 是当前分段长度,pkt_len 是完整报文长度;多段 mbuf 时二者并不相等。IP/UDP/TCP 校验和必须在字段填完、校验和字段清零后计算。
5. 验证结果
课程用 echo 回包建立了收发验证闭环:

小结
掌握这六个 API 就掌握了 DPDK 的骨架:rte_eal_init、rte_pktmbuf_pool_create、rte_eth_dev_configure、队列 setup、rte_eth_rx_burst、rte_eth_tx_burst。后续 ARP、ICMP、UDP 与 TCP 的区别,主要发生在 mbuf 数据区如何解析和重组。
296



被折叠的 条评论
为什么被折叠?



