Skip to content

Commit 09c7fd5

Browse files
committed
Merge branch 'fdb-backpressure-fixes'
Vladimir Oltean says: ==================== Fix broken backpressure during FDB dump in DSA drivers rtnl_fdb_dump() has logic to split a dump of PF_BRIDGE neighbors into multiple netlink skbs if the buffer provided by user space is too small (one buffer will typically handle a few hundred FDB entries). When the current buffer becomes full, nlmsg_put() in dsa_slave_port_fdb_do_dump() returns -EMSGSIZE and DSA saves the index of the last dumped FDB entry, returns to rtnl_fdb_dump() up to that point, and then the dump resumes on the same port with a new skb, and FDB entries up to the saved index are simply skipped. Since dsa_slave_port_fdb_do_dump() is pointed to by the "cb" passed to drivers, then drivers must check for the -EMSGSIZE error code returned by it. Otherwise, when a netlink skb becomes full, DSA will no longer save newly dumped FDB entries to it, but the driver will continue dumping. So FDB entries will be missing from the dump. DSA is one of the few switchdev drivers that have an .ndo_fdb_dump implementation, because of the assumption that the hardware and software FDBs cannot be efficiently kept in sync via SWITCHDEV_FDB_ADD_TO_BRIDGE. Other drivers with a home-cooked .ndo_fdb_dump implementation are ocelot and dpaa2-switch. These appear to do the correct thing, as do the other DSA drivers, so nothing else appears to need fixing. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 4a2b285 + 21b52fe commit 09c7fd5

File tree

4 files changed

+37
-22
lines changed

4 files changed

+37
-22
lines changed

drivers/net/dsa/hirschmann/hellcreek.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,7 @@ static int hellcreek_fdb_dump(struct dsa_switch *ds, int port,
912912
{
913913
struct hellcreek *hellcreek = ds->priv;
914914
u16 entries;
915+
int ret = 0;
915916
size_t i;
916917

917918
mutex_lock(&hellcreek->reg_lock);
@@ -943,12 +944,14 @@ static int hellcreek_fdb_dump(struct dsa_switch *ds, int port,
943944
if (!(entry.portmask & BIT(port)))
944945
continue;
945946

946-
cb(entry.mac, 0, entry.is_static, data);
947+
ret = cb(entry.mac, 0, entry.is_static, data);
948+
if (ret)
949+
break;
947950
}
948951

949952
mutex_unlock(&hellcreek->reg_lock);
950953

951-
return 0;
954+
return ret;
952955
}
953956

954957
static int hellcreek_vlan_filtering(struct dsa_switch *ds, int port,

drivers/net/dsa/lan9303-core.c

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -557,12 +557,12 @@ static int lan9303_alr_make_entry_raw(struct lan9303 *chip, u32 dat0, u32 dat1)
557557
return 0;
558558
}
559559

560-
typedef void alr_loop_cb_t(struct lan9303 *chip, u32 dat0, u32 dat1,
561-
int portmap, void *ctx);
560+
typedef int alr_loop_cb_t(struct lan9303 *chip, u32 dat0, u32 dat1,
561+
int portmap, void *ctx);
562562

563-
static void lan9303_alr_loop(struct lan9303 *chip, alr_loop_cb_t *cb, void *ctx)
563+
static int lan9303_alr_loop(struct lan9303 *chip, alr_loop_cb_t *cb, void *ctx)
564564
{
565-
int i;
565+
int ret = 0, i;
566566

567567
mutex_lock(&chip->alr_mutex);
568568
lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD,
@@ -582,13 +582,17 @@ static void lan9303_alr_loop(struct lan9303 *chip, alr_loop_cb_t *cb, void *ctx)
582582
LAN9303_ALR_DAT1_PORT_BITOFFS;
583583
portmap = alrport_2_portmap[alrport];
584584

585-
cb(chip, dat0, dat1, portmap, ctx);
585+
ret = cb(chip, dat0, dat1, portmap, ctx);
586+
if (ret)
587+
break;
586588

587589
lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD,
588590
LAN9303_ALR_CMD_GET_NEXT);
589591
lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD, 0);
590592
}
591593
mutex_unlock(&chip->alr_mutex);
594+
595+
return ret;
592596
}
593597

594598
static void alr_reg_to_mac(u32 dat0, u32 dat1, u8 mac[6])
@@ -606,18 +610,20 @@ struct del_port_learned_ctx {
606610
};
607611

