访问控制列表(ACL)用于根据预定义的规则对数据包进行过滤和分类。ACL 数据结构主要包括 ACL 参数、规则和上下文等。以下是 ACL 数据结构的详细解释,并附有中文注解。
rte_acl_param 结构体用于配置 ACL 上下文的参数。
struct rte_acl_param {
const char *name; // ACL 上下文的名称
int socket_id; // 分配内存的 NUMA 节点
uint32_t rule_size; // 规则大小
uint32_t max_rule_num; // 最大规则数量
};
rte_acl_rule 结构体用于定义单个 ACL 规则。
struct rte_acl_rule {
struct {
uint32_t category_mask; // 类别掩码
uint32_t priority; // 规则优先级
uint32_t userdata; // 用户数据
} data;
struct {
uint32_t value; // 字段值
uint32_t mask_range; // 掩码或范围
} field[RTE_ACL_MAX_FIELDS]; // 规则字段
};
rte_acl_ctx 结构体表示 ACL 上下文,用于存储和管理 ACL 规则。
#include <rte_eal.h>
#include <rte_acl.h>
#include <rte_mbuf.h>
#include <rte_ethdev.h>
#include <signal.h>
#define NUM_MBUFS 8191
#define MBUF_CACHE_SIZE 250
#define BURST_SIZE 32
#define IPV4_ADDR(a, b, c, d) ((uint32_t)(((a) & 0xff) << 24) | (((b) & 0xff) << 16) | (((c) & 0xff) << 8) | ((d) & 0xff))
static volatile bool force_quit;
struct rte_mempool *mbuf_pool;
struct rte_acl_ctx *acl_ctx;
// 信号处理函数,用于处理终止信号
static void signal_handler(int signum) {
if (signum == SIGINT || signum == SIGTERM) {
printf("\nSignal %d received, preparing to exit...\n", signum);
force_quit = true;
}
}
// 初始化 ACL 规则
static void init_acl_rules(void) {
struct rte_acl_param acl_param = {
.name = "acl_ctx", // ACL 上下文的名称
.socket_id = rte_socket_id(), // 分配内存的 NUMA 节点
.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(struct rte_acl_rule)), // 规则大小
.max_rule_num = 1024, // 最大规则数量
};
// 创建 ACL 上下文
acl_ctx = rte_acl_create(&acl_param);
if (acl_ctx == NULL) {
rte_exit(EXIT_FAILURE, "Cannot create ACL context\n");
}
// 定义 ACL 规则
struct rte_acl_rule acl_rules[2] = {
{
.data = {
.category_mask = 1, // 类别掩码
.priority = 1, // 规则优先级
.userdata = 1, // 用户数据(允许的数据包)
},
.field[0] = {
.value = IPV4_ADDR(192, 168, 1, 0), // 字段值
.mask_range = 0xFFFFFF00, // 掩码或范围(192.168.1.0/24)
}
},
{
.data = {
.category_mask = 1, // 类别掩码
.priority = 1, // 规则优先级
.userdata = 0, // 用户数据(丢弃的数据包)
},
.field[0] = {
.value = IPV4_ADDR(10, 0, 0, 0), // 字段值
.mask_range = 0xFF000000, // 掩码或范围(10.0.0.0/8)
}
}
};
// 添加 ACL 规则
if (rte_acl_add_rules(acl_ctx, acl_rules, 2) < 0) {
rte_exit(EXIT_FAILURE, "Cannot add ACL rules\n");
}
// 构建 ACL 规则
if (rte_acl_build(acl_ctx, NULL) < 0) {
rte_exit(EXIT_FAILURE, "Cannot build ACL context\n");
}
}
// 主循环函数,处理数据包并实现 ACL 和 L3 转发
static void l3fwd_acl_main_loop(void) {
struct rte_mbuf *pkts_burst[BURST_SIZE];
unsigned lcore_id;
lcore_id = rte_lcore_id();
printf("Entering main loop on lcore %u\n", lcore_id);
while (!force_quit) {
// 从每个端口接收数据包并处理
for (int port = 0; port < RTE_MAX_ETHPORTS; port++) {
uint16_t nb_rx = rte_eth_rx_burst(port, 0, pkts_burst, BURST_SIZE);
if (nb_rx == 0)
continue;
// 处理每个接收到的数据包
for (int i = 0; i < nb_rx; i++) {
struct rte_mbuf *m = pkts_burst[i];
struct rte_ipv4_hdr *ipv4_hdr;
uint32_t dst_ip;
uint8_t next_hop;
uint32_t result;
// 解析 IP 头部
ipv4_hdr = rte_pktmbuf_mtod_offset(m, struct rte_ipv4_hdr *, sizeof(struct rte_ether_hdr));
dst_ip = rte_be_to_cpu_32(ipv4_hdr->dst_addr);
// 查找 ACL 规则
rte_acl_classify(acl_ctx, (const uint8_t **)&ipv4_hdr, &result, 1, 1);
if (result == 0) {
// 丢弃不符合 ACL 规则的数据包
rte_pktmbuf_free(m);
continue;
}
// 查找 LPM 路由表
if (rte_lpm_lookup(lpm_table, dst_ip, &next_hop) == 0) {
// 转发数据包到下一跳端口
rte_eth_tx_burst(next_hop, 0, &m, 1);
} else {
// 丢弃无法找到路由的包
rte_pktmbuf_free(m);
}
}
}
}
}
int main(int argc, char **argv) {
// 初始化 DPDK 环境
int ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
force_quit = false;
// 注册信号处理函数
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
// 创建内存池,用于存放数据包
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");
// 配置以太网设备
struct rte_eth_conf port_conf = {
.rxmode = { .max_rx_pkt_len = ETHER_MAX_LEN }
};
for (int port = 0; port < RTE_MAX_ETHPORTS; port++) {
// 配置端口
if (rte_eth_dev_configure(port, 1, 1, &port_conf) < 0)
rte_exit(EXIT_FAILURE, "Cannot configure eth dev\n");
// 设置接收队列
if (rte_eth_rx_queue_setup(port, 0, 128, rte_eth_dev_socket_id(port), NULL, mbuf_pool) < 0)
rte_exit(EXIT_FAILURE, "Cannot setup rx queue\n");
// 设置发送队列
if (rte_eth_tx_queue_setup(port, 0, 128, rte_eth_dev_socket_id(port), NULL) < 0)
rte_exit(EXIT_FAILURE, "Cannot setup tx queue\n");
// 启动端口
if (rte_eth_dev_start(port) < 0)
rte_exit(EXIT_FAILURE, "Cannot start eth dev\n");
}
// 初始化 LPM 路由表
init_lpm_table();
// 初始化 ACL 规则
init_acl_rules();
// 进入主循环,处理数据包并实现 ACL 和 L3 转发
l3fwd_acl_main_loop();
// 清理资源
for (int port = 0; port < RTE_MAX_ETHPORTS; port++) {
rte_eth_dev_stop(port);
rte_eth_dev_close(port);
}
rte_mempool_free(mbuf_pool);
return 0;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。