2023-01-30 17:37:16

by Hans Schultz

[permalink] [raw]
Subject: [PATCH net-next 0/5] ATU and FDB synchronization on locked ports

This patch set makes it possible to have synchronized dynamic ATU and FDB
entries on locked ports. As locked ports are not able to automatically
learn, they depend on userspace added entries, where userspace can add
static or dynamic entries. The lifetime of static entries are completely
dependent on userspace intervention, and thus not of interest here. We
are only concerned with dynamic entries, which can be added with a
command like:

bridge fdb replace ADDR dev <DEV> master dynamic

We choose only to support this feature on locked ports, as it involves
utilizing the CPU to handle ATU related switchcore events (typically
interrupts) and thus can result in significant performance loss if
exposed to heavy traffic.

On locked ports it is important for userspace to know when an authorized
station has become silent, hence not breaking the communication of a
station that has been authorized based on the MAC-Authentication Bypass
(MAB) scheme. Thus if the station keeps being active after authorization,
it will continue to have an open port as long as it is active. Only after
a silent period will it have to be reauthorized. As the ageing process in
the ATU is dependent on incoming traffic to the switchcore port, it is
necessary for the ATU to signal that an entry has aged out, so that the
FDB can be updated at the correct time.

This patch set includes a solution for the Marvell mv88e6xxx driver, where
for this driver we use the Hold-At-One feature so that an age-out
violation interrupt occurs when a station has been silent for the
system-set age time. The age out violation interrupt allows the switchcore
driver to remove both the ATU and the FDB entry at the same time.

It is up to the maintainers of other switchcore drivers to implement the
feature for their specific driver.

Hans J. Schultz (5):
net: bridge: add dynamic flag to switchdev notifier
net: dsa: propagate flags down towards drivers
drivers: net: dsa: add fdb entry flags incoming to switchcore drivers
net: bridge: ensure FDB offloaded flag is handled as needed
net: dsa: mv88e6xxx: implementation of dynamic ATU entries

drivers/net/dsa/b53/b53_common.c | 12 ++++-
drivers/net/dsa/b53/b53_priv.h | 4 +-
drivers/net/dsa/hirschmann/hellcreek.c | 12 ++++-
drivers/net/dsa/lan9303-core.c | 12 ++++-
drivers/net/dsa/lantiq_gswip.c | 12 ++++-
drivers/net/dsa/microchip/ksz9477.c | 8 ++--
drivers/net/dsa/microchip/ksz9477.h | 8 ++--
drivers/net/dsa/microchip/ksz_common.c | 14 ++++--
drivers/net/dsa/mt7530.c | 12 ++++-
drivers/net/dsa/mv88e6xxx/chip.c | 24 ++++++++--
drivers/net/dsa/mv88e6xxx/global1_atu.c | 21 +++++++++
drivers/net/dsa/mv88e6xxx/port.c | 6 ++-
drivers/net/dsa/mv88e6xxx/switchdev.c | 61 +++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/switchdev.h | 5 ++
drivers/net/dsa/mv88e6xxx/trace.h | 5 ++
drivers/net/dsa/ocelot/felix.c | 12 ++++-
drivers/net/dsa/qca/qca8k-common.c | 12 ++++-
drivers/net/dsa/qca/qca8k.h | 4 +-
drivers/net/dsa/rzn1_a5psw.c | 12 ++++-
drivers/net/dsa/sja1105/sja1105_main.c | 19 ++++++--
include/net/dsa.h | 6 ++-
include/net/switchdev.h | 1 +
net/bridge/br_fdb.c | 5 +-
net/bridge/br_switchdev.c | 2 +
net/dsa/port.c | 28 +++++++-----
net/dsa/port.h | 8 ++--
net/dsa/slave.c | 17 +++++--
net/dsa/switch.c | 30 ++++++++----
net/dsa/switch.h | 1 +
29 files changed, 299 insertions(+), 74 deletions(-)

--
2.34.1



2023-01-30 17:37:19

by Hans Schultz

[permalink] [raw]
Subject: [PATCH net-next 5/5] net: dsa: mv88e6xxx: implementation of dynamic ATU entries

For 802.1X or MAB security authed hosts we want to have these hosts authed
by adding dynamic FDB entries, so that if an authed host goes silent for
a time period it's FDB entry will be removed and it must reauth when
wanting to communicate again.
In the mv88e6xxx offloaded case, we can use the HoldAt1 feature, that
gives an age out interrupt when the FDB entry is about to age out, so
that userspace can be notified of the entry being deleted with the help
of an SWITCHDEV_FDB_DEL_TO_BRIDGE event.
When adding a dynamic entry the bridge must be informed that the driver
takes care of the ageing be sending an SWITCHDEV_FDB_OFFLOADED event,
telling the bridge that this added FDB entry will be handled by the
driver.
With this implementation, trace events for age out interrupts are also
added.

note: A special case arises with the age out interrupt, as the entry
state/spid (source port id) value read from the registers will be zero.
Thus we need to extract the source port from the port vector instead.

Signed-off-by: Hans J. Schultz <[email protected]>
---
drivers/net/dsa/mv88e6xxx/chip.c | 18 ++++++--
drivers/net/dsa/mv88e6xxx/global1_atu.c | 21 +++++++++
drivers/net/dsa/mv88e6xxx/port.c | 6 ++-
drivers/net/dsa/mv88e6xxx/switchdev.c | 61 +++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/switchdev.h | 5 ++
drivers/net/dsa/mv88e6xxx/trace.h | 5 ++
6 files changed, 110 insertions(+), 6 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 61d5dc4680e3..a0007d96b2a3 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -42,6 +42,7 @@
#include "ptp.h"
#include "serdes.h"
#include "smi.h"
+#include "switchdev.h"

static void assert_reg_lock(struct mv88e6xxx_chip *chip)
{
@@ -2726,18 +2727,25 @@ static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
u16 fdb_flags, struct dsa_db db)
{
+ bool is_dynamic = !!(fdb_flags & DSA_FDB_FLAG_DYNAMIC);
struct mv88e6xxx_chip *chip = ds->priv;
+ u8 state;
int err;

- /* Ignore entries with flags set */
- if (fdb_flags)
- return 0;
+ state = MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC;
+ if (is_dynamic)
+ state = MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_7_NEWEST;
+ else
+ if (fdb_flags)
+ return 0;

mv88e6xxx_reg_lock(chip);
- err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
- MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
+ err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, state);
mv88e6xxx_reg_unlock(chip);

+ if (is_dynamic && !err)
+ mv88e6xxx_set_fdb_offloaded(ds, port, addr, vid);
+
return err;
}

diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c
index ce3b3690c3c0..c95f8cffba41 100644
--- a/drivers/net/dsa/mv88e6xxx/global1_atu.c
+++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c
@@ -432,6 +432,27 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)

spid = entry.state;

+ if (val & MV88E6XXX_G1_ATU_OP_AGE_OUT_VIOLATION) {
+ unsigned long port = 0;
+ unsigned long portvec = entry.portvec;
+
+ port = find_first_bit(&portvec, MV88E6XXX_MAX_PVT_PORTS);
+ if (port >= MV88E6XXX_MAX_PVT_PORTS) {
+ dev_err(chip->dev,
+ "ATU err: mac: %pM. Port not in portvec: %x\n",
+ entry.mac, entry.portvec);
+ goto out;
+ }
+
+ spid = port;
+ trace_mv88e6xxx_atu_age_out_violation(chip->dev, spid,
+ entry.portvec, entry.mac,
+ fid);
+
+ err = mv88e6xxx_handle_age_out_violation(chip, spid,
+ &entry, fid);
+ }
+
if (val & MV88E6XXX_G1_ATU_OP_MEMBER_VIOLATION) {
trace_mv88e6xxx_atu_member_violation(chip->dev, spid,
entry.portvec, entry.mac,
diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index f79cf716c541..5225971b9a33 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -1255,7 +1255,11 @@ int mv88e6xxx_port_set_lock(struct mv88e6xxx_chip *chip, int port,

reg &= ~MV88E6XXX_PORT_ASSOC_VECTOR_LOCKED_PORT;
if (locked)
- reg |= MV88E6XXX_PORT_ASSOC_VECTOR_LOCKED_PORT;
+ reg |= MV88E6XXX_PORT_ASSOC_VECTOR_LOCKED_PORT |
+ MV88E6XXX_PORT_ASSOC_VECTOR_REFRESH_LOCKED |
+ MV88E6XXX_PORT_ASSOC_VECTOR_IGNORE_WRONG |
+ MV88E6XXX_PORT_ASSOC_VECTOR_INT_AGE_OUT |
+ MV88E6XXX_PORT_ASSOC_VECTOR_HOLD_AT_1;

return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, reg);
}
diff --git a/drivers/net/dsa/mv88e6xxx/switchdev.c b/drivers/net/dsa/mv88e6xxx/switchdev.c
index 4c346a884fb2..76f7f8cc1835 100644
--- a/drivers/net/dsa/mv88e6xxx/switchdev.c
+++ b/drivers/net/dsa/mv88e6xxx/switchdev.c
@@ -12,6 +12,25 @@
#include "global1.h"
#include "switchdev.h"

+void mv88e6xxx_set_fdb_offloaded(struct dsa_switch *ds, int port,
+ const unsigned char *addr, u16 vid)
+{
+ struct switchdev_notifier_fdb_info info = {
+ .addr = addr,
+ .vid = vid,
+ .offloaded = true,
+ };
+ struct net_device *brport;
+ struct dsa_port *dp;
+
+ dp = dsa_to_port(ds, port);
+ brport = dsa_port_to_bridge_port(dp);
+
+ if (brport)
+ call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED,
+ brport, &info.info, NULL);
+}
+
struct mv88e6xxx_fid_search_ctx {
u16 fid_search;
u16 vid_found;
@@ -81,3 +100,45 @@ int mv88e6xxx_handle_miss_violation(struct mv88e6xxx_chip *chip, int port,

return err;
}
+
+int mv88e6xxx_handle_age_out_violation(struct mv88e6xxx_chip *chip, int port,
+ struct mv88e6xxx_atu_entry *entry,
+ u16 fid)
+{
+ struct switchdev_notifier_fdb_info info = {
+ .addr = entry->mac,
+ };
+ struct net_device *brport;
+ struct dsa_port *dp;
+ u16 vid;
+ int err;
+
+ err = mv88e6xxx_find_vid(chip, fid, &vid);
+ if (err)
+ return err;
+
+ info.vid = vid;
+ entry->portvec &= ~BIT(port);
+ entry->state = MV88E6XXX_G1_ATU_DATA_STATE_UC_UNUSED;
+ entry->trunk = false;
+
+ mv88e6xxx_reg_lock(chip);
+ err = mv88e6xxx_g1_atu_loadpurge(chip, fid, entry);
+ mv88e6xxx_reg_unlock(chip);
+ if (err)
+ return err;
+
+ dp = dsa_to_port(chip->ds, port);
+
+ rtnl_lock();
+ brport = dsa_port_to_bridge_port(dp);
+ if (!brport) {
+ rtnl_unlock();
+ return -ENODEV;
+ }
+ err = call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE,
+ brport, &info.info, NULL);
+ rtnl_unlock();
+
+ return err;
+}
diff --git a/drivers/net/dsa/mv88e6xxx/switchdev.h b/drivers/net/dsa/mv88e6xxx/switchdev.h
index 62214f9d62b0..5af6ac6a490a 100644
--- a/drivers/net/dsa/mv88e6xxx/switchdev.h
+++ b/drivers/net/dsa/mv88e6xxx/switchdev.h
@@ -12,8 +12,13 @@

