Thread (15 messages) 15 messages, 3 authors, 2022-08-19
STALE1406d

[RFC PATCH net-next 03/10] net: dsa: introduce and use robust form of dsa_broadcast()

From: Vladimir Oltean <vladimir.oltean@nxp.com>
Date: 2022-08-18 15:50:44
Subsystem: networking [dsa], networking [general], the rest · Maintainers: Andrew Lunn, Vladimir Oltean, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds

Introduce dsa_broadcast_robust(), which uses dsa_tree_notify_robust(),
and convert the bridge join and tag_8021q VLAN add procedures to use
this.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 net/dsa/dsa2.c      | 31 +++++++++++++++++++++++++++++++
 net/dsa/dsa_priv.h  |  2 ++
 net/dsa/port.c      |  6 ++++--
 net/dsa/tag_8021q.c |  8 ++++----
 4 files changed, 41 insertions(+), 6 deletions(-)
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index 50b87419342f..40134ed97980 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -94,6 +94,37 @@ int dsa_broadcast(unsigned long e, void *v)
 	return err;
 }
 
+/**
+ * dsa_broadcast_robust - Notify all DSA trees in the system, with rollback.
+ * @e: event, must be of type DSA_NOTIFIER_*
+ * @v: event-specific value.
+ * @e_rollback: event, must be of type DSA_NOTIFIER_*
+ * @v_rollback: event-specific value.
+ *
+ * Like dsa_broadcast(), except makes sure that switches are restored to the
+ * previous state in case the notifier call chain fails mid way.
+ */
+int dsa_broadcast_robust(unsigned long e, void *v, unsigned long e_rollback,
+			 void *v_rollback)
+{
+	struct dsa_switch_tree *dst;
+	int err = 0;
+
+	list_for_each_entry(dst, &dsa_tree_list, list) {
+		err = dsa_tree_notify_robust(dst, e, v, e_rollback, v_rollback);
+		if (err)
+			goto rollback;
+	}
+
+	return 0;
+
+rollback:
+	list_for_each_entry_continue_reverse(dst, &dsa_tree_list, list)
+		dsa_tree_notify(dst, e_rollback, v_rollback);
+
+	return err;
+}
+
 /**
  * dsa_lag_map() - Map LAG structure to a linear LAG array
  * @dst: Tree in which to record the mapping.
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 9db660aeee93..b4545b9ebb64 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -546,6 +546,8 @@ int dsa_tree_notify(struct dsa_switch_tree *dst, unsigned long e, void *v);
 int dsa_tree_notify_robust(struct dsa_switch_tree *dst, unsigned long e,
 			   void *v, unsigned long e_rollback, void *v_rollback);
 int dsa_broadcast(unsigned long e, void *v);
+int dsa_broadcast_robust(unsigned long e, void *v, unsigned long e_rollback,
+			 void *v_rollback);
 int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,
 			      struct net_device *master,
 			      const struct dsa_device_ops *tag_ops,
diff --git a/net/dsa/port.c b/net/dsa/port.c
index 2dd76eb1621c..6aa6402d3ed9 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -480,7 +480,8 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br,
 	brport_dev = dsa_port_to_bridge_port(dp);
 
 	info.bridge = *dp->bridge;
-	err = dsa_broadcast(DSA_NOTIFIER_BRIDGE_JOIN, &info);
+	err = dsa_broadcast_robust(DSA_NOTIFIER_BRIDGE_JOIN, &info,
+				   DSA_NOTIFIER_BRIDGE_LEAVE, &info);
 	if (err)
 		goto out_rollback;
 
@@ -1738,7 +1739,8 @@ int dsa_port_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid, bool broadcast)
 	};
 
 	if (broadcast)
-		return dsa_broadcast(DSA_NOTIFIER_TAG_8021Q_VLAN_ADD, &info);
+		return dsa_broadcast_robust(DSA_NOTIFIER_TAG_8021Q_VLAN_ADD, &info,
+					    DSA_NOTIFIER_TAG_8021Q_VLAN_DEL, &info);
 
 	return dsa_port_notify(dp, DSA_NOTIFIER_TAG_8021Q_VLAN_ADD, &info);
 }
diff --git a/net/dsa/tag_8021q.c b/net/dsa/tag_8021q.c
index 01a427800797..d20b9590a2e5 100644
--- a/net/dsa/tag_8021q.c
+++ b/net/dsa/tag_8021q.c
@@ -205,10 +205,10 @@ int dsa_switch_tag_8021q_vlan_add(struct dsa_switch *ds,
 	struct dsa_port *dp;
 	int err;
 
-	/* Since we use dsa_broadcast(), there might be other switches in other
-	 * trees which don't support tag_8021q, so don't return an error.
-	 * Or they might even support tag_8021q but have not registered yet to
-	 * use it (maybe they use another tagger currently).
+	/* Since we use dsa_broadcast_robust(), there might be other switches
+	 * in other trees which don't support tag_8021q, so don't return an
+	 * error. Or they might even support tag_8021q but have not registered
+	 * yet to use it (maybe they use another tagger currently).
 	 */
 	if (!ds->ops->tag_8021q_vlan_add || !ds->tag_8021q_ctx)
 		return 0;
-- 
2.34.1
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help