realtek: dsa: Add support for port isolation
authorSven Eckelmann <[email protected]>
Thu, 9 Oct 2025 12:59:16 +0000 (14:59 +0200)
committerRobert Marko <[email protected]>
Sun, 12 Oct 2025 10:49:49 +0000 (12:49 +0200)
If two ports are in isolation mode then these ports are not supposed to be
able to communicate between each other. This can be achieved in the realtek
switch by removing the other isolated port(s) from the port list of an
isolated port.

Signed-off-by: Sven Eckelmann <[email protected]>
Link: https://github.com/openwrt/openwrt/pull/20360
Signed-off-by: Robert Marko <[email protected]>
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.h

index 74cd728de5a8ddea09b3b7e0ec8b2f6588cc2213..bc8f9b656268c11ef01886ea9cf4583b7ef37f46 100644 (file)
@@ -1533,6 +1533,7 @@ static void rtldsa_update_port_member(struct rtl838x_switch_priv *priv, int port
        struct rtl838x_port *other_p;
        struct dsa_port *other_dp;
        int other_port;
+       bool isolated;
 
        dsa_switch_for_each_user_port(other_dp, priv->ds) {
                other_port = other_dp->index;
@@ -1547,7 +1548,9 @@ static void rtldsa_update_port_member(struct rtl838x_switch_priv *priv, int port
                if (join && priv->is_lagmember[other_port])
                        continue;
 
-               if (join) {
+               isolated = p->isolated && other_p->isolated;
+
+               if (join && !isolated) {
                        port_mask |= BIT_ULL(other_port);
                        other_p->pm |= BIT_ULL(port);
                } else {
@@ -1578,6 +1581,9 @@ static int rtl83xx_port_bridge_join(struct dsa_switch *ds, int port,
                return 0;
        }
 
+       /* reset to default flags for new net_bridge_port */
+       priv->ports[port].isolated = false;
+
        mutex_lock(&priv->reg_mutex);
 
        rtldsa_update_port_member(priv, port, bridge.dev, true);
@@ -2375,7 +2381,7 @@ out_unlock:
 static int rtl83xx_port_pre_bridge_flags(struct dsa_switch *ds, int port, struct switchdev_brport_flags flags, struct netlink_ext_ack *extack)
 {
        struct rtl838x_switch_priv *priv = ds->priv;
-       unsigned long features = 0;
+       unsigned long features = BR_ISOLATED;
        pr_debug("%s: %d %lX\n", __func__, port, flags.val);
        if (priv->r->enable_learning)
                features |= BR_LEARNING;
@@ -2408,6 +2414,17 @@ static int rtl83xx_port_bridge_flags(struct dsa_switch *ds, int port, struct swi
        if (priv->r->enable_bcast_flood && (flags.mask & BR_BCAST_FLOOD))
                priv->r->enable_bcast_flood(port, !!(flags.val & BR_BCAST_FLOOD));
 
+       if (flags.mask & BR_ISOLATED) {
+               struct dsa_port *dp = dsa_to_port(ds, port);
+               struct net_device *bridge_dev = dsa_port_bridge_dev_get(dp);
+
+               priv->ports[port].isolated = !!(flags.val & BR_ISOLATED);
+
+               mutex_lock(&priv->reg_mutex);
+               rtldsa_update_port_member(priv, port, bridge_dev, true);
+               mutex_unlock(&priv->reg_mutex);
+       }
+
        return 0;
 }
 
index 028e87820f2ed7ae88ff35879455fd112861eff9..0b0557bd0c264379d8cdf4a1b7f37fac025f2440 100644 (file)
@@ -684,6 +684,7 @@ struct rtl838x_port {
        bool phy_is_integrated:1;
        bool is10G:1;
        bool is2G5:1;
+       bool isolated:1;
        u64 pm;
        u16 pvid;
        bool eee_enabled;