DPDK L2fwd 源码阅读

/* SPDX-License-Identifier: BSD-3-Clause
 * Copyright(c) 2010-2016 Intel Corporation
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/queue.h>
#include <netinet/in.h>
#include <setjmp.h>
#include <stdarg.h>
#include <ctype.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <stdbool.h>

#include <rte_common.h>
#include <rte_log.h>
#include <rte_malloc.h>
#include <rte_memory.h>
#include <rte_memcpy.h>
#include <rte_eal.h>
#include <rte_launch.h>
#include <rte_atomic.h>
#include <rte_cycles.h>
#include <rte_prefetch.h>
#include <rte_lcore.h>
#include <rte_per_lcore.h>
#include <rte_branch_prediction.h>
#include <rte_interrupts.h>
#include <rte_random.h>
#include <rte_debug.h>
#include <rte_ether.h>
#include <rte_ethdev.h>
#include <rte_mempool.h>
#include <rte_mbuf.h>

static volatile bool force_quit;

/* MAC updating enabled by default */
static int mac_updating = 1;
/* MAC updating,默认开启。若不开启,则是和basicfw一样的模式。开启后,会有如下影响:

The source MAC address is replaced by the TX_PORT MAC address
源MAC地址会改写成发送端口的MAC地址

The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID
改写目的MAC地址,改写为 02:00:00:00:00:<发送端口的port id>
*/

#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1

#define MAX_PKT_BURST 32
#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
#define MEMPOOL_CACHE_SIZE 256

/*
 * Configurable number of RX/TX ring descriptors
 */
#define RTE_TEST_RX_DESC_DEFAULT 1024
#define RTE_TEST_TX_DESC_DEFAULT 1024
static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;

/* ethernet addresses of ports */
static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];

/* mask of enabled ports */
static uint32_t l2fwd_enabled_port_mask = 0;

/* list of enabled ports */
static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];

static unsigned int l2fwd_rx_queue_per_lcore = 1; // 每个逻辑核最多可以用来处理几个端口/队列(L2fwd 一个端口分配各一个收发队列)


#define MAX_RX_QUEUE_PER_LCORE 16
#define MAX_TX_QUEUE_PER_PORT 16
struct lcore_queue_conf { // 逻辑核上的队列配置
	unsigned n_rx_port; // 该 lcore 上绑定多少个端口,也作为下一个数组的下标(0 ~ n-1)。
	unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE]; // 存放一系列端口号,绑定哪些端口。
} __rte_cache_aligned;

// 这也就是 poll module driver 思想。绑定 lcore 和 port,特定的 lcore 轮询对应的一个或多个 port

struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE]; // 数组下标是 lcore id

static struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS]; // 用于缓冲未来要发送的数据包的结构,API rte_eth_tx_buffer 和 rte_eth_tx_buffer_flush使用的结构

static struct rte_eth_conf port_conf = {
	.rxmode = { // RX feature 见 flow_filtering
		.split_hdr_size = 0,
		.ignore_offload_bitfield = 1,
		.offloads = DEV_RX_OFFLOAD_CRC_STRIP,
	},
	.txmode = { // TX feature 
		.mq_mode = ETH_MQ_TX_NONE, // mq_多队列选项,有一些宏来定义用多队列发包的方法
	},
};

struct rte_mempool * l2fwd_pktmbuf_pool = NULL;

/* Per-port statistics struct */
struct l2fwd_port_statistics {
	uint64_t tx; // 发包的数量
	uint64_t rx; // 收包的数量
	uint64_t dropped; // 丢包的数量
} __rte_cache_aligned;
struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];

#define MAX_TIMER_PERIOD 86400 /* 1 day max */
/* A tsc-based timer responsible for triggering statistics printout */
// timer 负责每隔一段时间触发打印数据
static uint64_t timer_period = 10; /* default period is 10 seconds */