#include "chip.h"

+void mv88e6xxx_set_fdb_offloaded(struct dsa_switch *ds, int port,
+ const unsigned char *addr, u16 vid);
int mv88e6xxx_handle_miss_violation(struct mv88e6xxx_chip *chip, int port,
struct mv88e6xxx_atu_entry *entry,
u16 fid);
+int mv88e6xxx_handle_age_out_violation(struct mv88e6xxx_chip *chip, int port,
+ struct mv88e6xxx_atu_entry *entry,
+ u16 fid);

#endif /* _MV88E6XXX_SWITCHDEV_H_ */
diff --git a/drivers/net/dsa/mv88e6xxx/trace.h b/drivers/net/dsa/mv88e6xxx/trace.h
index f59ca04768e7..c6b32abf68a5 100644
--- a/drivers/net/dsa/mv88e6xxx/trace.h
+++ b/drivers/net/dsa/mv88e6xxx/trace.h
@@ -40,6 +40,11 @@ DECLARE_EVENT_CLASS(mv88e6xxx_atu_violation,
__entry->addr, __entry->fid)
);

+DEFINE_EVENT(mv88e6xxx_atu_violation, mv88e6xxx_atu_age_out_violation,
+ TP_PROTO(const struct device *dev, int spid, u16 portvec,
+ const unsigned char *addr, u16 fid),
+ TP_ARGS(dev, spid, portvec, addr, fid));
+
DEFINE_EVENT(mv88e6xxx_atu_violation, mv88e6xxx_atu_member_violation,
TP_PROTO(const struct device *dev, int spid, u16 portvec,
const unsigned char *addr, u16 fid),
--
2.34.1


2023-01-30 17:37:21

by Hans Schultz

[permalink] [raw]
Subject: [PATCH net-next 3/5] drivers: net: dsa: add fdb entry flags incoming to switchcore drivers

Ignore FDB entries with set flags coming in on all switchcore drivers.

Signed-off-by: Hans J. Schultz <[email protected]>
---
drivers/net/dsa/b53/b53_common.c | 12 ++++++++++--
drivers/net/dsa/b53/b53_priv.h | 4 ++--
drivers/net/dsa/hirschmann/hellcreek.c | 12 ++++++++++--
drivers/net/dsa/lan9303-core.c | 12 ++++++++++--
drivers/net/dsa/lantiq_gswip.c | 12 ++++++++++--
drivers/net/dsa/microchip/ksz9477.c | 8 ++++----
drivers/net/dsa/microchip/ksz9477.h | 8 ++++----
drivers/net/dsa/microchip/ksz_common.c | 14 +++++++++++---
drivers/net/dsa/mt7530.c | 12 ++++++++++--
drivers/net/dsa/mv88e6xxx/chip.c | 12 ++++++++++--
drivers/net/dsa/ocelot/felix.c | 12 ++++++++++--
drivers/net/dsa/qca/qca8k-common.c | 12 ++++++++++--
drivers/net/dsa/qca/qca8k.h | 4 ++--
drivers/net/dsa/rzn1_a5psw.c | 12 ++++++++++--
drivers/net/dsa/sja1105/sja1105_main.c | 19 ++++++++++++++-----
include/net/dsa.h | 4 ++--
net/dsa/switch.c | 12 ++++++++----
17 files changed, 137 insertions(+), 44 deletions(-)

diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index 59cdfc51ce06..cec60af6dfdc 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -1684,11 +1684,15 @@ static int b53_arl_op(struct b53_device *dev, int op, int port,

int b53_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
struct b53_device *priv = ds->priv;
int ret;

+ /* Ignore entries with set flags */
+ if (fdb_flags)
+ return 0;
+
/* 5325 and 5365 require some more massaging, but could
* be supported eventually
*/
@@ -1705,11 +1709,15 @@ EXPORT_SYMBOL(b53_fdb_add);

int b53_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
struct b53_device *priv = ds->priv;
int ret;

+ /* Ignore entries with set flags */
+ if (fdb_flags)
+ return 0;
+
mutex_lock(&priv->arl_mutex);
ret = b53_arl_op(priv, 0, port, addr, vid, false);
mutex_unlock(&priv->arl_mutex);
diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h
index 795cbffd5c2b..7673c4e712bb 100644
--- a/drivers/net/dsa/b53/b53_priv.h
+++ b/drivers/net/dsa/b53/b53_priv.h
@@ -362,10 +362,10 @@ int b53_vlan_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan);
int b53_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db);
+ u16 fdb_flags, struct dsa_db db);
int b53_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db);
+ u16 fdb_flags, struct dsa_db db);
int b53_fdb_dump(struct dsa_switch *ds, int port,
dsa_fdb_dump_cb_t *cb, void *data);
int b53_mdb_add(struct dsa_switch *ds, int port,
diff --git a/drivers/net/dsa/hirschmann/hellcreek.c b/drivers/net/dsa/hirschmann/hellcreek.c
index 595a548bb0a8..b5884fc9cf85 100644
--- a/drivers/net/dsa/hirschmann/hellcreek.c
+++ b/drivers/net/dsa/hirschmann/hellcreek.c
@@ -839,12 +839,16 @@ static int hellcreek_fdb_get(struct hellcreek *hellcreek,

static int hellcreek_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
struct hellcreek_fdb_entry entry = { 0 };
struct hellcreek *hellcreek = ds->priv;
int ret;

+ /* Ignore entries with set flags */
+ if (fdb_flags)
+ return 0;
+
dev_dbg(hellcreek->dev, "Add FDB entry for MAC=%pM\n", addr);

mutex_lock(&hellcreek->reg_lock);
@@ -885,12 +889,16 @@ static int hellcreek_fdb_add(struct dsa_switch *ds, int port,

static int hellcreek_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
struct hellcreek_fdb_entry entry = { 0 };
struct hellcreek *hellcreek = ds->priv;
int ret;

+ /* Ignore entries with set flags */
+ if (fdb_flags)
+ return 0;
+
dev_dbg(hellcreek->dev, "Delete FDB entry for MAC=%pM\n", addr);

mutex_lock(&hellcreek->reg_lock);
diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c
index cbe831875347..809da5fb23a8 100644
--- a/drivers/net/dsa/lan9303-core.c
+++ b/drivers/net/dsa/lan9303-core.c
@@ -1183,10 +1183,14 @@ static void lan9303_port_fast_age(struct dsa_switch *ds, int port)

static int lan9303_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
struct lan9303 *chip = ds->priv;

+ /* Ignore entries with set flags */
+ if (fdb_flags)
+ return 0;
+
dev_dbg(chip->dev, "%s(%d, %pM, %d)\n", __func__, port, addr, vid);
if (vid)
return -EOPNOTSUPP;
@@ -1196,10 +1200,14 @@ static int lan9303_port_fdb_add(struct dsa_switch *ds, int port,

static int lan9303_port_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
struct lan9303 *chip = ds->priv;

+ /* Ignore entries with set flags */
+ if (fdb_flags)
+ return 0;
+
dev_dbg(chip->dev, "%s(%d, %pM, %d)\n", __func__, port, addr, vid);
if (vid)
return -EOPNOTSUPP;
diff --git a/drivers/net/dsa/lantiq_gswip.c b/drivers/net/dsa/lantiq_gswip.c
index 05ecaa007ab1..a945e8e62232 100644
--- a/drivers/net/dsa/lantiq_gswip.c
+++ b/drivers/net/dsa/lantiq_gswip.c
@@ -1399,15 +1399,23 @@ static int gswip_port_fdb(struct dsa_switch *ds, int port,

static int gswip_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
+ /* Ignore entries with set flags */
+ if (fdb_flags)
+ return 0;
+
return gswip_port_fdb(ds, port, addr, vid, true);
}

static int gswip_port_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
+ /* Ignore entries with set flags */
+ if (fdb_flags)
+ return 0;
+
return gswip_port_fdb(ds, port, addr, vid, false);
}

diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c
index bf13d47c26cf..c6a09b444153 100644
--- a/drivers/net/dsa/microchip/ksz9477.c
+++ b/drivers/net/dsa/microchip/ksz9477.c
@@ -449,8 +449,8 @@ int ksz9477_port_vlan_del(struct ksz_device *dev, int port,
return 0;
}

-int ksz9477_fdb_add(struct ksz_device *dev, int port,
- const unsigned char *addr, u16 vid, struct dsa_db db)
+int ksz9477_fdb_add(struct ksz_device *dev, int port, const unsigned char *addr,
+ u16 vid, struct dsa_db db)
{
u32 alu_table[4];
u32 data;
@@ -505,8 +505,8 @@ int ksz9477_fdb_add(struct ksz_device *dev, int port,
return ret;
}

-int ksz9477_fdb_del(struct ksz_device *dev, int port,
- const unsigned char *addr, u16 vid, struct dsa_db db)
+int ksz9477_fdb_del(struct ksz_device *dev, int port, const unsigned char *addr,
+ u16 vid, struct dsa_db db)
{
u32 alu_table[4];
u32 data;
diff --git a/drivers/net/dsa/microchip/ksz9477.h b/drivers/net/dsa/microchip/ksz9477.h
index b6f7e3c46e3f..bb6182fa65b9 100644
--- a/drivers/net/dsa/microchip/ksz9477.h
+++ b/drivers/net/dsa/microchip/ksz9477.h
@@ -41,10 +41,10 @@ void ksz9477_get_caps(struct ksz_device *dev, int port,
struct phylink_config *config);
int ksz9477_fdb_dump(struct ksz_device *dev, int port,
dsa_fdb_dump_cb_t *cb, void *data);
-int ksz9477_fdb_add(struct ksz_device *dev, int port,
- const unsigned char *addr, u16 vid, struct dsa_db db);
-int ksz9477_fdb_del(struct ksz_device *dev, int port,
- const unsigned char *addr, u16 vid, struct dsa_db db);
+int ksz9477_fdb_add(struct ksz_device *dev, int port, const unsigned char *addr,
+ u16 vid, struct dsa_db db);
+int ksz9477_fdb_del(struct ksz_device *dev, int port, const unsigned char *addr,
+ u16 vid, struct dsa_db db);
int ksz9477_mdb_add(struct ksz_device *dev, int port,
const struct switchdev_obj_port_mdb *mdb, struct dsa_db db);
int ksz9477_mdb_del(struct ksz_device *dev, int port,
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index 46becc0382d6..a45e75ed4c36 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -2390,10 +2390,14 @@ static int ksz_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)

static int ksz_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
struct ksz_device *dev = ds->priv;

+ /* Ignore entries with set flags */
+ if (fdb_flags)
+ return 0;
+
if (!dev->dev_ops->fdb_add)
return -EOPNOTSUPP;

@@ -2401,11 +2405,15 @@ static int ksz_port_fdb_add(struct dsa_switch *ds, int port,
}

static int ksz_port_fdb_del(struct dsa_switch *ds, int port,
- const unsigned char *addr,
- u16 vid, struct dsa_db db)
+ const unsigned char *addr, u16 vid,
+ u16 fdb_flags, struct dsa_db db)
{
struct ksz_device *dev = ds->priv;

+ /* Ignore entries with set flags */
+ if (fdb_flags)
+ return 0;
+
if (!dev->dev_ops->fdb_del)
return -EOPNOTSUPP;

diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 616b21c90d05..fea14c093df8 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -1362,12 +1362,16 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
static int
mt7530_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
struct mt7530_priv *priv = ds->priv;
int ret;
u8 port_mask = BIT(port);

+ /* Ignore entries with set flags */
+ if (fdb_flags)
+ return 0;
+
mutex_lock(&priv->reg_mutex);
mt7530_fdb_write(priv, vid, port_mask, addr, -1, STATIC_ENT);
ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, NULL);
@@ -1379,12 +1383,16 @@ mt7530_port_fdb_add(struct dsa_switch *ds, int port,
static int
mt7530_port_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
struct mt7530_priv *priv = ds->priv;
int ret;
u8 port_mask = BIT(port);

+ /* Ignore entries with set flags */
+ if (fdb_flags)
+ return 0;
+
mutex_lock(&priv->reg_mutex);
mt7530_fdb_write(priv, vid, port_mask, addr, -1, STATIC_EMP);
ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, NULL);
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 0a5d6c7bb128..61d5dc4680e3 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -2724,11 +2724,15 @@ static int mv88e6xxx_vlan_msti_set(struct dsa_switch *ds,

static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
struct mv88e6xxx_chip *chip = ds->priv;
int err;

+ /* Ignore entries with flags set */
+ if (fdb_flags)
+ return 0;
+
mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
@@ -2739,11 +2743,15 @@ static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,

static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
struct mv88e6xxx_chip *chip = ds->priv;
int err;

+ /* Ignore entries with flags set */
+ if (fdb_flags)
+ return 0;
+
mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 0);
mv88e6xxx_reg_unlock(chip);
diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index f57b4095b793..38e6a8d64a0b 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -782,12 +782,16 @@ static int felix_fdb_dump(struct dsa_switch *ds, int port,

static int felix_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
struct net_device *bridge_dev = felix_classify_db(db);
struct dsa_port *dp = dsa_to_port(ds, port);
struct ocelot *ocelot = ds->priv;

+ /* Ignore entries with set flags */
+ if (fdb_flags)
+ return 0;
+
if (IS_ERR(bridge_dev))
return PTR_ERR(bridge_dev);

@@ -803,12 +807,16 @@ static int felix_fdb_add(struct dsa_switch *ds, int port,

static int felix_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
struct net_device *bridge_dev = felix_classify_db(db);
struct dsa_port *dp = dsa_to_port(ds, port);
struct ocelot *ocelot = ds->priv;

+ /* Ignore entries with set flags */
+ if (fdb_flags)
+ return 0;
+
if (IS_ERR(bridge_dev))
return PTR_ERR(bridge_dev);

diff --git a/drivers/net/dsa/qca/qca8k-common.c b/drivers/net/dsa/qca/qca8k-common.c
index 96773e432558..6d6aa2d0d487 100644
--- a/drivers/net/dsa/qca/qca8k-common.c
+++ b/drivers/net/dsa/qca/qca8k-common.c
@@ -758,21 +758,29 @@ int qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr,

int qca8k_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
u16 port_mask = BIT(port);

+ /* Ignore entries with set flags */
+ if (fdb_flags)
+ return 0;
+
return qca8k_port_fdb_insert(priv, addr, port_mask, vid);
}

int qca8k_port_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
u16 port_mask = BIT(port);

+ /* Ignore entries with set flags */
+ if (fdb_flags)
+ return 0;
+
if (!vid)
vid = QCA8K_PORT_VID_DEF;

diff --git a/drivers/net/dsa/qca/qca8k.h b/drivers/net/dsa/qca/qca8k.h
index 7996975d29d3..f51306e04e52 100644
--- a/drivers/net/dsa/qca/qca8k.h
+++ b/drivers/net/dsa/qca/qca8k.h
@@ -473,10 +473,10 @@ int qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr,
u16 port_mask, u16 vid);
int qca8k_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db);
+ u16 fdb_flags, struct dsa_db db);
int qca8k_port_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db);
+ u16 fdb_flags, struct dsa_db db);
int qca8k_port_fdb_dump(struct dsa_switch *ds, int port,
dsa_fdb_dump_cb_t *cb, void *data);

