[PATCH v3 1/2] linux: introduce multi-cpu dsa patch

Ansuel Smith ansuelsmth at gmail.com
Wed Feb 2 16:44:11 PST 2022


Add support for multi-cpu dsa. This is a reworked version of the RFC patch
proposed some time ago.
By default every dsa port is connected to the first cpu port and the command
'ip link set PORT cpu CPU_PORT' can be used to change the used cpu port at
runtime.
A specific function port_change_cpu_port is required to correctly setup the
port on cpu change request.

Signed-off-by: Ansuel Smith <ansuelsmth at gmail.com>
---
 ...net-dsa-allow-for-multiple-CPU-ports.patch |  97 +++++++++++++++
 ...add-ndo-for-setting-the-cpu-proprety.patch | 113 ++++++++++++++++++
 ...t-ndo_set_cpu-for-changing-DSA-port-.patch | 100 ++++++++++++++++
 ...clude-net-add-dsa_cpu_ports-function.patch |  39 ++++++
 4 files changed, 349 insertions(+)
 create mode 100644 target/linux/generic/hack-5.10/780-1-net-dsa-allow-for-multiple-CPU-ports.patch
 create mode 100644 target/linux/generic/hack-5.10/780-2-net-add-ndo-for-setting-the-cpu-proprety.patch
 create mode 100644 target/linux/generic/hack-5.10/780-3-net-dsa-implement-ndo_set_cpu-for-changing-DSA-port-.patch
 create mode 100644 target/linux/generic/hack-5.10/780-4-include-net-add-dsa_cpu_ports-function.patch

