realtek: dsa: Reelect primary port for a LAG

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>
This commit is contained in:
Harshal Gohel 2026-03-02 09:16:10 +00:00 committed by Hauke Mehrtens
parent 286445257d
commit 3743ed0e02
5 changed files with 85 additions and 4 deletions

View 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)

View 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;

View 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)

View 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,
};

View 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,
};