linux-doc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Linus Lüssing" <linus.luessing@c0d3.blue>
To: bridge@lists.linux.dev
Cc: netdev@vger.kernel.org, openwrt-devel@lists.openwrt.org,
	linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org,
	"Nikolay Aleksandrov" <razor@blackwall.org>,
	"Ido Schimmel" <idosch@nvidia.com>,
	"Ivan Vecera" <ivecera@redhat.com>,
	"Jiri Pirko" <jiri@resnulli.us>,
	"Vladimir Oltean" <olteanv@gmail.com>,
	"Andrew Lunn" <andrew@lunn.ch>,
	"Jonathan Corbet" <corbet@lwn.net>,
	"Simon Horman" <horms@kernel.org>,
	"Paolo Abeni" <pabeni@redhat.com>,
	"Jakub Kicinski" <kuba@kernel.org>,
	"Eric Dumazet" <edumazet@google.com>,
	"David S . Miller" <davem@davemloft.net>,
	"Kuniyuki Iwashima" <kuniyu@amazon.com>,
	"Stanislav Fomichev" <sdf@fomichev.me>,
	"Xiao Liang" <shaw.leon@gmail.com>,
	"Markus Stockhausen" <markus.stockhausen@gmx.de>,
	"Jan Hoffmann" <jan.christian.hoffmann@gmail.com>,
	"Birger Koblitz" <git@birger-koblitz.de>,
	"Bjørn Mork" <bjorn@mork.no>,
	"Linus Lüssing" <linus.luessing@c0d3.blue>
Subject: [PATCH net-next 5/5] net: dsa: forward bridge/switchdev mcast active notification
Date: Thu, 22 May 2025 21:17:07 +0200	[thread overview]
Message-ID: <20250522195952.29265-6-linus.luessing@c0d3.blue> (raw)
In-Reply-To: <20250522195952.29265-1-linus.luessing@c0d3.blue>

Add a new "port_mdb_active()" handler to the DSA API. This allows DSA
drivers to receive the multicast active notification from the
bridge. So that switch drivers can act on it accordingly, especially
to avoid packetloss.

The switchdev notifier "handled" attribute is propagated, too, so that a
DSA based switch driver can decide whether it wants to act on the event
for each port individually or only on the first one, on behalf of all
others.

Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
---
 Documentation/networking/dsa/dsa.rst |  9 +++++++++
 include/net/dsa.h                    |  5 +++++
 net/dsa/port.c                       | 19 +++++++++++++++++++
 net/dsa/port.h                       |  3 +++
 net/dsa/switch.c                     | 13 +++++++++++++
 net/dsa/switch.h                     | 11 ++++++++++-
 net/dsa/user.c                       | 21 ++++++++++++++++++++-
 7 files changed, 79 insertions(+), 2 deletions(-)

diff --git a/Documentation/networking/dsa/dsa.rst b/Documentation/networking/dsa/dsa.rst
index 7b2e69cd7ef0..0b0be619be04 100644
--- a/Documentation/networking/dsa/dsa.rst
+++ b/Documentation/networking/dsa/dsa.rst
@@ -1025,6 +1025,15 @@ Bridge VLAN filtering
   the specified MAC address from the specified VLAN ID if it was mapped into
   this port forwarding database.
 
+- ``port_mdb_active``: bridge layer function invoked when the bridge starts (or
+  stops) to actively apply multicast snooping to multicast payload, i.e. when
+  multicast snooping is enabled and a multicast querier is present on the link
+  for a particular protocol family (or not). A switch should (by default) ensure:
+  To flood multicast packets for the given protocol family if multicast snooping
+  is inactive - to avoid multicast (and consequently also IPv6 unicast, which
+  depends on multicast for NDP) packet loss. And should (by default) avoid
+  forwarding to an active port if there is no listener or multicast router on it.
+
 Link aggregation
 ----------------
 
