[PATCH net-next v4 08/14] net: bridge: mcast: track active state, if snooping is enabled

Linus Lüssing
2026-03-07T04:46:15Z

To be able to use the upcoming SWITCHDEV_ATTR_ID_BRIDGE_MC_ACTIVE
as a potential replacement for SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED
also check and toggle the active state if multicast snooping is enabled
or disabled. So that MC_ACTIVE not only checks the querier state, but
also if multicast snooping is enabled in general.

No functional change for the fast/data path yet.

Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
---
include/uapi/linux/if_link.h | 6 ++++--
net/bridge/br_multicast.c | 15 +++++++++++++--
2 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 66c59953d301..d963be8679b5 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -748,12 +748,14 @@ enum in6_addr_gen_mode {
* @IFLA_BR_MCAST_ACTIVE_V4
* Bridge IPv4 mcast active state, read only.
*
- * 1 if an IGMP querier is present, 0 otherwise.
+ * 1 if *IFLA_BR_MCAST_SNOOPING* is enabled and an IGMP querier is present,
+ * 0 otherwise.
*
* @IFLA_BR_MCAST_ACTIVE_V6
* Bridge IPv6 mcast active state, read only.
*
- * 1 if an MLD querier is present, 0 otherwise.
+ * 1 if *IFLA_BR_MCAST_SNOOPING* is enabled and an MLD querier is present,
+ * 0 otherwise.
*/
enum {
IFLA_BR_UNSPEC,
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index f37a18f3713c..cdc921b97243 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1124,6 +1124,7 @@ static void br_multicast_notify_active(struct net_bridge_mcast *brmctx,
*
* The multicast active state is set, per protocol family, if:
*
+ * - multicast snooping is enabled
* - an IGMP/MLD querier is present
* - for own IPv6 MLD querier: an IPv6 link-local address is configured on the
* bridge
@@ -1141,6 +1142,9 @@ static void br_multicast_update_active(struct net_bridge_mcast *brmctx)

lockdep_assert_held_once(&brmctx->br->multicast_lock);

+ if (!br_opt_get(brmctx->br, BROPT_MULTICAST_ENABLED))
+ force_inactive = true;
+
br_ip4_multicast_update_active(brmctx, force_inactive);
br_ip6_multicast_update_active(brmctx, force_inactive);

@@ -1355,6 +1359,12 @@ static struct sk_buff *br_multicast_alloc_query(struct net_bridge_mcast *brmctx,
return NULL;
}

+static void br_multicast_toggle_enabled(struct net_bridge *br, bool on)
+{
+ br_opt_toggle(br, BROPT_MULTICAST_ENABLED, on);
+ br_multicast_update_active(&br->multicast_ctx);
+}
+
struct net_bridge_mdb_entry *br_multicast_new_group(struct net_bridge *br,
struct br_ip *group)
{
@@ -1368,7 +1378,7 @@ struct net_bridge_mdb_entry *br_multicast_new_group(struct net_bridge *br,
if (atomic_read(&br->mdb_hash_tbl.nelems) >= br->hash_max) {
trace_br_mdb_full(br->dev, group);
br_mc_disabled_update(br->dev, false, NULL);
- br_opt_toggle(br, BROPT_MULTICAST_ENABLED, false);
+ br_multicast_toggle_enabled(br, false);
return ERR_PTR(-E2BIG);
}

@@ -4853,7 +4863,8 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val,
if (err)
goto unlock;

- br_opt_toggle(br, BROPT_MULTICAST_ENABLED, !!val);
+ br_multicast_toggle_enabled(br, !!val);
+
if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) {
change_snoopers = true;
br_multicast_del_grps(br);
--
2.53.0