From 8f3b4226976e2f28aa716cfd75caf252ea5c5ecc Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sat, 15 Jun 2024 01:12:33 +0200 Subject: [PATCH] linux: net: dsa: mt7530: add support for bridge port isolation Adds bridge port isolation to MT7621-based devices like the Ubiquiti EdgeRouter-X. --- ...dd-support-for-bridge-port-isolation.patch | 325 ++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 patches/openwrt/0010-linux-net-dsa-mt7530-add-support-for-bridge-port-isolation.patch diff --git a/patches/openwrt/0010-linux-net-dsa-mt7530-add-support-for-bridge-port-isolation.patch b/patches/openwrt/0010-linux-net-dsa-mt7530-add-support-for-bridge-port-isolation.patch new file mode 100644 index 0000000000..32fd48ead4 --- /dev/null +++ b/patches/openwrt/0010-linux-net-dsa-mt7530-add-support-for-bridge-port-isolation.patch @@ -0,0 +1,325 @@ +From: Matthias Schiffer +Date: Sat, 15 Jun 2024 01:09:41 +0200 +Subject: linux: net: dsa: mt7530: add support for bridge port isolation + +Backport of from net-next (and one older patch) to Linux 5.15. + +Signed-off-by: Matthias Schiffer + +diff --git a/target/linux/generic/backport-5.15/850-01-v5.19-net-bridge-offload-BR_HAIRPIN_MODE-BR_ISOLATED-BR_MU.patch b/target/linux/generic/backport-5.15/850-01-v5.19-net-bridge-offload-BR_HAIRPIN_MODE-BR_ISOLATED-BR_MU.patch +new file mode 100644 +index 0000000000000000000000000000000000000000..92234bde024882ecd81c1116279408963f33354e +--- /dev/null ++++ b/target/linux/generic/backport-5.15/850-01-v5.19-net-bridge-offload-BR_HAIRPIN_MODE-BR_ISOLATED-BR_MU.patch +@@ -0,0 +1,44 @@ ++From c3976a3f84451ca05ea5be013af6071bf9acab2c Mon Sep 17 00:00:00 2001 ++Message-ID: ++From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= ++Date: Sun, 10 Apr 2022 16:42:27 +0300 ++Subject: [PATCH] net: bridge: offload BR_HAIRPIN_MODE, BR_ISOLATED, ++ BR_MULTICAST_TO_UNICAST ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++Add BR_HAIRPIN_MODE, BR_ISOLATED and BR_MULTICAST_TO_UNICAST port flags to ++BR_PORT_FLAGS_HW_OFFLOAD so that switchdev drivers which have an offloaded ++data plane have a chance to reject these bridge port flags if they don't ++support them yet. ++ ++It makes the code path go through the ++SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS driver handlers, which return ++-EINVAL for everything they don't recognize. ++ ++For drivers that don't catch SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS at ++all, switchdev will return -EOPNOTSUPP for those which is then ignored, but ++those are in the minority. ++ ++Signed-off-by: Arınç ÜNAL ++Reviewed-by: Ido Schimmel ++Reviewed-by: Vladimir Oltean ++Link: https://lore.kernel.org/r/20220410134227.18810-1-arinc.unal@arinc9.com ++Signed-off-by: Jakub Kicinski ++--- ++ net/bridge/br_switchdev.c | 3 ++- ++ 1 file changed, 2 insertions(+), 1 deletion(-) ++ ++--- a/net/bridge/br_switchdev.c +++++ b/net/bridge/br_switchdev.c ++@@ -71,7 +71,8 @@ bool nbp_switchdev_allowed_egress(const ++ ++ /* Flags that can be offloaded to hardware */ ++ #define BR_PORT_FLAGS_HW_OFFLOAD (BR_LEARNING | BR_FLOOD | \ ++- BR_MCAST_FLOOD | BR_BCAST_FLOOD) +++ BR_MCAST_FLOOD | BR_BCAST_FLOOD | \ +++ BR_HAIRPIN_MODE | BR_ISOLATED | BR_MULTICAST_TO_UNICAST) ++ ++ int br_switchdev_set_port_flag(struct net_bridge_port *p, ++ unsigned long flags, +diff --git a/target/linux/generic/backport-5.15/850-02-v6.11-net-dsa-mt7530-factor-out-bridge-join-leave-logic.patch b/target/linux/generic/backport-5.15/850-02-v6.11-net-dsa-mt7530-factor-out-bridge-join-leave-logic.patch +new file mode 100644 +index 0000000000000000000000000000000000000000..41dc502395d1985b008806af6a6eee42fb2de2d1 +--- /dev/null ++++ b/target/linux/generic/backport-5.15/850-02-v6.11-net-dsa-mt7530-factor-out-bridge-join-leave-logic.patch +@@ -0,0 +1,176 @@ ++From c25c961fc7f36682f0a530150f1b7453ebc344cd Mon Sep 17 00:00:00 2001 ++From: Matthias Schiffer ++Date: Tue, 18 Jun 2024 09:17:12 +0200 ++Subject: [PATCH 1/2] net: dsa: mt7530: factor out bridge join/leave logic ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++As preparation for implementing bridge port isolation, move the logic to ++add and remove bits in the port matrix into a new helper ++mt7530_update_port_member(), which is called from ++mt7530_port_bridge_join() and mt7530_port_bridge_leave(). ++ ++Another part of the preparation is using dsa_port_offloads_bridge_dev() ++instead of dsa_port_offloads_bridge() to check for bridge membership, as ++we don't have a struct dsa_bridge in mt7530_port_bridge_flags(). ++ ++The port matrix setting is slightly streamlined, now always first setting ++the mt7530_port's pm field and then writing the port matrix from that ++field into the hardware register, instead of duplicating the bit ++manipulation for both the struct field and the register. ++ ++mt7530_port_bridge_join() was previously using |= to update the port ++matrix with the port bitmap, which was unnecessary, as pm would only ++have the CPU port set before joining a bridge; a simple assignment can ++be used for both joining and leaving (and will also work when individual ++bits are added/removed in port_bitmap with regard to the previous port ++matrix, which is what happens with port isolation). ++ ++No functional change intended. ++ ++Signed-off-by: Matthias Schiffer ++Reviewed-by: Wojciech Drewek ++Reviewed-by: Arınç ÜNAL ++Tested-by: Arınç ÜNAL ++Signed-off-by: David S. Miller ++--- ++ drivers/net/dsa/mt7530.c | 105 ++++++++++++++++++--------------------- ++ 1 file changed, 48 insertions(+), 57 deletions(-) ++ ++--- a/drivers/net/dsa/mt7530.c +++++ b/drivers/net/dsa/mt7530.c ++@@ -1386,6 +1386,52 @@ mt7530_stp_state_set(struct dsa_switch * ++ FID_PST(FID_BRIDGED, stp_state)); ++ } ++ +++static void mt7530_update_port_member(struct mt7530_priv *priv, int port, +++ const struct net_device *bridge_dev, +++ bool join) __must_hold(&priv->reg_mutex) +++{ +++ struct dsa_port *dp = dsa_to_port(priv->ds, port), *other_dp; +++ struct mt7530_port *p = &priv->ports[port], *other_p; +++ struct dsa_port *cpu_dp = dp->cpu_dp; +++ u32 port_bitmap = BIT(cpu_dp->index); +++ int other_port; +++ +++ dsa_switch_for_each_user_port(other_dp, priv->ds) { +++ other_port = other_dp->index; +++ other_p = &priv->ports[other_port]; +++ +++ if (dp == other_dp) +++ continue; +++ +++ /* Add/remove this port to/from the port matrix of the other +++ * ports in the same bridge. If the port is disabled, port +++ * matrix is kept and not being setup until the port becomes +++ * enabled. +++ */ +++ if (other_dp->bridge_dev != bridge_dev) +++ continue; +++ +++ if (join) { +++ other_p->pm |= PCR_MATRIX(BIT(port)); +++ port_bitmap |= BIT(other_port); +++ } else { +++ other_p->pm &= ~PCR_MATRIX(BIT(port)); +++ } +++ +++ if (other_p->enable) +++ mt7530_rmw(priv, MT7530_PCR_P(other_port), +++ PCR_MATRIX_MASK, other_p->pm); +++ } +++ +++ /* Add/remove the all other ports to this port matrix. For !join +++ * (leaving the bridge), only the CPU port will remain in the port matrix +++ * of this port. +++ */ +++ p->pm = PCR_MATRIX(port_bitmap); +++ if (priv->ports[port].enable) +++ mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, p->pm); +++} +++ ++ static int ++ mt7530_port_pre_bridge_flags(struct dsa_switch *ds, int port, ++ struct switchdev_brport_flags flags, ++@@ -1428,39 +1474,11 @@ static int ++ mt7530_port_bridge_join(struct dsa_switch *ds, int port, ++ struct net_device *bridge) ++ { ++- struct dsa_port *dp = dsa_to_port(ds, port), *other_dp; ++- struct dsa_port *cpu_dp = dp->cpu_dp; ++- u32 port_bitmap = BIT(cpu_dp->index); ++ struct mt7530_priv *priv = ds->priv; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++- dsa_switch_for_each_user_port(other_dp, ds) { ++- int other_port = other_dp->index; ++- ++- if (dp == other_dp) ++- continue; ++- ++- /* Add this port to the port matrix of the other ports in the ++- * same bridge. If the port is disabled, port matrix is kept ++- * and not being setup until the port becomes enabled. ++- */ ++- if (other_dp->bridge_dev != bridge) ++- continue; ++- ++- if (priv->ports[other_port].enable) ++- mt7530_set(priv, MT7530_PCR_P(other_port), ++- PCR_MATRIX(BIT(port))); ++- priv->ports[other_port].pm |= PCR_MATRIX(BIT(port)); ++- ++- port_bitmap |= BIT(other_port); ++- } ++- ++- /* Add the all other ports to this port matrix. */ ++- if (priv->ports[port].enable) ++- mt7530_rmw(priv, MT7530_PCR_P(port), ++- PCR_MATRIX_MASK, PCR_MATRIX(port_bitmap)); ++- priv->ports[port].pm |= PCR_MATRIX(port_bitmap); +++ mt7530_update_port_member(priv, port, bridge, true); ++ ++ /* Set to fallback mode for independent VLAN learning */ ++ mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK, ++@@ -1561,38 +1579,11 @@ static void ++ mt7530_port_bridge_leave(struct dsa_switch *ds, int port, ++ struct net_device *bridge) ++ { ++- struct dsa_port *dp = dsa_to_port(ds, port), *other_dp; ++- struct dsa_port *cpu_dp = dp->cpu_dp; ++ struct mt7530_priv *priv = ds->priv; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++- dsa_switch_for_each_user_port(other_dp, ds) { ++- int other_port = other_dp->index; ++- ++- if (dp == other_dp) ++- continue; ++- ++- /* Remove this port from the port matrix of the other ports ++- * in the same bridge. If the port is disabled, port matrix ++- * is kept and not being setup until the port becomes enabled. ++- */ ++- if (other_dp->bridge_dev != bridge) ++- continue; ++- ++- if (priv->ports[other_port].enable) ++- mt7530_clear(priv, MT7530_PCR_P(other_port), ++- PCR_MATRIX(BIT(port))); ++- priv->ports[other_port].pm &= ~PCR_MATRIX(BIT(port)); ++- } ++- ++- /* Set the cpu port to be the only one in the port matrix of ++- * this port. ++- */ ++- if (priv->ports[port].enable) ++- mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, ++- PCR_MATRIX(BIT(cpu_dp->index))); ++- priv->ports[port].pm = PCR_MATRIX(BIT(cpu_dp->index)); +++ mt7530_update_port_member(priv, port, bridge, false); ++ ++ /* When a port is removed from the bridge, the port would be set up ++ * back to the default as is at initial boot which is a VLAN-unaware +diff --git a/target/linux/generic/backport-5.15/850-03-v6.11-net-dsa-mt7530-add-support-for-bridge-port-isolation.patch b/target/linux/generic/backport-5.15/850-03-v6.11-net-dsa-mt7530-add-support-for-bridge-port-isolation.patch +new file mode 100644 +index 0000000000000000000000000000000000000000..c96531c9abdea94b0ffeeaf8e12e3a62ae6108e5 +--- /dev/null ++++ b/target/linux/generic/backport-5.15/850-03-v6.11-net-dsa-mt7530-add-support-for-bridge-port-isolation.patch +@@ -0,0 +1,79 @@ ++From 3d49ee2127c26fd2c77944fd2e3168c057f99439 Mon Sep 17 00:00:00 2001 ++From: Matthias Schiffer ++Date: Tue, 18 Jun 2024 09:17:13 +0200 ++Subject: [PATCH 2/2] net: dsa: mt7530: add support for bridge port isolation ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++Remove a pair of ports from the port matrix when both ports have the ++isolated flag set. ++ ++Signed-off-by: Matthias Schiffer ++Reviewed-by: Wojciech Drewek ++Reviewed-by: Arınç ÜNAL ++Tested-by: Arınç ÜNAL ++Signed-off-by: David S. Miller ++--- ++ drivers/net/dsa/mt7530.c | 18 ++++++++++++++++-- ++ drivers/net/dsa/mt7530.h | 1 + ++ 2 files changed, 17 insertions(+), 2 deletions(-) ++ ++--- a/drivers/net/dsa/mt7530.c +++++ b/drivers/net/dsa/mt7530.c ++@@ -1395,6 +1395,7 @@ static void mt7530_update_port_member(st ++ struct dsa_port *cpu_dp = dp->cpu_dp; ++ u32 port_bitmap = BIT(cpu_dp->index); ++ int other_port; +++ bool isolated; ++ ++ dsa_switch_for_each_user_port(other_dp, priv->ds) { ++ other_port = other_dp->index; ++@@ -1411,7 +1412,9 @@ static void mt7530_update_port_member(st ++ if (other_dp->bridge_dev != bridge_dev) ++ continue; ++ ++- if (join) { +++ isolated = p->isolated && other_p->isolated; +++ +++ if (join && !isolated) { ++ other_p->pm |= PCR_MATRIX(BIT(port)); ++ port_bitmap |= BIT(other_port); ++ } else { ++@@ -1438,7 +1441,7 @@ mt7530_port_pre_bridge_flags(struct dsa_ ++ struct netlink_ext_ack *extack) ++ { ++ if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | ++- BR_BCAST_FLOOD)) +++ BR_BCAST_FLOOD | BR_ISOLATED)) ++ return -EINVAL; ++ ++ return 0; ++@@ -1467,6 +1470,17 @@ mt7530_port_bridge_flags(struct dsa_swit ++ mt7530_rmw(priv, MT7530_MFC, BC_FFP(BIT(port)), ++ flags.val & BR_BCAST_FLOOD ? BC_FFP(BIT(port)) : 0); ++ +++ if (flags.mask & BR_ISOLATED) { +++ struct dsa_port *dp = dsa_to_port(ds, port); +++ struct net_device *bridge_dev = dp->bridge_dev; +++ +++ priv->ports[port].isolated = !!(flags.val & BR_ISOLATED); +++ +++ mutex_lock(&priv->reg_mutex); +++ mt7530_update_port_member(priv, port, bridge_dev, true); +++ mutex_unlock(&priv->reg_mutex); +++ } +++ ++ return 0; ++ } ++ ++--- a/drivers/net/dsa/mt7530.h +++++ b/drivers/net/dsa/mt7530.h ++@@ -706,6 +706,7 @@ struct mt7530_fdb { ++ */ ++ struct mt7530_port { ++ bool enable; +++ bool isolated; ++ u32 pm; ++ u16 pvid; ++ struct phylink_pcs *sgmii_pcs;