/* Print out statistics on packets dropped */
static void
print_stats(void)
{
	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
	unsigned portid;

	total_packets_dropped = 0;
	total_packets_tx = 0;
	total_packets_rx = 0;

	const char clr[] = { 27, '[', '2', 'J', '\0' };
	const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' };

		/* Clear screen and move to top left */
	printf("%s%s", clr, topLeft);

	printf("\nPort statistics ====================================");

	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
		/* skip disabled ports */
		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
			continue;
		printf("\nStatistics for port %u ------------------------------"
			   "\nPackets sent: %24"PRIu64
			   "\nPackets received: %20"PRIu64
			   "\nPackets dropped: %21"PRIu64,
			   portid,
			   port_statistics[portid].tx,
			   port_statistics[portid].rx,
			   port_statistics[portid].dropped);

		total_packets_dropped += port_statistics[portid].dropped;
		total_packets_tx += port_statistics[portid].tx;
		total_packets_rx += port_statistics[portid].rx;
	}
	printf("\nAggregate statistics ==============================="
		   "\nTotal packets sent: %18"PRIu64
		   "\nTotal packets received: %14"PRIu64
		   "\nTotal packets dropped: %15"PRIu64,
		   total_packets_tx,
		   total_packets_rx,
		   total_packets_dropped);
	printf("\n====================================================\n");
}

