v2: - Fixed indentation (tabs not spaces) - Fixed checkpatch issues - Fixed sign-off email mismatch
On Mon, Feb 23, 2026 at 9:58 AM Harsh raj Singh <[email protected]> wrote: > > do i have any update on it > > On Sat, Feb 21, 2026 at 12:13 AM Harsh raj Singh > <[email protected]> wrote: > > > > Hi, > > > > Please find attached my patch adding an ACL-based L2 forwarding example. > > > > Thanks, > > Harsh Raj Singh
From 8600ad787479e644df1abc7d213803fa77fb4fa4 Mon Sep 17 00:00:00 2001 From: Harsh Raj Singh <[email protected]> Date: Mon, 23 Feb 2026 14:30:16 +0530 Subject: [PATCH] examples/l2fwd_acl: add ACL-based L2 forwarding example This example demonstrates usage of the DPDK ACL library to classify packets based on 5-tuple fields and forward only matching packets. Signed-off-by: Harsh Raj Singh <[email protected]> --- examples/l2fwd_acl/README.md | 18 +++ examples/l2fwd_acl/main.c | 274 +++++++++++++++++++++++++++++++++ examples/l2fwd_acl/meson.build | 3 + 3 files changed, 295 insertions(+) create mode 100644 examples/l2fwd_acl/README.md create mode 100644 examples/l2fwd_acl/main.c create mode 100644 examples/l2fwd_acl/meson.build diff --git a/examples/l2fwd_acl/README.md b/examples/l2fwd_acl/README.md new file mode 100644 index 0000000000..5b5494e297 --- /dev/null +++ b/examples/l2fwd_acl/README.md @@ -0,0 +1,18 @@ +L2 Forwarding with ACL Example +============================== + +This example demonstrates use of the DPDK ACL library +to classify packets based on: + +- protocol +- source IPv4 +- destination IPv4 +- source port +- destination port + +Packets matching ACL rules are forwarded, +others are dropped. + +Run: + +./dpdk-l2fwd-acl -l 0-2 -n 4 -- -p 0x1 diff --git a/examples/l2fwd_acl/main.c b/examples/l2fwd_acl/main.c new file mode 100644 index 0000000000..9800adb8c8 --- /dev/null +++ b/examples/l2fwd_acl/main.c @@ -0,0 +1,274 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * l2fwd_acl example: demonstrates use of DPDK ACL library + */ + +#include <getopt.h> +#include <signal.h> +#include <stdbool.h> +#include <stdlib.h> + +#include <rte_acl.h> +#include <rte_eal.h> +#include <rte_ethdev.h> +#include <rte_ether.h> +#include <rte_ip.h> +#include <rte_log.h> +#include <rte_mbuf.h> +#include <rte_tcp.h> +#include <rte_udp.h> + +#define NUM_FIELDS 5 +#define MAX_RULES 32 +#define NB_MBUF 8192 +#define BURST 32 + +/* ---- Correct DPDK logging style ---- */ +#define RTE_LOGTYPE_L2FWD_ACL RTE_LOGTYPE_USER1 +#define LOGTYPE_L2FWD_ACL RTE_LOGTYPE_L2FWD_ACL + +RTE_ACL_RULE_DEF(acl_rule, NUM_FIELDS); + +struct pkt_key { + uint8_t proto; + uint32_t src_ip; + uint32_t dst_ip; + uint16_t src_port; + uint16_t dst_port; +}; + +enum { + PROTO_FIELD, + SRC_FIELD, + DST_FIELD, + SPORT_FIELD, + DPORT_FIELD +}; + +static volatile bool force_quit; +static uint32_t portmask = 0x1; + +static struct rte_acl_field_def field_defs[NUM_FIELDS] = { + { RTE_ACL_FIELD_TYPE_BITMASK, sizeof(uint8_t), PROTO_FIELD, 0, + offsetof(struct pkt_key, proto) }, + { RTE_ACL_FIELD_TYPE_MASK, sizeof(uint32_t), SRC_FIELD, 1, + offsetof(struct pkt_key, src_ip) }, + { RTE_ACL_FIELD_TYPE_MASK, sizeof(uint32_t), DST_FIELD, 2, + offsetof(struct pkt_key, dst_ip) }, + { RTE_ACL_FIELD_TYPE_RANGE, sizeof(uint16_t), SPORT_FIELD, 3, + offsetof(struct pkt_key, src_port) }, + { RTE_ACL_FIELD_TYPE_RANGE, sizeof(uint16_t), DPORT_FIELD, 3, + offsetof(struct pkt_key, dst_port) }, +}; + +static void +signal_handler(int sig) +{ + if (sig == SIGINT || sig == SIGTERM) + force_quit = true; +} + +static int +parse_args(int argc, char **argv) +{ + int opt; + + while ((opt = getopt(argc, argv, "p:")) != -1) { + switch (opt) { + case 'p': + portmask = strtoul(optarg, NULL, 16); + break; + default: + return -1; + } + } + return 0; +} + +/* ---------------- ACL INITIALIZATION ---------------- */ + +static struct rte_acl_ctx * +init_acl(void) +{ + struct rte_acl_param prm = { + .name = "acl_ctx", + .socket_id = rte_socket_id(), + .rule_size = RTE_ACL_RULE_SZ(NUM_FIELDS), + .max_rule_num = MAX_RULES, + }; + + struct rte_acl_ctx *ctx = rte_acl_create(&prm); + if (!ctx) + rte_exit(EXIT_FAILURE, "ACL create failed\n"); + + struct acl_rule rule; + memset(&rule, 0, sizeof(rule)); + + rule.data.priority = 10; + rule.data.category_mask = 1; + rule.data.userdata = 1; + + rule.field[PROTO_FIELD].value.u8 = IPPROTO_TCP; + rule.field[PROTO_FIELD].mask_range.u8 = 0xFF; + + rule.field[SRC_FIELD].value.u32 = + rte_be_to_cpu_32(RTE_IPV4(172, 17, 166, 200)); + rule.field[SRC_FIELD].mask_range.u32 = 32; + + rule.field[DST_FIELD].value.u32 = 0; + rule.field[DST_FIELD].mask_range.u32 = 0; + + rule.field[SPORT_FIELD].value.u16 = 0; + rule.field[SPORT_FIELD].mask_range.u16 = 65535; + + rule.field[DPORT_FIELD].value.u16 = 0; + rule.field[DPORT_FIELD].mask_range.u16 = 65535; + + if (rte_acl_add_rules(ctx, + (struct rte_acl_rule *)&rule, 1) < 0) + rte_exit(EXIT_FAILURE, "ACL rule add failed\n"); + + struct rte_acl_config cfg; + memset(&cfg, 0, sizeof(cfg)); + cfg.num_categories = 1; + cfg.num_fields = NUM_FIELDS; + memcpy(cfg.defs, field_defs, sizeof(field_defs)); + + if (rte_acl_build(ctx, &cfg) != 0) + rte_exit(EXIT_FAILURE, "ACL build failed\n"); + + RTE_LOG(INFO, L2FWD_ACL, "ACL ready\n"); + return ctx; +} + +/* ---------------- MAIN ---------------- */ + +int +main(int argc, char **argv) +{ + force_quit = false; + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + + int ret = rte_eal_init(argc, argv); + if (ret < 0) + rte_exit(EXIT_FAILURE, "EAL init failed\n"); + + argc -= ret; + argv += ret; + + if (parse_args(argc, argv) < 0) + rte_exit(EXIT_FAILURE, "Invalid arguments\n"); + + struct rte_acl_ctx *acl_ctx = init_acl(); + + struct rte_mempool *mp = rte_pktmbuf_pool_create( + "mbuf_pool", NB_MBUF, 256, 0, + RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); + + if (!mp) + rte_exit(EXIT_FAILURE, "mempool failed\n"); + + uint16_t port_id; + + RTE_ETH_FOREACH_DEV(port_id) { + + if (!(portmask & (1 << port_id))) + continue; + + struct rte_eth_conf conf = {0}; + + if (rte_eth_dev_configure(port_id, 1, 1, &conf) < 0) + rte_exit(EXIT_FAILURE, "port configure failed\n"); + + if (rte_eth_rx_queue_setup(port_id, 0, 1024, + rte_eth_dev_socket_id(port_id), + NULL, mp) < 0) + rte_exit(EXIT_FAILURE, "rx setup failed\n"); + + if (rte_eth_tx_queue_setup(port_id, 0, 1024, + rte_eth_dev_socket_id(port_id), + NULL) < 0) + rte_exit(EXIT_FAILURE, "tx setup failed\n"); + + if (rte_eth_dev_start(port_id) < 0) + rte_exit(EXIT_FAILURE, "port start failed\n"); + + rte_eth_promiscuous_enable(port_id); + + RTE_LOG(INFO, L2FWD_ACL, + "Started port %u\n", port_id); + } + + struct rte_mbuf *bufs[BURST]; + + while (!force_quit) { + + RTE_ETH_FOREACH_DEV(port_id) { + + if (!(portmask & (1 << port_id))) + continue; + + uint16_t nb = + rte_eth_rx_burst(port_id, 0, bufs, BURST); + + if (!nb) + continue; + + for (int i = 0; i < nb; i++) { + + struct rte_mbuf *m = bufs[i]; + struct rte_ether_hdr *eth = + rte_pktmbuf_mtod(m, + struct rte_ether_hdr *); + + if (eth->ether_type != + rte_cpu_to_be_16( + RTE_ETHER_TYPE_IPV4)) { + rte_pktmbuf_free(m); + continue; + } + + struct rte_ipv4_hdr *ip = + (struct rte_ipv4_hdr *)(eth + 1); + + struct pkt_key key = {0}; + key.proto = ip->next_proto_id; + key.src_ip = rte_be_to_cpu_32(ip->src_addr); + key.dst_ip = rte_be_to_cpu_32(ip->dst_addr); + + uint8_t *l4 = + (uint8_t *)ip + (ip->ihl * 4); + + if (key.proto == IPPROTO_TCP) { + struct rte_tcp_hdr *tcp = + (struct rte_tcp_hdr *)l4; + key.src_port = + rte_be_to_cpu_16(tcp->src_port); + key.dst_port = + rte_be_to_cpu_16(tcp->dst_port); + } else if (key.proto == IPPROTO_UDP) { + struct rte_udp_hdr *udp = + (struct rte_udp_hdr *)l4; + key.src_port = + rte_be_to_cpu_16(udp->src_port); + key.dst_port = + rte_be_to_cpu_16(udp->dst_port); + } + + const uint8_t *data[1] = { + (const uint8_t *)&key, + }; + uint32_t res[1]; + + rte_acl_classify(acl_ctx, data, res, 1, 1); + + if (res[0]) + rte_eth_tx_burst(port_id, 0, &m, 1); + else + rte_pktmbuf_free(m); + } + } + } + + return 0; +} diff --git a/examples/l2fwd_acl/meson.build b/examples/l2fwd_acl/meson.build new file mode 100644 index 0000000000..331dd545e9 --- /dev/null +++ b/examples/l2fwd_acl/meson.build @@ -0,0 +1,3 @@ +sources = files('main.c') + +deps += ['acl', 'ethdev', 'mbuf', 'net'] -- 2.43.0

