Browse Source

realtek: dsa: Adjust MSTP states after joining/leaving bridge

When joining a bridge or leaving a bridge, the CIST state will
automatically be adjusted by DSA using .port_stp_state_set(). But MSTIs are
completely unhandled.

If a port is joining a bridge, the default state must be disabled. The MSTP
daemon is then responsible for adjusting the state.

If the bridge is left, the forwarding state must be enforced because VLANs
(and with this also the MSTIs assigned to them) are shared between bridged
and non-bridged ports. An unbridged port must therefore not be left in an
blocked/disabled state for a VLAN (MSTI).

Suggested-by: Jonas Gorski <[email protected]>
Signed-off-by: Sven Eckelmann <[email protected]>
Link: https://github.com/openwrt/openwrt/pull/20421
Signed-off-by: Hauke Mehrtens <[email protected]>
Sven Eckelmann 2 months ago
parent
commit
5d36445dc1
1 changed files with 24 additions and 7 deletions
  1. 24 7
      target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c

+ 24 - 7
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c

@@ -27,6 +27,8 @@ static const u8 ipv6_all_hosts_mcast_addr_mask[ETH_ALEN] =
 extern struct rtl83xx_soc_info soc_info;
 
 static void rtldsa_init_counters(struct rtl838x_switch_priv *priv);
+static void rtldsa_port_xstp_state_set(struct rtl838x_switch_priv *priv, int port,
+				       u8 state, u16 mst_slot);
 
 static void rtl83xx_init_stats(struct rtl838x_switch_priv *priv)
 {
@@ -1497,6 +1499,7 @@ static int rtldsa_port_bridge_join(struct dsa_switch *ds, int port, struct dsa_b
 				   bool *tx_fwd_offload, struct netlink_ext_ack *extack)
 {
 	struct rtl838x_switch_priv *priv = ds->priv;
+	unsigned int i;
 
 	pr_debug("%s %x: %d", __func__, (u32)priv, port);
 
@@ -1510,6 +1513,10 @@ static int rtldsa_port_bridge_join(struct dsa_switch *ds, int port, struct dsa_b
 	if (priv->r->set_static_move_action)
 		priv->r->set_static_move_action(port, false);
 
+	/* Set to disabled in all MSTs, common code will take care of CIST */
+	for (i = 1; i < priv->n_mst; i++)
+		rtldsa_port_xstp_state_set(priv, port, BR_STATE_DISABLED, i);
+
 	mutex_unlock(&priv->reg_mutex);
 
 	return 0;
@@ -1518,6 +1525,7 @@ static int rtldsa_port_bridge_join(struct dsa_switch *ds, int port, struct dsa_b
 static void rtldsa_port_bridge_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge)
 {
 	struct rtl838x_switch_priv *priv = ds->priv;
+	unsigned int i;
 
 	pr_debug("%s %x: %d", __func__, (u32)priv, port);
 
@@ -1528,24 +1536,26 @@ static void rtldsa_port_bridge_leave(struct dsa_switch *ds, int port, struct dsa
 	if (priv->r->set_static_move_action)
 		priv->r->set_static_move_action(port, true);
 
+	/* Set to forwarding in all MSTs, common code will take care of CIST */
+	for (i = 1; i < priv->n_mst; i++)
+		rtldsa_port_xstp_state_set(priv, port, BR_STATE_FORWARDING, i);
+
 	mutex_unlock(&priv->reg_mutex);
 }
 
-void rtl83xx_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
+static void rtldsa_port_xstp_state_set(struct rtl838x_switch_priv *priv, int port,
+				       u8 state, u16 mst_slot)
+				       __must_hold(&priv->reg_mutex)
 {
-	u32 msti = 0;
 	u32 port_state[4];
 	int index, bit;
 	int pos = port;
-	struct rtl838x_switch_priv *priv = ds->priv;
 	int n = priv->port_width << 1;
 
 	/* Ports above or equal CPU port can never be configured */
 	if (port >= priv->cpu_port)
 		return;
 
-	mutex_lock(&priv->reg_mutex);
-
 	/* For the RTL839x and following, the bits are left-aligned, 838x and 930x
 	 * have 64 bit fields, 839x and 931x have 128 bit fields
 	 */
@@ -1559,7 +1569,7 @@ void rtl83xx_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
 	index = n - (pos >> 4) - 1;
 	bit = (pos << 1) % 32;
 
-	priv->r->stp_get(priv, msti, port_state);
+	priv->r->stp_get(priv, mst_slot, port_state);
 
 	pr_debug("Current state, port %d: %d\n", port, (port_state[index] >> bit) & 3);
 	port_state[index] &= ~(3 << bit);
@@ -1581,8 +1591,15 @@ void rtl83xx_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
 		break;
 	}
 
-	priv->r->stp_set(priv, msti, port_state);
+	priv->r->stp_set(priv, mst_slot, port_state);
+}
+
+void rtl83xx_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
+{
+	struct rtl838x_switch_priv *priv = ds->priv;
 
+	mutex_lock(&priv->reg_mutex);
+	rtldsa_port_xstp_state_set(priv, port, state, 0);
 	mutex_unlock(&priv->reg_mutex);
 }