mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
dpaa2-switch: rework FDB management on the bridge leave path
On bridge leave, the dpaa2_switch_port_set_fdb() function always allocates a new FDB for the port which is becoming standalone. In case no FDB is found, then the port leaving a bridge will continue to use the current one. The above logic does not cover the case in which there are multiple bridges which have ports from the same DPSW instance. In this case, when the last port leaves bridge #1, it finds an unused FDB to switch to, but the old FDB is not marked as unused. Since the number of FDBs is equal to the number of DPSW interfaces, this will eventually lead to multiple ports sharing the same FDB. Fix this by changing how we are managing the FDBs on the leave path. Instead of directly allocating a new FDB, first verify if the current port is the last one to leave a bridge. If this is the case, then continue to use the current FDB and only allocate another FDB if there are other ports remaining in the bridge. Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com> Link: https://patch.msgid.link/20260528173452.1953102-2-ioana.ciornei@nxp.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
cfa5274a5d
commit
efc1d92eac
|
|
@ -54,27 +54,44 @@ dpaa2_switch_filter_block_get_unused(struct ethsw_core *ethsw)
|
|||
static u16 dpaa2_switch_port_set_fdb(struct ethsw_port_priv *port_priv,
|
||||
struct net_device *bridge_dev)
|
||||
{
|
||||
struct ethsw_core *ethsw = port_priv->ethsw_data;
|
||||
struct ethsw_port_priv *other_port_priv = NULL;
|
||||
struct dpaa2_switch_fdb *fdb;
|
||||
struct net_device *other_dev;
|
||||
bool last_fdb_user = true;
|
||||
struct list_head *iter;
|
||||
int i;
|
||||
|
||||
/* If we leave a bridge (bridge_dev is NULL), find an unused
|
||||
* FDB and use that.
|
||||
*/
|
||||
if (!bridge_dev) {
|
||||
fdb = dpaa2_switch_fdb_get_unused(port_priv->ethsw_data);
|
||||
/* First verify if this is the last port to leave this bridge */
|
||||
for (i = 0; i < ethsw->sw_attr.num_ifs; i++) {
|
||||
if (!ethsw->ports[i] || ethsw->ports[i] == port_priv)
|
||||
continue;
|
||||
if (ethsw->ports[i]->fdb == port_priv->fdb) {
|
||||
last_fdb_user = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there is no unused FDB, we must be the last port that
|
||||
* leaves the last bridge, all the others are standalone. We
|
||||
* can just keep the FDB that we already have.
|
||||
*/
|
||||
|
||||
if (!fdb) {
|
||||
/* If this is the last user of the FDB, just keep using it. */
|
||||
if (last_fdb_user) {
|
||||
port_priv->fdb->bridge_dev = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Since we are not the last port which leaves a bridge,
|
||||
* acquire a new FDB and use it. The number of FDBs is sized to
|
||||
* accommodate all switch ports as standalone, each with its
|
||||
* private FDB, which means that dpaa2_switch_fdb_get_unused()
|
||||
* must succeed here. WARN if not.
|
||||
*/
|
||||
fdb = dpaa2_switch_fdb_get_unused(port_priv->ethsw_data);
|
||||
if (WARN_ON(!fdb))
|
||||
return 0;
|
||||
|
||||
port_priv->fdb = fdb;
|
||||
port_priv->fdb->in_use = true;
|
||||
port_priv->fdb->bridge_dev = NULL;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user