[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