dpdk

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

DPDK

DPDK

Purpose

目的

Guide agents through DPDK (Data Plane Development Kit): EAL initialization, poll-mode driver (PMD) concepts,
rte_eth_rx_burst
/
tx_burst
, mbuf mempools,
rte_ring
queues, huge page setup, RSS configuration, testpmd validation, QEMU virtio testing, and pipeline vs run-to-completion models.
指导 Agent 使用 DPDK(Data Plane Development Kit):EAL 初始化、轮询模式驱动(PMD)概念、
rte_eth_rx_burst
/
tx_burst
、mbuf 内存池、
rte_ring
队列、huge page 设置、RSS 配置、testpmd 验证、QEMU virtio 测试,以及 pipeline 与 run-to-completion 模型。

When to Use

适用场景

  • Building a userspace packet forwarder bypassing the kernel network stack
  • Achieving line-rate on 10/25/100 GbE NICs
  • Prototyping NFV/vSwitch data plane components
  • Testing NIC configuration with testpmd before custom code
  • Comparing DPDK throughput with kernel networking or AF_XDP
  • Running DPDK in VMs with virtio for development
  • 构建绕过内核网络栈的用户态数据包转发器
  • 在 10/25/100 GbE NIC 上达到线速
  • 原型开发 NFV/vSwitch 数据平面组件
  • 在编写自定义代码前,使用 testpmd 测试 NIC 配置
  • 将 DPDK 吞吐量与内核网络或 AF_XDP 进行比较
  • 在 VM 中使用 virtio 运行 DPDK 进行开发

Workflow

工作流

1. Huge pages setup

1. 设置 huge pages

bash
undefined
bash
undefined

2MB hugepages (common)

2MB hugepages (common)

echo 1024 | sudo tee /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
echo 1024 | sudo tee /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

1GB hugepages (better TLB perf on large memory)

1GB hugepages (better TLB perf on large memory)

echo 4 | sudo tee /sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages
echo 4 | sudo tee /sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages

Mount hugetlbfs

Mount hugetlbfs

sudo mkdir -p /mnt/huge sudo mount -t hugetlbfs nodev /mnt/huge
sudo mkdir -p /mnt/huge sudo mount -t hugetlbfs nodev /mnt/huge

Verify

Verify

grep Huge /proc/meminfo

DPDK EAL maps hugepages at startup — insufficient pages cause init failure.
grep Huge /proc/meminfo

DPDK EAL 会在启动时映射 hugepages——大页不足会导致初始化失败。

2. EAL initialization

2. EAL 初始化

c
#include <rte_eal.h>
#include <rte_ethdev.h>

int main(int argc, char **argv) {
    int ret = rte_eal_init(argc, argv);
    if (ret < 0)
        rte_exit(EXIT_FAILURE, "EAL init failed\n");
    // argc/argv adjusted — remaining args for app
    return run_dataplane(argc - ret, argv + ret);
}
bash
undefined
c
#include <rte_eal.h>
#include <rte_ethdev.h>

int main(int argc, char **argv) {
    int ret = rte_eal_init(argc, argv);
    if (ret < 0)
        rte_exit(EXIT_FAILURE, "EAL init failed\n");
    // argc/argv adjusted — remaining args for app
    return run_dataplane(argc - ret, argv + ret);
}
bash
undefined

Typical EAL args

Typical EAL args

./dpdk_app -l 0-3 -n 4 --huge-dir=/mnt/huge -- -p 0x3
./dpdk_app -l 0-3 -n 4 --huge-dir=/mnt/huge -- -p 0x3

Flags:

Flags:

-l 0-3 — cores for DPDK (lcore mask)

-l 0-3 — cores for DPDK (lcore mask)

-n 4 — memory channels

-n 4 — memory channels

--proc-type=primary

--proc-type=primary

--file-prefix=myapp — multi-instance

--file-prefix=myapp — multi-instance

undefined
undefined

3. Port configuration and PMD

3. 端口配置与 PMD

c
#include <rte_ethdev.h>

#define RX_RING_SIZE 1024
#define TX_RING_SIZE 1024
#define NUM_MBUFS    8191
#define MBUF_CACHE   250
#define BURST_SIZE   32

static const struct rte_eth_conf port_conf = {
    .rxmode = { .max_lro_pkt_size = RTE_ETHER_MAX_LEN },
};

struct rte_mempool *mbuf_pool;

int port_init(uint16_t port) {
    mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS,
        MBUF_CACHE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());

    struct rte_eth_rxconf rxq_conf = dev_info.default_rxconf;
    ret = rte_eth_rx_queue_setup(port, 0, RX_RING_SIZE,
        rte_eth_dev_socket_id(port), &rxq_conf, mbuf_pool);
    // ... tx queue setup ...
    ret = rte_eth_dev_start(port);
    rte_eth_promiscuous_enable(port);
    return 0;
}
bash
undefined
c
#include <rte_ethdev.h>

#define RX_RING_SIZE 1024
#define TX_RING_SIZE 1024
#define NUM_MBUFS    8191
#define MBUF_CACHE   250
#define BURST_SIZE   32

static const struct rte_eth_conf port_conf = {
    .rxmode = { .max_lro_pkt_size = RTE_ETHER_MAX_LEN },
};

struct rte_mempool *mbuf_pool;

int port_init(uint16_t port) {
    mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS,
        MBUF_CACHE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());

    struct rte_eth_rxconf rxq_conf = dev_info.default_rxconf;
    ret = rte_eth_rx_queue_setup(port, 0, RX_RING_SIZE,
        rte_eth_dev_socket_id(port), &rxq_conf, mbuf_pool);
    // ... tx queue setup ...
    ret = rte_eth_dev_start(port);
    rte_eth_promiscuous_enable(port);
    return 0;
}
bash
undefined

List available PMDs

List available PMDs

dpdk-devbind.py --status
dpdk-devbind.py --status

Bind NIC to vfio-pci (required for physical NICs)

Bind NIC to vfio-pci (required for physical NICs)

sudo modprobe vfio-pci sudo dpdk-devbind.py --bind=vfio-pci 0000:03:00.0
undefined
sudo modprobe vfio-pci sudo dpdk-devbind.py --bind=vfio-pci 0000:03:00.0
undefined

4. RX/TX burst loop

4. RX/TX 突发处理循环

c
static inline void lcore_main(void) {
    const uint16_t port = 0;
    struct rte_mbuf *bufs[BURST_SIZE];

    while (1) {
        uint16_t nb_rx = rte_eth_rx_burst(port, 0, bufs, BURST_SIZE);
        if (nb_rx == 0)
            continue;

        uint16_t nb_tx = rte_eth_tx_burst(port, 0, bufs, nb_rx);
        // Free unsent mbufs
        if (nb_tx < nb_rx) {
            for (uint16_t i = nb_tx; i < nb_rx; i++)
                rte_pktmbuf_free(bufs[i]);
        }
    }
}
Poll-mode: no interrupts — cores spin for packets. Assign one core per queue for scaling.
c
static inline void lcore_main(void) {
    const uint16_t port = 0;
    struct rte_mbuf *bufs[BURST_SIZE];

    while (1) {
        uint16_t nb_rx = rte_eth_rx_burst(port, 0, bufs, BURST_SIZE);
        if (nb_rx == 0)
            continue;

        uint16_t nb_tx = rte_eth_tx_burst(port, 0, bufs, nb_rx);
        // Free unsent mbufs
        if (nb_tx < nb_rx) {
            for (uint16_t i = nb_tx; i < nb_rx; i++)
                rte_pktmbuf_free(bufs[i]);
        }
    }
}
轮询模式:不使用中断——核心会持续轮询数据包。为实现横向扩展,每个队列分配一个核心。

5. rte_ring for inter-core queues

5. 使用 rte_ring 实现核心间队列

c
#include <rte_ring.h>

struct rte_ring *ring = rte_ring_create("RX_RING", 1024,
    rte_socket_id(), RING_F_SP_ENQ | RING_F_SC_DEQ);

// Producer (RX core)
rte_ring_enqueue_bulk(ring, (void **)bufs, nb_rx, NULL);

// Consumer (worker core)
uint16_t nb_deq = rte_ring_dequeue_bulk(ring, (void **)bufs, BURST_SIZE, NULL);
c
#include <rte_ring.h>

struct rte_ring *ring = rte_ring_create("RX_RING", 1024,
    rte_socket_id(), RING_F_SP_ENQ | RING_F_SC_DEQ);

// Producer (RX core)
rte_ring_enqueue_bulk(ring, (void **)bufs, nb_rx, NULL);

// Consumer (worker core)
uint16_t nb_deq = rte_ring_dequeue_bulk(ring, (void **)bufs, BURST_SIZE, NULL);

6. RSS configuration

6. RSS 配置

c
static const struct rte_eth_rss_conf rss_conf = {
    .rss_key = NULL,
    .rss_hf = RTE_ETH_RSS_IP | RTE_ETH_RSS_TCP | RTE_ETH_RSS_UDP,
};

struct rte_eth_conf port_conf = {
    .rxmode = { .mq_mode = RTE_ETH_MQ_RX_RSS },
    .rx_adv_conf = { .rss_conf = rss_conf },
};
Distributes flows across RX queues — map queues to cores for parallelism.
c
static const struct rte_eth_rss_conf rss_conf = {
    .rss_key = NULL,
    .rss_hf = RTE_ETH_RSS_IP | RTE_ETH_RSS_TCP | RTE_ETH_RSS_UDP,
};

struct rte_eth_conf port_conf = {
    .rxmode = { .mq_mode = RTE_ETH_MQ_RX_RSS },
    .rx_adv_conf = { .rss_conf = rss_conf },
};
将流分发到多个 RX 队列——将队列映射到不同核心以实现并行处理。

