Skip to content

Commit dc5340c

Browse files
Joseph Huangkuba-moo
authored andcommitted
net: dsa: mv88e6xxx: Verify after ATU Load ops
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>
1 parent d749d90 commit dc5340c

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
@@ -2208,13 +2208,11 @@ mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
22082208
return err;
22092209
}
22102210

2211-
static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
2212-
const unsigned char *addr, u16 vid,
2213-
u8 state)
2211+
static int mv88e6xxx_port_db_get(struct mv88e6xxx_chip *chip,
2212+
const unsigned char *addr, u16 vid,
2213+
u16 *fid, struct mv88e6xxx_atu_entry *entry)
22142214
{
2215-
struct mv88e6xxx_atu_entry entry;
22162215
struct mv88e6xxx_vtu_entry vlan;
2217-
u16 fid;
22182216
int err;
22192217

22202218
/* Ports have two private address databases: one for when the port is
@@ -2225,7 +2223,7 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
22252223
* VLAN ID into the port's database used for VLAN-unaware bridging.
22262224
*/
22272225
if (vid == 0) {
2228-
fid = MV88E6XXX_FID_BRIDGED;
2226+
*fid = MV88E6XXX_FID_BRIDGED;
22292227
} else {
22302228
err = mv88e6xxx_vtu_get(chip, vid, &vlan);
22312229
if (err)
@@ -2235,14 +2233,39 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
22352233
if (!vlan.valid)
22362234
return -EOPNOTSUPP;
22372235

2238-
fid = vlan.fid;
2236+
*fid = vlan.fid;
22392237
}
22402238

2241-
entry.state = 0;
2242-
ether_addr_copy(entry.mac, addr);
2243-
eth_addr_dec(entry.mac);
2239+
entry->state = 0;
2240+
ether_addr_copy(entry->mac, addr);
2241+
eth_addr_dec(entry->mac);
2242+
2243+
return mv88e6xxx_g1_atu_getnext(chip, *fid, entry);
2244+
}
2245+
2246+
static bool mv88e6xxx_port_db_find(struct mv88e6xxx_chip *chip,
2247+
const unsigned char *addr, u16 vid)
2248+
{
2249+
struct mv88e6xxx_atu_entry entry;
2250+
u16 fid;
2251+
int err;
22442252

2245-
err = mv88e6xxx_g1_atu_getnext(chip, fid, &entry);
2253+
err = mv88e6xxx_port_db_get(chip, addr, vid, &fid, &entry);
2254+
if (err)
2255+
return false;
2256+
2257+
return entry.state && ether_addr_equal(entry.mac, addr);
2258+
}
2259+
2260+
static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
2261+
const unsigned char *addr, u16 vid,
2262+
u8 state)
2263+
{
2264+
struct mv88e6xxx_atu_entry entry;
2265+
u16 fid;
2266+
int err;
2267+
2268+
err = mv88e6xxx_port_db_get(chip, addr, vid, &fid, &entry);
22462269
if (err)
22472270
return err;
22482271

@@ -2846,6 +2869,13 @@ static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
28462869
mv88e6xxx_reg_lock(chip);
28472870
err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
28482871
MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
2872+
if (err)
2873+
goto out;
2874+
2875+
if (!mv88e6xxx_port_db_find(chip, addr, vid))
2876+
err = -ENOSPC;
2877+
2878+
out:
28492879
mv88e6xxx_reg_unlock(chip);
28502880

28512881
return err;
@@ -6614,6 +6644,13 @@ static int mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port,
66146644
mv88e6xxx_reg_lock(chip);
66156645
err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
66166646
MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC);
6647+
if (err)
6648+
goto out;
6649+
6650+
if (!mv88e6xxx_port_db_find(chip, mdb->addr, mdb->vid))
6651+
err = -ENOSPC;
6652+
6653+
out:
66176654
mv88e6xxx_reg_unlock(chip);
66186655

66196656
return err;

0 commit comments

Comments
 (0)