diff --git a/drivers/net/dsa/rzn1_a5psw.c b/drivers/net/dsa/rzn1_a5psw.c
index 919027cf2012..236e0754e5eb 100644
--- a/drivers/net/dsa/rzn1_a5psw.c
+++ b/drivers/net/dsa/rzn1_a5psw.c
@@ -396,7 +396,7 @@ static int a5psw_lk_execute_lookup(struct a5psw *a5psw, union lk_data *lk_data,

static int a5psw_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
struct a5psw *a5psw = ds->priv;
union lk_data lk_data = {0};
@@ -405,6 +405,10 @@ static int a5psw_port_fdb_add(struct dsa_switch *ds, int port,
u16 entry;
u32 reg;

+ /* Ignore entries with set flags */
+ if (fdb_flags)
+ return 0;
+
ether_addr_copy(lk_data.entry.mac, addr);
lk_data.entry.port_mask = BIT(port);

@@ -447,7 +451,7 @@ static int a5psw_port_fdb_add(struct dsa_switch *ds, int port,

static int a5psw_port_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
struct a5psw *a5psw = ds->priv;
union lk_data lk_data = {0};
@@ -456,6 +460,10 @@ static int a5psw_port_fdb_del(struct dsa_switch *ds, int port,
u32 reg;
int ret;

+ /* Ignore entries with set flags */
+ if (fdb_flags)
+ return 0;
+
ether_addr_copy(lk_data.entry.mac, addr);

mutex_lock(&a5psw->lk_lock);
diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c
index b70dcf32a26d..6fddd832017b 100644
--- a/drivers/net/dsa/sja1105/sja1105_main.c
+++ b/drivers/net/dsa/sja1105/sja1105_main.c
@@ -1802,10 +1802,14 @@ int sja1105pqrs_fdb_del(struct dsa_switch *ds, int port,

static int sja1105_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
struct sja1105_private *priv = ds->priv;

+ /* Ignore entries with set flags */
+ if (fdb_flags)
+ return 0;
+
if (!vid) {
switch (db.type) {
case DSA_DB_PORT:
@@ -1824,10 +1828,14 @@ static int sja1105_fdb_add(struct dsa_switch *ds, int port,

static int sja1105_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
struct sja1105_private *priv = ds->priv;

+ /* Ignore entries with set flags */
+ if (fdb_flags)
+ return 0;
+
if (!vid) {
switch (db.type) {
case DSA_DB_PORT:
@@ -1930,7 +1938,8 @@ static void sja1105_fast_age(struct dsa_switch *ds, int port)

u64_to_ether_addr(l2_lookup.macaddr, macaddr);

- rc = sja1105_fdb_del(ds, port, macaddr, l2_lookup.vlanid, db);
+ rc = sja1105_fdb_del(ds, port, macaddr, l2_lookup.vlanid,
+ 0, db);
if (rc) {
dev_err(ds->dev,
"Failed to delete FDB entry %pM vid %lld: %pe\n",
@@ -1944,14 +1953,14 @@ static int sja1105_mdb_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db)
{
- return sja1105_fdb_add(ds, port, mdb->addr, mdb->vid, db);
+ return sja1105_fdb_add(ds, port, mdb->addr, mdb->vid, 0, db);
}

static int sja1105_mdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db)
{
- return sja1105_fdb_del(ds, port, mdb->addr, mdb->vid, db);
+ return sja1105_fdb_del(ds, port, mdb->addr, mdb->vid, 0, db);
}

/* Common function for unicast and broadcast flood configuration.
diff --git a/include/net/dsa.h b/include/net/dsa.h
index ff95bf1cdd14..4971e67d6481 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -1047,10 +1047,10 @@ struct dsa_switch_ops {
*/
int (*port_fdb_add)(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db);
+ u16 fdb_flags, struct dsa_db db);
int (*port_fdb_del)(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
- struct dsa_db db);
+ u16 fdb_flags, struct dsa_db db);
int (*port_fdb_dump)(struct dsa_switch *ds, int port,
dsa_fdb_dump_cb_t *cb, void *data);
int (*lag_fdb_add)(struct dsa_switch *ds, struct dsa_lag lag,
diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index 9b0d6ce0f7da..397665962451 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -248,7 +248,8 @@ static int dsa_port_do_fdb_add(struct dsa_port *dp, const unsigned char *addr,

/* No need to bother with refcounting for user ports */
if (!(dsa_port_is_cpu(dp) || dsa_port_is_dsa(dp)))
- return ds->ops->port_fdb_add(ds, port, addr, vid, db);
+ return ds->ops->port_fdb_add(ds, port, addr,
+ vid, fdb_flags, db);

mutex_lock(&dp->addr_lists_lock);

@@ -264,7 +265,8 @@ static int dsa_port_do_fdb_add(struct dsa_port *dp, const unsigned char *addr,
goto out;
}

- err = ds->ops->port_fdb_add(ds, port, addr, vid, db);
+ err = ds->ops->port_fdb_add(ds, port, addr,
+ vid, fdb_flags, db);
if (err) {
kfree(a);
goto out;
@@ -292,7 +294,8 @@ static int dsa_port_do_fdb_del(struct dsa_port *dp, const unsigned char *addr,

/* No need to bother with refcounting for user ports */
if (!(dsa_port_is_cpu(dp) || dsa_port_is_dsa(dp)))
- return ds->ops->port_fdb_del(ds, port, addr, vid, db);
+ return ds->ops->port_fdb_del(ds, port, addr,
+ vid, fdb_flags, db);

mutex_lock(&dp->addr_lists_lock);

@@ -305,7 +308,8 @@ static int dsa_port_do_fdb_del(struct dsa_port *dp, const unsigned char *addr,
if (!refcount_dec_and_test(&a->refcount))
goto out;

- err = ds->ops->port_fdb_del(ds, port, addr, vid, db);
+ err = ds->ops->port_fdb_del(ds, port, addr,
+ vid, fdb_flags, db);
if (err) {
refcount_set(&a->refcount, 1);
goto out;
--
2.34.1


2023-01-31 18:54:57

by Simon Horman

[permalink] [raw]
Subject: Re: [PATCH net-next 3/5] drivers: net: dsa: add fdb entry flags incoming to switchcore drivers

On Mon, Jan 30, 2023 at 06:34:27PM +0100, Hans J. Schultz wrote:
> Ignore FDB entries with set flags coming in on all switchcore drivers.
>
> Signed-off-by: Hans J. Schultz <[email protected]>
> ---
> drivers/net/dsa/b53/b53_common.c | 12 ++++++++++--
> drivers/net/dsa/b53/b53_priv.h | 4 ++--
> drivers/net/dsa/hirschmann/hellcreek.c | 12 ++++++++++--
> drivers/net/dsa/lan9303-core.c | 12 ++++++++++--
> drivers/net/dsa/lantiq_gswip.c | 12 ++++++++++--
> drivers/net/dsa/microchip/ksz9477.c | 8 ++++----
> drivers/net/dsa/microchip/ksz9477.h | 8 ++++----
> drivers/net/dsa/microchip/ksz_common.c | 14 +++++++++++---
> drivers/net/dsa/mt7530.c | 12 ++++++++++--
> drivers/net/dsa/mv88e6xxx/chip.c | 12 ++++++++++--
> drivers/net/dsa/ocelot/felix.c | 12 ++++++++++--
> drivers/net/dsa/qca/qca8k-common.c | 12 ++++++++++--
> drivers/net/dsa/qca/qca8k.h | 4 ++--
> drivers/net/dsa/rzn1_a5psw.c | 12 ++++++++++--
> drivers/net/dsa/sja1105/sja1105_main.c | 19 ++++++++++++++-----
> include/net/dsa.h | 4 ++--
> net/dsa/switch.c | 12 ++++++++----
> 17 files changed, 137 insertions(+), 44 deletions(-)
>
> diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
> index 59cdfc51ce06..cec60af6dfdc 100644
> --- a/drivers/net/dsa/b53/b53_common.c
> +++ b/drivers/net/dsa/b53/b53_common.c
> @@ -1684,11 +1684,15 @@ static int b53_arl_op(struct b53_device *dev, int op, int port,
>
> int b53_fdb_add(struct dsa_switch *ds, int port,
> const unsigned char *addr, u16 vid,
> - struct dsa_db db)
> + u16 fdb_flags, struct dsa_db db)
> {
> struct b53_device *priv = ds->priv;
> int ret;
>
> + /* Ignore entries with set flags */
> + if (fdb_flags)
> + return 0;


Would returning -EOPNOTSUPP be more appropriate?

...

2023-01-31 18:56:54

by Simon Horman

[permalink] [raw]
Subject: Re: [PATCH net-next 5/5] net: dsa: mv88e6xxx: implementation of dynamic ATU entries

On Mon, Jan 30, 2023 at 06:34:29PM +0100, Hans J. Schultz wrote:
> For 802.1X or MAB security authed hosts we want to have these hosts authed
> by adding dynamic FDB entries, so that if an authed host goes silent for
> a time period it's FDB entry will be removed and it must reauth when
> wanting to communicate again.
> In the mv88e6xxx offloaded case, we can use the HoldAt1 feature, that
> gives an age out interrupt when the FDB entry is about to age out, so
> that userspace can be notified of the entry being deleted with the help
> of an SWITCHDEV_FDB_DEL_TO_BRIDGE event.
> When adding a dynamic entry the bridge must be informed that the driver
> takes care of the ageing be sending an SWITCHDEV_FDB_OFFLOADED event,
> telling the bridge that this added FDB entry will be handled by the
> driver.
> With this implementation, trace events for age out interrupts are also
> added.
>
> note: A special case arises with the age out interrupt, as the entry
> state/spid (source port id) value read from the registers will be zero.
> Thus we need to extract the source port from the port vector instead.
>
> Signed-off-by: Hans J. Schultz <[email protected]>
> ---
> drivers/net/dsa/mv88e6xxx/chip.c | 18 ++++++--
> drivers/net/dsa/mv88e6xxx/global1_atu.c | 21 +++++++++
> drivers/net/dsa/mv88e6xxx/port.c | 6 ++-
> drivers/net/dsa/mv88e6xxx/switchdev.c | 61 +++++++++++++++++++++++++
> drivers/net/dsa/mv88e6xxx/switchdev.h | 5 ++
> drivers/net/dsa/mv88e6xxx/trace.h | 5 ++
> 6 files changed, 110 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
> index 61d5dc4680e3..a0007d96b2a3 100644
> --- a/drivers/net/dsa/mv88e6xxx/chip.c
> +++ b/drivers/net/dsa/mv88e6xxx/chip.c
> @@ -42,6 +42,7 @@
> #include "ptp.h"
> #include "serdes.h"
> #include "smi.h"
> +#include "switchdev.h"
>
> static void assert_reg_lock(struct mv88e6xxx_chip *chip)
> {
> @@ -2726,18 +2727,25 @@ static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
> const unsigned char *addr, u16 vid,
> u16 fdb_flags, struct dsa_db db)
> {
> + bool is_dynamic = !!(fdb_flags & DSA_FDB_FLAG_DYNAMIC);
> struct mv88e6xxx_chip *chip = ds->priv;
> + u8 state;
> int err;
>
> - /* Ignore entries with flags set */
> - if (fdb_flags)
> - return 0;
> + state = MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC;
> + if (is_dynamic)
> + state = MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_7_NEWEST;

What if flags other than DSA_FDB_FLAG_DYNAMIC are set (in future)?

> + else
> + if (fdb_flags)

nit: else if (fdb_flags)

> + return 0;
>

...

2023-01-31 19:25:41

by Ido Schimmel

[permalink] [raw]
Subject: Re: [PATCH net-next 0/5] ATU and FDB synchronization on locked ports

On Mon, Jan 30, 2023 at 06:34:24PM +0100, Hans J. Schultz wrote:
> This patch set makes it possible to have synchronized dynamic ATU and FDB
> entries on locked ports. As locked ports are not able to automatically
> learn, they depend on userspace added entries, where userspace can add
> static or dynamic entries. The lifetime of static entries are completely
> dependent on userspace intervention, and thus not of interest here. We
> are only concerned with dynamic entries, which can be added with a
> command like:
>
> bridge fdb replace ADDR dev <DEV> master dynamic
>
> We choose only to support this feature on locked ports, as it involves
> utilizing the CPU to handle ATU related switchcore events (typically
> interrupts) and thus can result in significant performance loss if
> exposed to heavy traffic.

Not sure I understand this reasoning. I was under the impression that
hostapd is installing dynamic entries instead of static ones since the
latter are not flushed when carrier is lost. Therefore, with static
entries it is possible to unplug a host (potentially plugging a
different one) and not lose authentication.

>
> On locked ports it is important for userspace to know when an authorized
> station has become silent, hence not breaking the communication of a
> station that has been authorized based on the MAC-Authentication Bypass
> (MAB) scheme. Thus if the station keeps being active after authorization,
> it will continue to have an open port as long as it is active. Only after
> a silent period will it have to be reauthorized. As the ageing process in
> the ATU is dependent on incoming traffic to the switchcore port, it is
> necessary for the ATU to signal that an entry has aged out, so that the
> FDB can be updated at the correct time.

Why mention MAB at all? Don't you want user space to always use dynamic
entries to authenticate hosts regardless of 802.1X/MAB?

>
> This patch set includes a solution for the Marvell mv88e6xxx driver, where
> for this driver we use the Hold-At-One feature so that an age-out
> violation interrupt occurs when a station has been silent for the
> system-set age time. The age out violation interrupt allows the switchcore
> driver to remove both the ATU and the FDB entry at the same time.
>
> It is up to the maintainers of other switchcore drivers to implement the
> feature for their specific driver.
>
> Hans J. Schultz (5):
> net: bridge: add dynamic flag to switchdev notifier
> net: dsa: propagate flags down towards drivers
> drivers: net: dsa: add fdb entry flags incoming to switchcore drivers
> net: bridge: ensure FDB offloaded flag is handled as needed
> net: dsa: mv88e6xxx: implementation of dynamic ATU entries

Will try to review tomorrow, but it looks like this set is missing
selftests. What about extending bridge_locked_port.sh?

2023-02-02 07:37:15

by Hans Schultz

[permalink] [raw]
Subject: Re: [PATCH net-next 0/5] ATU and FDB synchronization on locked ports

On 2023-01-31 20:25, Ido Schimmel wrote:
>
> Will try to review tomorrow, but it looks like this set is missing
> selftests. What about extending bridge_locked_port.sh?

I knew you would take this up. :-)
But I am not sure that it's so easy to have selftests here as it is
timing based and it would take the 5+ minutes just waiting to test in
the stadard case, and there is opnly support for mv88e6xxx driver with
this patch set.

2023-02-02 15:51:26

by Ido Schimmel

[permalink] [raw]
Subject: Re: [PATCH net-next 0/5] ATU and FDB synchronization on locked ports

On Thu, Feb 02, 2023 at 08:37:08AM +0100, [email protected] wrote:
> On 2023-01-31 20:25, Ido Schimmel wrote:
> >
> > Will try to review tomorrow, but it looks like this set is missing
> > selftests. What about extending bridge_locked_port.sh?
>
> I knew you would take this up. :-)
> But I am not sure that it's so easy to have selftests here as it is timing
> based and it would take the 5+ minutes just waiting to test in the stadard
> case, and there is opnly support for mv88e6xxx driver with this patch set.

The ageing time is configurable: See commit 081197591769 ("selftests:
net: bridge: Parameterize ageing timeout"). Please add test cases in the
next version.

2023-02-02 16:19:38

by Hans Schultz

[permalink] [raw]
Subject: Re: [PATCH net-next 0/5] ATU and FDB synchronization on locked ports

On 2023-02-02 16:43, Ido Schimmel wrote:
> On Thu, Feb 02, 2023 at 08:37:08AM +0100, [email protected]
> wrote:
>> On 2023-01-31 20:25, Ido Schimmel wrote:
>> >
>> > Will try to review tomorrow, but it looks like this set is missing
>> > selftests. What about extending bridge_locked_port.sh?
>>
>> I knew you would take this up. :-)
>> But I am not sure that it's so easy to have selftests here as it is
>> timing
>> based and it would take the 5+ minutes just waiting to test in the
>> stadard
>> case, and there is opnly support for mv88e6xxx driver with this patch
>> set.
>
> The ageing time is configurable: See commit 081197591769 ("selftests:
> net: bridge: Parameterize ageing timeout"). Please add test cases in
> the
> next version.

When I was looking at configuring the ageing time last time, my finding
was that the ageing time could not be set very low as there was some
part in the DSA layer etc, and confusion wrt units. I think the minimum
secured was like around 2 min. (not validated), which is not that much
of an improvement for fast testing. If you know what would be a good low
timeout to set, I would like to know.

2023-02-02 16:36:29

by Ido Schimmel

[permalink] [raw]
Subject: Re: [PATCH net-next 0/5] ATU and FDB synchronization on locked ports

On Thu, Feb 02, 2023 at 05:19:07PM +0100, [email protected] wrote:
> On 2023-02-02 16:43, Ido Schimmel wrote:
> > On Thu, Feb 02, 2023 at 08:37:08AM +0100, [email protected]
> > wrote:
> > > On 2023-01-31 20:25, Ido Schimmel wrote:
> > > >
> > > > Will try to review tomorrow, but it looks like this set is missing
> > > > selftests. What about extending bridge_locked_port.sh?
> > >
> > > I knew you would take this up. :-)
> > > But I am not sure that it's so easy to have selftests here as it is
> > > timing
> > > based and it would take the 5+ minutes just waiting to test in the
> > > stadard
> > > case, and there is opnly support for mv88e6xxx driver with this
> > > patch set.
> >
> > The ageing time is configurable: See commit 081197591769 ("selftests:
> > net: bridge: Parameterize ageing timeout"). Please add test cases in the
> > next version.
>
> When I was looking at configuring the ageing time last time, my finding was
> that the ageing time could not be set very low as there was some part in the
> DSA layer etc, and confusion wrt units. I think the minimum secured was like
> around 2 min. (not validated), which is not that much of an improvement for
> fast testing. If you know what would be a good low timeout to set, I would
> like to know.

My point is that the ageing time is parametrized via 'LOW_AGEING_TIME'
in forwarding.config so just use '$LOW_AGEING_TIME' in the selftest and
set it as high as it needs to be for mv88e6xxx in your own
forwarding.config.

2023-02-02 16:46:03

by Hans Schultz

[permalink] [raw]
Subject: Re: [PATCH net-next 3/5] drivers: net: dsa: add fdb entry flags incoming to switchcore drivers

On 2023-01-31 19:54, Simon Horman wrote:
>> --- a/drivers/net/dsa/b53/b53_common.c
>> +++ b/drivers/net/dsa/b53/b53_common.c
>> @@ -1684,11 +1684,15 @@ static int b53_arl_op(struct b53_device *dev,
>> int op, int port,
>>
>> int b53_fdb_add(struct dsa_switch *ds, int port,
>> const unsigned char *addr, u16 vid,
>> - struct dsa_db db)
>> + u16 fdb_flags, struct dsa_db db)
>> {
>> struct b53_device *priv = ds->priv;
>> int ret;
>>
>> + /* Ignore entries with set flags */
>> + if (fdb_flags)
>> + return 0;
>
>
> Would returning -EOPNOTSUPP be more appropriate?
>
> ...

I don't think that would be so good, as the command

bridge fdb replace ADDR dev <DEV> master dynamic

is a valid command and should not generate errors. When ignored by the
driver, it will just install a dynamic FDB entry in the bridge, and the
bridge will age it.

2023-02-02 17:00:48

by Hans Schultz

[permalink] [raw]
Subject: Re: [PATCH net-next 5/5] net: dsa: mv88e6xxx: implementation of dynamic ATU entries

On 2023-01-31 19:56, Simon Horman wrote:
>> --- a/drivers/net/dsa/mv88e6xxx/chip.c
>> +++ b/drivers/net/dsa/mv88e6xxx/chip.c
>> @@ -42,6 +42,7 @@
>> #include "ptp.h"
>> #include "serdes.h"
>> #include "smi.h"
>> +#include "switchdev.h"
>>
>> static void assert_reg_lock(struct mv88e6xxx_chip *chip)
>> {
>> @@ -2726,18 +2727,25 @@ static int mv88e6xxx_port_fdb_add(struct
>> dsa_switch *ds, int port,
>> const unsigned char *addr, u16 vid,
>> u16 fdb_flags, struct dsa_db db)
>> {
>> + bool is_dynamic = !!(fdb_flags & DSA_FDB_FLAG_DYNAMIC);
>> struct mv88e6xxx_chip *chip = ds->priv;
>> + u8 state;
>> int err;
>>
>> - /* Ignore entries with flags set */
>> - if (fdb_flags)
>> - return 0;
>> + state = MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC;
>> + if (is_dynamic)
>> + state = MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_7_NEWEST;
>
> What if flags other than DSA_FDB_FLAG_DYNAMIC are set (in future)?

They will have to be caught and handled here if there is support for it,
e.g. something like...

else if (someflag)
dosomething();

For now only one flag will actually be set and they are mutually
exclusive, as they will not make sense together with the potential flags
I know, but that can change at some time of course.

>
>> + else
>> + if (fdb_flags)
>
> nit: else if (fdb_flags)
>
>> + return 0;
>>
>
> ...

2023-02-02 17:18:21

by Hans Schultz

[permalink] [raw]
Subject: Re: [PATCH net-next 0/5] ATU and FDB synchronization on locked ports

On 2023-01-31 20:25, Ido Schimmel wrote:
>> command like:
>>
>> bridge fdb replace ADDR dev <DEV> master dynamic
>>
>> We choose only to support this feature on locked ports, as it involves
>> utilizing the CPU to handle ATU related switchcore events (typically
>> interrupts) and thus can result in significant performance loss if
>> exposed to heavy traffic.
>
> Not sure I understand this reasoning. I was under the impression that
> hostapd is installing dynamic entries instead of static ones since the
> latter are not flushed when carrier is lost. Therefore, with static
> entries it is possible to unplug a host (potentially plugging a
> different one) and not lose authentication.
>

Both auth schemes 802.1X and MAB install dynamic entries as you point
out, and both use locked ports.
In the case of non locked ports, they just learn normally and age and
refresh their entries, so the use case of a userspace added dynamic FDB
entry is hard for me to see. And having userspace being notified of an
ordinary event that a FDB entry has been aged out could maybe be used,
but for the reasons mentioned it is not supported here.

>>
>> On locked ports it is important for userspace to know when an
>> authorized
>> station has become silent, hence not breaking the communication of a
>> station that has been authorized based on the MAC-Authentication
>> Bypass
>> (MAB) scheme. Thus if the station keeps being active after
>> authorization,
>> it will continue to have an open port as long as it is active. Only
>> after
>> a silent period will it have to be reauthorized. As the ageing process
>> in
>> the ATU is dependent on incoming traffic to the switchcore port, it is
>> necessary for the ATU to signal that an entry has aged out, so that
>> the
>> FDB can be updated at the correct time.
>
> Why mention MAB at all? Don't you want user space to always use dynamic
> entries to authenticate hosts regardless of 802.1X/MAB?

Yes, you are right about that. I guess it came about as this was
developed much in the same time and with the code of MAB.

2023-02-03 08:17:30

by Simon Horman

[permalink] [raw]
Subject: Re: [PATCH net-next 3/5] drivers: net: dsa: add fdb entry flags incoming to switchcore drivers

On Thu, Feb 02, 2023 at 05:45:56PM +0100, [email protected] wrote:
> On 2023-01-31 19:54, Simon Horman wrote:
> > > --- a/drivers/net/dsa/b53/b53_common.c
> > > +++ b/drivers/net/dsa/b53/b53_common.c
> > > @@ -1684,11 +1684,15 @@ static int b53_arl_op(struct b53_device
> > > *dev, int op, int port,
> > >
> > > int b53_fdb_add(struct dsa_switch *ds, int port,
> > > const unsigned char *addr, u16 vid,
> > > - struct dsa_db db)
> > > + u16 fdb_flags, struct dsa_db db)
> > > {
> > > struct b53_device *priv = ds->priv;
> > > int ret;
> > >
> > > + /* Ignore entries with set flags */
> > > + if (fdb_flags)
> > > + return 0;
> >
> >
> > Would returning -EOPNOTSUPP be more appropriate?
> >
> > ...
>
> I don't think that would be so good, as the command
>
> bridge fdb replace ADDR dev <DEV> master dynamic
>
> is a valid command and should not generate errors. When ignored by the
> driver, it will just install a dynamic FDB entry in the bridge, and the
> bridge will age it.

Sure, I agree that it's not necessarily an error that needs
to propagate to the user.

My assumption, which I now see is likely false, is that drivers
could return -EOPNOTSUPP, to indicate to higher layers that the operation
is not supported. But the higher layers may not propagate that.

But it seems that is not the case here. So I think return 0 is fine
after all. Sorry for the noise.

2023-02-03 08:22:47

by Simon Horman

[permalink] [raw]
Subject: Re: [PATCH net-next 5/5] net: dsa: mv88e6xxx: implementation of dynamic ATU entries

On Thu, Feb 02, 2023 at 06:00:00PM +0100, [email protected] wrote:
> On 2023-01-31 19:56, Simon Horman wrote:
> > > --- a/drivers/net/dsa/mv88e6xxx/chip.c
> > > +++ b/drivers/net/dsa/mv88e6xxx/chip.c
> > > @@ -42,6 +42,7 @@
> > > #include "ptp.h"
> > > #include "serdes.h"
> > > #include "smi.h"
> > > +#include "switchdev.h"
> > >
> > > static void assert_reg_lock(struct mv88e6xxx_chip *chip)
> > > {
> > > @@ -2726,18 +2727,25 @@ static int mv88e6xxx_port_fdb_add(struct
> > > dsa_switch *ds, int port,
> > > const unsigned char *addr, u16 vid,
> > > u16 fdb_flags, struct dsa_db db)
> > > {
> > > + bool is_dynamic = !!(fdb_flags & DSA_FDB_FLAG_DYNAMIC);
> > > struct mv88e6xxx_chip *chip = ds->priv;
> > > + u8 state;
> > > int err;
> > >
> > > - /* Ignore entries with flags set */
> > > - if (fdb_flags)
> > > - return 0;
> > > + state = MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC;
> > > + if (is_dynamic)
> > > + state = MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_7_NEWEST;
> >
> > What if flags other than DSA_FDB_FLAG_DYNAMIC are set (in future)?
>
> They will have to be caught and handled here if there is support for it,
> e.g. something like...
>
> else if (someflag)
> dosomething();
>
> For now only one flag will actually be set and they are mutually exclusive,
> as they will not make sense together with the potential flags I know, but
> that can change at some time of course.

Yes, I see that is workable. I do feel that checking for other flags would
be a bit more robust. But as you say, there are none. So whichever
approach you prefer is fine by me.

> >
> > > + else
> > > + if (fdb_flags)
> >
> > nit: else if (fdb_flags)
> >
> > > + return 0;
> > >
> >
> > ...

2023-02-03 18:41:27

by Hans Schultz

[permalink] [raw]
Subject: Re: [PATCH net-next 3/5] drivers: net: dsa: add fdb entry flags incoming to switchcore drivers

On 2023-02-03 09:17, Simon Horman wrote:
> On Thu, Feb 02, 2023 at 05:45:56PM +0100, [email protected]
> wrote:
>> On 2023-01-31 19:54, Simon Horman wrote:
>> > > --- a/drivers/net/dsa/b53/b53_common.c
>> > > +++ b/drivers/net/dsa/b53/b53_common.c
>> > > @@ -1684,11 +1684,15 @@ static int b53_arl_op(struct b53_device
>> > > *dev, int op, int port,
>> > >
>> > > int b53_fdb_add(struct dsa_switch *ds, int port,
>> > > const unsigned char *addr, u16 vid,
>> > > - struct dsa_db db)
>> > > + u16 fdb_flags, struct dsa_db db)
>> > > {
>> > > struct b53_device *priv = ds->priv;
>> > > int ret;
>> > >
>> > > + /* Ignore entries with set flags */
>> > > + if (fdb_flags)
>> > > + return 0;
>> >
>> >
>> > Would returning -EOPNOTSUPP be more appropriate?
>> >
>> > ...
>>
>> I don't think that would be so good, as the command
>>
>> bridge fdb replace ADDR dev <DEV> master dynamic
>>
>> is a valid command and should not generate errors. When ignored by the
>> driver, it will just install a dynamic FDB entry in the bridge, and
>> the
>> bridge will age it.
>
> Sure, I agree that it's not necessarily an error that needs
> to propagate to the user.
>
> My assumption, which I now see is likely false, is that drivers
> could return -EOPNOTSUPP, to indicate to higher layers that the
> operation
> is not supported. But the higher layers may not propagate that.
>
> But it seems that is not the case here. So I think return 0 is fine
> after all. Sorry for the noise.

No noise at all... I think your concern is quite ligitimate. With this
flag there is no iproute2 changes, so not to change behaviour of old
commands the best is to ignore silently. But I have another flag coming
up that will be accomodated with a new iproute2 command, and then your
suggestion is more appropriate. The question will then be if the returns
for that flag should be -EOPNOTSUPP.

2023-02-03 20:44:33

by Vladimir Oltean

[permalink] [raw]
Subject: Re: [PATCH net-next 5/5] net: dsa: mv88e6xxx: implementation of dynamic ATU entries

On Fri, Feb 03, 2023 at 09:20:22AM +0100, Simon Horman wrote:
> > else if (someflag)
> > dosomething();
> >
> > For now only one flag will actually be set and they are mutually exclusive,
> > as they will not make sense together with the potential flags I know, but
> > that can change at some time of course.
>
> Yes, I see that is workable. I do feel that checking for other flags would
> be a bit more robust. But as you say, there are none. So whichever
> approach you prefer is fine by me.

The model we have for unsupported bits in the SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS
and SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS handlers is essentially this:

if (flags & ~(supported_flag_mask))
return -EOPNOTSUPP;

if (flags & supported_flag_1)
...

if (flags & supported_flag_2)
...

I suppose applying this model here would address Simon's extensibility concern.

2023-02-03 21:15:04

by Vladimir Oltean

[permalink] [raw]
Subject: Re: [PATCH net-next 0/5] ATU and FDB synchronization on locked ports

On Thu, Feb 02, 2023 at 06:36:14PM +0200, Ido Schimmel wrote:
> On Thu, Feb 02, 2023 at 05:19:07PM +0100, [email protected] wrote:
> > On 2023-02-02 16:43, Ido Schimmel wrote:
> > > On Thu, Feb 02, 2023 at 08:37:08AM +0100, [email protected] wrote:
> > > > On 2023-01-31 20:25, Ido Schimmel wrote:
> > > > >
> > > > > Will try to review tomorrow, but it looks like this set is missing
> > > > > selftests. What about extending bridge_locked_port.sh?
> > > >
> > > > I knew you would take this up. :-)
> > > > But I am not sure that it's so easy to have selftests here as it is timing
> > > > based and it would take the 5+ minutes just waiting to test in the stadard
> > > > case, and there is opnly support for mv88e6xxx driver with this
> > > > patch set.
> > >
> > > The ageing time is configurable: See commit 081197591769 ("selftests:
> > > net: bridge: Parameterize ageing timeout"). Please add test cases in the
> > > next version.
> >
> > When I was looking at configuring the ageing time last time, my finding was
> > that the ageing time could not be set very low as there was some part in the
> > DSA layer etc, and confusion wrt units. I think the minimum secured was like
> > around 2 min. (not validated), which is not that much of an improvement for
> > fast testing. If you know what would be a good low timeout to set, I would
> > like to know.
>
> My point is that the ageing time is parametrized via 'LOW_AGEING_TIME'
> in forwarding.config so just use '$LOW_AGEING_TIME' in the selftest and
> set it as high as it needs to be for mv88e6xxx in your own
> forwarding.config.

FWIW, we have a forwarding.config file in tools/testing/selftests/drivers/net/dsa/.
So you could cd to that folder, edit the file with your variable, and run the symlinked
script from there.

> as there was some part in the DSA layer etc

if (ds->ageing_time_min && ageing_time < ds->ageing_time_min)
return -ERANGE;

High tech, advanced software.....

You could print the ds->ageing_time_min variable. For mv88e6xxx, my 6390
and 6190 report 3750. I have to admit the ageing time units are confusing,
but Tobias Waldekranz kindly explained in one of those commit messages
that Ido linked to that these represent "centiseconds" (or 37.5 seconds).
And I think we discussed the units with you before. And in general, it's
not hard to find the answer if you search for it, I know I could find it.

Please stop trying to find silly excuses to always go through the path
of minimal resistance.

2023-02-04 08:13:13

by Simon Horman

[permalink] [raw]
Subject: Re: [PATCH net-next 5/5] net: dsa: mv88e6xxx: implementation of dynamic ATU entries

On Fri, Feb 03, 2023 at 10:44:22PM +0200, Vladimir Oltean wrote:
> On Fri, Feb 03, 2023 at 09:20:22AM +0100, Simon Horman wrote:
> > > else if (someflag)
> > > dosomething();
> > >
> > > For now only one flag will actually be set and they are mutually exclusive,
> > > as they will not make sense together with the potential flags I know, but
> > > that can change at some time of course.
> >
> > Yes, I see that is workable. I do feel that checking for other flags would
> > be a bit more robust. But as you say, there are none. So whichever
> > approach you prefer is fine by me.
>
> The model we have for unsupported bits in the SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS
> and SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS handlers is essentially this:
>
> if (flags & ~(supported_flag_mask))
> return -EOPNOTSUPP;
>
> if (flags & supported_flag_1)
> ...
>
> if (flags & supported_flag_2)
> ...
>
> I suppose applying this model here would address Simon's extensibility concern.

Yes, that is the model I had in mind.

2023-02-04 08:48:35

by Hans Schultz

[permalink] [raw]
Subject: Re: [PATCH net-next 5/5] net: dsa: mv88e6xxx: implementation of dynamic ATU entries

On 2023-02-04 09:12, Simon Horman wrote:
> On Fri, Feb 03, 2023 at 10:44:22PM +0200, Vladimir Oltean wrote:
>> On Fri, Feb 03, 2023 at 09:20:22AM +0100, Simon Horman wrote:
>> > > else if (someflag)
>> > > dosomething();
>> > >
>> > > For now only one flag will actually be set and they are mutually exclusive,
>> > > as they will not make sense together with the potential flags I know, but
>> > > that can change at some time of course.
>> >
>> > Yes, I see that is workable. I do feel that checking for other flags would
>> > be a bit more robust. But as you say, there are none. So whichever
>> > approach you prefer is fine by me.
>>
>> The model we have for unsupported bits in the
>> SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS
>> and SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS handlers is essentially this:
>>
>> if (flags & ~(supported_flag_mask))
>> return -EOPNOTSUPP;
>>
>> if (flags & supported_flag_1)
>> ...
>>
>> if (flags & supported_flag_2)
>> ...
>>
>> I suppose applying this model here would address Simon's extensibility
>> concern.
>
> Yes, that is the model I had in mind.

The only thing is that we actually need to return both 0 and -EOPNOTSUPP
for unsupported flags. The dynamic flag requires 0 when not supported
(and supported) AFAICS.
Setting a mask as 'supported' for a feature that is not really supported
defeats the notion of 'supported' IMHO.

2023-02-06 16:02:49

by Simon Horman

[permalink] [raw]
Subject: Re: [PATCH net-next 5/5] net: dsa: mv88e6xxx: implementation of dynamic ATU entries

On Sat, Feb 04, 2023 at 09:48:24AM +0100, [email protected] wrote:
> On 2023-02-04 09:12, Simon Horman wrote:
> > On Fri, Feb 03, 2023 at 10:44:22PM +0200, Vladimir Oltean wrote:
> > > On Fri, Feb 03, 2023 at 09:20:22AM +0100, Simon Horman wrote:
> > > > > else if (someflag)
> > > > > dosomething();
> > > > >
> > > > > For now only one flag will actually be set and they are mutually exclusive,
> > > > > as they will not make sense together with the potential flags I know, but
> > > > > that can change at some time of course.
> > > >
> > > > Yes, I see that is workable. I do feel that checking for other flags would
> > > > be a bit more robust. But as you say, there are none. So whichever
> > > > approach you prefer is fine by me.
> > >
> > > The model we have for unsupported bits in the
> > > SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS
> > > and SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS handlers is essentially this:
> > >
> > > if (flags & ~(supported_flag_mask))
> > > return -EOPNOTSUPP;
> > >
> > > if (flags & supported_flag_1)
> > > ...
> > >
> > > if (flags & supported_flag_2)
> > > ...
> > >
> > > I suppose applying this model here would address Simon's
> > > extensibility concern.
> >
> > Yes, that is the model I had in mind.
>
> The only thing is that we actually need to return both 0 and -EOPNOTSUPP for
> unsupported flags. The dynamic flag requires 0 when not supported (and
> supported) AFAICS.
> Setting a mask as 'supported' for a feature that is not really supported
> defeats the notion of 'supported' IMHO.

Just to clarify my suggestion one last time, it would be along the lines
of the following (completely untested!). I feel that it robustly covers
all cases for fdb_flags. And as a bonus doesn't need to be modified
if other (unsupported) flags are added in future.

if (fdb_flags & ~(DSA_FDB_FLAG_DYNAMIC))
return -EOPNOTSUPP;

is_dynamic = !!(fdb_flags & DSA_FDB_FLAG_DYNAMIC)
if (is_dynamic)
state = MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_7_NEWEST;


And perhaps for other drivers:

if (fdb_flags & ~(DSA_FDB_FLAG_DYNAMIC))
return -EOPNOTSUPP;
if (fdb_flags)
return 0;

Perhaps a helper would be warranted for the above.

But in writing this I think that, perhaps drivers could return -EOPNOTSUPP
for the DSA_FDB_FLAG_DYNAMIC case and the caller can handle, rather tha
propagate, -EOPNOTSUPP.

Returning -EOPNOTSUPP is the normal way to drivers to respond to requests
for unsupported hardware offloads. Sticking to that may be clearner
in the long run. That said, I do agree your current patch is correct
given the flag that is defined (by your patchset).

2023-02-14 21:54:20

by Hans Schultz

[permalink] [raw]
Subject: Re: [PATCH net-next 5/5] net: dsa: mv88e6xxx: implementation of dynamic ATU entries

On Mon, Feb 06, 2023 at 17:02, Simon Horman <[email protected]> wrote:
>
> Just to clarify my suggestion one last time, it would be along the lines
> of the following (completely untested!). I feel that it robustly covers
> all cases for fdb_flags. And as a bonus doesn't need to be modified
> if other (unsupported) flags are added in future.
>
> if (fdb_flags & ~(DSA_FDB_FLAG_DYNAMIC))
> return -EOPNOTSUPP;
>
> is_dynamic = !!(fdb_flags & DSA_FDB_FLAG_DYNAMIC)
> if (is_dynamic)
> state = MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_7_NEWEST;
>
>
> And perhaps for other drivers:
>
> if (fdb_flags & ~(DSA_FDB_FLAG_DYNAMIC))
> return -EOPNOTSUPP;
> if (fdb_flags)
> return 0;
>
> Perhaps a helper would be warranted for the above.

How would such a helper look? Inline function is not clean.

>
> But in writing this I think that, perhaps drivers could return -EOPNOTSUPP
> for the DSA_FDB_FLAG_DYNAMIC case and the caller can handle, rather tha
> propagate, -EOPNOTSUPP.

I looked at that, but changing the caller is also a bit ugly.

>
> Returning -EOPNOTSUPP is the normal way to drivers to respond to requests
> for unsupported hardware offloads. Sticking to that may be clearner
> in the long run. That said, I do agree your current patch is correct
> given the flag that is defined (by your patchset).

2023-02-17 17:44:40

by Vladimir Oltean

[permalink] [raw]
Subject: Re: [PATCH net-next 5/5] net: dsa: mv88e6xxx: implementation of dynamic ATU entries

On Tue, Feb 14, 2023 at 10:14:55PM +0100, Hans Schultz wrote:
> On Mon, Feb 06, 2023 at 17:02, Simon Horman <[email protected]> wrote:
> >
> > Just to clarify my suggestion one last time, it would be along the lines
> > of the following (completely untested!). I feel that it robustly covers
> > all cases for fdb_flags. And as a bonus doesn't need to be modified
> > if other (unsupported) flags are added in future.
> >
> > if (fdb_flags & ~(DSA_FDB_FLAG_DYNAMIC))
> > return -EOPNOTSUPP;
> >
> > is_dynamic = !!(fdb_flags & DSA_FDB_FLAG_DYNAMIC)
> > if (is_dynamic)
> > state = MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_7_NEWEST;
> >
> >
> > And perhaps for other drivers:
> >
> > if (fdb_flags & ~(DSA_FDB_FLAG_DYNAMIC))
> > return -EOPNOTSUPP;
> > if (fdb_flags)
> > return 0;
> >
> > Perhaps a helper would be warranted for the above.
>
> How would such a helper look? Inline function is not clean.
>
> >
> > But in writing this I think that, perhaps drivers could return -EOPNOTSUPP
> > for the DSA_FDB_FLAG_DYNAMIC case and the caller can handle, rather tha
> > propagate, -EOPNOTSUPP.
>
> I looked at that, but changing the caller is also a bit ugly.

Answering on behalf of Simon, and hoping he will agree.

You are missing a big opportunity to make the kernel avoid doing useless work.
The dsa_slave_fdb_event() function runs in atomic switchdev notifier context,
and schedules a deferred workqueue item - dsa_schedule_work() - to get sleepable
context to program hardware.

Only that scheduling a deferred work item is not exactly cheap, so we try to
avoid doing that unless we know that we'll end up doing something with that
FDB entry once the deferred work does get scheduled:

/* Check early that we're not doing work in vain.
* Host addresses on LAG ports still require regular FDB ops,
* since the CPU port isn't in a LAG.
*/
if (dp->lag && !host_addr) {
if (!ds->ops->lag_fdb_add || !ds->ops->lag_fdb_del)
return -EOPNOTSUPP;
} else {
if (!ds->ops->port_fdb_add || !ds->ops->port_fdb_del)
return -EOPNOTSUPP;
}

What you should be doing is you should be using the pahole tool to find
a good place for a new unsigned long field in struct dsa_switch, and add
a new field ds->supported_fdb_flags. You should extend the early checking
from dsa_slave_fdb_event() and exit without doing anything if the
(fdb->flags & ~ds->supported_fdb_flags) expression is non-zero.

This way you would kill 2 birds with 1 stone, since individual drivers
would no longer need to check the flags; DSA would guarantee not calling
them with unsupported flags.

It would be also very good to reach an agreement with switchdev
maintainers regarding the naming of the is_static/is_dyn field.

It would also be excellent if you could rename "fdb_flags" to just
"flags" within DSA.

2023-02-20 14:12:56

by Simon Horman

[permalink] [raw]
Subject: Re: [PATCH net-next 5/5] net: dsa: mv88e6xxx: implementation of dynamic ATU entries

On Fri, Feb 17, 2023 at 07:44:31PM +0200, Vladimir Oltean wrote:
> On Tue, Feb 14, 2023 at 10:14:55PM +0100, Hans Schultz wrote:
> > On Mon, Feb 06, 2023 at 17:02, Simon Horman <[email protected]> wrote:
> > >
> > > Just to clarify my suggestion one last time, it would be along the lines
> > > of the following (completely untested!). I feel that it robustly covers
> > > all cases for fdb_flags. And as a bonus doesn't need to be modified
> > > if other (unsupported) flags are added in future.
> > >
> > > if (fdb_flags & ~(DSA_FDB_FLAG_DYNAMIC))
> > > return -EOPNOTSUPP;
> > >
> > > is_dynamic = !!(fdb_flags & DSA_FDB_FLAG_DYNAMIC)
> > > if (is_dynamic)
> > > state = MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_7_NEWEST;
> > >
> > >
> > > And perhaps for other drivers:
> > >
> > > if (fdb_flags & ~(DSA_FDB_FLAG_DYNAMIC))
> > > return -EOPNOTSUPP;
> > > if (fdb_flags)
> > > return 0;
> > >
> > > Perhaps a helper would be warranted for the above.
> >
> > How would such a helper look? Inline function is not clean.
> >
> > >
> > > But in writing this I think that, perhaps drivers could return -EOPNOTSUPP
> > > for the DSA_FDB_FLAG_DYNAMIC case and the caller can handle, rather tha
> > > propagate, -EOPNOTSUPP.
> >
> > I looked at that, but changing the caller is also a bit ugly.
>
> Answering on behalf of Simon, and hoping he will agree.

Sorry for not responding earlier - I was on vacation last week.

TBH my idea was not nearly as well developed as the one you describe below.
But yes, I agree this is an interesting approach.

> You are missing a big opportunity to make the kernel avoid doing useless work.
> The dsa_slave_fdb_event() function runs in atomic switchdev notifier context,
> and schedules a deferred workqueue item - dsa_schedule_work() - to get sleepable
> context to program hardware.
>
> Only that scheduling a deferred work item is not exactly cheap, so we try to
> avoid doing that unless we know that we'll end up doing something with that
> FDB entry once the deferred work does get scheduled:
>
> /* Check early that we're not doing work in vain.
> * Host addresses on LAG ports still require regular FDB ops,
> * since the CPU port isn't in a LAG.
> */
> if (dp->lag && !host_addr) {
> if (!ds->ops->lag_fdb_add || !ds->ops->lag_fdb_del)
> return -EOPNOTSUPP;
> } else {
> if (!ds->ops->port_fdb_add || !ds->ops->port_fdb_del)
> return -EOPNOTSUPP;
> }
>
> What you should be doing is you should be using the pahole tool to find
> a good place for a new unsigned long field in struct dsa_switch, and add
> a new field ds->supported_fdb_flags. You should extend the early checking
> from dsa_slave_fdb_event() and exit without doing anything if the
> (fdb->flags & ~ds->supported_fdb_flags) expression is non-zero.
>
> This way you would kill 2 birds with 1 stone, since individual drivers
> would no longer need to check the flags; DSA would guarantee not calling
> them with unsupported flags.
>
> It would be also very good to reach an agreement with switchdev
> maintainers regarding the naming of the is_static/is_dyn field.
>
> It would also be excellent if you could rename "fdb_flags" to just
> "flags" within DSA.