diff --git a/include/net/dsa.h b/include/net/dsa.h
index a0a9481c52c2..edc0e6821ba2 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -1080,6 +1080,11 @@ struct dsa_switch_ops {
 	int	(*port_mdb_del)(struct dsa_switch *ds, int port,
 				const struct switchdev_obj_port_mdb *mdb,
 				struct dsa_db db);
+	int	(*port_mdb_active)(struct dsa_switch *ds, int port,
+				   const struct switchdev_mc_active mc_active,
+				   struct netlink_ext_ack *extack,
+				   bool handled);
+
 	/*
 	 * RXNFC
 	 */
diff --git a/net/dsa/port.c b/net/dsa/port.c
index 5c9d1798e830..a1e692d9122e 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -1290,6 +1290,25 @@ int dsa_port_bridge_host_mdb_del(const struct dsa_port *dp,
 	return dsa_port_host_mdb_del(dp, mdb, db);
 }
 
+int dsa_port_bridge_mdb_active(const struct dsa_port *dp,
+			       const struct switchdev_mc_active mc_active,
+			       struct netlink_ext_ack *extack,
+			       bool handled)
+{
+	struct dsa_switch *ds = dp->ds;
+	struct dsa_notifier_mdb_active_info info = {
+		.dp = dp,
+		.mc_active = mc_active,
+		.extack = extack,
+		.handled = handled,
+	};
+
+	if (!ds->ops->port_mdb_active)
+		return -EOPNOTSUPP;
+
+	return dsa_port_notify(dp, DSA_NOTIFIER_MDB_ACTIVE, &info);
+}
+
 int dsa_port_vlan_add(struct dsa_port *dp,
 		      const struct switchdev_obj_port_vlan *vlan,
 		      struct netlink_ext_ack *extack)
diff --git a/net/dsa/port.h b/net/dsa/port.h
index 6bc3291573c0..0e92815e7de2 100644
--- a/net/dsa/port.h
+++ b/net/dsa/port.h
@@ -75,6 +75,9 @@ int dsa_port_bridge_host_mdb_add(const struct dsa_port *dp,
 				 const struct switchdev_obj_port_mdb *mdb);
 int dsa_port_bridge_host_mdb_del(const struct dsa_port *dp,
 				 const struct switchdev_obj_port_mdb *mdb);
+int dsa_port_bridge_mdb_active(const struct dsa_port *dp,
+			       const struct switchdev_mc_active mc_active,
+			       struct netlink_ext_ack *extack, bool handled);
 int dsa_port_pre_bridge_flags(const struct dsa_port *dp,
 			      struct switchdev_brport_flags flags,
 			      struct netlink_ext_ack *extack);
diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index 3d2feeea897b..5b30dfe4bebd 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -652,6 +652,16 @@ static int dsa_switch_host_mdb_del(struct dsa_switch *ds,
 	return err;
 }
 
+static int dsa_switch_mdb_active(struct dsa_switch *ds,
+				 struct dsa_notifier_mdb_active_info *info)
+{
+	if (!ds->ops->port_mdb_active)
+		return -EOPNOTSUPP;
+
+	return ds->ops->port_mdb_active(ds, info->dp->index, info->mc_active,
+					info->extack, info->handled);
+}
+
 /* Port VLANs match on the targeted port and on all DSA ports */
 static bool dsa_port_vlan_match(struct dsa_port *dp,
 				struct dsa_notifier_vlan_info *info)
@@ -1026,6 +1036,9 @@ static int dsa_switch_event(struct notifier_block *nb,
 	case DSA_NOTIFIER_HOST_MDB_DEL:
 		err = dsa_switch_host_mdb_del(ds, info);
 		break;
+	case DSA_NOTIFIER_MDB_ACTIVE:
+		err = dsa_switch_mdb_active(ds, info);
+		break;
 	case DSA_NOTIFIER_VLAN_ADD:
 		err = dsa_switch_vlan_add(ds, info);
 		break;
diff --git a/net/dsa/switch.h b/net/dsa/switch.h
index be0a2749cd97..69a5004e48c8 100644
--- a/net/dsa/switch.h
+++ b/net/dsa/switch.h
@@ -24,6 +24,7 @@ enum {
 	DSA_NOTIFIER_MDB_DEL,
 	DSA_NOTIFIER_HOST_MDB_ADD,
 	DSA_NOTIFIER_HOST_MDB_DEL,
+	DSA_NOTIFIER_MDB_ACTIVE,
 	DSA_NOTIFIER_VLAN_ADD,
 	DSA_NOTIFIER_VLAN_DEL,
 	DSA_NOTIFIER_HOST_VLAN_ADD,
@@ -66,13 +67,21 @@ struct dsa_notifier_lag_fdb_info {
 	struct dsa_db db;
 };
 
-/* DSA_NOTIFIER_MDB_* */
+/* DSA_NOTIFIER_MDB_{ADD,DEL} */
 struct dsa_notifier_mdb_info {
 	const struct dsa_port *dp;
 	const struct switchdev_obj_port_mdb *mdb;
 	struct dsa_db db;
 };
 
+/* DSA_NOTIFIER_MDB_ACTIVE */
+struct dsa_notifier_mdb_active_info {
+	const struct dsa_port *dp;
+	const struct switchdev_mc_active mc_active;
+	struct netlink_ext_ack *extack;
+	int handled;
+};
+
 /* DSA_NOTIFIER_LAG_* */
 struct dsa_notifier_lag_info {
 	const struct dsa_port *dp;
diff --git a/net/dsa/user.c b/net/dsa/user.c
index 804dc7dac4f2..231b92d6e7b9 100644
--- a/net/dsa/user.c
+++ b/net/dsa/user.c
@@ -603,7 +603,7 @@ static int dsa_user_port_attr_set(struct net_device *dev, const void *ctx,
 	struct dsa_port *dp = dsa_user_to_port(dev);
 	int ret;
 
-	if (ctx && ctx != dp)
+	if (ctx && ctx != dp && attr->id != SWITCHDEV_ATTR_ID_BRIDGE_MC_ACTIVE)
 		return 0;
 
 	switch (attr->id) {
@@ -657,6 +657,15 @@ static int dsa_user_port_attr_set(struct net_device *dev, const void *ctx,
 
 		ret = dsa_port_vlan_msti(dp, &attr->u.vlan_msti);
 		break;
+	case SWITCHDEV_ATTR_ID_BRIDGE_MC_ACTIVE:
+		const bool *handled = ctx;
+
+		if (!dsa_port_offloads_bridge_dev(dp, attr->orig_dev))
+			return -EOPNOTSUPP;
+
+		ret = dsa_port_bridge_mdb_active(dp, attr->u.mc_active, extack,
+						 *handled);
+		break;
 	default:
 		ret = -EOPNOTSUPP;
 		break;
@@ -3758,6 +3767,11 @@ static int dsa_user_switchdev_event(struct notifier_block *unused,
 
 	switch (event) {
 	case SWITCHDEV_PORT_ATTR_SET:
+		struct switchdev_notifier_port_attr_info *item = ptr;
+
+		if (item && item->attr->id == SWITCHDEV_ATTR_ID_BRIDGE_MC_ACTIVE)
+			item->info.ctx = &item->handled;
+
 		err = switchdev_handle_port_attr_set(dev, ptr,
 						     dsa_user_dev_check,
 						     dsa_user_port_attr_set);
@@ -3796,6 +3810,11 @@ static int dsa_user_switchdev_blocking_event(struct notifier_block *unused,
 							    dsa_user_port_obj_del);
 		return notifier_from_errno(err);
 	case SWITCHDEV_PORT_ATTR_SET:
+		struct switchdev_notifier_port_attr_info *item = ptr;
+
+		if (item && item->attr->id == SWITCHDEV_ATTR_ID_BRIDGE_MC_ACTIVE)
+			item->info.ctx = &item->handled;
+
 		err = switchdev_handle_port_attr_set(dev, ptr,
 						     dsa_user_dev_check,
 						     dsa_user_port_attr_set);
-- 
2.49.0


  parent reply	other threads:[~2025-05-22 20:00 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-05-22 19:17 [PATCH net-next 0/5] net: bridge: propagate safe mcast snooping to switchdev + DSA Linus Lüssing
2025-05-22 19:17 ` [PATCH net-next 1/5] net: bridge: mcast: explicitly track active state Linus Lüssing
2025-05-23  9:44   ` kernel test robot
2025-05-25 17:13   ` Ido Schimmel
2025-05-22 19:17 ` [PATCH net-next 2/5] net: bridge: mcast: export ip{4,6}_active state to netlink Linus Lüssing
2025-05-25 17:20   ` Ido Schimmel
2025-05-22 19:17 ` [PATCH net-next 3/5] net: bridge: mcast: check if snooping is enabled for active state Linus Lüssing
2025-05-23 13:02   ` Simon Horman
2025-05-22 19:17 ` [PATCH net-next 4/5] net: bridge: switchdev: notify on mcast active changes Linus Lüssing
2025-05-22 19:17 ` Linus Lüssing [this message]
2025-05-23  9:24   ` [PATCH net-next 5/5] net: dsa: forward bridge/switchdev mcast active notification kernel test robot
2025-05-23  9:44   ` kernel test robot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250522195952.29265-6-linus.luessing@c0d3.blue \
    --to=linus.luessing@c0d3.blue \
    --cc=andrew@lunn.ch \
    --cc=bjorn@mork.no \
    --cc=bridge@lists.linux.dev \
    --cc=corbet@lwn.net \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=git@birger-koblitz.de \
    --cc=horms@kernel.org \
    --cc=idosch@nvidia.com \
    --cc=ivecera@redhat.com \
    --cc=jan.christian.hoffmann@gmail.com \
    --cc=jiri@resnulli.us \
    --cc=kuba@kernel.org \
    --cc=kuniyu@amazon.com \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=markus.stockhausen@gmx.de \
    --cc=netdev@vger.kernel.org \
    --cc=olteanv@gmail.com \
    --cc=openwrt-devel@lists.openwrt.org \
    --cc=pabeni@redhat.com \
    --cc=razor@blackwall.org \
    --cc=sdf@fomichev.me \
    --cc=shaw.leon@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).