All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3)
@ 2022-05-23 10:42 Vladimir Oltean
  2022-05-23 10:42 ` [RFC PATCH net-next 01/12] net: introduce iterators over synced hw addresses Vladimir Oltean
                   ` (13 more replies)
  0 siblings, 14 replies; 31+ messages in thread
From: Vladimir Oltean @ 2022-05-23 10:42 UTC (permalink / raw)
  To: netdev
  Cc: Jakub Kicinski, Florian Fainelli, Vivien Didelot, Andrew Lunn,
	Vladimir Oltean, Tobias Waldekranz, Marek Behún,
	Ansuel Smith, DENG Qingfang, Alvin Šipraga, Claudiu Manoil,
	Alexandre Belloni, UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

From: Vladimir Oltean <vladimir.oltean@nxp.com>

Note: this patch set isn't probably tested nearly well enough, and
contains (at least minor) bugs. Don't do crazy things with it. I'm
posting it to get feedback on the proposed UAPI.

Those who have been following part 1:
https://patchwork.kernel.org/project/netdevbpf/cover/20220511095020.562461-1-vladimir.oltean@nxp.com/
and part 2:
https://patchwork.kernel.org/project/netdevbpf/cover/20220521213743.2735445-1-vladimir.oltean@nxp.com/
will know that I am trying to enable the second internal port pair from
the NXP LS1028A Felix switch for DSA-tagged traffic via "ocelot-8021q".
This series represents part 3 of that effort.

Covered here are some code structure changes so that DSA monitors
changeupper events of its masters, as well as new UAPI introduction via
rtnetlink for changing the current master. Note, in the case of a LAG
DSA master, DSA user ports can be assigned to the LAG in 2 ways, either
through this new IFLA_DSA_MASTER, or simply when their existing DSA
master joins a LAG.

Compared to previous attempts to introduce support for multiple CPU ports:
https://lore.kernel.org/netdev/20210410133454.4768-1-ansuelsmth@gmail.com/

my proposal is to not change anything in the default behavior (i.e.
still start off with the first CPU port from the device tree as the only
active CPU port). But focus is instead put on being able to live-change
what the user-to-CPU-port affinity is. Marek Behun has expressed a
potential use case as being to dynamically load balance the termination
of ports between CPU ports, and that should be best handled by a user
space daemon if it only had the means - this creates the means.

Host address filtering is interesting with multiple CPU ports.
There are 2 types of host filtered addresses to consider:
- standalone MAC addresses of ports. These are either inherited from the
  respective DSA masters of the ports, or from the device tree blob.
- local bridge FDB entries.

Traditionally, DSA manages host-filtered addresses by calling
port_fdb_add(dp->cpu_dp->index) in the appropriate database.
But for example, when we have 2 bridged DSA user ports, one with CPU
port A and the other with CPU port B, and the bridge offloads a local
FDB entry for 00:01:02:03:04:05, DSA would attempt to first call
port_fdb_add(A, 00:01:02:03:04:05, DSA_DB_BRIDGE), then
port_fdb_add(B, 00:01:02:03:04:05, DSA_DB_BRIDGE). And since an FDB
entry can have a single destination, the second port_fdb_add()
overwrites the first one, and locally terminated traffic for the ports
assigned to CPU port A is broken.

What should be done in that situation, at least with the HW I'm working
with, is that the host filtered addresses should be delivered towards a
"multicast" destination that covers both CPU ports, and let the
forwarding matrix eliminate the CPU port that the current user port
isn't affine to.

In my proposed patch set, the Felix driver does exactly that: host
filtered addresses are learned towards a special PGID_CPU that has both
tag_8021q CPU ports as destinations.

I have considered introducing new dsa_switch_ops API in the form of
host_fdb_add(user port) and host_fdb_del(user port) rather than calling
port_fdb_add(cpu port). After all, this would be similar to the newly
introduced port_set_host_flood(user port). But I need to think a bit
more whether it's needed right away.

Finally, there's LAG. Proposals have been made before to describe in DT
that CPU ports are under a LAG, the idea being that we could then do the
same for DSA (cascade) ports. The common problem is that shared (CPU and
DSA) ports have no netdev exposed.

I didn't do that, instead I went for the more natural approach of saying
that if the CPU ports are in a LAG, then the DSA masters are in a
symmetric LAG as well. So why not just monitor when the DSA masters join
a LAG, and piggyback on that configuration and make DSA reconfigure
itself accordingly.

So LAG devices can now be DSA masters, and this is accomplished by
populating their dev->dsa_ptr. Note that we do not create a specific
struct dsa_port to populate their dsa_ptr, instead we reuse the dsa_ptr
of one of the physical DSA masters (the first one, in fact).

Vladimir Oltean (12):
  net: introduce iterators over synced hw addresses
  net: dsa: walk through all changeupper notifier functions
  net: dsa: don't stop at NOTIFY_OK when calling
    ds->ops->port_prechangeupper
  net: bridge: move DSA master bridging restriction to DSA
  net: dsa: existing DSA masters cannot join upper interfaces
  net: dsa: only bring down user ports assigned to a given DSA master
  net: dsa: all DSA masters must be down when changing the tagging
    protocol
  net: dsa: use dsa_tree_for_each_cpu_port in
    dsa_tree_{setup,teardown}_master
  net: dsa: introduce dsa_port_get_master()
  net: dsa: allow the DSA master to be seen and changed through
    rtnetlink
  net: dsa: allow masters to join a LAG
  net: dsa: felix: add support for changing DSA master

 drivers/net/dsa/bcm_sf2.c                     |   4 +-
 drivers/net/dsa/bcm_sf2_cfp.c                 |   4 +-
 drivers/net/dsa/lan9303-core.c                |   4 +-
 drivers/net/dsa/ocelot/felix.c                | 117 ++++-
 drivers/net/dsa/ocelot/felix.h                |   3 +
 .../net/ethernet/mediatek/mtk_ppe_offload.c   |   2 +-
 drivers/net/ethernet/mscc/ocelot.c            |   3 +-
 include/linux/netdevice.h                     |   6 +
 include/net/dsa.h                             |  23 +
 include/soc/mscc/ocelot.h                     |   1 +
 include/uapi/linux/if_link.h                  |  10 +
 net/bridge/br_if.c                            |  20 -
 net/dsa/Makefile                              |  10 +-
 net/dsa/dsa.c                                 |   9 +
 net/dsa/dsa2.c                                |  72 ++--
 net/dsa/dsa_priv.h                            |  18 +-
 net/dsa/master.c                              |  62 ++-
 net/dsa/netlink.c                             |  62 +++
 net/dsa/port.c                                | 162 ++++++-
 net/dsa/slave.c                               | 404 +++++++++++++++++-
 net/dsa/switch.c                              |  22 +-
 net/dsa/tag_8021q.c                           |   4 +-
 22 files changed, 915 insertions(+), 107 deletions(-)
 create mode 100644 net/dsa/netlink.c

-- 
2.25.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [RFC PATCH net-next 01/12] net: introduce iterators over synced hw addresses
  2022-05-23 10:42 [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3) Vladimir Oltean
