目 录CONTENT

文章目录

dpdk 入门 - 程序基础框架

16Reverie
2025-06-15 / 0 评论 / 0 点赞 / 6 阅读 / 0 字

一个 dpdk 程序最基础的框架需要包含:dpdk 程序初始化、主处理函数、资源清理释放。

官方示例程序中,helloworld 是一个最基础的 dpdk 程序之一(多核运行),它包含了初始化、在每个核心上运行 helloworld 打印、资源清理释放。示例程序 skeleton 则是一个最简单的报文转发程序,它实现了在一个端口接收,在另一个配对的端口(可为自身)发送出去。

初始化流程

在处理数据包之前,每个 DPDK 应用程序都必须遵循特定的初始化顺序:

EAL Initialization(环境抽象层初始化)

环境抽象层(EAL)是 DPDK 应用程序中必须初始化的第一个组件。它处理与底层平台的交互,包括内存管理、PCI 设备发现和 CPU 核心分配等。

int ret = rte_eal_init(argc, argv);
if (ret < 0)
    rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");

EAL 初始化解析命令行参数,为 DPDK 分配大页面,为数据包处理分配 CPU 核心,并探测可用的网络设备。

使用 Mempools 进行内存管理

通常在 EAL 初始化之后创建 mempool ,DPDK 应用程序使用内存池(mempools)来有效地分配和释放数据包缓冲区(mbufs)。

struct rte_mempool *mbuf_pool = rte_pktmbuf_pool_create(
    "MBUF_POOL",            /* name */
    NUM_MBUFS * nb_ports,   /* number of elements */
    MBUF_CACHE_SIZE,        /* cache size */
    0,                      /* private data size */
    RTE_MBUF_DEFAULT_BUF_SIZE, /* data buffer size */
    rte_socket_id()         /* socket ID */
);
if (mbuf_pool == NULL)
    rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");

以太网设备配置

初始化 EAL 并创建内存池之后,应用程序配置以太网设备。通常包括设置端口、配置 Rx 和 Tx 队列、启动端口和配置混杂模式等步骤:

/* Configure the Ethernet device */
ret = rte_eth_dev_configure(port_id, rx_rings, tx_rings, &port_conf);
if (ret < 0)
    rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
             ret, port_id);

/* Set up Rx queues */
for (q = 0; q < rx_rings; q++) {
    ret = rte_eth_rx_queue_setup(port_id, q, RX_DESC_DEFAULT,
                                 rte_eth_dev_socket_id(port_id),
                                 NULL, mbuf_pool);
    if (ret < 0)
        rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup: err=%d, port=%u\n",
                 ret, port_id);
}

/* Set up Tx queues */
for (q = 0; q < tx_rings; q++) {
    ret = rte_eth_tx_queue_setup(port_id, q, TX_DESC_DEFAULT,
                                 rte_eth_dev_socket_id(port_id),
                                 NULL);
    if (ret < 0)
        rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup: err=%d, port=%u\n",
                 ret, port_id);
}

/* Start the Ethernet device */
ret = rte_eth_dev_start(port_id);
if (ret < 0)
    rte_exit(EXIT_FAILURE, "rte_eth_dev_start: err=%d, port=%u\n",
             ret, port_id);

/* Optional: Enable promiscuous mode */
rte_eth_promiscuous_enable(port_id);

至此,dpdk 程序的基本的初始化完成。

包处理循环

程序初始化完成后,进入程序处理循环,通常为包处理循环,步骤可以简单概括为:收包 -> 包处理 -> 发包。

一个简单的数据包转发循环可能看起来像这样:

/* Main processing loop */
for (;;) {
    /* Get burst of packets from Rx queue */
    const uint16_t nb_rx = rte_eth_rx_burst(port_id, 0,
                                          pkts_burst, MAX_PKT_BURST);
    if (unlikely(nb_rx == 0))
        continue;

    /* Process packets (in this case, just forward them) */
    uint16_t nb_tx = rte_eth_tx_burst(port_id ^ 1, 0,
                                     pkts_burst, nb_rx);

    /* Free any unsent packets */
    if (unlikely(nb_tx < nb_rx)) {
        uint16_t buf;
        for (buf = nb_tx; buf < nb_rx; buf++)
            rte_pktmbuf_free(pkts_burst[buf]);
    }
}

其中rte_eth_rx_burst 函数负责收包,能够一次接收多个报文,函数返回接收到的报文数量;

rte_eth_tx_burst 函数完成发包,能够一次发送多个报文,返回发送的报文数量。

当报文未能全部发送时,剩余的报文需要手动释放处理。

多核数据包处理

DPDK 应用程序可以利用多个 CPU 内核进行数据包处理。典型的方法是使用运行到完成模型(RTC)将包处理循环运行到多个的 CPU 核上。

rte_eal_mp_remote_launch(lcore_main, NULL, CALL_MASTER);

结束

程序主循环结束后,程序需要对资源进行释放,通常包括:设备停用、资源清理释放等,具体代码参考官方示例。

0

评论区