realtek: dsa: rtl93xx: Support multi spanning tree states
authorIssam Hamdi <[email protected]>
Tue, 15 Jul 2025 18:22:26 +0000 (20:22 +0200)
committerHauke Mehrtens <[email protected]>
Sat, 15 Nov 2025 15:21:16 +0000 (16:21 +0100)
The MSTP support (usually implemented by mstpd) requires from the kernel
that a VLAN can associated with an MSTI. At the moment, all these VLANs
just get the msti 0 harcoded on creation. But the
vlan_tables_read()+vlan_tables_write() helper already allow the
modification of the MSTI and only require a minimal hook to expose this
functionality.

It is also necessary to adjust the (M)STP states per MSTI and not only per
port (or for the CIST). The rtl83xx_port_stp_state_set() function was in
theory already capable to modify other MSTIs than CIST - if the msti would
not have been hardcoded to 0.

The userspace can trigger these modifications using netlink:

* (Re)associating VLANs with an MSTI:

      bridge vlan global set dev <BR> vid <X> msti <Y>

* Setting the port state in a given MSTI:

      bridge mst set dev <PORT> msti <Y> state <Z>

Signed-off-by: Issam Hamdi <[email protected]>
Co-developed-by: Sven Eckelmann <[email protected]>
Signed-off-by: Sven Eckelmann <[email protected]>
Link: https://github.com/openwrt/openwrt/pull/20421
Signed-off-by: Hauke Mehrtens <[email protected]>
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c

index e595df93baf0d409226fe6c4bcac3faddd59870a..cc29fd1ba6f0b08e5d94b69bffc2c526d56383f5 100644 (file)
@@ -1677,6 +1677,18 @@ static void rtl930x_fast_age(struct dsa_switch *ds, int port)
        mutex_unlock(&priv->reg_mutex);
 }
 
+static int rtldsa_port_mst_state_set(struct dsa_switch *ds, int port,
+                                    const struct switchdev_mst_state *st)
+{
+       struct rtl838x_switch_priv *priv = ds->priv;
+
+       mutex_lock(&priv->reg_mutex);
+       rtldsa_port_xstp_state_set(priv, port, st->state, st->msti);
+       mutex_unlock(&priv->reg_mutex);
+
+       return 0;
+}
+
 static int rtl83xx_vlan_filtering(struct dsa_switch *ds, int port,
                                  bool vlan_filtering,
                                  struct netlink_ext_ack *extack)
@@ -1877,6 +1889,23 @@ static int rtldsa_port_vlan_fast_age(struct dsa_switch *ds, int port, u16 vid)
        return ret;
 }
 
+static int rtldsa_vlan_msti_set(struct dsa_switch *ds, struct dsa_bridge bridge,
+                               const struct switchdev_vlan_msti *msti)
+{
+       struct rtl838x_switch_priv *priv = ds->priv;
+       struct rtl838x_vlan_info info;
+       int mst_slot = msti->msti;
+
+       if (mst_slot >= priv->n_mst)
+               return -EINVAL;
+
+       priv->r->vlan_tables_read(msti->vid, &info);
+       info.fid = mst_slot;
+       priv->r->vlan_set_tagged(msti->vid, &info);
+
+       return 0;
+}
+
 static void rtl83xx_setup_l2_uc_entry(struct rtl838x_l2_entry *e, int port, int vid, u64 mac)
 {
        memset(e, 0, sizeof(*e));
@@ -2666,10 +2695,12 @@ const struct dsa_switch_ops rtl83xx_switch_ops = {
        .port_bridge_leave      = rtldsa_port_bridge_leave,
        .port_stp_state_set     = rtl83xx_port_stp_state_set,
        .port_fast_age          = rtl83xx_fast_age,
+       .port_mst_state_set     = rtldsa_port_mst_state_set,
 
        .port_vlan_filtering    = rtl83xx_vlan_filtering,
        .port_vlan_add          = rtl83xx_vlan_add,
        .port_vlan_del          = rtl83xx_vlan_del,
+       .vlan_msti_set          = rtldsa_vlan_msti_set,
 
        .port_fdb_add           = rtl83xx_port_fdb_add,
        .port_fdb_del           = rtl83xx_port_fdb_del,
@@ -2723,11 +2754,13 @@ const struct dsa_switch_ops rtl93xx_switch_ops = {
        .port_bridge_leave      = rtldsa_port_bridge_leave,
        .port_stp_state_set     = rtl83xx_port_stp_state_set,
        .port_fast_age          = rtl930x_fast_age,
+       .port_mst_state_set     = rtldsa_port_mst_state_set,
 
        .port_vlan_filtering    = rtl83xx_vlan_filtering,
        .port_vlan_add          = rtl83xx_vlan_add,
        .port_vlan_del          = rtl83xx_vlan_del,
        .port_vlan_fast_age     = rtldsa_port_vlan_fast_age,
+       .vlan_msti_set          = rtldsa_vlan_msti_set,
 
        .port_fdb_add           = rtl83xx_port_fdb_add,
        .port_fdb_del           = rtl83xx_port_fdb_del,