]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
realtek: dsa: Reelect primary port for a LAG
authorHarshal Gohel <hg@simonwunderlich.de>
Mon, 2 Mar 2026 09:16:10 +0000 (09:16 +0000)
committerHauke Mehrtens <hauke@hauke-m.de>
Sat, 7 Mar 2026 19:33:21 +0000 (20:33 +0100)
rtl93xx hardware supports trunk fdb entries. That requires driver to
translate port-fdb entry to trunk fdb entry if the port is part of a
LAG.

There is no standard way of indicating fdb entries for bond interfaces.

One can use debugfs interface l2_table to dump all the entries stored in
the hardware. Trunk FDB entries are now displayed properly with trunk ID
and participating ports

Co-developed-by: Sven Eckelmann <se@simonwunderlich.de>
Signed-off-by: Sven Eckelmann <se@simonwunderlich.de>
Signed-off-by: Harshal Gohel <hg@simonwunderlich.de>
Link: https://github.com/openwrt/openwrt/pull/21740
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/debugfs.c
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.h
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl930x.c
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl931x.c

index 4b560f61928451ec01b90160d1cff4e9222e61bc..e8085eb7093a19ad963b8c39ad8659082ec3d97e 100644 (file)
@@ -268,6 +268,13 @@ static void l2_table_print_entry(struct seq_file *m, struct rtl838x_switch_priv
                           e->vid, e->rvid);
 
                seq_printf(m, "  port %d age %d", e->port, e->age);
+               if (e->is_trunk) {
+                       seq_printf(m, "  trunk %d trunk_members: 0x%08llx non-primary: 0x%08llx primary-port: %d",
+                                  e->trunk,
+                                  priv->lags_port_members[e->trunk],
+                                  priv->lag_non_primary,
+                                  priv->lag_primary[e->trunk]);
+               }
                if (e->is_static)
                        seq_puts(m, " static");
                if (e->block_da)
index 90dbdf9c3a2a62718e7e771dd49470e01588e864..92ca67b5d696c73a3f13aed60d9bf402abb8d010 100644 (file)
@@ -1865,6 +1865,39 @@ static int rtldsa_find_l2_cam_entry(struct rtl838x_switch_priv *priv, u64 seed,
        return idx;
 }
 
+/**
+ * rtldsa_find_lag_group_from_port() - Find lag group of current port
+ * @priv: private data of rtldsa switch
+ * @port: port id of potential LAG member
+ * Return: -ENOENT when port does not belong to any lag group, lag id otherwise
+ */
+static int rtldsa_find_lag_group_from_port(struct rtl838x_switch_priv *priv, int port)
+{
+       if (!(priv->lagmembers & BIT_ULL(port)))
+               return -ENOENT;
+
+       /* port is a lag member */
+       for (int lag_group = 0; lag_group < MAX_LAGS; lag_group++) {
+               if (priv->lags_port_members[lag_group] & BIT_ULL(port))
+                       return lag_group;
+       }
+
+       return -ENOENT;
+}
+
+/**
+ * rtldsa_93xx_prepare_lag_fdb() - Prepare fdb entry for LAG
+ * @e: L2 entry data
+ * @lag_group: lag id of the trunk group
+ */
+inline void rtldsa_93xx_prepare_lag_fdb(struct rtl838x_l2_entry *e, int lag_group)
+{
+       if (e && lag_group >= 0) {
+               e->is_trunk = true;
+               e->trunk = lag_group;
+       }
+}
+
 static int rtldsa_port_fdb_add(struct dsa_switch *ds, int port,
                               const unsigned char *addr, u16 vid,
                               const struct dsa_db db)
