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

Signed-off-by: Ansuel Smith <ansuels...@gmail.com>
---
 ...net-dsa-allow_for_multiple_CPU_ports.patch | 159 ++++++++++++++++++
 ..._ndo_for_setting_the_iflink_property.patch |  88 ++++++++++
 ..._netlink_for_changing_ports_CPU_port.patch |  89 ++++++++++
 ...clude-net-add-dsa_cpu_ports-function.patch |  34 ++++
 4 files changed, 370 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_iflink_property.patch
 create mode 100644 
target/linux/generic/hack-5.10/780-3-net-dsa-implement_ndo_set_netlink_for_changing_ports_CPU_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 0000000000..9c3a9e77e2
--- /dev/null
+++ 
b/target/linux/generic/hack-5.10/780-1-net-dsa-allow_for_multiple_CPU_ports.patch
@@ -0,0 +1,159 @@
+From:   Marek Behún <marek.be...@nic.cz>
+Subject: [PATCH RFC net-next 1/3] net: dsa: allow for multiple CPU ports
+Date:   Sat, 24 Aug 2019 04:42:48 +0200
+
+Allow for multiple CPU ports in a DSA switch tree. By default assign the
+CPU ports to user ports in a round robin way, ie. if there are two CPU
+ports connected to eth0 and eth1, and five user ports (lan1..lan5),
+assign them as:
+  lan1 <-> eth0
+  lan2 <-> eth1
+  lan3 <-> eth0
+  lan4 <-> eth1
+  lan5 <-> eth0
+
+Signed-off-by: Marek Behún <marek.be...@nic.cz>
+Signed-off-by: Ansuel Smith <ansuels...@gmail.com>
+---
+ include/net/dsa.h |  5 +--
+ net/dsa/dsa2.c    | 84 +++++++++++++++++++++++++++++++----------------
+ 2 files changed, 58 insertions(+), 31 deletions(-)
+
+--- a/net/dsa/dsa2.c
++++ b/net/dsa/dsa2.c
+@@ -211,36 +211,46 @@ static bool dsa_tree_setup_routing_table
+       return complete;
+ }
+ 
+-static struct dsa_port *dsa_tree_find_first_cpu(struct dsa_switch_tree *dst)
++static int dsa_tree_setup_default_cpus(struct dsa_switch_tree *dst)
+ {
+-      struct dsa_port *dp;
+-
++      struct dsa_port *cpu_dp, *dp, *first_cpu_dp = NULL, *last_cpu_dp = NULL;
++      
++      /* Find first and last CPU port */
+       list_for_each_entry(dp, &dst->ports, list)
+-              if (dsa_port_is_cpu(dp))
+-                      return dp;
+-
+-      return NULL;
+-}
++              if (dsa_port_is_cpu(dp)) {
++                      if (first_cpu_dp == NULL)
++                              first_cpu_dp = dp;
+ 
+-static int dsa_tree_setup_default_cpu(struct dsa_switch_tree *dst)
+-{
+-      struct dsa_port *cpu_dp, *dp;
++                      last_cpu_dp = dp;
++              }
+ 
+-      cpu_dp = dsa_tree_find_first_cpu(dst);
+-      if (!cpu_dp) {
++      if (first_cpu_dp == NULL) {
+               pr_err("DSA: tree %d has no CPU port\n", dst->index);
+               return -EINVAL;
+       }
+ 
+-      /* Assign the default CPU port to all ports of the fabric */
++      cpu_dp = first_cpu_dp;
++
++      /* Assign the CPU ports in round-robbin way to all ports of the fabric 
*/
+       list_for_each_entry(dp, &dst->ports, list)
+-              if (dsa_port_is_user(dp) || dsa_port_is_dsa(dp))
++              if (dsa_port_is_user(dp) || dsa_port_is_dsa(dp)) {
+                       dp->cpu_dp = cpu_dp;
+ 
++                      if (cpu_dp == last_cpu_dp)
++                              cpu_dp = first_cpu_dp;
++                      else
++                              while((cpu_dp = list_next_entry(cpu_dp, list)) 
!= 0)
++                                      if (dsa_port_is_cpu(cpu_dp))
++                                              break;
++
++                      if (dp->ds->ops->port_change_cpu_port)
++                              dp->ds->ops->port_change_cpu_port(dp->ds, 
dp->index, dp->cpu_dp);
++              }
++
+       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;
+ 
+@@ -572,7 +582,7 @@ static void dsa_tree_teardown_switches(s
+               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;
+@@ -581,14 +591,20 @@ static int dsa_tree_setup_master(struct
+               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;
+ 
+@@ -612,7 +628,7 @@ static int dsa_tree_setup(struct dsa_swi
+       if (!complete)
+               return 0;
+ 
+-      err = dsa_tree_setup_default_cpu(dst);
++      err = dsa_tree_setup_default_cpus(dst);
+       if (err)
+               return err;
+ 
+@@ -620,7 +636,7 @@ static int dsa_tree_setup(struct dsa_swi
+       if (err)
+               goto teardown_default_cpu;
+ 
+-      err = dsa_tree_setup_master(dst);
++      err = dsa_tree_setup_masters(dst);
+       if (err)
+               goto teardown_switches;
+ 
+@@ -633,7 +649,7 @@ static int dsa_tree_setup(struct dsa_swi
+ teardown_switches:
+       dsa_tree_teardown_switches(dst);
+ teardown_default_cpu:
+-      dsa_tree_teardown_default_cpu(dst);
++      dsa_tree_teardown_default_cpus(dst);
+ 
+       return err;
+ }
+@@ -645,11 +661,11 @@ static void dsa_tree_teardown(struct dsa
+       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);
diff --git 
a/target/linux/generic/hack-5.10/780-2-net-add_ndo_for_setting_the_iflink_property.patch
 
b/target/linux/generic/hack-5.10/780-2-net-add_ndo_for_setting_the_iflink_property.patch
new file mode 100644
index 0000000000..5fab81249e
--- /dev/null
+++ 
b/target/linux/generic/hack-5.10/780-2-net-add_ndo_for_setting_the_iflink_property.patch
@@ -0,0 +1,88 @@
+From:   Marek Behún <marek.be...@nic.cz>
+Subject: [PATCH RFC net-next 2/3] net: add ndo for setting the iflink property
+Date:   Sat, 24 Aug 2019 04:42:49 +0200
+
+In DSA the iflink 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_iflink method into the ndo strucutre to be a pair to
+ndo_get_iflink. Also create dev_set_iflink and call this from the
+netlink code, so that userspace can change the iflink value.
+
+Signed-off-by: Marek Behún <marek.be...@nic.cz>
+Signed-off-by: Ansuel Smith <ansuels...@gmail.com>
+---
+ include/linux/netdevice.h |  5 +++++
+ net/core/dev.c            | 15 +++++++++++++++
+ net/core/rtnetlink.c      |  7 +++++++
+ 3 files changed, 27 insertions(+)
+
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -1284,6 +1284,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_iflink)(struct net_device *dev, int iflink);
++ *    Called to set the iflink 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
+@@ -1519,6 +1521,8 @@ struct net_device_ops {
+                                                     int queue_index,
+                                                     u32 maxrate);
+       int                     (*ndo_get_iflink)(const struct net_device *dev);
++      int                     (*ndo_set_iflink)(struct net_device *dev,
++                                                int iflink);
+       int                     (*ndo_change_proto_down)(struct net_device *dev,
+                                                        bool proto_down);
+       int                     (*ndo_fill_metadata_dst)(struct net_device *dev,
+@@ -2896,6 +2900,7 @@ void dev_add_offload(struct packet_offlo
+ void dev_remove_offload(struct packet_offload *po);
+ 
+ int dev_get_iflink(const struct net_device *dev);
++int dev_set_iflink(struct net_device *dev, int iflink);
+ int dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);
+ int dev_fill_forward_path(const struct net_device *dev, const u8 *daddr,
+                         struct net_device_path_stack *stack);
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -822,6 +822,21 @@ int dev_get_iflink(const struct net_devi
+ EXPORT_SYMBOL(dev_get_iflink);
+ 
+ /**
++ *    dev_set_iflink - set 'iflink' value of an interface
++ *    @dev: target interface
++ *    @iflink: new value
++ *
++ *    Change the interface to which this interface is linked to.
++ */
++int dev_set_iflink(struct net_device *dev, int iflink)
++{
++      if (dev->netdev_ops && dev->netdev_ops->ndo_set_iflink)
++              return dev->netdev_ops->ndo_set_iflink(dev, iflink);
++
++      return -EOPNOTSUPP;
++}
++
++/**
+  *    dev_fill_metadata_dst - Retrieve tunnel egress information.
+  *    @dev: targeted interface
+  *    @skb: The packet.
+--- a/net/core/rtnetlink.c
++++ b/net/core/rtnetlink.c
+@@ -2717,6 +2717,13 @@ static int do_setlink(const struct sk_bu
+               status |= DO_SETLINK_MODIFIED;
+       }
+ 
++      if (tb[IFLA_LINK]) {
++              err = dev_set_iflink(dev, nla_get_u32(tb[IFLA_LINK]));
++              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)
diff --git 
a/target/linux/generic/hack-5.10/780-3-net-dsa-implement_ndo_set_netlink_for_changing_ports_CPU_port.patch
 
b/target/linux/generic/hack-5.10/780-3-net-dsa-implement_ndo_set_netlink_for_changing_ports_CPU_port.patch
new file mode 100644
index 0000000000..89d53debf8
--- /dev/null
+++ 
b/target/linux/generic/hack-5.10/780-3-net-dsa-implement_ndo_set_netlink_for_changing_ports_CPU_port.patch
@@ -0,0 +1,89 @@
+From:   Marek Behún <marek.be...@nic.cz>
+Subject: [PATCH RFC net-next 3/3] net: dsa: implement ndo_set_netlink for 
changing port's CPU port
+Date:   Sat, 24 Aug 2019 04:42:50 +0200
+
+Implement ndo_set_iflink 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.be...@nic.cz>
+Signed-off-by: Ansuel Smith <ansuels...@gmail.com>
+---
+ include/net/dsa.h |  6 ++++++
+ net/dsa/slave.c   | 35 +++++++++++++++++++++++++++++++++++
+ 2 files changed, 41 insertions(+)
+
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -654,6 +654,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)          \
+--- a/net/dsa/slave.c
++++ b/net/dsa/slave.c
+@@ -62,6 +62,44 @@ static int dsa_slave_get_iflink(const st
+       return dsa_slave_to_master(dev)->ifindex;
+ }
+ 
++static int dsa_slave_set_iflink(struct net_device *dev, int iflink)
++{
++      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), iflink);
++      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);
+@@ -1667,6 +1705,7 @@ static const struct net_device_ops dsa_s
+       .ndo_fdb_dump           = dsa_slave_fdb_dump,
+       .ndo_do_ioctl           = dsa_slave_ioctl,
+       .ndo_get_iflink         = dsa_slave_get_iflink,
++      .ndo_set_iflink         = dsa_slave_set_iflink,
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_netpoll_setup      = dsa_slave_netpoll_setup,
+       .ndo_netpoll_cleanup    = dsa_slave_netpoll_cleanup,
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 0000000000..d03b8e62d7
--- /dev/null
+++ 
b/target/linux/generic/hack-5.10/780-4-include-net-add-dsa_cpu_ports-function.patch
@@ -0,0 +1,34 @@
+From 2bf13a906ce96f67eb292c8e519c6d2215501d82 Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuels...@gmail.com>
+Date: Sun, 4 Apr 2021 12:58:50 +0200
+Subject: [PATCH 1/2] 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 <ansuels...@gmail.com>
+---
+ include/net/dsa.h | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -387,6 +387,18 @@ static inline u32 dsa_user_ports(struct
+       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.30.2.windows.1


_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Reply via email to