diff --git a/target/linux/generic/hack-5.10/780-1-net-dsa-allow-for-multiple-CPU-ports.patch b/target/linux/generic/hack-5.10/780-1-net-dsa-allow-for-multiple-CPU-ports.patch
new file mode 100644
index 00000000..9b4a57c6
--- /dev/null
+++ b/target/linux/generic/hack-5.10/780-1-net-dsa-allow-for-multiple-CPU-ports.patch
@@ -0,0 +1,97 @@
+From 48d1e9543273c7670ebef15a4d27b13023895a28 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <marek.behun at nic.cz>
+Date: Sat, 24 Aug 2019 04:42:48 +0200
+Subject: [PATCH 1/4] net: dsa: allow for multiple CPU ports
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Allow for multiple CPU ports in a DSA switch tree. The default assing
+logic is still used where the first defined CPU port is selected for all
+the user ports. The CPU port has to be changed at runtime.
+
+Signed-off-by: Marek Behún <marek.behun at nic.cz>
+---
+ net/dsa/dsa2.c | 22 ++++++++++++++--------
+ 1 file changed, 14 insertions(+), 8 deletions(-)
+
+diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
+index 183003e45762..4a8de5e2f0f5 100644
+--- a/net/dsa/dsa2.c
++++ b/net/dsa/dsa2.c
+@@ -240,7 +240,7 @@ static int dsa_tree_setup_default_cpu(struct dsa_switch_tree *dst)
+ 	return 0;
+ }
+ 
+-static void dsa_tree_teardown_default_cpu(struct dsa_switch_tree *dst)
++static void dsa_tree_teardown_default_cpus(struct dsa_switch_tree *dst)
+ {
+ 	struct dsa_port *dp;
+ 
+@@ -553,7 +553,7 @@ static void dsa_tree_teardown_switches(struct dsa_switch_tree *dst)
+ 		dsa_switch_teardown(dp->ds);
+ }
+ 
+-static int dsa_tree_setup_master(struct dsa_switch_tree *dst)
++static int dsa_tree_setup_masters(struct dsa_switch_tree *dst)
+ {
+ 	struct dsa_port *dp;
+ 	int err;
+@@ -562,14 +562,20 @@ static int dsa_tree_setup_master(struct dsa_switch_tree *dst)
+ 		if (dsa_port_is_cpu(dp)) {
+ 			err = dsa_master_setup(dp->master, dp);
+ 			if (err)
+-				return err;
++				goto teardown;
+ 		}
+ 	}
+ 
+ 	return 0;
++teardown:
++	list_for_each_entry(dp, &dst->ports, list)
++		if (dsa_port_is_cpu(dp))
++			dsa_master_teardown(dp->master);
++
++	return err;
+ }
+ 
+-static void dsa_tree_teardown_master(struct dsa_switch_tree *dst)
++static void dsa_tree_teardown_masters(struct dsa_switch_tree *dst)
+ {
+ 	struct dsa_port *dp;
+ 
+@@ -601,7 +607,7 @@ static int dsa_tree_setup(struct dsa_switch_tree *dst)
+ 	if (err)
+ 		goto teardown_default_cpu;
+ 
+-	err = dsa_tree_setup_master(dst);
++	err = dsa_tree_setup_masters(dst);
+ 	if (err)
+ 		goto teardown_switches;
+ 
+@@ -614,7 +620,7 @@ static int dsa_tree_setup(struct dsa_switch_tree *dst)
+ teardown_switches:
+ 	dsa_tree_teardown_switches(dst);
+ teardown_default_cpu:
+-	dsa_tree_teardown_default_cpu(dst);
++	dsa_tree_teardown_default_cpus(dst);
+ 
+ 	return err;
+ }
+@@ -626,11 +632,11 @@ static void dsa_tree_teardown(struct dsa_switch_tree *dst)
+ 	if (!dst->setup)
+ 		return;
+ 
+-	dsa_tree_teardown_master(dst);
++	dsa_tree_teardown_masters(dst);
+ 
+ 	dsa_tree_teardown_switches(dst);
+ 
+-	dsa_tree_teardown_default_cpu(dst);
++	dsa_tree_teardown_default_cpus(dst);
+ 
+ 	list_for_each_entry_safe(dl, next, &dst->rtable, list) {
+ 		list_del(&dl->list);
+-- 
+2.34.1
+
diff --git a/target/linux/generic/hack-5.10/780-2-net-add-ndo-for-setting-the-cpu-proprety.patch b/target/linux/generic/hack-5.10/780-2-net-add-ndo-for-setting-the-cpu-proprety.patch
new file mode 100644
index 00000000..d9441feb
--- /dev/null
+++ b/target/linux/generic/hack-5.10/780-2-net-add-ndo-for-setting-the-cpu-proprety.patch
@@ -0,0 +1,113 @@
+From 07ad275393f991d29aff1e9951e01e0a1f1582b4 Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuelsmth at gmail.com>
+Date: Sun, 23 Jan 2022 00:49:10 +0100
+Subject: [PATCH 2/4] net: add ndo for setting the cpu proprety
+
+In DSA the cpu value is used to report to which CPU port a given switch
+port is connected to. Since we want to support multi-CPU DSA, we want
+the user to be able to change this value.
+
+Add ndo_set_cpu method into the ndo structure and also create
+dev_set_cpu and call this from the netlink code, so that userspace can
+change the cpu value.
+
+Signed-off-by: Ansuel Smith <ansuelsmth at gmail.com>
+---
+ include/linux/netdevice.h    |  5 +++++
+ include/uapi/linux/if_link.h |  1 +
+ net/core/dev.c               | 18 ++++++++++++++++++
+ net/core/rtnetlink.c         |  7 +++++++
+ 4 files changed, 31 insertions(+)
+
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index 7c3da0e1ea9d..c59181a116fd 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -1237,6 +1237,8 @@ struct netdev_net_notifier {
+  *	TX queue.
+  * int (*ndo_get_iflink)(const struct net_device *dev);
+  *	Called to get the iflink value of this device.
++ * int (*ndo_set_cpu)(struct net_device *dev, int cpu);
++ *	Called to set the cpu value of this device.
+  * void (*ndo_change_proto_down)(struct net_device *dev,
+  *				 bool proto_down);
+  *	This function is used to pass protocol port error state information
+@@ -1470,6 +1472,8 @@ struct net_device_ops {
+ 						      int queue_index,
+ 						      u32 maxrate);
+ 	int			(*ndo_get_iflink)(const struct net_device *dev);
++	int			(*ndo_set_cpu)(struct net_device *dev,
++					       int cpu);
+ 	int			(*ndo_change_proto_down)(struct net_device *dev,
+ 							 bool proto_down);
+ 	int			(*ndo_fill_metadata_dst)(struct net_device *dev,
+@@ -2797,6 +2801,7 @@ void dev_add_offload(struct packet_offload *po);
+ void dev_remove_offload(struct packet_offload *po);
+ 
+ int dev_get_iflink(const struct net_device *dev);
++int dev_set_cpu(struct net_device *dev, int cpu);
+ int dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);
+ struct net_device *__dev_get_by_flags(struct net *net, unsigned short flags,
+ 				      unsigned short mask);
+diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
+index c4b23f06f69e..b035c911eadc 100644
+--- a/include/uapi/linux/if_link.h
++++ b/include/uapi/linux/if_link.h
+@@ -340,6 +340,7 @@ enum {
+ 	IFLA_ALT_IFNAME, /* Alternative ifname */
+ 	IFLA_PERM_ADDRESS,
+ 	IFLA_PROTO_DOWN_REASON,
++	IFLA_CPU,
+ 	__IFLA_MAX
+ };
+ 
+diff --git a/net/core/dev.c b/net/core/dev.c
+index 38412e70f761..a213719a11ed 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -820,6 +820,24 @@ int dev_get_iflink(const struct net_device *dev)
+ }
+ EXPORT_SYMBOL(dev_get_iflink);
+ 
++/**
++ *	dev_set_cpu - set 'cpu' value of a dsa interface
++ *	@dev: target interface
++ *	@cpu: new value
++ *
++ *	Change the cpu port to which this dsa interface is linked to.
++ */
++int dev_set_cpu(struct net_device *dev, int cpu)
++{
++	if (!dev->dsa_ptr)
++		return -EOPNOTSUPP;
++
++	if (dev->netdev_ops && dev->netdev_ops->ndo_set_cpu)
++		return dev->netdev_ops->ndo_set_cpu(dev, cpu);
++
++	return -EOPNOTSUPP;
++}
++
+ /**
+  *	dev_fill_metadata_dst - Retrieve tunnel egress information.
+  *	@dev: targeted interface
+diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
+index 7d7223691783..767ac3bf6358 100644
+--- a/net/core/rtnetlink.c
++++ b/net/core/rtnetlink.c
+@@ -2716,6 +2716,13 @@ static int do_setlink(const struct sk_buff *skb,
+ 		status |= DO_SETLINK_MODIFIED;
+ 	}
+ 
++	if (tb[IFLA_CPU]) {
++		err = dev_set_cpu(dev, nla_get_u32(tb[IFLA_CPU]));
++		if (err)
++			goto errout;
++		status |= DO_SETLINK_MODIFIED;
++	}
++
+ 	if (tb[IFLA_CARRIER]) {
+ 		err = dev_change_carrier(dev, nla_get_u8(tb[IFLA_CARRIER]));
+ 		if (err)
+-- 
+2.34.1
+
diff --git a/target/linux/generic/hack-5.10/780-3-net-dsa-implement-ndo_set_cpu-for-changing-DSA-port-.patch b/target/linux/generic/hack-5.10/780-3-net-dsa-implement-ndo_set_cpu-for-changing-DSA-port-.patch
new file mode 100644
index 00000000..b6f454bf
--- /dev/null
+++ b/target/linux/generic/hack-5.10/780-3-net-dsa-implement-ndo_set_cpu-for-changing-DSA-port-.patch
@@ -0,0 +1,100 @@
+From 96d426097d16234a5c0f7bf30a87a381fb7821e8 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <marek.behun at nic.cz>
+Date: Sat, 24 Aug 2019 04:42:50 +0200
+Subject: [PATCH 3/4] net: dsa: implement ndo_set_cpu for changing DSA port's
+ CPU port
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Implement ndo_set_cpu for DSA slave device. In multi-CPU port setup
+this should be used to change to which CPU destination port a given port
+should be connected.
+
+This adds a new operation into the DSA switch operations structure,
+port_change_cpu_port. A driver implementing this function has the
+ability to change CPU destination port of a given port.
+
+Signed-off-by: Marek Behún <marek.behun at nic.cz>
+---
+ include/net/dsa.h |  6 ++++++
+ net/dsa/slave.c   | 39 +++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 45 insertions(+)
+
+diff --git a/include/net/dsa.h b/include/net/dsa.h
+index 35429a140dfa..70bd07c4ea15 100644
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -647,6 +647,12 @@ struct dsa_switch_ops {
+ 	int	(*port_change_mtu)(struct dsa_switch *ds, int port,
+ 				   int new_mtu);
+ 	int	(*port_max_mtu)(struct dsa_switch *ds, int port);
++
++	/*
++	 * Multi-CPU port support
++	 */
++	int	(*port_change_cpu_port)(struct dsa_switch *ds, int port,
++					struct dsa_port *new_cpu_dp);
+ };
+ 
+ #define DSA_DEVLINK_PARAM_DRIVER(_id, _name, _type, _cmodes)		\
+diff --git a/net/dsa/slave.c b/net/dsa/slave.c
+index 3bc5ca40c9fb..8f871d2699c2 100644
+--- a/net/dsa/slave.c
++++ b/net/dsa/slave.c
+@@ -62,6 +62,44 @@ static int dsa_slave_get_iflink(const struct net_device *dev)
+ 	return dsa_slave_to_master(dev)->ifindex;
+ }
+ 
++static int dsa_slave_set_cpu(struct net_device *dev, int cpu)
++{
++	struct net_device *master = dsa_slave_to_master(dev);
++	struct dsa_port *dp = dsa_slave_to_port(dev);
++	struct dsa_slave_priv *p = netdev_priv(dev);
++	struct net_device *new_cpu_dev;
++	struct dsa_port *new_cpu_dp;
++	int err;
++
++	if (!dp->ds->ops->port_change_cpu_port)
++		return -EOPNOTSUPP;
++
++	new_cpu_dev = dev_get_by_index(dev_net(dev), cpu);
++	if (!new_cpu_dev)
++		return -ENODEV;
++
++	new_cpu_dp = new_cpu_dev->dsa_ptr;
++	if (!new_cpu_dp)
++		return -EINVAL;
++
++	/* new CPU port has to be on the same switch tree */
++	if (new_cpu_dp->dst != dp->cpu_dp->dst)
++		return -EINVAL;
++
++	err = dp->ds->ops->port_change_cpu_port(dp->ds, dp->index, new_cpu_dp);
++	if (err)
++		return err;
++
++	if (ether_addr_equal(dev->dev_addr, master->dev_addr))
++	 	eth_hw_addr_inherit(dev, new_cpu_dev);
++
++	/* should this be done atomically? */
++	dp->cpu_dp = new_cpu_dp;
++	p->xmit = new_cpu_dp->tag_ops->xmit;
++
++	return 0;
++}
++
+ static int dsa_slave_open(struct net_device *dev)
+ {
+ 	struct net_device *master = dsa_slave_to_master(dev);
+@@ -1594,6 +1632,7 @@ static const struct net_device_ops dsa_slave_netdev_ops = {
+ 	.ndo_fdb_dump		= dsa_slave_fdb_dump,
+ 	.ndo_do_ioctl		= dsa_slave_ioctl,
+ 	.ndo_get_iflink		= dsa_slave_get_iflink,
++	.ndo_set_cpu		= dsa_slave_set_cpu,
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+ 	.ndo_netpoll_setup	= dsa_slave_netpoll_setup,
+ 	.ndo_netpoll_cleanup	= dsa_slave_netpoll_cleanup,
+-- 
+2.34.1
+
diff --git a/target/linux/generic/hack-5.10/780-4-include-net-add-dsa_cpu_ports-function.patch b/target/linux/generic/hack-5.10/780-4-include-net-add-dsa_cpu_ports-function.patch
new file mode 100644
index 00000000..22f85bca
--- /dev/null
+++ b/target/linux/generic/hack-5.10/780-4-include-net-add-dsa_cpu_ports-function.patch
@@ -0,0 +1,39 @@
+From 7085cfadfc26f4483c544790c80b3fc6acf1bdb3 Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuelsmth at gmail.com>
+Date: Sun, 4 Apr 2021 12:58:50 +0200
+Subject: [PATCH 4/4] include: net: add dsa_cpu_ports function
+
+dsa_cpu_ports can be useful for switch that has multiple cpu port to
+retrieve the cpu mask for ACL and bridge table.
+
+Signed-off-by: Ansuel Smith <ansuelsmth at gmail.com>
+---
+ include/net/dsa.h | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/include/net/dsa.h b/include/net/dsa.h
+index 70bd07c4ea15..06aa0d9912ee 100644
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -380,6 +380,18 @@ static inline u32 dsa_user_ports(struct dsa_switch *ds)
+ 	return mask;
+ }
+ 
++static inline u32 dsa_cpu_ports(struct dsa_switch *ds)
++{
++	u32 mask = 0;
++	int p;
++
++	for (p = 0; p < ds->num_ports; p++)
++		if (dsa_is_cpu_port(ds, p))
++			mask |= BIT(p);
++
++	return mask;
++}
++
+ /* Return the local port used to reach an arbitrary switch device */
+ static inline unsigned int dsa_routing_port(struct dsa_switch *ds, int device)
+ {
+-- 
+2.34.1
+
-- 
2.34.1




More information about the openwrt-devel mailing list