public inbox for dev@dpdk.org
 help / color / mirror / Atom feed
* [PATCH v2] examples/l2fwd_acl: add ACL-based L2 forwarding example
@ 2026-02-20 11:48 Harsh raj Singh
  2026-02-23  8:42 ` Konstantin Ananyev
  0 siblings, 1 reply; 4+ messages in thread
From: Harsh raj Singh @ 2026-02-20 11:48 UTC (permalink / raw)
  To: dev

From 27423213cde0594243b96114d67ade6f51cdf764 Mon Sep 17 00:00:00 2001
From: Harsh Raj Singh <harshraj215@gmail.com>
Date: Thu, 19 Feb 2026 14:16:16 +0530
Subject: [PATCH v2] examples/l2fwd_acl: add ACL-based L2 forwarding example

This example demonstrates usage 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.

The example provides a minimal reference
for developers wanting to integrate ACL
classification into packet forwarding paths.

Signed-off-by: Harsh Raj Singh <harshraj215@gmail.com>

From 27423213cde0594243b96114d67ade6f51cdf764 Mon Sep 17 00:00:00 2001
From: Harsh Raj Singh <harshraj215@gmail.com>
Date: Thu, 19 Feb 2026 14:16: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:

  - protocol
  - source IPv4
  - destination IPv4
  - source port
  - destination port

Packets matching ACL rules are forwarded,
others are dropped.

The example provides a minimal reference
for developers wanting to integrate ACL
classification into packet forwarding paths.

Signed-off-by: Harsh Raj Singh <harshraj215@gmail.com>
---
 examples/l2fwd_acl/README.md   |  18 +++
 examples/l2fwd_acl/main.c      | 247 +++++++++++++++++++++++++++++++++
 examples/l2fwd_acl/meson.build |   3 +
 examples/meson.build           |   1 +
 4 files changed, 269 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..6e05145b33
--- /dev/null
+++ b/examples/l2fwd_acl/main.c
@@ -0,0 +1,247 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * l2fwd_acl example: demonstrates use of DPDK ACL library
+ */
+
+#include <stdbool.h>
+#include <signal.h>
+#include <getopt.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_mbuf.h>
+#include <rte_tcp.h>
+#include <rte_udp.h>
+#include <rte_log.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']
diff --git a/examples/meson.build b/examples/meson.build
index 25d9c88457..bce2982229 100644
--- a/examples/meson.build
+++ b/examples/meson.build
@@ -24,6 +24,7 @@ all_examples = [
         'ipsec-secgw',
         'ipv4_multicast',
         'l2fwd',
+        'l2fwd_acl',
         'l2fwd-cat',
         'l2fwd-crypto',
         'l2fwd-event',
-- 
2.43.0

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* RE: [PATCH v2] examples/l2fwd_acl: add ACL-based L2 forwarding example
  2026-02-20 11:48 [PATCH v2] examples/l2fwd_acl: add ACL-based L2 forwarding example Harsh raj Singh
@ 2026-02-23  8:42 ` Konstantin Ananyev
       [not found]   ` <CAN33txFwhtZR4A8MfoHOMYmuVTTCxjDo6feRVfP1BFA40rmiZA@mail.gmail.com>
  0 siblings, 1 reply; 4+ messages in thread
From: Konstantin Ananyev @ 2026-02-23  8:42 UTC (permalink / raw)
  To: Harsh raj Singh, dev@dpdk.org


> This example demonstrates usage 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.
> 
> The example provides a minimal reference
> for developers wanting to integrate ACL
> classification into packet forwarding paths.

Can you probably explain why you think that
l3fwd in acl mode is not enough and extra one is needed?

> 
> Signed-off-by: Harsh Raj Singh <harshraj215@gmail.com>
> 
> From 27423213cde0594243b96114d67ade6f51cdf764 Mon Sep 17 00:00:00 2001
> From: Harsh Raj Singh <harshraj215@gmail.com>
> Date: Thu, 19 Feb 2026 14:16: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:
> 
>   - protocol
>   - source IPv4
>   - destination IPv4
>   - source port
>   - destination port
> 
> Packets matching ACL rules are forwarded,
> others are dropped.
> 
> The example provides a minimal reference
> for developers wanting to integrate ACL
> classification into packet forwarding paths.
> 
> Signed-off-by: Harsh Raj Singh <harshraj215@gmail.com>
> ---
>  examples/l2fwd_acl/README.md   |  18 +++
>  examples/l2fwd_acl/main.c      | 247 +++++++++++++++++++++++++++++++++
>  examples/l2fwd_acl/meson.build |   3 +
>  examples/meson.build           |   1 +
>  4 files changed, 269 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..6e05145b33
> --- /dev/null
> +++ b/examples/l2fwd_acl/main.c
> @@ -0,0 +1,247 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * l2fwd_acl example: demonstrates use of DPDK ACL library
> + */
> +
> +#include <stdbool.h>
> +#include <signal.h>
> +#include <getopt.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_mbuf.h>
> +#include <rte_tcp.h>
> +#include <rte_udp.h>
> +#include <rte_log.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']
> diff --git a/examples/meson.build b/examples/meson.build
> index 25d9c88457..bce2982229 100644
> --- a/examples/meson.build
> +++ b/examples/meson.build
> @@ -24,6 +24,7 @@ all_examples = [
>          'ipsec-secgw',
>          'ipv4_multicast',
>          'l2fwd',
> +        'l2fwd_acl',
>          'l2fwd-cat',
>          'l2fwd-crypto',
>          'l2fwd-event',
> --
> 2.43.0

^ permalink raw reply	[flat|nested] 4+ messages in thread

* RE: [PATCH v2] examples/l2fwd_acl: add ACL-based L2 forwarding example
       [not found]   ` <CAN33txFwhtZR4A8MfoHOMYmuVTTCxjDo6feRVfP1BFA40rmiZA@mail.gmail.com>
