From 89322b4d69a75ccf1758794b0bce7af375ce1ca1 Mon Sep 17 00:00:00 2001 From: Harshal Gohel Date: Tue, 27 Jan 2026 11:35:16 +0000 Subject: [PATCH] rtl93xx: dsa: Handle lag_change properly 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 ; 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 Signed-off-by: Sven Eckelmann Signed-off-by: Harshal Gohel Link: https://github.com/openwrt/openwrt/pull/21740 Signed-off-by: Hauke Mehrtens --- .../drivers/net/dsa/rtl83xx/common.c | 7 +++++- .../files-6.12/drivers/net/dsa/rtl83xx/dsa.c | 24 +++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/common.c b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/common.c index 481083805c..a7a614a0c5 100644 --- a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/common.c +++ b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/common.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -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); diff --git a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c index 92ca67b5d6..ca3252c1ed 100644 --- a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c @@ -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; }