@ 2022-05-23 10:42 ` Vladimir Oltean
  2022-05-23 17:54   ` Florian Fainelli
  2022-05-23 10:42 ` [RFC PATCH net-next 02/12] net: dsa: walk through all changeupper notifier functions Vladimir Oltean
                   ` (12 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Vladimir Oltean @ 2022-05-23 10:42 UTC (permalink / raw)
  To: netdev
  Cc: Jakub Kicinski, Florian Fainelli, Vivien Didelot, Andrew Lunn,
	Vladimir Oltean, Tobias Waldekranz, Marek Behún,
	Ansuel Smith, DENG Qingfang, Alvin Šipraga, Claudiu Manoil,
	Alexandre Belloni, UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

From: Vladimir Oltean <vladimir.oltean@nxp.com>

Some network drivers use __dev_mc_sync()/__dev_uc_sync() and therefore
program the hardware only with addresses with a non-zero sync_cnt.

Some of the above drivers also need to save/restore the address
filtering lists when certain events happen, and they need to walk
through the struct net_device :: uc and struct net_device :: mc lists.
But these lists contain unsynced addresses too.

To keep the appearance of an elementary form of data encapsulation,
provide iterators through these lists that only look at entries with a
non-zero sync_cnt, instead of filtering entries out from device drivers.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 include/linux/netdevice.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index f615a66c89e9..47b59f99b037 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -253,11 +253,17 @@ struct netdev_hw_addr_list {
 #define netdev_uc_empty(dev) netdev_hw_addr_list_empty(&(dev)->uc)
 #define netdev_for_each_uc_addr(ha, dev) \
 	netdev_hw_addr_list_for_each(ha, &(dev)->uc)
+#define netdev_for_each_synced_uc_addr(_ha, _dev) \
+	netdev_for_each_uc_addr((_ha), (_dev)) \
+		if ((_ha)->sync_cnt)
 
 #define netdev_mc_count(dev) netdev_hw_addr_list_count(&(dev)->mc)
 #define netdev_mc_empty(dev) netdev_hw_addr_list_empty(&(dev)->mc)
 #define netdev_for_each_mc_addr(ha, dev) \
 	netdev_hw_addr_list_for_each(ha, &(dev)->mc)
+#define netdev_for_each_synced_mc_addr(_ha, _dev) \
+	netdev_for_each_mc_addr((_ha), (_dev)) \
+		if ((_ha)->sync_cnt)
 
 struct hh_cache {
 	unsigned int	hh_len;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH net-next 02/12] net: dsa: walk through all changeupper notifier functions
  2022-05-23 10:42 [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3) Vladimir Oltean
  2022-05-23 10:42 ` [RFC PATCH net-next 01/12] net: introduce iterators over synced hw addresses Vladimir Oltean
@ 2022-05-23 10:42 ` Vladimir Oltean
  2022-05-23 18:11   ` Florian Fainelli
  2022-05-23 10:42 ` [RFC PATCH net-next 03/12] net: dsa: don't stop at NOTIFY_OK when calling ds->ops->port_prechangeupper Vladimir Oltean
                   ` (11 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Vladimir Oltean @ 2022-05-23 10:42 UTC (permalink / raw)
  To: netdev
  Cc: Jakub Kicinski, Florian Fainelli, Vivien Didelot, Andrew Lunn,
	Vladimir Oltean, Tobias Waldekranz, Marek Behún,
	Ansuel Smith, DENG Qingfang, Alvin Šipraga, Claudiu Manoil,
	Alexandre Belloni, UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

From: Vladimir Oltean <vladimir.oltean@nxp.com>

Traditionally, DSA has had a single netdev notifier handling function
for each device type.

For the sake of code cleanliness, we would like to introduce more
handling functions which do one thing, but the conditions for entering
these functions start to overlap. Example: a handling function which
tracks whether any bridges contain both DSA and non-DSA interfaces.
Either this is placed before dsa_slave_changeupper(), case in which it
will prevent that function from executing, or we place it after
dsa_slave_changeupper(), case in which we will prevent it from
executing. The other alternative is to ignore errors from the new
handling function (not ideal).

To support this usage, we need to change the pattern. In the new model,
we enter all notifier handling sub-functions, and exit with NOTIFY_DONE
if there is nothing to do. This allows the sub-functions to be
relatively free-form and independent from each other.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 net/dsa/slave.c | 37 ++++++++++++++++++++++++++++---------
 1 file changed, 28 insertions(+), 9 deletions(-)

diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 17c7ec8b2245..8d62c634c331 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -2452,6 +2452,9 @@ static int dsa_slave_changeupper(struct net_device *dev,
 	struct netlink_ext_ack *extack;
 	int err = NOTIFY_DONE;
 
+	if (!dsa_slave_dev_check(dev))
+		return err;
+
 	extack = netdev_notifier_info_to_extack(&info->info);
 
 	if (netif_is_bridge_master(info->upper_dev)) {
@@ -2506,6 +2509,9 @@ static int dsa_slave_prechangeupper(struct net_device *dev,
 {
 	struct dsa_port *dp = dsa_slave_to_port(dev);
 
+	if (!dsa_slave_dev_check(dev))
+		return NOTIFY_DONE;
+
 	if (netif_is_bridge_master(info->upper_dev) && !info->linking)
 		dsa_port_pre_bridge_leave(dp, info->upper_dev);
 	else if (netif_is_lag_master(info->upper_dev) && !info->linking)
@@ -2526,6 +2532,9 @@ dsa_slave_lag_changeupper(struct net_device *dev,
 	int err = NOTIFY_DONE;
 	struct dsa_port *dp;
 
+	if (!netif_is_lag_master(dev))
+		return err;
+
 	netdev_for_each_lower_dev(dev, lower, iter) {
 		if (!dsa_slave_dev_check(lower))
 			continue;
@@ -2555,6 +2564,9 @@ dsa_slave_lag_prechangeupper(struct net_device *dev,
 	int err = NOTIFY_DONE;
 	struct dsa_port *dp;
 
+	if (!netif_is_lag_master(dev))
+		return err;
+
 	netdev_for_each_lower_dev(dev, lower, iter) {
 		if (!dsa_slave_dev_check(lower))
 			continue;
@@ -2676,22 +2688,29 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb,
 		if (err != NOTIFY_DONE)
 			return err;
 
-		if (dsa_slave_dev_check(dev))
-			return dsa_slave_prechangeupper(dev, ptr);
+		err = dsa_slave_prechangeupper(dev, ptr);
+		if (notifier_to_errno(err))
+			return err;
 
-		if (netif_is_lag_master(dev))
-			return dsa_slave_lag_prechangeupper(dev, ptr);
+		err = dsa_slave_lag_prechangeupper(dev, ptr);
+		if (notifier_to_errno(err))
+			return err;
 
 		break;
 	}
-	case NETDEV_CHANGEUPPER:
-		if (dsa_slave_dev_check(dev))
-			return dsa_slave_changeupper(dev, ptr);
+	case NETDEV_CHANGEUPPER: {
+		int err;
+
+		err = dsa_slave_changeupper(dev, ptr);
+		if (notifier_to_errno(err))
+			return err;
 
-		if (netif_is_lag_master(dev))
-			return dsa_slave_lag_changeupper(dev, ptr);
+		err = dsa_slave_lag_changeupper(dev, ptr);
+		if (notifier_to_errno(err))
+			return err;
 
 		break;
+	}
 	case NETDEV_CHANGELOWERSTATE: {
 		struct netdev_notifier_changelowerstate_info *info = ptr;
 		struct dsa_port *dp;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH net-next 03/12] net: dsa: don't stop at NOTIFY_OK when calling ds->ops->port_prechangeupper
  2022-05-23 10:42 [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3) Vladimir Oltean
  2022-05-23 10:42 ` [RFC PATCH net-next 01/12] net: introduce iterators over synced hw addresses Vladimir Oltean
  2022-05-23 10:42 ` [RFC PATCH net-next 02/12] net: dsa: walk through all changeupper notifier functions Vladimir Oltean
@ 2022-05-23 10:42 ` Vladimir Oltean
  2022-05-23 17:56   ` Florian Fainelli
  2022-05-23 10:42 ` [RFC PATCH net-next 04/12] net: bridge: move DSA master bridging restriction to DSA Vladimir Oltean
                   ` (10 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Vladimir Oltean @ 2022-05-23 10:42 UTC (permalink / raw)
  To: netdev
  Cc: Jakub Kicinski, Florian Fainelli, Vivien Didelot, Andrew Lunn,
	Vladimir Oltean, Tobias Waldekranz, Marek Behún,
	Ansuel Smith, DENG Qingfang, Alvin Šipraga, Claudiu Manoil,
	Alexandre Belloni, UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

From: Vladimir Oltean <vladimir.oltean@nxp.com>

dsa_slave_prechangeupper_sanity_check() is supposed to enforce some
adjacency restrictions, and calls ds->ops->port_prechangeupper if the
driver implements it.

We convert the error code from the port_prechangeupper() call to a
notifier code, and 0 is converted to NOTIFY_OK, but the caller of
dsa_slave_prechangeupper_sanity_check() stops at any notifier code
different from NOTIFY_DONE.

Avoid this by converting back the notifier code to an error code, so
that both NOTIFY_OK and NOTIFY_DONE will be seen as 0. This allows more
parallel sanity check functions to be added.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 net/dsa/slave.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 8d62c634c331..d8768e8f7862 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -2685,7 +2685,7 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb,
 		int err;
 
 		err = dsa_slave_prechangeupper_sanity_check(dev, info);
-		if (err != NOTIFY_DONE)
+		if (notifier_to_errno(err))
 			return err;
 
 		err = dsa_slave_prechangeupper(dev, ptr);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH net-next 04/12] net: bridge: move DSA master bridging restriction to DSA
  2022-05-23 10:42 [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3) Vladimir Oltean
                   ` (2 preceding siblings ...)
  2022-05-23 10:42 ` [RFC PATCH net-next 03/12] net: dsa: don't stop at NOTIFY_OK when calling ds->ops->port_prechangeupper Vladimir Oltean
@ 2022-05-23 10:42 ` Vladimir Oltean
  2022-05-23 17:57   ` Florian Fainelli
  2022-05-23 23:02   ` Nikolay Aleksandrov
  2022-05-23 10:42 ` [RFC PATCH net-next 05/12] net: dsa: existing DSA masters cannot join upper interfaces Vladimir Oltean
                   ` (9 subsequent siblings)
  13 siblings, 2 replies; 31+ messages in thread
From: Vladimir Oltean @ 2022-05-23 10:42 UTC (permalink / raw)
  To: netdev
  Cc: Jakub Kicinski, Florian Fainelli, Vivien Didelot, Andrew Lunn,
	Vladimir Oltean, Tobias Waldekranz, Marek Behún,
	Ansuel Smith, DENG Qingfang, Alvin Šipraga, Claudiu Manoil,
	Alexandre Belloni, UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

From: Vladimir Oltean <vladimir.oltean@nxp.com>

When DSA gains support for multiple CPU ports in a LAG, it will become
mandatory to monitor the changeupper events for the DSA master.

In fact, there are already some restrictions to be imposed in that area,
namely that a DSA master cannot be a bridge port except in some special
circumstances.

Centralize the restrictions at the level of the DSA layer as a
preliminary step.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 net/bridge/br_if.c | 20 --------------------
 net/dsa/slave.c    | 44 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+), 20 deletions(-)

diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 47fcbade7389..916c051f0f0b 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -568,26 +568,6 @@ int br_add_if(struct net_bridge *br, struct net_device *dev,
 	    !is_valid_ether_addr(dev->dev_addr))
 		return -EINVAL;
 
-	/* Also don't allow bridging of net devices that are DSA masters, since
-	 * the bridge layer rx_handler prevents the DSA fake ethertype handler
-	 * to be invoked, so we don't get the chance to strip off and parse the
-	 * DSA switch tag protocol header (the bridge layer just returns
-	 * RX_HANDLER_CONSUMED, stopping RX processing for these frames).
-	 * The only case where that would not be an issue is when bridging can
-	 * already be offloaded, such as when the DSA master is itself a DSA
-	 * or plain switchdev port, and is bridged only with other ports from
-	 * the same hardware device.
-	 */
-	if (netdev_uses_dsa(dev)) {
-		list_for_each_entry(p, &br->port_list, list) {
-			if (!netdev_port_same_parent_id(dev, p->dev)) {
-				NL_SET_ERR_MSG(extack,
-					       "Cannot do software bridging with a DSA master");
-				return -EINVAL;
-			}
-		}
-	}
-
 	/* No bridging of bridges */
 	if (dev->netdev_ops->ndo_start_xmit == br_dev_xmit) {
 		NL_SET_ERR_MSG(extack,
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index d8768e8f7862..309d8dde0179 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -2674,6 +2674,46 @@ dsa_slave_prechangeupper_sanity_check(struct net_device *dev,
 	return NOTIFY_DONE;
 }
 
+/* Don't allow bridging of DSA masters, since the bridge layer rx_handler
+ * prevents the DSA fake ethertype handler to be invoked, so we don't get the
+ * chance to strip off and parse the DSA switch tag protocol header (the bridge
+ * layer just returns RX_HANDLER_CONSUMED, stopping RX processing for these
+ * frames).
+ * The only case where that would not be an issue is when bridging can already
+ * be offloaded, such as when the DSA master is itself a DSA or plain switchdev
+ * port, and is bridged only with other ports from the same hardware device.
+ */
+static int
+dsa_bridge_prechangelower_sanity_check(struct net_device *new_lower,
+				       struct netdev_notifier_changeupper_info *info)
+{
+	struct net_device *br = info->upper_dev;
+	struct netlink_ext_ack *extack;
+	struct net_device *lower;
+	struct list_head *iter;
+
+	if (!netif_is_bridge_master(br))
+		return NOTIFY_DONE;
+
+	if (!info->linking)
+		return NOTIFY_DONE;
+
+	extack = netdev_notifier_info_to_extack(&info->info);
+
+	netdev_for_each_lower_dev(br, lower, iter) {
+		if (!netdev_uses_dsa(new_lower) && !netdev_uses_dsa(lower))
+			continue;
+
+		if (!netdev_port_same_parent_id(lower, new_lower)) {
+			NL_SET_ERR_MSG(extack,
+				       "Cannot do software bridging with a DSA master");
+			return notifier_from_errno(-EINVAL);
+		}
+	}
+
+	return NOTIFY_DONE;
+}
+
 static int dsa_slave_netdevice_event(struct notifier_block *nb,
 				     unsigned long event, void *ptr)
 {
@@ -2688,6 +2728,10 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb,
 		if (notifier_to_errno(err))
 			return err;
 
+		err = dsa_bridge_prechangelower_sanity_check(dev, info);
+		if (notifier_to_errno(err))
+			return err;
+
 		err = dsa_slave_prechangeupper(dev, ptr);
 		if (notifier_to_errno(err))
 			return err;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH net-next 05/12] net: dsa: existing DSA masters cannot join upper interfaces
  2022-05-23 10:42 [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3) Vladimir Oltean
                   ` (3 preceding siblings ...)
  2022-05-23 10:42 ` [RFC PATCH net-next 04/12] net: bridge: move DSA master bridging restriction to DSA Vladimir Oltean
@ 2022-05-23 10:42 ` Vladimir Oltean
  2022-05-23 17:58   ` Florian Fainelli
  2022-05-23 10:42 ` [RFC PATCH net-next 06/12] net: dsa: only bring down user ports assigned to a given DSA master Vladimir Oltean
                   ` (8 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Vladimir Oltean @ 2022-05-23 10:42 UTC (permalink / raw)
  To: netdev
  Cc: Jakub Kicinski, Florian Fainelli, Vivien Didelot, Andrew Lunn,
	Vladimir Oltean, Tobias Waldekranz, Marek Behún,
	Ansuel Smith, DENG Qingfang, Alvin Šipraga, Claudiu Manoil,
	Alexandre Belloni, UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

From: Vladimir Oltean <vladimir.oltean@nxp.com>

All the traffic to/from a DSA master is supposed to be distributed among
its DSA switch upper interfaces, so we should not allow other upper
device kinds.

An exception to this is DSA_TAG_PROTO_NONE (switches with no DSA tags),
and in that case it is actually expected to create e.g. VLAN interfaces
on the master. But for those, netdev_uses_dsa(master) returns false, so
the restriction doesn't apply.

The motivation for this change is to allow LAG interfaces of DSA masters
to be DSA masters themselves. We want to restrict the user's degrees of
freedom by 1: the LAG should already have all DSA masters as lowers, and
while lower ports of the LAG can be removed, none can be added after the
fact.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 net/dsa/slave.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 309d8dde0179..0455fb3cf03d 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -2674,6 +2674,35 @@ dsa_slave_prechangeupper_sanity_check(struct net_device *dev,
 	return NOTIFY_DONE;
 }
 
+static int
+dsa_master_prechangeupper_sanity_check(struct net_device *master,
+				       struct netdev_notifier_changeupper_info *info)
+{
+	struct netlink_ext_ack *extack;
+
+	if (!netdev_uses_dsa(master))
+		return NOTIFY_DONE;
+
+	if (!info->linking)
+		return NOTIFY_DONE;
+
+	/* Allow DSA switch uppers */
+	if (dsa_slave_dev_check(info->upper_dev))
+		return NOTIFY_DONE;
+
+	/* Allow bridge uppers of DSA masters, subject to further
+	 * restrictions in dsa_bridge_prechangelower_sanity_check()
+	 */
+	if (netif_is_bridge_master(info->upper_dev))
+		return NOTIFY_DONE;
+
+	extack = netdev_notifier_info_to_extack(&info->info);
+
+	NL_SET_ERR_MSG_MOD(extack,
+			   "DSA master cannot join unknown upper interfaces");
+	return notifier_from_errno(-EBUSY);
+}
+
 /* Don't allow bridging of DSA masters, since the bridge layer rx_handler
  * prevents the DSA fake ethertype handler to be invoked, so we don't get the
  * chance to strip off and parse the DSA switch tag protocol header (the bridge
@@ -2728,6 +2757,10 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb,
 		if (notifier_to_errno(err))
 			return err;
 
+		err = dsa_master_prechangeupper_sanity_check(dev, info);
+		if (notifier_to_errno(err))
+			return err;
+
 		err = dsa_bridge_prechangelower_sanity_check(dev, info);
 		if (notifier_to_errno(err))
 			return err;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH net-next 06/12] net: dsa: only bring down user ports assigned to a given DSA master
  2022-05-23 10:42 [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3) Vladimir Oltean
                   ` (4 preceding siblings ...)
  2022-05-23 10:42 ` [RFC PATCH net-next 05/12] net: dsa: existing DSA masters cannot join upper interfaces Vladimir Oltean
@ 2022-05-23 10:42 ` Vladimir Oltean
  2022-05-23 17:59   ` Florian Fainelli
  2022-05-23 10:42 ` [RFC PATCH net-next 07/12] net: dsa: all DSA masters must be down when changing the tagging protocol Vladimir Oltean
                   ` (7 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Vladimir Oltean @ 2022-05-23 10:42 UTC (permalink / raw)
  To: netdev
  Cc: Jakub Kicinski, Florian Fainelli, Vivien Didelot, Andrew Lunn,
	Vladimir Oltean, Tobias Waldekranz, Marek Behún,
	Ansuel Smith, DENG Qingfang, Alvin Šipraga, Claudiu Manoil,
	Alexandre Belloni, UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

From: Vladimir Oltean <vladimir.oltean@nxp.com>

This is an adaptation of commit c0a8a9c27493 ("net: dsa: automatically
bring user ports down when master goes down") for multiple DSA masters.
When a DSA master goes down, only the user ports under its control
should go down too, the others can still send/receive traffic.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 net/dsa/slave.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 0455fb3cf03d..c0be747c66ac 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -2848,6 +2848,9 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb,
 			if (!dsa_port_is_user(dp))
 				continue;
 
+			if (dp->cpu_dp != cpu_dp)
+				continue;
+
 			list_add(&dp->slave->close_list, &close_list);
 		}
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH net-next 07/12] net: dsa: all DSA masters must be down when changing the tagging protocol
  2022-05-23 10:42 [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3) Vladimir Oltean
                   ` (5 preceding siblings ...)
  2022-05-23 10:42 ` [RFC PATCH net-next 06/12] net: dsa: only bring down user ports assigned to a given DSA master Vladimir Oltean
@ 2022-05-23 10:42 ` Vladimir Oltean
  2022-05-23 18:00   ` Florian Fainelli
  2022-05-23 10:42 ` [RFC PATCH net-next 08/12] net: dsa: use dsa_tree_for_each_cpu_port in dsa_tree_{setup,teardown}_master Vladimir Oltean
                   ` (6 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Vladimir Oltean @ 2022-05-23 10:42 UTC (permalink / raw)
  To: netdev
  Cc: Jakub Kicinski, Florian Fainelli, Vivien Didelot, Andrew Lunn,
	Vladimir Oltean, Tobias Waldekranz, Marek Behún,
	Ansuel Smith, DENG Qingfang, Alvin Šipraga, Claudiu Manoil,
	Alexandre Belloni, UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

From: Vladimir Oltean <vladimir.oltean@nxp.com>

The fact that the tagging protocol is set and queried from the
/sys/class/net/<dsa-master>/dsa/tagging file is a bit of a quirk from
the single CPU port days which isn't aging very well now that DSA can
have more than a single CPU port. This is because the tagging protocol
is a switch property, yet in the presence of multiple CPU ports it can
be queried and set from multiple sysfs files, all of which are handled
by the same implementation.

The current logic ensures that the net device whose sysfs file we're
changing the tagging protocol through must be down. That net device is
the DSA master, and this is fine for single DSA master / CPU port setups.

But exactly because the tagging protocol is per switch [ tree, in fact ]
and not per DSA master, this isn't fine any longer with multiple CPU
ports, and we must iterate through the tree and find all DSA masters,
and make sure that all of them are down.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 net/dsa/dsa2.c     | 10 +++-------
 net/dsa/dsa_priv.h |  1 -
 net/dsa/master.c   |  2 +-
 3 files changed, 4 insertions(+), 9 deletions(-)

diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index ec0df4e498d6..4f0042339d4f 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -1235,7 +1235,6 @@ static int dsa_tree_bind_tag_proto(struct dsa_switch_tree *dst,
  * they would have formed disjoint trees (different "dsa,member" values).
  */
 int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,
-			      struct net_device *master,
 			      const struct dsa_device_ops *tag_ops,
 			      const struct dsa_device_ops *old_tag_ops)
 {
@@ -1251,14 +1250,11 @@ int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,
 	 * attempts to change the tagging protocol. If we ever lift the IFF_UP
 	 * restriction, there needs to be another mutex which serializes this.
 	 */
-	if (master->flags & IFF_UP)
-		goto out_unlock;
-
 	list_for_each_entry(dp, &dst->ports, list) {
-		if (!dsa_port_is_user(dp))
-			continue;
+		if (dsa_port_is_cpu(dp) && (dp->master->flags & IFF_UP))
+			goto out_unlock;
 
-		if (dp->slave->flags & IFF_UP)
+		if (dsa_port_is_user(dp) && (dp->slave->flags & IFF_UP))
 			goto out_unlock;
 	}
 
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index d9722e49864b..cc1cc866dc42 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -545,7 +545,6 @@ struct dsa_lag *dsa_tree_lag_find(struct dsa_switch_tree *dst,
 int dsa_tree_notify(struct dsa_switch_tree *dst, unsigned long e, void *v);
 int dsa_broadcast(unsigned long e, void *v);
 int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,
-			      struct net_device *master,
 			      const struct dsa_device_ops *tag_ops,
 			      const struct dsa_device_ops *old_tag_ops);
 void dsa_tree_master_admin_state_change(struct dsa_switch_tree *dst,
diff --git a/net/dsa/master.c b/net/dsa/master.c
index 2851e44c4cf0..32c0a00a8b92 100644
--- a/net/dsa/master.c
+++ b/net/dsa/master.c
@@ -307,7 +307,7 @@ static ssize_t tagging_store(struct device *d, struct device_attribute *attr,
 		 */
 		goto out;
 
-	err = dsa_tree_change_tag_proto(cpu_dp->ds->dst, dev, new_tag_ops,
+	err = dsa_tree_change_tag_proto(cpu_dp->ds->dst, new_tag_ops,
 					old_tag_ops);
 	if (err) {
 		/* On failure the old tagger is restored, so we don't need the
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH net-next 08/12] net: dsa: use dsa_tree_for_each_cpu_port in dsa_tree_{setup,teardown}_master
  2022-05-23 10:42 [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3) Vladimir Oltean
                   ` (6 preceding siblings ...)
  2022-05-23 10:42 ` [RFC PATCH net-next 07/12] net: dsa: all DSA masters must be down when changing the tagging protocol Vladimir Oltean
@ 2022-05-23 10:42 ` Vladimir Oltean
  2022-05-23 18:01   ` Florian Fainelli
  2022-05-23 10:42 ` [RFC PATCH net-next 09/12] net: dsa: introduce dsa_port_get_master() Vladimir Oltean
                   ` (5 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Vladimir Oltean @ 2022-05-23 10:42 UTC (permalink / raw)
  To: netdev
  Cc: Jakub Kicinski, Florian Fainelli, Vivien Didelot, Andrew Lunn,
	Vladimir Oltean, Tobias Waldekranz, Marek Behún,
	Ansuel Smith, DENG Qingfang, Alvin Šipraga, Claudiu Manoil,
	Alexandre Belloni, UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

From: Vladimir Oltean <vladimir.oltean@nxp.com>

More logic will be added to dsa_tree_setup_master() and
dsa_tree_teardown_master() in upcoming changes.

Reduce the indentation by one level in these functions by introducing
and using a dedicated iterator for CPU ports of a tree.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 include/net/dsa.h |  4 ++++
 net/dsa/dsa2.c    | 46 +++++++++++++++++++++-------------------------
 2 files changed, 25 insertions(+), 25 deletions(-)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 14f07275852b..ad345fa17297 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -555,6 +555,10 @@ static inline bool dsa_is_user_port(struct dsa_switch *ds, int p)
 	list_for_each_entry((_dp), &(_dst)->ports, list) \
 		if (dsa_port_is_user((_dp)))
 
+#define dsa_tree_for_each_cpu_port(_dp, _dst) \
+	list_for_each_entry((_dp), &(_dst)->ports, list) \
+		if (dsa_port_is_cpu((_dp)))
+
 #define dsa_switch_for_each_port(_dp, _ds) \
 	list_for_each_entry((_dp), &(_ds)->dst->ports, list) \
 		if ((_dp)->ds == (_ds))
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index 4f0042339d4f..74167bf0fbe5 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -1043,26 +1043,24 @@ static int dsa_tree_setup_switches(struct dsa_switch_tree *dst)
 
 static int dsa_tree_setup_master(struct dsa_switch_tree *dst)
 {
-	struct dsa_port *dp;
+	struct dsa_port *cpu_dp;
 	int err = 0;
 
 	rtnl_lock();
 
-	list_for_each_entry(dp, &dst->ports, list) {
-		if (dsa_port_is_cpu(dp)) {
-			struct net_device *master = dp->master;
-			bool admin_up = (master->flags & IFF_UP) &&
-					!qdisc_tx_is_noop(master);
+	dsa_tree_for_each_cpu_port(cpu_dp, dst) {
+		struct net_device *master = cpu_dp->master;
+		bool admin_up = (master->flags & IFF_UP) &&
+				!qdisc_tx_is_noop(master);
 
-			err = dsa_master_setup(master, dp);
-			if (err)
-				break;
+		err = dsa_master_setup(master, cpu_dp);
+		if (err)
+			break;
 
-			/* Replay master state event */
-			dsa_tree_master_admin_state_change(dst, master, admin_up);
-			dsa_tree_master_oper_state_change(dst, master,
-							  netif_oper_up(master));
-		}
+		/* Replay master state event */
+		dsa_tree_master_admin_state_change(dst, master, admin_up);
+		dsa_tree_master_oper_state_change(dst, master,
+						  netif_oper_up(master));
 	}
 
 	rtnl_unlock();
@@ -1072,22 +1070,20 @@ static int dsa_tree_setup_master(struct dsa_switch_tree *dst)
 
 static void dsa_tree_teardown_master(struct dsa_switch_tree *dst)
 {
-	struct dsa_port *dp;
+	struct dsa_port *cpu_dp;
 
 	rtnl_lock();
 
-	list_for_each_entry(dp, &dst->ports, list) {
-		if (dsa_port_is_cpu(dp)) {
-			struct net_device *master = dp->master;
+	dsa_tree_for_each_cpu_port(cpu_dp, dst) {
+		struct net_device *master = cpu_dp->master;
 
-			/* Synthesizing an "admin down" state is sufficient for
-			 * the switches to get a notification if the master is
-			 * currently up and running.
-			 */
-			dsa_tree_master_admin_state_change(dst, master, false);
+		/* Synthesizing an "admin down" state is sufficient for
+		 * the switches to get a notification if the master is
+		 * currently up and running.
+		 */
+		dsa_tree_master_admin_state_change(dst, master, false);
 
-			dsa_master_teardown(master);
-		}
+		dsa_master_teardown(master);
 	}
 
 	rtnl_unlock();
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH net-next 09/12] net: dsa: introduce dsa_port_get_master()
  2022-05-23 10:42 [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3) Vladimir Oltean
                   ` (7 preceding siblings ...)
  2022-05-23 10:42 ` [RFC PATCH net-next 08/12] net: dsa: use dsa_tree_for_each_cpu_port in dsa_tree_{setup,teardown}_master Vladimir Oltean
@ 2022-05-23 10:42 ` Vladimir Oltean
  2022-05-23 18:08   ` Florian Fainelli
  2022-05-23 10:42 ` [RFC PATCH net-next 10/12] net: dsa: allow the DSA master to be seen and changed through rtnetlink Vladimir Oltean
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Vladimir Oltean @ 2022-05-23 10:42 UTC (permalink / raw)
  To: netdev
  Cc: Jakub Kicinski, Florian Fainelli, Vivien Didelot, Andrew Lunn,
	Vladimir Oltean, Tobias Waldekranz, Marek Behún,
	Ansuel Smith, DENG Qingfang, Alvin Šipraga, Claudiu Manoil,
	Alexandre Belloni, UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

From: Vladimir Oltean <vladimir.oltean@nxp.com>

There is a desire to support for DSA masters in a LAG.

That configuration is intended to work by simply enslaving the master to
a bonding/team device. But the physical DSA master (the LAG slave) still
has a dev->dsa_ptr, and that cpu_dp still corresponds to the physical
CPU port.

However, we would like to be able to retrieve the LAG that's the upper
of the physical DSA master. In preparation for that, introduce a helper
called dsa_port_get_master() that replaces all occurrences of the
dp->cpu_dp->master pattern. The distinction between LAG and non-LAG will
be made later within the helper itself.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 drivers/net/dsa/bcm_sf2.c                     |  4 +--
 drivers/net/dsa/bcm_sf2_cfp.c                 |  4 +--
 drivers/net/dsa/lan9303-core.c                |  4 +--
 .../net/ethernet/mediatek/mtk_ppe_offload.c   |  2 +-
 include/net/dsa.h                             |  5 ++++
 net/dsa/dsa2.c                                |  8 +++---
 net/dsa/dsa_priv.h                            |  2 +-
 net/dsa/port.c                                | 28 +++++++++----------
 net/dsa/slave.c                               | 11 ++++----
 net/dsa/tag_8021q.c                           |  4 +--
 10 files changed, 38 insertions(+), 34 deletions(-)

diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index 87e81c636339..4551528d822c 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -982,7 +982,7 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds)
 static void bcm_sf2_sw_get_wol(struct dsa_switch *ds, int port,
 			       struct ethtool_wolinfo *wol)
 {
-	struct net_device *p = dsa_to_port(ds, port)->cpu_dp->master;
+	struct net_device *p = dsa_port_to_master(dsa_to_port(ds, port));
 	struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
 	struct ethtool_wolinfo pwol = { };
 
@@ -1006,7 +1006,7 @@ static void bcm_sf2_sw_get_wol(struct dsa_switch *ds, int port,
 static int bcm_sf2_sw_set_wol(struct dsa_switch *ds, int port,
 			      struct ethtool_wolinfo *wol)
 {
-	struct net_device *p = dsa_to_port(ds, port)->cpu_dp->master;
+	struct net_device *p = dsa_port_to_master(dsa_to_port(ds, port));
 	struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
 	s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
 	struct ethtool_wolinfo pwol =  { };
diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c
index edbe5e7f1cb6..90636ae3db98 100644
--- a/drivers/net/dsa/bcm_sf2_cfp.c
+++ b/drivers/net/dsa/bcm_sf2_cfp.c
@@ -1102,7 +1102,7 @@ static int bcm_sf2_cfp_rule_get_all(struct bcm_sf2_priv *priv,
 int bcm_sf2_get_rxnfc(struct dsa_switch *ds, int port,
 		      struct ethtool_rxnfc *nfc, u32 *rule_locs)
 {
-	struct net_device *p = dsa_to_port(ds, port)->cpu_dp->master;
+	struct net_device *p = dsa_port_to_master(dsa_to_port(ds, port));
 	struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
 	int ret = 0;
 
@@ -1145,7 +1145,7 @@ int bcm_sf2_get_rxnfc(struct dsa_switch *ds, int port,
 int bcm_sf2_set_rxnfc(struct dsa_switch *ds, int port,
 		      struct ethtool_rxnfc *nfc)
 {
-	struct net_device *p = dsa_to_port(ds, port)->cpu_dp->master;
+	struct net_device *p = dsa_port_to_master(dsa_to_port(ds, port));
 	struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
 	int ret = 0;
 
diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c
index e03ff1f267bb..181e082b0919 100644
--- a/drivers/net/dsa/lan9303-core.c
+++ b/drivers/net/dsa/lan9303-core.c
@@ -1090,7 +1090,7 @@ static int lan9303_port_enable(struct dsa_switch *ds, int port,
 	if (!dsa_port_is_user(dp))
 		return 0;
 
-	vlan_vid_add(dp->cpu_dp->master, htons(ETH_P_8021Q), port);
+	vlan_vid_add(dsa_port_to_master(dp), htons(ETH_P_8021Q), port);
 
 	return lan9303_enable_processing_port(chip, port);
 }
@@ -1103,7 +1103,7 @@ static void lan9303_port_disable(struct dsa_switch *ds, int port)
 	if (!dsa_port_is_user(dp))
 		return;
 
-	vlan_vid_del(dp->cpu_dp->master, htons(ETH_P_8021Q), port);
+	vlan_vid_del(dsa_port_to_master(dp), htons(ETH_P_8021Q), port);
 
 	lan9303_disable_processing_port(chip, port);
 	lan9303_phy_write(ds, chip->phy_addr_base + port, MII_BMCR, BMCR_PDOWN);
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
index c9353071f96a..632af8c97043 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
@@ -174,7 +174,7 @@ mtk_flow_get_dsa_port(struct net_device **dev)
 	if (dp->cpu_dp->tag_ops->proto != DSA_TAG_PROTO_MTK)
 		return -ENODEV;
 
-	*dev = dp->cpu_dp->master;
+	*dev = dsa_port_to_master(dp);
 
 	return dp->index;
 #else
diff --git a/include/net/dsa.h b/include/net/dsa.h
index ad345fa17297..7f6ca944c092 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -714,6 +714,11 @@ static inline bool dsa_port_offloads_lag(struct dsa_port *dp,
 	return dsa_port_lag_dev_get(dp) == lag->dev;
 }
 
+static inline struct net_device *dsa_port_to_master(const struct dsa_port *dp)
+{
+	return dp->cpu_dp->master;
+}
+
 static inline
 struct net_device *dsa_port_to_bridge_port(const struct dsa_port *dp)
 {
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index 74167bf0fbe5..8ff5467ac3e2 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -1246,11 +1246,11 @@ int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,
 	 * attempts to change the tagging protocol. If we ever lift the IFF_UP
 	 * restriction, there needs to be another mutex which serializes this.
 	 */
-	list_for_each_entry(dp, &dst->ports, list) {
-		if (dsa_port_is_cpu(dp) && (dp->master->flags & IFF_UP))
+	dsa_tree_for_each_user_port(dp, dst) {
+		if (dsa_port_to_master(dp)->flags & IFF_UP)
 			goto out_unlock;
 
-		if (dsa_port_is_user(dp) && (dp->slave->flags & IFF_UP))
+		if (dp->slave->flags & IFF_UP)
 			goto out_unlock;
 	}
 
@@ -1780,7 +1780,7 @@ void dsa_switch_shutdown(struct dsa_switch *ds)
 	rtnl_lock();
 
 	dsa_switch_for_each_user_port(dp, ds) {
-		master = dp->cpu_dp->master;
+		master = dsa_port_to_master(dp);
 		slave_dev = dp->slave;
 
 		netdev_upper_dev_unlink(master, slave_dev);
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index cc1cc866dc42..f3562cef32ad 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -322,7 +322,7 @@ dsa_slave_to_master(const struct net_device *dev)
 {
 	struct dsa_port *dp = dsa_slave_to_port(dev);
 
-	return dp->cpu_dp->master;
+	return dsa_port_to_master(dp);
 }
 
 /* If under a bridge with vlan_filtering=0, make sure to send pvid-tagged
diff --git a/net/dsa/port.c b/net/dsa/port.c
index 85cac22cb056..8557217ed5de 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -1022,7 +1022,7 @@ int dsa_port_standalone_host_fdb_add(struct dsa_port *dp,
 int dsa_port_bridge_host_fdb_add(struct dsa_port *dp,
 				 const unsigned char *addr, u16 vid)
 {
-	struct dsa_port *cpu_dp = dp->cpu_dp;
+	struct net_device *master = dsa_port_to_master(dp);
 	struct dsa_db db = {
 		.type = DSA_DB_BRIDGE,
 		.bridge = *dp->bridge,
@@ -1033,8 +1033,8 @@ int dsa_port_bridge_host_fdb_add(struct dsa_port *dp,
 	 * requires rtnl_lock(), since we can't guarantee that is held here,
 	 * and we can't take it either.
 	 */
-	if (cpu_dp->master->priv_flags & IFF_UNICAST_FLT) {
-		err = dev_uc_add(cpu_dp->master, addr);
+	if (master->priv_flags & IFF_UNICAST_FLT) {
+		err = dev_uc_add(master, addr);
 		if (err)
 			return err;
 	}
@@ -1073,15 +1073,15 @@ int dsa_port_standalone_host_fdb_del(struct dsa_port *dp,
 int dsa_port_bridge_host_fdb_del(struct dsa_port *dp,
 				 const unsigned char *addr, u16 vid)
 {
-	struct dsa_port *cpu_dp = dp->cpu_dp;
+	struct net_device *master = dsa_port_to_master(dp);
 	struct dsa_db db = {
 		.type = DSA_DB_BRIDGE,
 		.bridge = *dp->bridge,
 	};
 	int err;
 
-	if (cpu_dp->master->priv_flags & IFF_UNICAST_FLT) {
-		err = dev_uc_del(cpu_dp->master, addr);
+	if (master->priv_flags & IFF_UNICAST_FLT) {
+		err = dev_uc_del(master, addr);
 		if (err)
 			return err;
 	}
@@ -1204,14 +1204,14 @@ int dsa_port_standalone_host_mdb_add(const struct dsa_port *dp,
 int dsa_port_bridge_host_mdb_add(const struct dsa_port *dp,
 				 const struct switchdev_obj_port_mdb *mdb)
 {
-	struct dsa_port *cpu_dp = dp->cpu_dp;
+	struct net_device *master = dsa_port_to_master(dp);
 	struct dsa_db db = {
 		.type = DSA_DB_BRIDGE,
 		.bridge = *dp->bridge,
 	};
 	int err;
 
-	err = dev_mc_add(cpu_dp->master, mdb->addr);
+	err = dev_mc_add(master, mdb->addr);
 	if (err)
 		return err;
 
@@ -1248,14 +1248,14 @@ int dsa_port_standalone_host_mdb_del(const struct dsa_port *dp,
 int dsa_port_bridge_host_mdb_del(const struct dsa_port *dp,
 				 const struct switchdev_obj_port_mdb *mdb)
 {
-	struct dsa_port *cpu_dp = dp->cpu_dp;
+	struct net_device *master = dsa_port_to_master(dp);
 	struct dsa_db db = {
 		.type = DSA_DB_BRIDGE,
 		.bridge = *dp->bridge,
 	};
 	int err;
 
-	err = dev_mc_del(cpu_dp->master, mdb->addr);
+	err = dev_mc_del(master, mdb->addr);
 	if (err)
 		return err;
 
@@ -1290,19 +1290,19 @@ int dsa_port_host_vlan_add(struct dsa_port *dp,
 			   const struct switchdev_obj_port_vlan *vlan,
 			   struct netlink_ext_ack *extack)
 {
+	struct net_device *master = dsa_port_to_master(dp);
 	struct dsa_notifier_vlan_info info = {
 		.dp = dp,
 		.vlan = vlan,
 		.extack = extack,
 	};
-	struct dsa_port *cpu_dp = dp->cpu_dp;
 	int err;
 
 	err = dsa_port_notify(dp, DSA_NOTIFIER_HOST_VLAN_ADD, &info);
 	if (err && err != -EOPNOTSUPP)
 		return err;
 
-	vlan_vid_add(cpu_dp->master, htons(ETH_P_8021Q), vlan->vid);
+	vlan_vid_add(master, htons(ETH_P_8021Q), vlan->vid);
 
 	return err;
 }
@@ -1310,18 +1310,18 @@ int dsa_port_host_vlan_add(struct dsa_port *dp,
 int dsa_port_host_vlan_del(struct dsa_port *dp,
 			   const struct switchdev_obj_port_vlan *vlan)
 {
+	struct net_device *master = dsa_port_to_master(dp);
 	struct dsa_notifier_vlan_info info = {
 		.dp = dp,
 		.vlan = vlan,
 	};
-	struct dsa_port *cpu_dp = dp->cpu_dp;
 	int err;
 
 	err = dsa_port_notify(dp, DSA_NOTIFIER_HOST_VLAN_DEL, &info);
 	if (err && err != -EOPNOTSUPP)
 		return err;
 
-	vlan_vid_del(cpu_dp->master, htons(ETH_P_8021Q), vlan->vid);
+	vlan_vid_del(master, htons(ETH_P_8021Q), vlan->vid);
 
 	return err;
 }
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index c0be747c66ac..0d0deca99eba 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -1481,8 +1481,7 @@ static int dsa_slave_setup_tc_block(struct net_device *dev,
 static int dsa_slave_setup_ft_block(struct dsa_switch *ds, int port,
 				    void *type_data)
 {
-	struct dsa_port *cpu_dp = dsa_to_port(ds, port)->cpu_dp;
-	struct net_device *master = cpu_dp->master;
+	struct net_device *master = dsa_port_to_master(dsa_to_port(ds, port));
 
 	if (!master->netdev_ops->ndo_setup_tc)
 		return -EOPNOTSUPP;
@@ -2123,13 +2122,14 @@ static int dsa_slave_fill_forward_path(struct net_device_path_ctx *ctx,
 				       struct net_device_path *path)
 {
 	struct dsa_port *dp = dsa_slave_to_port(ctx->dev);
+	struct net_device *master = dsa_port_to_master(dp);
 	struct dsa_port *cpu_dp = dp->cpu_dp;
 
 	path->dev = ctx->dev;
 	path->type = DEV_PATH_DSA;
 	path->dsa.proto = cpu_dp->tag_ops->proto;
 	path->dsa.port = dp->index;
-	ctx->dev = cpu_dp->master;
+	ctx->dev = master;
 
 	return 0;
 }
@@ -2247,9 +2247,9 @@ static int dsa_slave_phy_setup(struct net_device *slave_dev)
 void dsa_slave_setup_tagger(struct net_device *slave)
 {
 	struct dsa_port *dp = dsa_slave_to_port(slave);
+	struct net_device *master = dsa_port_to_master(dp);
 	struct dsa_slave_priv *p = netdev_priv(slave);
 	const struct dsa_port *cpu_dp = dp->cpu_dp;
-	struct net_device *master = cpu_dp->master;
 	const struct dsa_switch *ds = dp->ds;
 
 	slave->needed_headroom = cpu_dp->tag_ops->needed_headroom;
@@ -2306,8 +2306,7 @@ int dsa_slave_resume(struct net_device *slave_dev)
 
 int dsa_slave_create(struct dsa_port *port)
 {
-	const struct dsa_port *cpu_dp = port->cpu_dp;
-	struct net_device *master = cpu_dp->master;
+	struct net_device *master = dsa_port_to_master(port);
 	struct dsa_switch *ds = port->ds;
 	const char *name = port->name;
 	struct net_device *slave_dev;
diff --git a/net/dsa/tag_8021q.c b/net/dsa/tag_8021q.c
index 01a427800797..b91c2894b6fd 100644
--- a/net/dsa/tag_8021q.c
+++ b/net/dsa/tag_8021q.c
@@ -332,7 +332,7 @@ static int dsa_tag_8021q_port_setup(struct dsa_switch *ds, int port)
 	if (!dsa_port_is_user(dp))
 		return 0;
 
-	master = dp->cpu_dp->master;
+	master = dsa_port_to_master(dp);
 
 	err = dsa_port_tag_8021q_vlan_add(dp, vid, false);
 	if (err) {
@@ -361,7 +361,7 @@ static void dsa_tag_8021q_port_teardown(struct dsa_switch *ds, int port)
 	if (!dsa_port_is_user(dp))
 		return;
 
-	master = dp->cpu_dp->master;
+	master = dsa_port_to_master(dp);
 
 	dsa_port_tag_8021q_vlan_del(dp, vid, false);
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH net-next 10/12] net: dsa: allow the DSA master to be seen and changed through rtnetlink
  2022-05-23 10:42 [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3) Vladimir Oltean
                   ` (8 preceding siblings ...)
  2022-05-23 10:42 ` [RFC PATCH net-next 09/12] net: dsa: introduce dsa_port_get_master() Vladimir Oltean
@ 2022-05-23 10:42 ` Vladimir Oltean
  2022-05-23 18:41   ` Florian Fainelli
  2022-05-23 10:42 ` [RFC PATCH net-next 11/12] net: dsa: allow masters to join a LAG Vladimir Oltean
                   ` (3 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Vladimir Oltean @ 2022-05-23 10:42 UTC (permalink / raw)
  To: netdev
  Cc: Jakub Kicinski, Florian Fainelli, Vivien Didelot, Andrew Lunn,
	Vladimir Oltean, Tobias Waldekranz, Marek Behún,
	Ansuel Smith, DENG Qingfang, Alvin Šipraga, Claudiu Manoil,
	Alexandre Belloni, UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

From: Vladimir Oltean <vladimir.oltean@nxp.com>

Some DSA switches have multiple CPU ports, which can be used to improve
CPU termination throughput, but DSA, through dsa_tree_setup_cpu_ports(),
sets up only the first one, leading to suboptimal use of hardware.

The desire is to not change the default configuration but to permit the
user to create a dynamic mapping between individual user ports and the
CPU port that they are served by, configurable through rtnetlink. It is
also intended to permit load balancing between CPU ports, and in that
case, the foreseen model is for the DSA master to be a bonding interface
whose lowers are the physical DSA masters.

To that end, we create a struct rtnl_link_ops for DSA user ports with
the "dsa" kind. We expose the IFLA_DSA_MASTER link attribute that
contains the ifindex of the newly desired DSA master.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 include/net/dsa.h            |   8 +++
 include/uapi/linux/if_link.h |  10 +++
 net/dsa/Makefile             |  10 ++-
 net/dsa/dsa.c                |   9 +++
 net/dsa/dsa2.c               |  14 ++++
 net/dsa/dsa_priv.h           |  10 +++
 net/dsa/master.c             |   1 +
 net/dsa/netlink.c            |  62 ++++++++++++++++
 net/dsa/port.c               | 133 +++++++++++++++++++++++++++++++++++
 net/dsa/slave.c              | 117 ++++++++++++++++++++++++++++++
 10 files changed, 373 insertions(+), 1 deletion(-)
 create mode 100644 net/dsa/netlink.c

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 7f6ca944c092..0958ad3289c9 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -555,6 +555,10 @@ static inline bool dsa_is_user_port(struct dsa_switch *ds, int p)
 	list_for_each_entry((_dp), &(_dst)->ports, list) \
 		if (dsa_port_is_user((_dp)))
 
+#define dsa_tree_for_each_user_port_continue_reverse(_dp, _dst) \
+	list_for_each_entry_continue_reverse((_dp), &(_dst)->ports, list) \
+		if (dsa_port_is_user((_dp)))
+
 #define dsa_tree_for_each_cpu_port(_dp, _dst) \
 	list_for_each_entry((_dp), &(_dst)->ports, list) \
 		if (dsa_port_is_cpu((_dp)))
@@ -826,6 +830,10 @@ struct dsa_switch_ops {
 	int	(*connect_tag_protocol)(struct dsa_switch *ds,
 					enum dsa_tag_protocol proto);
 
+	int	(*port_change_master)(struct dsa_switch *ds, int port,
+				      struct net_device *master,
+				      struct netlink_ext_ack *extack);
+
 	/* Optional switch-wide initialization and destruction methods */
 	int	(*setup)(struct dsa_switch *ds);
 	void	(*teardown)(struct dsa_switch *ds);
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 5f58dcfe2787..f0a7797924ea 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -1373,4 +1373,14 @@ enum {
 
 #define IFLA_MCTP_MAX (__IFLA_MCTP_MAX - 1)
 
+/* DSA section */
+
+enum {
+	IFLA_DSA_UNSPEC,
+	IFLA_DSA_MASTER,
+	__IFLA_DSA_MAX,
+};
+
+#define IFLA_DSA_MAX	(__IFLA_DSA_MAX - 1)
+
 #endif /* _UAPI_LINUX_IF_LINK_H */
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
index 9f75820e7c98..d0ed170bb7aa 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -1,7 +1,15 @@
 # SPDX-License-Identifier: GPL-2.0
 # the core
 obj-$(CONFIG_NET_DSA) += dsa_core.o
-dsa_core-y += dsa.o dsa2.o master.o port.o slave.o switch.o tag_8021q.o
+dsa_core-y += \
+	dsa.o \
+	dsa2.o \
+	master.o \
+	netlink.o \
+	port.o \
+	slave.o \
+	switch.o \
+	tag_8021q.o
 
 # tagging formats
 obj-$(CONFIG_NET_DSA_TAG_AR9331) += tag_ar9331.o
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index be7b320cda76..64b14f655b23 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -536,8 +536,16 @@ static int __init dsa_init_module(void)
 	dsa_tag_driver_register(&DSA_TAG_DRIVER_NAME(none_ops),
 				THIS_MODULE);
 
+	rc = rtnl_link_register(&dsa_link_ops);
+	if (rc)
+		goto netlink_register_fail;
+
 	return 0;
 
+netlink_register_fail:
+	dsa_tag_driver_unregister(&DSA_TAG_DRIVER_NAME(none_ops));
+	dsa_slave_unregister_notifier();
+	dev_remove_pack(&dsa_pack_type);
 register_notifier_fail:
 	destroy_workqueue(dsa_owq);
 
@@ -547,6 +555,7 @@ module_init(dsa_init_module);
 
 static void __exit dsa_cleanup_module(void)
 {
+	rtnl_link_unregister(&dsa_link_ops);
 	dsa_tag_driver_unregister(&DSA_TAG_DRIVER_NAME(none_ops));
 
 	dsa_slave_unregister_notifier();
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index 8ff5467ac3e2..32d5a5413bb9 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -386,6 +386,20 @@ static struct dsa_port *dsa_tree_find_first_cpu(struct dsa_switch_tree *dst)
 	return NULL;
 }
 
+struct net_device *dsa_tree_find_first_master(struct dsa_switch_tree *dst)
+{
+	struct device_node *ethernet;
+	struct net_device *master;
+	struct dsa_port *cpu_dp;
+
+	cpu_dp = dsa_tree_find_first_cpu(dst);
+	ethernet = of_parse_phandle(cpu_dp->dn, "ethernet", 0);
+	master = of_find_net_device_by_node(ethernet);
+	of_node_put(ethernet);
+
+	return master;
+}
+
 /* Assign the default CPU port (the first one in the tree) to all ports of the
  * fabric which don't already have one as part of their own switch.
  */
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index f3562cef32ad..1ce0e48d5a92 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -200,6 +200,9 @@ static inline struct net_device *dsa_master_find_slave(struct net_device *dev,
 	return NULL;
 }
 
+/* netlink.c */
+extern struct rtnl_link_ops dsa_link_ops __read_mostly;
+
 /* port.c */
 void dsa_port_set_tag_protocol(struct dsa_port *cpu_dp,
 			       const struct dsa_device_ops *tag_ops);
@@ -292,6 +295,8 @@ void dsa_port_hsr_leave(struct dsa_port *dp, struct net_device *hsr);
 int dsa_port_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid, bool broadcast);
 void dsa_port_tag_8021q_vlan_del(struct dsa_port *dp, u16 vid, bool broadcast);
 void dsa_port_set_host_flood(struct dsa_port *dp, bool uc, bool mc);
+int dsa_port_change_master(struct dsa_port *dp, struct net_device *master,
+			   struct netlink_ext_ack *extack);
 
 /* slave.c */
 extern const struct dsa_device_ops notag_netdev_ops;
@@ -305,8 +310,12 @@ int dsa_slave_suspend(struct net_device *slave_dev);
 int dsa_slave_resume(struct net_device *slave_dev);
 int dsa_slave_register_notifier(void);
 void dsa_slave_unregister_notifier(void);
+void dsa_slave_sync_ha(struct net_device *dev);
+void dsa_slave_unsync_ha(struct net_device *dev);
 void dsa_slave_setup_tagger(struct net_device *slave);
 int dsa_slave_change_mtu(struct net_device *dev, int new_mtu);
+int dsa_slave_change_master(struct net_device *dev, struct net_device *master,
+			    struct netlink_ext_ack *extack);
 int dsa_slave_manage_vlan_filtering(struct net_device *dev,
 				    bool vlan_filtering);
 
@@ -542,6 +551,7 @@ void dsa_lag_map(struct dsa_switch_tree *dst, struct dsa_lag *lag);
 void dsa_lag_unmap(struct dsa_switch_tree *dst, struct dsa_lag *lag);
 struct dsa_lag *dsa_tree_lag_find(struct dsa_switch_tree *dst,
 				  const struct net_device *lag_dev);
+struct net_device *dsa_tree_find_first_master(struct dsa_switch_tree *dst);
 int dsa_tree_notify(struct dsa_switch_tree *dst, unsigned long e, void *v);
 int dsa_broadcast(unsigned long e, void *v);
 int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,
diff --git a/net/dsa/master.c b/net/dsa/master.c
index 32c0a00a8b92..a7420bad0a0a 100644
--- a/net/dsa/master.c
+++ b/net/dsa/master.c
@@ -6,6 +6,7 @@
  *	Vivien Didelot <vivien.didelot@savoirfairelinux.com>
  */
 
+#include <linux/of_net.h>
 #include "dsa_priv.h"
 
 static int dsa_master_get_regs_len(struct net_device *dev)
diff --git a/net/dsa/netlink.c b/net/dsa/netlink.c
new file mode 100644
index 000000000000..0f43bbb94769
--- /dev/null
+++ b/net/dsa/netlink.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright 2022 NXP
+ */
+#include <linux/netdevice.h>
+#include <net/rtnetlink.h>
+
+#include "dsa_priv.h"
+
+static const struct nla_policy dsa_policy[IFLA_DSA_MAX + 1] = {
+	[IFLA_DSA_MASTER]	= { .type = NLA_U32 },
+};
+
+static int dsa_changelink(struct net_device *dev, struct nlattr *tb[],
+			  struct nlattr *data[],
+			  struct netlink_ext_ack *extack)
+{
+	int err;
+
+	if (!data)
+		return 0;
+
+	if (data[IFLA_DSA_MASTER]) {
+		u32 ifindex = nla_get_u32(data[IFLA_DSA_MASTER]);
+		struct net_device *master;
+
+		master = __dev_get_by_index(dev_net(dev), ifindex);
+		if (!master)
+			return -EINVAL;
+
+		err = dsa_slave_change_master(dev, master, extack);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static size_t dsa_get_size(const struct net_device *dev)
+{
+	return nla_total_size(sizeof(u32)) +	/* IFLA_DSA_MASTER  */
+	       0;
+}
+
+static int dsa_fill_info(struct sk_buff *skb, const struct net_device *dev)
+{
+	struct net_device *master = dsa_slave_to_master(dev);
+
+	if (nla_put_u32(skb, IFLA_DSA_MASTER, master->ifindex))
+		return -EMSGSIZE;
+
+	return 0;
+}
+
+struct rtnl_link_ops dsa_link_ops __read_mostly = {
+	.kind			= "dsa",
+	.priv_size		= sizeof(struct dsa_port),
+	.maxtype		= IFLA_DSA_MAX,
+	.policy			= dsa_policy,
+	.changelink		= dsa_changelink,
+	.get_size		= dsa_get_size,
+	.fill_info		= dsa_fill_info,
+};
diff --git a/net/dsa/port.c b/net/dsa/port.c
index 8557217ed5de..ced7f8d8ec62 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -7,6 +7,7 @@
  */
 
 #include <linux/if_bridge.h>
+#include <linux/netdevice.h>
 #include <linux/notifier.h>
 #include <linux/of_mdio.h>
 #include <linux/of_net.h>
@@ -1370,6 +1371,138 @@ int dsa_port_mrp_del_ring_role(const struct dsa_port *dp,
 	return ds->ops->port_mrp_del_ring_role(ds, dp->index, mrp);
 }
 
+static int dsa_port_assign_master(struct dsa_port *dp,
+				  struct net_device *master,
+				  struct netlink_ext_ack *extack,
+				  bool fail_on_err)
+{
+	struct dsa_switch *ds = dp->ds;
+	int port = dp->index, err;
+
+	err = ds->ops->port_change_master(ds, port, master, extack);
+	if (err && !fail_on_err)
+		dev_err(ds->dev, "port %d failed to assign master %s: %pe\n",
+			port, master->name, ERR_PTR(err));
+
+	if (err && fail_on_err)
+		return err;
+
+	dp->cpu_dp = master->dsa_ptr;
+
+	return 0;
+}
+
+/* Change the dp->cpu_dp affinity for a user port. Note that both cross-chip
+ * notifiers and drivers have implicit assumptions about user-to-CPU-port
+ * mappings, so we unfortunately cannot delay the deletion of the objects
+ * (switchdev, standalone addresses, standalone VLANs) on the old CPU port
+ * until the new CPU port has been set up. So we need to completely tear down
+ * the old CPU port before changing it, and restore it on errors during the
+ * bringup of the new one.
+ */
+int dsa_port_change_master(struct dsa_port *dp, struct net_device *master,
+			   struct netlink_ext_ack *extack)
+{
+	struct net_device *bridge_dev = dsa_port_bridge_dev_get(dp);
+	struct net_device *old_master = dsa_port_to_master(dp);
+	struct net_device *dev = dp->slave;
+	struct dsa_switch *ds = dp->ds;
+	int port = dp->index;
+	bool vlan_filtering;
+	int err, tmp;
+
+	/* Bridges may hold host FDB, MDB and VLAN objects. These need to be
+	 * migrated, so dynamically unoffload and later reoffload the bridge
+	 * port.
+	 */
+	if (bridge_dev) {
+		dsa_port_pre_bridge_leave(dp, bridge_dev);
+		dsa_port_bridge_leave(dp, bridge_dev);
+	}
+
+	/* The port might still be VLAN filtering even if it's no longer
+	 * under a bridge, either due to ds->vlan_filtering_is_global or
+	 * ds->needs_standalone_vlan_filtering. In turn this means VLANs
+	 * on the CPU port.
+	 */
+	vlan_filtering = dsa_port_is_vlan_filtering(dp);
+	if (vlan_filtering) {
+		err = dsa_slave_manage_vlan_filtering(dev, false);
+		if (err) {
+			dev_err(ds->dev,
+				"port %d failed to remove standalone VLANs: %pe\n",
+				port, ERR_PTR(err));
+			goto rewind_old_bridge;
+		}
+	}
+
+	/* Standalone addresses, and addresses of upper interfaces like
+	 * VLAN, LAG, HSR need to be migrated.
+	 */
+	dsa_slave_unsync_ha(dev);
+
+	err = dsa_port_assign_master(dp, master, extack, true);
+	if (err)
+		goto rewind_old_addrs;
+
+	dsa_slave_sync_ha(dev);
+
+	if (vlan_filtering) {
+		err = dsa_slave_manage_vlan_filtering(dev, true);
+		if (err) {
+			dev_err(ds->dev,
+				"port %d failed to restore standalone VLANs: %pe\n",
+				port, ERR_PTR(err));
+			goto rewind_new_addrs;
+		}
+	}
+
+	if (bridge_dev) {
+		err = dsa_port_bridge_join(dp, bridge_dev, extack);
+		if (err && err == -EOPNOTSUPP) {
+			dev_err(ds->dev,
+				"port %d failed to reoffload bridge %s: %pe\n",
+				port, bridge_dev->name, ERR_PTR(err));
+			goto rewind_new_vlan;
+		}
+	}
+
+	return 0;
+
+rewind_new_vlan:
+	if (vlan_filtering)
+		dsa_slave_manage_vlan_filtering(dev, false);
+
+rewind_new_addrs:
+	dsa_slave_unsync_ha(dev);
+
+	dsa_port_assign_master(dp, old_master, NULL, false);
+
+/* Restore the objects on the old CPU port */
+rewind_old_addrs:
+	dsa_slave_sync_ha(dev);
+
+	if (vlan_filtering) {
+		tmp = dsa_slave_manage_vlan_filtering(dev, true);
+		if (tmp) {
+			dev_err(ds->dev, "port %d failed to restore standalone VLANs: %pe\n",
+				dp->index, ERR_PTR(tmp));
+		}
+	}
+
+rewind_old_bridge:
+	if (bridge_dev) {
+		tmp = dsa_port_bridge_join(dp, bridge_dev, extack);
+		if (tmp) {
+			dev_err(ds->dev,
+				"port %d failed to rejoin bridge %s: %pe\n",
+				dp->index, bridge_dev->name, ERR_PTR(tmp));
+		}
+	}
+
+	return err;
+}
+
 void dsa_port_set_tag_protocol(struct dsa_port *cpu_dp,
 			       const struct dsa_device_ops *tag_ops)
 {
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 0d0deca99eba..95bfce49d57d 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -164,6 +164,48 @@ static int dsa_slave_unsync_mc(struct net_device *dev,
 	return dsa_slave_schedule_standalone_work(dev, DSA_MC_DEL, addr, 0);
 }
 
+void dsa_slave_sync_ha(struct net_device *dev)
+{
+	struct dsa_port *dp = dsa_slave_to_port(dev);
+	struct dsa_switch *ds = dp->ds;
+	struct netdev_hw_addr *ha;
+
+	netif_addr_lock_bh(dev);
+
+	netdev_for_each_synced_mc_addr(ha, dev)
+		dsa_slave_sync_mc(dev, ha->addr);
+
+	netdev_for_each_synced_uc_addr(ha, dev)
+		dsa_slave_sync_uc(dev, ha->addr);
+
+	netif_addr_unlock_bh(dev);
+
+	if (dsa_switch_supports_uc_filtering(ds) ||
+	    dsa_switch_supports_mc_filtering(ds))
+		dsa_flush_workqueue();
+}
+
+void dsa_slave_unsync_ha(struct net_device *dev)
+{
+	struct dsa_port *dp = dsa_slave_to_port(dev);
+	struct dsa_switch *ds = dp->ds;
+	struct netdev_hw_addr *ha;
+
+	netif_addr_lock_bh(dev);
+
+	netdev_for_each_synced_uc_addr(ha, dev)
+		dsa_slave_unsync_uc(dev, ha->addr);
+
+	netdev_for_each_synced_mc_addr(ha, dev)
+		dsa_slave_unsync_mc(dev, ha->addr);
+
+	netif_addr_unlock_bh(dev);
+
+	if (dsa_switch_supports_uc_filtering(ds) ||
+	    dsa_switch_supports_mc_filtering(ds))
+		dsa_flush_workqueue();
+}
+
 /* slave mii_bus handling ***************************************************/
 static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg)
 {
@@ -2322,6 +2364,7 @@ int dsa_slave_create(struct dsa_port *port)
 	if (slave_dev == NULL)
 		return -ENOMEM;
 
+	slave_dev->rtnl_link_ops = &dsa_link_ops;
 	slave_dev->ethtool_ops = &dsa_slave_ethtool_ops;
 #if IS_ENABLED(CONFIG_DCB)
 	slave_dev->dcbnl_ops = &dsa_slave_dcbnl_ops;
@@ -2438,6 +2481,80 @@ void dsa_slave_destroy(struct net_device *slave_dev)
 	free_netdev(slave_dev);
 }
 
+int dsa_slave_change_master(struct net_device *dev, struct net_device *master,
+			    struct netlink_ext_ack *extack)
+{
+	struct net_device *old_master = dsa_slave_to_master(dev);
+	struct dsa_port *dp = dsa_slave_to_port(dev);
+	struct dsa_switch *ds = dp->ds;
+	struct net_device *upper;
+	struct list_head *iter;
+	int err;
+
+	if (master == old_master)
+		return 0;
+
+	if (!ds->ops->port_change_master)
+		return -EOPNOTSUPP;
+
+	if (!netdev_uses_dsa(master)) {
+		NL_SET_ERR_MSG_MOD(extack,
+				   "Interface not eligible as DSA master");
+		return -EOPNOTSUPP;
+	}
+
+	netdev_for_each_upper_dev_rcu(master, upper, iter) {
+		if (dsa_slave_dev_check(upper))
+			continue;
+		if (netif_is_bridge_master(upper))
+			continue;
+		NL_SET_ERR_MSG_MOD(extack, "Cannot join master with unknown uppers");
+		return -EOPNOTSUPP;
+	}
+
+	/* Since we allow live-changing the DSA master, plus we auto-open the
+	 * DSA master when the user port opens => we need to ensure that the
+	 * new DSA master is open too.
+	 */
+	if (dev->flags & IFF_UP) {
+		err = dev_open(master, extack);
+		if (err)
+			return err;
+	}
+
+	netdev_upper_dev_unlink(old_master, dev);
+
+	err = netdev_upper_dev_link(master, dev, extack);
+	if (err)
+		goto out_revert_old_master_unlink;
+
+	err = dsa_port_change_master(dp, master, extack);
+	if (err)
+		goto out_revert_master_link;
+
+	/* Update the MTU of the new CPU port through cross-chip notifiers */
+	err = dsa_slave_change_mtu(dev, dev->mtu);
+	if (err && err != -EOPNOTSUPP) {
+		netdev_warn(dev,
+			    "nonfatal error updating MTU with new master: %pe\n",
+			    ERR_PTR(err));
+	}
+
+	/* If the port doesn't have its own MAC address and relies on the DSA
+	 * master's one, inherit it again from the new DSA master.
+	 */
+	if (is_zero_ether_addr(dp->mac))
+		eth_hw_addr_inherit(dev, master);
+
+	return 0;
+
+out_revert_master_link:
+	netdev_upper_dev_unlink(master, dev);
+out_revert_old_master_unlink:
+	netdev_upper_dev_link(old_master, dev, NULL);
+	return err;
+}
+
 bool dsa_slave_dev_check(const struct net_device *dev)
 {
 	return dev->netdev_ops == &dsa_slave_netdev_ops;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH net-next 11/12] net: dsa: allow masters to join a LAG
  2022-05-23 10:42 [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3) Vladimir Oltean
                   ` (9 preceding siblings ...)
  2022-05-23 10:42 ` [RFC PATCH net-next 10/12] net: dsa: allow the DSA master to be seen and changed through rtnetlink Vladimir Oltean
@ 2022-05-23 10:42 ` Vladimir Oltean
  2022-05-23 10:42 ` [RFC PATCH net-next 12/12] net: dsa: felix: add support for changing DSA master Vladimir Oltean
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 31+ messages in thread
From: Vladimir Oltean @ 2022-05-23 10:42 UTC (permalink / raw)
  To: netdev
  Cc: Jakub Kicinski, Florian Fainelli, Vivien Didelot, Andrew Lunn,
	Vladimir Oltean, Tobias Waldekranz, Marek Behún,
	Ansuel Smith, DENG Qingfang, Alvin Šipraga, Claudiu Manoil,
	Alexandre Belloni, UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

From: Vladimir Oltean <vladimir.oltean@nxp.com>

There are 2 ways in which a DSA user port may become handled by 2 CPU
ports in a LAG:

(1) its current DSA master joins a LAG

 ip link del bond0 && ip link add bond0 type bond mode 802.3ad
 ip link set eno2 master bond0

When this happens, all user ports with "eno2" as DSA master get
automatically migrated to "bond0" as DSA master.

(2) it is explicitly configured as such by the user

 # Before, the DSA master was eno3
 ip link set swp0 type dsa master bond0

The design of this configuration is that the LAG device dynamically
becomes a DSA master through dsa_master_setup() when the first physical
DSA master becomes a LAG slave, and stops being so through
dsa_master_teardown() when the last physical DSA master leaves.

A LAG interface is considered as a valid DSA master only if it contains
existing DSA masters, and no other lower interfaces. Therefore, we
mainly rely on method (1) to enter this configuration.

Each physical DSA master (LAG slave) retains its dev->dsa_ptr for when
it becomes a standalone DSA master again. But the LAG master also has a
dev->dsa_ptr, and this is actually duplicated from one of the physical
LAG slaves, and therefore needs to be balanced when LAG slaves come and
go.

To the switch driver, putting DSA masters in a LAG is seen as putting
their associated CPU ports in a LAG.

We need to prepare cross-chip host FDB notifiers for CPU ports in a LAG,
by calling the driver's ->lag_fdb_add method rather than ->port_fdb_add.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 include/net/dsa.h  |   6 ++
 net/dsa/dsa_priv.h |   5 ++
 net/dsa/master.c   |  59 +++++++++++++++++
 net/dsa/port.c     |   1 +
 net/dsa/slave.c    | 157 +++++++++++++++++++++++++++++++++++++++++++--
 net/dsa/switch.c   |  22 +++++--
 6 files changed, 242 insertions(+), 8 deletions(-)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 0958ad3289c9..158efd3e2ab3 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -296,6 +296,9 @@ struct dsa_port {
 	u8			master_admin_up:1;
 	u8			master_oper_up:1;
 
+	/* Valid only on user ports */
+	u8			cpu_port_in_lag:1;
+
 	u8			setup:1;
 
 	struct device_node	*dn;
@@ -720,6 +723,9 @@ static inline bool dsa_port_offloads_lag(struct dsa_port *dp,
 
 static inline struct net_device *dsa_port_to_master(const struct dsa_port *dp)
 {
+	if (dp->cpu_port_in_lag)
+		return dsa_port_lag_dev_get(dp->cpu_dp);
+
 	return dp->cpu_dp->master;
 }
 
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 1ce0e48d5a92..236fb1fb7b6c 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -184,6 +184,11 @@ static inline int dsa_tag_protocol_overhead(const struct dsa_device_ops *ops)
 /* master.c */
 int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp);
 void dsa_master_teardown(struct net_device *dev);
+int dsa_master_lag_setup(struct net_device *lag_dev, struct dsa_port *cpu_dp,
+			 struct netdev_lag_upper_info *uinfo,
+			 struct netlink_ext_ack *extack);
+void dsa_master_lag_teardown(struct net_device *lag_dev,
+			     struct dsa_port *cpu_dp);
 
 static inline struct net_device *dsa_master_find_slave(struct net_device *dev,
 						       int device, int port)
diff --git a/net/dsa/master.c b/net/dsa/master.c
index a7420bad0a0a..66fb972da2dd 100644
--- a/net/dsa/master.c
+++ b/net/dsa/master.c
@@ -418,3 +418,62 @@ void dsa_master_teardown(struct net_device *dev)
 	 */
 	wmb();
 }
+
+int dsa_master_lag_setup(struct net_device *lag_dev, struct dsa_port *cpu_dp,
+			 struct netdev_lag_upper_info *uinfo,
+			 struct netlink_ext_ack *extack)
+{
+	bool master_setup = false;
+	struct net_device *lower;
+	struct list_head *iter;
+	int err;
+
+	/* To be eligible as a DSA master, a LAG must have all lower
+	 * interfaces be eligible DSA masters.
+	 */
+	netdev_for_each_lower_dev(lag_dev, lower, iter) {
+		if (!netdev_uses_dsa(lower)) {
+			NL_SET_ERR_MSG_MOD(extack,
+					   "All LAG ports must be eligible as DSA masters");
+			return -EINVAL;
+		}
+	}
+
+	if (!netdev_uses_dsa(lag_dev)) {
+		err = dsa_master_setup(lag_dev, cpu_dp);
+		if (err)
+			return err;
+	}
+
+	err = dsa_port_lag_join(cpu_dp, lag_dev, uinfo, extack);
+	if (err) {
+		NL_SET_ERR_MSG_MOD(extack,
+				   "CPU port failed to join LAG");
+		goto out_master_teardown;
+	}
+
+	return 0;
+
+out_master_teardown:
+	if (master_setup)
+		dsa_master_teardown(lag_dev);
+	return err;
+}
+
+/* Tear down a master if there isn't any other user port on it,
+ * optionally also destroying LAG information.
+ */
+void dsa_master_lag_teardown(struct net_device *lag_dev,
+			     struct dsa_port *cpu_dp)
+{
+	struct net_device *upper;
+	struct list_head *iter;
+
+	dsa_port_lag_leave(cpu_dp, lag_dev);
+
+	netdev_for_each_upper_dev_rcu(lag_dev, upper, iter)
+		if (dsa_slave_dev_check(upper))
+			return;
+
+	dsa_master_teardown(lag_dev);
+}
diff --git a/net/dsa/port.c b/net/dsa/port.c
index ced7f8d8ec62..a90c03d15061 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -1388,6 +1388,7 @@ static int dsa_port_assign_master(struct dsa_port *dp,
 		return err;
 
 	dp->cpu_dp = master->dsa_ptr;
+	dp->cpu_port_in_lag = netif_is_lag_master(master);
 
 	return 0;
 }
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 95bfce49d57d..f21524c0fbd5 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -2812,6 +2812,10 @@ dsa_master_prechangeupper_sanity_check(struct net_device *master,
 	if (netif_is_bridge_master(info->upper_dev))
 		return NOTIFY_DONE;
 
+	/* Allow LAG uppers */
+	if (netif_is_lag_master(info->upper_dev))
+		return NOTIFY_DONE;
+
 	extack = netdev_notifier_info_to_extack(&info->info);
 
 	NL_SET_ERR_MSG_MOD(extack,
@@ -2859,6 +2863,138 @@ dsa_bridge_prechangelower_sanity_check(struct net_device *new_lower,
 	return NOTIFY_DONE;
 }
 
+static void dsa_tree_migrate_ports_from_lag_master(struct dsa_switch_tree *dst,
+						   struct net_device *lag_dev)
+{
+	struct net_device *new_master;
+	struct dsa_port *dp;
+	int err;
+
+	new_master = dsa_tree_find_first_master(dst);
+
+	dsa_tree_for_each_user_port(dp, dst) {
+		if (dsa_port_to_master(dp) != lag_dev)
+			continue;
+
+		err = dsa_port_change_master(dp, new_master, NULL);
+		if (err) {
+			netdev_err(dp->slave,
+				   "failed to restore master to %s: %pe\n",
+				   new_master->name, ERR_PTR(err));
+		}
+	}
+}
+
+static int dsa_master_lag_join(struct net_device *master,
+			       struct net_device *lag_dev,
+			       struct netdev_lag_upper_info *uinfo,
+			       struct netlink_ext_ack *extack)
+{
+	struct dsa_port *cpu_dp = master->dsa_ptr;
+	struct dsa_switch_tree *dst = cpu_dp->dst;
+	struct dsa_port *dp;
+	int err;
+
+	err = dsa_master_lag_setup(lag_dev, cpu_dp, uinfo, extack);
+	if (err)
+		return err;
+
+	dsa_tree_for_each_user_port(dp, dst) {
+		if (dsa_port_to_master(dp) != master)
+			continue;
+
+		err = dsa_port_change_master(dp, lag_dev, extack);
+		if (err)
+			goto restore;
+	}
+
+	return 0;
+
+restore:
+	dsa_tree_for_each_user_port_continue_reverse(dp, dst) {
+		if (dsa_port_to_master(dp) != lag_dev)
+			continue;
+
+		err = dsa_port_change_master(dp, master, NULL);
+		if (err) {
+			netdev_err(dp->slave,
+				   "failed to restore master to %s: %pe\n",
+				   master->name, ERR_PTR(err));
+		}
+	}
+
+	dsa_master_lag_teardown(lag_dev, master->dsa_ptr);
+
+	return err;
+}
+
+static void dsa_master_lag_leave(struct net_device *master,
+				 struct net_device *lag_dev)
+{
+	struct dsa_port *dp, *cpu_dp = lag_dev->dsa_ptr;
+	struct dsa_switch_tree *dst = cpu_dp->dst;
+	struct dsa_port *new_cpu_dp = NULL;
+	struct net_device *lower;
+	struct list_head *iter;
+
+	netdev_for_each_lower_dev(lag_dev, lower, iter) {
+		if (netdev_uses_dsa(lower)) {
+			new_cpu_dp = lower->dsa_ptr;
+			break;
+		}
+	}
+
+	if (new_cpu_dp) {
+		/* Update the CPU port of the user ports still under the LAG
+		 * so that dsa_port_to_master() continues to work properly
+		 */
+		dsa_tree_for_each_user_port(dp, dst)
+			if (dsa_port_to_master(dp) == lag_dev)
+				dp->cpu_dp = new_cpu_dp;
+
+		/* Update the index of the virtual CPU port to match the lowest
+		 * physical CPU port
+		 */
+		lag_dev->dsa_ptr = new_cpu_dp;
+		wmb();
+	} else {
+		/* If the LAG DSA master has no ports left, migrate back all
+		 * user ports to the first physical CPU port
+		 */
+		dsa_tree_migrate_ports_from_lag_master(dst, lag_dev);
+	}
+
+	/* This DSA master has left its LAG in any case, so let
+	 * the CPU port leave the hardware LAG as well
+	 */
+	dsa_master_lag_teardown(lag_dev, master->dsa_ptr);
+}
+
+static int dsa_master_changeupper(struct net_device *dev,
+				  struct netdev_notifier_changeupper_info *info)
+{
+	struct netlink_ext_ack *extack;
+	int err = NOTIFY_DONE;
+
+	if (!netdev_uses_dsa(dev))
+		return err;
+
+	extack = netdev_notifier_info_to_extack(&info->info);
+
+	if (netif_is_lag_master(info->upper_dev)) {
+		if (info->linking) {
+			err = dsa_master_lag_join(dev, info->upper_dev,
+						  info->upper_info, extack);
+			err = notifier_from_errno(err);
+		} else {
+			dsa_master_lag_leave(dev, info->upper_dev);
+			err = NOTIFY_OK;
+		}
+	}
+
+	return err;
+}
+
 static int dsa_slave_netdevice_event(struct notifier_block *nb,
 				     unsigned long event, void *ptr)
 {
@@ -2902,6 +3038,10 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb,
 		if (notifier_to_errno(err))
 			return err;
 
+		err = dsa_master_changeupper(dev, ptr);
+		if (notifier_to_errno(err))
+			return err;
+
 		break;
 	}
 	case NETDEV_CHANGELOWERSTATE: {
@@ -2909,12 +3049,21 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb,
 		struct dsa_port *dp;
 		int err;
 
-		if (!dsa_slave_dev_check(dev))
-			break;
+		if (dsa_slave_dev_check(dev)) {
+			dp = dsa_slave_to_port(dev);
+
+			err = dsa_port_lag_change(dp, info->lower_state_info);
+		}
 
-		dp = dsa_slave_to_port(dev);
+		/* Mirror LAG port events on DSA masters that are in
+		 * a LAG towards their respective switch CPU ports
+		 */
+		if (netdev_uses_dsa(dev)) {
+			dp = dev->dsa_ptr;
+
+			err = dsa_port_lag_change(dp, info->lower_state_info);
+		}
 
-		err = dsa_port_lag_change(dp, info->lower_state_info);
 		return notifier_from_errno(err);
 	}
 	case NETDEV_CHANGE:
diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index 2b56218fc57c..f443916d2571 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -397,8 +397,15 @@ static int dsa_switch_host_fdb_add(struct dsa_switch *ds,
 
 	dsa_switch_for_each_port(dp, ds) {
 		if (dsa_port_host_address_match(dp, info->dp)) {
-			err = dsa_port_do_fdb_add(dp, info->addr, info->vid,
-						  info->db);
+			if (dsa_port_is_cpu(dp) && info->dp->cpu_port_in_lag) {
+				err = dsa_switch_do_lag_fdb_add(ds, dp->lag,
+								info->addr,
+								info->vid,
+								info->db);
+			} else {
+				err = dsa_port_do_fdb_add(dp, info->addr,
+							  info->vid, info->db);
+			}
 			if (err)
 				break;
 		}
@@ -418,8 +425,15 @@ static int dsa_switch_host_fdb_del(struct dsa_switch *ds,
 
 	dsa_switch_for_each_port(dp, ds) {
 		if (dsa_port_host_address_match(dp, info->dp)) {
-			err = dsa_port_do_fdb_del(dp, info->addr, info->vid,
-						  info->db);
+			if (dsa_port_is_cpu(dp) && info->dp->cpu_port_in_lag) {
+				err = dsa_switch_do_lag_fdb_del(ds, dp->lag,
+								info->addr,
+								info->vid,
+								info->db);
+			} else {
+				err = dsa_port_do_fdb_del(dp, info->addr,
+							  info->vid, info->db);
+			}
 			if (err)
 				break;
 		}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [RFC PATCH net-next 12/12] net: dsa: felix: add support for changing DSA master
  2022-05-23 10:42 [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3) Vladimir Oltean
                   ` (10 preceding siblings ...)
  2022-05-23 10:42 ` [RFC PATCH net-next 11/12] net: dsa: allow masters to join a LAG Vladimir Oltean
@ 2022-05-23 10:42 ` Vladimir Oltean
  2022-05-23 21:53 ` [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3) Florian Fainelli
  2022-05-24 12:02 ` Ansuel Smith
  13 siblings, 0 replies; 31+ messages in thread
From: Vladimir Oltean @ 2022-05-23 10:42 UTC (permalink / raw)
  To: netdev
  Cc: Jakub Kicinski, Florian Fainelli, Vivien Didelot, Andrew Lunn,
	Vladimir Oltean, Tobias Waldekranz, Marek Behún,
	Ansuel Smith, DENG Qingfang, Alvin Šipraga, Claudiu Manoil,
	Alexandre Belloni, UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

From: Vladimir Oltean <vladimir.oltean@nxp.com>

Changing the DSA master means different things depending on the tagging
protocol in use.

For NPI mode ("ocelot" and "seville"), there is a single port which can
be configured as NPI, but DSA only permits changing the CPU port
affinity of user ports one by one. So changing a user port to a
different NPI port globally changes what the NPI port is, and breaks the
user ports still using the old one.

To address this while still permitting the change of the NPI port,
require that the user ports which are still affine to the old NPI port
are down, and cannot be brought up until they are all affine to the same
NPI port.

The tag_8021q mode ("ocelot-8021q") is more flexible, in that each user
port can be freely assigned to one CPU port or to the other. This works
by filtering host addresses towards both tag_8021q CPU ports, and then
restricting the forwarding from a certain user port only to one of the
two tag_8021q CPU ports.

Additionally, the 2 tag_8021q CPU ports can be placed in a LAG. This
works by enabling forwarding via PGID_SRC from a certain user port
towards the logical port ID containing both tag_8021q CPU ports, but
then restricting forwarding per packet, via the LAG hash codes in
PGID_AGGR, to either one or the other.

When we change the DSA master to a LAG device, DSA guarantees us that
the LAG has at least one lower interface as a physical DSA master.
But DSA masters can come and go as lowers of that LAG, and
ds->ops->port_change_master() will not get called, because the DSA
master is still the same (the LAG). So we need to hook into the
ds->ops->port_lag_{join,leave} calls on the CPU ports and update the
logical port ID of the LAG that user ports are assigned to.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 drivers/net/dsa/ocelot/felix.c     | 117 ++++++++++++++++++++++++++++-
 drivers/net/dsa/ocelot/felix.h     |   3 +
 drivers/net/ethernet/mscc/ocelot.c |   3 +-
 include/soc/mscc/ocelot.h          |   1 +
 4 files changed, 121 insertions(+), 3 deletions(-)

diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index 3e07dc39007a..4e648382c05d 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -42,6 +42,25 @@ static struct net_device *felix_classify_db(struct dsa_db db)
 	}
 }
 
+static int felix_cpu_port_for_master(struct dsa_switch *ds,
+				     struct net_device *master)
+{
+	struct ocelot *ocelot = ds->priv;
+	struct dsa_port *cpu_dp;
+	int lag;
+
+	if (netif_is_lag_master(master)) {
+		mutex_lock(&ocelot->fwd_domain_lock);
+		lag = ocelot_bond_get_id(ocelot, master);
+		mutex_unlock(&ocelot->fwd_domain_lock);
+
+		return lag;
+	}
+
+	cpu_dp = master->dsa_ptr;
+	return cpu_dp->index;
+}
+
 /* Set up VCAP ES0 rules for pushing a tag_8021q VLAN towards the CPU such that
  * the tagger can perform RX source port identification.
  */
@@ -422,6 +441,39 @@ static unsigned long felix_tag_npi_get_host_fwd_mask(struct dsa_switch *ds)
 	return BIT(ocelot->num_phys_ports);
 }
 
+static int felix_tag_npi_change_master(struct dsa_switch *ds, int port,
+				       struct net_device *master,
+				       struct netlink_ext_ack *extack)
+{
+	struct dsa_port *dp = dsa_to_port(ds, port), *other_dp;
+	struct ocelot *ocelot = ds->priv;
+
+	if (netif_is_lag_master(master)) {
+		NL_SET_ERR_MSG_MOD(extack, "LAG DSA master only supported using ocelot-8021q");
+		return -EOPNOTSUPP;
+	}
+
+	/* Changing the NPI port breaks user ports still assigned to the old
+	 * one, so only allow it while they're down, and don't allow them to
+	 * come back up until they're all changed to the new one.
+	 */
+	dsa_switch_for_each_user_port(other_dp, ds) {
+		struct net_device *slave = other_dp->slave;
+
+		if (other_dp != dp && (slave->flags & IFF_UP) &&
+		    dsa_port_to_master(other_dp) != master) {
+			NL_SET_ERR_MSG_MOD(extack,
+					   "Cannot change while old master still has users");
+			return -EOPNOTSUPP;
+		}
+	}
+
+	felix_npi_port_deinit(ocelot, ocelot->npi);
+	felix_npi_port_init(ocelot, felix_cpu_port_for_master(ds, master));
+
+	return 0;
+}
+
 /* Alternatively to using the NPI functionality, that same hardware MAC
  * connected internally to the enetc or fman DSA master can be configured to
  * use the software-defined tag_8021q frame format. As far as the hardware is
@@ -433,6 +485,7 @@ static const struct felix_tag_proto_ops felix_tag_npi_proto_ops = {
 	.setup			= felix_tag_npi_setup,
 	.teardown		= felix_tag_npi_teardown,
 	.get_host_fwd_mask	= felix_tag_npi_get_host_fwd_mask,
+	.change_master		= felix_tag_npi_change_master,
 };
 
 static int felix_tag_8021q_setup(struct dsa_switch *ds)
@@ -501,10 +554,24 @@ static unsigned long felix_tag_8021q_get_host_fwd_mask(struct dsa_switch *ds)
 	return dsa_cpu_ports(ds);
 }
 
+static int felix_tag_8021q_change_master(struct dsa_switch *ds, int port,
+					 struct net_device *master,
+					 struct netlink_ext_ack *extack)
+{
+	int cpu = felix_cpu_port_for_master(ds, master);
+	struct ocelot *ocelot = ds->priv;
+
+	ocelot_port_unassign_dsa_8021q_cpu(ocelot, port);
+	ocelot_port_assign_dsa_8021q_cpu(ocelot, port, cpu);
+
+	return felix_update_trapping_destinations(ds, true);
+}
+
 static const struct felix_tag_proto_ops felix_tag_8021q_proto_ops = {
 	.setup			= felix_tag_8021q_setup,
 	.teardown		= felix_tag_8021q_teardown,
 	.get_host_fwd_mask	= felix_tag_8021q_get_host_fwd_mask,
+	.change_master		= felix_tag_8021q_change_master,
 };
 
 static void felix_set_host_flood(struct dsa_switch *ds, unsigned long mask,
@@ -664,6 +731,16 @@ static void felix_port_set_host_flood(struct dsa_switch *ds, int port,
 			     !!felix->host_flood_mc_mask, true);
 }
 
+static int felix_port_change_master(struct dsa_switch *ds, int port,
+				    struct net_device *master,
+				    struct netlink_ext_ack *extack)
+{
+	struct ocelot *ocelot = ds->priv;
+	struct felix *felix = ocelot_to_felix(ocelot);
+
+	return felix->tag_proto_ops->change_master(ds, port, master, extack);
+}
+
 static int felix_set_ageing_time(struct dsa_switch *ds,
 				 unsigned int ageing_time)
 {
@@ -855,8 +932,17 @@ static int felix_lag_join(struct dsa_switch *ds, int port,
 			  struct netdev_lag_upper_info *info)
 {
 	struct ocelot *ocelot = ds->priv;
+	int err;
 
-	return ocelot_port_lag_join(ocelot, port, lag.dev, info);
+	err = ocelot_port_lag_join(ocelot, port, lag.dev, info);
+	if (err)
+		return err;
+
+	/* Update the logical LAG port that serves as tag_8021q CPU port */
+	if (!dsa_is_cpu_port(ds, port))
+		return 0;
+
+	return felix_port_change_master(ds, port, lag.dev, NULL);
 }
 
 static int felix_lag_leave(struct dsa_switch *ds, int port,
@@ -866,7 +952,11 @@ static int felix_lag_leave(struct dsa_switch *ds, int port,
 
 	ocelot_port_lag_leave(ocelot, port, lag.dev);
 
-	return 0;
+	/* Update the logical LAG port that serves as tag_8021q CPU port */
+	if (!dsa_is_cpu_port(ds, port))
+		return 0;
+
+	return felix_port_change_master(ds, port, lag.dev, NULL);
 }
 
 static int felix_lag_change(struct dsa_switch *ds, int port)
@@ -1004,6 +1094,27 @@ static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port,
 		felix->info->port_sched_speed_set(ocelot, port, speed);
 }
 
+static int felix_port_enable(struct dsa_switch *ds, int port,
+			     struct phy_device *phydev)
+{
+	struct dsa_port *dp = dsa_to_port(ds, port);
+	struct ocelot *ocelot = ds->priv;
+
+	if (!dsa_port_is_user(dp))
+		return 0;
+
+	if (ocelot->npi >= 0) {
+		struct net_device *master = dsa_port_to_master(dp);
+
+		if (felix_cpu_port_for_master(ds, master) != ocelot->npi) {
+			dev_err(ds->dev, "Multiple masters are not allowed\n");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static void felix_port_qos_map_init(struct ocelot *ocelot, int port)
 {
 	int i;
@@ -1839,6 +1950,7 @@ const struct dsa_switch_ops felix_switch_ops = {
 	.phylink_mac_select_pcs		= felix_phylink_mac_select_pcs,
 	.phylink_mac_link_down		= felix_phylink_mac_link_down,
 	.phylink_mac_link_up		= felix_phylink_mac_link_up,
+	.port_enable			= felix_port_enable,
 	.port_fast_age			= felix_port_fast_age,
 	.port_fdb_dump			= felix_fdb_dump,
 	.port_fdb_add			= felix_fdb_add,
@@ -1894,6 +2006,7 @@ const struct dsa_switch_ops felix_switch_ops = {
 	.port_add_dscp_prio		= felix_port_add_dscp_prio,
 	.port_del_dscp_prio		= felix_port_del_dscp_prio,
 	.port_set_host_flood		= felix_port_set_host_flood,
+	.port_change_master		= felix_port_change_master,
 };
 
 struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port)
diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h
index 9e07eb7ee28d..a1350342d47c 100644
--- a/drivers/net/dsa/ocelot/felix.h
+++ b/drivers/net/dsa/ocelot/felix.h
@@ -70,6 +70,9 @@ struct felix_tag_proto_ops {
 	int (*setup)(struct dsa_switch *ds);
 	void (*teardown)(struct dsa_switch *ds);
 	unsigned long (*get_host_fwd_mask)(struct dsa_switch *ds);
+	int (*change_master)(struct dsa_switch *ds, int port,
+			     struct net_device *master,
+			     struct netlink_ext_ack *extack);
 };
 
 extern const struct dsa_switch_ops felix_switch_ops;
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index 8da7e25a47c9..3a73bf31f3eb 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -2036,7 +2036,7 @@ static u32 ocelot_get_bond_mask(struct ocelot *ocelot, struct net_device *bond)
 /* The logical port number of a LAG is equal to the lowest numbered physical
  * port ID present in that LAG. It may change if that port ever leaves the LAG.
  */
-static int ocelot_bond_get_id(struct ocelot *ocelot, struct net_device *bond)
+int ocelot_bond_get_id(struct ocelot *ocelot, struct net_device *bond)
 {
 	int bond_mask = ocelot_get_bond_mask(ocelot, bond);
 
@@ -2045,6 +2045,7 @@ static int ocelot_bond_get_id(struct ocelot *ocelot, struct net_device *bond)
 
 	return __ffs(bond_mask);
 }
+EXPORT_SYMBOL_GPL(ocelot_bond_get_id);
 
 static u32 ocelot_dsa_8021q_cpu_assigned_ports(struct ocelot *ocelot,
 					       struct ocelot_port *cpu)
diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
index 5f88385a7748..9b777e4fa98e 100644
--- a/include/soc/mscc/ocelot.h
+++ b/include/soc/mscc/ocelot.h
@@ -948,6 +948,7 @@ int ocelot_port_lag_join(struct ocelot *ocelot, int port,
 void ocelot_port_lag_leave(struct ocelot *ocelot, int port,
 			   struct net_device *bond);
 void ocelot_port_lag_change(struct ocelot *ocelot, int port, bool lag_tx_active);
+int ocelot_bond_get_id(struct ocelot *ocelot, struct net_device *bond);
 
 int ocelot_devlink_sb_register(struct ocelot *ocelot);
 void ocelot_devlink_sb_unregister(struct ocelot *ocelot);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH net-next 01/12] net: introduce iterators over synced hw addresses
  2022-05-23 10:42 ` [RFC PATCH net-next 01/12] net: introduce iterators over synced hw addresses Vladimir Oltean
@ 2022-05-23 17:54   ` Florian Fainelli
  0 siblings, 0 replies; 31+ messages in thread
From: Florian Fainelli @ 2022-05-23 17:54 UTC (permalink / raw)
  To: Vladimir Oltean, netdev
  Cc: Jakub Kicinski, Vivien Didelot, Andrew Lunn, Tobias Waldekranz,
	Marek Behún, Ansuel Smith, DENG Qingfang,
	Alvin Šipraga, Claudiu Manoil, Alexandre Belloni,
	UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

On 5/23/22 03:42, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> Some network drivers use __dev_mc_sync()/__dev_uc_sync() and therefore
> program the hardware only with addresses with a non-zero sync_cnt.
> 
> Some of the above drivers also need to save/restore the address
> filtering lists when certain events happen, and they need to walk
> through the struct net_device :: uc and struct net_device :: mc lists.
> But these lists contain unsynced addresses too.
> 
> To keep the appearance of an elementary form of data encapsulation,
> provide iterators through these lists that only look at entries with a
> non-zero sync_cnt, instead of filtering entries out from device drivers.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH net-next 03/12] net: dsa: don't stop at NOTIFY_OK when calling ds->ops->port_prechangeupper
  2022-05-23 10:42 ` [RFC PATCH net-next 03/12] net: dsa: don't stop at NOTIFY_OK when calling ds->ops->port_prechangeupper Vladimir Oltean
@ 2022-05-23 17:56   ` Florian Fainelli
  0 siblings, 0 replies; 31+ messages in thread
From: Florian Fainelli @ 2022-05-23 17:56 UTC (permalink / raw)
  To: Vladimir Oltean, netdev
  Cc: Jakub Kicinski, Vivien Didelot, Andrew Lunn, Tobias Waldekranz,
	Marek Behún, Ansuel Smith, DENG Qingfang,
	Alvin Šipraga, Claudiu Manoil, Alexandre Belloni,
	UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

On 5/23/22 03:42, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> dsa_slave_prechangeupper_sanity_check() is supposed to enforce some
> adjacency restrictions, and calls ds->ops->port_prechangeupper if the
> driver implements it.
> 
> We convert the error code from the port_prechangeupper() call to a
> notifier code, and 0 is converted to NOTIFY_OK, but the caller of
> dsa_slave_prechangeupper_sanity_check() stops at any notifier code
> different from NOTIFY_DONE.
> 
> Avoid this by converting back the notifier code to an error code, so
> that both NOTIFY_OK and NOTIFY_DONE will be seen as 0. This allows more
> parallel sanity check functions to be added.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH net-next 04/12] net: bridge: move DSA master bridging restriction to DSA
  2022-05-23 10:42 ` [RFC PATCH net-next 04/12] net: bridge: move DSA master bridging restriction to DSA Vladimir Oltean
@ 2022-05-23 17:57   ` Florian Fainelli
  2022-05-23 23:02   ` Nikolay Aleksandrov
  1 sibling, 0 replies; 31+ messages in thread
From: Florian Fainelli @ 2022-05-23 17:57 UTC (permalink / raw)
  To: Vladimir Oltean, netdev
  Cc: Jakub Kicinski, Vivien Didelot, Andrew Lunn, Tobias Waldekranz,
	Marek Behún, Ansuel Smith, DENG Qingfang,
	Alvin Šipraga, Claudiu Manoil, Alexandre Belloni,
	UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

On 5/23/22 03:42, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> When DSA gains support for multiple CPU ports in a LAG, it will become
> mandatory to monitor the changeupper events for the DSA master.
> 
> In fact, there are already some restrictions to be imposed in that area,
> namely that a DSA master cannot be a bridge port except in some special
> circumstances.
> 
> Centralize the restrictions at the level of the DSA layer as a
> preliminary step.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH net-next 05/12] net: dsa: existing DSA masters cannot join upper interfaces
  2022-05-23 10:42 ` [RFC PATCH net-next 05/12] net: dsa: existing DSA masters cannot join upper interfaces Vladimir Oltean
@ 2022-05-23 17:58   ` Florian Fainelli
  0 siblings, 0 replies; 31+ messages in thread
From: Florian Fainelli @ 2022-05-23 17:58 UTC (permalink / raw)
  To: Vladimir Oltean, netdev
  Cc: Jakub Kicinski, Vivien Didelot, Andrew Lunn, Tobias Waldekranz,
	Marek Behún, Ansuel Smith, DENG Qingfang,
	Alvin Šipraga, Claudiu Manoil, Alexandre Belloni,
	UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

On 5/23/22 03:42, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> All the traffic to/from a DSA master is supposed to be distributed among
> its DSA switch upper interfaces, so we should not allow other upper
> device kinds.
> 
> An exception to this is DSA_TAG_PROTO_NONE (switches with no DSA tags),
> and in that case it is actually expected to create e.g. VLAN interfaces
> on the master. But for those, netdev_uses_dsa(master) returns false, so
> the restriction doesn't apply.
> 
> The motivation for this change is to allow LAG interfaces of DSA masters
> to be DSA masters themselves. We want to restrict the user's degrees of
> freedom by 1: the LAG should already have all DSA masters as lowers, and
> while lower ports of the LAG can be removed, none can be added after the
> fact.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH net-next 06/12] net: dsa: only bring down user ports assigned to a given DSA master
  2022-05-23 10:42 ` [RFC PATCH net-next 06/12] net: dsa: only bring down user ports assigned to a given DSA master Vladimir Oltean
@ 2022-05-23 17:59   ` Florian Fainelli
  0 siblings, 0 replies; 31+ messages in thread
From: Florian Fainelli @ 2022-05-23 17:59 UTC (permalink / raw)
  To: Vladimir Oltean, netdev
  Cc: Jakub Kicinski, Vivien Didelot, Andrew Lunn, Tobias Waldekranz,
	Marek Behún, Ansuel Smith, DENG Qingfang,
	Alvin Šipraga, Claudiu Manoil, Alexandre Belloni,
	UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

On 5/23/22 03:42, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> This is an adaptation of commit c0a8a9c27493 ("net: dsa: automatically
> bring user ports down when master goes down") for multiple DSA masters.
> When a DSA master goes down, only the user ports under its control
> should go down too, the others can still send/receive traffic.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH net-next 07/12] net: dsa: all DSA masters must be down when changing the tagging protocol
  2022-05-23 10:42 ` [RFC PATCH net-next 07/12] net: dsa: all DSA masters must be down when changing the tagging protocol Vladimir Oltean
@ 2022-05-23 18:00   ` Florian Fainelli
  0 siblings, 0 replies; 31+ messages in thread
From: Florian Fainelli @ 2022-05-23 18:00 UTC (permalink / raw)
  To: Vladimir Oltean, netdev
  Cc: Jakub Kicinski, Vivien Didelot, Andrew Lunn, Tobias Waldekranz,
	Marek Behún, Ansuel Smith, DENG Qingfang,
	Alvin Šipraga, Claudiu Manoil, Alexandre Belloni,
	UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

On 5/23/22 03:42, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> The fact that the tagging protocol is set and queried from the
> /sys/class/net/<dsa-master>/dsa/tagging file is a bit of a quirk from
> the single CPU port days which isn't aging very well now that DSA can
> have more than a single CPU port. This is because the tagging protocol
> is a switch property, yet in the presence of multiple CPU ports it can
> be queried and set from multiple sysfs files, all of which are handled
> by the same implementation.
> 
> The current logic ensures that the net device whose sysfs file we're
> changing the tagging protocol through must be down. That net device is
> the DSA master, and this is fine for single DSA master / CPU port setups.
> 
> But exactly because the tagging protocol is per switch [ tree, in fact ]
> and not per DSA master, this isn't fine any longer with multiple CPU
> ports, and we must iterate through the tree and find all DSA masters,
> and make sure that all of them are down.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH net-next 08/12] net: dsa: use dsa_tree_for_each_cpu_port in dsa_tree_{setup,teardown}_master
  2022-05-23 10:42 ` [RFC PATCH net-next 08/12] net: dsa: use dsa_tree_for_each_cpu_port in dsa_tree_{setup,teardown}_master Vladimir Oltean
@ 2022-05-23 18:01   ` Florian Fainelli
  0 siblings, 0 replies; 31+ messages in thread
From: Florian Fainelli @ 2022-05-23 18:01 UTC (permalink / raw)
  To: Vladimir Oltean, netdev
  Cc: Jakub Kicinski, Vivien Didelot, Andrew Lunn, Tobias Waldekranz,
	Marek Behún, Ansuel Smith, DENG Qingfang,
	Alvin Šipraga, Claudiu Manoil, Alexandre Belloni,
	UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

On 5/23/22 03:42, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> More logic will be added to dsa_tree_setup_master() and
> dsa_tree_teardown_master() in upcoming changes.
> 
> Reduce the indentation by one level in these functions by introducing
> and using a dedicated iterator for CPU ports of a tree.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH net-next 09/12] net: dsa: introduce dsa_port_get_master()
  2022-05-23 10:42 ` [RFC PATCH net-next 09/12] net: dsa: introduce dsa_port_get_master() Vladimir Oltean
@ 2022-05-23 18:08   ` Florian Fainelli
  0 siblings, 0 replies; 31+ messages in thread
From: Florian Fainelli @ 2022-05-23 18:08 UTC (permalink / raw)
  To: Vladimir Oltean, netdev
  Cc: Jakub Kicinski, Vivien Didelot, Andrew Lunn, Tobias Waldekranz,
	Marek Behún, Ansuel Smith, DENG Qingfang,
	Alvin Šipraga, Claudiu Manoil, Alexandre Belloni,
	UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

On 5/23/22 03:42, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> There is a desire to support for DSA masters in a LAG.
> 
> That configuration is intended to work by simply enslaving the master to
> a bonding/team device. But the physical DSA master (the LAG slave) still
> has a dev->dsa_ptr, and that cpu_dp still corresponds to the physical
> CPU port.
> 
> However, we would like to be able to retrieve the LAG that's the upper
> of the physical DSA master. In preparation for that, introduce a helper
> called dsa_port_get_master() that replaces all occurrences of the
> dp->cpu_dp->master pattern. The distinction between LAG and non-LAG will
> be made later within the helper itself.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH net-next 02/12] net: dsa: walk through all changeupper notifier functions
  2022-05-23 10:42 ` [RFC PATCH net-next 02/12] net: dsa: walk through all changeupper notifier functions Vladimir Oltean
@ 2022-05-23 18:11   ` Florian Fainelli
  0 siblings, 0 replies; 31+ messages in thread
From: Florian Fainelli @ 2022-05-23 18:11 UTC (permalink / raw)
  To: Vladimir Oltean, netdev
  Cc: Jakub Kicinski, Vivien Didelot, Andrew Lunn, Tobias Waldekranz,
	Marek Behún, Ansuel Smith, DENG Qingfang,
	Alvin Šipraga, Claudiu Manoil, Alexandre Belloni,
	UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

On 5/23/22 03:42, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> Traditionally, DSA has had a single netdev notifier handling function
> for each device type.
> 
> For the sake of code cleanliness, we would like to introduce more
> handling functions which do one thing, but the conditions for entering
> these functions start to overlap. Example: a handling function which
> tracks whether any bridges contain both DSA and non-DSA interfaces.
> Either this is placed before dsa_slave_changeupper(), case in which it
> will prevent that function from executing, or we place it after
> dsa_slave_changeupper(), case in which we will prevent it from
> executing. The other alternative is to ignore errors from the new
> handling function (not ideal).
> 
> To support this usage, we need to change the pattern. In the new model,
> we enter all notifier handling sub-functions, and exit with NOTIFY_DONE
> if there is nothing to do. This allows the sub-functions to be
> relatively free-form and independent from each other.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH net-next 10/12] net: dsa: allow the DSA master to be seen and changed through rtnetlink
  2022-05-23 10:42 ` [RFC PATCH net-next 10/12] net: dsa: allow the DSA master to be seen and changed through rtnetlink Vladimir Oltean
@ 2022-05-23 18:41   ` Florian Fainelli
  2022-05-23 23:08     ` Vladimir Oltean
  0 siblings, 1 reply; 31+ messages in thread
From: Florian Fainelli @ 2022-05-23 18:41 UTC (permalink / raw)
  To: Vladimir Oltean, netdev
  Cc: Jakub Kicinski, Vivien Didelot, Andrew Lunn, Tobias Waldekranz,
	Marek Behún, Ansuel Smith, DENG Qingfang,
	Alvin Šipraga, Claudiu Manoil, Alexandre Belloni,
	UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

On 5/23/22 03:42, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> Some DSA switches have multiple CPU ports, which can be used to improve
> CPU termination throughput, but DSA, through dsa_tree_setup_cpu_ports(),
> sets up only the first one, leading to suboptimal use of hardware.
> 
> The desire is to not change the default configuration but to permit the
> user to create a dynamic mapping between individual user ports and the
> CPU port that they are served by, configurable through rtnetlink. It is
> also intended to permit load balancing between CPU ports, and in that
> case, the foreseen model is for the DSA master to be a bonding interface
> whose lowers are the physical DSA masters.
> 
> To that end, we create a struct rtnl_link_ops for DSA user ports with
> the "dsa" kind. We expose the IFLA_DSA_MASTER link attribute that
> contains the ifindex of the newly desired DSA master.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> ---

[snip]

> +
> +static int dsa_changelink(struct net_device *dev, struct nlattr *tb[],
> +			  struct nlattr *data[],
> +			  struct netlink_ext_ack *extack)
> +{
> +	int err;
> +
> +	if (!data)
> +		return 0;
> +
> +	if (data[IFLA_DSA_MASTER]) {

We could add a comment to explain that IFLA_LINK is "reserved" for 
standard usage of associating the DSA device with a different upper 
type, like VLAN, bridge master etc.

> +		u32 ifindex = nla_get_u32(data[IFLA_DSA_MASTER]);
> +		struct net_device *master;
> +
> +		master = __dev_get_by_index(dev_net(dev), ifindex);
> +		if (!master)
> +			return -EINVAL;
> +
> +		err = dsa_slave_change_master(dev, master, extack);
> +		if (err)
> +			return err;
> +	}

I would be tempted to reduce the indentation here because we are almost 
guaranteed to add code in that conditional section?

[snip]

>   
> +static int dsa_port_assign_master(struct dsa_port *dp,
> +				  struct net_device *master,
> +				  struct netlink_ext_ack *extack,
> +				  bool fail_on_err)
> +{
> +	struct dsa_switch *ds = dp->ds;
> +	int port = dp->index, err;
> +
> +	err = ds->ops->port_change_master(ds, port, master, extack);
> +	if (err && !fail_on_err)
> +		dev_err(ds->dev, "port %d failed to assign master %s: %pe\n",
> +			port, master->name, ERR_PTR(err));

Should not that go over extack instead?

> +
> +	if (err && fail_on_err)
> +		return err;
> +
> +	dp->cpu_dp = master->dsa_ptr;
> +
> +	return 0;
> +}
> +
> +/* Change the dp->cpu_dp affinity for a user port. Note that both cross-chip
> + * notifiers and drivers have implicit assumptions about user-to-CPU-port
> + * mappings, so we unfortunately cannot delay the deletion of the objects
> + * (switchdev, standalone addresses, standalone VLANs) on the old CPU port
> + * until the new CPU port has been set up. So we need to completely tear down
> + * the old CPU port before changing it, and restore it on errors during the
> + * bringup of the new one.
> + */
> +int dsa_port_change_master(struct dsa_port *dp, struct net_device *master,
> +			   struct netlink_ext_ack *extack)
> +{
> +	struct net_device *bridge_dev = dsa_port_bridge_dev_get(dp);
> +	struct net_device *old_master = dsa_port_to_master(dp);
> +	struct net_device *dev = dp->slave;
> +	struct dsa_switch *ds = dp->ds;
> +	int port = dp->index;
> +	bool vlan_filtering;
> +	int err, tmp;
> +
> +	/* Bridges may hold host FDB, MDB and VLAN objects. These need to be
> +	 * migrated, so dynamically unoffload and later reoffload the bridge
> +	 * port.
> +	 */
> +	if (bridge_dev) {
> +		dsa_port_pre_bridge_leave(dp, bridge_dev);
> +		dsa_port_bridge_leave(dp, bridge_dev);
> +	}
> +
> +	/* The port might still be VLAN filtering even if it's no longer
> +	 * under a bridge, either due to ds->vlan_filtering_is_global or
> +	 * ds->needs_standalone_vlan_filtering. In turn this means VLANs
> +	 * on the CPU port.
> +	 */
> +	vlan_filtering = dsa_port_is_vlan_filtering(dp);
> +	if (vlan_filtering) {
> +		err = dsa_slave_manage_vlan_filtering(dev, false);
> +		if (err) {
> +			dev_err(ds->dev,
> +				"port %d failed to remove standalone VLANs: %pe\n",
> +				port, ERR_PTR(err));

Likewise, should not that be via extack? And likewise for pretty much 
any message down below.

[snip]

> +	if (!ds->ops->port_change_master)
> +		return -EOPNOTSUPP;

This could be provided over extactk since it is not even supposed to be 
happening.
-- 
Florian

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3)
  2022-05-23 10:42 [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3) Vladimir Oltean
                   ` (11 preceding siblings ...)
  2022-05-23 10:42 ` [RFC PATCH net-next 12/12] net: dsa: felix: add support for changing DSA master Vladimir Oltean
@ 2022-05-23 21:53 ` Florian Fainelli
  2022-05-23 22:51   ` Vladimir Oltean
  2022-05-24 12:02 ` Ansuel Smith
  13 siblings, 1 reply; 31+ messages in thread
From: Florian Fainelli @ 2022-05-23 21:53 UTC (permalink / raw)
  To: Vladimir Oltean, netdev
  Cc: Jakub Kicinski, Vivien Didelot, Andrew Lunn, Tobias Waldekranz,
	Marek Behún, Ansuel Smith, DENG Qingfang,
	Alvin Šipraga, Claudiu Manoil, Alexandre Belloni,
	UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

On 5/23/22 03:42, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> Note: this patch set isn't probably tested nearly well enough, and
> contains (at least minor) bugs. Don't do crazy things with it. I'm
> posting it to get feedback on the proposed UAPI.
> 
> Those who have been following part 1:
> https://patchwork.kernel.org/project/netdevbpf/cover/20220511095020.562461-1-vladimir.oltean@nxp.com/
> and part 2:
> https://patchwork.kernel.org/project/netdevbpf/cover/20220521213743.2735445-1-vladimir.oltean@nxp.com/
> will know that I am trying to enable the second internal port pair from
> the NXP LS1028A Felix switch for DSA-tagged traffic via "ocelot-8021q".
> This series represents part 3 of that effort.
> 
> Covered here are some code structure changes so that DSA monitors
> changeupper events of its masters, as well as new UAPI introduction via
> rtnetlink for changing the current master. Note, in the case of a LAG
> DSA master, DSA user ports can be assigned to the LAG in 2 ways, either
> through this new IFLA_DSA_MASTER, or simply when their existing DSA
> master joins a LAG.
> 
> Compared to previous attempts to introduce support for multiple CPU ports:
> https://lore.kernel.org/netdev/20210410133454.4768-1-ansuelsmth@gmail.com/
> 
> my proposal is to not change anything in the default behavior (i.e.
> still start off with the first CPU port from the device tree as the only
> active CPU port). But focus is instead put on being able to live-change
> what the user-to-CPU-port affinity is. Marek Behun has expressed a
> potential use case as being to dynamically load balance the termination
> of ports between CPU ports, and that should be best handled by a user
> space daemon if it only had the means - this creates the means.
> 
> Host address filtering is interesting with multiple CPU ports.
> There are 2 types of host filtered addresses to consider:
> - standalone MAC addresses of ports. These are either inherited from the
>    respective DSA masters of the ports, or from the device tree blob.
> - local bridge FDB entries.
> 
> Traditionally, DSA manages host-filtered addresses by calling
> port_fdb_add(dp->cpu_dp->index) in the appropriate database.
> But for example, when we have 2 bridged DSA user ports, one with CPU
> port A and the other with CPU port B, and the bridge offloads a local
> FDB entry for 00:01:02:03:04:05, DSA would attempt to first call
> port_fdb_add(A, 00:01:02:03:04:05, DSA_DB_BRIDGE), then
> port_fdb_add(B, 00:01:02:03:04:05, DSA_DB_BRIDGE). And since an FDB
> entry can have a single destination, the second port_fdb_add()
> overwrites the first one, and locally terminated traffic for the ports
> assigned to CPU port A is broken.
> 
> What should be done in that situation, at least with the HW I'm working
> with, is that the host filtered addresses should be delivered towards a
> "multicast" destination that covers both CPU ports, and let the
> forwarding matrix eliminate the CPU port that the current user port
> isn't affine to.
> 
> In my proposed patch set, the Felix driver does exactly that: host
> filtered addresses are learned towards a special PGID_CPU that has both
> tag_8021q CPU ports as destinations.
> 
> I have considered introducing new dsa_switch_ops API in the form of
> host_fdb_add(user port) and host_fdb_del(user port) rather than calling
> port_fdb_add(cpu port). After all, this would be similar to the newly
> introduced port_set_host_flood(user port). But I need to think a bit
> more whether it's needed right away.
> 
> Finally, there's LAG. Proposals have been made before to describe in DT
> that CPU ports are under a LAG, the idea being that we could then do the
> same for DSA (cascade) ports. The common problem is that shared (CPU and
> DSA) ports have no netdev exposed.
> 
> I didn't do that, instead I went for the more natural approach of saying
> that if the CPU ports are in a LAG, then the DSA masters are in a
> symmetric LAG as well. So why not just monitor when the DSA masters join
> a LAG, and piggyback on that configuration and make DSA reconfigure
> itself accordingly.
> 
> So LAG devices can now be DSA masters, and this is accomplished by
> populating their dev->dsa_ptr. Note that we do not create a specific
> struct dsa_port to populate their dsa_ptr, instead we reuse the dsa_ptr
> of one of the physical DSA masters (the first one, in fact).

This looks pretty good to me and did not blow up with bcm_sf2 not 
implementing port_change_master, so far so good.
-- 
Florian

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3)
  2022-05-23 21:53 ` [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3) Florian Fainelli
@ 2022-05-23 22:51   ` Vladimir Oltean
  0 siblings, 0 replies; 31+ messages in thread
From: Vladimir Oltean @ 2022-05-23 22:51 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Vladimir Oltean, netdev, Jakub Kicinski, Vivien Didelot,
	Andrew Lunn, Tobias Waldekranz, Marek Behún, Ansuel Smith,
	DENG Qingfang, Alvin Šipraga, Claudiu Manoil,
	Alexandre Belloni, UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich

On Mon, May 23, 2022 at 02:53:13PM -0700, Florian Fainelli wrote:
> This looks pretty good to me and did not blow up with bcm_sf2 not
> implementing port_change_master, so far so good.

Well, what did you expect? :)

Do you want the iproute2 patch as well, do you intend to add support for
multiple CPU ports on Starfighter?

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH net-next 04/12] net: bridge: move DSA master bridging restriction to DSA
  2022-05-23 10:42 ` [RFC PATCH net-next 04/12] net: bridge: move DSA master bridging restriction to DSA Vladimir Oltean
  2022-05-23 17:57   ` Florian Fainelli
@ 2022-05-23 23:02   ` Nikolay Aleksandrov
  1 sibling, 0 replies; 31+ messages in thread
From: Nikolay Aleksandrov @ 2022-05-23 23:02 UTC (permalink / raw)
  To: Vladimir Oltean, netdev
  Cc: Jakub Kicinski, Florian Fainelli, Vivien Didelot, Andrew Lunn,
	Tobias Waldekranz, Marek Behún, Ansuel Smith, DENG Qingfang,
	Alvin Šipraga, Claudiu Manoil, Alexandre Belloni,
	UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Frank Wunderlich,
	Vladimir Oltean

On 23/05/2022 13:42, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> When DSA gains support for multiple CPU ports in a LAG, it will become
> mandatory to monitor the changeupper events for the DSA master.
> 
> In fact, there are already some restrictions to be imposed in that area,
> namely that a DSA master cannot be a bridge port except in some special
> circumstances.
> 
> Centralize the restrictions at the level of the DSA layer as a
> preliminary step.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> ---
>  net/bridge/br_if.c | 20 --------------------
>  net/dsa/slave.c    | 44 ++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 44 insertions(+), 20 deletions(-)

I gotta say I love patches like this one. Thanks,

Acked-by: Nikolay Aleksandrov <razor@blackwall.org>

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH net-next 10/12] net: dsa: allow the DSA master to be seen and changed through rtnetlink
  2022-05-23 18:41   ` Florian Fainelli
@ 2022-05-23 23:08     ` Vladimir Oltean
  0 siblings, 0 replies; 31+ messages in thread
From: Vladimir Oltean @ 2022-05-23 23:08 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Vladimir Oltean, netdev, Jakub Kicinski, Vivien Didelot,
	Andrew Lunn, Tobias Waldekranz, Marek Behún, Ansuel Smith,
	DENG Qingfang, Alvin Šipraga, Claudiu Manoil,
	Alexandre Belloni, UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich

On Mon, May 23, 2022 at 11:41:45AM -0700, Florian Fainelli wrote:
> > +static int dsa_changelink(struct net_device *dev, struct nlattr *tb[],
> > +			  struct nlattr *data[],
> > +			  struct netlink_ext_ack *extack)
> > +{
> > +	int err;
> > +
> > +	if (!data)
> > +		return 0;
> > +
> > +	if (data[IFLA_DSA_MASTER]) {
> 
> We could add a comment to explain that IFLA_LINK is "reserved" for standard
> usage of associating the DSA device with a different upper type, like VLAN,
> bridge master etc.

TBH I don't have a very strong opinion here. IFLA_LINK does not mean the
same thing for all virtual netdevices, it means one thing for vlan/macvlan
where it describes an upper/lower relationship and another for veth
where it describes the pair, and yet another for DSA where it describes
the host port.

What seems to be universally loved about IFLA_LINK is that the notation
"eth0@eth1" used by iproute2 is cute, it lets loose users' imagination.

I did ask here whether it would be good to introduce a more specific
attribute, no response though.
https://lore.kernel.org/netdev/20210411170939.cxmva5vdcpqu4bmi@skbuf/

If the IFLA_LINK meaning is namespaced per netdev kind, I suppose we
could reuse that just fine to change the DSA master. In any case I
wouldn't want to make the debate of the century out of this.

> > +		u32 ifindex = nla_get_u32(data[IFLA_DSA_MASTER]);
> > +		struct net_device *master;
> > +
> > +		master = __dev_get_by_index(dev_net(dev), ifindex);
> > +		if (!master)
> > +			return -EINVAL;
> > +
> > +		err = dsa_slave_change_master(dev, master, extack);
> > +		if (err)
> > +			return err;
> > +	}
> 
> I would be tempted to reduce the indentation here because we are almost
> guaranteed to add code in that conditional section?

The idea was to avoid code movement if we ever add other netlink
attributes other than IFLA_DSA_MASTER. But not sure whether to optimize
for that.

> [snip]
> 
> > +static int dsa_port_assign_master(struct dsa_port *dp,
> > +				  struct net_device *master,
> > +				  struct netlink_ext_ack *extack,
> > +				  bool fail_on_err)
> > +{
> > +	struct dsa_switch *ds = dp->ds;
> > +	int port = dp->index, err;
> > +
> > +	err = ds->ops->port_change_master(ds, port, master, extack);
> > +	if (err && !fail_on_err)
> > +		dev_err(ds->dev, "port %d failed to assign master %s: %pe\n",
> > +			port, master->name, ERR_PTR(err));
> 
> Should not that go over extack instead?

Here we print if "fail_on_err" was false. We avoid failing on errors
when we are in an error rollback code path. This is also the reason why
I did not set extack, presumably because it may have been set before by
ds->ops->port_change_master. Printing to the console shows all errors
along the path, setting the extack shows only the first, or last, error.

> > +
> > +	if (err && fail_on_err)
> > +		return err;
> > +
> > +	dp->cpu_dp = master->dsa_ptr;
> > +
> > +	return 0;
> > +}
> > +
> > +/* Change the dp->cpu_dp affinity for a user port. Note that both cross-chip
> > + * notifiers and drivers have implicit assumptions about user-to-CPU-port
> > + * mappings, so we unfortunately cannot delay the deletion of the objects
> > + * (switchdev, standalone addresses, standalone VLANs) on the old CPU port
> > + * until the new CPU port has been set up. So we need to completely tear down
> > + * the old CPU port before changing it, and restore it on errors during the
> > + * bringup of the new one.
> > + */
> > +int dsa_port_change_master(struct dsa_port *dp, struct net_device *master,
> > +			   struct netlink_ext_ack *extack)
> > +{
> > +	struct net_device *bridge_dev = dsa_port_bridge_dev_get(dp);
> > +	struct net_device *old_master = dsa_port_to_master(dp);
> > +	struct net_device *dev = dp->slave;
> > +	struct dsa_switch *ds = dp->ds;
> > +	int port = dp->index;
> > +	bool vlan_filtering;
> > +	int err, tmp;
> > +
> > +	/* Bridges may hold host FDB, MDB and VLAN objects. These need to be
> > +	 * migrated, so dynamically unoffload and later reoffload the bridge
> > +	 * port.
> > +	 */
> > +	if (bridge_dev) {
> > +		dsa_port_pre_bridge_leave(dp, bridge_dev);
> > +		dsa_port_bridge_leave(dp, bridge_dev);
> > +	}
> > +
> > +	/* The port might still be VLAN filtering even if it's no longer
> > +	 * under a bridge, either due to ds->vlan_filtering_is_global or
> > +	 * ds->needs_standalone_vlan_filtering. In turn this means VLANs
> > +	 * on the CPU port.
> > +	 */
> > +	vlan_filtering = dsa_port_is_vlan_filtering(dp);
> > +	if (vlan_filtering) {
> > +		err = dsa_slave_manage_vlan_filtering(dev, false);
> > +		if (err) {
> > +			dev_err(ds->dev,
> > +				"port %d failed to remove standalone VLANs: %pe\n",
> > +				port, ERR_PTR(err));
> 
> Likewise, should not that be via extack? And likewise for pretty much any
> message down below.

Here we could populate the extack.

> [snip]
> 
> > +	if (!ds->ops->port_change_master)
> > +		return -EOPNOTSUPP;
> 
> This could be provided over extactk since it is not even supposed to be
> happening.

What do you mean it's not supposed to be happening? This is the only
place where we have a NULL check for ds->ops->port_change_master.
I didn't add an extack here because I didn't think there's much to say
beside the usual strerror(EOPNOTSUPP) = "Operation not supported".
I may add an extack saying "Driver does not support changing DSA master"
or some sort of message like that.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3)
  2022-05-23 10:42 [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3) Vladimir Oltean
                   ` (12 preceding siblings ...)
  2022-05-23 21:53 ` [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3) Florian Fainelli
@ 2022-05-24 12:02 ` Ansuel Smith
  2022-05-24 12:29   ` Vladimir Oltean
  13 siblings, 1 reply; 31+ messages in thread
From: Ansuel Smith @ 2022-05-24 12:02 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: netdev, Jakub Kicinski, Florian Fainelli, Vivien Didelot,
	Andrew Lunn, Tobias Waldekranz, Marek Behún, DENG Qingfang,
	Alvin Šipraga, Claudiu Manoil, Alexandre Belloni,
	UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich, Vladimir Oltean

On Mon, May 23, 2022 at 01:42:44PM +0300, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> Note: this patch set isn't probably tested nearly well enough, and
> contains (at least minor) bugs. Don't do crazy things with it. I'm
> posting it to get feedback on the proposed UAPI.
> 
> Those who have been following part 1:
> https://patchwork.kernel.org/project/netdevbpf/cover/20220511095020.562461-1-vladimir.oltean@nxp.com/
> and part 2:
> https://patchwork.kernel.org/project/netdevbpf/cover/20220521213743.2735445-1-vladimir.oltean@nxp.com/
> will know that I am trying to enable the second internal port pair from
> the NXP LS1028A Felix switch for DSA-tagged traffic via "ocelot-8021q".
> This series represents part 3 of that effort.
> 
> Covered here are some code structure changes so that DSA monitors
> changeupper events of its masters, as well as new UAPI introduction via
> rtnetlink for changing the current master. Note, in the case of a LAG
> DSA master, DSA user ports can be assigned to the LAG in 2 ways, either
> through this new IFLA_DSA_MASTER, or simply when their existing DSA
> master joins a LAG.
> 
> Compared to previous attempts to introduce support for multiple CPU ports:
> https://lore.kernel.org/netdev/20210410133454.4768-1-ansuelsmth@gmail.com/
> 
> my proposal is to not change anything in the default behavior (i.e.
> still start off with the first CPU port from the device tree as the only
> active CPU port). But focus is instead put on being able to live-change
> what the user-to-CPU-port affinity is. Marek Behun has expressed a
> potential use case as being to dynamically load balance the termination
> of ports between CPU ports, and that should be best handled by a user
> space daemon if it only had the means - this creates the means.
> 
> Host address filtering is interesting with multiple CPU ports.
> There are 2 types of host filtered addresses to consider:
> - standalone MAC addresses of ports. These are either inherited from the
>   respective DSA masters of the ports, or from the device tree blob.
> - local bridge FDB entries.
> 
> Traditionally, DSA manages host-filtered addresses by calling
> port_fdb_add(dp->cpu_dp->index) in the appropriate database.
> But for example, when we have 2 bridged DSA user ports, one with CPU
> port A and the other with CPU port B, and the bridge offloads a local
> FDB entry for 00:01:02:03:04:05, DSA would attempt to first call
> port_fdb_add(A, 00:01:02:03:04:05, DSA_DB_BRIDGE), then
> port_fdb_add(B, 00:01:02:03:04:05, DSA_DB_BRIDGE). And since an FDB
> entry can have a single destination, the second port_fdb_add()
> overwrites the first one, and locally terminated traffic for the ports
> assigned to CPU port A is broken.
> 
> What should be done in that situation, at least with the HW I'm working
> with, is that the host filtered addresses should be delivered towards a
> "multicast" destination that covers both CPU ports, and let the
> forwarding matrix eliminate the CPU port that the current user port
> isn't affine to.
> 
> In my proposed patch set, the Felix driver does exactly that: host
> filtered addresses are learned towards a special PGID_CPU that has both
> tag_8021q CPU ports as destinations.
> 
> I have considered introducing new dsa_switch_ops API in the form of
> host_fdb_add(user port) and host_fdb_del(user port) rather than calling
> port_fdb_add(cpu port). After all, this would be similar to the newly
> introduced port_set_host_flood(user port). But I need to think a bit
> more whether it's needed right away.
> 
> Finally, there's LAG. Proposals have been made before to describe in DT
> that CPU ports are under a LAG, the idea being that we could then do the
> same for DSA (cascade) ports. The common problem is that shared (CPU and
> DSA) ports have no netdev exposed.
> 
> I didn't do that, instead I went for the more natural approach of saying
> that if the CPU ports are in a LAG, then the DSA masters are in a
> symmetric LAG as well. So why not just monitor when the DSA masters join
> a LAG, and piggyback on that configuration and make DSA reconfigure
> itself accordingly.
> 
> So LAG devices can now be DSA masters, and this is accomplished by
> populating their dev->dsa_ptr. Note that we do not create a specific
> struct dsa_port to populate their dsa_ptr, instead we reuse the dsa_ptr
> of one of the physical DSA masters (the first one, in fact).
> 
> Vladimir Oltean (12):
>   net: introduce iterators over synced hw addresses
>   net: dsa: walk through all changeupper notifier functions
>   net: dsa: don't stop at NOTIFY_OK when calling
>     ds->ops->port_prechangeupper
>   net: bridge: move DSA master bridging restriction to DSA
>   net: dsa: existing DSA masters cannot join upper interfaces
>   net: dsa: only bring down user ports assigned to a given DSA master
>   net: dsa: all DSA masters must be down when changing the tagging
>     protocol
>   net: dsa: use dsa_tree_for_each_cpu_port in
>     dsa_tree_{setup,teardown}_master
>   net: dsa: introduce dsa_port_get_master()
>   net: dsa: allow the DSA master to be seen and changed through
>     rtnetlink
>   net: dsa: allow masters to join a LAG
>   net: dsa: felix: add support for changing DSA master
> 
>  drivers/net/dsa/bcm_sf2.c                     |   4 +-
>  drivers/net/dsa/bcm_sf2_cfp.c                 |   4 +-
>  drivers/net/dsa/lan9303-core.c                |   4 +-
>  drivers/net/dsa/ocelot/felix.c                | 117 ++++-
>  drivers/net/dsa/ocelot/felix.h                |   3 +
>  .../net/ethernet/mediatek/mtk_ppe_offload.c   |   2 +-
>  drivers/net/ethernet/mscc/ocelot.c            |   3 +-
>  include/linux/netdevice.h                     |   6 +
>  include/net/dsa.h                             |  23 +
>  include/soc/mscc/ocelot.h                     |   1 +
>  include/uapi/linux/if_link.h                  |  10 +
>  net/bridge/br_if.c                            |  20 -
>  net/dsa/Makefile                              |  10 +-
>  net/dsa/dsa.c                                 |   9 +
>  net/dsa/dsa2.c                                |  72 ++--
>  net/dsa/dsa_priv.h                            |  18 +-
>  net/dsa/master.c                              |  62 ++-
>  net/dsa/netlink.c                             |  62 +++
>  net/dsa/port.c                                | 162 ++++++-
>  net/dsa/slave.c                               | 404 +++++++++++++++++-
>  net/dsa/switch.c                              |  22 +-
>  net/dsa/tag_8021q.c                           |   4 +-
>  22 files changed, 915 insertions(+), 107 deletions(-)
>  create mode 100644 net/dsa/netlink.c
> 
> -- 
> 2.25.1
> 

Probably offtopic but I wonder if the use of a LAG as master can
cause some problem with configuration where the switch use a mgmt port
to send settings. Wonder if with this change we will have to introduce
an additional value to declare a management port that will be used since
master can now be set to various values. Or just the driver will have to
handle this with its priv struct (think this is the correct solution)

I still have to find time to test this with qca8k.

-- 
	Ansuel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3)
  2022-05-24 12:02 ` Ansuel Smith
@ 2022-05-24 12:29   ` Vladimir Oltean
  2022-05-24 12:38     ` Ansuel Smith
  0 siblings, 1 reply; 31+ messages in thread
From: Vladimir Oltean @ 2022-05-24 12:29 UTC (permalink / raw)
  To: Ansuel Smith
  Cc: Vladimir Oltean, netdev, Jakub Kicinski, Florian Fainelli,
	Vivien Didelot, Andrew Lunn, Tobias Waldekranz, Marek Behún,
	DENG Qingfang, Alvin Šipraga, Claudiu Manoil,
	Alexandre Belloni, UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich

On Tue, May 24, 2022 at 02:02:19PM +0200, Ansuel Smith wrote:
> Probably offtopic but I wonder if the use of a LAG as master can
> cause some problem with configuration where the switch use a mgmt port
> to send settings. Wonder if with this change we will have to introduce
> an additional value to declare a management port that will be used since
> master can now be set to various values. Or just the driver will have to
> handle this with its priv struct (think this is the correct solution)
> 
> I still have to find time to test this with qca8k.

Not offtopic, this is a good point. dsa_tree_master_admin_state_change()
and dsa_tree_master_oper_state_change() set various flags in cpu_dp =
master->dsa_ptr. It's unclear if the cpu_dp we assign to a LAG should
track the admin/oper state of the LAG itself or of the physical port.
Especially since the lag->dsa_ptr is the same as one of the master->dsa_ptr.
It's clear that the same structure can't track both states. I'm thinking
we should suppress the NETDEV_CHANGE and NETDEV_UP monitoring from slave.c
on LAG DSA masters, and track only the physical ones. In any case,
management traffic does not really benefit from being sent/received over
a LAG, and I'm thinking we should just use the physical port.
Your qca8k_master_change() function explicitly only checks for CPU port
0, which in retrospect was a very wise decision in terms of forward
compatibility with device trees with multiple CPU ports.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3)
  2022-05-24 12:29   ` Vladimir Oltean
@ 2022-05-24 12:38     ` Ansuel Smith
  2022-05-24 13:24       ` Vladimir Oltean
  0 siblings, 1 reply; 31+ messages in thread
From: Ansuel Smith @ 2022-05-24 12:38 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Vladimir Oltean, netdev, Jakub Kicinski, Florian Fainelli,
	Vivien Didelot, Andrew Lunn, Tobias Waldekranz, Marek Behún,
	DENG Qingfang, Alvin Šipraga, Claudiu Manoil,
	Alexandre Belloni, UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich

On Tue, May 24, 2022 at 12:29:06PM +0000, Vladimir Oltean wrote:
> On Tue, May 24, 2022 at 02:02:19PM +0200, Ansuel Smith wrote:
> > Probably offtopic but I wonder if the use of a LAG as master can
> > cause some problem with configuration where the switch use a mgmt port
> > to send settings. Wonder if with this change we will have to introduce
> > an additional value to declare a management port that will be used since
> > master can now be set to various values. Or just the driver will have to
> > handle this with its priv struct (think this is the correct solution)
> > 
> > I still have to find time to test this with qca8k.
> 
> Not offtopic, this is a good point. dsa_tree_master_admin_state_change()
> and dsa_tree_master_oper_state_change() set various flags in cpu_dp =
> master->dsa_ptr. It's unclear if the cpu_dp we assign to a LAG should
> track the admin/oper state of the LAG itself or of the physical port.
> Especially since the lag->dsa_ptr is the same as one of the master->dsa_ptr.
> It's clear that the same structure can't track both states. I'm thinking
> we should suppress the NETDEV_CHANGE and NETDEV_UP monitoring from slave.c
> on LAG DSA masters, and track only the physical ones. In any case,
> management traffic does not really benefit from being sent/received over
> a LAG, and I'm thinking we should just use the physical port.
> Your qca8k_master_change() function explicitly only checks for CPU port
> 0, which in retrospect was a very wise decision in terms of forward
> compatibility with device trees with multiple CPU ports.

Switch can also have some hw limitation where mgmt packet are accepted
only by one specific port and I assume using a LAG with load balance can
cause some problem (packet not ack).

Yes I think the oper_state_change would be problematic with a LAG
configuration since the driver should use the pysical port anyway (to
prevent any hw limitation/issue) and track only that.

But I think we can put that on hold and think of a correct solution when
we have a solid base with all of this implemented. Considering qca8k
is the only user of that feature and things will have to change anyway
when qca8k will get support for multiple cpu port, we can address that
later. (in theory everything should work correctly if qca8k doesn't
declare multiple cpu port or a LAG is not confugred) 

-- 
	Ansuel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3)
  2022-05-24 12:38     ` Ansuel Smith
@ 2022-05-24 13:24       ` Vladimir Oltean
  0 siblings, 0 replies; 31+ messages in thread
From: Vladimir Oltean @ 2022-05-24 13:24 UTC (permalink / raw)
  To: Ansuel Smith
  Cc: Vladimir Oltean, netdev, Jakub Kicinski, Florian Fainelli,
	Vivien Didelot, Andrew Lunn, Tobias Waldekranz, Marek Behún,
	DENG Qingfang, Alvin Šipraga, Claudiu Manoil,
	Alexandre Belloni, UNGLinuxDriver, Colin Foster, Linus Walleij,
	Luiz Angelo Daros de Luca, Roopa Prabhu, Nikolay Aleksandrov,
	Frank Wunderlich

On Tue, May 24, 2022 at 02:38:53PM +0200, Ansuel Smith wrote:
> On Tue, May 24, 2022 at 12:29:06PM +0000, Vladimir Oltean wrote:
> > On Tue, May 24, 2022 at 02:02:19PM +0200, Ansuel Smith wrote:
> > > Probably offtopic but I wonder if the use of a LAG as master can
> > > cause some problem with configuration where the switch use a mgmt port
> > > to send settings. Wonder if with this change we will have to introduce
> > > an additional value to declare a management port that will be used since
> > > master can now be set to various values. Or just the driver will have to
> > > handle this with its priv struct (think this is the correct solution)
> > > 
> > > I still have to find time to test this with qca8k.
> > 
> > Not offtopic, this is a good point. dsa_tree_master_admin_state_change()
> > and dsa_tree_master_oper_state_change() set various flags in cpu_dp =
> > master->dsa_ptr. It's unclear if the cpu_dp we assign to a LAG should
> > track the admin/oper state of the LAG itself or of the physical port.
> > Especially since the lag->dsa_ptr is the same as one of the master->dsa_ptr.
> > It's clear that the same structure can't track both states. I'm thinking
> > we should suppress the NETDEV_CHANGE and NETDEV_UP monitoring from slave.c
> > on LAG DSA masters, and track only the physical ones. In any case,
> > management traffic does not really benefit from being sent/received over
> > a LAG, and I'm thinking we should just use the physical port.
> > Your qca8k_master_change() function explicitly only checks for CPU port
> > 0, which in retrospect was a very wise decision in terms of forward
> > compatibility with device trees with multiple CPU ports.
> 
> Switch can also have some hw limitation where mgmt packet are accepted
> only by one specific port and I assume using a LAG with load balance can
> cause some problem (packet not ack).
> 
> Yes I think the oper_state_change would be problematic with a LAG
> configuration since the driver should use the pysical port anyway (to
> prevent any hw limitation/issue) and track only that.
> 
> But I think we can put that on hold and think of a correct solution when
> we have a solid base with all of this implemented. Considering qca8k
> is the only user of that feature and things will have to change anyway
> when qca8k will get support for multiple cpu port, we can address that
> later. (in theory everything should work correctly if qca8k doesn't
> declare multiple cpu port or a LAG is not confugred) 

Consider this - the way in which DSA tracks the state of DSA masters
already "supports multiple [ physical ] CPU ports". It's just a matter
of driver writers acknowledging this and doing the right thing in the
ds->ops->master_state_change() callback. DSA tells us when any physical
master goes up or down, and it does this regardless of whether that
master's dsa_ptr is the dp->cpu_dp of any user port. Otherwise said,
given this device tree snippet:

eth0: ethernet@0 {
	...
};

eth1: ethernet@1 {
	...
};

ethernet-switch@0 {
	ethernet-ports {
		ethernet-port@0 {
			label = "swp0";
		};

		ethernet-port@1 {
			label = "swp1";
		};

		ethernet-port@2 {
			ethernet = <&eth0>;
		};

		ethernet-port@3 {
			ethernet = <&eth1>;
		};
	};
};

Current mainline DSA will create swp0@eth0 and swp1@eth0, but it will
call dsa_master_setup(eth0) and dsa_master_setup(eth1). Then it will
monitor the state of both eth0 and eth1, and pass updates to both
masters' states down to the driver.

It is therefore the responsibility of the driver to ensure forward
compatibility with multiple CPU ports (otherwise said, if one master
goes down, don't hurry to say "I don't have any management interface to
use for register access" - maybe the other one is still ok).
Consequently, you can use a DSA master for register access even if no
dp->cpu_dp points to it. This patch set is just about changing the
dp->cpu_dp mapping that is used for netdevice traffic, which is quite
orthogonal to the concern you describe.

^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2022-05-24 13:24 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-23 10:42 [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3) Vladimir Oltean
2022-05-23 10:42 ` [RFC PATCH net-next 01/12] net: introduce iterators over synced hw addresses Vladimir Oltean
2022-05-23 17:54   ` Florian Fainelli
2022-05-23 10:42 ` [RFC PATCH net-next 02/12] net: dsa: walk through all changeupper notifier functions Vladimir Oltean
2022-05-23 18:11   ` Florian Fainelli
2022-05-23 10:42 ` [RFC PATCH net-next 03/12] net: dsa: don't stop at NOTIFY_OK when calling ds->ops->port_prechangeupper Vladimir Oltean
2022-05-23 17:56   ` Florian Fainelli
2022-05-23 10:42 ` [RFC PATCH net-next 04/12] net: bridge: move DSA master bridging restriction to DSA Vladimir Oltean
2022-05-23 17:57   ` Florian Fainelli
2022-05-23 23:02   ` Nikolay Aleksandrov
2022-05-23 10:42 ` [RFC PATCH net-next 05/12] net: dsa: existing DSA masters cannot join upper interfaces Vladimir Oltean
2022-05-23 17:58   ` Florian Fainelli
2022-05-23 10:42 ` [RFC PATCH net-next 06/12] net: dsa: only bring down user ports assigned to a given DSA master Vladimir Oltean
2022-05-23 17:59   ` Florian Fainelli
2022-05-23 10:42 ` [RFC PATCH net-next 07/12] net: dsa: all DSA masters must be down when changing the tagging protocol Vladimir Oltean
2022-05-23 18:00   ` Florian Fainelli
2022-05-23 10:42 ` [RFC PATCH net-next 08/12] net: dsa: use dsa_tree_for_each_cpu_port in dsa_tree_{setup,teardown}_master Vladimir Oltean
2022-05-23 18:01   ` Florian Fainelli
2022-05-23 10:42 ` [RFC PATCH net-next 09/12] net: dsa: introduce dsa_port_get_master() Vladimir Oltean
2022-05-23 18:08   ` Florian Fainelli
2022-05-23 10:42 ` [RFC PATCH net-next 10/12] net: dsa: allow the DSA master to be seen and changed through rtnetlink Vladimir Oltean
2022-05-23 18:41   ` Florian Fainelli
2022-05-23 23:08     ` Vladimir Oltean
2022-05-23 10:42 ` [RFC PATCH net-next 11/12] net: dsa: allow masters to join a LAG Vladimir Oltean
2022-05-23 10:42 ` [RFC PATCH net-next 12/12] net: dsa: felix: add support for changing DSA master Vladimir Oltean
2022-05-23 21:53 ` [RFC PATCH net-next 00/12] DSA changes for multiple CPU ports (part 3) Florian Fainelli
2022-05-23 22:51   ` Vladimir Oltean
2022-05-24 12:02 ` Ansuel Smith
2022-05-24 12:29   ` Vladimir Oltean
2022-05-24 12:38     ` Ansuel Smith
2022-05-24 13:24       ` Vladimir Oltean

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.