DPDK 20 雙埠收發測試完整指南 - Ubuntu
目錄
環境需求
硬體需求
- CPU: 支援 SSE4.2 的 x86_64 處理器(建議 4 核心以上)
- 記憶體: 最少 4GB(建議 8GB 以上)
- 網卡:
- 2 個 DPDK 支援的網路埠(可以是雙埠網卡或兩張單埠網卡)
- 支援的網卡:Intel 82599/X520/X710/E810, Mellanox ConnectX-3/4/5/6
- 虛擬環境:virtio-net, vmxnet3
軟體需求
- Ubuntu: 20.04 LTS 或 22.04 LTS
- 核心: 4.15 以上
- 編譯器: GCC 7.5+ 或 Clang 6.0+
檢查系統
# 檢查 CPU 支援
grep -m1 sse4_2 /proc/cpuinfo
# 檢查網卡
lspci | grep -i ethernet
# 檢查核心版本
uname -r
DPDK 安裝
方法一:從套件管理器安裝(簡單但版本較舊)
# Ubuntu 20.04/22.04
sudo apt update
sudo apt install dpdk dpdk-dev dpdk-doc libdpdk-dev
方法二:從原始碼編譯(推薦,最新版本)
1. 安裝依賴
sudo apt update
sudo apt install -y build-essential libnuma-dev python3-pip \
python3-pyelftools python3-setuptools meson ninja-build \
pkg-config libarchive-dev libelf-dev libpcap-dev
# Python 依賴
pip3 install meson ninja pyelftools
2. 下載 DPDK 20.11 LTS
cd /tmp
wget https://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz
tar xf dpdk-20.11.9.tar.xz
cd dpdk-stable-20.11.9
3. 編譯安裝
# 設定編譯選項
meson build
cd build
# 配置選項(可選)
meson configure -Dexamples=all
meson configure -Ddisable_drivers=regex/octeontx2
# 編譯
ninja
# 安裝
sudo ninja install
sudo ldconfig
# 驗證安裝
pkg-config --modversion libdpdk
系統配置
1. 設定大頁記憶體(Hugepages)
# 檢查當前設定
grep -i huge /proc/meminfo
# 設定 2MB 大頁(推薦用於測試)
echo 1024 | sudo tee /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
# 或設定 1GB 大頁(更好的效能)
echo 4 | sudo tee /sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages
# 掛載 hugetlbfs
sudo mkdir -p /mnt/huge
sudo mount -t hugetlbfs nodev /mnt/huge
# 永久設定(加入 /etc/fstab)
echo "nodev /mnt/huge hugetlbfs defaults 0 0" | sudo tee -antml /etc/fstab
# 永久設定大頁數量(/etc/sysctl.conf)
echo "vm.nr_hugepages = 1024" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
2. 載入核心模組
# 載入 UIO 模組
sudo modprobe uio
sudo modprobe uio_pci_generic
# 或使用 VFIO(更安全,推薦)
sudo modprobe vfio-pci
sudo chmod a+x /dev/vfio
sudo chmod 0666 /dev/vfio/*
# 自動載入(永久)
echo "uio" | sudo tee -a /etc/modules
echo "uio_pci_generic" | sudo tee -a /etc/modules
# 或
echo "vfio-pci" | sudo tee -a /etc/modules
3. 綁定網卡到 DPDK
# 查看網卡狀態
sudo dpdk-devbind.py --status
# 範例輸出:
# Network devices using kernel driver
# ====================================
# 0000:02:00.0 '82599ES 10-Gigabit' if=eth0 drv=ixgbe unused=vfio-pci
# 0000:02:00.1 '82599ES 10-Gigabit' if=eth1 drv=ixgbe unused=vfio-pci
# 綁定網卡(請替換為您的 PCI 地址)
sudo ifconfig eth0 down
sudo ifconfig eth1 down
# 使用 vfio-pci(推薦)
sudo dpdk-devbind.py -b vfio-pci 0000:02:00.0 0000:02:00.1
# 或使用 uio_pci_generic
sudo dpdk-devbind.py -b uio_pci_generic 0000:02:00.0 0000:02:00.1
# 確認綁定
sudo dpdk-devbind.py --status
4. 設定 CPU 隔離(可選但推薦)
# 編輯 /etc/default/grub
# 加入 isolcpus=2,3,4,5 到 GRUB_CMDLINE_LINUX_DEFAULT
sudo nano /etc/default/grub
# 更新 grub
sudo update-grub
sudo reboot
測試程式實作
1. 基本轉發測試程式 (l2fwd_test.c)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <signal.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
#include <rte_cycles.h>
#include <rte_lcore.h>
#include <rte_mbuf.h>
#include <rte_ether.h>
#include <rte_ip.h>
#include <rte_udp.h>
#define RX_RING_SIZE 1024
#define TX_RING_SIZE 1024
#define NUM_MBUFS 8191
#define MBUF_CACHE_SIZE 250
#define BURST_SIZE 32
static volatile bool force_quit = false;
/* 統計資訊 */
struct port_statistics {
uint64_t tx;
uint64_t rx;
uint64_t dropped;
} __rte_cache_aligned;
static struct port_statistics port_stats[2];
/* 乙太網埠配置 */
static const struct rte_eth_conf port_conf_default = {
.rxmode = {
.max_rx_pkt_len = RTE_ETHER_MAX_LEN,
},
};
/* 初始化埠 */
static inline int
port_init(uint16_t port, struct rte_mempool *mbuf_pool)
{
struct rte_eth_conf port_conf = port_conf_default;
const uint16_t rx_rings = 1, tx_rings = 1;
uint16_t nb_rxd = RX_RING_SIZE;
uint16_t nb_txd = TX_RING_SIZE;
int retval;
struct rte_eth_dev_info dev_info;
struct rte_eth_txconf txconf;
if (!rte_eth_dev_is_valid_port(port))
return -1;
/* 獲取設備資訊 */
retval = rte_eth_dev_info_get(port, &dev_info);
if (retval != 0) {
printf("Error during getting device (port %u) info: %s\n",
port, strerror(-retval));
return retval;
}
if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
port_conf.txmode.offloads |= DEV_TX_OFFLOAD_MBUF_FAST_FREE;
/* 配置設備 */
retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
if (retval != 0)
return retval;
retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd);
if (retval != 0)
return retval;
/* 配置 RX 佇列 */
for (uint16_t q = 0; q < rx_rings; q++) {
retval = rte_eth_rx_queue_setup(port, q, nb_rxd,
rte_eth_dev_socket_id(port), NULL, mbuf_pool);
if (retval < 0)
return retval;
}
txconf = dev_info.default_txconf;
txconf.offloads = port_conf.txmode.offloads;
/* 配置 TX 佇列 */
for (uint16_t q = 0; q < tx_rings; q++) {
retval = rte_eth_tx_queue_setup(port, q, nb_txd,
rte_eth_dev_socket_id(port), &txconf);
if (retval < 0)
return retval;
}
/* 啟動設備 */
retval = rte_eth_dev_start(port);
if (retval < 0)
return retval;
/* 顯示埠 MAC 地址 */
struct rte_ether_addr addr;
retval = rte_eth_macaddr_get(port, &addr);
if (retval != 0)
return retval;
printf("Port %u MAC: %02" PRIx8 ":%02" PRIx8 ":%02" PRIx8
":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 "\n",
port,
addr.addr_bytes[0], addr.addr_bytes[1],
addr.addr_bytes[2], addr.addr_bytes[3],
addr.addr_bytes[4], addr.addr_bytes[5]);
/* 啟用混雜模式 */
retval = rte_eth_promiscuous_enable(port);
if (retval != 0)
return retval;
return 0;
}
/* 主要處理迴圈 */
static void
l2fwd_main_loop(void)
{
struct rte_mbuf *pkts_burst[BURST_SIZE];
uint16_t port;
uint16_t nb_rx, nb_tx;
printf("\nCore %u forwarding packets. [Ctrl+C to quit]\n",
rte_lcore_id());
/* 主迴圈 */
while (!force_quit) {
/* 從埠 0 接收,轉發到埠 1 */
nb_rx = rte_eth_rx_burst(0, 0, pkts_burst, BURST_SIZE);
if (nb_rx > 0) {
port_stats[0].rx += nb_rx;
nb_tx = rte_eth_tx_burst(1, 0, pkts_burst, nb_rx);
port_stats[1].tx += nb_tx;
/* 釋放未傳送的封包 */
if (unlikely(nb_tx < nb_rx)) {
port_stats[1].dropped += (nb_rx - nb_tx);
for (uint16_t buf = nb_tx; buf < nb_rx; buf++)
rte_pktmbuf_free(pkts_burst[buf]);
}
}
/* 從埠 1 接收,轉發到埠 0 */
nb_rx = rte_eth_rx_burst(1, 0, pkts_burst, BURST_SIZE);
if (nb_rx > 0) {
port_stats[1].rx += nb_rx;
nb_tx = rte_eth_tx_burst(0, 0, pkts_burst, nb_rx);
port_stats[0].tx += nb_tx;
/* 釋放未傳送的封包 */
if (unlikely(nb_tx < nb_rx)) {
port_stats[0].dropped += (nb_rx - nb_tx);
for (uint16_t buf = nb_tx; buf < nb_rx; buf++)
rte_pktmbuf_free(pkts_burst[buf]);
}
}
}
}
/* 顯示統計資訊 */
static void
print_stats(void)
{
uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
total_packets_dropped = port_stats[0].dropped + port_stats[1].dropped;
total_packets_tx = port_stats[0].tx + port_stats[1].tx;
total_packets_rx = port_stats[0].rx + port_stats[1].rx;
printf("\n====== Port Statistics ======\n");
printf("Port 0: RX: %"PRIu64" TX: %"PRIu64" Dropped: %"PRIu64"\n",
port_stats[0].rx, port_stats[0].tx, port_stats[0].dropped);
printf("Port 1: RX: %"PRIu64" TX: %"PRIu64" Dropped: %"PRIu64"\n",
port_stats[1].rx, port_stats[1].tx, port_stats[1].dropped);
printf("Total: RX: %"PRIu64" TX: %"PRIu64" Dropped: %"PRIu64"\n",
total_packets_rx, total_packets_tx, total_packets_dropped);
printf("============================\n");
}
/* 信號處理 */
static void
signal_handler(int signum)
{
if (signum == SIGINT || signum == SIGTERM) {
printf("\n\nSignal %d received, preparing to exit...\n", signum);
force_quit = true;
}
}
int
main(int argc, char *argv[])
{
struct rte_mempool *mbuf_pool;
uint16_t portid;
int ret;
/* 初始化 EAL */
ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
argc -= ret;
argv += ret;
/* 檢查是否有兩個埠可用 */
if (rte_eth_dev_count_avail() < 2)
rte_exit(EXIT_FAILURE, "Error: need at least 2 ports\n");
/* 建立 mbuf 池 */
mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS,
MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE,
rte_socket_id());
if (mbuf_pool == NULL)
rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
/* 初始化所有埠 */
RTE_ETH_FOREACH_DEV(portid) {
if (portid >= 2)
break;
if (port_init(portid, mbuf_pool) != 0)
rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu16 "\n", portid);
}
/* 註冊信號處理 */
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
/* 執行主迴圈 */
l2fwd_main_loop();
/* 顯示最終統計 */
print_stats();
/* 清理 */
RTE_ETH_FOREACH_DEV(portid) {
if (portid >= 2)
break;
printf("Closing port %"PRIu16"...\n", portid);
rte_eth_dev_stop(portid);
rte_eth_dev_close(portid);
}
printf("Bye...\n");
return 0;
}
2. Makefile
# SPDX-License-Identifier: BSD-3-Clause
# binary name
APP = l2fwd_test
# all source are stored in SRCS-y
SRCS-y := l2fwd_test.c
# Build using pkg-config variables if possible
ifeq ($(shell pkg-config --exists libdpdk && echo 0),0)
all: shared
.PHONY: shared static
shared: build/$(APP)-shared
ln -sf $(APP)-shared build/$(APP)
static: build/$(APP)-static
ln -sf $(APP)-static build/$(APP)
PKGCONF ?= pkg-config
PC_FILE := $(shell $(PKGCONF) --path libdpdk 2>/dev/null)
CFLAGS += -O3 $(shell $(PKGCONF) --cflags libdpdk)
LDFLAGS_SHARED = $(shell $(PKGCONF) --libs libdpdk)
LDFLAGS_STATIC = $(shell $(PKGCONF) --static --libs libdpdk)
build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build
$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC)
build:
@mkdir -p $@
.PHONY: clean
clean:
rm -f build/$(APP) build/$(APP)-static build/$(APP)-shared
test -d build && rmdir -p build || true
else # Build using legacy build system
ifeq ($(RTE_SDK),)
$(error "Please define RTE_SDK environment variable")
endif
# Default target, detect a build directory, by looking for a path with a .config
RTE_TARGET ?= $(notdir $(abspath $(dir $(firstword $(wildcard $(RTE_SDK)/*/.config)))))
include $(RTE_SDK)/mk/rte.vars.mk
CFLAGS += -O3
CFLAGS += $(WERROR_FLAGS)
include $(RTE_SDK)/mk/rte.extapp.mk
endif
3. 進階測試程式(含封包產生器)
/* packet_generator.c - 封包產生與測試 */
#include <rte_cycles.h>
/* 產生測試封包 */
static struct rte_mbuf *
create_test_packet(struct rte_mempool *pool, uint16_t pkt_size)
{
struct rte_mbuf *pkt;
struct rte_ether_hdr *eth_hdr;
struct rte_ipv4_hdr *ip_hdr;
struct rte_udp_hdr *udp_hdr;
uint8_t *payload;
pkt = rte_pktmbuf_alloc(pool);
if (pkt == NULL)
return NULL;
/* 乙太網標頭 */
eth_hdr = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *);
rte_eth_random_addr(eth_hdr->s_addr.addr_bytes);
rte_eth_random_addr(eth_hdr->d_addr.addr_bytes);
eth_hdr->ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
/* IP 標頭 */
ip_hdr = (struct rte_ipv4_hdr *)(eth_hdr + 1);
memset(ip_hdr, 0, sizeof(*ip_hdr));
ip_hdr->version_ihl = 0x45;
ip_hdr->type_of_service = 0;
ip_hdr->total_length = rte_cpu_to_be_16(pkt_size - sizeof(*eth_hdr));
ip_hdr->packet_id = 0;
ip_hdr->fragment_offset = 0;
ip_hdr->time_to_live = 64;
ip_hdr->next_proto_id = IPPROTO_UDP;
ip_hdr->src_addr = rte_cpu_to_be_32(0x0A000001); // 10.0.0.1
ip_hdr->dst_addr = rte_cpu_to_be_32(0x0A000002); // 10.0.0.2
/* UDP 標頭 */
udp_hdr = (struct rte_udp_hdr *)(ip_hdr + 1);
udp_hdr->src_port = rte_cpu_to_be_16(1234);
udp_hdr->dst_port = rte_cpu_to_be_16(5678);
udp_hdr->dgram_len = rte_cpu_to_be_16(pkt_size - sizeof(*eth_hdr) - sizeof(*ip_hdr));
/* 填充資料 */
payload = (uint8_t *)(udp_hdr + 1);
for (int i = 0; i < pkt_size - sizeof(*eth_hdr) - sizeof(*ip_hdr) - sizeof(*udp_hdr); i++) {
payload[i] = i & 0xFF;
}
pkt->data_len = pkt_size;
pkt->pkt_len = pkt_size;
return pkt;
}
/* 效能測試函數 */
static void
run_performance_test(uint16_t port_id, struct rte_mempool *pool)
{
struct rte_mbuf *pkts[BURST_SIZE];
uint64_t start_cycles, end_cycles;
uint64_t total_packets = 0;
double duration;
printf("\nStarting performance test on port %u...\n", port_id);
/* 準備測試封包 */
for (int i = 0; i < BURST_SIZE; i++) {
pkts[i] = create_test_packet(pool, 64); // 64 位元組封包
if (pkts[i] == NULL) {
printf("Failed to create packet %d\n", i);
return;
}
}
/* 開始測試 */
start_cycles = rte_get_timer_cycles();
/* 傳送 1 百萬個封包 */
for (int i = 0; i < 1000000 / BURST_SIZE; i++) {
uint16_t nb_tx = rte_eth_tx_burst(port_id, 0, pkts, BURST_SIZE);
total_packets += nb_tx;
/* 重新分配未傳送的封包 */
for (uint16_t j = nb_tx; j < BURST_SIZE; j++) {
rte_pktmbuf_free(pkts[j]);
pkts[j] = create_test_packet(pool, 64);
}
}
end_cycles = rte_get_timer_cycles();
/* 計算結果 */
duration = (double)(end_cycles - start_cycles) / rte_get_timer_hz();
printf("Sent %lu packets in %.2f seconds\n", total_packets, duration);
printf("Rate: %.2f Mpps\n", total_packets / duration / 1000000);
printf("Throughput: %.2f Gbps\n", total_packets * 64 * 8 / duration / 1000000000);
/* 清理 */
for (int i = 0; i < BURST_SIZE; i++) {
if (pkts[i] != NULL)
rte_pktmbuf_free(pkts[i]);
}
}
執行測試
1. 編譯程式
# 使用 pkg-config
make
# 或指定 DPDK 路徑
make RTE_SDK=/usr/local/share/dpdk RTE_TARGET=x86_64-native-linux-gcc
2. 執行基本轉發測試
# 基本執行
sudo ./build/l2fwd_test
# 指定核心和記憶體
sudo ./build/l2fwd_test -l 0-3 -n 4
# 使用特定核心進行轉發
sudo ./build/l2fwd_test -l 0,2 -n 4 -- -p 0x3
# 啟用除錯訊息
sudo ./build/l2fwd_test --log-level=8
3. 使用 testpmd(DPDK 內建測試工具)
# 基本轉發模式
sudo dpdk-testpmd -l 0-3 -n 4 -- -i --portmask=0x3 --nb-cores=2
# 在 testpmd 提示符下
testpmd> set fwd mac # MAC 轉發模式
testpmd> start
# 其他轉發模式
testpmd> set fwd io # I/O 模式
testpmd> set fwd rxonly # 只接收
testpmd> set fwd txonly # 只傳送
testpmd> set fwd csum # Checksum 轉發
# 顯示統計
testpmd> show port stats all
testpmd> show fwd stats all
# 停止測試
testpmd> stop
testpmd> quit
4. 產生測試流量
使用 pktgen-dpdk
# 安裝 pktgen
git clone https://github.com/pktgen/Pktgen-DPDK.git
cd Pktgen-DPDK
make
# 執行 pktgen
sudo ./app/x86_64-native-linux-gcc/pktgen -l 0-3 -n 4 -- \
-P -m "[1:2].0, [3:4].1"
# pktgen 命令
Pktgen> set 0 count 1000000
Pktgen> set 0 size 64
Pktgen> set 0 rate 100
Pktgen> start 0
使用 MoonGen(高精度流量產生器)
# 安裝 MoonGen
git clone https://github.com/emmericp/MoonGen
cd MoonGen
./build.sh
# 執行測試
sudo ./moongen examples/l2-load-latency.lua 0 1
效能監控
1. 即時監控腳本
#!/bin/bash
# dpdk_monitor.sh
while true; do
clear
echo "===== DPDK Port Statistics ====="
# 顯示埠資訊
for port in 0 1; do
echo "Port $port:"
cat /sys/class/net/dpdk_port_$port/statistics/rx_packets 2>/dev/null || echo "N/A"
cat /sys/class/net/dpdk_port_$port/statistics/tx_packets 2>/dev/null || echo "N/A"
done
# CPU 使用率
echo -e "\n===== CPU Usage ====="
mpstat -P ALL 1 1 | tail -n +4
# 記憶體使用
echo -e "\n===== Memory Usage ====="
free -h | grep -E "Mem|Huge"
# 中斷統計
echo -e "\n===== Interrupts ====="
grep -E "eth|dpdk" /proc/interrupts | head -5
sleep 2
done
2. 效能分析
# 使用 perf 分析
sudo perf record -g ./build/l2fwd_test
sudo perf report
# 檢查 CPU 快取未命中
sudo perf stat -e cache-misses,cache-references ./build/l2fwd_test
# 追蹤系統呼叫
sudo strace -c ./build/l2fwd_test
3. 調優建議
# CPU 頻率調節
sudo cpupower frequency-set -g performance
# 關閉 CPU C-states
sudo cpupower idle-set -d 2
sudo cpupower idle-set -d 3
# NUMA 優化
numactl --cpunodebind=0 --membind=0 ./build/l2fwd_test
# 網卡中斷親和性
sudo sh -c 'echo 2 > /proc/irq/24/smp_affinity'
常見問題
Q1: 找不到網卡
# 檢查網卡是否支援
dpdk-devbind.py --status-dev net
# 確認驅動載入
lsmod | grep -E "vfio|uio"
# 重新綁定
sudo dpdk-devbind.py -u 0000:02:00.0
sudo dpdk-devbind.py -b vfio-pci 0000:02:00.0
Q2: 大頁記憶體不足
# 增加大頁數量
echo 2048 | sudo tee /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
# 檢查分配
grep -i huge /proc/meminfo
# 清理舊的大頁
sudo rm -f /mnt/huge/*
Q3: 權限問題
# 使用 vfio 需要設定權限
sudo chmod a+x /dev/vfio
sudo chmod 0666 /dev/vfio/*
# 或加入 vfio 群組
sudo usermod -a -G vfio $USER
Q4: 虛擬機測試
KVM/QEMU 設定
<!-- 虛擬機 XML 配置 -->
<interface type='hostdev'>
<source>
<address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
</source>
<model type='virtio'/>
</interface>
VirtualBox 設定
# 啟用虛擬化
VBoxManage modifyvm "VM_NAME" --hwvirtex on --nestedpaging on
# 設定網卡類型
VBoxManage modifyvm "VM_NAME" --nictype1 virtio
VBoxManage modifyvm "VM_NAME" --nictype2 virtio
Q5: 效能不佳
- 檢查 CPU 親和性
taskset -pc $(pidof l2fwd_test)
- 檢查 NUMA 節點
numactl --hardware
lstopo
- 檢查網卡設定
ethtool -g eth0 # Ring buffer 大小
ethtool -c eth0 # Coalescing 設定
ethtool -k eth0 # Offload 功能
進階配置
多佇列支援
/* 修改程式支援多佇列 */
#define NB_RX_QUEUE 4
#define NB_TX_QUEUE 4
/* RSS 配置 */
struct rte_eth_conf port_conf = {
.rxmode = {
.mq_mode = ETH_MQ_RX_RSS,
},
.rx_adv_conf = {
.rss_conf = {
.rss_key = NULL,
.rss_hf = ETH_RSS_IP | ETH_RSS_UDP | ETH_RSS_TCP,
},
},
};
使用 rte_flow 進行封包分類
/* 建立 flow rule */
struct rte_flow_attr attr = {
.ingress = 1,
};
struct rte_flow_item pattern[] = {
{
.type = RTE_FLOW_ITEM_TYPE_ETH,
},
{
.type = RTE_FLOW_ITEM_TYPE_IPV4,
},
{
.type = RTE_FLOW_ITEM_TYPE_END,
},
};
struct rte_flow_action action[] = {
{
.type = RTE_FLOW_ACTION_TYPE_QUEUE,
.conf = &(struct rte_flow_action_queue){
.index = 0,
},
},
{
.type = RTE_FLOW_ACTION_TYPE_END,
},
};
總結
這份指南涵蓋了在 Ubuntu 上使用 DPDK 20 測試雙埠收發的完整流程:
- 環境準備:安裝 DPDK、配置系統
- 程式開發:基本轉發程式、效能測試
- 執行測試:使用自定義程式或 testpmd
- 效能監控:即時監控、效能分析
- 問題排查:常見問題解決方案
關鍵要點:
- Ubuntu 完全支援 DPDK 測試
- 虛擬機也可以測試(使用 virtio-net)
- 適當的系統配置對效能至關重要
- 使用 testpmd 可快速驗證功能
根據您的硬體和需求,可以進一步調整配置以獲得最佳效能。