On Sat, 21 Mar 2026 15:48:40 +0100
Robin Jarry <[email protected]> wrote:

> Linux TAP devices deliver all packets to userspace regardless of the
> PROMISC/ALLMULTI flags on the interface. When promiscuous mode is
> disabled, drop received packets whose destination MAC does not match
> any configured unicast or multicast address.
> 
> The receive path checks the destination MAC against the device's
> unicast address table (managed by the ethdev layer), the multicast
> address list (stored by the driver since the ethdev layer does not keep
> a copy), and accepts broadcast unconditionally. Promiscuous and
> all-multicast modes bypass the respective checks.
> 
> To support multiple unicast addresses via rte_eth_dev_mac_addr_add(),
> allocate mac_addrs with rte_zmalloc (TAP_MAX_MAC_ADDRS=16) instead of
> pointing into dev_private, and advertise the new limit in dev_infos_get.
> 
> Dropped packets are reported via per-queue xstats
> (rx_q<N>_mac_filter_drops).
> 
> Signed-off-by: Robin Jarry <[email protected]>
> ---

Here is a test for this.

From f1f093323a713abdfeb36a486a16b4b816095953 Mon Sep 17 00:00:00 2001
From: Stephen Hemminger <[email protected]>
Date: Sat, 21 Mar 2026 16:14:00 -0700
Subject: [PATCH 2/2] net/tap: add tests for software MAC address filtering

Extend the TAP PMD test suite to cover the new MAC filtering API.
Verify that dev_info advertises multiple unicast addresses,
mac_addr_add/remove and set_mc_addr_list work correctly,
and mac_filter_drops xstats are present and reset properly.

Signed-off-by: Stephen Hemminger <[email protected]>
---
 app/test/test_pmd_tap.c | 133 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 133 insertions(+)

diff --git a/app/test/test_pmd_tap.c b/app/test/test_pmd_tap.c
index dabd7d3506..bd3d4a64cc 100644
--- a/app/test/test_pmd_tap.c
+++ b/app/test/test_pmd_tap.c
@@ -757,6 +757,135 @@ test_tap_setup(void)
        return 0;
 }
 
+/*
+ * MAC address filtering tests.
+ *
+ * These exercise the new software MAC filtering paths added to TAP:
+ * mac_addr_add/remove, set_mc_addr_list, xstats for mac_filter_drops,
+ * and the increased max_mac_addrs reported in dev_info.
+ */
+
+static int
+test_tap_mac_filter_info(void)
+{
+       struct rte_eth_dev_info dev_info;
+
+       TEST_ASSERT_SUCCESS(rte_eth_dev_info_get(tap_port0, &dev_info),
+                           "failed to get dev info");
+       TEST_ASSERT(dev_info.max_mac_addrs >= 16,
+                   "max_mac_addrs=%u, expected >= 16",
+                   dev_info.max_mac_addrs);
+
+       return TEST_SUCCESS;
+}
+
+static int
+test_tap_mac_addr_ops(void)
+{
+       struct rte_ether_addr addr, addr2;
+
+       rte_eth_random_addr(addr.addr_bytes);
+       rte_eth_random_addr(addr2.addr_bytes);
+
+       TEST_ASSERT_SUCCESS(rte_eth_dev_mac_addr_add(tap_port0, &addr, 0),
+                           "mac_addr_add first address failed");
+       TEST_ASSERT_SUCCESS(rte_eth_dev_mac_addr_add(tap_port0, &addr2, 0),
+                           "mac_addr_add second address failed");
+
+       rte_eth_dev_mac_addr_remove(tap_port0, &addr2);
+       rte_eth_dev_mac_addr_remove(tap_port0, &addr);
+
+       return TEST_SUCCESS;
+}
+
+static int
+test_tap_mc_addr_list(void)
+{
+       struct rte_ether_addr mc_addrs[3];
+       int i;
+
+       for (i = 0; i < 3; i++) {
+               rte_eth_random_addr(mc_addrs[i].addr_bytes);
+               mc_addrs[i].addr_bytes[0] |= RTE_ETHER_GROUP_ADDR;
+       }
+
+       TEST_ASSERT_SUCCESS(rte_eth_dev_set_mc_addr_list(tap_port0, mc_addrs, 
3),
+                           "set_mc_addr_list(3) failed");
+       TEST_ASSERT_SUCCESS(rte_eth_dev_set_mc_addr_list(tap_port0, mc_addrs, 
1),
+                           "set_mc_addr_list(1) failed");
+       TEST_ASSERT_SUCCESS(rte_eth_dev_set_mc_addr_list(tap_port0, NULL, 0),
+                           "set_mc_addr_list(0) failed");
+
+       return TEST_SUCCESS;
+}
+
+static int
+test_tap_xstats_mac_filter(void)
+{
+       struct rte_eth_xstat_name *names = NULL;
+       struct rte_eth_xstat *xstats = NULL;
+       int nb_xstats, ret, i;
+       int found = 0;
+       int result = TEST_FAILED;
+
+       nb_xstats = rte_eth_xstats_get_names(tap_port0, NULL, 0);
+       TEST_ASSERT(nb_xstats > 0,
+                   "expected at least 1 xstat, got %d", nb_xstats);
+
+       names = calloc(nb_xstats, sizeof(*names));
+       xstats = calloc(nb_xstats, sizeof(*xstats));
+       if (names == NULL || xstats == NULL) {
+               printf("Error: failed to allocate xstats arrays\n");
+               goto out;
+       }
+
+       ret = rte_eth_xstats_get_names(tap_port0, names, nb_xstats);
+       if (ret != nb_xstats) {
+               printf("Error: xstats_get_names returned %d, expected %d\n",
+                      ret, nb_xstats);
+               goto out;
+       }
+
+       /* Verify at least one mac_filter_drops counter exists */
+       for (i = 0; i < nb_xstats; i++) {
+               if (strstr(names[i].name, "mac_filter_drops") != NULL)
+                       found++;
+       }
+       if (found == 0) {
+               printf("Error: no mac_filter_drops xstat found\n");
+               goto out;
+       }
+
+       /* Reset and verify the mac_filter_drops counters are zero */
+       if (rte_eth_xstats_reset(tap_port0) != 0) {
+               printf("Error: xstats_reset failed\n");
+               goto out;
+       }
+
+       ret = rte_eth_xstats_get(tap_port0, xstats, nb_xstats);
+       if (ret != nb_xstats) {
+               printf("Error: xstats_get after reset returned %d\n", ret);
+               goto out;
+       }
+
+       for (i = 0; i < nb_xstats; i++) {
+               if (strstr(names[i].name, "mac_filter_drops") == NULL)
+                       continue;
+               if (xstats[i].value != 0) {
+                       printf("Error: %s not zero after reset\n",
+                              names[i].name);
+                       goto out;
+               }
+       }
+
+       result = TEST_SUCCESS;
+
+out:
+       free(names);
+       free(xstats);
+       return result;
+}
+
 /* Individual test case wrappers */
 
 static int
@@ -1128,6 +1257,10 @@ static struct unit_test_suite test_pmd_tap_suite = {
                TEST_CASE(test_tap_multiqueue),
                TEST_CASE(test_tap_rx_queue_setup),
                TEST_CASE(test_tap_tx_burst),
+               TEST_CASE(test_tap_mac_filter_info),
+               TEST_CASE(test_tap_mac_addr_ops),
+               TEST_CASE(test_tap_mc_addr_list),
+               TEST_CASE(test_tap_xstats_mac_filter),
                TEST_CASES_END()
        }
 };
-- 
2.53.0

Reply via email to