7. testpmd validation

7. testpmd 验证

bash
undefined
bash
undefined

Build testpmd

Build testpmd

cd dpdk/build ninja -C build dpdk-testpmd
cd dpdk/build ninja -C build dpdk-testpmd

Forward mode test

Forward mode test

sudo ./build/app/dpdk-testpmd -l 0-3 -n 4 -- -i --forward-mode=io
testpmd> show port stats all testpmd> start tx_first testpmd> show port stats all

Forward modes: `io`, `mac`, `macswap`, `flowgen` for throughput testing.
sudo ./build/app/dpdk-testpmd -l 0-3 -n 4 -- -i --forward-mode=io
testpmd> show port stats all testpmd> start tx_first testpmd> show port stats all

转发模式:`io`、`mac`、`macswap`、`flowgen`,用于吞吐量测试。

8. QEMU virtio testing

8. QEMU virtio 测试

bash
qemu-system-x86_64 \
  -cpu host -m 4096 -smp 4 \
  -netdev user,id=net0 \
  -device virtio-net-pci,netdev=net0,mq=on,vectors=10 \
  -object memory-backend-file,id=mem,size=2G,mem-path=/dev/hugepages,share=on \
  -numa node,memdev=mem \
  ...
Inside VM: bind virtio PCI to
vfio-pci
or use
vhost-user
for higher perf.
bash
qemu-system-x86_64 \
  -cpu host -m 4096 -smp 4 \
  -netdev user,id=net0 \
  -device virtio-net-pci,netdev=net0,mq=on,vectors=10 \
  -object memory-backend-file,id=mem,size=2G,mem-path=/dev/hugepages,share=on \
  -numa node,memdev=mem \
  ...
在 VM 内:将 virtio PCI 绑定到
vfio-pci
,或使用
vhost-user
获得更高性能。

9. Pipeline vs run-to-completion

9. Pipeline 与 run-to-completion

Run-to-completion (simple)
├── One core: RX → process → TX
└── Good for low latency, simple logic

Pipeline (scaled)
├── Core 0: RX → ring
├── Core 1-N: process from ring → ring
└── Core N+1: TX
    └── Better for complex per-packet processing
Run-to-completion (simple)
├── One core: RX → process → TX
└── Good for low latency, simple logic

Pipeline (scaled)
├── Core 0: RX → ring
├── Core 1-N: process from ring → ring
└── Core N+1: TX
    └── Better for complex per-packet processing

Common Problems

常见问题

SymptomCauseFix
EAL: Cannot init hugepagesInsufficient hugepagesIncrease
nr_hugepages
; mount hugetlbfs
No probed ethernet devices
NIC not bound to DPDK driver
dpdk-devbind.py --bind=vfio-pci
RX drops climbingMbuf pool exhaustedIncrease
NUM_MBUFS
; check leak (free mbufs)
0 Mbps in testpmdPort not started
start
in testpmd; check link status
VFIO permission errorNo IOMMU group access
chmod
/
chown
vfio group; enable IOMMU
Poor multi-core scalingRSS not distributingEnable RSS; multiple RX queues
症状原因修复方式
EAL:无法初始化 hugepageshugepages 不足增加
nr_hugepages
;挂载 hugetlbfs
No probed ethernet devices
NIC 未绑定到 DPDK 驱动
dpdk-devbind.py --bind=vfio-pci
RX 丢包数持续上升Mbuf 池已耗尽增加
NUM_MBUFS
;检查内存泄漏(释放 mbuf)
testpmd 中速率为 0 Mbps端口未启动在 testpmd 中执行
start
;检查链路状态
VFIO 权限错误无法访问 IOMMU group使用
chmod
/
chown
修改 vfio group 权限;启用 IOMMU
多核扩展性能不佳RSS 未分发流量启用 RSS;使用多个 RX 队列

Related Skills

相关 Skill

  • skills/async-io/af-xdp
    — lighter-weight XDP alternative
  • skills/async-io/io-uring
    — kernel async I/O comparison
  • skills/observability/ebpf
    — XDP programs redirecting to AF_XDP
  • skills/virtualization/qemu-kvm
    — QEMU setup for virtio testing
  • skills/allocators/numa-programming
    — NUMA-aware DPDK memory
  • skills/profilers/linux-perf
    — profile DPDK lcore hot paths
  • skills/async-io/af-xdp
    — 更轻量的 XDP 替代方案
  • skills/async-io/io-uring
    — 内核异步 I/O 对比
  • skills/observability/ebpf
    — 将 XDP 程序重定向到 AF_XDP
  • skills/virtualization/qemu-kvm
    — 用于 virtio 测试的 QEMU 设置
  • skills/allocators/numa-programming
    — NUMA 感知的 DPDK 内存
  • skills/profilers/linux-perf
    — 分析 DPDK lcore 热路径性能