608612
/* Clear learned (non-static) entry on given port */
609-
static void alr_loop_cb_del_port_learned(struct lan9303 *chip, u32 dat0,
610-
u32 dat1, int portmap, void *ctx)
613+
static int alr_loop_cb_del_port_learned(struct lan9303 *chip, u32 dat0,
614+
u32 dat1, int portmap, void *ctx)
611615
{
612616
struct del_port_learned_ctx *del_ctx = ctx;
613617
int port = del_ctx->port;
614618

615619
if (((BIT(port) & portmap) == 0) || (dat1 & LAN9303_ALR_DAT1_STATIC))
616-
return;
620+
return 0;
617621

618622
/* learned entries has only one port, we can just delete */
619623
dat1 &= ~LAN9303_ALR_DAT1_VALID; /* delete entry */
620624
lan9303_alr_make_entry_raw(chip, dat0, dat1);
625+
626+
return 0;
621627
}
622628

623629
struct port_fdb_dump_ctx {
@@ -626,19 +632,19 @@ struct port_fdb_dump_ctx {
626632
dsa_fdb_dump_cb_t *cb;
627633
};
628634

629-
static void alr_loop_cb_fdb_port_dump(struct lan9303 *chip, u32 dat0,
630-
u32 dat1, int portmap, void *ctx)
635+
static int alr_loop_cb_fdb_port_dump(struct lan9303 *chip, u32 dat0,
636+
u32 dat1, int portmap, void *ctx)
631637
{
632638
struct port_fdb_dump_ctx *dump_ctx = ctx;
633639
u8 mac[ETH_ALEN];
634640
bool is_static;
635641

636642
if ((BIT(dump_ctx->port) & portmap) == 0)
637-
return;
643+
return 0;
638644

639645
alr_reg_to_mac(dat0, dat1, mac);
640646
is_static = !!(dat1 & LAN9303_ALR_DAT1_STATIC);
641-
dump_ctx->cb(mac, 0, is_static, dump_ctx->data);
647+
return dump_ctx->cb(mac, 0, is_static, dump_ctx->data);
642648
}
643649

644650
/* Set a static ALR entry. Delete entry if port_map is zero */
@@ -1210,9 +1216,7 @@ static int lan9303_port_fdb_dump(struct dsa_switch *ds, int port,
12101216
};
12111217

12121218
dev_dbg(chip->dev, "%s(%d)\n", __func__, port);
1213-
lan9303_alr_loop(chip, alr_loop_cb_fdb_port_dump, &dump_ctx);
1214-
1215-
return 0;
1219+
return lan9303_alr_loop(chip, alr_loop_cb_fdb_port_dump, &dump_ctx);
12161220
}
12171221

12181222
static int lan9303_port_mdb_prepare(struct dsa_switch *ds, int port,

drivers/net/dsa/lantiq_gswip.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,11 +1404,17 @@ static int gswip_port_fdb_dump(struct dsa_switch *ds, int port,
14041404
addr[1] = mac_bridge.key[2] & 0xff;
14051405
addr[0] = (mac_bridge.key[2] >> 8) & 0xff;
14061406
if (mac_bridge.val[1] & GSWIP_TABLE_MAC_BRIDGE_STATIC) {
1407-
if (mac_bridge.val[0] & BIT(port))
1408-
cb(addr, 0, true, data);
1407+
if (mac_bridge.val[0] & BIT(port)) {
1408+
err = cb(addr, 0, true, data);
1409+
if (err)
1410+
return err;
1411+
}
14091412
} else {
1410-
if (((mac_bridge.val[0] & GENMASK(7, 4)) >> 4) == port)
1411-
cb(addr, 0, false, data);
1413+
if (((mac_bridge.val[0] & GENMASK(7, 4)) >> 4) == port) {
1414+
err = cb(addr, 0, false, data);
1415+
if (err)
1416+
return err;
1417+
}
14121418
}
14131419
}
14141420
return 0;

drivers/net/dsa/sja1105/sja1105_main.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1635,7 +1635,9 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
16351635
/* We need to hide the dsa_8021q VLANs from the user. */
16361636
if (priv->vlan_state == SJA1105_VLAN_UNAWARE)
16371637
l2_lookup.vlanid = 0;
1638-
cb(macaddr, l2_lookup.vlanid, l2_lookup.lockeds, data);
1638+
rc = cb(macaddr, l2_lookup.vlanid, l2_lookup.lockeds, data);
1639+
if (rc)
1640+
return rc;
16391641
}
16401642
return 0;
16411643
}

0 commit comments

Comments
 (0)