dpdk
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDPDK
DPDK
Purpose
目的
Guide agents through DPDK (Data Plane Development Kit): EAL initialization, poll-mode driver (PMD) concepts, /, mbuf mempools, queues, huge page setup, RSS configuration, testpmd validation, QEMU virtio testing, and pipeline vs run-to-completion models.
rte_eth_rx_bursttx_burstrte_ring指导 Agent 使用 DPDK(Data Plane Development Kit):EAL 初始化、轮询模式驱动(PMD)概念、/、mbuf 内存池、 队列、huge page 设置、RSS 配置、testpmd 验证、QEMU virtio 测试,以及 pipeline 与 run-to-completion 模型。
rte_eth_rx_bursttx_burstrte_ringWhen 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
undefinedbash
undefined2MB 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
undefinedc
#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
undefinedTypical 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
undefinedundefined3. 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
undefinedc
#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
undefinedList 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
undefinedsudo modprobe vfio-pci
sudo dpdk-devbind.py --bind=vfio-pci 0000:03:00.0
undefined4. 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
undefinedbash
undefinedBuild 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 or use for higher perf.
vfio-pcivhost-userbash
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-pcivhost-user9. 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 processingRun-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 processingCommon Problems
常见问题
| Symptom | Cause | Fix |
|---|---|---|
| EAL: Cannot init hugepages | Insufficient hugepages | Increase |
| NIC not bound to DPDK driver | |
| RX drops climbing | Mbuf pool exhausted | Increase |
| 0 Mbps in testpmd | Port not started | |
| VFIO permission error | No IOMMU group access | |
| Poor multi-core scaling | RSS not distributing | Enable RSS; multiple RX queues |
| 症状 | 原因 | 修复方式 |
|---|---|---|
| EAL:无法初始化 hugepages | hugepages 不足 | 增加 |
| NIC 未绑定到 DPDK 驱动 | |
| RX 丢包数持续上升 | Mbuf 池已耗尽 | 增加 |
| testpmd 中速率为 0 Mbps | 端口未启动 | 在 testpmd 中执行 |
| VFIO 权限错误 | 无法访问 IOMMU group | 使用 |
| 多核扩展性能不佳 | RSS 未分发流量 | 启用 RSS;使用多个 RX 队列 |
Related Skills
相关 Skill
- — lighter-weight XDP alternative
skills/async-io/af-xdp - — kernel async I/O comparison
skills/async-io/io-uring - — XDP programs redirecting to AF_XDP
skills/observability/ebpf - — QEMU setup for virtio testing
skills/virtualization/qemu-kvm - — NUMA-aware DPDK memory
skills/allocators/numa-programming - — profile DPDK lcore hot paths
skills/profilers/linux-perf
- — 更轻量的 XDP 替代方案
skills/async-io/af-xdp - — 内核异步 I/O 对比
skills/async-io/io-uring - — 将 XDP 程序重定向到 AF_XDP
skills/observability/ebpf - — 用于 virtio 测试的 QEMU 设置
skills/virtualization/qemu-kvm - — NUMA 感知的 DPDK 内存
skills/allocators/numa-programming - — 分析 DPDK lcore 热路径性能
skills/profilers/linux-perf