@@ -1874,10 +1907,16 @@ static int rtldsa_port_fdb_add(struct dsa_switch *ds, int port,
        struct rtl838x_l2_entry e;
        int err = 0, idx;
        u64 seed = priv->r->l2_hash_seed(mac, vid);
+       int lag_group = rtldsa_find_lag_group_from_port(priv, port);
 
-       if (priv->lag_non_primary & BIT_ULL(port)) {
-               pr_debug("%s: %d is lag slave. ignore\n", __func__, port);
-               return 0;
+       if (lag_group >= 0 && priv->r->prepare_lag_fdb) {
+               priv->r->prepare_lag_fdb(&e, lag_group);
+       } else {
+               if (priv->lag_non_primary & BIT_ULL(port)) {
+                       pr_debug("%s: %d is lag slave but prepare_lag_fdb is not supported. ignore\n",
+                                __func__, port);
+                       return 0;
+               }
        }
 
        mutex_lock(&priv->reg_mutex);
@@ -1917,8 +1956,13 @@ static int rtldsa_port_fdb_del(struct dsa_switch *ds, int port,
        struct rtl838x_l2_entry e;
        int err = 0, idx;
        u64 seed = priv->r->l2_hash_seed(mac, vid);
+       int lag_group = rtldsa_find_lag_group_from_port(priv, port);
+
+       if (lag_group >= 0 && priv->r->prepare_lag_fdb)
+               priv->r->prepare_lag_fdb(&e, lag_group);
 
        pr_debug("In %s, mac %llx, vid: %d\n", __func__, mac, vid);
+
        mutex_lock(&priv->reg_mutex);
 
        idx = rtldsa_find_l2_hash_entry(priv, seed, true, &e);
@@ -1960,6 +2004,10 @@ static int rtldsa_port_fdb_dump(struct dsa_switch *ds, int port,
                if (!e.valid)
                        continue;
 
+               // Ignore trunk fdb entries
+               if (e.is_trunk)
+                       continue;
+
                if (e.port == port || e.port == RTL930X_PORT_IGNORE)
                        cb(e.mac, e.vid, e.is_static, data);
 
@@ -1973,6 +2021,10 @@ static int rtldsa_port_fdb_dump(struct dsa_switch *ds, int port,
                if (!e.valid)
                        continue;
 
+               // Ignore trunk fdb entries
+               if (e.is_trunk)
+                       continue;
+
                if (e.port == port)
                        cb(e.mac, e.vid, e.is_static, data);
        }
@@ -2396,7 +2448,6 @@ static int rtldsa_port_lag_leave(struct dsa_switch *ds, int port,
        }
        pr_info("port_lag_del: group %d, port %d\n", group, port);
        priv->lagmembers &= ~BIT_ULL(port);
-       priv->lag_primary[group] = -1;
        priv->lag_non_primary &= ~BIT_ULL(port);
        pr_debug("lag_members = %llX\n", priv->lagmembers);
        err = rtl83xx_lag_del(priv->ds, group, port);
@@ -2405,6 +2456,19 @@ static int rtldsa_port_lag_leave(struct dsa_switch *ds, int port,
                goto out;
        }
 
+       /* To re-elect primary interface, just remove the first interface in
+        * this-group's interfaces from non-primary
+        */
+       if (priv->lags_port_members[group]) {
+               priv->lag_primary[group] = fls64(priv->lags_port_members[group]);
+               priv->lag_non_primary &= ~BIT_ULL(priv->lag_primary[group]);
+       }
+
+       /* No need to update fdb entries since they make use of trunk_id for entry.
+        * The primary interface is only calculated at time of
+        * port_fdb_dump
+        */
+
 out:
        mutex_unlock(&priv->reg_mutex);
        return 0;
index 77b7097ca3eb882a72b26960de4a7e2a6f794648..f5b6445d3ba0579c2ec53aedab8d4c81791ad1df 100644 (file)
@@ -1366,6 +1366,8 @@ struct rtldsa_config {
        void (*led_init)(struct rtl838x_switch_priv *priv);
        void (*qos_init)(struct rtl838x_switch_priv *priv);
        int (*trk_mbr_ctr)(int group);
+       void (*lag_switch_init)(struct rtl838x_switch_priv *priv);
+       void (*prepare_lag_fdb)(struct rtl838x_l2_entry *e, int lag_group);
        int (*lag_set_port_members)(struct rtl838x_switch_priv *priv, int group, u64 members,
                                    struct netdev_lag_upper_info *info);
        int (*lag_setup_algomask)(struct rtl838x_switch_priv *priv, int group,
@@ -1449,6 +1451,8 @@ void rtl930x_dbgfs_init(struct rtl838x_switch_priv *priv);
 int rtldsa_93xx_lag_set_distribution_algorithm(struct rtl838x_switch_priv *priv,
                                               int group, int algoidx, u32 algomsk);
 
+void rtldsa_93xx_prepare_lag_fdb(struct rtl838x_l2_entry *e, int lag_group);
+
 void rtldsa_counters_lock_register(struct rtl838x_switch_priv *priv, int port)
        __acquires(&priv->ports[port].counters.lock);
 void rtldsa_counters_unlock_register(struct rtl838x_switch_priv *priv, int port)
index 1452f65c5d0cd8a8318b7814bbb21ab096cd7762..345e642037ab27826cf570359b49e7e7d84cf30e 100644 (file)
@@ -2801,5 +2801,8 @@ const struct rtldsa_config rtldsa_930x_cfg = {
        .set_receive_management_action = rtldsa_930x_set_receive_management_action,
        .qos_init = rtldsa_930x_qos_init,
        .trk_hash_ctrl = RTL930X_TRK_HASH_CTRL,
+       .prepare_lag_fdb = rtldsa_93xx_prepare_lag_fdb,
+       .lag_switch_init = rtldsa_93xx_lag_switch_init,
+       .lag_set_port_members = rtldsa_93xx_lag_set_port_members,
        .lag_set_distribution_algorithm = rtldsa_93xx_lag_set_distribution_algorithm,
 };
index be65340cab916c9a352caaf6f948332cb1497102..e83175312096918076564a59c0b9eba14935565f 100644 (file)
@@ -1925,5 +1925,8 @@ const struct rtldsa_config rtldsa_931x_cfg = {
        .set_receive_management_action = rtldsa_931x_set_receive_management_action,
        .qos_init = rtldsa_931x_qos_init,
        .trk_hash_ctrl = RTL931X_TRK_HASH_CTRL,
+       .prepare_lag_fdb = rtldsa_93xx_prepare_lag_fdb,
+       .lag_switch_init = rtldsa_93xx_lag_switch_init,
+       .lag_set_port_members = rtldsa_93xx_lag_set_port_members,
        .lag_set_distribution_algorithm = rtldsa_93xx_lag_set_distribution_algorithm,
 };