static void
l2fwd_mac_updating(struct rte_mbuf *m, unsigned dest_portid) // 改写包的 MAC 层信息
{
	struct ether_hdr *eth;
	void *tmp;

	eth = rte_pktmbuf_mtod(m, struct ether_hdr *);

	/* 02:00:00:
<think>首先,用户的问题是关于在DPDK 21.11环境中使用make编译l2fwd应用程序。用户引用了站内引用[1],但说明该引用仅供参考,不是用户真正的需求。用户强调参考上一次问题和我的回答,但我没有看到上一次问题的历史内容。在这个对话中,这是用户第一次提到DPDK,所以我需要基于当前查询回应。 用户的核心查询:"我想获取使用make在dpdk21.11环境下编译l2fwd的方法 请问在dpdk21.11中使用make编译l2fwd的方法"。意思是用户想知道如何在DPDK 21.11版本中使用make命令来编译l2fwd示例应用程序。 现在,回顾系统指令: - 所有行内数学表达式用$...$格式。 - 独立公式用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识。 用户还提到了"参考站内引用:引用[1]",但说它仅供参考。引用[1]的内容是关于清理和编译DPDK本身的,而不是特定编译l2fwd。用户说这并非真正的需求,我应该聚焦在编译l2fwd上。 关键点:我需要提供在DPDK 21.11环境中编译l2fwd的方法。l2fwdDPDK的一个示例应用程序,通常位于examples目录下。 标准步骤: 1. 确保DPDK已正确安装和配置。 2. 导航到l2fwd示例目录。 3. 使用make编译。 由于用户指定了DPDK 21.11版本,我应该确认步骤适用于该版本。DPDK 21.11可能使用meson作为默认构建系统,但用户明确要求使用“make”,所以可能是指传统的Makefile方式。 在DPDK中,示例应用程序通常有自己的Makefile,可以使用make编译,前提是DPDK环境变量设置正确。 步骤概述: - 设置环境变量如RTE_SDK和RTE_TARGET。 - cd到l2fwd目录。 - 运行make。 编译DPDK本身通常是通过meson,但编译示例应用程序可以是单独的。 用户引用中提到“make install T=i686-native-linuxapp-gcc”,这是在编译DPDK库。对于编译l2fwd,它是应用层的编译。 所以,我的回答应包括: - 设置DPDK环境。 - 编译l2fwd的具体命令。 使用中文。 结构清晰。 最后生成相关问题。 添加引用标识:由于用户提供了引用[1],我会在相关部分引用它,但聚焦在l2fwd编译。 完整回答结构: 1. 解释前提:确保DPDK已安装。 2. 描述步骤:如何编译l2fwd。 3. 提供命令示例。 4. 添加引用如果需要。 5. 生成相关问题。 相关问题应该基于主题:DPDK编译、示例应用等。 可能的步骤: - 导航到DPDK目录:假设/home/user/dpdk-21.11。 - 设置环境变量:export RTE_SDK=$(pwd)(如果当前在DPDK根目录)。 - export RTE_TARGET=build(这取决于目标;用户引用中用了i686-native-linuxapp-gcc或x86_64-native-linuxapp-gcc)。 - cd examples/l2fwd。 - make。 在DPDK 21.11中,构建系统可能统一使用meson,但示例中可能仍有Makefile支持。我应该确保准确性。 回想:在DPDK示例中,传统上使用Makefile,依赖于RTE_SDK和RTE_TARGET。 是的,所以在回答中: 首先,确保DPDK本身已编译。引用用户提供的清理和编译部分作为参考。 用户引用[1]是关于编译DPDK库的: - make clean - make install T=i686-native-linuxapp-gcc(对于32-bit) 或者x86_64-native-linuxapp-gcc(对于64-bit) 然后,对于l2fwd,类似。 在回答中: 1. 编译DPDK库(如果需要):参考引用[1]。 2. 编译l2fwd应用:cd到l2fwd目录,运行make。 具体命令。 使用中文。 生成相关问题如: 1. 如何配置DPDK环境变量? 2. l2fwd应用程序的使用方法? 3. 其他DPDK示例的编译方式? 最后,添加引用标识。 </think>以下是针对在DPDK 21.11环境中使用`make`编译`l2fwd`示例应用程序的详细步骤。`l2fwd`是一个二层转发示例程序,位于DPDK的示例目录中。编译前,确保您的系统(如32位或64位)已安装必要的依赖(如GCC、make等),并且DPDK 21.11源码包已正确解压。编译过程依赖于设置环境变量(如`RTE_SDK`和`RTE_TARGET`),这些变量指向DPDK源码目录和目标平台构建配置。 ### 编译步骤 1. **清理和编译DPDK库(可选,如有残留文件)**: 如果之前尝试过编译或安装,建议先清理DPDK库。这可以避免残留文件导致错误。参考您提供的引用[1],针对您的系统架构: - **32位系统**:使用`T=i686-native-linuxapp-gcc`。 - **64位系统**:使用`T=x86_64-native-linuxapp-gcc`。 命令示例: ```bash # 进入DPDK根目录,例如 /home/user/dpdk-21.11 cd /path/to/dpdk-21.11 # 清理残留文件 make clean # 编译并安装DPDK库(选择适合您系统的TARGET) make install T=i686-native-linuxapp-gcc # 适用于32位系统 # 或 make install T=x86_64-native-linuxapp-gcc # 适用于64位系统 ``` 此步骤确保DPDK核心库已正确构建,为编译示例应用提供基础[^1]。完成后,环境变量`RTE_TARGET`会自动设置为编译目标(如`x86_64-native-linuxapp-gcc`)。 2. **设置环境变量**: 编译`l2fwd`前,必须定义`RTE_SDK`(指向DPDK源码根目录)和`RTE_TARGET`(指向目标平台配置)。如果上一步已运行`make install`,`RTE_TARGET`通常已设置;否则手动设置: ```bash # 设置RTE_SDK为DPDK根目录路径 export RTE_SDK=/path/to/dpdk-21.11 # 设置RTE_TARGET为目标平台(与编译DPDK库时一致) export RTE_TARGET=x86_64-native-linuxapp-gcc # 示例为64位,替换为您的实际目标 ``` 验证变量是否生效: ```bash echo $RTE_SDK echo $RTE_TARGET ``` 3. **编译l2fwd应用程序**: 导航到`l2fwd`示例目录,然后使用`make`编译: ```bash # 进入l2fwd目录 cd $RTE_SDK/examples/l2fwd # 使用make编译应用程序 make ``` 编译成功后,可执行文件`build/l2fwd`会生成在examples/l2fwd目录的子目录中(路径为`$RTE_SDK/examples/l2fwd/build/app/l2fwd`)。您可以直接运行它: ```bash # 运行l2fwd(需root权限,并配置大页内存等) sudo ./build/app/l2fwd -l 0-1 -- -p 0x1 ``` ### 注意事项 - **DPDK版本兼容性**:DPDK 21.11支持传统`make`构建系统,但默认推荐使用`meson`。本方法基于`make`,确保您已禁用meson或使用旧版Makefile(DPDK 21.11示例仍保留Makefile支持)。 - **常见问题**: - 如果编译报错(如未定义变量),检查`RTE_SDK`和`RTE_TARGET`是否正确设置。 - 确保系统安装DPDK依赖包(如libnuma-dev、python等),可通过DPDK文档安装。 - 编译后,运行`l2fwd`前需配置大页内存和绑定网卡(使用`dpdk-devbind.py`工具)。 - **参考文档**:详细指南见[DPDK 21.11官方文档](https://doc.dpdk.org/guides-21.11/sample_app_ug/l2_forward_real_virtual.html)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值