Skip to content

Commit 956d8ef

Browse files
Joseph Huanggregkh
authored andcommitted
net: dsa: mv88e6xxx: Verify after ATU Load ops
[ Upstream commit dc5340c ] ATU Load operations could fail silently if there's not enough space on the device to hold the new entry. When this happens, the symptom depends on the unknown flood settings. If unknown multicast flood is disabled, the multicast packets are dropped when the ATU table is full. If unknown multicast flood is enabled, the multicast packets will be flooded to all ports. Either way, IGMP snooping is broken when the ATU Load operation fails silently. Do a Read-After-Write verification after each fdb/mdb add operation to make sure that the operation was really successful, and return -ENOSPC otherwise. Fixes: defb05b ("net: dsa: mv88e6xxx: Add support for fdb_add, fdb_del, and fdb_getnext") Signed-off-by: Joseph Huang <Joseph.Huang@garmin.com> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Link: https://patch.msgid.link/20250306172306.3859214-1-Joseph.Huang@garmin.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 251841a commit 956d8ef

File tree

1 file changed

+48
-11
lines changed
  • drivers/net/dsa/mv88e6xxx

1 file changed

+48
-11
lines changed

drivers/net/dsa/mv88e6xxx/chip.c

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2261,13 +2261,11 @@ mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
22612261
return err;
22622262
}
22632263

2264-
static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
2265-
const unsigned char *addr, u16 vid,
2266-
u8 state)
2264+
static int mv88e6xxx_port_db_get(struct mv88e6xxx_chip *chip,
2265+
const unsigned char *addr, u16 vid,
2266+
u16 *fid, struct mv88e6xxx_atu_entry *entry)
22672267
{
2268-
struct mv88e6xxx_atu_entry entry;
22692268
struct mv88e6xxx_vtu_entry vlan;
2270-
u16 fid;
22712269
int err;
22722270

22732271
/* Ports have two private address databases: one for when the port is
@@ -2278,7 +2276,7 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
22782276
* VLAN ID into the port's database used for VLAN-unaware bridging.
22792277
*/
22802278
if (vid == 0) {
2281-
fid = MV88E6XXX_FID_BRIDGED;
2279+
*fid = MV88E6XXX_FID_BRIDGED;
22822280
} else {
22832281
err = mv88e6xxx_vtu_get(chip, vid, &vlan);
22842282
if (err)
@@ -2288,14 +2286,39 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
22882286
if (!vlan.valid)
22892287
return -EOPNOTSUPP;
22902288

2291-
fid = vlan.fid;
2289+
*fid = vlan.fid;
22922290
}
22932291

2294-
entry.state = 0;
2295-
ether_addr_copy(entry.mac, addr);
2296-
eth_addr_dec(entry.mac);
2292+
entry->state = 0;
2293+
ether_addr_copy(entry->mac, addr);
2294+
eth_addr_dec(entry->mac);
2295+
2296+
return mv88e6xxx_g1_atu_getnext(chip, *fid, entry);
2297+
}
2298+
2299+
static bool mv88e6xxx_port_db_find(struct mv88e6xxx_chip *chip,
2300+
const unsigned char *addr, u16 vid)
2301+
{
2302+
struct mv88e6xxx_atu_entry entry;
2303+
u16 fid;
2304+
int err;
22972305

2298-
err = mv88e6xxx_g1_atu_getnext(chip, fid, &entry);
2306+
err = mv88e6xxx_port_db_get(chip, addr, vid, &fid, &entry);
2307+
if (err)
2308+
return false;
2309+
2310+
return entry.state && ether_addr_equal(entry.mac, addr);
2311+
}
2312+
2313+
static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
2314+
const unsigned char *addr, u16 vid,
2315+
u8 state)
2316+
{
2317+
struct mv88e6xxx_atu_entry entry;
2318+
u16 fid;
2319+
int err;
2320+
2321+
err = mv88e6xxx_port_db_get(chip, addr, vid, &fid, &entry);
22992322
if (err)
23002323
return err;
23012324

@@ -2893,6 +2916,13 @@ static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
28932916
mv88e6xxx_reg_lock(chip);
28942917
err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
28952918
MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
2919+
if (err)
2920+
goto out;
2921+
2922+
if (!mv88e6xxx_port_db_find(chip, addr, vid))
2923+
err = -ENOSPC;
2924+
2925+
out:
28962926
mv88e6xxx_reg_unlock(chip);
28972927

28982928
return err;
@@ -6593,6 +6623,13 @@ static int mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port,
65936623
mv88e6xxx_reg_lock(chip);
65946624
err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
65956625
MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC);
6626+
if (err)
6627+
goto out;
6628+
6629+
if (!mv88e6xxx_port_db_find(chip, mdb->addr, mdb->vid))
6630+
err = -ENOSPC;
6631+
6632+
out:
65966633
mv88e6xxx_reg_unlock(chip);
65976634

65986635
return err;

0 commit comments

Comments
 (0)