]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
rtl93xx: dsa: Handle lag_change properly 21740/head
authorHarshal Gohel <hg@simonwunderlich.de>
Tue, 27 Jan 2026 11:35:16 +0000 (11:35 +0000)
committerHauke Mehrtens <hauke@hauke-m.de>
Sat, 7 Mar 2026 19:33:22 +0000 (20:33 +0100)
LACP frequently changes active/backup links. driver must also handle
dp->lag_tx_enabled.

This should only affect egress LAG table, ingress should not be touched.
To test, connect a known working 802.3ad compatible switch (Mikrotik).
Configure bond with 802.3ad on openwrt as well as mikrotik.
Observer active/backup links on openwrt with
```
for iface in <list of bond participants>; do
ip -d link show $iface
done
```
This should show ACTIVE/BACKUP status which must be synchronized with
the partner's ACTIVE/BACKUP status if LACP is working correctly.

Backup interface must not be chosen by the distribution algorithm to
transmit egress packet

At the moment, we have two parties involved in the selection of active LAG TX
ports:
- the bonding/DSA code which informs about activated/deactivated ports using
  .port_lag_change
- the HW which is deactivating ports based on the link state see
  RTL93XX_TRK_CTRL_LINK_DOWN_AVOID

In our case, the software is supposed to manage everything

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/common.c
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c

index 481083805cac32d9d560e81145a6b0e6f5204d6a..a7a614a0c562e57c0a7f34c7c5e39345c58f9cb2 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/of_mdio.h>
 #include <linux/of_platform.h>
 #include <net/arp.h>
+#include <net/lag.h>
 #include <net/nexthop.h>
 #include <net/neighbour.h>
 #include <net/netevent.h>
@@ -565,6 +566,11 @@ static int rtldsa_93xx_lag_set_group2ports(struct rtl838x_switch_priv *priv, int
 
        table_pos = 0;
        for_each_set_bit(i, ports, ARRAY_SIZE(priv->ports)) {
+               struct net_device *lag_slave = priv->ports[i].dp->user;
+
+               if (lag_slave && !net_lag_port_dev_txable(lag_slave))
+                       continue;
+
                group_ports[table_pos] = i;
                table_pos++;
        }
@@ -1803,7 +1809,6 @@ void rtldsa_93xx_lag_switch_init(struct rtl838x_switch_priv *priv)
        trk_ctrlmask |= RTL93XX_TRK_CTRL_NON_TMN_TUNNEL_HASH_SEL;
        trk_ctrlmask |= RTL93XX_TRK_CTRL_TRK_STAND_ALONE_MODE;
        trk_ctrlmask |= RTL93XX_TRK_CTRL_LOCAL_FIRST;
-       trk_ctrlmask |= RTL93XX_TRK_CTRL_LINK_DOWN_AVOID;
 
        sw_w32(trk_ctrlmask, priv->r->trk_ctrl);
 
index 92ca67b5d696c73a3f13aed60d9bf402abb8d010..ca3252c1ed91eddfce62e1dec9104ba76fa2f0bb 100644 (file)
@@ -2377,8 +2377,28 @@ static bool rtldsa_83xx_lag_can_offload(struct dsa_switch *ds,
 
 static int rtldsa_port_lag_change(struct dsa_switch *ds, int port)
 {
-       pr_debug("%s: %d\n", __func__, port);
-       /* Nothing to be done... */
+       struct dsa_port *dp = dsa_to_port(ds, port);
+       struct rtl838x_switch_priv *priv = ds->priv;
+       int lag_group;
+       int ret;
+
+       if (!dp)
+               return -EINVAL;
+
+       lag_group = rtldsa_find_lag_group_from_port(priv, port);
+       if (lag_group < 0)
+               return lag_group;
+
+       if (priv->r->lag_set_port_members) {
+               /* Set same port members again, the function should check against
+                * lag_tx_enabled and set egress ports accordingly.
+                */
+               ret = priv->r->lag_set_port_members(priv, lag_group,
+                                                   priv->lags_port_members[lag_group],
+                                                   NULL);
+               if (ret)
+                       return ret;
+       }
 
        return 0;
 }