Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

linux: net: dsa: mt7530: add support for bridge port isolation #3286

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,325 @@
From: Matthias Schiffer <[email protected]>
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 <[email protected]>

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: <c3976a3f84451ca05ea5be013af6071bf9acab2c.1718445041.git.mschiffer@universe-factory.net>
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <[email protected]>
+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 <[email protected]>
+Reviewed-by: Ido Schimmel <[email protected]>
+Reviewed-by: Vladimir Oltean <[email protected]>
+Link: https://lore.kernel.org/r/[email protected]
+Signed-off-by: Jakub Kicinski <[email protected]>
+---
+ 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 <[email protected]>
+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 <[email protected]>
+Reviewed-by: Wojciech Drewek <[email protected]>
+Reviewed-by: Arınç ÜNAL <[email protected]>
+Tested-by: Arınç ÜNAL <[email protected]>
+Signed-off-by: David S. Miller <[email protected]>
+---
+ 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 <[email protected]>
+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 <[email protected]>
+Reviewed-by: Wojciech Drewek <[email protected]>
+Reviewed-by: Arınç ÜNAL <[email protected]>
+Tested-by: Arınç ÜNAL <[email protected]>
+Signed-off-by: David S. Miller <[email protected]>
+---
+ 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;