From 9f8a150432cfcb8a4e0db2ed3a504060ed37b74f 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 | 274 ++++++++++++++++++ 1 file changed, 274 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 00000000000..f230a934769 --- /dev/null +++ b/patches/openwrt/0010-linux-net-dsa-mt7530-add-support-for-bridge-port-isolation.patch @@ -0,0 +1,274 @@ +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 +https://patchwork.kernel.org/project/netdevbpf/list/?series=862224 (and +one older patch) to Linux 5.15. + +Signed-off-by: Matthias Schiffer + +diff --git a/target/linux/generic/backport-5.15/850-v5.19-net-bridge-offload-BR_HAIRPIN_MODE-BR_ISOLATED-BR_MU.patch b/target/linux/generic/backport-5.15/850-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-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/pending-5.15/797-net-dsa-mt7530-factor-out-bridge-join-leave-logic.patch b/target/linux/generic/pending-5.15/797-net-dsa-mt7530-factor-out-bridge-join-leave-logic.patch +new file mode 100644 +index 0000000000000000000000000000000000000000..4c39c9f8589c26ce21e1e30bbdb862bb6b5e2647 +--- /dev/null ++++ b/target/linux/generic/pending-5.15/797-net-dsa-mt7530-factor-out-bridge-join-leave-logic.patch +@@ -0,0 +1,134 @@ ++--- a/drivers/net/dsa/mt7530.c +++++ b/drivers/net/dsa/mt7530.c ++@@ -1386,6 +1386,50 @@ 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. */ +++ 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 +1472,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 +1577,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/pending-5.15/798-net-dsa-mt7530-add-support-for-bridge-port-isolation.patch b/target/linux/generic/pending-5.15/798-net-dsa-mt7530-add-support-for-bridge-port-isolation.patch +new file mode 100644 +index 0000000000000000000000000000000000000000..e9ef751957d93c312a313dfba0502856ddf4eb9e +--- /dev/null ++++ b/target/linux/generic/pending-5.15/798-net-dsa-mt7530-add-support-for-bridge-port-isolation.patch +@@ -0,0 +1,68 @@ ++--- a/drivers/net/dsa/mt7530.c +++++ b/drivers/net/dsa/mt7530.c ++@@ -1387,7 +1387,8 @@ mt7530_stp_state_set(struct dsa_switch * ++ } ++ ++ static void mt7530_update_port_member(struct mt7530_priv *priv, int port, ++- const struct net_device *bridge_dev, bool join) +++ 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; ++@@ -1395,6 +1396,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 +1413,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 { ++@@ -1436,7 +1440,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; ++@@ -1465,6 +1469,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;