@ 2026-02-23  9:39     ` Konstantin Ananyev
  2026-02-23  9:44       ` Harsh raj Singh
  0 siblings, 1 reply; 4+ messages in thread
From: Konstantin Ananyev @ 2026-02-23  9:39 UTC (permalink / raw)
  To: Harsh raj Singh; +Cc: dev@dpdk.org



>Thanks for the review.
>The intention of this example is not to replace the existing l3fwd ACL mode, but to provide a minimal and easier starting point for >users who want to understand how to use the DPDK ACL library in isolation.

For that thing, I think  we do have an ACL UT: app/test/*acl*

>The l3fwd application is quite large and includes full L3 forwarding logic, routing tables, multiple lookup paths, and various >configuration options. Because of that, it can be difficult for new users to identify the specific steps required to
>define ACL fields, create and build an ACL context, insert rules, and perform classification on packets.
>This example focuses only on demonstrating ACL usage in a small, self-contained program, without routing or complex forwarding >logic. The goal is to make it easier for beginners to learn how ACL classification works before integrating it into larger applications.
>If the maintainers feel that this use case is already sufficiently covered by existing examples, I’m happy to adjust or improve the patch >accordingly.

I don't think there is a need to introduce a new sample app just for that.
Feel free to submit a patch that improves l3fwd docs and/or comments to make
It easier for newcomers to understand it.

On a slightly different subject:
when you replying to patch's comments - don't forget to hit 'reply all' button,
and please use plain-text format.

Thanks
Konstantin

 


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v2] examples/l2fwd_acl: add ACL-based L2 forwarding example
  2026-02-23  9:39     ` Konstantin Ananyev
@ 2026-02-23  9:44       ` Harsh raj Singh
  0 siblings, 0 replies; 4+ messages in thread
From: Harsh raj Singh @ 2026-02-23  9:44 UTC (permalink / raw)
  To: Konstantin Ananyev; +Cc: dev@dpdk.org

Hi Konstantin,

Thanks for the clarification.
That makes sense. I agree that improving the existing l3fwd
documentation and comments would be more useful than introducing a
separate sample application.

I’ll drop this patch and instead prepare a new patch that focuses on
improving the l3fwd ACL documentation and adding clearer explanations
in the code where appropriate.

Thanks for the guidance.

Best regards,
Harsh


On Mon, Feb 23, 2026 at 3:09 PM Konstantin Ananyev
<konstantin.ananyev@huawei.com> wrote:
>
>
>
> >Thanks for the review.
> >The intention of this example is not to replace the existing l3fwd ACL mode, but to provide a minimal and easier starting point for >users who want to understand how to use the DPDK ACL library in isolation.
>
> For that thing, I think  we do have an ACL UT: app/test/*acl*
>
> >The l3fwd application is quite large and includes full L3 forwarding logic, routing tables, multiple lookup paths, and various >configuration options. Because of that, it can be difficult for new users to identify the specific steps required to
> >define ACL fields, create and build an ACL context, insert rules, and perform classification on packets.
> >This example focuses only on demonstrating ACL usage in a small, self-contained program, without routing or complex forwarding >logic. The goal is to make it easier for beginners to learn how ACL classification works before integrating it into larger applications.
> >If the maintainers feel that this use case is already sufficiently covered by existing examples, I’m happy to adjust or improve the patch >accordingly.
>
> I don't think there is a need to introduce a new sample app just for that.
> Feel free to submit a patch that improves l3fwd docs and/or comments to make
> It easier for newcomers to understand it.
>
> On a slightly different subject:
> when you replying to patch's comments - don't forget to hit 'reply all' button,
> and please use plain-text format.
>
> Thanks
> Konstantin
>
>
>

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-02-24  7:38 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-20 11:48 [PATCH v2] examples/l2fwd_acl: add ACL-based L2 forwarding example Harsh raj Singh
2026-02-23  8:42 ` Konstantin Ananyev
     [not found]   ` <CAN33txFwhtZR4A8MfoHOMYmuVTTCxjDo6feRVfP1BFA40rmiZA@mail.gmail.com>
2026-02-23  9:39     ` Konstantin Ananyev
2026-02-23  9:44       ` Harsh raj Singh

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox