访问控制列表(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;
}

putao
8 声望1 粉丝

推动世界向前发展,改善民生。