linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net-next 0/3] Extend locked port feature with FDB locked flag (MAC-Auth/MAB)
@ 2022-03-10 14:23 Hans Schultz
  2022-03-10 14:23 ` [PATCH net-next 1/3] net: bridge: add fdb flag to extent locked port feature Hans Schultz
                   ` (4 more replies)
  0 siblings, 5 replies; 63+ messages in thread
From: Hans Schultz @ 2022-03-10 14:23 UTC (permalink / raw)
  To: davem, kuba
  Cc: netdev, Hans Schultz, Andrew Lunn, Vivien Didelot,
	Florian Fainelli, Vladimir Oltean, Jiri Pirko, Ivan Vecera,
	Roopa Prabhu, Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel,
	linux-kernel, bridge

This patch set extends the locked port feature for devices
that are behind a locked port, but do not have the ability to
authorize themselves as a supplicant using IEEE 802.1X.
Such devices can be printers, meters or anything related to
fixed installations. Instead of 802.1X authorization, devices
can get access based on their MAC addresses being whitelisted.

For an authorization daemon to detect that a device is trying
to get access through a locked port, the bridge will add the
MAC address of the device to the FDB with a locked flag to it.
Thus the authorization daemon can catch the FDB add event and
check if the MAC address is in the whitelist and if so replace
the FDB entry without the locked flag enabled, and thus open
the port for the device.

This feature is known as MAC-Auth or MAC Authentication Bypass
(MAB) in Cisco terminology, where the full MAB concept involves
additional Cisco infrastructure for authorization. There is no
real authentication process, as the MAC address of the device
is the only input the authorization daemon, in the general
case, has to base the decision if to unlock the port or not.

With this patch set, an implementation of the offloaded case is
supplied for the mv88e6xxx driver. When a packet ingresses on
a locked port, an ATU miss violation event will occur. When
handling such ATU miss violation interrupts, the MAC address of
the device is added to the FDB with a zero destination port
vector (DPV) and the MAC address is communicated through the
switchdev layer to the bridge, so that a FDB entry with the
locked flag enabled can be added.

Hans Schultz (3):
  net: bridge: add fdb flag to extent locked port feature
  net: switchdev: add support for offloading of fdb locked flag
  net: dsa: mv88e6xxx: mac-auth/MAB implementation

 drivers/net/dsa/mv88e6xxx/Makefile            |  1 +
 drivers/net/dsa/mv88e6xxx/chip.c              | 10 +--
 drivers/net/dsa/mv88e6xxx/chip.h              |  5 ++
 drivers/net/dsa/mv88e6xxx/global1.h           |  1 +
 drivers/net/dsa/mv88e6xxx/global1_atu.c       | 29 +++++++-
 .../net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c   | 67 +++++++++++++++++++
 .../net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h   | 20 ++++++
 drivers/net/dsa/mv88e6xxx/port.c              | 11 +++
 drivers/net/dsa/mv88e6xxx/port.h              |  1 +
 include/net/switchdev.h                       |  3 +-
 include/uapi/linux/neighbour.h                |  1 +
 net/bridge/br.c                               |  3 +-
 net/bridge/br_fdb.c                           | 13 +++-
 net/bridge/br_input.c                         | 11 ++-
 net/bridge/br_private.h                       |  5 +-
 15 files changed, 167 insertions(+), 14 deletions(-)
 create mode 100644 drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c
 create mode 100644 drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h

-- 
2.30.2


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH net-next 1/3] net: bridge: add fdb flag to extent locked port feature
  2022-03-10 14:23 [PATCH net-next 0/3] Extend locked port feature with FDB locked flag (MAC-Auth/MAB) Hans Schultz
@ 2022-03-10 14:23 ` Hans Schultz
  2022-03-10 14:42   ` Nikolay Aleksandrov
  2022-03-14 15:30   ` Ido Schimmel
  2022-03-10 14:23 ` [PATCH net-next 2/3] net: switchdev: add support for offloading of fdb locked flag Hans Schultz
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 63+ messages in thread
From: Hans Schultz @ 2022-03-10 14:23 UTC (permalink / raw)
  To: davem, kuba
  Cc: netdev, Hans Schultz, Andrew Lunn, Vivien Didelot,
	Florian Fainelli, Vladimir Oltean, Jiri Pirko, Ivan Vecera,
	Roopa Prabhu, Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel,
	linux-kernel, bridge

Add an intermediate state for clients behind a locked port to allow for
possible opening of the port for said clients. This feature corresponds
to the Mac-Auth and MAC Authentication Bypass (MAB) named features. The
latter defined by Cisco.

Signed-off-by: Hans Schultz <schultz.hans+netdev@gmail.com>
---
 include/uapi/linux/neighbour.h |  1 +
 net/bridge/br_fdb.c            |  6 ++++++
 net/bridge/br_input.c          | 11 ++++++++++-
 net/bridge/br_private.h        |  3 ++-
 4 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/neighbour.h b/include/uapi/linux/neighbour.h
index db05fb55055e..83115a592d58 100644
--- a/include/uapi/linux/neighbour.h
+++ b/include/uapi/linux/neighbour.h
@@ -208,6 +208,7 @@ enum {
 	NFEA_UNSPEC,
 	NFEA_ACTIVITY_NOTIFY,
 	NFEA_DONT_REFRESH,
+	NFEA_LOCKED,
 	__NFEA_MAX
 };
 #define NFEA_MAX (__NFEA_MAX - 1)
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 6ccda68bd473..396dcf3084cf 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -105,6 +105,7 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
 	struct nda_cacheinfo ci;
 	struct nlmsghdr *nlh;
 	struct ndmsg *ndm;
+	u8 ext_flags = 0;
 
 	nlh = nlmsg_put(skb, portid, seq, type, sizeof(*ndm), flags);
 	if (nlh == NULL)
@@ -125,11 +126,16 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
 		ndm->ndm_flags |= NTF_EXT_LEARNED;
 	if (test_bit(BR_FDB_STICKY, &fdb->flags))
 		ndm->ndm_flags |= NTF_STICKY;
+	if (test_bit(BR_FDB_ENTRY_LOCKED, &fdb->flags))
+		ext_flags |= 1 << NFEA_LOCKED;
 
 	if (nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->key.addr))
 		goto nla_put_failure;
 	if (nla_put_u32(skb, NDA_MASTER, br->dev->ifindex))
 		goto nla_put_failure;
+	if (nla_put_u8(skb, NDA_FDB_EXT_ATTRS, ext_flags))
+		goto nla_put_failure;
+
 	ci.ndm_used	 = jiffies_to_clock_t(now - fdb->used);
 	ci.ndm_confirmed = 0;
 	ci.ndm_updated	 = jiffies_to_clock_t(now - fdb->updated);
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index e0c13fcc50ed..897908484b18 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -75,6 +75,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
 	struct net_bridge_mcast *brmctx;
 	struct net_bridge_vlan *vlan;
 	struct net_bridge *br;
+	unsigned long flags = 0;
 	u16 vid = 0;
 	u8 state;
 
@@ -94,8 +95,16 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
 			br_fdb_find_rcu(br, eth_hdr(skb)->h_source, vid);
 
 		if (!fdb_src || READ_ONCE(fdb_src->dst) != p ||
-		    test_bit(BR_FDB_LOCAL, &fdb_src->flags))
+		    test_bit(BR_FDB_LOCAL, &fdb_src->flags)) {
+			if (!fdb_src) {
+				set_bit(BR_FDB_ENTRY_LOCKED, &flags);
+				br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, flags);
+			}
 			goto drop;
+		} else {
+			if (test_bit(BR_FDB_ENTRY_LOCKED, &fdb_src->flags))
+				goto drop;
+		}
 	}
 
 	nbp_switchdev_frame_mark(p, skb);
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 48bc61ebc211..f5a0b68c4857 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -248,7 +248,8 @@ enum {
 	BR_FDB_ADDED_BY_EXT_LEARN,
 	BR_FDB_OFFLOADED,
 	BR_FDB_NOTIFY,
-	BR_FDB_NOTIFY_INACTIVE
+	BR_FDB_NOTIFY_INACTIVE,
+	BR_FDB_ENTRY_LOCKED,
 };
 
 struct net_bridge_fdb_key {
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH net-next 2/3] net: switchdev: add support for offloading of fdb locked flag
  2022-03-10 14:23 [PATCH net-next 0/3] Extend locked port feature with FDB locked flag (MAC-Auth/MAB) Hans Schultz
  2022-03-10 14:23 ` [PATCH net-next 1/3] net: bridge: add fdb flag to extent locked port feature Hans Schultz
@ 2022-03-10 14:23 ` Hans Schultz
  2022-03-10 14:23 ` [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation Hans Schultz
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 63+ messages in thread
From: Hans Schultz @ 2022-03-10 14:23 UTC (permalink / raw)
  To: davem, kuba
  Cc: netdev, Hans Schultz, Andrew Lunn, Vivien Didelot,
	Florian Fainelli, Vladimir Oltean, Jiri Pirko, Ivan Vecera,
	Roopa Prabhu, Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel,
	linux-kernel, bridge

Used for Mac-auth/MAB feature in the offloaded case.

Signed-off-by: Hans Schultz <schultz.hans+netdev@gmail.com>
---
 include/net/switchdev.h | 3 ++-
 net/bridge/br.c         | 3 ++-
 net/bridge/br_fdb.c     | 7 +++++--
 net/bridge/br_private.h | 2 +-
 4 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/include/net/switchdev.h b/include/net/switchdev.h
index 3e424d40fae3..d5d923411f5e 100644
--- a/include/net/switchdev.h
+++ b/include/net/switchdev.h
@@ -229,7 +229,8 @@ struct switchdev_notifier_fdb_info {
 	u16 vid;
 	u8 added_by_user:1,
 	   is_local:1,
-	   offloaded:1;
+	   offloaded:1,
+	   locked:1;
 };
 
 struct switchdev_notifier_port_obj_info {
diff --git a/net/bridge/br.c b/net/bridge/br.c
index b1dea3febeea..adcdbecbc218 100644
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -166,7 +166,8 @@ static int br_switchdev_event(struct notifier_block *unused,
 	case SWITCHDEV_FDB_ADD_TO_BRIDGE:
 		fdb_info = ptr;
 		err = br_fdb_external_learn_add(br, p, fdb_info->addr,
-						fdb_info->vid, false);
+						fdb_info->vid, false,
+						fdb_info->locked);
 		if (err) {
 			err = notifier_from_errno(err);
 			break;
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 396dcf3084cf..91387aa7e400 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -987,7 +987,7 @@ static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge *br,
 					   "FDB entry towards bridge must be permanent");
 			return -EINVAL;
 		}
-		err = br_fdb_external_learn_add(br, p, addr, vid, true);
+		err = br_fdb_external_learn_add(br, p, addr, vid, true, false);
 	} else {
 		spin_lock_bh(&br->hash_lock);
 		err = fdb_add_entry(br, p, addr, ndm, nlh_flags, vid, nfea_tb);
@@ -1216,7 +1216,7 @@ void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p)
 
 int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
 			      const unsigned char *addr, u16 vid,
-			      bool swdev_notify)
+			      bool swdev_notify, bool locked)
 {
 	struct net_bridge_fdb_entry *fdb;
 	bool modified = false;
@@ -1236,6 +1236,9 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
 		if (!p)
 			flags |= BIT(BR_FDB_LOCAL);
 
+		if (locked)
+			flags |= BIT(BR_FDB_ENTRY_LOCKED);
+
 		fdb = fdb_create(br, p, addr, vid, flags);
 		if (!fdb) {
 			err = -ENOMEM;
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index f5a0b68c4857..3275e33b112f 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -790,7 +790,7 @@ int br_fdb_sync_static(struct net_bridge *br, struct net_bridge_port *p);
 void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p);
 int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
 			      const unsigned char *addr, u16 vid,
-			      bool swdev_notify);
+			      bool swdev_notify, bool locked);
 int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p,
 			      const unsigned char *addr, u16 vid,
 			      bool swdev_notify);
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-10 14:23 [PATCH net-next 0/3] Extend locked port feature with FDB locked flag (MAC-Auth/MAB) Hans Schultz
  2022-03-10 14:23 ` [PATCH net-next 1/3] net: bridge: add fdb flag to extent locked port feature Hans Schultz
  2022-03-10 14:23 ` [PATCH net-next 2/3] net: switchdev: add support for offloading of fdb locked flag Hans Schultz
@ 2022-03-10 14:23 ` Hans Schultz
  2022-03-10 14:28   ` Vladimir Oltean
  2022-03-10 14:54   ` Andrew Lunn
  2022-03-14 15:50 ` [PATCH net-next 0/3] Extend locked port feature with FDB locked flag (MAC-Auth/MAB) Ido Schimmel
  2022-03-17  0:18 ` Florian Fainelli
  4 siblings, 2 replies; 63+ messages in thread
From: Hans Schultz @ 2022-03-10 14:23 UTC (permalink / raw)
  To: davem, kuba
  Cc: netdev, Hans Schultz, Andrew Lunn, Vivien Didelot,
	Florian Fainelli, Vladimir Oltean, Jiri Pirko, Ivan Vecera,
	Roopa Prabhu, Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel,
	linux-kernel, bridge

This implementation for the Marvell mv88e6xxx chip series, is
based on handling ATU miss violations occurring when packets
ingress on a port that is locked. The mac address triggering
the ATU miss violation is communicated through switchdev to
the bridge module, which adds a fdb entry with the fdb locked
flag set.
Note: The locked port must have learning enabled for the ATU
miss violation to occur.

Signed-off-by: Hans Schultz <schultz.hans+netdev@gmail.com>
---
 drivers/net/dsa/mv88e6xxx/Makefile            |  1 +
 drivers/net/dsa/mv88e6xxx/chip.c              | 10 +--
 drivers/net/dsa/mv88e6xxx/chip.h              |  5 ++
 drivers/net/dsa/mv88e6xxx/global1.h           |  1 +
 drivers/net/dsa/mv88e6xxx/global1_atu.c       | 29 +++++++-
 .../net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c   | 67 +++++++++++++++++++
 .../net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h   | 20 ++++++
 drivers/net/dsa/mv88e6xxx/port.c              | 11 +++
 drivers/net/dsa/mv88e6xxx/port.h              |  1 +
 9 files changed, 138 insertions(+), 7 deletions(-)
 create mode 100644 drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c
 create mode 100644 drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h

diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile
index c8eca2b6f959..3ca57709730d 100644
--- a/drivers/net/dsa/mv88e6xxx/Makefile
+++ b/drivers/net/dsa/mv88e6xxx/Makefile
@@ -15,3 +15,4 @@ mv88e6xxx-objs += port_hidden.o
 mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += ptp.o
 mv88e6xxx-objs += serdes.o
 mv88e6xxx-objs += smi.o
+mv88e6xxx-objs += mv88e6xxx_switchdev.o
\ No newline at end of file
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 84b90fc36c58..e1b6bd738085 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1714,11 +1714,11 @@ static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
 	return err;
 }
 
-static int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
-			      int (*cb)(struct mv88e6xxx_chip *chip,
-					const struct mv88e6xxx_vtu_entry *entry,
-					void *priv),
-			      void *priv)
+int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
+		       int (*cb)(struct mv88e6xxx_chip *chip,
+				 const struct mv88e6xxx_vtu_entry *entry,
+				 void *priv),
+		       void *priv)
 {
 	struct mv88e6xxx_vtu_entry entry = {
 		.vid = mv88e6xxx_max_vid(chip),
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 30b92a265613..64e8fc470fdf 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -763,6 +763,11 @@ static inline void mv88e6xxx_reg_unlock(struct mv88e6xxx_chip *chip)
 	mutex_unlock(&chip->reg_lock);
 }
 
+int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
+		       int (*cb)(struct mv88e6xxx_chip *chip,
+				 const struct mv88e6xxx_vtu_entry *entry,
+				 void *priv),
+		       void *priv);
 int mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *bitmap);
 
 #endif /* _MV88E6XXX_CHIP_H */
diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h
index 2c1607c858a1..729cc0610d9a 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.h
+++ b/drivers/net/dsa/mv88e6xxx/global1.h
@@ -136,6 +136,7 @@
 #define MV88E6XXX_G1_ATU_DATA_TRUNK				0x8000
 #define MV88E6XXX_G1_ATU_DATA_TRUNK_ID_MASK			0x00f0
 #define MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_MASK			0x3ff0
+#define MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_NO_EGRESS		0x0000
 #define MV88E6XXX_G1_ATU_DATA_STATE_MASK			0x000f
 #define MV88E6XXX_G1_ATU_DATA_STATE_UC_UNUSED			0x0000
 #define MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_1_OLDEST		0x0001
diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c
index 40bd67a5c8e9..afa54fe8667e 100644
--- a/drivers/net/dsa/mv88e6xxx/global1_atu.c
+++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c
@@ -12,6 +12,8 @@
 
 #include "chip.h"
 #include "global1.h"
+#include "port.h"
+#include "mv88e6xxx_switchdev.h"
 
 /* Offset 0x01: ATU FID Register */
 
@@ -114,6 +116,18 @@ static int mv88e6xxx_g1_atu_op_wait(struct mv88e6xxx_chip *chip)
 	return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_ATU_OP, bit, 0);
 }
 
+static int mv88e6xxx_g1_read_atu_violation(struct mv88e6xxx_chip *chip)
+{
+	int err;
+
+	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_OP,
+				 MV88E6XXX_G1_ATU_OP_BUSY | MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION);
+	if (err)
+		return err;
+
+	return mv88e6xxx_g1_atu_op_wait(chip);
+}
+
 static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op)
 {
 	u16 val;
@@ -356,11 +370,11 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
 	int spid;
 	int err;
 	u16 val;
+	u16 fid;
 
 	mv88e6xxx_reg_lock(chip);
 
-	err = mv88e6xxx_g1_atu_op(chip, 0,
-				  MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION);
+	err = mv88e6xxx_g1_read_atu_violation(chip);
 	if (err)
 		goto out;
 
@@ -368,6 +382,10 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
 	if (err)
 		goto out;
 
+	err = mv88e6xxx_g1_read(chip, MV88E6352_G1_ATU_FID, &fid);
+	if (err)
+		goto out;
+
 	err = mv88e6xxx_g1_atu_data_read(chip, &entry);
 	if (err)
 		goto out;
@@ -396,6 +414,13 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
 				    "ATU miss violation for %pM portvec %x spid %d\n",
 				    entry.mac, entry.portvec, spid);
 		chip->ports[spid].atu_miss_violation++;
+		if (mv88e6xxx_port_is_locked(chip, chip->ports[spid].port))
+			err = mv88e6xxx_switchdev_handle_atu_miss_violation(chip,
+									    chip->ports[spid].port,
+									    &entry,
+									    fid);
+		if (err)
+			goto out;
 	}
 
 	if (val & MV88E6XXX_G1_ATU_OP_FULL_VIOLATION) {
diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c
new file mode 100644
index 000000000000..e0ca452b6f86
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * mv88e6xxx_switchdev.c
+ *
+ *	Authors:
+ *	Hans J. Schultz		<hans.schultz@westermo.com>
+ *
+ */
+
+#include <net/switchdev.h>
+#include "chip.h"
+#include "global1.h"
+
+struct mv88e6xxx_fid_search_ctx {
+	u16 fid_search;
+	u16 vid_found;
+};
+
+static int mv88e6xxx_find_vid_on_matching_fid(struct mv88e6xxx_chip *chip,
+					      const struct mv88e6xxx_vtu_entry *entry,
+					      void *priv)
+{
+	struct mv88e6xxx_fid_search_ctx *ctx = priv;
+
+	if (ctx->fid_search == entry->fid) {
+		ctx->vid_found = entry->vid;
+		return 1;
+	}
+	return 0;
+}
+
+int mv88e6xxx_switchdev_handle_atu_miss_violation(struct mv88e6xxx_chip *chip,
+						  int port,
+						  struct mv88e6xxx_atu_entry *entry,
+						  u16 fid)
+{
+	struct switchdev_notifier_fdb_info info = {
+		.addr = entry->mac,
+		.vid = 0,
+		.added_by_user = false,
+		.is_local = false,
+		.offloaded = true,
+		.locked = true,
+	};
+	struct mv88e6xxx_fid_search_ctx ctx;
+	struct netlink_ext_ack *extack;
+	struct net_device *brport;
+	struct dsa_port *dp;
+	int err;
+
+	ctx.fid_search = fid;
+	err = mv88e6xxx_vtu_walk(chip, mv88e6xxx_find_vid_on_matching_fid, &ctx);
+	if (err < 0)
+		return err;
+	if (err == 1)
+		info.vid = ctx.vid_found;
+	else
+		return -ENODATA;
+
+	dp = dsa_to_port(chip->ds, port);
+	brport = dsa_port_to_bridge_port(dp);
+	err = call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE, brport, &info.info, extack);
+	if (err)
+		return err;
+	entry->portvec = MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_NO_EGRESS;
+	return mv88e6xxx_g1_atu_loadpurge(chip, fid, entry);
+}
diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h
new file mode 100644
index 000000000000..127f3098f745
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * mv88e6xxx_switchdev.h
+ *
+ *	Authors:
+ *	Hans J. Schultz		<hans.schultz@westermo.com>
+ *
+ */
+
+#ifndef DRIVERS_NET_DSA_MV88E6XXX_MV88E6XXX_SWITCHDEV_H_
+#define DRIVERS_NET_DSA_MV88E6XXX_MV88E6XXX_SWITCHDEV_H_
+
+#include <net/switchdev.h>
+
+int mv88e6xxx_switchdev_handle_atu_miss_violation(struct mv88e6xxx_chip *chip,
+						  int port,
+						  struct mv88e6xxx_atu_entry *entry,
+						  u16 fid);
+
+#endif /* DRIVERS_NET_DSA_MV88E6XXX_MV88E6XXX_SWITCHDEV_H_ */
diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index 795b3128768f..6b375b0caa2c 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -1239,6 +1239,17 @@ int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,
 	return err;
 }
 
+bool mv88e6xxx_port_is_locked(struct mv88e6xxx_chip *chip, int port)
+{
+	u16 reg;
+
+	if (mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg))
+		return false;
+	if (!(reg & MV88E6XXX_PORT_CTL0_SA_FILT_DROP_ON_LOCK))
+		return false;
+	return true;
+}
+
 int mv88e6xxx_port_set_lock(struct mv88e6xxx_chip *chip, int port,
 			    bool locked)
 {
diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h
index e0a705d82019..09ea8f1615bb 100644
--- a/drivers/net/dsa/mv88e6xxx/port.h
+++ b/drivers/net/dsa/mv88e6xxx/port.h
@@ -374,6 +374,7 @@ int mv88e6xxx_port_set_fid(struct mv88e6xxx_chip *chip, int port, u16 fid);
 int mv88e6xxx_port_get_pvid(struct mv88e6xxx_chip *chip, int port, u16 *pvid);
 int mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid);
 
+bool mv88e6xxx_port_is_locked(struct mv88e6xxx_chip *chip, int port);
 int mv88e6xxx_port_set_lock(struct mv88e6xxx_chip *chip, int port,
 			    bool locked);
 
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-10 14:23 ` [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation Hans Schultz
@ 2022-03-10 14:28   ` Vladimir Oltean
  2022-03-10 15:00     ` Hans Schultz
                       ` (2 more replies)
  2022-03-10 14:54   ` Andrew Lunn
  1 sibling, 3 replies; 63+ messages in thread
From: Vladimir Oltean @ 2022-03-10 14:28 UTC (permalink / raw)
  To: Hans Schultz
  Cc: davem, kuba, netdev, Hans Schultz, Andrew Lunn, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On Thu, Mar 10, 2022 at 03:23:20PM +0100, Hans Schultz wrote:
> This implementation for the Marvell mv88e6xxx chip series, is
> based on handling ATU miss violations occurring when packets
> ingress on a port that is locked. The mac address triggering
> the ATU miss violation is communicated through switchdev to
> the bridge module, which adds a fdb entry with the fdb locked
> flag set.
> Note: The locked port must have learning enabled for the ATU
> miss violation to occur.
> 
> Signed-off-by: Hans Schultz <schultz.hans+netdev@gmail.com>
> ---
>  drivers/net/dsa/mv88e6xxx/Makefile            |  1 +
>  drivers/net/dsa/mv88e6xxx/chip.c              | 10 +--
>  drivers/net/dsa/mv88e6xxx/chip.h              |  5 ++
>  drivers/net/dsa/mv88e6xxx/global1.h           |  1 +
>  drivers/net/dsa/mv88e6xxx/global1_atu.c       | 29 +++++++-
>  .../net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c   | 67 +++++++++++++++++++
>  .../net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h   | 20 ++++++
>  drivers/net/dsa/mv88e6xxx/port.c              | 11 +++
>  drivers/net/dsa/mv88e6xxx/port.h              |  1 +
>  9 files changed, 138 insertions(+), 7 deletions(-)
>  create mode 100644 drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c
>  create mode 100644 drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h
> 
> diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile
> index c8eca2b6f959..3ca57709730d 100644
> --- a/drivers/net/dsa/mv88e6xxx/Makefile
> +++ b/drivers/net/dsa/mv88e6xxx/Makefile
> @@ -15,3 +15,4 @@ mv88e6xxx-objs += port_hidden.o
>  mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += ptp.o
>  mv88e6xxx-objs += serdes.o
>  mv88e6xxx-objs += smi.o
> +mv88e6xxx-objs += mv88e6xxx_switchdev.o
> \ No newline at end of file
> diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
> index 84b90fc36c58..e1b6bd738085 100644
> --- a/drivers/net/dsa/mv88e6xxx/chip.c
> +++ b/drivers/net/dsa/mv88e6xxx/chip.c
> @@ -1714,11 +1714,11 @@ static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
>  	return err;
>  }
>  
> -static int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
> -			      int (*cb)(struct mv88e6xxx_chip *chip,
> -					const struct mv88e6xxx_vtu_entry *entry,
> -					void *priv),
> -			      void *priv)
> +int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
> +		       int (*cb)(struct mv88e6xxx_chip *chip,
> +				 const struct mv88e6xxx_vtu_entry *entry,
> +				 void *priv),
> +		       void *priv)
>  {
>  	struct mv88e6xxx_vtu_entry entry = {
>  		.vid = mv88e6xxx_max_vid(chip),
> diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
> index 30b92a265613..64e8fc470fdf 100644
> --- a/drivers/net/dsa/mv88e6xxx/chip.h
> +++ b/drivers/net/dsa/mv88e6xxx/chip.h
> @@ -763,6 +763,11 @@ static inline void mv88e6xxx_reg_unlock(struct mv88e6xxx_chip *chip)
>  	mutex_unlock(&chip->reg_lock);
>  }
>  
> +int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
> +		       int (*cb)(struct mv88e6xxx_chip *chip,
> +				 const struct mv88e6xxx_vtu_entry *entry,
> +				 void *priv),
> +		       void *priv);
>  int mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *bitmap);
>  
>  #endif /* _MV88E6XXX_CHIP_H */
> diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h
> index 2c1607c858a1..729cc0610d9a 100644
> --- a/drivers/net/dsa/mv88e6xxx/global1.h
> +++ b/drivers/net/dsa/mv88e6xxx/global1.h
> @@ -136,6 +136,7 @@
>  #define MV88E6XXX_G1_ATU_DATA_TRUNK				0x8000
>  #define MV88E6XXX_G1_ATU_DATA_TRUNK_ID_MASK			0x00f0
>  #define MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_MASK			0x3ff0
> +#define MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_NO_EGRESS		0x0000
>  #define MV88E6XXX_G1_ATU_DATA_STATE_MASK			0x000f
>  #define MV88E6XXX_G1_ATU_DATA_STATE_UC_UNUSED			0x0000
>  #define MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_1_OLDEST		0x0001
> diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c
> index 40bd67a5c8e9..afa54fe8667e 100644
> --- a/drivers/net/dsa/mv88e6xxx/global1_atu.c
> +++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c
> @@ -12,6 +12,8 @@
>  
>  #include "chip.h"
>  #include "global1.h"
> +#include "port.h"
> +#include "mv88e6xxx_switchdev.h"
>  
>  /* Offset 0x01: ATU FID Register */
>  
> @@ -114,6 +116,18 @@ static int mv88e6xxx_g1_atu_op_wait(struct mv88e6xxx_chip *chip)
>  	return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_ATU_OP, bit, 0);
>  }
>  
> +static int mv88e6xxx_g1_read_atu_violation(struct mv88e6xxx_chip *chip)
> +{
> +	int err;
> +
> +	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_OP,
> +				 MV88E6XXX_G1_ATU_OP_BUSY | MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION);
> +	if (err)
> +		return err;
> +
> +	return mv88e6xxx_g1_atu_op_wait(chip);
> +}
> +
>  static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op)
>  {
>  	u16 val;
> @@ -356,11 +370,11 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
>  	int spid;
>  	int err;
>  	u16 val;
> +	u16 fid;
>  
>  	mv88e6xxx_reg_lock(chip);
>  
> -	err = mv88e6xxx_g1_atu_op(chip, 0,
> -				  MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION);
> +	err = mv88e6xxx_g1_read_atu_violation(chip);
>  	if (err)
>  		goto out;
>  
> @@ -368,6 +382,10 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
>  	if (err)
>  		goto out;
>  
> +	err = mv88e6xxx_g1_read(chip, MV88E6352_G1_ATU_FID, &fid);
> +	if (err)
> +		goto out;
> +
>  	err = mv88e6xxx_g1_atu_data_read(chip, &entry);
>  	if (err)
>  		goto out;
> @@ -396,6 +414,13 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
>  				    "ATU miss violation for %pM portvec %x spid %d\n",
>  				    entry.mac, entry.portvec, spid);
>  		chip->ports[spid].atu_miss_violation++;
> +		if (mv88e6xxx_port_is_locked(chip, chip->ports[spid].port))
> +			err = mv88e6xxx_switchdev_handle_atu_miss_violation(chip,
> +									    chip->ports[spid].port,
> +									    &entry,
> +									    fid);

Do we want to suppress the ATU miss violation warnings if we're going to
notify the bridge, or is it better to keep them for some reason?
My logic is that they're part of normal operation, so suppressing makes
sense.

> +		if (err)
> +			goto out;
>  	}
>  
>  	if (val & MV88E6XXX_G1_ATU_OP_FULL_VIOLATION) {
> diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c
> new file mode 100644
> index 000000000000..e0ca452b6f86
> --- /dev/null
> +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c
> @@ -0,0 +1,67 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * mv88e6xxx_switchdev.c
> + *
> + *	Authors:
> + *	Hans J. Schultz		<hans.schultz@westermo.com>
> + *
> + */
> +
> +#include <net/switchdev.h>
> +#include "chip.h"
> +#include "global1.h"
> +
> +struct mv88e6xxx_fid_search_ctx {
> +	u16 fid_search;
> +	u16 vid_found;
> +};
> +
> +static int mv88e6xxx_find_vid_on_matching_fid(struct mv88e6xxx_chip *chip,
> +					      const struct mv88e6xxx_vtu_entry *entry,
> +					      void *priv)
> +{
> +	struct mv88e6xxx_fid_search_ctx *ctx = priv;
> +
> +	if (ctx->fid_search == entry->fid) {
> +		ctx->vid_found = entry->vid;
> +		return 1;
> +	}
> +	return 0;
> +}
> +
> +int mv88e6xxx_switchdev_handle_atu_miss_violation(struct mv88e6xxx_chip *chip,
> +						  int port,
> +						  struct mv88e6xxx_atu_entry *entry,
> +						  u16 fid)
> +{
> +	struct switchdev_notifier_fdb_info info = {
> +		.addr = entry->mac,
> +		.vid = 0,
> +		.added_by_user = false,
> +		.is_local = false,
> +		.offloaded = true,
> +		.locked = true,
> +	};
> +	struct mv88e6xxx_fid_search_ctx ctx;
> +	struct netlink_ext_ack *extack;
> +	struct net_device *brport;
> +	struct dsa_port *dp;
> +	int err;
> +
> +	ctx.fid_search = fid;
> +	err = mv88e6xxx_vtu_walk(chip, mv88e6xxx_find_vid_on_matching_fid, &ctx);
> +	if (err < 0)
> +		return err;
> +	if (err == 1)
> +		info.vid = ctx.vid_found;
> +	else
> +		return -ENODATA;
> +
> +	dp = dsa_to_port(chip->ds, port);
> +	brport = dsa_port_to_bridge_port(dp);

Since this is threaded interrupt context, I suppose it could race with
dsa_port_bridge_leave(). So it is best to check whether "brport" is NULL
or not.

Speaking of races with dsa_port_bridge_leave().. does SWITCHDEV_FDB_ADD_TO_BRIDGE
not require rtnl_lock?

> +	err = call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE, brport, &info.info, extack);

It is buggy to pass an uninitialized on-stack extack, just pass NULL if
there's no one to consume it.

Alternatively, if the bridge produces a valid extack message for errors
in this case (I haven't checked), it may be more useful to manually
print the extack._msg to the kernel log - see dsa_switch_sync_vlan_filtering()
for an example.

I am a bit uncomfortable having every driver implement this ad-hoc and
potentially have a gazillion subtle bugs like these, could we have a
common function exported by DSA that deals with SWITCHDEV_FDB_ADD_TO_BRIDGE?

> +	if (err)
> +		return err;
> +	entry->portvec = MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_NO_EGRESS;
> +	return mv88e6xxx_g1_atu_loadpurge(chip, fid, entry);
> +}
> diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h
> new file mode 100644
> index 000000000000..127f3098f745
> --- /dev/null
> +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h
> @@ -0,0 +1,20 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * mv88e6xxx_switchdev.h
> + *
> + *	Authors:
> + *	Hans J. Schultz		<hans.schultz@westermo.com>
> + *
> + */
> +
> +#ifndef DRIVERS_NET_DSA_MV88E6XXX_MV88E6XXX_SWITCHDEV_H_
> +#define DRIVERS_NET_DSA_MV88E6XXX_MV88E6XXX_SWITCHDEV_H_
> +
> +#include <net/switchdev.h>
> +
> +int mv88e6xxx_switchdev_handle_atu_miss_violation(struct mv88e6xxx_chip *chip,
> +						  int port,
> +						  struct mv88e6xxx_atu_entry *entry,
> +						  u16 fid);
> +
> +#endif /* DRIVERS_NET_DSA_MV88E6XXX_MV88E6XXX_SWITCHDEV_H_ */
> diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
> index 795b3128768f..6b375b0caa2c 100644
> --- a/drivers/net/dsa/mv88e6xxx/port.c
> +++ b/drivers/net/dsa/mv88e6xxx/port.c
> @@ -1239,6 +1239,17 @@ int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,
>  	return err;
>  }
>  
> +bool mv88e6xxx_port_is_locked(struct mv88e6xxx_chip *chip, int port)
> +{
> +	u16 reg;
> +
> +	if (mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg))
> +		return false;
> +	if (!(reg & MV88E6XXX_PORT_CTL0_SA_FILT_DROP_ON_LOCK))
> +		return false;
> +	return true;
> +}
> +
>  int mv88e6xxx_port_set_lock(struct mv88e6xxx_chip *chip, int port,
>  			    bool locked)
>  {
> diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h
> index e0a705d82019..09ea8f1615bb 100644
> --- a/drivers/net/dsa/mv88e6xxx/port.h
> +++ b/drivers/net/dsa/mv88e6xxx/port.h
> @@ -374,6 +374,7 @@ int mv88e6xxx_port_set_fid(struct mv88e6xxx_chip *chip, int port, u16 fid);
>  int mv88e6xxx_port_get_pvid(struct mv88e6xxx_chip *chip, int port, u16 *pvid);
>  int mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid);
>  
> +bool mv88e6xxx_port_is_locked(struct mv88e6xxx_chip *chip, int port);
>  int mv88e6xxx_port_set_lock(struct mv88e6xxx_chip *chip, int port,
>  			    bool locked);
>  
> -- 
> 2.30.2
> 

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 1/3] net: bridge: add fdb flag to extent locked port feature
  2022-03-10 14:23 ` [PATCH net-next 1/3] net: bridge: add fdb flag to extent locked port feature Hans Schultz
@ 2022-03-10 14:42   ` Nikolay Aleksandrov
  2022-03-10 15:38     ` Hans Schultz
  2022-03-14 15:30   ` Ido Schimmel
  1 sibling, 1 reply; 63+ messages in thread
From: Nikolay Aleksandrov @ 2022-03-10 14:42 UTC (permalink / raw)
  To: Hans Schultz, davem, kuba
  Cc: netdev, Hans Schultz, Andrew Lunn, Vivien Didelot,
	Florian Fainelli, Vladimir Oltean, Jiri Pirko, Ivan Vecera,
	Roopa Prabhu, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On 10/03/2022 16:23, Hans Schultz wrote:
> Add an intermediate state for clients behind a locked port to allow for
> possible opening of the port for said clients. This feature corresponds
> to the Mac-Auth and MAC Authentication Bypass (MAB) named features. The
> latter defined by Cisco.
> 
> Signed-off-by: Hans Schultz <schultz.hans+netdev@gmail.com>
> ---
>   include/uapi/linux/neighbour.h |  1 +
>   net/bridge/br_fdb.c            |  6 ++++++
>   net/bridge/br_input.c          | 11 ++++++++++-
>   net/bridge/br_private.h        |  3 ++-
>   4 files changed, 19 insertions(+), 2 deletions(-)
> 
> diff --git a/include/uapi/linux/neighbour.h b/include/uapi/linux/neighbour.h
> index db05fb55055e..83115a592d58 100644
> --- a/include/uapi/linux/neighbour.h
> +++ b/include/uapi/linux/neighbour.h
> @@ -208,6 +208,7 @@ enum {
>   	NFEA_UNSPEC,
>   	NFEA_ACTIVITY_NOTIFY,
>   	NFEA_DONT_REFRESH,
> +	NFEA_LOCKED,
>   	__NFEA_MAX
>   };

Hmm, can you use NDA_FLAGS_EXT instead ?
That should simplify things and reduce the nl size.

>   #define NFEA_MAX (__NFEA_MAX - 1)
> diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
> index 6ccda68bd473..396dcf3084cf 100644
> --- a/net/bridge/br_fdb.c
> +++ b/net/bridge/br_fdb.c
> @@ -105,6 +105,7 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
>   	struct nda_cacheinfo ci;
>   	struct nlmsghdr *nlh;
>   	struct ndmsg *ndm;
> +	u8 ext_flags = 0;
>   
>   	nlh = nlmsg_put(skb, portid, seq, type, sizeof(*ndm), flags);
>   	if (nlh == NULL)
> @@ -125,11 +126,16 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
>   		ndm->ndm_flags |= NTF_EXT_LEARNED;
>   	if (test_bit(BR_FDB_STICKY, &fdb->flags))
>   		ndm->ndm_flags |= NTF_STICKY;
> +	if (test_bit(BR_FDB_ENTRY_LOCKED, &fdb->flags))
> +		ext_flags |= 1 << NFEA_LOCKED;
>   
>   	if (nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->key.addr))
>   		goto nla_put_failure;
>   	if (nla_put_u32(skb, NDA_MASTER, br->dev->ifindex))
>   		goto nla_put_failure;
> +	if (nla_put_u8(skb, NDA_FDB_EXT_ATTRS, ext_flags))
> +		goto nla_put_failure;
> +
>   	ci.ndm_used	 = jiffies_to_clock_t(now - fdb->used);
>   	ci.ndm_confirmed = 0;
>   	ci.ndm_updated	 = jiffies_to_clock_t(now - fdb->updated);
> diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
> index e0c13fcc50ed..897908484b18 100644
> --- a/net/bridge/br_input.c
> +++ b/net/bridge/br_input.c
> @@ -75,6 +75,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
>   	struct net_bridge_mcast *brmctx;
>   	struct net_bridge_vlan *vlan;
>   	struct net_bridge *br;
> +	unsigned long flags = 0;

Please move this below...

>   	u16 vid = 0;
>   	u8 state;
>   
> @@ -94,8 +95,16 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
>   			br_fdb_find_rcu(br, eth_hdr(skb)->h_source, vid);
>   
>   		if (!fdb_src || READ_ONCE(fdb_src->dst) != p ||
> -		    test_bit(BR_FDB_LOCAL, &fdb_src->flags))
> +		    test_bit(BR_FDB_LOCAL, &fdb_src->flags)) {
> +			if (!fdb_src) {

... here where it's only used.

> +				set_bit(BR_FDB_ENTRY_LOCKED, &flags);
> +				br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, flags);
> +			}
>   			goto drop;
> +		} else {
> +			if (test_bit(BR_FDB_ENTRY_LOCKED, &fdb_src->flags))
> +				goto drop;
> +		}
>   	}
>   
>   	nbp_switchdev_frame_mark(p, skb);
> diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
> index 48bc61ebc211..f5a0b68c4857 100644
> --- a/net/bridge/br_private.h
> +++ b/net/bridge/br_private.h
> @@ -248,7 +248,8 @@ enum {
>   	BR_FDB_ADDED_BY_EXT_LEARN,
>   	BR_FDB_OFFLOADED,
>   	BR_FDB_NOTIFY,
> -	BR_FDB_NOTIFY_INACTIVE
> +	BR_FDB_NOTIFY_INACTIVE,
> +	BR_FDB_ENTRY_LOCKED,
>   };
>   
>   struct net_bridge_fdb_key {


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-10 14:23 ` [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation Hans Schultz
  2022-03-10 14:28   ` Vladimir Oltean
@ 2022-03-10 14:54   ` Andrew Lunn
  2022-03-11  7:59     ` Hans Schultz
  1 sibling, 1 reply; 63+ messages in thread
From: Andrew Lunn @ 2022-03-10 14:54 UTC (permalink / raw)
  To: Hans Schultz
  Cc: davem, kuba, netdev, Hans Schultz, Vivien Didelot,
	Florian Fainelli, Vladimir Oltean, Jiri Pirko, Ivan Vecera,
	Roopa Prabhu, Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel,
	linux-kernel, bridge

> +		if (mv88e6xxx_port_is_locked(chip, chip->ports[spid].port))
> +			err = mv88e6xxx_switchdev_handle_atu_miss_violation(chip,
> +									    chip->ports[spid].port,
> +									    &entry,
> +									    fid);

> +static int mv88e6xxx_find_vid_on_matching_fid(struct mv88e6xxx_chip *chip,
> +					      const struct mv88e6xxx_vtu_entry *entry,
> +					      void *priv)
> +{
> +	struct mv88e6xxx_fid_search_ctx *ctx = priv;
> +
> +	if (ctx->fid_search == entry->fid) {
> +		ctx->vid_found = entry->vid;
> +		return 1;
> +	}
> +	return 0;
> +}
> +
> +int mv88e6xxx_switchdev_handle_atu_miss_violation(struct mv88e6xxx_chip *chip,
> +						  int port,
> +						  struct mv88e6xxx_atu_entry *entry,
> +						  u16 fid)
> +{
> +	struct switchdev_notifier_fdb_info info = {
> +		.addr = entry->mac,
> +		.vid = 0,
> +		.added_by_user = false,
> +		.is_local = false,
> +		.offloaded = true,
> +		.locked = true,
> +	};
> +	struct mv88e6xxx_fid_search_ctx ctx;
> +	struct netlink_ext_ack *extack;
> +	struct net_device *brport;
> +	struct dsa_port *dp;
> +	int err;
> +
> +	ctx.fid_search = fid;
> +	err = mv88e6xxx_vtu_walk(chip, mv88e6xxx_find_vid_on_matching_fid, &ctx);

I could be reading this code wrong, but it looks like you assume there
is a single new entry in the ATU. But interrupts on these devices are
slow. It would be easy for two or more devices to pop into existence
at the same time. Don't you need to walk the whole ATU to find all the
new entries? Have you tried this with a traffic generating populating
the ATU with new entries at different rates, up to line rate? Do you
get notifications for them all?

    Andrew

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-10 14:28   ` Vladimir Oltean
@ 2022-03-10 15:00     ` Hans Schultz
  2022-03-10 15:07       ` Vladimir Oltean
  2022-03-10 15:57     ` Hans Schultz
  2022-03-14 10:46     ` Hans Schultz
  2 siblings, 1 reply; 63+ messages in thread
From: Hans Schultz @ 2022-03-10 15:00 UTC (permalink / raw)
  To: Vladimir Oltean, Hans Schultz
  Cc: davem, kuba, netdev, Andrew Lunn, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On tor, mar 10, 2022 at 16:28, Vladimir Oltean <olteanv@gmail.com> wrote:
> On Thu, Mar 10, 2022 at 03:23:20PM +0100, Hans Schultz wrote:
>> This implementation for the Marvell mv88e6xxx chip series, is
>> based on handling ATU miss violations occurring when packets
>> ingress on a port that is locked. The mac address triggering
>> the ATU miss violation is communicated through switchdev to
>> the bridge module, which adds a fdb entry with the fdb locked
>> flag set.
>> Note: The locked port must have learning enabled for the ATU
>> miss violation to occur.
>> 
>> Signed-off-by: Hans Schultz <schultz.hans+netdev@gmail.com>
>> ---
>>  drivers/net/dsa/mv88e6xxx/Makefile            |  1 +
>>  drivers/net/dsa/mv88e6xxx/chip.c              | 10 +--
>>  drivers/net/dsa/mv88e6xxx/chip.h              |  5 ++
>>  drivers/net/dsa/mv88e6xxx/global1.h           |  1 +
>>  drivers/net/dsa/mv88e6xxx/global1_atu.c       | 29 +++++++-
>>  .../net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c   | 67 +++++++++++++++++++
>>  .../net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h   | 20 ++++++
>>  drivers/net/dsa/mv88e6xxx/port.c              | 11 +++
>>  drivers/net/dsa/mv88e6xxx/port.h              |  1 +
>>  9 files changed, 138 insertions(+), 7 deletions(-)
>>  create mode 100644 drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c
>>  create mode 100644 drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h
>> 
>> diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile
>> index c8eca2b6f959..3ca57709730d 100644
>> --- a/drivers/net/dsa/mv88e6xxx/Makefile
>> +++ b/drivers/net/dsa/mv88e6xxx/Makefile
>> @@ -15,3 +15,4 @@ mv88e6xxx-objs += port_hidden.o
>>  mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += ptp.o
>>  mv88e6xxx-objs += serdes.o
>>  mv88e6xxx-objs += smi.o
>> +mv88e6xxx-objs += mv88e6xxx_switchdev.o
>> \ No newline at end of file
>> diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
>> index 84b90fc36c58..e1b6bd738085 100644
>> --- a/drivers/net/dsa/mv88e6xxx/chip.c
>> +++ b/drivers/net/dsa/mv88e6xxx/chip.c
>> @@ -1714,11 +1714,11 @@ static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
>>  	return err;
>>  }
>>  
>> -static int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
>> -			      int (*cb)(struct mv88e6xxx_chip *chip,
>> -					const struct mv88e6xxx_vtu_entry *entry,
>> -					void *priv),
>> -			      void *priv)
>> +int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
>> +		       int (*cb)(struct mv88e6xxx_chip *chip,
>> +				 const struct mv88e6xxx_vtu_entry *entry,
>> +				 void *priv),
>> +		       void *priv)
>>  {
>>  	struct mv88e6xxx_vtu_entry entry = {
>>  		.vid = mv88e6xxx_max_vid(chip),
>> diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
>> index 30b92a265613..64e8fc470fdf 100644
>> --- a/drivers/net/dsa/mv88e6xxx/chip.h
>> +++ b/drivers/net/dsa/mv88e6xxx/chip.h
>> @@ -763,6 +763,11 @@ static inline void mv88e6xxx_reg_unlock(struct mv88e6xxx_chip *chip)
>>  	mutex_unlock(&chip->reg_lock);
>>  }
>>  
>> +int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
>> +		       int (*cb)(struct mv88e6xxx_chip *chip,
>> +				 const struct mv88e6xxx_vtu_entry *entry,
>> +				 void *priv),
>> +		       void *priv);
>>  int mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *bitmap);
>>  
>>  #endif /* _MV88E6XXX_CHIP_H */
>> diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h
>> index 2c1607c858a1..729cc0610d9a 100644
>> --- a/drivers/net/dsa/mv88e6xxx/global1.h
>> +++ b/drivers/net/dsa/mv88e6xxx/global1.h
>> @@ -136,6 +136,7 @@
>>  #define MV88E6XXX_G1_ATU_DATA_TRUNK				0x8000
>>  #define MV88E6XXX_G1_ATU_DATA_TRUNK_ID_MASK			0x00f0
>>  #define MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_MASK			0x3ff0
>> +#define MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_NO_EGRESS		0x0000
>>  #define MV88E6XXX_G1_ATU_DATA_STATE_MASK			0x000f
>>  #define MV88E6XXX_G1_ATU_DATA_STATE_UC_UNUSED			0x0000
>>  #define MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_1_OLDEST		0x0001
>> diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c
>> index 40bd67a5c8e9..afa54fe8667e 100644
>> --- a/drivers/net/dsa/mv88e6xxx/global1_atu.c
>> +++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c
>> @@ -12,6 +12,8 @@
>>  
>>  #include "chip.h"
>>  #include "global1.h"
>> +#include "port.h"
>> +#include "mv88e6xxx_switchdev.h"
>>  
>>  /* Offset 0x01: ATU FID Register */
>>  
>> @@ -114,6 +116,18 @@ static int mv88e6xxx_g1_atu_op_wait(struct mv88e6xxx_chip *chip)
>>  	return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_ATU_OP, bit, 0);
>>  }
>>  
>> +static int mv88e6xxx_g1_read_atu_violation(struct mv88e6xxx_chip *chip)
>> +{
>> +	int err;
>> +
>> +	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_OP,
>> +				 MV88E6XXX_G1_ATU_OP_BUSY | MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION);
>> +	if (err)
>> +		return err;
>> +
>> +	return mv88e6xxx_g1_atu_op_wait(chip);
>> +}
>> +
>>  static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op)
>>  {
>>  	u16 val;
>> @@ -356,11 +370,11 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
>>  	int spid;
>>  	int err;
>>  	u16 val;
>> +	u16 fid;
>>  
>>  	mv88e6xxx_reg_lock(chip);
>>  
>> -	err = mv88e6xxx_g1_atu_op(chip, 0,
>> -				  MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION);
>> +	err = mv88e6xxx_g1_read_atu_violation(chip);
>>  	if (err)
>>  		goto out;
>>  
>> @@ -368,6 +382,10 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
>>  	if (err)
>>  		goto out;
>>  
>> +	err = mv88e6xxx_g1_read(chip, MV88E6352_G1_ATU_FID, &fid);
>> +	if (err)
>> +		goto out;
>> +
>>  	err = mv88e6xxx_g1_atu_data_read(chip, &entry);
>>  	if (err)
>>  		goto out;
>> @@ -396,6 +414,13 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
>>  				    "ATU miss violation for %pM portvec %x spid %d\n",
>>  				    entry.mac, entry.portvec, spid);
>>  		chip->ports[spid].atu_miss_violation++;
>> +		if (mv88e6xxx_port_is_locked(chip, chip->ports[spid].port))
>> +			err = mv88e6xxx_switchdev_handle_atu_miss_violation(chip,
>> +									    chip->ports[spid].port,
>> +									    &entry,
>> +									    fid);
>
> Do we want to suppress the ATU miss violation warnings if we're going to
> notify the bridge, or is it better to keep them for some reason?
> My logic is that they're part of normal operation, so suppressing makes
> sense.
>
>> +		if (err)
>> +			goto out;
>>  	}
>>  
>>  	if (val & MV88E6XXX_G1_ATU_OP_FULL_VIOLATION) {
>> diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c
>> new file mode 100644
>> index 000000000000..e0ca452b6f86
>> --- /dev/null
>> +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c
>> @@ -0,0 +1,67 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * mv88e6xxx_switchdev.c
>> + *
>> + *	Authors:
>> + *	Hans J. Schultz		<hans.schultz@westermo.com>
>> + *
>> + */
>> +
>> +#include <net/switchdev.h>
>> +#include "chip.h"
>> +#include "global1.h"
>> +
>> +struct mv88e6xxx_fid_search_ctx {
>> +	u16 fid_search;
>> +	u16 vid_found;
>> +};
>> +
>> +static int mv88e6xxx_find_vid_on_matching_fid(struct mv88e6xxx_chip *chip,
>> +					      const struct mv88e6xxx_vtu_entry *entry,
>> +					      void *priv)
>> +{
>> +	struct mv88e6xxx_fid_search_ctx *ctx = priv;
>> +
>> +	if (ctx->fid_search == entry->fid) {
>> +		ctx->vid_found = entry->vid;
>> +		return 1;
>> +	}
>> +	return 0;
>> +}
>> +
>> +int mv88e6xxx_switchdev_handle_atu_miss_violation(struct mv88e6xxx_chip *chip,
>> +						  int port,
>> +						  struct mv88e6xxx_atu_entry *entry,
>> +						  u16 fid)
>> +{
>> +	struct switchdev_notifier_fdb_info info = {
>> +		.addr = entry->mac,
>> +		.vid = 0,
>> +		.added_by_user = false,
>> +		.is_local = false,
>> +		.offloaded = true,
>> +		.locked = true,
>> +	};
>> +	struct mv88e6xxx_fid_search_ctx ctx;
>> +	struct netlink_ext_ack *extack;
>> +	struct net_device *brport;
>> +	struct dsa_port *dp;
>> +	int err;
>> +
>> +	ctx.fid_search = fid;
>> +	err = mv88e6xxx_vtu_walk(chip, mv88e6xxx_find_vid_on_matching_fid, &ctx);
>> +	if (err < 0)
>> +		return err;
>> +	if (err == 1)
>> +		info.vid = ctx.vid_found;
>> +	else
>> +		return -ENODATA;
>> +
>> +	dp = dsa_to_port(chip->ds, port);
>> +	brport = dsa_port_to_bridge_port(dp);
>
> Since this is threaded interrupt context, I suppose it could race with
> dsa_port_bridge_leave(). So it is best to check whether "brport" is NULL
> or not.
>
Would something like:
if (dsa_is_unused_port(chip->ds, port))
        return -ENODATA;

be appropriate and sufficient for that?

> Speaking of races with dsa_port_bridge_leave().. does SWITCHDEV_FDB_ADD_TO_BRIDGE
> not require rtnl_lock?
>
Yes, I will add that...

>> +	err = call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE, brport, &info.info, extack);
>
> It is buggy to pass an uninitialized on-stack extack, just pass NULL if
> there's no one to consume it.
>
> Alternatively, if the bridge produces a valid extack message for errors
> in this case (I haven't checked), it may be more useful to manually
> print the extack._msg to the kernel log - see dsa_switch_sync_vlan_filtering()
> for an example.

I will look into which case is the most appropriate...

>
> I am a bit uncomfortable having every driver implement this ad-hoc and
> potentially have a gazillion subtle bugs like these, could we have a
> common function exported by DSA that deals with SWITCHDEV_FDB_ADD_TO_BRIDGE?
>
I think that would be a good idea, only that a bunch of other drivers
already have implementations that would need changes. In general, I think
there should be a more centralized thought-through expandable API in
switchdev for stuff like this. It should also include the rtnl_lock.

>> +	if (err)
>> +		return err;
>> +	entry->portvec = MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_NO_EGRESS;
>> +	return mv88e6xxx_g1_atu_loadpurge(chip, fid, entry);
>> +}
>> diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h
>> new file mode 100644
>> index 000000000000..127f3098f745
>> --- /dev/null
>> +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h
>> @@ -0,0 +1,20 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later
>> + *
>> + * mv88e6xxx_switchdev.h
>> + *
>> + *	Authors:
>> + *	Hans J. Schultz		<hans.schultz@westermo.com>
>> + *
>> + */
>> +
>> +#ifndef DRIVERS_NET_DSA_MV88E6XXX_MV88E6XXX_SWITCHDEV_H_
>> +#define DRIVERS_NET_DSA_MV88E6XXX_MV88E6XXX_SWITCHDEV_H_
>> +
>> +#include <net/switchdev.h>
>> +
>> +int mv88e6xxx_switchdev_handle_atu_miss_violation(struct mv88e6xxx_chip *chip,
>> +						  int port,
>> +						  struct mv88e6xxx_atu_entry *entry,
>> +						  u16 fid);
>> +
>> +#endif /* DRIVERS_NET_DSA_MV88E6XXX_MV88E6XXX_SWITCHDEV_H_ */
>> diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
>> index 795b3128768f..6b375b0caa2c 100644
>> --- a/drivers/net/dsa/mv88e6xxx/port.c
>> +++ b/drivers/net/dsa/mv88e6xxx/port.c
>> @@ -1239,6 +1239,17 @@ int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,
>>  	return err;
>>  }
>>  
>> +bool mv88e6xxx_port_is_locked(struct mv88e6xxx_chip *chip, int port)
>> +{
>> +	u16 reg;
>> +
>> +	if (mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg))
>> +		return false;
>> +	if (!(reg & MV88E6XXX_PORT_CTL0_SA_FILT_DROP_ON_LOCK))
>> +		return false;
>> +	return true;
>> +}
>> +
>>  int mv88e6xxx_port_set_lock(struct mv88e6xxx_chip *chip, int port,
>>  			    bool locked)
>>  {
>> diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h
>> index e0a705d82019..09ea8f1615bb 100644
>> --- a/drivers/net/dsa/mv88e6xxx/port.h
>> +++ b/drivers/net/dsa/mv88e6xxx/port.h
>> @@ -374,6 +374,7 @@ int mv88e6xxx_port_set_fid(struct mv88e6xxx_chip *chip, int port, u16 fid);
>>  int mv88e6xxx_port_get_pvid(struct mv88e6xxx_chip *chip, int port, u16 *pvid);
>>  int mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid);
>>  
>> +bool mv88e6xxx_port_is_locked(struct mv88e6xxx_chip *chip, int port);
>>  int mv88e6xxx_port_set_lock(struct mv88e6xxx_chip *chip, int port,
>>  			    bool locked);
>>  
>> -- 
>> 2.30.2
>> 

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-10 15:00     ` Hans Schultz
@ 2022-03-10 15:07       ` Vladimir Oltean
  2022-03-10 15:51         ` Hans Schultz
  0 siblings, 1 reply; 63+ messages in thread
From: Vladimir Oltean @ 2022-03-10 15:07 UTC (permalink / raw)
  To: Hans Schultz
  Cc: davem, kuba, netdev, Andrew Lunn, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On Thu, Mar 10, 2022 at 04:00:52PM +0100, Hans Schultz wrote:
> >> +	brport = dsa_port_to_bridge_port(dp);
> >
> > Since this is threaded interrupt context, I suppose it could race with
> > dsa_port_bridge_leave(). So it is best to check whether "brport" is NULL
> > or not.
> >
> Would something like:
> if (dsa_is_unused_port(chip->ds, port))
>         return -ENODATA;
> 
> be appropriate and sufficient for that?

static inline
struct net_device *dsa_port_to_bridge_port(const struct dsa_port *dp)
{
	if (!dp->bridge)
		return NULL;

	if (dp->lag)
		return dp->lag->dev;
	else if (dp->hsr_dev)
		return dp->hsr_dev;

	return dp->slave;
}

Notice the "dp->bridge" check. The assignments are in dsa_port_bridge_create()
and in dsa_port_bridge_destroy(). These functions assume rtnl_mutex protection.
The question was how do you serialize with that, and why do you assume
that dsa_port_to_bridge_port() returns non-NULL.

So no, dsa_is_unused_port() would do absolutely nothing to help.

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 1/3] net: bridge: add fdb flag to extent locked port feature
  2022-03-10 14:42   ` Nikolay Aleksandrov
@ 2022-03-10 15:38     ` Hans Schultz
  2022-03-10 15:57       ` Nikolay Aleksandrov
  0 siblings, 1 reply; 63+ messages in thread
From: Hans Schultz @ 2022-03-10 15:38 UTC (permalink / raw)
  To: Nikolay Aleksandrov, Hans Schultz, davem, kuba
  Cc: netdev, Andrew Lunn, Vivien Didelot, Florian Fainelli,
	Vladimir Oltean, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Daniel Borkmann, Ido Schimmel, linux-kernel, bridge

On tor, mar 10, 2022 at 16:42, Nikolay Aleksandrov <razor@blackwall.org> wrote:
> On 10/03/2022 16:23, Hans Schultz wrote:
>> Add an intermediate state for clients behind a locked port to allow for
>> possible opening of the port for said clients. This feature corresponds
>> to the Mac-Auth and MAC Authentication Bypass (MAB) named features. The
>> latter defined by Cisco.
>> 
>> Signed-off-by: Hans Schultz <schultz.hans+netdev@gmail.com>
>> ---
>>   include/uapi/linux/neighbour.h |  1 +
>>   net/bridge/br_fdb.c            |  6 ++++++
>>   net/bridge/br_input.c          | 11 ++++++++++-
>>   net/bridge/br_private.h        |  3 ++-
>>   4 files changed, 19 insertions(+), 2 deletions(-)
>> 
>> diff --git a/include/uapi/linux/neighbour.h b/include/uapi/linux/neighbour.h
>> index db05fb55055e..83115a592d58 100644
>> --- a/include/uapi/linux/neighbour.h
>> +++ b/include/uapi/linux/neighbour.h
>> @@ -208,6 +208,7 @@ enum {
>>   	NFEA_UNSPEC,
>>   	NFEA_ACTIVITY_NOTIFY,
>>   	NFEA_DONT_REFRESH,
>> +	NFEA_LOCKED,
>>   	__NFEA_MAX
>>   };
>
> Hmm, can you use NDA_FLAGS_EXT instead ?
> That should simplify things and reduce the nl size.
>

I am using NDA_FDB_EXT_ATTRS. NFEA_LOCKED is just the
flag as the other flags section is full wrt the normal flags, but maybe it
doesn't fit in that section?

I will just note that iproute2 support for parsing nested attributes
does not work, thus the BR_FDB_NOTIFY section (lines 150-165) are
obsolete with respect to iproute2 as it is now. I cannot rule out that
someone has some other tool that can handle this BR_FDB_NOTIFY, but I
could not make iproute2 as it stands handle nested attributes. And of
course there is no handling of NDA_FDB_EXT_ATTRS in iproute2 now.

>>   #define NFEA_MAX (__NFEA_MAX - 1)
>> diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
>> index 6ccda68bd473..396dcf3084cf 100644
>> --- a/net/bridge/br_fdb.c
>> +++ b/net/bridge/br_fdb.c
>> @@ -105,6 +105,7 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
>>   	struct nda_cacheinfo ci;
>>   	struct nlmsghdr *nlh;
>>   	struct ndmsg *ndm;
>> +	u8 ext_flags = 0;
>>   
>>   	nlh = nlmsg_put(skb, portid, seq, type, sizeof(*ndm), flags);
>>   	if (nlh == NULL)
>> @@ -125,11 +126,16 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
>>   		ndm->ndm_flags |= NTF_EXT_LEARNED;
>>   	if (test_bit(BR_FDB_STICKY, &fdb->flags))
>>   		ndm->ndm_flags |= NTF_STICKY;
>> +	if (test_bit(BR_FDB_ENTRY_LOCKED, &fdb->flags))
>> +		ext_flags |= 1 << NFEA_LOCKED;
>>   
>>   	if (nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->key.addr))
>>   		goto nla_put_failure;
>>   	if (nla_put_u32(skb, NDA_MASTER, br->dev->ifindex))
>>   		goto nla_put_failure;
>> +	if (nla_put_u8(skb, NDA_FDB_EXT_ATTRS, ext_flags))
>> +		goto nla_put_failure;
>> +
>>   	ci.ndm_used	 = jiffies_to_clock_t(now - fdb->used);
>>   	ci.ndm_confirmed = 0;
>>   	ci.ndm_updated	 = jiffies_to_clock_t(now - fdb->updated);
>> diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
>> index e0c13fcc50ed..897908484b18 100644
>> --- a/net/bridge/br_input.c
>> +++ b/net/bridge/br_input.c
>> @@ -75,6 +75,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
>>   	struct net_bridge_mcast *brmctx;
>>   	struct net_bridge_vlan *vlan;
>>   	struct net_bridge *br;
>> +	unsigned long flags = 0;
>
> Please move this below...
>
>>   	u16 vid = 0;
>>   	u8 state;
>>   
>> @@ -94,8 +95,16 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
>>   			br_fdb_find_rcu(br, eth_hdr(skb)->h_source, vid);
>>   
>>   		if (!fdb_src || READ_ONCE(fdb_src->dst) != p ||
>> -		    test_bit(BR_FDB_LOCAL, &fdb_src->flags))
>> +		    test_bit(BR_FDB_LOCAL, &fdb_src->flags)) {
>> +			if (!fdb_src) {
>
> ... here where it's only used.
>

Forgot that one. Shall do!

>> +				set_bit(BR_FDB_ENTRY_LOCKED, &flags);
>> +				br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, flags);
>> +			}
>>   			goto drop;
>> +		} else {
>> +			if (test_bit(BR_FDB_ENTRY_LOCKED, &fdb_src->flags))
>> +				goto drop;
>> +		}
>>   	}
>>   
>>   	nbp_switchdev_frame_mark(p, skb);
>> diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
>> index 48bc61ebc211..f5a0b68c4857 100644
>> --- a/net/bridge/br_private.h
>> +++ b/net/bridge/br_private.h
>> @@ -248,7 +248,8 @@ enum {
>>   	BR_FDB_ADDED_BY_EXT_LEARN,
>>   	BR_FDB_OFFLOADED,
>>   	BR_FDB_NOTIFY,
>> -	BR_FDB_NOTIFY_INACTIVE
>> +	BR_FDB_NOTIFY_INACTIVE,
>> +	BR_FDB_ENTRY_LOCKED,
>>   };
>>   
>>   struct net_bridge_fdb_key {

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-10 15:07       ` Vladimir Oltean
@ 2022-03-10 15:51         ` Hans Schultz
  2022-03-10 16:05           ` Vladimir Oltean
  0 siblings, 1 reply; 63+ messages in thread
From: Hans Schultz @ 2022-03-10 15:51 UTC (permalink / raw)
  To: Vladimir Oltean, Hans Schultz
  Cc: davem, kuba, netdev, Andrew Lunn, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On tor, mar 10, 2022 at 17:07, Vladimir Oltean <olteanv@gmail.com> wrote:
> On Thu, Mar 10, 2022 at 04:00:52PM +0100, Hans Schultz wrote:
>> >> +	brport = dsa_port_to_bridge_port(dp);
>> >
>> > Since this is threaded interrupt context, I suppose it could race with
>> > dsa_port_bridge_leave(). So it is best to check whether "brport" is NULL
>> > or not.
>> >
>> Would something like:
>> if (dsa_is_unused_port(chip->ds, port))
>>         return -ENODATA;
>> 
>> be appropriate and sufficient for that?
>
> static inline
> struct net_device *dsa_port_to_bridge_port(const struct dsa_port *dp)
> {
> 	if (!dp->bridge)
> 		return NULL;
>
> 	if (dp->lag)
> 		return dp->lag->dev;
> 	else if (dp->hsr_dev)
> 		return dp->hsr_dev;
>
> 	return dp->slave;
> }
>
> Notice the "dp->bridge" check. The assignments are in dsa_port_bridge_create()
> and in dsa_port_bridge_destroy(). These functions assume rtnl_mutex protection.
> The question was how do you serialize with that, and why do you assume
> that dsa_port_to_bridge_port() returns non-NULL.
>
> So no, dsa_is_unused_port() would do absolutely nothing to help.

I was thinking in indirect terms (dangerous I know :-).

But wrt the nl lock, I wonder when other threads could pull the carpet
away under this, and so I might have to wait till after the last call
(mv88e6xxx_g1_atu_loadpurge) to free the nl lock?

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 1/3] net: bridge: add fdb flag to extent locked port feature
  2022-03-10 15:38     ` Hans Schultz
@ 2022-03-10 15:57       ` Nikolay Aleksandrov
  2022-03-10 16:11         ` Hans Schultz
  0 siblings, 1 reply; 63+ messages in thread
From: Nikolay Aleksandrov @ 2022-03-10 15:57 UTC (permalink / raw)
  To: Hans Schultz, davem, kuba
  Cc: netdev, Andrew Lunn, Vivien Didelot, Florian Fainelli,
	Vladimir Oltean, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Daniel Borkmann, Ido Schimmel, linux-kernel, bridge

On 10/03/2022 17:38, Hans Schultz wrote:
> On tor, mar 10, 2022 at 16:42, Nikolay Aleksandrov <razor@blackwall.org> wrote:
>> On 10/03/2022 16:23, Hans Schultz wrote:
>>> Add an intermediate state for clients behind a locked port to allow for
>>> possible opening of the port for said clients. This feature corresponds
>>> to the Mac-Auth and MAC Authentication Bypass (MAB) named features. The
>>> latter defined by Cisco.
>>>
>>> Signed-off-by: Hans Schultz <schultz.hans+netdev@gmail.com>
>>> ---
>>>    include/uapi/linux/neighbour.h |  1 +
>>>    net/bridge/br_fdb.c            |  6 ++++++
>>>    net/bridge/br_input.c          | 11 ++++++++++-
>>>    net/bridge/br_private.h        |  3 ++-
>>>    4 files changed, 19 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/include/uapi/linux/neighbour.h b/include/uapi/linux/neighbour.h
>>> index db05fb55055e..83115a592d58 100644
>>> --- a/include/uapi/linux/neighbour.h
>>> +++ b/include/uapi/linux/neighbour.h
>>> @@ -208,6 +208,7 @@ enum {
>>>    	NFEA_UNSPEC,
>>>    	NFEA_ACTIVITY_NOTIFY,
>>>    	NFEA_DONT_REFRESH,
>>> +	NFEA_LOCKED,
>>>    	__NFEA_MAX
>>>    };
>>
>> Hmm, can you use NDA_FLAGS_EXT instead ?
>> That should simplify things and reduce the nl size.
>>
> 
> I am using NDA_FDB_EXT_ATTRS. NFEA_LOCKED is just the
> flag as the other flags section is full wrt the normal flags, but maybe it
> doesn't fit in that section?
> 

Actually wait a second, this is completely wrong use of NDA_FDB_EXT_ATTRS.
That is a nested attribute, so the code below is wrong. More below..

> I will just note that iproute2 support for parsing nested attributes
> does not work, thus the BR_FDB_NOTIFY section (lines 150-165) are
> obsolete with respect to iproute2 as it is now. I cannot rule out that
> someone has some other tool that can handle this BR_FDB_NOTIFY, but I
> could not make iproute2 as it stands handle nested attributes. And of
> course there is no handling of NDA_FDB_EXT_ATTRS in iproute2 now.
> >>>    #define NFEA_MAX (__NFEA_MAX - 1)
>>> diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
>>> index 6ccda68bd473..396dcf3084cf 100644
>>> --- a/net/bridge/br_fdb.c
>>> +++ b/net/bridge/br_fdb.c
>>> @@ -105,6 +105,7 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
>>>    	struct nda_cacheinfo ci;
>>>    	struct nlmsghdr *nlh;
>>>    	struct ndmsg *ndm;
>>> +	u8 ext_flags = 0;
>>>    
>>>    	nlh = nlmsg_put(skb, portid, seq, type, sizeof(*ndm), flags);
>>>    	if (nlh == NULL)
>>> @@ -125,11 +126,16 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
>>>    		ndm->ndm_flags |= NTF_EXT_LEARNED;
>>>    	if (test_bit(BR_FDB_STICKY, &fdb->flags))
>>>    		ndm->ndm_flags |= NTF_STICKY;
>>> +	if (test_bit(BR_FDB_ENTRY_LOCKED, &fdb->flags))
>>> +		ext_flags |= 1 << NFEA_LOCKED;
>>>    
>>>    	if (nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->key.addr))
>>>    		goto nla_put_failure;
>>>    	if (nla_put_u32(skb, NDA_MASTER, br->dev->ifindex))
>>>    		goto nla_put_failure;
>>> +	if (nla_put_u8(skb, NDA_FDB_EXT_ATTRS, ext_flags))
>>> +		goto nla_put_failure;
>>> +

This is wrong. NDA_FDB_EXT_ATTRS is a nested attribute, you can't use it as a u8.
You need to have this structure:
  [ NDA_FDB_EXT_ATTRS ]
   ` [ NFEA_LOCKED ]

But that's why I asked if you could use the NDA_FLAGS_EXT attribute. You can see
the logic from the neigh code.

Also note that you need to account for the new attribute's size in fdb_nlmsg_size().


>>>    	ci.ndm_used	 = jiffies_to_clock_t(now - fdb->used);
>>>    	ci.ndm_confirmed = 0;
>>>    	ci.ndm_updated	 = jiffies_to_clock_t(now - fdb->updated);
>>> diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
>>> index e0c13fcc50ed..897908484b18 100644
>>> --- a/net/bridge/br_input.c
>>> +++ b/net/bridge/br_input.c
>>> @@ -75,6 +75,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
>>>    	struct net_bridge_mcast *brmctx;
>>>    	struct net_bridge_vlan *vlan;
>>>    	struct net_bridge *br;
>>> +	unsigned long flags = 0;
>>
>> Please move this below...
>>
>>>    	u16 vid = 0;
>>>    	u8 state;
>>>    
>>> @@ -94,8 +95,16 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
>>>    			br_fdb_find_rcu(br, eth_hdr(skb)->h_source, vid);
>>>    
>>>    		if (!fdb_src || READ_ONCE(fdb_src->dst) != p ||
>>> -		    test_bit(BR_FDB_LOCAL, &fdb_src->flags))
>>> +		    test_bit(BR_FDB_LOCAL, &fdb_src->flags)) {
>>> +			if (!fdb_src) {
>>
>> ... here where it's only used.
>>
> 
> Forgot that one. Shall do!
> 
>>> +				set_bit(BR_FDB_ENTRY_LOCKED, &flags);
>>> +				br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, flags);
>>> +			}
>>>    			goto drop;
>>> +		} else {
>>> +			if (test_bit(BR_FDB_ENTRY_LOCKED, &fdb_src->flags))
>>> +				goto drop;
>>> +		}
>>>    	}
>>>    
>>>    	nbp_switchdev_frame_mark(p, skb);
>>> diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
>>> index 48bc61ebc211..f5a0b68c4857 100644
>>> --- a/net/bridge/br_private.h
>>> +++ b/net/bridge/br_private.h
>>> @@ -248,7 +248,8 @@ enum {
>>>    	BR_FDB_ADDED_BY_EXT_LEARN,
>>>    	BR_FDB_OFFLOADED,
>>>    	BR_FDB_NOTIFY,
>>> -	BR_FDB_NOTIFY_INACTIVE
>>> +	BR_FDB_NOTIFY_INACTIVE,
>>> +	BR_FDB_ENTRY_LOCKED,
>>>    };
>>>    
>>>    struct net_bridge_fdb_key {


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-10 14:28   ` Vladimir Oltean
  2022-03-10 15:00     ` Hans Schultz
@ 2022-03-10 15:57     ` Hans Schultz
  2022-03-14 10:46     ` Hans Schultz
  2 siblings, 0 replies; 63+ messages in thread
From: Hans Schultz @ 2022-03-10 15:57 UTC (permalink / raw)
  To: Vladimir Oltean, Hans Schultz
  Cc: davem, kuba, netdev, Andrew Lunn, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On tor, mar 10, 2022 at 16:28, Vladimir Oltean <olteanv@gmail.com> wrote:
> On Thu, Mar 10, 2022 at 03:23:20PM +0100, Hans Schultz wrote:
>> This implementation for the Marvell mv88e6xxx chip series, is
>> based on handling ATU miss violations occurring when packets
>> ingress on a port that is locked. The mac address triggering
>> the ATU miss violation is communicated through switchdev to
>> the bridge module, which adds a fdb entry with the fdb locked
>> flag set.
>> Note: The locked port must have learning enabled for the ATU
>> miss violation to occur.
>> 
>> Signed-off-by: Hans Schultz <schultz.hans+netdev@gmail.com>
>> ---
>>  drivers/net/dsa/mv88e6xxx/Makefile            |  1 +
>>  drivers/net/dsa/mv88e6xxx/chip.c              | 10 +--
>>  drivers/net/dsa/mv88e6xxx/chip.h              |  5 ++
>>  drivers/net/dsa/mv88e6xxx/global1.h           |  1 +
>>  drivers/net/dsa/mv88e6xxx/global1_atu.c       | 29 +++++++-
>>  .../net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c   | 67 +++++++++++++++++++
>>  .../net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h   | 20 ++++++
>>  drivers/net/dsa/mv88e6xxx/port.c              | 11 +++
>>  drivers/net/dsa/mv88e6xxx/port.h              |  1 +
>>  9 files changed, 138 insertions(+), 7 deletions(-)
>>  create mode 100644 drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c
>>  create mode 100644 drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h
>> 
>> diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile
>> index c8eca2b6f959..3ca57709730d 100644
>> --- a/drivers/net/dsa/mv88e6xxx/Makefile
>> +++ b/drivers/net/dsa/mv88e6xxx/Makefile
>> @@ -15,3 +15,4 @@ mv88e6xxx-objs += port_hidden.o
>>  mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += ptp.o
>>  mv88e6xxx-objs += serdes.o
>>  mv88e6xxx-objs += smi.o
>> +mv88e6xxx-objs += mv88e6xxx_switchdev.o
>> \ No newline at end of file
>> diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
>> index 84b90fc36c58..e1b6bd738085 100644
>> --- a/drivers/net/dsa/mv88e6xxx/chip.c
>> +++ b/drivers/net/dsa/mv88e6xxx/chip.c
>> @@ -1714,11 +1714,11 @@ static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
>>  	return err;
>>  }
>>  
>> -static int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
>> -			      int (*cb)(struct mv88e6xxx_chip *chip,
>> -					const struct mv88e6xxx_vtu_entry *entry,
>> -					void *priv),
>> -			      void *priv)
>> +int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
>> +		       int (*cb)(struct mv88e6xxx_chip *chip,
>> +				 const struct mv88e6xxx_vtu_entry *entry,
>> +				 void *priv),
>> +		       void *priv)
>>  {
>>  	struct mv88e6xxx_vtu_entry entry = {
>>  		.vid = mv88e6xxx_max_vid(chip),
>> diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
>> index 30b92a265613..64e8fc470fdf 100644
>> --- a/drivers/net/dsa/mv88e6xxx/chip.h
>> +++ b/drivers/net/dsa/mv88e6xxx/chip.h
>> @@ -763,6 +763,11 @@ static inline void mv88e6xxx_reg_unlock(struct mv88e6xxx_chip *chip)
>>  	mutex_unlock(&chip->reg_lock);
>>  }
>>  
>> +int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
>> +		       int (*cb)(struct mv88e6xxx_chip *chip,
>> +				 const struct mv88e6xxx_vtu_entry *entry,
>> +				 void *priv),
>> +		       void *priv);
>>  int mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *bitmap);
>>  
>>  #endif /* _MV88E6XXX_CHIP_H */
>> diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h
>> index 2c1607c858a1..729cc0610d9a 100644
>> --- a/drivers/net/dsa/mv88e6xxx/global1.h
>> +++ b/drivers/net/dsa/mv88e6xxx/global1.h
>> @@ -136,6 +136,7 @@
>>  #define MV88E6XXX_G1_ATU_DATA_TRUNK				0x8000
>>  #define MV88E6XXX_G1_ATU_DATA_TRUNK_ID_MASK			0x00f0
>>  #define MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_MASK			0x3ff0
>> +#define MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_NO_EGRESS		0x0000
>>  #define MV88E6XXX_G1_ATU_DATA_STATE_MASK			0x000f
>>  #define MV88E6XXX_G1_ATU_DATA_STATE_UC_UNUSED			0x0000
>>  #define MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_1_OLDEST		0x0001
>> diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c
>> index 40bd67a5c8e9..afa54fe8667e 100644
>> --- a/drivers/net/dsa/mv88e6xxx/global1_atu.c
>> +++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c
>> @@ -12,6 +12,8 @@
>>  
>>  #include "chip.h"
>>  #include "global1.h"
>> +#include "port.h"
>> +#include "mv88e6xxx_switchdev.h"
>>  
>>  /* Offset 0x01: ATU FID Register */
>>  
>> @@ -114,6 +116,18 @@ static int mv88e6xxx_g1_atu_op_wait(struct mv88e6xxx_chip *chip)
>>  	return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_ATU_OP, bit, 0);
>>  }
>>  
>> +static int mv88e6xxx_g1_read_atu_violation(struct mv88e6xxx_chip *chip)
>> +{
>> +	int err;
>> +
>> +	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_OP,
>> +				 MV88E6XXX_G1_ATU_OP_BUSY | MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION);
>> +	if (err)
>> +		return err;
>> +
>> +	return mv88e6xxx_g1_atu_op_wait(chip);
>> +}
>> +
>>  static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op)
>>  {
>>  	u16 val;
>> @@ -356,11 +370,11 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
>>  	int spid;
>>  	int err;
>>  	u16 val;
>> +	u16 fid;
>>  
>>  	mv88e6xxx_reg_lock(chip);
>>  
>> -	err = mv88e6xxx_g1_atu_op(chip, 0,
>> -				  MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION);
>> +	err = mv88e6xxx_g1_read_atu_violation(chip);
>>  	if (err)
>>  		goto out;
>>  
>> @@ -368,6 +382,10 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
>>  	if (err)
>>  		goto out;
>>  
>> +	err = mv88e6xxx_g1_read(chip, MV88E6352_G1_ATU_FID, &fid);
>> +	if (err)
>> +		goto out;
>> +
>>  	err = mv88e6xxx_g1_atu_data_read(chip, &entry);
>>  	if (err)
>>  		goto out;
>> @@ -396,6 +414,13 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
>>  				    "ATU miss violation for %pM portvec %x spid %d\n",
>>  				    entry.mac, entry.portvec, spid);
>>  		chip->ports[spid].atu_miss_violation++;
>> +		if (mv88e6xxx_port_is_locked(chip, chip->ports[spid].port))
>> +			err = mv88e6xxx_switchdev_handle_atu_miss_violation(chip,
>> +									    chip->ports[spid].port,
>> +									    &entry,
>> +									    fid);
>
> Do we want to suppress the ATU miss violation warnings if we're going to
> notify the bridge, or is it better to keep them for some reason?
> My logic is that they're part of normal operation, so suppressing makes
> sense.
>

Only one issue is that the ATU miss violations would not be reported on
ports that are not locked, while the bridge will not be notified either.

>> +		if (err)
>> +			goto out;
>>  	}
>>  
>>  	if (val & MV88E6XXX_G1_ATU_OP_FULL_VIOLATION) {
>> diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c
>> new file mode 100644
>> index 000000000000..e0ca452b6f86
>> --- /dev/null
>> +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c
>> @@ -0,0 +1,67 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * mv88e6xxx_switchdev.c
>> + *
>> + *	Authors:
>> + *	Hans J. Schultz		<hans.schultz@westermo.com>
>> + *
>> + */
>> +
>> +#include <net/switchdev.h>
>> +#include "chip.h"
>> +#include "global1.h"
>> +
>> +struct mv88e6xxx_fid_search_ctx {
>> +	u16 fid_search;
>> +	u16 vid_found;
>> +};
>> +
>> +static int mv88e6xxx_find_vid_on_matching_fid(struct mv88e6xxx_chip *chip,
>> +					      const struct mv88e6xxx_vtu_entry *entry,
>> +					      void *priv)
>> +{
>> +	struct mv88e6xxx_fid_search_ctx *ctx = priv;
>> +
>> +	if (ctx->fid_search == entry->fid) {
>> +		ctx->vid_found = entry->vid;
>> +		return 1;
>> +	}
>> +	return 0;
>> +}
>> +
>> +int mv88e6xxx_switchdev_handle_atu_miss_violation(struct mv88e6xxx_chip *chip,
>> +						  int port,
>> +						  struct mv88e6xxx_atu_entry *entry,
>> +						  u16 fid)
>> +{
>> +	struct switchdev_notifier_fdb_info info = {
>> +		.addr = entry->mac,
>> +		.vid = 0,
>> +		.added_by_user = false,
>> +		.is_local = false,
>> +		.offloaded = true,
>> +		.locked = true,
>> +	};
>> +	struct mv88e6xxx_fid_search_ctx ctx;
>> +	struct netlink_ext_ack *extack;
>> +	struct net_device *brport;
>> +	struct dsa_port *dp;
>> +	int err;
>> +
>> +	ctx.fid_search = fid;
>> +	err = mv88e6xxx_vtu_walk(chip, mv88e6xxx_find_vid_on_matching_fid, &ctx);
>> +	if (err < 0)
>> +		return err;
>> +	if (err == 1)
>> +		info.vid = ctx.vid_found;
>> +	else
>> +		return -ENODATA;
>> +
>> +	dp = dsa_to_port(chip->ds, port);
>> +	brport = dsa_port_to_bridge_port(dp);
>
> Since this is threaded interrupt context, I suppose it could race with
> dsa_port_bridge_leave(). So it is best to check whether "brport" is NULL
> or not.
>
> Speaking of races with dsa_port_bridge_leave().. does SWITCHDEV_FDB_ADD_TO_BRIDGE
> not require rtnl_lock?
>
>> +	err = call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE, brport, &info.info, extack);
>
> It is buggy to pass an uninitialized on-stack extack, just pass NULL if
> there's no one to consume it.
>
> Alternatively, if the bridge produces a valid extack message for errors
> in this case (I haven't checked), it may be more useful to manually
> print the extack._msg to the kernel log - see dsa_switch_sync_vlan_filtering()
> for an example.
>
> I am a bit uncomfortable having every driver implement this ad-hoc and
> potentially have a gazillion subtle bugs like these, could we have a
> common function exported by DSA that deals with SWITCHDEV_FDB_ADD_TO_BRIDGE?
>
>> +	if (err)
>> +		return err;
>> +	entry->portvec = MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_NO_EGRESS;
>> +	return mv88e6xxx_g1_atu_loadpurge(chip, fid, entry);
>> +}
>> diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h
>> new file mode 100644
>> index 000000000000..127f3098f745
>> --- /dev/null
>> +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h
>> @@ -0,0 +1,20 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later
>> + *
>> + * mv88e6xxx_switchdev.h
>> + *
>> + *	Authors:
>> + *	Hans J. Schultz		<hans.schultz@westermo.com>
>> + *
>> + */
>> +
>> +#ifndef DRIVERS_NET_DSA_MV88E6XXX_MV88E6XXX_SWITCHDEV_H_
>> +#define DRIVERS_NET_DSA_MV88E6XXX_MV88E6XXX_SWITCHDEV_H_
>> +
>> +#include <net/switchdev.h>
>> +
>> +int mv88e6xxx_switchdev_handle_atu_miss_violation(struct mv88e6xxx_chip *chip,
>> +						  int port,
>> +						  struct mv88e6xxx_atu_entry *entry,
>> +						  u16 fid);
>> +
>> +#endif /* DRIVERS_NET_DSA_MV88E6XXX_MV88E6XXX_SWITCHDEV_H_ */
>> diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
>> index 795b3128768f..6b375b0caa2c 100644
>> --- a/drivers/net/dsa/mv88e6xxx/port.c
>> +++ b/drivers/net/dsa/mv88e6xxx/port.c
>> @@ -1239,6 +1239,17 @@ int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,
>>  	return err;
>>  }
>>  
>> +bool mv88e6xxx_port_is_locked(struct mv88e6xxx_chip *chip, int port)
>> +{
>> +	u16 reg;
>> +
>> +	if (mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg))
>> +		return false;
>> +	if (!(reg & MV88E6XXX_PORT_CTL0_SA_FILT_DROP_ON_LOCK))
>> +		return false;
>> +	return true;
>> +}
>> +
>>  int mv88e6xxx_port_set_lock(struct mv88e6xxx_chip *chip, int port,
>>  			    bool locked)
>>  {
>> diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h
>> index e0a705d82019..09ea8f1615bb 100644
>> --- a/drivers/net/dsa/mv88e6xxx/port.h
>> +++ b/drivers/net/dsa/mv88e6xxx/port.h
>> @@ -374,6 +374,7 @@ int mv88e6xxx_port_set_fid(struct mv88e6xxx_chip *chip, int port, u16 fid);
>>  int mv88e6xxx_port_get_pvid(struct mv88e6xxx_chip *chip, int port, u16 *pvid);
>>  int mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid);
>>  
>> +bool mv88e6xxx_port_is_locked(struct mv88e6xxx_chip *chip, int port);
>>  int mv88e6xxx_port_set_lock(struct mv88e6xxx_chip *chip, int port,
>>  			    bool locked);
>>  
>> -- 
>> 2.30.2
>> 

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-10 15:51         ` Hans Schultz
@ 2022-03-10 16:05           ` Vladimir Oltean
  2022-03-10 16:40             ` Hans Schultz
  0 siblings, 1 reply; 63+ messages in thread
From: Vladimir Oltean @ 2022-03-10 16:05 UTC (permalink / raw)
  To: Hans Schultz
  Cc: davem, kuba, netdev, Andrew Lunn, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On Thu, Mar 10, 2022 at 04:51:15PM +0100, Hans Schultz wrote:
> On tor, mar 10, 2022 at 17:07, Vladimir Oltean <olteanv@gmail.com> wrote:
> > On Thu, Mar 10, 2022 at 04:00:52PM +0100, Hans Schultz wrote:
> >> >> +	brport = dsa_port_to_bridge_port(dp);
> >> >
> >> > Since this is threaded interrupt context, I suppose it could race with
> >> > dsa_port_bridge_leave(). So it is best to check whether "brport" is NULL
> >> > or not.
> >> >
> >> Would something like:
> >> if (dsa_is_unused_port(chip->ds, port))
> >>         return -ENODATA;
> >> 
> >> be appropriate and sufficient for that?
> >
> > static inline
> > struct net_device *dsa_port_to_bridge_port(const struct dsa_port *dp)
> > {
> > 	if (!dp->bridge)
> > 		return NULL;
> >
> > 	if (dp->lag)
> > 		return dp->lag->dev;
> > 	else if (dp->hsr_dev)
> > 		return dp->hsr_dev;
> >
> > 	return dp->slave;
> > }
> >
> > Notice the "dp->bridge" check. The assignments are in dsa_port_bridge_create()
> > and in dsa_port_bridge_destroy(). These functions assume rtnl_mutex protection.
> > The question was how do you serialize with that, and why do you assume
> > that dsa_port_to_bridge_port() returns non-NULL.
> >
> > So no, dsa_is_unused_port() would do absolutely nothing to help.
> 
> I was thinking in indirect terms (dangerous I know :-).

Sorry, I don't understand what you mean by "indirect terms". An "unused
port" is one with 'status = "disabled";' in the device tree. I would
expect that you don't need to handle FDB entries towards such a port!

You have a port receiving traffic with an unknown {MAC SA, VID}.
When the port is configured as locked by the bridge, this traffic will
generate ATU miss interrupts. These will be handled in an interrupt
thread that is scheduled to be handled some time in the future.
In between the moment when the packet is received and the moment when
the interrupt thread runs, a user could run "ip link set lan0 nomaster".
Then the interrupt thread would notify the bridge about these entries,
point during which a bridge port no longer exists => NULL pointer dereference.
By taking the rtnl_lock() and then checking whether dsa_port_to_bridge_port()
is NULL, you figure out whether the interrupt handler ran completely
before dsa_port_bridge_leave(), or completely after dsa_port_bridge_leave().

> 
> But wrt the nl lock, I wonder when other threads could pull the carpet
> away under this, and so I might have to wait till after the last call
> (mv88e6xxx_g1_atu_loadpurge) to free the nl lock?

That might make sense. It means: if the user runs "ip link set lan0 nomaster",
wait until I've notified the bridge and installed the entry to my own
ATU, so that they're in sync. Then, del_nbp() -> br_fdb_delete_by_port()
would come in, find that entry notified by us (I think!) and remove it.
If you call rtnl_unlock() too early, it might be possible that the ATU
entry remains lingering (unless I'm missing some subtle implicit
serialization based on mv88e6xxx_reg_lock() or similar).

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 1/3] net: bridge: add fdb flag to extent locked port feature
  2022-03-10 15:57       ` Nikolay Aleksandrov
@ 2022-03-10 16:11         ` Hans Schultz
  2022-03-10 16:14           ` Nikolay Aleksandrov
  0 siblings, 1 reply; 63+ messages in thread
From: Hans Schultz @ 2022-03-10 16:11 UTC (permalink / raw)
  To: Nikolay Aleksandrov, Hans Schultz, davem, kuba
  Cc: netdev, Andrew Lunn, Vivien Didelot, Florian Fainelli,
	Vladimir Oltean, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Daniel Borkmann, Ido Schimmel, linux-kernel, bridge

On tor, mar 10, 2022 at 17:57, Nikolay Aleksandrov <razor@blackwall.org> wrote:
> On 10/03/2022 17:38, Hans Schultz wrote:
>> On tor, mar 10, 2022 at 16:42, Nikolay Aleksandrov <razor@blackwall.org> wrote:
>>> On 10/03/2022 16:23, Hans Schultz wrote:
>>>> Add an intermediate state for clients behind a locked port to allow for
>>>> possible opening of the port for said clients. This feature corresponds
>>>> to the Mac-Auth and MAC Authentication Bypass (MAB) named features. The
>>>> latter defined by Cisco.
>>>>
>>>> Signed-off-by: Hans Schultz <schultz.hans+netdev@gmail.com>
>>>> ---
>>>>    include/uapi/linux/neighbour.h |  1 +
>>>>    net/bridge/br_fdb.c            |  6 ++++++
>>>>    net/bridge/br_input.c          | 11 ++++++++++-
>>>>    net/bridge/br_private.h        |  3 ++-
>>>>    4 files changed, 19 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/include/uapi/linux/neighbour.h b/include/uapi/linux/neighbour.h
>>>> index db05fb55055e..83115a592d58 100644
>>>> --- a/include/uapi/linux/neighbour.h
>>>> +++ b/include/uapi/linux/neighbour.h
>>>> @@ -208,6 +208,7 @@ enum {
>>>>    	NFEA_UNSPEC,
>>>>    	NFEA_ACTIVITY_NOTIFY,
>>>>    	NFEA_DONT_REFRESH,
>>>> +	NFEA_LOCKED,
>>>>    	__NFEA_MAX
>>>>    };
>>>
>>> Hmm, can you use NDA_FLAGS_EXT instead ?
>>> That should simplify things and reduce the nl size.
>>>
>> 
>> I am using NDA_FDB_EXT_ATTRS. NFEA_LOCKED is just the
>> flag as the other flags section is full wrt the normal flags, but maybe it
>> doesn't fit in that section?
>> 
>
> Actually wait a second, this is completely wrong use of NDA_FDB_EXT_ATTRS.
> That is a nested attribute, so the code below is wrong. More below..
>
>> I will just note that iproute2 support for parsing nested attributes
>> does not work, thus the BR_FDB_NOTIFY section (lines 150-165) are
>> obsolete with respect to iproute2 as it is now. I cannot rule out that
>> someone has some other tool that can handle this BR_FDB_NOTIFY, but I
>> could not make iproute2 as it stands handle nested attributes. And of
>> course there is no handling of NDA_FDB_EXT_ATTRS in iproute2 now.
>> >>>    #define NFEA_MAX (__NFEA_MAX - 1)
>>>> diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
>>>> index 6ccda68bd473..396dcf3084cf 100644
>>>> --- a/net/bridge/br_fdb.c
>>>> +++ b/net/bridge/br_fdb.c
>>>> @@ -105,6 +105,7 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
>>>>    	struct nda_cacheinfo ci;
>>>>    	struct nlmsghdr *nlh;
>>>>    	struct ndmsg *ndm;
>>>> +	u8 ext_flags = 0;
>>>>    
>>>>    	nlh = nlmsg_put(skb, portid, seq, type, sizeof(*ndm), flags);
>>>>    	if (nlh == NULL)
>>>> @@ -125,11 +126,16 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
>>>>    		ndm->ndm_flags |= NTF_EXT_LEARNED;
>>>>    	if (test_bit(BR_FDB_STICKY, &fdb->flags))
>>>>    		ndm->ndm_flags |= NTF_STICKY;
>>>> +	if (test_bit(BR_FDB_ENTRY_LOCKED, &fdb->flags))
>>>> +		ext_flags |= 1 << NFEA_LOCKED;
>>>>    
>>>>    	if (nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->key.addr))
>>>>    		goto nla_put_failure;
>>>>    	if (nla_put_u32(skb, NDA_MASTER, br->dev->ifindex))
>>>>    		goto nla_put_failure;
>>>> +	if (nla_put_u8(skb, NDA_FDB_EXT_ATTRS, ext_flags))
>>>> +		goto nla_put_failure;
>>>> +
>
> This is wrong. NDA_FDB_EXT_ATTRS is a nested attribute, you can't use it as a u8.
> You need to have this structure:
>   [ NDA_FDB_EXT_ATTRS ]
>    ` [ NFEA_LOCKED ]
>
> But that's why I asked if you could use the NDA_FLAGS_EXT attribute. You can see
> the logic from the neigh code.

Ahh yes, NDA_FLAGS_EXT was not there in the 5.15.x kernel I have
originally being making the patches in.

I hope that the handling of nested attributes has been fixed in
iproute2. ;-)

>
> Also note that you need to account for the new attribute's size in fdb_nlmsg_size().
>
>
>>>>    	ci.ndm_used	 = jiffies_to_clock_t(now - fdb->used);
>>>>    	ci.ndm_confirmed = 0;
>>>>    	ci.ndm_updated	 = jiffies_to_clock_t(now - fdb->updated);
>>>> diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
>>>> index e0c13fcc50ed..897908484b18 100644
>>>> --- a/net/bridge/br_input.c
>>>> +++ b/net/bridge/br_input.c
>>>> @@ -75,6 +75,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
>>>>    	struct net_bridge_mcast *brmctx;
>>>>    	struct net_bridge_vlan *vlan;
>>>>    	struct net_bridge *br;
>>>> +	unsigned long flags = 0;
>>>
>>> Please move this below...
>>>
>>>>    	u16 vid = 0;
>>>>    	u8 state;
>>>>    
>>>> @@ -94,8 +95,16 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
>>>>    			br_fdb_find_rcu(br, eth_hdr(skb)->h_source, vid);
>>>>    
>>>>    		if (!fdb_src || READ_ONCE(fdb_src->dst) != p ||
>>>> -		    test_bit(BR_FDB_LOCAL, &fdb_src->flags))
>>>> +		    test_bit(BR_FDB_LOCAL, &fdb_src->flags)) {
>>>> +			if (!fdb_src) {
>>>
>>> ... here where it's only used.
>>>
>> 
>> Forgot that one. Shall do!
>> 
>>>> +				set_bit(BR_FDB_ENTRY_LOCKED, &flags);
>>>> +				br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, flags);
>>>> +			}
>>>>    			goto drop;
>>>> +		} else {
>>>> +			if (test_bit(BR_FDB_ENTRY_LOCKED, &fdb_src->flags))
>>>> +				goto drop;
>>>> +		}
>>>>    	}
>>>>    
>>>>    	nbp_switchdev_frame_mark(p, skb);
>>>> diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
>>>> index 48bc61ebc211..f5a0b68c4857 100644
>>>> --- a/net/bridge/br_private.h
>>>> +++ b/net/bridge/br_private.h
>>>> @@ -248,7 +248,8 @@ enum {
>>>>    	BR_FDB_ADDED_BY_EXT_LEARN,
>>>>    	BR_FDB_OFFLOADED,
>>>>    	BR_FDB_NOTIFY,
>>>> -	BR_FDB_NOTIFY_INACTIVE
>>>> +	BR_FDB_NOTIFY_INACTIVE,
>>>> +	BR_FDB_ENTRY_LOCKED,
>>>>    };
>>>>    
>>>>    struct net_bridge_fdb_key {

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 1/3] net: bridge: add fdb flag to extent locked port feature
  2022-03-10 16:11         ` Hans Schultz
@ 2022-03-10 16:14           ` Nikolay Aleksandrov
  2022-03-10 16:33             ` Hans Schultz
  0 siblings, 1 reply; 63+ messages in thread
From: Nikolay Aleksandrov @ 2022-03-10 16:14 UTC (permalink / raw)
  To: Hans Schultz, davem, kuba
  Cc: netdev, Andrew Lunn, Vivien Didelot, Florian Fainelli,
	Vladimir Oltean, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Daniel Borkmann, Ido Schimmel, linux-kernel, bridge

On 10/03/2022 18:11, Hans Schultz wrote:
> On tor, mar 10, 2022 at 17:57, Nikolay Aleksandrov <razor@blackwall.org> wrote:
>> On 10/03/2022 17:38, Hans Schultz wrote:
>>> On tor, mar 10, 2022 at 16:42, Nikolay Aleksandrov <razor@blackwall.org> wrote:
>>>> On 10/03/2022 16:23, Hans Schultz wrote:
>>>>> Add an intermediate state for clients behind a locked port to allow for
>>>>> possible opening of the port for said clients. This feature corresponds
>>>>> to the Mac-Auth and MAC Authentication Bypass (MAB) named features. The
>>>>> latter defined by Cisco.
>>>>>
>>>>> Signed-off-by: Hans Schultz <schultz.hans+netdev@gmail.com>
>>>>> ---
>>>>>     include/uapi/linux/neighbour.h |  1 +
>>>>>     net/bridge/br_fdb.c            |  6 ++++++
>>>>>     net/bridge/br_input.c          | 11 ++++++++++-
>>>>>     net/bridge/br_private.h        |  3 ++-
>>>>>     4 files changed, 19 insertions(+), 2 deletions(-)
>>>>>
>>>>> diff --git a/include/uapi/linux/neighbour.h b/include/uapi/linux/neighbour.h
>>>>> index db05fb55055e..83115a592d58 100644
>>>>> --- a/include/uapi/linux/neighbour.h
>>>>> +++ b/include/uapi/linux/neighbour.h
>>>>> @@ -208,6 +208,7 @@ enum {
>>>>>     	NFEA_UNSPEC,
>>>>>     	NFEA_ACTIVITY_NOTIFY,
>>>>>     	NFEA_DONT_REFRESH,
>>>>> +	NFEA_LOCKED,
>>>>>     	__NFEA_MAX
>>>>>     };
>>>>
>>>> Hmm, can you use NDA_FLAGS_EXT instead ?
>>>> That should simplify things and reduce the nl size.
>>>>
>>>
>>> I am using NDA_FDB_EXT_ATTRS. NFEA_LOCKED is just the
>>> flag as the other flags section is full wrt the normal flags, but maybe it
>>> doesn't fit in that section?
>>>
>>
>> Actually wait a second, this is completely wrong use of NDA_FDB_EXT_ATTRS.
>> That is a nested attribute, so the code below is wrong. More below..
>>
>>> I will just note that iproute2 support for parsing nested attributes
>>> does not work, thus the BR_FDB_NOTIFY section (lines 150-165) are
>>> obsolete with respect to iproute2 as it is now. I cannot rule out that
>>> someone has some other tool that can handle this BR_FDB_NOTIFY, but I
>>> could not make iproute2 as it stands handle nested attributes. And of
>>> course there is no handling of NDA_FDB_EXT_ATTRS in iproute2 now.
>>>>>>     #define NFEA_MAX (__NFEA_MAX - 1)
>>>>> diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
>>>>> index 6ccda68bd473..396dcf3084cf 100644
>>>>> --- a/net/bridge/br_fdb.c
>>>>> +++ b/net/bridge/br_fdb.c
>>>>> @@ -105,6 +105,7 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
>>>>>     	struct nda_cacheinfo ci;
>>>>>     	struct nlmsghdr *nlh;
>>>>>     	struct ndmsg *ndm;
>>>>> +	u8 ext_flags = 0;
>>>>>     
>>>>>     	nlh = nlmsg_put(skb, portid, seq, type, sizeof(*ndm), flags);
>>>>>     	if (nlh == NULL)
>>>>> @@ -125,11 +126,16 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
>>>>>     		ndm->ndm_flags |= NTF_EXT_LEARNED;
>>>>>     	if (test_bit(BR_FDB_STICKY, &fdb->flags))
>>>>>     		ndm->ndm_flags |= NTF_STICKY;
>>>>> +	if (test_bit(BR_FDB_ENTRY_LOCKED, &fdb->flags))
>>>>> +		ext_flags |= 1 << NFEA_LOCKED;
>>>>>     
>>>>>     	if (nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->key.addr))
>>>>>     		goto nla_put_failure;
>>>>>     	if (nla_put_u32(skb, NDA_MASTER, br->dev->ifindex))
>>>>>     		goto nla_put_failure;
>>>>> +	if (nla_put_u8(skb, NDA_FDB_EXT_ATTRS, ext_flags))
>>>>> +		goto nla_put_failure;
>>>>> +
>>
>> This is wrong. NDA_FDB_EXT_ATTRS is a nested attribute, you can't use it as a u8.
>> You need to have this structure:
>>    [ NDA_FDB_EXT_ATTRS ]
>>     ` [ NFEA_LOCKED ]
>>
>> But that's why I asked if you could use the NDA_FLAGS_EXT attribute. You can see
>> the logic from the neigh code.
> 
> Ahh yes, NDA_FLAGS_EXT was not there in the 5.15.x kernel I have
> originally being making the patches in.
> 
> I hope that the handling of nested attributes has been fixed in
> iproute2. ;-)
> 

It hasn't been broken, I'm guessing you're having issues with the nested bit being set.
Check NLA_F_NESTED and NLA_TYPE_MASK.

>>
>> Also note that you need to account for the new attribute's size in fdb_nlmsg_size().
>>
>>
>>>>>     	ci.ndm_used	 = jiffies_to_clock_t(now - fdb->used);
>>>>>     	ci.ndm_confirmed = 0;
>>>>>     	ci.ndm_updated	 = jiffies_to_clock_t(now - fdb->updated);
>>>>> diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
>>>>> index e0c13fcc50ed..897908484b18 100644
>>>>> --- a/net/bridge/br_input.c
>>>>> +++ b/net/bridge/br_input.c
>>>>> @@ -75,6 +75,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
>>>>>     	struct net_bridge_mcast *brmctx;
>>>>>     	struct net_bridge_vlan *vlan;
>>>>>     	struct net_bridge *br;
>>>>> +	unsigned long flags = 0;
>>>>
>>>> Please move this below...
>>>>
>>>>>     	u16 vid = 0;
>>>>>     	u8 state;
>>>>>     
>>>>> @@ -94,8 +95,16 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
>>>>>     			br_fdb_find_rcu(br, eth_hdr(skb)->h_source, vid);
>>>>>     
>>>>>     		if (!fdb_src || READ_ONCE(fdb_src->dst) != p ||
>>>>> -		    test_bit(BR_FDB_LOCAL, &fdb_src->flags))
>>>>> +		    test_bit(BR_FDB_LOCAL, &fdb_src->flags)) {
>>>>> +			if (!fdb_src) {
>>>>
>>>> ... here where it's only used.
>>>>
>>>
>>> Forgot that one. Shall do!
>>>
>>>>> +				set_bit(BR_FDB_ENTRY_LOCKED, &flags);
>>>>> +				br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, flags);
>>>>> +			}
>>>>>     			goto drop;
>>>>> +		} else {
>>>>> +			if (test_bit(BR_FDB_ENTRY_LOCKED, &fdb_src->flags))
>>>>> +				goto drop;
>>>>> +		}
>>>>>     	}
>>>>>     
>>>>>     	nbp_switchdev_frame_mark(p, skb);
>>>>> diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
>>>>> index 48bc61ebc211..f5a0b68c4857 100644
>>>>> --- a/net/bridge/br_private.h
>>>>> +++ b/net/bridge/br_private.h
>>>>> @@ -248,7 +248,8 @@ enum {
>>>>>     	BR_FDB_ADDED_BY_EXT_LEARN,
>>>>>     	BR_FDB_OFFLOADED,
>>>>>     	BR_FDB_NOTIFY,
>>>>> -	BR_FDB_NOTIFY_INACTIVE
>>>>> +	BR_FDB_NOTIFY_INACTIVE,
>>>>> +	BR_FDB_ENTRY_LOCKED,
>>>>>     };
>>>>>     
>>>>>     struct net_bridge_fdb_key {


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 1/3] net: bridge: add fdb flag to extent locked port feature
  2022-03-10 16:14           ` Nikolay Aleksandrov
@ 2022-03-10 16:33             ` Hans Schultz
  0 siblings, 0 replies; 63+ messages in thread
From: Hans Schultz @ 2022-03-10 16:33 UTC (permalink / raw)
  To: Nikolay Aleksandrov, Hans Schultz, davem, kuba
  Cc: netdev, Andrew Lunn, Vivien Didelot, Florian Fainelli,
	Vladimir Oltean, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Daniel Borkmann, Ido Schimmel, linux-kernel, bridge

On tor, mar 10, 2022 at 18:14, Nikolay Aleksandrov <razor@blackwall.org> wrote:
> On 10/03/2022 18:11, Hans Schultz wrote:
>> On tor, mar 10, 2022 at 17:57, Nikolay Aleksandrov <razor@blackwall.org> wrote:
>>> On 10/03/2022 17:38, Hans Schultz wrote:
>>>> On tor, mar 10, 2022 at 16:42, Nikolay Aleksandrov <razor@blackwall.org> wrote:
>>>>> On 10/03/2022 16:23, Hans Schultz wrote:
>>>>>> Add an intermediate state for clients behind a locked port to allow for
>>>>>> possible opening of the port for said clients. This feature corresponds
>>>>>> to the Mac-Auth and MAC Authentication Bypass (MAB) named features. The
>>>>>> latter defined by Cisco.
>>>>>>
>>>>>> Signed-off-by: Hans Schultz <schultz.hans+netdev@gmail.com>
>>>>>> ---
>>>>>>     include/uapi/linux/neighbour.h |  1 +
>>>>>>     net/bridge/br_fdb.c            |  6 ++++++
>>>>>>     net/bridge/br_input.c          | 11 ++++++++++-
>>>>>>     net/bridge/br_private.h        |  3 ++-
>>>>>>     4 files changed, 19 insertions(+), 2 deletions(-)
>>>>>>
>>>>>> diff --git a/include/uapi/linux/neighbour.h b/include/uapi/linux/neighbour.h
>>>>>> index db05fb55055e..83115a592d58 100644
>>>>>> --- a/include/uapi/linux/neighbour.h
>>>>>> +++ b/include/uapi/linux/neighbour.h
>>>>>> @@ -208,6 +208,7 @@ enum {
>>>>>>     	NFEA_UNSPEC,
>>>>>>     	NFEA_ACTIVITY_NOTIFY,
>>>>>>     	NFEA_DONT_REFRESH,
>>>>>> +	NFEA_LOCKED,
>>>>>>     	__NFEA_MAX
>>>>>>     };
>>>>>
>>>>> Hmm, can you use NDA_FLAGS_EXT instead ?
>>>>> That should simplify things and reduce the nl size.
>>>>>
>>>>
>>>> I am using NDA_FDB_EXT_ATTRS. NFEA_LOCKED is just the
>>>> flag as the other flags section is full wrt the normal flags, but maybe it
>>>> doesn't fit in that section?
>>>>
>>>
>>> Actually wait a second, this is completely wrong use of NDA_FDB_EXT_ATTRS.
>>> That is a nested attribute, so the code below is wrong. More below..
>>>
>>>> I will just note that iproute2 support for parsing nested attributes
>>>> does not work, thus the BR_FDB_NOTIFY section (lines 150-165) are
>>>> obsolete with respect to iproute2 as it is now. I cannot rule out that
>>>> someone has some other tool that can handle this BR_FDB_NOTIFY, but I
>>>> could not make iproute2 as it stands handle nested attributes. And of
>>>> course there is no handling of NDA_FDB_EXT_ATTRS in iproute2 now.
>>>>>>>     #define NFEA_MAX (__NFEA_MAX - 1)
>>>>>> diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
>>>>>> index 6ccda68bd473..396dcf3084cf 100644
>>>>>> --- a/net/bridge/br_fdb.c
>>>>>> +++ b/net/bridge/br_fdb.c
>>>>>> @@ -105,6 +105,7 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
>>>>>>     	struct nda_cacheinfo ci;
>>>>>>     	struct nlmsghdr *nlh;
>>>>>>     	struct ndmsg *ndm;
>>>>>> +	u8 ext_flags = 0;
>>>>>>     
>>>>>>     	nlh = nlmsg_put(skb, portid, seq, type, sizeof(*ndm), flags);
>>>>>>     	if (nlh == NULL)
>>>>>> @@ -125,11 +126,16 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
>>>>>>     		ndm->ndm_flags |= NTF_EXT_LEARNED;
>>>>>>     	if (test_bit(BR_FDB_STICKY, &fdb->flags))
>>>>>>     		ndm->ndm_flags |= NTF_STICKY;
>>>>>> +	if (test_bit(BR_FDB_ENTRY_LOCKED, &fdb->flags))
>>>>>> +		ext_flags |= 1 << NFEA_LOCKED;
>>>>>>     
>>>>>>     	if (nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->key.addr))
>>>>>>     		goto nla_put_failure;
>>>>>>     	if (nla_put_u32(skb, NDA_MASTER, br->dev->ifindex))
>>>>>>     		goto nla_put_failure;
>>>>>> +	if (nla_put_u8(skb, NDA_FDB_EXT_ATTRS, ext_flags))
>>>>>> +		goto nla_put_failure;
>>>>>> +
>>>
>>> This is wrong. NDA_FDB_EXT_ATTRS is a nested attribute, you can't use it as a u8.
>>> You need to have this structure:
>>>    [ NDA_FDB_EXT_ATTRS ]
>>>     ` [ NFEA_LOCKED ]
>>>
>>> But that's why I asked if you could use the NDA_FLAGS_EXT attribute. You can see
>>> the logic from the neigh code.
>> 
>> Ahh yes, NDA_FLAGS_EXT was not there in the 5.15.x kernel I have
>> originally being making the patches in.
>> 
>> I hope that the handling of nested attributes has been fixed in
>> iproute2. ;-)
>> 
>
> It hasn't been broken, I'm guessing you're having issues with the nested bit being set.
> Check NLA_F_NESTED and NLA_TYPE_MASK.
>

Hmmm, then I wonder why I could not make the same code as in the said
lines (150-165) in br_fdb.c give any parsed attributes in iproute2 under
tb[NDA_FDB_EXT_ATTR].

Did I miss something, or are those lines incorrect?

>>>
>>> Also note that you need to account for the new attribute's size in fdb_nlmsg_size().
>>>
>>>
>>>>>>     	ci.ndm_used	 = jiffies_to_clock_t(now - fdb->used);
>>>>>>     	ci.ndm_confirmed = 0;
>>>>>>     	ci.ndm_updated	 = jiffies_to_clock_t(now - fdb->updated);
>>>>>> diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
>>>>>> index e0c13fcc50ed..897908484b18 100644
>>>>>> --- a/net/bridge/br_input.c
>>>>>> +++ b/net/bridge/br_input.c
>>>>>> @@ -75,6 +75,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
>>>>>>     	struct net_bridge_mcast *brmctx;
>>>>>>     	struct net_bridge_vlan *vlan;
>>>>>>     	struct net_bridge *br;
>>>>>> +	unsigned long flags = 0;
>>>>>
>>>>> Please move this below...
>>>>>
>>>>>>     	u16 vid = 0;
>>>>>>     	u8 state;
>>>>>>     
>>>>>> @@ -94,8 +95,16 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
>>>>>>     			br_fdb_find_rcu(br, eth_hdr(skb)->h_source, vid);
>>>>>>     
>>>>>>     		if (!fdb_src || READ_ONCE(fdb_src->dst) != p ||
>>>>>> -		    test_bit(BR_FDB_LOCAL, &fdb_src->flags))
>>>>>> +		    test_bit(BR_FDB_LOCAL, &fdb_src->flags)) {
>>>>>> +			if (!fdb_src) {
>>>>>
>>>>> ... here where it's only used.
>>>>>
>>>>
>>>> Forgot that one. Shall do!
>>>>
>>>>>> +				set_bit(BR_FDB_ENTRY_LOCKED, &flags);
>>>>>> +				br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, flags);
>>>>>> +			}
>>>>>>     			goto drop;
>>>>>> +		} else {
>>>>>> +			if (test_bit(BR_FDB_ENTRY_LOCKED, &fdb_src->flags))
>>>>>> +				goto drop;
>>>>>> +		}
>>>>>>     	}
>>>>>>     
>>>>>>     	nbp_switchdev_frame_mark(p, skb);
>>>>>> diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
>>>>>> index 48bc61ebc211..f5a0b68c4857 100644
>>>>>> --- a/net/bridge/br_private.h
>>>>>> +++ b/net/bridge/br_private.h
>>>>>> @@ -248,7 +248,8 @@ enum {
>>>>>>     	BR_FDB_ADDED_BY_EXT_LEARN,
>>>>>>     	BR_FDB_OFFLOADED,
>>>>>>     	BR_FDB_NOTIFY,
>>>>>> -	BR_FDB_NOTIFY_INACTIVE
>>>>>> +	BR_FDB_NOTIFY_INACTIVE,
>>>>>> +	BR_FDB_ENTRY_LOCKED,
>>>>>>     };
>>>>>>     
>>>>>>     struct net_bridge_fdb_key {

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-10 16:05           ` Vladimir Oltean
@ 2022-03-10 16:40             ` Hans Schultz
  0 siblings, 0 replies; 63+ messages in thread
From: Hans Schultz @ 2022-03-10 16:40 UTC (permalink / raw)
  To: Vladimir Oltean, Hans Schultz
  Cc: davem, kuba, netdev, Andrew Lunn, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On tor, mar 10, 2022 at 18:05, Vladimir Oltean <olteanv@gmail.com> wrote:
> On Thu, Mar 10, 2022 at 04:51:15PM +0100, Hans Schultz wrote:
>> On tor, mar 10, 2022 at 17:07, Vladimir Oltean <olteanv@gmail.com> wrote:
>> > On Thu, Mar 10, 2022 at 04:00:52PM +0100, Hans Schultz wrote:
>> >> >> +	brport = dsa_port_to_bridge_port(dp);
>> >> >
>> >> > Since this is threaded interrupt context, I suppose it could race with
>> >> > dsa_port_bridge_leave(). So it is best to check whether "brport" is NULL
>> >> > or not.
>> >> >
>> >> Would something like:
>> >> if (dsa_is_unused_port(chip->ds, port))
>> >>         return -ENODATA;
>> >> 
>> >> be appropriate and sufficient for that?
>> >
>> > static inline
>> > struct net_device *dsa_port_to_bridge_port(const struct dsa_port *dp)
>> > {
>> > 	if (!dp->bridge)
>> > 		return NULL;
>> >
>> > 	if (dp->lag)
>> > 		return dp->lag->dev;
>> > 	else if (dp->hsr_dev)
>> > 		return dp->hsr_dev;
>> >
>> > 	return dp->slave;
>> > }
>> >
>> > Notice the "dp->bridge" check. The assignments are in dsa_port_bridge_create()
>> > and in dsa_port_bridge_destroy(). These functions assume rtnl_mutex protection.
>> > The question was how do you serialize with that, and why do you assume
>> > that dsa_port_to_bridge_port() returns non-NULL.
>> >
>> > So no, dsa_is_unused_port() would do absolutely nothing to help.
>> 
>> I was thinking in indirect terms (dangerous I know :-).
>
> Sorry, I don't understand what you mean by "indirect terms". An "unused
> port" is one with 'status = "disabled";' in the device tree. I would
> expect that you don't need to handle FDB entries towards such a port!
>

Right!

> You have a port receiving traffic with an unknown {MAC SA, VID}.
> When the port is configured as locked by the bridge, this traffic will
> generate ATU miss interrupts. These will be handled in an interrupt
> thread that is scheduled to be handled some time in the future.
> In between the moment when the packet is received and the moment when
> the interrupt thread runs, a user could run "ip link set lan0 nomaster".
> Then the interrupt thread would notify the bridge about these entries,
> point during which a bridge port no longer exists => NULL pointer dereference.
> By taking the rtnl_lock() and then checking whether dsa_port_to_bridge_port()
> is NULL, you figure out whether the interrupt handler ran completely
> before dsa_port_bridge_leave(), or completely after dsa_port_bridge_leave().
>
>> 
>> But wrt the nl lock, I wonder when other threads could pull the carpet
>> away under this, and so I might have to wait till after the last call
>> (mv88e6xxx_g1_atu_loadpurge) to free the nl lock?
>
> That might make sense. It means: if the user runs "ip link set lan0 nomaster",
> wait until I've notified the bridge and installed the entry to my own
> ATU, so that they're in sync. Then, del_nbp() -> br_fdb_delete_by_port()
> would come in, find that entry notified by us (I think!) and remove it.
> If you call rtnl_unlock() too early, it might be possible that the ATU
> entry remains lingering (unless I'm missing some subtle implicit
> serialization based on mv88e6xxx_reg_lock() or similar).

I will go with releasing the lock after the last call. I think that
should be okay.

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-10 14:54   ` Andrew Lunn
@ 2022-03-11  7:59     ` Hans Schultz
  0 siblings, 0 replies; 63+ messages in thread
From: Hans Schultz @ 2022-03-11  7:59 UTC (permalink / raw)
  To: Andrew Lunn, Hans Schultz
  Cc: davem, kuba, netdev, Vivien Didelot, Florian Fainelli,
	Vladimir Oltean, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On tor, mar 10, 2022 at 15:54, Andrew Lunn <andrew@lunn.ch> wrote:
>> +		if (mv88e6xxx_port_is_locked(chip, chip->ports[spid].port))
>> +			err = mv88e6xxx_switchdev_handle_atu_miss_violation(chip,
>> +									    chip->ports[spid].port,
>> +									    &entry,
>> +									    fid);
>
>> +static int mv88e6xxx_find_vid_on_matching_fid(struct mv88e6xxx_chip *chip,
>> +					      const struct mv88e6xxx_vtu_entry *entry,
>> +					      void *priv)
>> +{
>> +	struct mv88e6xxx_fid_search_ctx *ctx = priv;
>> +
>> +	if (ctx->fid_search == entry->fid) {
>> +		ctx->vid_found = entry->vid;
>> +		return 1;
>> +	}
>> +	return 0;
>> +}
>> +
>> +int mv88e6xxx_switchdev_handle_atu_miss_violation(struct mv88e6xxx_chip *chip,
>> +						  int port,
>> +						  struct mv88e6xxx_atu_entry *entry,
>> +						  u16 fid)
>> +{
>> +	struct switchdev_notifier_fdb_info info = {
>> +		.addr = entry->mac,
>> +		.vid = 0,
>> +		.added_by_user = false,
>> +		.is_local = false,
>> +		.offloaded = true,
>> +		.locked = true,
>> +	};
>> +	struct mv88e6xxx_fid_search_ctx ctx;
>> +	struct netlink_ext_ack *extack;
>> +	struct net_device *brport;
>> +	struct dsa_port *dp;
>> +	int err;
>> +
>> +	ctx.fid_search = fid;
>> +	err = mv88e6xxx_vtu_walk(chip, mv88e6xxx_find_vid_on_matching_fid, &ctx);
>
> I could be reading this code wrong, but it looks like you assume there
> is a single new entry in the ATU. But interrupts on these devices are
> slow. It would be easy for two or more devices to pop into existence
> at the same time. Don't you need to walk the whole ATU to find all the
> new entries? Have you tried this with a traffic generating populating
> the ATU with new entries at different rates, up to line rate? Do you
> get notifications for them all?
>
>     Andrew

We have not tried your said test, but if a packet doesn't manage to
trigger a ATU miss violation interrupt, not much will happen as far as I
see. The device sending the packet will not get access, but if it sends
again (maybe after a short while), it can still trigger the ATU miss
violation interrupt and get access.
I think that the normal behaviour for a device would be to try and
connect, and if that is not successfull inside a short time, it will wait
for a timeout before trying again.

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-10 14:28   ` Vladimir Oltean
  2022-03-10 15:00     ` Hans Schultz
  2022-03-10 15:57     ` Hans Schultz
@ 2022-03-14 10:46     ` Hans Schultz
  2022-03-16 23:34       ` Vladimir Oltean
  2 siblings, 1 reply; 63+ messages in thread
From: Hans Schultz @ 2022-03-14 10:46 UTC (permalink / raw)
  To: Vladimir Oltean, Hans Schultz
  Cc: davem, kuba, netdev, Andrew Lunn, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On tor, mar 10, 2022 at 16:28, Vladimir Oltean <olteanv@gmail.com> wrote:
> On Thu, Mar 10, 2022 at 03:23:20PM +0100, Hans Schultz wrote:
>> This implementation for the Marvell mv88e6xxx chip series, is
>> based on handling ATU miss violations occurring when packets
>> ingress on a port that is locked. The mac address triggering
>> the ATU miss violation is communicated through switchdev to
>> the bridge module, which adds a fdb entry with the fdb locked
>> flag set.
>> Note: The locked port must have learning enabled for the ATU
>> miss violation to occur.
>> 
>> Signed-off-by: Hans Schultz <schultz.hans+netdev@gmail.com>
>> ---
>>  drivers/net/dsa/mv88e6xxx/Makefile            |  1 +
>>  drivers/net/dsa/mv88e6xxx/chip.c              | 10 +--
>>  drivers/net/dsa/mv88e6xxx/chip.h              |  5 ++
>>  drivers/net/dsa/mv88e6xxx/global1.h           |  1 +
>>  drivers/net/dsa/mv88e6xxx/global1_atu.c       | 29 +++++++-
>>  .../net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c   | 67 +++++++++++++++++++
>>  .../net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h   | 20 ++++++
>>  drivers/net/dsa/mv88e6xxx/port.c              | 11 +++
>>  drivers/net/dsa/mv88e6xxx/port.h              |  1 +
>>  9 files changed, 138 insertions(+), 7 deletions(-)
>>  create mode 100644 drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c
>>  create mode 100644 drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h
>> 
>> diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile
>> index c8eca2b6f959..3ca57709730d 100644
>> --- a/drivers/net/dsa/mv88e6xxx/Makefile
>> +++ b/drivers/net/dsa/mv88e6xxx/Makefile
>> @@ -15,3 +15,4 @@ mv88e6xxx-objs += port_hidden.o
>>  mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += ptp.o
>>  mv88e6xxx-objs += serdes.o
>>  mv88e6xxx-objs += smi.o
>> +mv88e6xxx-objs += mv88e6xxx_switchdev.o
>> \ No newline at end of file
>> diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
>> index 84b90fc36c58..e1b6bd738085 100644
>> --- a/drivers/net/dsa/mv88e6xxx/chip.c
>> +++ b/drivers/net/dsa/mv88e6xxx/chip.c
>> @@ -1714,11 +1714,11 @@ static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
>>  	return err;
>>  }
>>  
>> -static int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
>> -			      int (*cb)(struct mv88e6xxx_chip *chip,
>> -					const struct mv88e6xxx_vtu_entry *entry,
>> -					void *priv),
>> -			      void *priv)
>> +int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
>> +		       int (*cb)(struct mv88e6xxx_chip *chip,
>> +				 const struct mv88e6xxx_vtu_entry *entry,
>> +				 void *priv),
>> +		       void *priv)
>>  {
>>  	struct mv88e6xxx_vtu_entry entry = {
>>  		.vid = mv88e6xxx_max_vid(chip),
>> diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
>> index 30b92a265613..64e8fc470fdf 100644
>> --- a/drivers/net/dsa/mv88e6xxx/chip.h
>> +++ b/drivers/net/dsa/mv88e6xxx/chip.h
>> @@ -763,6 +763,11 @@ static inline void mv88e6xxx_reg_unlock(struct mv88e6xxx_chip *chip)
>>  	mutex_unlock(&chip->reg_lock);
>>  }
>>  
>> +int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
>> +		       int (*cb)(struct mv88e6xxx_chip *chip,
>> +				 const struct mv88e6xxx_vtu_entry *entry,
>> +				 void *priv),
>> +		       void *priv);
>>  int mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *bitmap);
>>  
>>  #endif /* _MV88E6XXX_CHIP_H */
>> diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h
>> index 2c1607c858a1..729cc0610d9a 100644
>> --- a/drivers/net/dsa/mv88e6xxx/global1.h
>> +++ b/drivers/net/dsa/mv88e6xxx/global1.h
>> @@ -136,6 +136,7 @@
>>  #define MV88E6XXX_G1_ATU_DATA_TRUNK				0x8000
>>  #define MV88E6XXX_G1_ATU_DATA_TRUNK_ID_MASK			0x00f0
>>  #define MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_MASK			0x3ff0
>> +#define MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_NO_EGRESS		0x0000
>>  #define MV88E6XXX_G1_ATU_DATA_STATE_MASK			0x000f
>>  #define MV88E6XXX_G1_ATU_DATA_STATE_UC_UNUSED			0x0000
>>  #define MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_1_OLDEST		0x0001
>> diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c
>> index 40bd67a5c8e9..afa54fe8667e 100644
>> --- a/drivers/net/dsa/mv88e6xxx/global1_atu.c
>> +++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c
>> @@ -12,6 +12,8 @@
>>  
>>  #include "chip.h"
>>  #include "global1.h"
>> +#include "port.h"
>> +#include "mv88e6xxx_switchdev.h"
>>  
>>  /* Offset 0x01: ATU FID Register */
>>  
>> @@ -114,6 +116,18 @@ static int mv88e6xxx_g1_atu_op_wait(struct mv88e6xxx_chip *chip)
>>  	return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_ATU_OP, bit, 0);
>>  }
>>  
>> +static int mv88e6xxx_g1_read_atu_violation(struct mv88e6xxx_chip *chip)
>> +{
>> +	int err;
>> +
>> +	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_OP,
>> +				 MV88E6XXX_G1_ATU_OP_BUSY | MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION);
>> +	if (err)
>> +		return err;
>> +
>> +	return mv88e6xxx_g1_atu_op_wait(chip);
>> +}
>> +
>>  static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op)
>>  {
>>  	u16 val;
>> @@ -356,11 +370,11 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
>>  	int spid;
>>  	int err;
>>  	u16 val;
>> +	u16 fid;
>>  
>>  	mv88e6xxx_reg_lock(chip);
>>  
>> -	err = mv88e6xxx_g1_atu_op(chip, 0,
>> -				  MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION);
>> +	err = mv88e6xxx_g1_read_atu_violation(chip);
>>  	if (err)
>>  		goto out;
>>  
>> @@ -368,6 +382,10 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
>>  	if (err)
>>  		goto out;
>>  
>> +	err = mv88e6xxx_g1_read(chip, MV88E6352_G1_ATU_FID, &fid);
>> +	if (err)
>> +		goto out;
>> +
>>  	err = mv88e6xxx_g1_atu_data_read(chip, &entry);
>>  	if (err)
>>  		goto out;
>> @@ -396,6 +414,13 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
>>  				    "ATU miss violation for %pM portvec %x spid %d\n",
>>  				    entry.mac, entry.portvec, spid);
>>  		chip->ports[spid].atu_miss_violation++;
>> +		if (mv88e6xxx_port_is_locked(chip, chip->ports[spid].port))
>> +			err = mv88e6xxx_switchdev_handle_atu_miss_violation(chip,
>> +									    chip->ports[spid].port,
>> +									    &entry,
>> +									    fid);
>
> Do we want to suppress the ATU miss violation warnings if we're going to
> notify the bridge, or is it better to keep them for some reason?
> My logic is that they're part of normal operation, so suppressing makes
> sense.
>

I have been seeing many ATU member violations after the miss violation is
handled (using ping), and I think it could be considered to suppress the ATU member
violations interrupts by setting the IgnoreWrongData bit for the
port (sect 4.4.7). This would be something to do whenever a port is set in locked mode?

>> +		if (err)
>> +			goto out;
>>  	}
>>  
>>  	if (val & MV88E6XXX_G1_ATU_OP_FULL_VIOLATION) {
>> diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c
>> new file mode 100644
>> index 000000000000..e0ca452b6f86
>> --- /dev/null
>> +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c
>> @@ -0,0 +1,67 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * mv88e6xxx_switchdev.c
>> + *
>> + *	Authors:
>> + *	Hans J. Schultz		<hans.schultz@westermo.com>
>> + *
>> + */
>> +
>> +#include <net/switchdev.h>
>> +#include "chip.h"
>> +#include "global1.h"
>> +
>> +struct mv88e6xxx_fid_search_ctx {
>> +	u16 fid_search;
>> +	u16 vid_found;
>> +};
>> +
>> +static int mv88e6xxx_find_vid_on_matching_fid(struct mv88e6xxx_chip *chip,
>> +					      const struct mv88e6xxx_vtu_entry *entry,
>> +					      void *priv)
>> +{
>> +	struct mv88e6xxx_fid_search_ctx *ctx = priv;
>> +
>> +	if (ctx->fid_search == entry->fid) {
>> +		ctx->vid_found = entry->vid;
>> +		return 1;
>> +	}
>> +	return 0;
>> +}
>> +
>> +int mv88e6xxx_switchdev_handle_atu_miss_violation(struct mv88e6xxx_chip *chip,
>> +						  int port,
>> +						  struct mv88e6xxx_atu_entry *entry,
>> +						  u16 fid)
>> +{
>> +	struct switchdev_notifier_fdb_info info = {
>> +		.addr = entry->mac,
>> +		.vid = 0,
>> +		.added_by_user = false,
>> +		.is_local = false,
>> +		.offloaded = true,
>> +		.locked = true,
>> +	};
>> +	struct mv88e6xxx_fid_search_ctx ctx;
>> +	struct netlink_ext_ack *extack;
>> +	struct net_device *brport;
>> +	struct dsa_port *dp;
>> +	int err;
>> +
>> +	ctx.fid_search = fid;
>> +	err = mv88e6xxx_vtu_walk(chip, mv88e6xxx_find_vid_on_matching_fid, &ctx);
>> +	if (err < 0)
>> +		return err;
>> +	if (err == 1)
>> +		info.vid = ctx.vid_found;
>> +	else
>> +		return -ENODATA;
>> +
>> +	dp = dsa_to_port(chip->ds, port);
>> +	brport = dsa_port_to_bridge_port(dp);
>
> Since this is threaded interrupt context, I suppose it could race with
> dsa_port_bridge_leave(). So it is best to check whether "brport" is NULL
> or not.
>
> Speaking of races with dsa_port_bridge_leave().. does SWITCHDEV_FDB_ADD_TO_BRIDGE
> not require rtnl_lock?
>
>> +	err = call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE, brport, &info.info, extack);
>
> It is buggy to pass an uninitialized on-stack extack, just pass NULL if
> there's no one to consume it.
>
> Alternatively, if the bridge produces a valid extack message for errors
> in this case (I haven't checked), it may be more useful to manually
> print the extack._msg to the kernel log - see dsa_switch_sync_vlan_filtering()
> for an example.
>
> I am a bit uncomfortable having every driver implement this ad-hoc and
> potentially have a gazillion subtle bugs like these, could we have a
> common function exported by DSA that deals with SWITCHDEV_FDB_ADD_TO_BRIDGE?
>
>> +	if (err)
>> +		return err;
>> +	entry->portvec = MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_NO_EGRESS;
>> +	return mv88e6xxx_g1_atu_loadpurge(chip, fid, entry);
>> +}
>> diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h
>> new file mode 100644
>> index 000000000000..127f3098f745
>> --- /dev/null
>> +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h
>> @@ -0,0 +1,20 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later
>> + *
>> + * mv88e6xxx_switchdev.h
>> + *
>> + *	Authors:
>> + *	Hans J. Schultz		<hans.schultz@westermo.com>
>> + *
>> + */
>> +
>> +#ifndef DRIVERS_NET_DSA_MV88E6XXX_MV88E6XXX_SWITCHDEV_H_
>> +#define DRIVERS_NET_DSA_MV88E6XXX_MV88E6XXX_SWITCHDEV_H_
>> +
>> +#include <net/switchdev.h>
>> +
>> +int mv88e6xxx_switchdev_handle_atu_miss_violation(struct mv88e6xxx_chip *chip,
>> +						  int port,
>> +						  struct mv88e6xxx_atu_entry *entry,
>> +						  u16 fid);
>> +
>> +#endif /* DRIVERS_NET_DSA_MV88E6XXX_MV88E6XXX_SWITCHDEV_H_ */
>> diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
>> index 795b3128768f..6b375b0caa2c 100644
>> --- a/drivers/net/dsa/mv88e6xxx/port.c
>> +++ b/drivers/net/dsa/mv88e6xxx/port.c
>> @@ -1239,6 +1239,17 @@ int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,
>>  	return err;
>>  }
>>  
>> +bool mv88e6xxx_port_is_locked(struct mv88e6xxx_chip *chip, int port)
>> +{
>> +	u16 reg;
>> +
>> +	if (mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg))
>> +		return false;
>> +	if (!(reg & MV88E6XXX_PORT_CTL0_SA_FILT_DROP_ON_LOCK))
>> +		return false;
>> +	return true;
>> +}
>> +
>>  int mv88e6xxx_port_set_lock(struct mv88e6xxx_chip *chip, int port,
>>  			    bool locked)
>>  {
>> diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h
>> index e0a705d82019..09ea8f1615bb 100644
>> --- a/drivers/net/dsa/mv88e6xxx/port.h
>> +++ b/drivers/net/dsa/mv88e6xxx/port.h
>> @@ -374,6 +374,7 @@ int mv88e6xxx_port_set_fid(struct mv88e6xxx_chip *chip, int port, u16 fid);
>>  int mv88e6xxx_port_get_pvid(struct mv88e6xxx_chip *chip, int port, u16 *pvid);
>>  int mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid);
>>  
>> +bool mv88e6xxx_port_is_locked(struct mv88e6xxx_chip *chip, int port);
>>  int mv88e6xxx_port_set_lock(struct mv88e6xxx_chip *chip, int port,
>>  			    bool locked);
>>  
>> -- 
>> 2.30.2
>> 

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 1/3] net: bridge: add fdb flag to extent locked port feature
  2022-03-10 14:23 ` [PATCH net-next 1/3] net: bridge: add fdb flag to extent locked port feature Hans Schultz
  2022-03-10 14:42   ` Nikolay Aleksandrov
@ 2022-03-14 15:30   ` Ido Schimmel
  2022-03-15  8:48     ` Hans Schultz
  1 sibling, 1 reply; 63+ messages in thread
From: Ido Schimmel @ 2022-03-14 15:30 UTC (permalink / raw)
  To: Hans Schultz
  Cc: davem, kuba, netdev, Hans Schultz, Andrew Lunn, Vivien Didelot,
	Florian Fainelli, Vladimir Oltean, Jiri Pirko, Ivan Vecera,
	Roopa Prabhu, Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel,
	linux-kernel, bridge

On Thu, Mar 10, 2022 at 03:23:18PM +0100, Hans Schultz wrote:
> Add an intermediate state for clients behind a locked port to allow for
> possible opening of the port for said clients. This feature corresponds
> to the Mac-Auth and MAC Authentication Bypass (MAB) named features. The
> latter defined by Cisco.
> 
> Signed-off-by: Hans Schultz <schultz.hans+netdev@gmail.com>
> ---
>  include/uapi/linux/neighbour.h |  1 +
>  net/bridge/br_fdb.c            |  6 ++++++
>  net/bridge/br_input.c          | 11 ++++++++++-
>  net/bridge/br_private.h        |  3 ++-
>  4 files changed, 19 insertions(+), 2 deletions(-)
> 
> diff --git a/include/uapi/linux/neighbour.h b/include/uapi/linux/neighbour.h
> index db05fb55055e..83115a592d58 100644
> --- a/include/uapi/linux/neighbour.h
> +++ b/include/uapi/linux/neighbour.h
> @@ -208,6 +208,7 @@ enum {
>  	NFEA_UNSPEC,
>  	NFEA_ACTIVITY_NOTIFY,
>  	NFEA_DONT_REFRESH,
> +	NFEA_LOCKED,
>  	__NFEA_MAX
>  };
>  #define NFEA_MAX (__NFEA_MAX - 1)
> diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
> index 6ccda68bd473..396dcf3084cf 100644
> --- a/net/bridge/br_fdb.c
> +++ b/net/bridge/br_fdb.c
> @@ -105,6 +105,7 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
>  	struct nda_cacheinfo ci;
>  	struct nlmsghdr *nlh;
>  	struct ndmsg *ndm;
> +	u8 ext_flags = 0;
>  
>  	nlh = nlmsg_put(skb, portid, seq, type, sizeof(*ndm), flags);
>  	if (nlh == NULL)
> @@ -125,11 +126,16 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
>  		ndm->ndm_flags |= NTF_EXT_LEARNED;
>  	if (test_bit(BR_FDB_STICKY, &fdb->flags))
>  		ndm->ndm_flags |= NTF_STICKY;
> +	if (test_bit(BR_FDB_ENTRY_LOCKED, &fdb->flags))
> +		ext_flags |= 1 << NFEA_LOCKED;
>  
>  	if (nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->key.addr))
>  		goto nla_put_failure;
>  	if (nla_put_u32(skb, NDA_MASTER, br->dev->ifindex))
>  		goto nla_put_failure;
> +	if (nla_put_u8(skb, NDA_FDB_EXT_ATTRS, ext_flags))
> +		goto nla_put_failure;
> +
>  	ci.ndm_used	 = jiffies_to_clock_t(now - fdb->used);
>  	ci.ndm_confirmed = 0;
>  	ci.ndm_updated	 = jiffies_to_clock_t(now - fdb->updated);
> diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
> index e0c13fcc50ed..897908484b18 100644
> --- a/net/bridge/br_input.c
> +++ b/net/bridge/br_input.c
> @@ -75,6 +75,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
>  	struct net_bridge_mcast *brmctx;
>  	struct net_bridge_vlan *vlan;
>  	struct net_bridge *br;
> +	unsigned long flags = 0;
>  	u16 vid = 0;
>  	u8 state;
>  
> @@ -94,8 +95,16 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
>  			br_fdb_find_rcu(br, eth_hdr(skb)->h_source, vid);
>  
>  		if (!fdb_src || READ_ONCE(fdb_src->dst) != p ||
> -		    test_bit(BR_FDB_LOCAL, &fdb_src->flags))
> +		    test_bit(BR_FDB_LOCAL, &fdb_src->flags)) {
> +			if (!fdb_src) {
> +				set_bit(BR_FDB_ENTRY_LOCKED, &flags);

This flag is read-only for user space, right? That is, the kernel needs
to reject it during netlink policy validation.

> +				br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, flags);
> +			}
>  			goto drop;
> +		} else {

IIUC, we get here in case there is a non-local FDB entry with the SA
that points to our port. Can you write it as:

if (!fdb_src || READ_ONCE(fdb_src->dst) != p ||
    test_bit(BR_FDB_LOCAL, &fdb_src->flags) ||
    test_bit(BR_FDB_ENTRY_LOCKED, &fdb_src->flags)) {
    	if (!fdb_src) {
	...
	}
	goto drop;
}

> +			if (test_bit(BR_FDB_ENTRY_LOCKED, &fdb_src->flags))
> +				goto drop;
> +		}
>  	}
>  
>  	nbp_switchdev_frame_mark(p, skb);
> diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
> index 48bc61ebc211..f5a0b68c4857 100644
> --- a/net/bridge/br_private.h
> +++ b/net/bridge/br_private.h
> @@ -248,7 +248,8 @@ enum {
>  	BR_FDB_ADDED_BY_EXT_LEARN,
>  	BR_FDB_OFFLOADED,
>  	BR_FDB_NOTIFY,
> -	BR_FDB_NOTIFY_INACTIVE
> +	BR_FDB_NOTIFY_INACTIVE,
> +	BR_FDB_ENTRY_LOCKED,
>  };
>  
>  struct net_bridge_fdb_key {
> -- 
> 2.30.2
> 

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 0/3] Extend locked port feature with FDB locked flag (MAC-Auth/MAB)
  2022-03-10 14:23 [PATCH net-next 0/3] Extend locked port feature with FDB locked flag (MAC-Auth/MAB) Hans Schultz
                   ` (2 preceding siblings ...)
  2022-03-10 14:23 ` [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation Hans Schultz
@ 2022-03-14 15:50 ` Ido Schimmel
  2022-03-15  8:59   ` Hans Schultz
  2022-03-17  0:18 ` Florian Fainelli
  4 siblings, 1 reply; 63+ messages in thread
From: Ido Schimmel @ 2022-03-14 15:50 UTC (permalink / raw)
  To: Hans Schultz
  Cc: davem, kuba, netdev, Hans Schultz, Andrew Lunn, Vivien Didelot,
	Florian Fainelli, Vladimir Oltean, Jiri Pirko, Ivan Vecera,
	Roopa Prabhu, Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel,
	linux-kernel, bridge

On Thu, Mar 10, 2022 at 03:23:17PM +0100, Hans Schultz wrote:
> This patch set extends the locked port feature for devices
> that are behind a locked port, but do not have the ability to
> authorize themselves as a supplicant using IEEE 802.1X.
> Such devices can be printers, meters or anything related to
> fixed installations. Instead of 802.1X authorization, devices
> can get access based on their MAC addresses being whitelisted.
> 
> For an authorization daemon to detect that a device is trying
> to get access through a locked port, the bridge will add the
> MAC address of the device to the FDB with a locked flag to it.
> Thus the authorization daemon can catch the FDB add event and
> check if the MAC address is in the whitelist and if so replace
> the FDB entry without the locked flag enabled, and thus open
> the port for the device.
> 
> This feature is known as MAC-Auth or MAC Authentication Bypass
> (MAB) in Cisco terminology, where the full MAB concept involves
> additional Cisco infrastructure for authorization. There is no
> real authentication process, as the MAC address of the device
> is the only input the authorization daemon, in the general
> case, has to base the decision if to unlock the port or not.
> 
> With this patch set, an implementation of the offloaded case is
> supplied for the mv88e6xxx driver. When a packet ingresses on
> a locked port, an ATU miss violation event will occur. When

When do you get an ATU miss violation? In case there is no FDB entry for
the SA or also when there is an FDB entry, but it points to a different
port? I see that the bridge will only create a "locked" FDB entry in
case there is no existing entry, but it will not transition an existing
entry to "locked" state. I guess ATU miss refers to an actual miss and
not mismatch.

The HW I work with doesn't have the ability to generate such
notifications, but it can trap packets on MISS (no entry) or MISMATCH
(exists, but with different port). I believe that in order to support
this feature we need to inject MISS-ed packets to the Rx path so that
eventually the bridge itself will create the "locked" entry as opposed
to notifying the bridge about the entry as in your case.

> handling such ATU miss violation interrupts, the MAC address of
> the device is added to the FDB with a zero destination port
> vector (DPV) and the MAC address is communicated through the
> switchdev layer to the bridge, so that a FDB entry with the
> locked flag enabled can be added.
> 
> Hans Schultz (3):
>   net: bridge: add fdb flag to extent locked port feature
>   net: switchdev: add support for offloading of fdb locked flag
>   net: dsa: mv88e6xxx: mac-auth/MAB implementation

Please extend tools/testing/selftests/net/forwarding/bridge_locked_port.sh
with new test cases for this code.

> 
>  drivers/net/dsa/mv88e6xxx/Makefile            |  1 +
>  drivers/net/dsa/mv88e6xxx/chip.c              | 10 +--
>  drivers/net/dsa/mv88e6xxx/chip.h              |  5 ++
>  drivers/net/dsa/mv88e6xxx/global1.h           |  1 +
>  drivers/net/dsa/mv88e6xxx/global1_atu.c       | 29 +++++++-
>  .../net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c   | 67 +++++++++++++++++++
>  .../net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h   | 20 ++++++
>  drivers/net/dsa/mv88e6xxx/port.c              | 11 +++
>  drivers/net/dsa/mv88e6xxx/port.h              |  1 +
>  include/net/switchdev.h                       |  3 +-
>  include/uapi/linux/neighbour.h                |  1 +
>  net/bridge/br.c                               |  3 +-
>  net/bridge/br_fdb.c                           | 13 +++-
>  net/bridge/br_input.c                         | 11 ++-
>  net/bridge/br_private.h                       |  5 +-
>  15 files changed, 167 insertions(+), 14 deletions(-)
>  create mode 100644 drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c
>  create mode 100644 drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h
> 
> -- 
> 2.30.2
> 

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 1/3] net: bridge: add fdb flag to extent locked port feature
  2022-03-14 15:30   ` Ido Schimmel
@ 2022-03-15  8:48     ` Hans Schultz
  2022-03-15 11:00       ` Ido Schimmel
  0 siblings, 1 reply; 63+ messages in thread
From: Hans Schultz @ 2022-03-15  8:48 UTC (permalink / raw)
  To: Ido Schimmel, Hans Schultz
  Cc: davem, kuba, netdev, Andrew Lunn, Vivien Didelot,
	Florian Fainelli, Vladimir Oltean, Jiri Pirko, Ivan Vecera,
	Roopa Prabhu, Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel,
	linux-kernel, bridge

On mån, mar 14, 2022 at 17:30, Ido Schimmel <idosch@idosch.org> wrote:
> On Thu, Mar 10, 2022 at 03:23:18PM +0100, Hans Schultz wrote:
>> Add an intermediate state for clients behind a locked port to allow for
>> possible opening of the port for said clients. This feature corresponds
>> to the Mac-Auth and MAC Authentication Bypass (MAB) named features. The
>> latter defined by Cisco.
>> 
>> Signed-off-by: Hans Schultz <schultz.hans+netdev@gmail.com>
>> ---
>>  include/uapi/linux/neighbour.h |  1 +
>>  net/bridge/br_fdb.c            |  6 ++++++
>>  net/bridge/br_input.c          | 11 ++++++++++-
>>  net/bridge/br_private.h        |  3 ++-
>>  4 files changed, 19 insertions(+), 2 deletions(-)
>> 
>> diff --git a/include/uapi/linux/neighbour.h b/include/uapi/linux/neighbour.h
>> index db05fb55055e..83115a592d58 100644
>> --- a/include/uapi/linux/neighbour.h
>> +++ b/include/uapi/linux/neighbour.h
>> @@ -208,6 +208,7 @@ enum {
>>  	NFEA_UNSPEC,
>>  	NFEA_ACTIVITY_NOTIFY,
>>  	NFEA_DONT_REFRESH,
>> +	NFEA_LOCKED,
>>  	__NFEA_MAX
>>  };
>>  #define NFEA_MAX (__NFEA_MAX - 1)
>> diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
>> index 6ccda68bd473..396dcf3084cf 100644
>> --- a/net/bridge/br_fdb.c
>> +++ b/net/bridge/br_fdb.c
>> @@ -105,6 +105,7 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
>>  	struct nda_cacheinfo ci;
>>  	struct nlmsghdr *nlh;
>>  	struct ndmsg *ndm;
>> +	u8 ext_flags = 0;
>>  
>>  	nlh = nlmsg_put(skb, portid, seq, type, sizeof(*ndm), flags);
>>  	if (nlh == NULL)
>> @@ -125,11 +126,16 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
>>  		ndm->ndm_flags |= NTF_EXT_LEARNED;
>>  	if (test_bit(BR_FDB_STICKY, &fdb->flags))
>>  		ndm->ndm_flags |= NTF_STICKY;
>> +	if (test_bit(BR_FDB_ENTRY_LOCKED, &fdb->flags))
>> +		ext_flags |= 1 << NFEA_LOCKED;
>>  
>>  	if (nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->key.addr))
>>  		goto nla_put_failure;
>>  	if (nla_put_u32(skb, NDA_MASTER, br->dev->ifindex))
>>  		goto nla_put_failure;
>> +	if (nla_put_u8(skb, NDA_FDB_EXT_ATTRS, ext_flags))
>> +		goto nla_put_failure;
>> +
>>  	ci.ndm_used	 = jiffies_to_clock_t(now - fdb->used);
>>  	ci.ndm_confirmed = 0;
>>  	ci.ndm_updated	 = jiffies_to_clock_t(now - fdb->updated);
>> diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
>> index e0c13fcc50ed..897908484b18 100644
>> --- a/net/bridge/br_input.c
>> +++ b/net/bridge/br_input.c
>> @@ -75,6 +75,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
>>  	struct net_bridge_mcast *brmctx;
>>  	struct net_bridge_vlan *vlan;
>>  	struct net_bridge *br;
>> +	unsigned long flags = 0;
>>  	u16 vid = 0;
>>  	u8 state;
>>  
>> @@ -94,8 +95,16 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
>>  			br_fdb_find_rcu(br, eth_hdr(skb)->h_source, vid);
>>  
>>  		if (!fdb_src || READ_ONCE(fdb_src->dst) != p ||
>> -		    test_bit(BR_FDB_LOCAL, &fdb_src->flags))
>> +		    test_bit(BR_FDB_LOCAL, &fdb_src->flags)) {
>> +			if (!fdb_src) {
>> +				set_bit(BR_FDB_ENTRY_LOCKED, &flags);
>
> This flag is read-only for user space, right? That is, the kernel needs
> to reject it during netlink policy validation.
>

Yes, the flag is only readable from user space, unless there is a wish
to change that.

>> +				br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, flags);
>> +			}
>>  			goto drop;
>> +		} else {
>
> IIUC, we get here in case there is a non-local FDB entry with the SA
> that points to our port. Can you write it as:
>

Yes, looks like that's more optimal. :)

> if (!fdb_src || READ_ONCE(fdb_src->dst) != p ||
>     test_bit(BR_FDB_LOCAL, &fdb_src->flags) ||
>     test_bit(BR_FDB_ENTRY_LOCKED, &fdb_src->flags)) {
>     	if (!fdb_src) {
> 	...
> 	}
> 	goto drop;
> }
>
>> +			if (test_bit(BR_FDB_ENTRY_LOCKED, &fdb_src->flags))
>> +				goto drop;
>> +		}
>>  	}
>>  
>>  	nbp_switchdev_frame_mark(p, skb);
>> diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
>> index 48bc61ebc211..f5a0b68c4857 100644
>> --- a/net/bridge/br_private.h
>> +++ b/net/bridge/br_private.h
>> @@ -248,7 +248,8 @@ enum {
>>  	BR_FDB_ADDED_BY_EXT_LEARN,
>>  	BR_FDB_OFFLOADED,
>>  	BR_FDB_NOTIFY,
>> -	BR_FDB_NOTIFY_INACTIVE
>> +	BR_FDB_NOTIFY_INACTIVE,
>> +	BR_FDB_ENTRY_LOCKED,
>>  };
>>  
>>  struct net_bridge_fdb_key {
>> -- 
>> 2.30.2
>> 

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 0/3] Extend locked port feature with FDB locked flag (MAC-Auth/MAB)
  2022-03-14 15:50 ` [PATCH net-next 0/3] Extend locked port feature with FDB locked flag (MAC-Auth/MAB) Ido Schimmel
@ 2022-03-15  8:59   ` Hans Schultz
  2022-03-15 11:11     ` Ido Schimmel
  0 siblings, 1 reply; 63+ messages in thread
From: Hans Schultz @ 2022-03-15  8:59 UTC (permalink / raw)
  To: Ido Schimmel, Hans Schultz
  Cc: davem, kuba, netdev, Andrew Lunn, Vivien Didelot,
	Florian Fainelli, Vladimir Oltean, Jiri Pirko, Ivan Vecera,
	Roopa Prabhu, Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel,
	linux-kernel, bridge

On mån, mar 14, 2022 at 17:50, Ido Schimmel <idosch@idosch.org> wrote:
> On Thu, Mar 10, 2022 at 03:23:17PM +0100, Hans Schultz wrote:
>> This patch set extends the locked port feature for devices
>> that are behind a locked port, but do not have the ability to
>> authorize themselves as a supplicant using IEEE 802.1X.
>> Such devices can be printers, meters or anything related to
>> fixed installations. Instead of 802.1X authorization, devices
>> can get access based on their MAC addresses being whitelisted.
>> 
>> For an authorization daemon to detect that a device is trying
>> to get access through a locked port, the bridge will add the
>> MAC address of the device to the FDB with a locked flag to it.
>> Thus the authorization daemon can catch the FDB add event and
>> check if the MAC address is in the whitelist and if so replace
>> the FDB entry without the locked flag enabled, and thus open
>> the port for the device.
>> 
>> This feature is known as MAC-Auth or MAC Authentication Bypass
>> (MAB) in Cisco terminology, where the full MAB concept involves
>> additional Cisco infrastructure for authorization. There is no
>> real authentication process, as the MAC address of the device
>> is the only input the authorization daemon, in the general
>> case, has to base the decision if to unlock the port or not.
>> 
>> With this patch set, an implementation of the offloaded case is
>> supplied for the mv88e6xxx driver. When a packet ingresses on
>> a locked port, an ATU miss violation event will occur. When
>
> When do you get an ATU miss violation? In case there is no FDB entry for
> the SA or also when there is an FDB entry, but it points to a different
> port? I see that the bridge will only create a "locked" FDB entry in
> case there is no existing entry, but it will not transition an existing
> entry to "locked" state. I guess ATU miss refers to an actual miss and
> not mismatch.
>

On a locked port, I get ATU miss violations when there is no FDB entry
for the SA, while if there is an entry but it is not assigned to the
port, then I get an ATU member violation (which I have now masked on
locked ports to limit unwanted interrupts).

So it seems to me that my 'ATU miss' corresponds to your MISS and my
'ATU member' corresponds to your MISMATCH. Since I inject an entry with
destination port vector (DPV) zero I get member violations after the
first miss violation.

> The HW I work with doesn't have the ability to generate such
> notifications, but it can trap packets on MISS (no entry) or MISMATCH
> (exists, but with different port). I believe that in order to support
> this feature we need to inject MISS-ed packets to the Rx path so that
> eventually the bridge itself will create the "locked" entry as opposed
> to notifying the bridge about the entry as in your case.
>

This seems to me to be the way forward in your case. What kind or family
of chips is your HW based on?

>> handling such ATU miss violation interrupts, the MAC address of
>> the device is added to the FDB with a zero destination port
>> vector (DPV) and the MAC address is communicated through the
>> switchdev layer to the bridge, so that a FDB entry with the
>> locked flag enabled can be added.
>> 
>> Hans Schultz (3):
>>   net: bridge: add fdb flag to extent locked port feature
>>   net: switchdev: add support for offloading of fdb locked flag
>>   net: dsa: mv88e6xxx: mac-auth/MAB implementation
>
> Please extend tools/testing/selftests/net/forwarding/bridge_locked_port.sh
> with new test cases for this code.
>

Shall do.

>> 
>>  drivers/net/dsa/mv88e6xxx/Makefile            |  1 +
>>  drivers/net/dsa/mv88e6xxx/chip.c              | 10 +--
>>  drivers/net/dsa/mv88e6xxx/chip.h              |  5 ++
>>  drivers/net/dsa/mv88e6xxx/global1.h           |  1 +
>>  drivers/net/dsa/mv88e6xxx/global1_atu.c       | 29 +++++++-
>>  .../net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c   | 67 +++++++++++++++++++
>>  .../net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h   | 20 ++++++
>>  drivers/net/dsa/mv88e6xxx/port.c              | 11 +++
>>  drivers/net/dsa/mv88e6xxx/port.h              |  1 +
>>  include/net/switchdev.h                       |  3 +-
>>  include/uapi/linux/neighbour.h                |  1 +
>>  net/bridge/br.c                               |  3 +-
>>  net/bridge/br_fdb.c                           | 13 +++-
>>  net/bridge/br_input.c                         | 11 ++-
>>  net/bridge/br_private.h                       |  5 +-
>>  15 files changed, 167 insertions(+), 14 deletions(-)
>>  create mode 100644 drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c
>>  create mode 100644 drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h
>> 
>> -- 
>> 2.30.2
>> 

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 1/3] net: bridge: add fdb flag to extent locked port feature
  2022-03-15  8:48     ` Hans Schultz
@ 2022-03-15 11:00       ` Ido Schimmel
  0 siblings, 0 replies; 63+ messages in thread
From: Ido Schimmel @ 2022-03-15 11:00 UTC (permalink / raw)
  To: Hans Schultz
  Cc: davem, kuba, netdev, Andrew Lunn, Vivien Didelot,
	Florian Fainelli, Vladimir Oltean, Jiri Pirko, Ivan Vecera,
	Roopa Prabhu, Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel,
	linux-kernel, bridge

On Tue, Mar 15, 2022 at 09:48:52AM +0100, Hans Schultz wrote:
> On mån, mar 14, 2022 at 17:30, Ido Schimmel <idosch@idosch.org> wrote:
> > On Thu, Mar 10, 2022 at 03:23:18PM +0100, Hans Schultz wrote:
> >> @@ -94,8 +95,16 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
> >>  			br_fdb_find_rcu(br, eth_hdr(skb)->h_source, vid);
> >>  
> >>  		if (!fdb_src || READ_ONCE(fdb_src->dst) != p ||
> >> -		    test_bit(BR_FDB_LOCAL, &fdb_src->flags))
> >> +		    test_bit(BR_FDB_LOCAL, &fdb_src->flags)) {
> >> +			if (!fdb_src) {
> >> +				set_bit(BR_FDB_ENTRY_LOCKED, &flags);
> >
> > This flag is read-only for user space, right? That is, the kernel needs
> > to reject it during netlink policy validation.
> >
> 
> Yes, the flag is only readable from user space, unless there is a wish
> to change that.

OK, so please spell it out in the commit message so that it is clear the
flag can only be set by the kernel.

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 0/3] Extend locked port feature with FDB locked flag (MAC-Auth/MAB)
  2022-03-15  8:59   ` Hans Schultz
@ 2022-03-15 11:11     ` Ido Schimmel
  0 siblings, 0 replies; 63+ messages in thread
From: Ido Schimmel @ 2022-03-15 11:11 UTC (permalink / raw)
  To: Hans Schultz
  Cc: davem, kuba, netdev, Andrew Lunn, Vivien Didelot,
	Florian Fainelli, Vladimir Oltean, Jiri Pirko, Ivan Vecera,
	Roopa Prabhu, Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel,
	linux-kernel, bridge

On Tue, Mar 15, 2022 at 09:59:49AM +0100, Hans Schultz wrote:
> On mån, mar 14, 2022 at 17:50, Ido Schimmel <idosch@idosch.org> wrote:
> > On Thu, Mar 10, 2022 at 03:23:17PM +0100, Hans Schultz wrote:
> >> This patch set extends the locked port feature for devices
> >> that are behind a locked port, but do not have the ability to
> >> authorize themselves as a supplicant using IEEE 802.1X.
> >> Such devices can be printers, meters or anything related to
> >> fixed installations. Instead of 802.1X authorization, devices
> >> can get access based on their MAC addresses being whitelisted.
> >> 
> >> For an authorization daemon to detect that a device is trying
> >> to get access through a locked port, the bridge will add the
> >> MAC address of the device to the FDB with a locked flag to it.
> >> Thus the authorization daemon can catch the FDB add event and
> >> check if the MAC address is in the whitelist and if so replace
> >> the FDB entry without the locked flag enabled, and thus open
> >> the port for the device.
> >> 
> >> This feature is known as MAC-Auth or MAC Authentication Bypass
> >> (MAB) in Cisco terminology, where the full MAB concept involves
> >> additional Cisco infrastructure for authorization. There is no
> >> real authentication process, as the MAC address of the device
> >> is the only input the authorization daemon, in the general
> >> case, has to base the decision if to unlock the port or not.
> >> 
> >> With this patch set, an implementation of the offloaded case is
> >> supplied for the mv88e6xxx driver. When a packet ingresses on
> >> a locked port, an ATU miss violation event will occur. When
> >
> > When do you get an ATU miss violation? In case there is no FDB entry for
> > the SA or also when there is an FDB entry, but it points to a different
> > port? I see that the bridge will only create a "locked" FDB entry in
> > case there is no existing entry, but it will not transition an existing
> > entry to "locked" state. I guess ATU miss refers to an actual miss and
> > not mismatch.
> >
> 
> On a locked port, I get ATU miss violations when there is no FDB entry
> for the SA, while if there is an entry but it is not assigned to the
> port, then I get an ATU member violation (which I have now masked on
> locked ports to limit unwanted interrupts).
> 
> So it seems to me that my 'ATU miss' corresponds to your MISS and my
> 'ATU member' corresponds to your MISMATCH. Since I inject an entry with
> destination port vector (DPV) zero I get member violations after the
> first miss violation.

Which causes packets to be silently dropped by the device? Sounds OK, I
just want to verify I understand the behavior.

> 
> > The HW I work with doesn't have the ability to generate such
> > notifications, but it can trap packets on MISS (no entry) or MISMATCH
> > (exists, but with different port). I believe that in order to support
> > this feature we need to inject MISS-ed packets to the Rx path so that
> > eventually the bridge itself will create the "locked" entry as opposed
> > to notifying the bridge about the entry as in your case.
> >
> 
> This seems to me to be the way forward in your case. What kind or family
> of chips is your HW based on?

Nvidia Spectrum ASICs. Some users mentioned 802.1X support, but a
requirement never materialized so we didn't work on it.

> 
> >> handling such ATU miss violation interrupts, the MAC address of
> >> the device is added to the FDB with a zero destination port
> >> vector (DPV) and the MAC address is communicated through the
> >> switchdev layer to the bridge, so that a FDB entry with the
> >> locked flag enabled can be added.
> >> 
> >> Hans Schultz (3):
> >>   net: bridge: add fdb flag to extent locked port feature
> >>   net: switchdev: add support for offloading of fdb locked flag
> >>   net: dsa: mv88e6xxx: mac-auth/MAB implementation
> >
> > Please extend tools/testing/selftests/net/forwarding/bridge_locked_port.sh
> > with new test cases for this code.
> >
> 
> Shall do.

Thanks!

> 
> >> 
> >>  drivers/net/dsa/mv88e6xxx/Makefile            |  1 +
> >>  drivers/net/dsa/mv88e6xxx/chip.c              | 10 +--
> >>  drivers/net/dsa/mv88e6xxx/chip.h              |  5 ++
> >>  drivers/net/dsa/mv88e6xxx/global1.h           |  1 +
> >>  drivers/net/dsa/mv88e6xxx/global1_atu.c       | 29 +++++++-
> >>  .../net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c   | 67 +++++++++++++++++++
> >>  .../net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h   | 20 ++++++
> >>  drivers/net/dsa/mv88e6xxx/port.c              | 11 +++
> >>  drivers/net/dsa/mv88e6xxx/port.h              |  1 +
> >>  include/net/switchdev.h                       |  3 +-
> >>  include/uapi/linux/neighbour.h                |  1 +
> >>  net/bridge/br.c                               |  3 +-
> >>  net/bridge/br_fdb.c                           | 13 +++-
> >>  net/bridge/br_input.c                         | 11 ++-
> >>  net/bridge/br_private.h                       |  5 +-
> >>  15 files changed, 167 insertions(+), 14 deletions(-)
> >>  create mode 100644 drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.c
> >>  create mode 100644 drivers/net/dsa/mv88e6xxx/mv88e6xxx_switchdev.h
> >> 
> >> -- 
> >> 2.30.2
> >> 

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-14 10:46     ` Hans Schultz
@ 2022-03-16 23:34       ` Vladimir Oltean
  2022-03-17  8:52         ` Hans Schultz
  0 siblings, 1 reply; 63+ messages in thread
From: Vladimir Oltean @ 2022-03-16 23:34 UTC (permalink / raw)
  To: Hans Schultz
  Cc: davem, kuba, netdev, Andrew Lunn, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On Mon, Mar 14, 2022 at 11:46:51AM +0100, Hans Schultz wrote:
> >> @@ -396,6 +414,13 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
> >>  				    "ATU miss violation for %pM portvec %x spid %d\n",
> >>  				    entry.mac, entry.portvec, spid);
> >>  		chip->ports[spid].atu_miss_violation++;
> >> +		if (mv88e6xxx_port_is_locked(chip, chip->ports[spid].port))
> >> +			err = mv88e6xxx_switchdev_handle_atu_miss_violation(chip,
> >> +									    chip->ports[spid].port,
> >> +									    &entry,
> >> +									    fid);
> >
> > Do we want to suppress the ATU miss violation warnings if we're going to
> > notify the bridge, or is it better to keep them for some reason?
> > My logic is that they're part of normal operation, so suppressing makes
> > sense.
> >
> 
> I have been seeing many ATU member violations after the miss violation is
> handled (using ping), and I think it could be considered to suppress the ATU member
> violations interrupts by setting the IgnoreWrongData bit for the
> port (sect 4.4.7). This would be something to do whenever a port is set in locked mode?

So the first packet with a given MAC SA triggers an ATU miss violation
interrupt.

You program that MAC SA into the ATU with a destination port mask of all
zeroes. This suppresses further ATU miss interrupts for this MAC SA, but
now generates ATU member violations, because the MAC SA _is_ present in
the ATU, but not towards the expected port (in fact, towards _no_ port).

Especially if user space decides it doesn't want to authorize this MAC
SA, it really becomes a problem because this is now a vector for denial
of service, with every packet triggering an ATU member violation
interrupt.

So your suggestion is to set the IgnoreWrongData bit on locked ports,
and this will suppress the actual member violation interrupts for
traffic coming from these ports.

So if the user decides to unplug a previously authorized printer from
switch port 1 and move it to port 2, how is this handled? If there isn't
a mechanism in place to delete the locked FDB entry when the printer
goes away, then by setting IgnoreWrongData you're effectively also
suppressing migration notifications.

Oh, btw, my question was: could you consider suppressing the _prints_ on
an ATU miss violation on a locked port?

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 0/3] Extend locked port feature with FDB locked flag (MAC-Auth/MAB)
  2022-03-10 14:23 [PATCH net-next 0/3] Extend locked port feature with FDB locked flag (MAC-Auth/MAB) Hans Schultz
                   ` (3 preceding siblings ...)
  2022-03-14 15:50 ` [PATCH net-next 0/3] Extend locked port feature with FDB locked flag (MAC-Auth/MAB) Ido Schimmel
@ 2022-03-17  0:18 ` Florian Fainelli
  2022-03-17  8:29   ` Hans Schultz
  4 siblings, 1 reply; 63+ messages in thread
From: Florian Fainelli @ 2022-03-17  0:18 UTC (permalink / raw)
  To: Hans Schultz, davem, kuba
  Cc: netdev, Hans Schultz, Andrew Lunn, Vivien Didelot,
	Vladimir Oltean, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge



On 3/10/2022 6:23 AM, Hans Schultz wrote:
> This patch set extends the locked port feature for devices
> that are behind a locked port, but do not have the ability to
> authorize themselves as a supplicant using IEEE 802.1X.
> Such devices can be printers, meters or anything related to
> fixed installations. Instead of 802.1X authorization, devices
> can get access based on their MAC addresses being whitelisted.
> 
> For an authorization daemon to detect that a device is trying
> to get access through a locked port, the bridge will add the
> MAC address of the device to the FDB with a locked flag to it.
> Thus the authorization daemon can catch the FDB add event and
> check if the MAC address is in the whitelist and if so replace
> the FDB entry without the locked flag enabled, and thus open
> the port for the device.
> 
> This feature is known as MAC-Auth or MAC Authentication Bypass
> (MAB) in Cisco terminology, where the full MAB concept involves
> additional Cisco infrastructure for authorization. There is no
> real authentication process, as the MAC address of the device
> is the only input the authorization daemon, in the general
> case, has to base the decision if to unlock the port or not.
> 
> With this patch set, an implementation of the offloaded case is
> supplied for the mv88e6xxx driver. When a packet ingresses on
> a locked port, an ATU miss violation event will occur. When
> handling such ATU miss violation interrupts, the MAC address of
> the device is added to the FDB with a zero destination port
> vector (DPV) and the MAC address is communicated through the
> switchdev layer to the bridge, so that a FDB entry with the
> locked flag enabled can be added.

FWIW, we may have about a 30% - 70% split between switches that will 
signal ATU violations over a side band interrupt, like mv88e6xxx will, 
and the rest will likely signal such events via the proprietary tag format.
-- 
Florian

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 0/3] Extend locked port feature with FDB locked flag (MAC-Auth/MAB)
  2022-03-17  0:18 ` Florian Fainelli
@ 2022-03-17  8:29   ` Hans Schultz
  2022-03-17 18:42     ` Vladimir Oltean
  0 siblings, 1 reply; 63+ messages in thread
From: Hans Schultz @ 2022-03-17  8:29 UTC (permalink / raw)
  To: Florian Fainelli, Hans Schultz, davem, kuba
  Cc: netdev, Andrew Lunn, Vivien Didelot, Vladimir Oltean, Jiri Pirko,
	Ivan Vecera, Roopa Prabhu, Nikolay Aleksandrov, Daniel Borkmann,
	Ido Schimmel, linux-kernel, bridge

On ons, mar 16, 2022 at 17:18, Florian Fainelli <f.fainelli@gmail.com> wrote:
> On 3/10/2022 6:23 AM, Hans Schultz wrote:
>> This patch set extends the locked port feature for devices
>> that are behind a locked port, but do not have the ability to
>> authorize themselves as a supplicant using IEEE 802.1X.
>> Such devices can be printers, meters or anything related to
>> fixed installations. Instead of 802.1X authorization, devices
>> can get access based on their MAC addresses being whitelisted.
>> 
>> For an authorization daemon to detect that a device is trying
>> to get access through a locked port, the bridge will add the
>> MAC address of the device to the FDB with a locked flag to it.
>> Thus the authorization daemon can catch the FDB add event and
>> check if the MAC address is in the whitelist and if so replace
>> the FDB entry without the locked flag enabled, and thus open
>> the port for the device.
>> 
>> This feature is known as MAC-Auth or MAC Authentication Bypass
>> (MAB) in Cisco terminology, where the full MAB concept involves
>> additional Cisco infrastructure for authorization. There is no
>> real authentication process, as the MAC address of the device
>> is the only input the authorization daemon, in the general
>> case, has to base the decision if to unlock the port or not.
>> 
>> With this patch set, an implementation of the offloaded case is
>> supplied for the mv88e6xxx driver. When a packet ingresses on
>> a locked port, an ATU miss violation event will occur. When
>> handling such ATU miss violation interrupts, the MAC address of
>> the device is added to the FDB with a zero destination port
>> vector (DPV) and the MAC address is communicated through the
>> switchdev layer to the bridge, so that a FDB entry with the
>> locked flag enabled can be added.
>
> FWIW, we may have about a 30% - 70% split between switches that will 
> signal ATU violations over a side band interrupt, like mv88e6xxx will, 
> and the rest will likely signal such events via the proprietary tag
> format.

I guess that the proprietary tag scheme a scenario where the packet can
be forwarded to the bridge module's ingress queue on the respective
port?

> -- 
> Florian

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-16 23:34       ` Vladimir Oltean
@ 2022-03-17  8:52         ` Hans Schultz
  2022-03-17 14:19           ` Andrew Lunn
  0 siblings, 1 reply; 63+ messages in thread
From: Hans Schultz @ 2022-03-17  8:52 UTC (permalink / raw)
  To: Vladimir Oltean, Hans Schultz
  Cc: davem, kuba, netdev, Andrew Lunn, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On tor, mar 17, 2022 at 01:34, Vladimir Oltean <olteanv@gmail.com> wrote:
> On Mon, Mar 14, 2022 at 11:46:51AM +0100, Hans Schultz wrote:
>> >> @@ -396,6 +414,13 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
>> >>  				    "ATU miss violation for %pM portvec %x spid %d\n",
>> >>  				    entry.mac, entry.portvec, spid);
>> >>  		chip->ports[spid].atu_miss_violation++;
>> >> +		if (mv88e6xxx_port_is_locked(chip, chip->ports[spid].port))
>> >> +			err = mv88e6xxx_switchdev_handle_atu_miss_violation(chip,
>> >> +									    chip->ports[spid].port,
>> >> +									    &entry,
>> >> +									    fid);
>> >
>> > Do we want to suppress the ATU miss violation warnings if we're going to
>> > notify the bridge, or is it better to keep them for some reason?
>> > My logic is that they're part of normal operation, so suppressing makes
>> > sense.
>> >
>> 
>> I have been seeing many ATU member violations after the miss violation is
>> handled (using ping), and I think it could be considered to suppress the ATU member
>> violations interrupts by setting the IgnoreWrongData bit for the
>> port (sect 4.4.7). This would be something to do whenever a port is set in locked mode?
>
> So the first packet with a given MAC SA triggers an ATU miss violation
> interrupt.
>
> You program that MAC SA into the ATU with a destination port mask of all
> zeroes. This suppresses further ATU miss interrupts for this MAC SA, but
> now generates ATU member violations, because the MAC SA _is_ present in
> the ATU, but not towards the expected port (in fact, towards _no_ port).
>
> Especially if user space decides it doesn't want to authorize this MAC
> SA, it really becomes a problem because this is now a vector for denial
> of service, with every packet triggering an ATU member violation
> interrupt.
>
> So your suggestion is to set the IgnoreWrongData bit on locked ports,
> and this will suppress the actual member violation interrupts for
> traffic coming from these ports.
>
> So if the user decides to unplug a previously authorized printer from
> switch port 1 and move it to port 2, how is this handled? If there isn't
> a mechanism in place to delete the locked FDB entry when the printer
> goes away, then by setting IgnoreWrongData you're effectively also
> suppressing migration notifications.

I don't think such a scenario is so realistic, as changing port is not
just something done casually, besides port 2 then must also be a locked
port to have the same policy.

The other aspect is that the user space daemon that authorizes catches
the fdb add entry events and checks if it is a locked entry. So it will
be up to said daemon to decide the policy, like remove the fdb entry
after a timeout.

>
> Oh, btw, my question was: could you consider suppressing the _prints_ on
> an ATU miss violation on a locked port?

As there will only be such on the first packet, I think it should be
logged and those prints serve that purpose, so I think it is best to
keep the print.
If in the future some tests or other can argue for suppressing the
prints, it is an easy thing to do.

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-17  8:52         ` Hans Schultz
@ 2022-03-17 14:19           ` Andrew Lunn
  2022-03-17 15:36             ` Vladimir Oltean
  2022-03-21 14:51             ` Hans Schultz
  0 siblings, 2 replies; 63+ messages in thread
From: Andrew Lunn @ 2022-03-17 14:19 UTC (permalink / raw)
  To: Hans Schultz
  Cc: Vladimir Oltean, davem, kuba, netdev, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On Thu, Mar 17, 2022 at 09:52:15AM +0100, Hans Schultz wrote:
> On tor, mar 17, 2022 at 01:34, Vladimir Oltean <olteanv@gmail.com> wrote:
> > On Mon, Mar 14, 2022 at 11:46:51AM +0100, Hans Schultz wrote:
> >> >> @@ -396,6 +414,13 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
> >> >>  				    "ATU miss violation for %pM portvec %x spid %d\n",
> >> >>  				    entry.mac, entry.portvec, spid);
> >> >>  		chip->ports[spid].atu_miss_violation++;
> >> >> +		if (mv88e6xxx_port_is_locked(chip, chip->ports[spid].port))
> >> >> +			err = mv88e6xxx_switchdev_handle_atu_miss_violation(chip,
> >> >> +									    chip->ports[spid].port,
> >> >> +									    &entry,
> >> >> +									    fid);
> >> >
> >> > Do we want to suppress the ATU miss violation warnings if we're going to
> >> > notify the bridge, or is it better to keep them for some reason?
> >> > My logic is that they're part of normal operation, so suppressing makes
> >> > sense.
> >> >
> >> 
> >> I have been seeing many ATU member violations after the miss violation is
> >> handled (using ping), and I think it could be considered to suppress the ATU member
> >> violations interrupts by setting the IgnoreWrongData bit for the
> >> port (sect 4.4.7). This would be something to do whenever a port is set in locked mode?
> >
> > So the first packet with a given MAC SA triggers an ATU miss violation
> > interrupt.
> >
> > You program that MAC SA into the ATU with a destination port mask of all
> > zeroes. This suppresses further ATU miss interrupts for this MAC SA, but
> > now generates ATU member violations, because the MAC SA _is_ present in
> > the ATU, but not towards the expected port (in fact, towards _no_ port).
> >
> > Especially if user space decides it doesn't want to authorize this MAC
> > SA, it really becomes a problem because this is now a vector for denial
> > of service, with every packet triggering an ATU member violation
> > interrupt.
> >
> > So your suggestion is to set the IgnoreWrongData bit on locked ports,
> > and this will suppress the actual member violation interrupts for
> > traffic coming from these ports.
> >
> > So if the user decides to unplug a previously authorized printer from
> > switch port 1 and move it to port 2, how is this handled? If there isn't
> > a mechanism in place to delete the locked FDB entry when the printer
> > goes away, then by setting IgnoreWrongData you're effectively also
> > suppressing migration notifications.
> 
> I don't think such a scenario is so realistic, as changing port is not
> just something done casually, besides port 2 then must also be a locked
> port to have the same policy.

I think it is very realistic. It is also something which does not work
is going to cause a lot of confusion. People will blame the printer,
when in fact they should be blaming the switch. They will be rebooting
the printer, when in fact, they need to reboot the switch etc.

I expect there is a way to cleanly support this, you just need to
figure it out.

> The other aspect is that the user space daemon that authorizes catches
> the fdb add entry events and checks if it is a locked entry. So it will
> be up to said daemon to decide the policy, like remove the fdb entry
> after a timeout.
> 
> >
> > Oh, btw, my question was: could you consider suppressing the _prints_ on
> > an ATU miss violation on a locked port?
> 
> As there will only be such on the first packet, I think it should be
> logged and those prints serve that purpose, so I think it is best to
> keep the print.
> If in the future some tests or other can argue for suppressing the
> prints, it is an easy thing to do.

Please use a traffic generator and try to DOS one of your own
switches. Can you?

	  Andrew

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-17 14:19           ` Andrew Lunn
@ 2022-03-17 15:36             ` Vladimir Oltean
  2022-03-17 16:07               ` Hans Schultz
  2022-03-21 14:51             ` Hans Schultz
  1 sibling, 1 reply; 63+ messages in thread
From: Vladimir Oltean @ 2022-03-17 15:36 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Hans Schultz, davem, kuba, netdev, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On Thu, Mar 17, 2022 at 03:19:46PM +0100, Andrew Lunn wrote:
> On Thu, Mar 17, 2022 at 09:52:15AM +0100, Hans Schultz wrote:
> > On tor, mar 17, 2022 at 01:34, Vladimir Oltean <olteanv@gmail.com> wrote:
> > > On Mon, Mar 14, 2022 at 11:46:51AM +0100, Hans Schultz wrote:
> > >> >> @@ -396,6 +414,13 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
> > >> >>  				    "ATU miss violation for %pM portvec %x spid %d\n",
> > >> >>  				    entry.mac, entry.portvec, spid);
> > >> >>  		chip->ports[spid].atu_miss_violation++;
> > >> >> +		if (mv88e6xxx_port_is_locked(chip, chip->ports[spid].port))
> > >> >> +			err = mv88e6xxx_switchdev_handle_atu_miss_violation(chip,
> > >> >> +									    chip->ports[spid].port,
> > >> >> +									    &entry,
> > >> >> +									    fid);
> > >> >
> > >> > Do we want to suppress the ATU miss violation warnings if we're going to
> > >> > notify the bridge, or is it better to keep them for some reason?
> > >> > My logic is that they're part of normal operation, so suppressing makes
> > >> > sense.
> > >> >
> > >> 
> > >> I have been seeing many ATU member violations after the miss violation is
> > >> handled (using ping), and I think it could be considered to suppress the ATU member
> > >> violations interrupts by setting the IgnoreWrongData bit for the
> > >> port (sect 4.4.7). This would be something to do whenever a port is set in locked mode?
> > >
> > > So the first packet with a given MAC SA triggers an ATU miss violation
> > > interrupt.
> > >
> > > You program that MAC SA into the ATU with a destination port mask of all
> > > zeroes. This suppresses further ATU miss interrupts for this MAC SA, but
> > > now generates ATU member violations, because the MAC SA _is_ present in
> > > the ATU, but not towards the expected port (in fact, towards _no_ port).
> > >
> > > Especially if user space decides it doesn't want to authorize this MAC
> > > SA, it really becomes a problem because this is now a vector for denial
> > > of service, with every packet triggering an ATU member violation
> > > interrupt.
> > >
> > > So your suggestion is to set the IgnoreWrongData bit on locked ports,
> > > and this will suppress the actual member violation interrupts for
> > > traffic coming from these ports.
> > >
> > > So if the user decides to unplug a previously authorized printer from
> > > switch port 1 and move it to port 2, how is this handled? If there isn't
> > > a mechanism in place to delete the locked FDB entry when the printer
> > > goes away, then by setting IgnoreWrongData you're effectively also
> > > suppressing migration notifications.
> > 
> > I don't think such a scenario is so realistic, as changing port is not
> > just something done casually, besides port 2 then must also be a locked
> > port to have the same policy.
> 
> I think it is very realistic. It is also something which does not work
> is going to cause a lot of confusion. People will blame the printer,
> when in fact they should be blaming the switch. They will be rebooting
> the printer, when in fact, they need to reboot the switch etc.
> 
> I expect there is a way to cleanly support this, you just need to
> figure it out.

Hans, why must port 2 also be a locked port? The FDB entry with no
destinations is present in the ATU, and static, why would just locked
ports match it?

> > The other aspect is that the user space daemon that authorizes catches
> > the fdb add entry events and checks if it is a locked entry. So it will
> > be up to said daemon to decide the policy, like remove the fdb entry
> > after a timeout.

When you say 'timeout', what is the moment when the timer starts counting?
The last reception of the user space daemon of a packet with this MAC SA,
or the moment when the FDB entry originally became unlocked?

I expect that once a device is authorized, and forwarding towards the
devices that it wants to talk to is handled in hardware, that the CPU no
longer receives packets from this device. In other words, are you saying
that you're going to break networking for the printer every 5 minutes,
as a keepalive measure?

I still think there should be a functional fast path for authorized
station migrations.

> > > Oh, btw, my question was: could you consider suppressing the _prints_ on
> > > an ATU miss violation on a locked port?
> > 
> > As there will only be such on the first packet, I think it should be
> > logged and those prints serve that purpose, so I think it is best to
> > keep the print.
> > If in the future some tests or other can argue for suppressing the
> > prints, it is an easy thing to do.
> 
> Please use a traffic generator and try to DOS one of your own
> switches. Can you?
> 
> 	  Andrew

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-17 15:36             ` Vladimir Oltean
@ 2022-03-17 16:07               ` Hans Schultz
  2022-03-17 16:18                 ` Vladimir Oltean
  0 siblings, 1 reply; 63+ messages in thread
From: Hans Schultz @ 2022-03-17 16:07 UTC (permalink / raw)
  To: Vladimir Oltean, Andrew Lunn
  Cc: Hans Schultz, davem, kuba, netdev, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On tor, mar 17, 2022 at 17:36, Vladimir Oltean <olteanv@gmail.com> wrote:
> On Thu, Mar 17, 2022 at 03:19:46PM +0100, Andrew Lunn wrote:
>> On Thu, Mar 17, 2022 at 09:52:15AM +0100, Hans Schultz wrote:
>> > On tor, mar 17, 2022 at 01:34, Vladimir Oltean <olteanv@gmail.com> wrote:
>> > > On Mon, Mar 14, 2022 at 11:46:51AM +0100, Hans Schultz wrote:
>> > >> >> @@ -396,6 +414,13 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
>> > >> >>  				    "ATU miss violation for %pM portvec %x spid %d\n",
>> > >> >>  				    entry.mac, entry.portvec, spid);
>> > >> >>  		chip->ports[spid].atu_miss_violation++;
>> > >> >> +		if (mv88e6xxx_port_is_locked(chip, chip->ports[spid].port))
>> > >> >> +			err = mv88e6xxx_switchdev_handle_atu_miss_violation(chip,
>> > >> >> +									    chip->ports[spid].port,
>> > >> >> +									    &entry,
>> > >> >> +									    fid);
>> > >> >
>> > >> > Do we want to suppress the ATU miss violation warnings if we're going to
>> > >> > notify the bridge, or is it better to keep them for some reason?
>> > >> > My logic is that they're part of normal operation, so suppressing makes
>> > >> > sense.
>> > >> >
>> > >> 
>> > >> I have been seeing many ATU member violations after the miss violation is
>> > >> handled (using ping), and I think it could be considered to suppress the ATU member
>> > >> violations interrupts by setting the IgnoreWrongData bit for the
>> > >> port (sect 4.4.7). This would be something to do whenever a port is set in locked mode?
>> > >
>> > > So the first packet with a given MAC SA triggers an ATU miss violation
>> > > interrupt.
>> > >
>> > > You program that MAC SA into the ATU with a destination port mask of all
>> > > zeroes. This suppresses further ATU miss interrupts for this MAC SA, but
>> > > now generates ATU member violations, because the MAC SA _is_ present in
>> > > the ATU, but not towards the expected port (in fact, towards _no_ port).
>> > >
>> > > Especially if user space decides it doesn't want to authorize this MAC
>> > > SA, it really becomes a problem because this is now a vector for denial
>> > > of service, with every packet triggering an ATU member violation
>> > > interrupt.
>> > >
>> > > So your suggestion is to set the IgnoreWrongData bit on locked ports,
>> > > and this will suppress the actual member violation interrupts for
>> > > traffic coming from these ports.
>> > >
>> > > So if the user decides to unplug a previously authorized printer from
>> > > switch port 1 and move it to port 2, how is this handled? If there isn't
>> > > a mechanism in place to delete the locked FDB entry when the printer
>> > > goes away, then by setting IgnoreWrongData you're effectively also
>> > > suppressing migration notifications.
>> > 
>> > I don't think such a scenario is so realistic, as changing port is not
>> > just something done casually, besides port 2 then must also be a locked
>> > port to have the same policy.
>> 
>> I think it is very realistic. It is also something which does not work
>> is going to cause a lot of confusion. People will blame the printer,
>> when in fact they should be blaming the switch. They will be rebooting
>> the printer, when in fact, they need to reboot the switch etc.
>> 
>> I expect there is a way to cleanly support this, you just need to
>> figure it out.
>
> Hans, why must port 2 also be a locked port? The FDB entry with no
> destinations is present in the ATU, and static, why would just locked
> ports match it?
>
You are right of course, but it was more from a policy standpoint as I
pointed out. If the FDB entry is removed after some timeout and the
device in the meantime somehow is on another port that is not locked
with full access, the device will of course get full access.
But since it was not given access in the first instance, the policy is
not consistent.

>> > The other aspect is that the user space daemon that authorizes catches
>> > the fdb add entry events and checks if it is a locked entry. So it will
>> > be up to said daemon to decide the policy, like remove the fdb entry
>> > after a timeout.
>
> When you say 'timeout', what is the moment when the timer starts counting?
> The last reception of the user space daemon of a packet with this MAC SA,
> or the moment when the FDB entry originally became unlocked?

I think that if the device is not given access, a timer should be
started at that moment. No further FDB add events with the same MAC
address will come of course until the FDB entry is removed, which I
think would be done based on the said timer.
>
> I expect that once a device is authorized, and forwarding towards the
> devices that it wants to talk to is handled in hardware, that the CPU no
> longer receives packets from this device. In other words, are you saying
> that you're going to break networking for the printer every 5 minutes,
> as a keepalive measure?

No, I don't think that would be a good idea, but as we are in userspace,
that is a policy decision of those creating the daemon. The kernel just
facilitates, it does not make those decisions as far as I think.
>
> I still think there should be a functional fast path for authorized
> station migrations.
>
I am not sure in what way you are suggesting that should be, if the
kernel should actively do something there? If a station is authorized,
and somehow is transferred to another port, if that port is not locked it
will get access, if the port is locked a miss violation will occur etc...

>> > > Oh, btw, my question was: could you consider suppressing the _prints_ on
>> > > an ATU miss violation on a locked port?
>> > 
>> > As there will only be such on the first packet, I think it should be
>> > logged and those prints serve that purpose, so I think it is best to
>> > keep the print.
>> > If in the future some tests or other can argue for suppressing the
>> > prints, it is an easy thing to do.
>> 
>> Please use a traffic generator and try to DOS one of your own
>> switches. Can you?
>> 
>> 	  Andrew

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-17 16:07               ` Hans Schultz
@ 2022-03-17 16:18                 ` Vladimir Oltean
  2022-03-17 16:58                   ` Hans Schultz
  0 siblings, 1 reply; 63+ messages in thread
From: Vladimir Oltean @ 2022-03-17 16:18 UTC (permalink / raw)
  To: Hans Schultz
  Cc: Andrew Lunn, davem, kuba, netdev, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On Thu, Mar 17, 2022 at 05:07:15PM +0100, Hans Schultz wrote:
> On tor, mar 17, 2022 at 17:36, Vladimir Oltean <olteanv@gmail.com> wrote:
> > On Thu, Mar 17, 2022 at 03:19:46PM +0100, Andrew Lunn wrote:
> >> On Thu, Mar 17, 2022 at 09:52:15AM +0100, Hans Schultz wrote:
> >> > On tor, mar 17, 2022 at 01:34, Vladimir Oltean <olteanv@gmail.com> wrote:
> >> > > On Mon, Mar 14, 2022 at 11:46:51AM +0100, Hans Schultz wrote:
> >> > >> >> @@ -396,6 +414,13 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
> >> > >> >>  				    "ATU miss violation for %pM portvec %x spid %d\n",
> >> > >> >>  				    entry.mac, entry.portvec, spid);
> >> > >> >>  		chip->ports[spid].atu_miss_violation++;
> >> > >> >> +		if (mv88e6xxx_port_is_locked(chip, chip->ports[spid].port))
> >> > >> >> +			err = mv88e6xxx_switchdev_handle_atu_miss_violation(chip,
> >> > >> >> +									    chip->ports[spid].port,
> >> > >> >> +									    &entry,
> >> > >> >> +									    fid);
> >> > >> >
> >> > >> > Do we want to suppress the ATU miss violation warnings if we're going to
> >> > >> > notify the bridge, or is it better to keep them for some reason?
> >> > >> > My logic is that they're part of normal operation, so suppressing makes
> >> > >> > sense.
> >> > >> >
> >> > >> 
> >> > >> I have been seeing many ATU member violations after the miss violation is
> >> > >> handled (using ping), and I think it could be considered to suppress the ATU member
> >> > >> violations interrupts by setting the IgnoreWrongData bit for the
> >> > >> port (sect 4.4.7). This would be something to do whenever a port is set in locked mode?
> >> > >
> >> > > So the first packet with a given MAC SA triggers an ATU miss violation
> >> > > interrupt.
> >> > >
> >> > > You program that MAC SA into the ATU with a destination port mask of all
> >> > > zeroes. This suppresses further ATU miss interrupts for this MAC SA, but
> >> > > now generates ATU member violations, because the MAC SA _is_ present in
> >> > > the ATU, but not towards the expected port (in fact, towards _no_ port).
> >> > >
> >> > > Especially if user space decides it doesn't want to authorize this MAC
> >> > > SA, it really becomes a problem because this is now a vector for denial
> >> > > of service, with every packet triggering an ATU member violation
> >> > > interrupt.
> >> > >
> >> > > So your suggestion is to set the IgnoreWrongData bit on locked ports,
> >> > > and this will suppress the actual member violation interrupts for
> >> > > traffic coming from these ports.
> >> > >
> >> > > So if the user decides to unplug a previously authorized printer from
> >> > > switch port 1 and move it to port 2, how is this handled? If there isn't
> >> > > a mechanism in place to delete the locked FDB entry when the printer
> >> > > goes away, then by setting IgnoreWrongData you're effectively also
> >> > > suppressing migration notifications.
> >> > 
> >> > I don't think such a scenario is so realistic, as changing port is not
> >> > just something done casually, besides port 2 then must also be a locked
> >> > port to have the same policy.
> >> 
> >> I think it is very realistic. It is also something which does not work
> >> is going to cause a lot of confusion. People will blame the printer,
> >> when in fact they should be blaming the switch. They will be rebooting
> >> the printer, when in fact, they need to reboot the switch etc.
> >> 
> >> I expect there is a way to cleanly support this, you just need to
> >> figure it out.
> >
> > Hans, why must port 2 also be a locked port? The FDB entry with no
> > destinations is present in the ATU, and static, why would just locked
> > ports match it?
> >
> You are right of course, but it was more from a policy standpoint as I
> pointed out. If the FDB entry is removed after some timeout and the
> device in the meantime somehow is on another port that is not locked
> with full access, the device will of course get full access.
> But since it was not given access in the first instance, the policy is
> not consistent.
> 
> >> > The other aspect is that the user space daemon that authorizes catches
> >> > the fdb add entry events and checks if it is a locked entry. So it will
> >> > be up to said daemon to decide the policy, like remove the fdb entry
> >> > after a timeout.
> >
> > When you say 'timeout', what is the moment when the timer starts counting?
> > The last reception of the user space daemon of a packet with this MAC SA,
> > or the moment when the FDB entry originally became unlocked?
> 
> I think that if the device is not given access, a timer should be
> started at that moment. No further FDB add events with the same MAC
> address will come of course until the FDB entry is removed, which I
> think would be done based on the said timer.
> >
> > I expect that once a device is authorized, and forwarding towards the
> > devices that it wants to talk to is handled in hardware, that the CPU no
> > longer receives packets from this device. In other words, are you saying
> > that you're going to break networking for the printer every 5 minutes,
> > as a keepalive measure?
> 
> No, I don't think that would be a good idea, but as we are in userspace,
> that is a policy decision of those creating the daemon. The kernel just
> facilitates, it does not make those decisions as far as I think.
> >
> > I still think there should be a functional fast path for authorized
> > station migrations.
> >
> I am not sure in what way you are suggesting that should be, if the
> kernel should actively do something there? If a station is authorized,
> and somehow is transferred to another port, if that port is not locked it
> will get access, if the port is locked a miss violation will occur etc...

Wait, if the new port is locked and the device was previously
authorized, why will the new port trigger a miss violation? This is the
part I'm not following. The authorization is still present in the form
of an ATU entry on the old locked port, is it not?

> >> > > Oh, btw, my question was: could you consider suppressing the _prints_ on
> >> > > an ATU miss violation on a locked port?
> >> > 
> >> > As there will only be such on the first packet, I think it should be
> >> > logged and those prints serve that purpose, so I think it is best to
> >> > keep the print.
> >> > If in the future some tests or other can argue for suppressing the
> >> > prints, it is an easy thing to do.
> >> 
> >> Please use a traffic generator and try to DOS one of your own
> >> switches. Can you?
> >> 
> >> 	  Andrew

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-17 16:18                 ` Vladimir Oltean
@ 2022-03-17 16:58                   ` Hans Schultz
  2022-03-17 17:20                     ` Vladimir Oltean
  0 siblings, 1 reply; 63+ messages in thread
From: Hans Schultz @ 2022-03-17 16:58 UTC (permalink / raw)
  To: Vladimir Oltean, Hans Schultz
  Cc: Andrew Lunn, davem, kuba, netdev, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On tor, mar 17, 2022 at 18:18, Vladimir Oltean <olteanv@gmail.com> wrote:
> On Thu, Mar 17, 2022 at 05:07:15PM +0100, Hans Schultz wrote:
>> On tor, mar 17, 2022 at 17:36, Vladimir Oltean <olteanv@gmail.com> wrote:
>> > On Thu, Mar 17, 2022 at 03:19:46PM +0100, Andrew Lunn wrote:
>> >> On Thu, Mar 17, 2022 at 09:52:15AM +0100, Hans Schultz wrote:
>> >> > On tor, mar 17, 2022 at 01:34, Vladimir Oltean <olteanv@gmail.com> wrote:
>> >> > > On Mon, Mar 14, 2022 at 11:46:51AM +0100, Hans Schultz wrote:
>> >> > >> >> @@ -396,6 +414,13 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
>> >> > >> >>  				    "ATU miss violation for %pM portvec %x spid %d\n",
>> >> > >> >>  				    entry.mac, entry.portvec, spid);
>> >> > >> >>  		chip->ports[spid].atu_miss_violation++;
>> >> > >> >> +		if (mv88e6xxx_port_is_locked(chip, chip->ports[spid].port))
>> >> > >> >> +			err = mv88e6xxx_switchdev_handle_atu_miss_violation(chip,
>> >> > >> >> +									    chip->ports[spid].port,
>> >> > >> >> +									    &entry,
>> >> > >> >> +									    fid);
>> >> > >> >
>> >> > >> > Do we want to suppress the ATU miss violation warnings if we're going to
>> >> > >> > notify the bridge, or is it better to keep them for some reason?
>> >> > >> > My logic is that they're part of normal operation, so suppressing makes
>> >> > >> > sense.
>> >> > >> >
>> >> > >> 
>> >> > >> I have been seeing many ATU member violations after the miss violation is
>> >> > >> handled (using ping), and I think it could be considered to suppress the ATU member
>> >> > >> violations interrupts by setting the IgnoreWrongData bit for the
>> >> > >> port (sect 4.4.7). This would be something to do whenever a port is set in locked mode?
>> >> > >
>> >> > > So the first packet with a given MAC SA triggers an ATU miss violation
>> >> > > interrupt.
>> >> > >
>> >> > > You program that MAC SA into the ATU with a destination port mask of all
>> >> > > zeroes. This suppresses further ATU miss interrupts for this MAC SA, but
>> >> > > now generates ATU member violations, because the MAC SA _is_ present in
>> >> > > the ATU, but not towards the expected port (in fact, towards _no_ port).
>> >> > >
>> >> > > Especially if user space decides it doesn't want to authorize this MAC
>> >> > > SA, it really becomes a problem because this is now a vector for denial
>> >> > > of service, with every packet triggering an ATU member violation
>> >> > > interrupt.
>> >> > >
>> >> > > So your suggestion is to set the IgnoreWrongData bit on locked ports,
>> >> > > and this will suppress the actual member violation interrupts for
>> >> > > traffic coming from these ports.
>> >> > >
>> >> > > So if the user decides to unplug a previously authorized printer from
>> >> > > switch port 1 and move it to port 2, how is this handled? If there isn't
>> >> > > a mechanism in place to delete the locked FDB entry when the printer
>> >> > > goes away, then by setting IgnoreWrongData you're effectively also
>> >> > > suppressing migration notifications.
>> >> > 
>> >> > I don't think such a scenario is so realistic, as changing port is not
>> >> > just something done casually, besides port 2 then must also be a locked
>> >> > port to have the same policy.
>> >> 
>> >> I think it is very realistic. It is also something which does not work
>> >> is going to cause a lot of confusion. People will blame the printer,
>> >> when in fact they should be blaming the switch. They will be rebooting
>> >> the printer, when in fact, they need to reboot the switch etc.
>> >> 
>> >> I expect there is a way to cleanly support this, you just need to
>> >> figure it out.
>> >
>> > Hans, why must port 2 also be a locked port? The FDB entry with no
>> > destinations is present in the ATU, and static, why would just locked
>> > ports match it?
>> >
>> You are right of course, but it was more from a policy standpoint as I
>> pointed out. If the FDB entry is removed after some timeout and the
>> device in the meantime somehow is on another port that is not locked
>> with full access, the device will of course get full access.
>> But since it was not given access in the first instance, the policy is
>> not consistent.
>> 
>> >> > The other aspect is that the user space daemon that authorizes catches
>> >> > the fdb add entry events and checks if it is a locked entry. So it will
>> >> > be up to said daemon to decide the policy, like remove the fdb entry
>> >> > after a timeout.
>> >
>> > When you say 'timeout', what is the moment when the timer starts counting?
>> > The last reception of the user space daemon of a packet with this MAC SA,
>> > or the moment when the FDB entry originally became unlocked?
>> 
>> I think that if the device is not given access, a timer should be
>> started at that moment. No further FDB add events with the same MAC
>> address will come of course until the FDB entry is removed, which I
>> think would be done based on the said timer.
>> >
>> > I expect that once a device is authorized, and forwarding towards the
>> > devices that it wants to talk to is handled in hardware, that the CPU no
>> > longer receives packets from this device. In other words, are you saying
>> > that you're going to break networking for the printer every 5 minutes,
>> > as a keepalive measure?
>> 
>> No, I don't think that would be a good idea, but as we are in userspace,
>> that is a policy decision of those creating the daemon. The kernel just
>> facilitates, it does not make those decisions as far as I think.
>> >
>> > I still think there should be a functional fast path for authorized
>> > station migrations.
>> >
>> I am not sure in what way you are suggesting that should be, if the
>> kernel should actively do something there? If a station is authorized,
>> and somehow is transferred to another port, if that port is not locked it
>> will get access, if the port is locked a miss violation will occur etc...
>
> Wait, if the new port is locked and the device was previously
> authorized, why will the new port trigger a miss violation? This is the
> part I'm not following. The authorization is still present in the form
> of an ATU entry on the old locked port, is it not?
>
I am sure (have not tested) that a miss violation will occur. It might
be a member violation in this instance though.
When thinking of it, afaik there is no way today of having fine control
over the DPV when adding a FDB entry.
If the DPV could be finer controlled the entry could cover several
possible ports and the fast (immediate migration) will be accomplished?

>> >> > > Oh, btw, my question was: could you consider suppressing the _prints_ on
>> >> > > an ATU miss violation on a locked port?
>> >> > 
>> >> > As there will only be such on the first packet, I think it should be
>> >> > logged and those prints serve that purpose, so I think it is best to
>> >> > keep the print.
>> >> > If in the future some tests or other can argue for suppressing the
>> >> > prints, it is an easy thing to do.
>> >> 
>> >> Please use a traffic generator and try to DOS one of your own
>> >> switches. Can you?
>> >> 
>> >> 	  Andrew

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-17 16:58                   ` Hans Schultz
@ 2022-03-17 17:20                     ` Vladimir Oltean
  2022-03-18 10:04                       ` Hans Schultz
  0 siblings, 1 reply; 63+ messages in thread
From: Vladimir Oltean @ 2022-03-17 17:20 UTC (permalink / raw)
  To: Hans Schultz
  Cc: Andrew Lunn, davem, kuba, netdev, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On Thu, Mar 17, 2022 at 05:58:26PM +0100, Hans Schultz wrote:
> On tor, mar 17, 2022 at 18:18, Vladimir Oltean <olteanv@gmail.com> wrote:
> > On Thu, Mar 17, 2022 at 05:07:15PM +0100, Hans Schultz wrote:
> >> On tor, mar 17, 2022 at 17:36, Vladimir Oltean <olteanv@gmail.com> wrote:
> >> > On Thu, Mar 17, 2022 at 03:19:46PM +0100, Andrew Lunn wrote:
> >> >> On Thu, Mar 17, 2022 at 09:52:15AM +0100, Hans Schultz wrote:
> >> >> > On tor, mar 17, 2022 at 01:34, Vladimir Oltean <olteanv@gmail.com> wrote:
> >> >> > > On Mon, Mar 14, 2022 at 11:46:51AM +0100, Hans Schultz wrote:
> >> >> > >> >> @@ -396,6 +414,13 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
> >> >> > >> >>  				    "ATU miss violation for %pM portvec %x spid %d\n",
> >> >> > >> >>  				    entry.mac, entry.portvec, spid);
> >> >> > >> >>  		chip->ports[spid].atu_miss_violation++;
> >> >> > >> >> +		if (mv88e6xxx_port_is_locked(chip, chip->ports[spid].port))
> >> >> > >> >> +			err = mv88e6xxx_switchdev_handle_atu_miss_violation(chip,
> >> >> > >> >> +									    chip->ports[spid].port,
> >> >> > >> >> +									    &entry,
> >> >> > >> >> +									    fid);
> >> >> > >> >
> >> >> > >> > Do we want to suppress the ATU miss violation warnings if we're going to
> >> >> > >> > notify the bridge, or is it better to keep them for some reason?
> >> >> > >> > My logic is that they're part of normal operation, so suppressing makes
> >> >> > >> > sense.
> >> >> > >> >
> >> >> > >> 
> >> >> > >> I have been seeing many ATU member violations after the miss violation is
> >> >> > >> handled (using ping), and I think it could be considered to suppress the ATU member
> >> >> > >> violations interrupts by setting the IgnoreWrongData bit for the
> >> >> > >> port (sect 4.4.7). This would be something to do whenever a port is set in locked mode?
> >> >> > >
> >> >> > > So the first packet with a given MAC SA triggers an ATU miss violation
> >> >> > > interrupt.
> >> >> > >
> >> >> > > You program that MAC SA into the ATU with a destination port mask of all
> >> >> > > zeroes. This suppresses further ATU miss interrupts for this MAC SA, but
> >> >> > > now generates ATU member violations, because the MAC SA _is_ present in
> >> >> > > the ATU, but not towards the expected port (in fact, towards _no_ port).
> >> >> > >
> >> >> > > Especially if user space decides it doesn't want to authorize this MAC
> >> >> > > SA, it really becomes a problem because this is now a vector for denial
> >> >> > > of service, with every packet triggering an ATU member violation
> >> >> > > interrupt.
> >> >> > >
> >> >> > > So your suggestion is to set the IgnoreWrongData bit on locked ports,
> >> >> > > and this will suppress the actual member violation interrupts for
> >> >> > > traffic coming from these ports.
> >> >> > >
> >> >> > > So if the user decides to unplug a previously authorized printer from
> >> >> > > switch port 1 and move it to port 2, how is this handled? If there isn't
> >> >> > > a mechanism in place to delete the locked FDB entry when the printer
> >> >> > > goes away, then by setting IgnoreWrongData you're effectively also
> >> >> > > suppressing migration notifications.
> >> >> > 
> >> >> > I don't think such a scenario is so realistic, as changing port is not
> >> >> > just something done casually, besides port 2 then must also be a locked
> >> >> > port to have the same policy.
> >> >> 
> >> >> I think it is very realistic. It is also something which does not work
> >> >> is going to cause a lot of confusion. People will blame the printer,
> >> >> when in fact they should be blaming the switch. They will be rebooting
> >> >> the printer, when in fact, they need to reboot the switch etc.
> >> >> 
> >> >> I expect there is a way to cleanly support this, you just need to
> >> >> figure it out.
> >> >
> >> > Hans, why must port 2 also be a locked port? The FDB entry with no
> >> > destinations is present in the ATU, and static, why would just locked
> >> > ports match it?
> >> >
> >> You are right of course, but it was more from a policy standpoint as I
> >> pointed out. If the FDB entry is removed after some timeout and the
> >> device in the meantime somehow is on another port that is not locked
> >> with full access, the device will of course get full access.
> >> But since it was not given access in the first instance, the policy is
> >> not consistent.
> >> 
> >> >> > The other aspect is that the user space daemon that authorizes catches
> >> >> > the fdb add entry events and checks if it is a locked entry. So it will
> >> >> > be up to said daemon to decide the policy, like remove the fdb entry
> >> >> > after a timeout.
> >> >
> >> > When you say 'timeout', what is the moment when the timer starts counting?
> >> > The last reception of the user space daemon of a packet with this MAC SA,
> >> > or the moment when the FDB entry originally became unlocked?
> >> 
> >> I think that if the device is not given access, a timer should be
> >> started at that moment. No further FDB add events with the same MAC
> >> address will come of course until the FDB entry is removed, which I
> >> think would be done based on the said timer.
> >> >
> >> > I expect that once a device is authorized, and forwarding towards the
> >> > devices that it wants to talk to is handled in hardware, that the CPU no
> >> > longer receives packets from this device. In other words, are you saying
> >> > that you're going to break networking for the printer every 5 minutes,
> >> > as a keepalive measure?
> >> 
> >> No, I don't think that would be a good idea, but as we are in userspace,
> >> that is a policy decision of those creating the daemon. The kernel just
> >> facilitates, it does not make those decisions as far as I think.
> >> >
> >> > I still think there should be a functional fast path for authorized
> >> > station migrations.
> >> >
> >> I am not sure in what way you are suggesting that should be, if the
> >> kernel should actively do something there? If a station is authorized,
> >> and somehow is transferred to another port, if that port is not locked it
> >> will get access, if the port is locked a miss violation will occur etc...
> >
> > Wait, if the new port is locked and the device was previously
> > authorized, why will the new port trigger a miss violation? This is the
> > part I'm not following. The authorization is still present in the form
> > of an ATU entry on the old locked port, is it not?
> >
> I am sure (have not tested) that a miss violation will occur. It might
> be a member violation in this instance though.
> When thinking of it, afaik there is no way today of having fine control
> over the DPV when adding a FDB entry.
> If the DPV could be finer controlled the entry could cover several
> possible ports and the fast (immediate migration) will be accomplished?

I'm not sure I understand this, either.

You're saying we should configure the authorizations as de-facto
multicast ATU entries towards all locked ports, so that there wouldn't
be any violation when a station migrates, because the new port is still
in the destination port mask of the ATU entry?

Yes, but... this leaks traffic between ports to a significant degree.
Any packet that targets your printer now targets your colleague's printer too.

I was expecting you'd say that when the cable is unplugged from the
switch, the authorization daemon is notified through rtnetlink of the
link state change, and it flushes the port of addresses it has added
(because the kernel surely does not do this).

This could work to an extent, but it wouldn't handle the case where the
printer isn't connected directly to the 802.1X port, but through
another dumb switch. I don't know enough about 802.1X, but I don't see
why this isn't a valid configuration.

To explain what I'm thinking of. At office, IT gave one Ethernet port to
each desk, but I have multiple devices. I have a PC, a printer, and a
development board, each with a single Ethernet port, so I use a dumb
4-port switch to connect all these devices to the 802.1X port beneath my
desk. I talked to IT, brought my printer to them, they agreed to bypass
802.1X authorization for it based on the MAC address on its label.

I've been working from home for the past few years, but now I need to
return to office. But since years have passed, some colleagues left,
some new colleagues came, and I need to change my desk. The new one
belonged to a co-worker who also had a dumb switch on his desk, so I see
no reason to move mine too. I unplug the printer from my dumb switch,
plug it into the new one, but it doesn't work. What do I do, open a
ticket to IT asking for halp?

To be honest this is purely fictional and I haven't tried it, but it
sounds like I should when I get the chance, to get a better image of how
things are supposed to work.

> >> >> > > Oh, btw, my question was: could you consider suppressing the _prints_ on
> >> >> > > an ATU miss violation on a locked port?
> >> >> > 
> >> >> > As there will only be such on the first packet, I think it should be
> >> >> > logged and those prints serve that purpose, so I think it is best to
> >> >> > keep the print.
> >> >> > If in the future some tests or other can argue for suppressing the
> >> >> > prints, it is an easy thing to do.
> >> >> 
> >> >> Please use a traffic generator and try to DOS one of your own
> >> >> switches. Can you?
> >> >> 
> >> >> 	  Andrew

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 0/3] Extend locked port feature with FDB locked flag (MAC-Auth/MAB)
  2022-03-17  8:29   ` Hans Schultz
@ 2022-03-17 18:42     ` Vladimir Oltean
  0 siblings, 0 replies; 63+ messages in thread
From: Vladimir Oltean @ 2022-03-17 18:42 UTC (permalink / raw)
  To: Hans Schultz
  Cc: Florian Fainelli, davem, kuba, netdev, Andrew Lunn,
	Vivien Didelot, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On Thu, Mar 17, 2022 at 09:29:10AM +0100, Hans Schultz wrote:
> On ons, mar 16, 2022 at 17:18, Florian Fainelli <f.fainelli@gmail.com> wrote:
> > On 3/10/2022 6:23 AM, Hans Schultz wrote:
> >> This patch set extends the locked port feature for devices
> >> that are behind a locked port, but do not have the ability to
> >> authorize themselves as a supplicant using IEEE 802.1X.
> >> Such devices can be printers, meters or anything related to
> >> fixed installations. Instead of 802.1X authorization, devices
> >> can get access based on their MAC addresses being whitelisted.
> >> 
> >> For an authorization daemon to detect that a device is trying
> >> to get access through a locked port, the bridge will add the
> >> MAC address of the device to the FDB with a locked flag to it.
> >> Thus the authorization daemon can catch the FDB add event and
> >> check if the MAC address is in the whitelist and if so replace
> >> the FDB entry without the locked flag enabled, and thus open
> >> the port for the device.
> >> 
> >> This feature is known as MAC-Auth or MAC Authentication Bypass
> >> (MAB) in Cisco terminology, where the full MAB concept involves
> >> additional Cisco infrastructure for authorization. There is no
> >> real authentication process, as the MAC address of the device
> >> is the only input the authorization daemon, in the general
> >> case, has to base the decision if to unlock the port or not.
> >> 
> >> With this patch set, an implementation of the offloaded case is
> >> supplied for the mv88e6xxx driver. When a packet ingresses on
> >> a locked port, an ATU miss violation event will occur. When
> >> handling such ATU miss violation interrupts, the MAC address of
> >> the device is added to the FDB with a zero destination port
> >> vector (DPV) and the MAC address is communicated through the
> >> switchdev layer to the bridge, so that a FDB entry with the
> >> locked flag enabled can be added.
> >
> > FWIW, we may have about a 30% - 70% split between switches that will 
> > signal ATU violations over a side band interrupt, like mv88e6xxx will, 
> > and the rest will likely signal such events via the proprietary tag
> > format.
> 
> I guess that the proprietary tag scheme a scenario where the packet can
> be forwarded to the bridge module's ingress queue on the respective
> port?

I'm not sure what you mean by forwarding to the bridge module's ingress
queue. I expect that both cases of drivers to interact with the bridge
in the exact same way, expect one of them calls call_switchdev_notifiers()
from an interrupt context, and the other from NET_RX softirq context,
from the tagging protocol driver (ok, maybe not directly, it depends
upon whether we need rtnl_lock which sleeps, things like that).

I might be just projecting based on what I know, but the way I interpret
what Florian has said is by thinking of "learn frames" as described here:
https://patchwork.kernel.org/project/netdevbpf/cover/20220209130538.533699-1-schultz.hans+netdev@gmail.com/#24734685
The advantage of signaling ATU misses or membership violations via learn
frames is that you have a much wider toolbox of mitigations for denial
of service. Instead of one ATU interrupt per packet, you have NAPI on
the DSA master, interrupt coalescing, policers on the DSA master, rate
limiting for learn frames in the switch...

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-17 17:20                     ` Vladimir Oltean
@ 2022-03-18 10:04                       ` Hans Schultz
  2022-03-18 12:14                         ` Vladimir Oltean
  0 siblings, 1 reply; 63+ messages in thread
From: Hans Schultz @ 2022-03-18 10:04 UTC (permalink / raw)
  To: Vladimir Oltean, Hans Schultz
  Cc: Andrew Lunn, davem, kuba, netdev, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On tor, mar 17, 2022 at 19:20, Vladimir Oltean <olteanv@gmail.com> wrote:
> On Thu, Mar 17, 2022 at 05:58:26PM +0100, Hans Schultz wrote:
>> On tor, mar 17, 2022 at 18:18, Vladimir Oltean <olteanv@gmail.com> wrote:
>> > On Thu, Mar 17, 2022 at 05:07:15PM +0100, Hans Schultz wrote:
>> >> On tor, mar 17, 2022 at 17:36, Vladimir Oltean <olteanv@gmail.com> wrote:
>> >> > On Thu, Mar 17, 2022 at 03:19:46PM +0100, Andrew Lunn wrote:
>> >> >> On Thu, Mar 17, 2022 at 09:52:15AM +0100, Hans Schultz wrote:
>> >> >> > On tor, mar 17, 2022 at 01:34, Vladimir Oltean <olteanv@gmail.com> wrote:
>> >> >> > > On Mon, Mar 14, 2022 at 11:46:51AM +0100, Hans Schultz wrote:
>> >> >> > >> >> @@ -396,6 +414,13 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
>> >> >> > >> >>  				    "ATU miss violation for %pM portvec %x spid %d\n",
>> >> >> > >> >>  				    entry.mac, entry.portvec, spid);
>> >> >> > >> >>  		chip->ports[spid].atu_miss_violation++;
>> >> >> > >> >> +		if (mv88e6xxx_port_is_locked(chip, chip->ports[spid].port))
>> >> >> > >> >> +			err = mv88e6xxx_switchdev_handle_atu_miss_violation(chip,
>> >> >> > >> >> +									    chip->ports[spid].port,
>> >> >> > >> >> +									    &entry,
>> >> >> > >> >> +									    fid);
>> >> >> > >> >
>> >> >> > >> > Do we want to suppress the ATU miss violation warnings if we're going to
>> >> >> > >> > notify the bridge, or is it better to keep them for some reason?
>> >> >> > >> > My logic is that they're part of normal operation, so suppressing makes
>> >> >> > >> > sense.
>> >> >> > >> >
>> >> >> > >> 
>> >> >> > >> I have been seeing many ATU member violations after the miss violation is
>> >> >> > >> handled (using ping), and I think it could be considered to suppress the ATU member
>> >> >> > >> violations interrupts by setting the IgnoreWrongData bit for the
>> >> >> > >> port (sect 4.4.7). This would be something to do whenever a port is set in locked mode?
>> >> >> > >
>> >> >> > > So the first packet with a given MAC SA triggers an ATU miss violation
>> >> >> > > interrupt.
>> >> >> > >
>> >> >> > > You program that MAC SA into the ATU with a destination port mask of all
>> >> >> > > zeroes. This suppresses further ATU miss interrupts for this MAC SA, but
>> >> >> > > now generates ATU member violations, because the MAC SA _is_ present in
>> >> >> > > the ATU, but not towards the expected port (in fact, towards _no_ port).
>> >> >> > >
>> >> >> > > Especially if user space decides it doesn't want to authorize this MAC
>> >> >> > > SA, it really becomes a problem because this is now a vector for denial
>> >> >> > > of service, with every packet triggering an ATU member violation
>> >> >> > > interrupt.
>> >> >> > >
>> >> >> > > So your suggestion is to set the IgnoreWrongData bit on locked ports,
>> >> >> > > and this will suppress the actual member violation interrupts for
>> >> >> > > traffic coming from these ports.
>> >> >> > >
>> >> >> > > So if the user decides to unplug a previously authorized printer from
>> >> >> > > switch port 1 and move it to port 2, how is this handled? If there isn't
>> >> >> > > a mechanism in place to delete the locked FDB entry when the printer
>> >> >> > > goes away, then by setting IgnoreWrongData you're effectively also
>> >> >> > > suppressing migration notifications.
>> >> >> > 
>> >> >> > I don't think such a scenario is so realistic, as changing port is not
>> >> >> > just something done casually, besides port 2 then must also be a locked
>> >> >> > port to have the same policy.
>> >> >> 
>> >> >> I think it is very realistic. It is also something which does not work
>> >> >> is going to cause a lot of confusion. People will blame the printer,
>> >> >> when in fact they should be blaming the switch. They will be rebooting
>> >> >> the printer, when in fact, they need to reboot the switch etc.
>> >> >> 
>> >> >> I expect there is a way to cleanly support this, you just need to
>> >> >> figure it out.
>> >> >
>> >> > Hans, why must port 2 also be a locked port? The FDB entry with no
>> >> > destinations is present in the ATU, and static, why would just locked
>> >> > ports match it?
>> >> >
>> >> You are right of course, but it was more from a policy standpoint as I
>> >> pointed out. If the FDB entry is removed after some timeout and the
>> >> device in the meantime somehow is on another port that is not locked
>> >> with full access, the device will of course get full access.
>> >> But since it was not given access in the first instance, the policy is
>> >> not consistent.
>> >> 
>> >> >> > The other aspect is that the user space daemon that authorizes catches
>> >> >> > the fdb add entry events and checks if it is a locked entry. So it will
>> >> >> > be up to said daemon to decide the policy, like remove the fdb entry
>> >> >> > after a timeout.
>> >> >
>> >> > When you say 'timeout', what is the moment when the timer starts counting?
>> >> > The last reception of the user space daemon of a packet with this MAC SA,
>> >> > or the moment when the FDB entry originally became unlocked?
>> >> 
>> >> I think that if the device is not given access, a timer should be
>> >> started at that moment. No further FDB add events with the same MAC
>> >> address will come of course until the FDB entry is removed, which I
>> >> think would be done based on the said timer.
>> >> >
>> >> > I expect that once a device is authorized, and forwarding towards the
>> >> > devices that it wants to talk to is handled in hardware, that the CPU no
>> >> > longer receives packets from this device. In other words, are you saying
>> >> > that you're going to break networking for the printer every 5 minutes,
>> >> > as a keepalive measure?
>> >> 
>> >> No, I don't think that would be a good idea, but as we are in userspace,
>> >> that is a policy decision of those creating the daemon. The kernel just
>> >> facilitates, it does not make those decisions as far as I think.
>> >> >
>> >> > I still think there should be a functional fast path for authorized
>> >> > station migrations.
>> >> >
>> >> I am not sure in what way you are suggesting that should be, if the
>> >> kernel should actively do something there? If a station is authorized,
>> >> and somehow is transferred to another port, if that port is not locked it
>> >> will get access, if the port is locked a miss violation will occur etc...
>> >
>> > Wait, if the new port is locked and the device was previously
>> > authorized, why will the new port trigger a miss violation? This is the
>> > part I'm not following. The authorization is still present in the form
>> > of an ATU entry on the old locked port, is it not?
>> >
>> I am sure (have not tested) that a miss violation will occur. It might
>> be a member violation in this instance though.
>> When thinking of it, afaik there is no way today of having fine control
>> over the DPV when adding a FDB entry.
>> If the DPV could be finer controlled the entry could cover several
>> possible ports and the fast (immediate migration) will be accomplished?
>
> I'm not sure I understand this, either.
>
> You're saying we should configure the authorizations as de-facto
> multicast ATU entries towards all locked ports, so that there wouldn't
> be any violation when a station migrates, because the new port is still
> in the destination port mask of the ATU entry?
>
> Yes, but... this leaks traffic between ports to a significant degree.
> Any packet that targets your printer now targets your colleague's printer too.
>
> I was expecting you'd say that when the cable is unplugged from the
> switch, the authorization daemon is notified through rtnetlink of the
> link state change, and it flushes the port of addresses it has added
> (because the kernel surely does not do this).
>
So, my HW tests show that when the link is removed, the FDB entries
related to the port are flushed automatically.

> This could work to an extent, but it wouldn't handle the case where the
> printer isn't connected directly to the 802.1X port, but through
> another dumb switch. I don't know enough about 802.1X, but I don't see
> why this isn't a valid configuration.
>
ATM, the dynamic flag (bridge fdb add MAC dev DEV master dynamic)
doesn't create an ageing FDB entry in the offloaded case. Maybe if that
was solved, it would be a good enough solution, as for a noisy device,
it would lose some packets every 5 minutes, which higher layers should
be able to handle?

> To explain what I'm thinking of. At office, IT gave one Ethernet port to
> each desk, but I have multiple devices. I have a PC, a printer, and a
> development board, each with a single Ethernet port, so I use a dumb
> 4-port switch to connect all these devices to the 802.1X port beneath my
> desk. I talked to IT, brought my printer to them, they agreed to bypass
> 802.1X authorization for it based on the MAC address on its label.
>
> I've been working from home for the past few years, but now I need to
> return to office. But since years have passed, some colleagues left,
> some new colleagues came, and I need to change my desk. The new one
> belonged to a co-worker who also had a dumb switch on his desk, so I see
> no reason to move mine too. I unplug the printer from my dumb switch,
> plug it into the new one, but it doesn't work. What do I do, open a
> ticket to IT asking for halp?
>
> To be honest this is purely fictional and I haven't tried it, but it
> sounds like I should when I get the chance, to get a better image of how
> things are supposed to work.
>
>> >> >> > > Oh, btw, my question was: could you consider suppressing the _prints_ on
>> >> >> > > an ATU miss violation on a locked port?
>> >> >> > 
>> >> >> > As there will only be such on the first packet, I think it should be
>> >> >> > logged and those prints serve that purpose, so I think it is best to
>> >> >> > keep the print.
>> >> >> > If in the future some tests or other can argue for suppressing the
>> >> >> > prints, it is an easy thing to do.
>> >> >> 
>> >> >> Please use a traffic generator and try to DOS one of your own
>> >> >> switches. Can you?
>> >> >> 
>> >> >> 	  Andrew

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-18 10:04                       ` Hans Schultz
@ 2022-03-18 12:14                         ` Vladimir Oltean
  2022-03-18 13:10                           ` Hans Schultz
  0 siblings, 1 reply; 63+ messages in thread
From: Vladimir Oltean @ 2022-03-18 12:14 UTC (permalink / raw)
  To: Hans Schultz
  Cc: Andrew Lunn, davem, kuba, netdev, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On Fri, Mar 18, 2022 at 11:04:36AM +0100, Hans Schultz wrote:
> On tor, mar 17, 2022 at 19:20, Vladimir Oltean <olteanv@gmail.com> wrote:
> > On Thu, Mar 17, 2022 at 05:58:26PM +0100, Hans Schultz wrote:
> >> On tor, mar 17, 2022 at 18:18, Vladimir Oltean <olteanv@gmail.com> wrote:
> >> > On Thu, Mar 17, 2022 at 05:07:15PM +0100, Hans Schultz wrote:
> >> >> On tor, mar 17, 2022 at 17:36, Vladimir Oltean <olteanv@gmail.com> wrote:
> >> >> > On Thu, Mar 17, 2022 at 03:19:46PM +0100, Andrew Lunn wrote:
> >> >> >> On Thu, Mar 17, 2022 at 09:52:15AM +0100, Hans Schultz wrote:
> >> >> >> > On tor, mar 17, 2022 at 01:34, Vladimir Oltean <olteanv@gmail.com> wrote:
> >> >> >> > > On Mon, Mar 14, 2022 at 11:46:51AM +0100, Hans Schultz wrote:
> >> >> >> > >> >> @@ -396,6 +414,13 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
> >> >> >> > >> >>  				    "ATU miss violation for %pM portvec %x spid %d\n",
> >> >> >> > >> >>  				    entry.mac, entry.portvec, spid);
> >> >> >> > >> >>  		chip->ports[spid].atu_miss_violation++;
> >> >> >> > >> >> +		if (mv88e6xxx_port_is_locked(chip, chip->ports[spid].port))
> >> >> >> > >> >> +			err = mv88e6xxx_switchdev_handle_atu_miss_violation(chip,
> >> >> >> > >> >> +									    chip->ports[spid].port,
> >> >> >> > >> >> +									    &entry,
> >> >> >> > >> >> +									    fid);
> >> >> >> > >> >
> >> >> >> > >> > Do we want to suppress the ATU miss violation warnings if we're going to
> >> >> >> > >> > notify the bridge, or is it better to keep them for some reason?
> >> >> >> > >> > My logic is that they're part of normal operation, so suppressing makes
> >> >> >> > >> > sense.
> >> >> >> > >> >
> >> >> >> > >>
> >> >> >> > >> I have been seeing many ATU member violations after the miss violation is
> >> >> >> > >> handled (using ping), and I think it could be considered to suppress the ATU member
> >> >> >> > >> violations interrupts by setting the IgnoreWrongData bit for the
> >> >> >> > >> port (sect 4.4.7). This would be something to do whenever a port is set in locked mode?
> >> >> >> > >
> >> >> >> > > So the first packet with a given MAC SA triggers an ATU miss violation
> >> >> >> > > interrupt.
> >> >> >> > >
> >> >> >> > > You program that MAC SA into the ATU with a destination port mask of all
> >> >> >> > > zeroes. This suppresses further ATU miss interrupts for this MAC SA, but
> >> >> >> > > now generates ATU member violations, because the MAC SA _is_ present in
> >> >> >> > > the ATU, but not towards the expected port (in fact, towards _no_ port).
> >> >> >> > >
> >> >> >> > > Especially if user space decides it doesn't want to authorize this MAC
> >> >> >> > > SA, it really becomes a problem because this is now a vector for denial
> >> >> >> > > of service, with every packet triggering an ATU member violation
> >> >> >> > > interrupt.
> >> >> >> > >
> >> >> >> > > So your suggestion is to set the IgnoreWrongData bit on locked ports,
> >> >> >> > > and this will suppress the actual member violation interrupts for
> >> >> >> > > traffic coming from these ports.
> >> >> >> > >
> >> >> >> > > So if the user decides to unplug a previously authorized printer from
> >> >> >> > > switch port 1 and move it to port 2, how is this handled? If there isn't
> >> >> >> > > a mechanism in place to delete the locked FDB entry when the printer
> >> >> >> > > goes away, then by setting IgnoreWrongData you're effectively also
> >> >> >> > > suppressing migration notifications.
> >> >> >> >
> >> >> >> > I don't think such a scenario is so realistic, as changing port is not
> >> >> >> > just something done casually, besides port 2 then must also be a locked
> >> >> >> > port to have the same policy.
> >> >> >>
> >> >> >> I think it is very realistic. It is also something which does not work
> >> >> >> is going to cause a lot of confusion. People will blame the printer,
> >> >> >> when in fact they should be blaming the switch. They will be rebooting
> >> >> >> the printer, when in fact, they need to reboot the switch etc.
> >> >> >>
> >> >> >> I expect there is a way to cleanly support this, you just need to
> >> >> >> figure it out.
> >> >> >
> >> >> > Hans, why must port 2 also be a locked port? The FDB entry with no
> >> >> > destinations is present in the ATU, and static, why would just locked
> >> >> > ports match it?
> >> >> >
> >> >> You are right of course, but it was more from a policy standpoint as I
> >> >> pointed out. If the FDB entry is removed after some timeout and the
> >> >> device in the meantime somehow is on another port that is not locked
> >> >> with full access, the device will of course get full access.
> >> >> But since it was not given access in the first instance, the policy is
> >> >> not consistent.
> >> >>
> >> >> >> > The other aspect is that the user space daemon that authorizes catches
> >> >> >> > the fdb add entry events and checks if it is a locked entry. So it will
> >> >> >> > be up to said daemon to decide the policy, like remove the fdb entry
> >> >> >> > after a timeout.
> >> >> >
> >> >> > When you say 'timeout', what is the moment when the timer starts counting?
> >> >> > The last reception of the user space daemon of a packet with this MAC SA,
> >> >> > or the moment when the FDB entry originally became unlocked?
> >> >>
> >> >> I think that if the device is not given access, a timer should be
> >> >> started at that moment. No further FDB add events with the same MAC
> >> >> address will come of course until the FDB entry is removed, which I
> >> >> think would be done based on the said timer.
> >> >> >
> >> >> > I expect that once a device is authorized, and forwarding towards the
> >> >> > devices that it wants to talk to is handled in hardware, that the CPU no
> >> >> > longer receives packets from this device. In other words, are you saying
> >> >> > that you're going to break networking for the printer every 5 minutes,
> >> >> > as a keepalive measure?
> >> >>
> >> >> No, I don't think that would be a good idea, but as we are in userspace,
> >> >> that is a policy decision of those creating the daemon. The kernel just
> >> >> facilitates, it does not make those decisions as far as I think.
> >> >> >
> >> >> > I still think there should be a functional fast path for authorized
> >> >> > station migrations.
> >> >> >
> >> >> I am not sure in what way you are suggesting that should be, if the
> >> >> kernel should actively do something there? If a station is authorized,
> >> >> and somehow is transferred to another port, if that port is not locked it
> >> >> will get access, if the port is locked a miss violation will occur etc...
> >> >
> >> > Wait, if the new port is locked and the device was previously
> >> > authorized, why will the new port trigger a miss violation? This is the
> >> > part I'm not following. The authorization is still present in the form
> >> > of an ATU entry on the old locked port, is it not?
> >> >
> >> I am sure (have not tested) that a miss violation will occur. It might
> >> be a member violation in this instance though.
> >> When thinking of it, afaik there is no way today of having fine control
> >> over the DPV when adding a FDB entry.
> >> If the DPV could be finer controlled the entry could cover several
> >> possible ports and the fast (immediate migration) will be accomplished?
> >
> > I'm not sure I understand this, either.
> >
> > You're saying we should configure the authorizations as de-facto
> > multicast ATU entries towards all locked ports, so that there wouldn't
> > be any violation when a station migrates, because the new port is still
> > in the destination port mask of the ATU entry?
> >
> > Yes, but... this leaks traffic between ports to a significant degree.
> > Any packet that targets your printer now targets your colleague's printer too.
> >
> > I was expecting you'd say that when the cable is unplugged from the
> > switch, the authorization daemon is notified through rtnetlink of the
> > link state change, and it flushes the port of addresses it has added
> > (because the kernel surely does not do this).
> >
> So, my HW tests show that when the link is removed, the FDB entries
> related to the port are flushed automatically.

Don't get me wrong, some addresses are flushed, this is handled by
dsa_port_fast_age() as a result of the fact that the bridge port
transitions to the DISABLED state when the link is lost. But those
should only be the dynamically learned addresses. I'm not sure what
flags your user space daemon uses to program ATU entries to hardware,
but if those entries are anything other than dynamic, I don't think that
dsa_port_fast_age() should flush them.

root@debian:~# ip link add br0 type bridge
root@debian:~# ip link set swp3 master br0
[46343.691692] br0: port 1(swp3) entered blocking state
[46343.696791] br0: port 1(swp3) entered disabled state
[46343.703962] device swp3 entered promiscuous mode
root@debian:~# bridge fdb add dev swp3 00:01:02:03:04:05 master static
root@debian:~# bridge fdb show dev swp3
00:01:02:03:04:05 vlan 1 offload master br0 static
00:01:02:03:04:05 offload master br0 static
00:04:9f:05:f6:28 vlan 1 master br0 permanent
00:04:9f:05:f6:28 master br0 permanent
00:01:02:03:04:05 vlan 1 self
00:01:02:03:04:05 self
root@debian:~# ip link set swp3 up
[46391.626362] fsl_enetc 0000:00:00.2 eno2: configuring for fixed/internal link mode
[46391.634110] fsl_enetc 0000:00:00.2 eno2: Link is Up - 2.5Gbps/Full - flow control rx/tx
[46391.635256] mscc_felix 0000:00:00.5 swp3: configuring for inband/qsgmii link mode
root@debian:~# [46395.751268] mscc_felix 0000:00:00.5 swp3: Link is Up - 1Gbps/Full - flow control rx/tx
[46395.759613] IPv6: ADDRCONF(NETDEV_CHANGE): swp3: link becomes ready
root@debian:~# bridge fdb show dev swp3
00:01:02:03:04:05 vlan 1 offload master br0 static
00:01:02:03:04:05 offload master br0 static
00:04:9f:05:f6:28 vlan 1 master br0 permanent
00:04:9f:05:f6:28 master br0 permanent
00:01:02:03:04:05 vlan 1 self
00:01:02:03:04:05 self
root@debian:~# ip link set swp3 down
[46403.978832] mscc_felix 0000:00:00.5 swp3: Link is Down
root@debian:~# bridge fdb show dev swp3
00:01:02:03:04:05 vlan 1 offload master br0 static
00:01:02:03:04:05 offload master br0 static
00:04:9f:05:f6:28 vlan 1 master br0 permanent
00:04:9f:05:f6:28 master br0 permanent
00:01:02:03:04:05 vlan 1 self
00:01:02:03:04:05 self
root@debian:~# ip link set swp3 up
[46410.499445] mscc_felix 0000:00:00.5 swp3: configuring for inband/qsgmii link mode
root@debian:~# [46414.597381] mscc_felix 0000:00:00.5 swp3: Link is Up - 1Gbps/Full - flow control rx/tx
[46414.605775] IPv6: ADDRCONF(NETDEV_CHANGE): swp3: link becomes ready
root@debian:~# bridge fdb show dev swp3
00:01:02:03:04:05 vlan 1 offload master br0 static
00:01:02:03:04:05 offload master br0 static
00:04:9f:05:f6:28 vlan 1 master br0 permanent
00:04:9f:05:f6:28 master br0 permanent
00:01:02:03:04:05 vlan 1 self
00:01:02:03:04:05 self

I've searched for the call paths of br_fdb_delete_by_port().
One caller is br_stp_disable_port(), but this passes 0 to "do_all", so
this can't be it. Also, both IFLA_BRPORT_FLUSH and the "flush" sysfs
pass 0 to "do_all".

If it's not the user space daemon who is deleting these entries, this is strange.
More details on my suspicion below.

> > This could work to an extent, but it wouldn't handle the case where the
> > printer isn't connected directly to the 802.1X port, but through
> > another dumb switch. I don't know enough about 802.1X, but I don't see
> > why this isn't a valid configuration.
> >
> ATM, the dynamic flag (bridge fdb add MAC dev DEV master dynamic)
> doesn't create an ageing FDB entry in the offloaded case. Maybe if that
> was solved, it would be a good enough solution, as for a noisy device,
> it would lose some packets every 5 minutes, which higher layers should
> be able to handle?

Before we explore this too deeply, can you first double-check whether
station migrations will trigger a miss or a member violation?

When I look at the documentation, I see that the switch triggers a member
violation, unless the ATU age interrupt is enabled and the entry's state
is less than 4 (which it should be if RefreshLocked is false). In this
latter case, the documentation says that a miss violation will be
triggered, not a membership one. So if you satisfy these requirements,
you should be able to safely set IgnoreWrongData, and not miss out on
migrations.

My suspicion is that, since you add ATU authorizations on locked ports
with RefreshLocked as false, they will eventually age out. But the
driver doesn't enable the ATU age interrupt through Global 2 register 5,
so software never finds out when these ATU entries expire. And the idea
of triggering an ATU age interrupt when the entry state becomes less
than 4 (i.e. they are aged half-way) is precisely done such that you
don't break networking for the printer every 5 minutes. The switch
notifies you in advance of the complete entry expiration. I think you
should service this interrupt in the driver. Note that my belief is that
such ATU entries on locked ports aren't truly 'dynamic' as far as user
space is concerned. Sure, they age, but this is just a way for software
to keep them in check. But user space doesn't have to know this. To the
application, the entry is static, and the driver just refreshes the
entry unless told by the application to delete it.

Basically what I'm saying is that more testing needs to be done to make
sure that the hardware is configured to do something reasonable in all
cases, and doesn't just work by coincidence.

Makes sense?

> > To explain what I'm thinking of. At office, IT gave one Ethernet port to
> > each desk, but I have multiple devices. I have a PC, a printer, and a
> > development board, each with a single Ethernet port, so I use a dumb
> > 4-port switch to connect all these devices to the 802.1X port beneath my
> > desk. I talked to IT, brought my printer to them, they agreed to bypass
> > 802.1X authorization for it based on the MAC address on its label.
> >
> > I've been working from home for the past few years, but now I need to
> > return to office. But since years have passed, some colleagues left,
> > some new colleagues came, and I need to change my desk. The new one
> > belonged to a co-worker who also had a dumb switch on his desk, so I see
> > no reason to move mine too. I unplug the printer from my dumb switch,
> > plug it into the new one, but it doesn't work. What do I do, open a
> > ticket to IT asking for halp?
> >
> > To be honest this is purely fictional and I haven't tried it, but it
> > sounds like I should when I get the chance, to get a better image of how
> > things are supposed to work.
> >
> >> >> >> > > Oh, btw, my question was: could you consider suppressing the _prints_ on
> >> >> >> > > an ATU miss violation on a locked port?
> >> >> >> >
> >> >> >> > As there will only be such on the first packet, I think it should be
> >> >> >> > logged and those prints serve that purpose, so I think it is best to
> >> >> >> > keep the print.
> >> >> >> > If in the future some tests or other can argue for suppressing the
> >> >> >> > prints, it is an easy thing to do.
> >> >> >>
> >> >> >> Please use a traffic generator and try to DOS one of your own
> >> >> >> switches. Can you?
> >> >> >>
> >> >> >> 	  Andrew

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-18 12:14                         ` Vladimir Oltean
@ 2022-03-18 13:10                           ` Hans Schultz
  2022-03-18 13:19                             ` Vladimir Oltean
  0 siblings, 1 reply; 63+ messages in thread
From: Hans Schultz @ 2022-03-18 13:10 UTC (permalink / raw)
  To: Vladimir Oltean, Hans Schultz
  Cc: Andrew Lunn, davem, kuba, netdev, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On fre, mar 18, 2022 at 14:14, Vladimir Oltean <olteanv@gmail.com> wrote:
> On Fri, Mar 18, 2022 at 11:04:36AM +0100, Hans Schultz wrote:
>> On tor, mar 17, 2022 at 19:20, Vladimir Oltean <olteanv@gmail.com> wrote:
>> > On Thu, Mar 17, 2022 at 05:58:26PM +0100, Hans Schultz wrote:
>> >> On tor, mar 17, 2022 at 18:18, Vladimir Oltean <olteanv@gmail.com> wrote:
>> >> > On Thu, Mar 17, 2022 at 05:07:15PM +0100, Hans Schultz wrote:
>> >> >> On tor, mar 17, 2022 at 17:36, Vladimir Oltean <olteanv@gmail.com> wrote:
>> >> >> > On Thu, Mar 17, 2022 at 03:19:46PM +0100, Andrew Lunn wrote:
>> >> >> >> On Thu, Mar 17, 2022 at 09:52:15AM +0100, Hans Schultz wrote:
>> >> >> >> > On tor, mar 17, 2022 at 01:34, Vladimir Oltean <olteanv@gmail.com> wrote:
>> >> >> >> > > On Mon, Mar 14, 2022 at 11:46:51AM +0100, Hans Schultz wrote:
>> >> >> >> > >> >> @@ -396,6 +414,13 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
>> >> >> >> > >> >>  				    "ATU miss violation for %pM portvec %x spid %d\n",
>> >> >> >> > >> >>  				    entry.mac, entry.portvec, spid);
>> >> >> >> > >> >>  		chip->ports[spid].atu_miss_violation++;
>> >> >> >> > >> >> +		if (mv88e6xxx_port_is_locked(chip, chip->ports[spid].port))
>> >> >> >> > >> >> +			err = mv88e6xxx_switchdev_handle_atu_miss_violation(chip,
>> >> >> >> > >> >> +									    chip->ports[spid].port,
>> >> >> >> > >> >> +									    &entry,
>> >> >> >> > >> >> +									    fid);
>> >> >> >> > >> >
>> >> >> >> > >> > Do we want to suppress the ATU miss violation warnings if we're going to
>> >> >> >> > >> > notify the bridge, or is it better to keep them for some reason?
>> >> >> >> > >> > My logic is that they're part of normal operation, so suppressing makes
>> >> >> >> > >> > sense.
>> >> >> >> > >> >
>> >> >> >> > >>
>> >> >> >> > >> I have been seeing many ATU member violations after the miss violation is
>> >> >> >> > >> handled (using ping), and I think it could be considered to suppress the ATU member
>> >> >> >> > >> violations interrupts by setting the IgnoreWrongData bit for the
>> >> >> >> > >> port (sect 4.4.7). This would be something to do whenever a port is set in locked mode?
>> >> >> >> > >
>> >> >> >> > > So the first packet with a given MAC SA triggers an ATU miss violation
>> >> >> >> > > interrupt.
>> >> >> >> > >
>> >> >> >> > > You program that MAC SA into the ATU with a destination port mask of all
>> >> >> >> > > zeroes. This suppresses further ATU miss interrupts for this MAC SA, but
>> >> >> >> > > now generates ATU member violations, because the MAC SA _is_ present in
>> >> >> >> > > the ATU, but not towards the expected port (in fact, towards _no_ port).
>> >> >> >> > >
>> >> >> >> > > Especially if user space decides it doesn't want to authorize this MAC
>> >> >> >> > > SA, it really becomes a problem because this is now a vector for denial
>> >> >> >> > > of service, with every packet triggering an ATU member violation
>> >> >> >> > > interrupt.
>> >> >> >> > >
>> >> >> >> > > So your suggestion is to set the IgnoreWrongData bit on locked ports,
>> >> >> >> > > and this will suppress the actual member violation interrupts for
>> >> >> >> > > traffic coming from these ports.
>> >> >> >> > >
>> >> >> >> > > So if the user decides to unplug a previously authorized printer from
>> >> >> >> > > switch port 1 and move it to port 2, how is this handled? If there isn't
>> >> >> >> > > a mechanism in place to delete the locked FDB entry when the printer
>> >> >> >> > > goes away, then by setting IgnoreWrongData you're effectively also
>> >> >> >> > > suppressing migration notifications.
>> >> >> >> >
>> >> >> >> > I don't think such a scenario is so realistic, as changing port is not
>> >> >> >> > just something done casually, besides port 2 then must also be a locked
>> >> >> >> > port to have the same policy.
>> >> >> >>
>> >> >> >> I think it is very realistic. It is also something which does not work
>> >> >> >> is going to cause a lot of confusion. People will blame the printer,
>> >> >> >> when in fact they should be blaming the switch. They will be rebooting
>> >> >> >> the printer, when in fact, they need to reboot the switch etc.
>> >> >> >>
>> >> >> >> I expect there is a way to cleanly support this, you just need to
>> >> >> >> figure it out.
>> >> >> >
>> >> >> > Hans, why must port 2 also be a locked port? The FDB entry with no
>> >> >> > destinations is present in the ATU, and static, why would just locked
>> >> >> > ports match it?
>> >> >> >
>> >> >> You are right of course, but it was more from a policy standpoint as I
>> >> >> pointed out. If the FDB entry is removed after some timeout and the
>> >> >> device in the meantime somehow is on another port that is not locked
>> >> >> with full access, the device will of course get full access.
>> >> >> But since it was not given access in the first instance, the policy is
>> >> >> not consistent.
>> >> >>
>> >> >> >> > The other aspect is that the user space daemon that authorizes catches
>> >> >> >> > the fdb add entry events and checks if it is a locked entry. So it will
>> >> >> >> > be up to said daemon to decide the policy, like remove the fdb entry
>> >> >> >> > after a timeout.
>> >> >> >
>> >> >> > When you say 'timeout', what is the moment when the timer starts counting?
>> >> >> > The last reception of the user space daemon of a packet with this MAC SA,
>> >> >> > or the moment when the FDB entry originally became unlocked?
>> >> >>
>> >> >> I think that if the device is not given access, a timer should be
>> >> >> started at that moment. No further FDB add events with the same MAC
>> >> >> address will come of course until the FDB entry is removed, which I
>> >> >> think would be done based on the said timer.
>> >> >> >
>> >> >> > I expect that once a device is authorized, and forwarding towards the
>> >> >> > devices that it wants to talk to is handled in hardware, that the CPU no
>> >> >> > longer receives packets from this device. In other words, are you saying
>> >> >> > that you're going to break networking for the printer every 5 minutes,
>> >> >> > as a keepalive measure?
>> >> >>
>> >> >> No, I don't think that would be a good idea, but as we are in userspace,
>> >> >> that is a policy decision of those creating the daemon. The kernel just
>> >> >> facilitates, it does not make those decisions as far as I think.
>> >> >> >
>> >> >> > I still think there should be a functional fast path for authorized
>> >> >> > station migrations.
>> >> >> >
>> >> >> I am not sure in what way you are suggesting that should be, if the
>> >> >> kernel should actively do something there? If a station is authorized,
>> >> >> and somehow is transferred to another port, if that port is not locked it
>> >> >> will get access, if the port is locked a miss violation will occur etc...
>> >> >
>> >> > Wait, if the new port is locked and the device was previously
>> >> > authorized, why will the new port trigger a miss violation? This is the
>> >> > part I'm not following. The authorization is still present in the form
>> >> > of an ATU entry on the old locked port, is it not?
>> >> >
>> >> I am sure (have not tested) that a miss violation will occur. It might
>> >> be a member violation in this instance though.
>> >> When thinking of it, afaik there is no way today of having fine control
>> >> over the DPV when adding a FDB entry.
>> >> If the DPV could be finer controlled the entry could cover several
>> >> possible ports and the fast (immediate migration) will be accomplished?
>> >
>> > I'm not sure I understand this, either.
>> >
>> > You're saying we should configure the authorizations as de-facto
>> > multicast ATU entries towards all locked ports, so that there wouldn't
>> > be any violation when a station migrates, because the new port is still
>> > in the destination port mask of the ATU entry?
>> >
>> > Yes, but... this leaks traffic between ports to a significant degree.
>> > Any packet that targets your printer now targets your colleague's printer too.
>> >
>> > I was expecting you'd say that when the cable is unplugged from the
>> > switch, the authorization daemon is notified through rtnetlink of the
>> > link state change, and it flushes the port of addresses it has added
>> > (because the kernel surely does not do this).
>> >
>> So, my HW tests show that when the link is removed, the FDB entries
>> related to the port are flushed automatically.
>
> Don't get me wrong, some addresses are flushed, this is handled by
> dsa_port_fast_age() as a result of the fact that the bridge port
> transitions to the DISABLED state when the link is lost. But those
> should only be the dynamically learned addresses. I'm not sure what
> flags your user space daemon uses to program ATU entries to hardware,
> but if those entries are anything other than dynamic, I don't think that
> dsa_port_fast_age() should flush them.

In the offloaded case there is no difference between static and dynamic
flags, which I see as a general issue. (The resulting ATU entry is static
in either case.)

These FDB entries are removed when link goes down (soft or hard). The
zero DPV entries that the new code introduces age out after 5 minutes,
while the locked flagged FDB entries are removed by link down (thus the
FDB and the ATU are not in sync in this case).

I need to get hold of a couple hubs to test the migration issue when no
link goes down, which I can do in the weekend, and test on Monday. :-)

>
> root@debian:~# ip link add br0 type bridge
> root@debian:~# ip link set swp3 master br0
> [46343.691692] br0: port 1(swp3) entered blocking state
> [46343.696791] br0: port 1(swp3) entered disabled state
> [46343.703962] device swp3 entered promiscuous mode
> root@debian:~# bridge fdb add dev swp3 00:01:02:03:04:05 master static
> root@debian:~# bridge fdb show dev swp3
> 00:01:02:03:04:05 vlan 1 offload master br0 static
> 00:01:02:03:04:05 offload master br0 static
> 00:04:9f:05:f6:28 vlan 1 master br0 permanent
> 00:04:9f:05:f6:28 master br0 permanent
> 00:01:02:03:04:05 vlan 1 self
> 00:01:02:03:04:05 self
> root@debian:~# ip link set swp3 up
> [46391.626362] fsl_enetc 0000:00:00.2 eno2: configuring for fixed/internal link mode
> [46391.634110] fsl_enetc 0000:00:00.2 eno2: Link is Up - 2.5Gbps/Full - flow control rx/tx
> [46391.635256] mscc_felix 0000:00:00.5 swp3: configuring for inband/qsgmii link mode
> root@debian:~# [46395.751268] mscc_felix 0000:00:00.5 swp3: Link is Up - 1Gbps/Full - flow control rx/tx
> [46395.759613] IPv6: ADDRCONF(NETDEV_CHANGE): swp3: link becomes ready
> root@debian:~# bridge fdb show dev swp3
> 00:01:02:03:04:05 vlan 1 offload master br0 static
> 00:01:02:03:04:05 offload master br0 static
> 00:04:9f:05:f6:28 vlan 1 master br0 permanent
> 00:04:9f:05:f6:28 master br0 permanent
> 00:01:02:03:04:05 vlan 1 self
> 00:01:02:03:04:05 self
> root@debian:~# ip link set swp3 down
> [46403.978832] mscc_felix 0000:00:00.5 swp3: Link is Down
> root@debian:~# bridge fdb show dev swp3
> 00:01:02:03:04:05 vlan 1 offload master br0 static
> 00:01:02:03:04:05 offload master br0 static
> 00:04:9f:05:f6:28 vlan 1 master br0 permanent
> 00:04:9f:05:f6:28 master br0 permanent
> 00:01:02:03:04:05 vlan 1 self
> 00:01:02:03:04:05 self
> root@debian:~# ip link set swp3 up
> [46410.499445] mscc_felix 0000:00:00.5 swp3: configuring for inband/qsgmii link mode
> root@debian:~# [46414.597381] mscc_felix 0000:00:00.5 swp3: Link is Up - 1Gbps/Full - flow control rx/tx
> [46414.605775] IPv6: ADDRCONF(NETDEV_CHANGE): swp3: link becomes ready
> root@debian:~# bridge fdb show dev swp3
> 00:01:02:03:04:05 vlan 1 offload master br0 static
> 00:01:02:03:04:05 offload master br0 static
> 00:04:9f:05:f6:28 vlan 1 master br0 permanent
> 00:04:9f:05:f6:28 master br0 permanent
> 00:01:02:03:04:05 vlan 1 self
> 00:01:02:03:04:05 self
>
> I've searched for the call paths of br_fdb_delete_by_port().
> One caller is br_stp_disable_port(), but this passes 0 to "do_all", so
> this can't be it. Also, both IFLA_BRPORT_FLUSH and the "flush" sysfs
> pass 0 to "do_all".
>
> If it's not the user space daemon who is deleting these entries, this is strange.
> More details on my suspicion below.
>
>> > This could work to an extent, but it wouldn't handle the case where the
>> > printer isn't connected directly to the 802.1X port, but through
>> > another dumb switch. I don't know enough about 802.1X, but I don't see
>> > why this isn't a valid configuration.
>> >
>> ATM, the dynamic flag (bridge fdb add MAC dev DEV master dynamic)
>> doesn't create an ageing FDB entry in the offloaded case. Maybe if that
>> was solved, it would be a good enough solution, as for a noisy device,
>> it would lose some packets every 5 minutes, which higher layers should
>> be able to handle?
>
> Before we explore this too deeply, can you first double-check whether
> station migrations will trigger a miss or a member violation?
>
> When I look at the documentation, I see that the switch triggers a member
> violation, unless the ATU age interrupt is enabled and the entry's state
> is less than 4 (which it should be if RefreshLocked is false). In this
> latter case, the documentation says that a miss violation will be
> triggered, not a membership one. So if you satisfy these requirements,
> you should be able to safely set IgnoreWrongData, and not miss out on
> migrations.
>
> My suspicion is that, since you add ATU authorizations on locked ports
> with RefreshLocked as false, they will eventually age out. But the
> driver doesn't enable the ATU age interrupt through Global 2 register 5,
> so software never finds out when these ATU entries expire. And the idea
> of triggering an ATU age interrupt when the entry state becomes less
> than 4 (i.e. they are aged half-way) is precisely done such that you
> don't break networking for the printer every 5 minutes. The switch
> notifies you in advance of the complete entry expiration. I think you
> should service this interrupt in the driver. Note that my belief is that
> such ATU entries on locked ports aren't truly 'dynamic' as far as user
> space is concerned. Sure, they age, but this is just a way for software
> to keep them in check. But user space doesn't have to know this. To the
> application, the entry is static, and the driver just refreshes the
> entry unless told by the application to delete it.
>
> Basically what I'm saying is that more testing needs to be done to make
> sure that the hardware is configured to do something reasonable in all
> cases, and doesn't just work by coincidence.
>
> Makes sense?
>
>> > To explain what I'm thinking of. At office, IT gave one Ethernet port to
>> > each desk, but I have multiple devices. I have a PC, a printer, and a
>> > development board, each with a single Ethernet port, so I use a dumb
>> > 4-port switch to connect all these devices to the 802.1X port beneath my
>> > desk. I talked to IT, brought my printer to them, they agreed to bypass
>> > 802.1X authorization for it based on the MAC address on its label.
>> >
>> > I've been working from home for the past few years, but now I need to
>> > return to office. But since years have passed, some colleagues left,
>> > some new colleagues came, and I need to change my desk. The new one
>> > belonged to a co-worker who also had a dumb switch on his desk, so I see
>> > no reason to move mine too. I unplug the printer from my dumb switch,
>> > plug it into the new one, but it doesn't work. What do I do, open a
>> > ticket to IT asking for halp?
>> >
>> > To be honest this is purely fictional and I haven't tried it, but it
>> > sounds like I should when I get the chance, to get a better image of how
>> > things are supposed to work.
>> >
>> >> >> >> > > Oh, btw, my question was: could you consider suppressing the _prints_ on
>> >> >> >> > > an ATU miss violation on a locked port?
>> >> >> >> >
>> >> >> >> > As there will only be such on the first packet, I think it should be
>> >> >> >> > logged and those prints serve that purpose, so I think it is best to
>> >> >> >> > keep the print.
>> >> >> >> > If in the future some tests or other can argue for suppressing the
>> >> >> >> > prints, it is an easy thing to do.
>> >> >> >>
>> >> >> >> Please use a traffic generator and try to DOS one of your own
>> >> >> >> switches. Can you?
>> >> >> >>
>> >> >> >> 	  Andrew

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-18 13:10                           ` Hans Schultz
@ 2022-03-18 13:19                             ` Vladimir Oltean
  2022-03-22 11:01                               ` Hans Schultz
  0 siblings, 1 reply; 63+ messages in thread
From: Vladimir Oltean @ 2022-03-18 13:19 UTC (permalink / raw)
  To: Hans Schultz
  Cc: Andrew Lunn, davem, kuba, netdev, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On Fri, Mar 18, 2022 at 02:10:26PM +0100, Hans Schultz wrote:
> In the offloaded case there is no difference between static and dynamic
> flags, which I see as a general issue. (The resulting ATU entry is static
> in either case.)

It _is_ a problem. We had the same problem with the is_local bit.
Independently of this series, you can add the dynamic bit to struct
switchdev_notifier_fdb_info and make drivers reject it.

> These FDB entries are removed when link goes down (soft or hard). The
> zero DPV entries that the new code introduces age out after 5 minutes,
> while the locked flagged FDB entries are removed by link down (thus the
> FDB and the ATU are not in sync in this case).

Ok, so don't let them disappear from hardware, refresh them from the
driver, since user space and the bridge driver expect that they are
still there.

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-17 14:19           ` Andrew Lunn
  2022-03-17 15:36             ` Vladimir Oltean
@ 2022-03-21 14:51             ` Hans Schultz
  1 sibling, 0 replies; 63+ messages in thread
From: Hans Schultz @ 2022-03-21 14:51 UTC (permalink / raw)
  To: Andrew Lunn, Hans Schultz
  Cc: Vladimir Oltean, davem, kuba, netdev, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On tor, mar 17, 2022 at 15:19, Andrew Lunn <andrew@lunn.ch> wrote:
> On Thu, Mar 17, 2022 at 09:52:15AM +0100, Hans Schultz wrote:
>> On tor, mar 17, 2022 at 01:34, Vladimir Oltean <olteanv@gmail.com> wrote:
>> > On Mon, Mar 14, 2022 at 11:46:51AM +0100, Hans Schultz wrote:
>> >> >> @@ -396,6 +414,13 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
>> >> >>  				    "ATU miss violation for %pM portvec %x spid %d\n",
>> >> >>  				    entry.mac, entry.portvec, spid);
>> >> >>  		chip->ports[spid].atu_miss_violation++;
>> >> >> +		if (mv88e6xxx_port_is_locked(chip, chip->ports[spid].port))
>> >> >> +			err = mv88e6xxx_switchdev_handle_atu_miss_violation(chip,
>> >> >> +									    chip->ports[spid].port,
>> >> >> +									    &entry,
>> >> >> +									    fid);
>> >> >
>> >> > Do we want to suppress the ATU miss violation warnings if we're going to
>> >> > notify the bridge, or is it better to keep them for some reason?
>> >> > My logic is that they're part of normal operation, so suppressing makes
>> >> > sense.
>> >> >
>> >> 
>> >> I have been seeing many ATU member violations after the miss violation is
>> >> handled (using ping), and I think it could be considered to suppress the ATU member
>> >> violations interrupts by setting the IgnoreWrongData bit for the
>> >> port (sect 4.4.7). This would be something to do whenever a port is set in locked mode?
>> >
>> > So the first packet with a given MAC SA triggers an ATU miss violation
>> > interrupt.
>> >
>> > You program that MAC SA into the ATU with a destination port mask of all
>> > zeroes. This suppresses further ATU miss interrupts for this MAC SA, but
>> > now generates ATU member violations, because the MAC SA _is_ present in
>> > the ATU, but not towards the expected port (in fact, towards _no_ port).
>> >
>> > Especially if user space decides it doesn't want to authorize this MAC
>> > SA, it really becomes a problem because this is now a vector for denial
>> > of service, with every packet triggering an ATU member violation
>> > interrupt.
>> >
>> > So your suggestion is to set the IgnoreWrongData bit on locked ports,
>> > and this will suppress the actual member violation interrupts for
>> > traffic coming from these ports.
>> >
>> > So if the user decides to unplug a previously authorized printer from
>> > switch port 1 and move it to port 2, how is this handled? If there isn't
>> > a mechanism in place to delete the locked FDB entry when the printer
>> > goes away, then by setting IgnoreWrongData you're effectively also
>> > suppressing migration notifications.
>> 
>> I don't think such a scenario is so realistic, as changing port is not
>> just something done casually, besides port 2 then must also be a locked
>> port to have the same policy.
>
> I think it is very realistic. It is also something which does not work
> is going to cause a lot of confusion. People will blame the printer,
> when in fact they should be blaming the switch. They will be rebooting
> the printer, when in fact, they need to reboot the switch etc.
>
> I expect there is a way to cleanly support this, you just need to
> figure it out.
>
>> The other aspect is that the user space daemon that authorizes catches
>> the fdb add entry events and checks if it is a locked entry. So it will
>> be up to said daemon to decide the policy, like remove the fdb entry
>> after a timeout.
>> 
>> >
>> > Oh, btw, my question was: could you consider suppressing the _prints_ on
>> > an ATU miss violation on a locked port?
>> 
>> As there will only be such on the first packet, I think it should be
>> logged and those prints serve that purpose, so I think it is best to
>> keep the print.
>> If in the future some tests or other can argue for suppressing the
>> prints, it is an easy thing to do.
>
> Please use a traffic generator and try to DOS one of your own
> switches. Can you?
>
> 	  Andrew

Here is a trafgen report, where I sent packets to a locked port with random SAs:

    42527020 packets outgoing
  3104472460 bytes outgoing
         329 sec, 989345 usec on CPU0 (5835746 packets)
         329 sec, 985243 usec on CPU1 (2119061 packets)
         329 sec, 997323 usec on CPU2 (5656546 packets)
         329 sec, 989475 usec on CPU3 (5617322 packets)
         330 sec, 5228 usec on CPU4 (6034671 packets)
         330 sec, 1603 usec on CPU5 (5833505 packets)
         329 sec, 989319 usec on CPU6 (5709841 packets)
         329 sec, 989294 usec on CPU7 (5720328 packets)

I could do 'bridge fdb show' after stopping the traffic, printing out a
very long list (minutes to print). The ATU was normal, so there is an
issue of the soft FDB locked entries not ageing out.

I saw many reports of suppressed IRQs in the kernel log.

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-18 13:19                             ` Vladimir Oltean
@ 2022-03-22 11:01                               ` Hans Schultz
  2022-03-22 11:08                                 ` Vladimir Oltean
  0 siblings, 1 reply; 63+ messages in thread
From: Hans Schultz @ 2022-03-22 11:01 UTC (permalink / raw)
  To: Vladimir Oltean, Hans Schultz
  Cc: Andrew Lunn, davem, kuba, netdev, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On fre, mar 18, 2022 at 15:19, Vladimir Oltean <olteanv@gmail.com> wrote:
> On Fri, Mar 18, 2022 at 02:10:26PM +0100, Hans Schultz wrote:
>> In the offloaded case there is no difference between static and dynamic
>> flags, which I see as a general issue. (The resulting ATU entry is static
>> in either case.)
>
> It _is_ a problem. We had the same problem with the is_local bit.
> Independently of this series, you can add the dynamic bit to struct
> switchdev_notifier_fdb_info and make drivers reject it.
>
>> These FDB entries are removed when link goes down (soft or hard). The
>> zero DPV entries that the new code introduces age out after 5 minutes,
>> while the locked flagged FDB entries are removed by link down (thus the
>> FDB and the ATU are not in sync in this case).
>
> Ok, so don't let them disappear from hardware, refresh them from the
> driver, since user space and the bridge driver expect that they are
> still there.

I have now tested with two extra unmanaged switches (each connected to a
seperate port on our managed switch, and when migrating from one port to
another, there is member violations, but as the initial entry ages out,
a new miss violation occurs and the new port adds the locked entry. In
this case I only see one locked entry, either on the initial port or
later on the port the host migrated to (via switch).

If I refresh the ATU entries indefinitly, then this migration will for
sure not work, and with the member violation suppressed, it will be
silent about it.

So I don't think it is a good idea to refresh the ATU entries
indefinitely.

Another issue I see, is that there is a deadlock or similar issue when
receiving violations and running 'bridge fdb show' (it seemed that
member violations also caused this, but not sure yet...), as the unit
freezes, not to return...

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-22 11:01                               ` Hans Schultz
@ 2022-03-22 11:08                                 ` Vladimir Oltean
  2022-03-22 13:21                                   ` Hans Schultz
  2022-03-23 10:13                                   ` Hans Schultz
  0 siblings, 2 replies; 63+ messages in thread
From: Vladimir Oltean @ 2022-03-22 11:08 UTC (permalink / raw)
  To: Hans Schultz
  Cc: Andrew Lunn, davem, kuba, netdev, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On Tue, Mar 22, 2022 at 12:01:13PM +0100, Hans Schultz wrote:
> On fre, mar 18, 2022 at 15:19, Vladimir Oltean <olteanv@gmail.com> wrote:
> > On Fri, Mar 18, 2022 at 02:10:26PM +0100, Hans Schultz wrote:
> >> In the offloaded case there is no difference between static and dynamic
> >> flags, which I see as a general issue. (The resulting ATU entry is static
> >> in either case.)
> >
> > It _is_ a problem. We had the same problem with the is_local bit.
> > Independently of this series, you can add the dynamic bit to struct
> > switchdev_notifier_fdb_info and make drivers reject it.
> >
> >> These FDB entries are removed when link goes down (soft or hard). The
> >> zero DPV entries that the new code introduces age out after 5 minutes,
> >> while the locked flagged FDB entries are removed by link down (thus the
> >> FDB and the ATU are not in sync in this case).
> >
> > Ok, so don't let them disappear from hardware, refresh them from the
> > driver, since user space and the bridge driver expect that they are
> > still there.
> 
> I have now tested with two extra unmanaged switches (each connected to a
> seperate port on our managed switch, and when migrating from one port to
> another, there is member violations, but as the initial entry ages out,
> a new miss violation occurs and the new port adds the locked entry. In
> this case I only see one locked entry, either on the initial port or
> later on the port the host migrated to (via switch).
> 
> If I refresh the ATU entries indefinitly, then this migration will for
> sure not work, and with the member violation suppressed, it will be
> silent about it.

Manual says that migrations should trigger miss violations if configured
adequately, is this not the case?

> So I don't think it is a good idea to refresh the ATU entries
> indefinitely.
> 
> Another issue I see, is that there is a deadlock or similar issue when
> receiving violations and running 'bridge fdb show' (it seemed that
> member violations also caused this, but not sure yet...), as the unit
> freezes, not to return...

Have you enabled lockdep, debug atomic sleep, detect hung tasks, things
like that?

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-22 11:08                                 ` Vladimir Oltean
@ 2022-03-22 13:21                                   ` Hans Schultz
  2022-03-22 14:47                                     ` Hans Schultz
  2022-03-23 10:13                                   ` Hans Schultz
  1 sibling, 1 reply; 63+ messages in thread
From: Hans Schultz @ 2022-03-22 13:21 UTC (permalink / raw)
  To: Vladimir Oltean, Hans Schultz
  Cc: Andrew Lunn, davem, kuba, netdev, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On tis, mar 22, 2022 at 13:08, Vladimir Oltean <olteanv@gmail.com> wrote:
> On Tue, Mar 22, 2022 at 12:01:13PM +0100, Hans Schultz wrote:
>> On fre, mar 18, 2022 at 15:19, Vladimir Oltean <olteanv@gmail.com> wrote:
>> > On Fri, Mar 18, 2022 at 02:10:26PM +0100, Hans Schultz wrote:
>> >> In the offloaded case there is no difference between static and dynamic
>> >> flags, which I see as a general issue. (The resulting ATU entry is static
>> >> in either case.)
>> >
>> > It _is_ a problem. We had the same problem with the is_local bit.
>> > Independently of this series, you can add the dynamic bit to struct
>> > switchdev_notifier_fdb_info and make drivers reject it.
>> >
>> >> These FDB entries are removed when link goes down (soft or hard). The
>> >> zero DPV entries that the new code introduces age out after 5 minutes,
>> >> while the locked flagged FDB entries are removed by link down (thus the
>> >> FDB and the ATU are not in sync in this case).
>> >
>> > Ok, so don't let them disappear from hardware, refresh them from the
>> > driver, since user space and the bridge driver expect that they are
>> > still there.
>> 
>> I have now tested with two extra unmanaged switches (each connected to a
>> seperate port on our managed switch, and when migrating from one port to
>> another, there is member violations, but as the initial entry ages out,
>> a new miss violation occurs and the new port adds the locked entry. In
>> this case I only see one locked entry, either on the initial port or
>> later on the port the host migrated to (via switch).
>> 
>> If I refresh the ATU entries indefinitly, then this migration will for
>> sure not work, and with the member violation suppressed, it will be
>> silent about it.
>
> Manual says that migrations should trigger miss violations if configured
> adequately, is this not the case?
>
Yes, but that depends on the ATU entries ageing out. As it is now, it works.

>> So I don't think it is a good idea to refresh the ATU entries
>> indefinitely.
>> 
>> Another issue I see, is that there is a deadlock or similar issue when
>> receiving violations and running 'bridge fdb show' (it seemed that
>> member violations also caused this, but not sure yet...), as the unit
>> freezes, not to return...
>
> Have you enabled lockdep, debug atomic sleep, detect hung tasks, things
> like that?

No, I haven't looked deeper into it yet. Maybe I was hoping someone had
an idea... but I guess it cannot be a netlink deadlock?

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-22 13:21                                   ` Hans Schultz
@ 2022-03-22 14:47                                     ` Hans Schultz
  0 siblings, 0 replies; 63+ messages in thread
From: Hans Schultz @ 2022-03-22 14:47 UTC (permalink / raw)
  To: Hans Schultz, Vladimir Oltean, Hans Schultz
  Cc: Andrew Lunn, davem, kuba, netdev, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On tis, mar 22, 2022 at 14:21, Hans Schultz <schultz.hans@gmail.com> wrote:
> On tis, mar 22, 2022 at 13:08, Vladimir Oltean <olteanv@gmail.com> wrote:
>> On Tue, Mar 22, 2022 at 12:01:13PM +0100, Hans Schultz wrote:
>>> On fre, mar 18, 2022 at 15:19, Vladimir Oltean <olteanv@gmail.com> wrote:
>>> > On Fri, Mar 18, 2022 at 02:10:26PM +0100, Hans Schultz wrote:
>>> >> In the offloaded case there is no difference between static and dynamic
>>> >> flags, which I see as a general issue. (The resulting ATU entry is static
>>> >> in either case.)
>>> >
>>> > It _is_ a problem. We had the same problem with the is_local bit.
>>> > Independently of this series, you can add the dynamic bit to struct
>>> > switchdev_notifier_fdb_info and make drivers reject it.
>>> >
>>> >> These FDB entries are removed when link goes down (soft or hard). The
>>> >> zero DPV entries that the new code introduces age out after 5 minutes,
>>> >> while the locked flagged FDB entries are removed by link down (thus the
>>> >> FDB and the ATU are not in sync in this case).
>>> >
>>> > Ok, so don't let them disappear from hardware, refresh them from the
>>> > driver, since user space and the bridge driver expect that they are
>>> > still there.
>>> 
>>> I have now tested with two extra unmanaged switches (each connected to a
>>> seperate port on our managed switch, and when migrating from one port to
>>> another, there is member violations, but as the initial entry ages out,
>>> a new miss violation occurs and the new port adds the locked entry. In
>>> this case I only see one locked entry, either on the initial port or
>>> later on the port the host migrated to (via switch).
>>> 
>>> If I refresh the ATU entries indefinitly, then this migration will for
>>> sure not work, and with the member violation suppressed, it will be
>>> silent about it.
>>
>> Manual says that migrations should trigger miss violations if configured
>> adequately, is this not the case?
>>
> Yes, but that depends on the ATU entries ageing out. As it is now, it works.
>
>>> So I don't think it is a good idea to refresh the ATU entries
>>> indefinitely.
>>> 
>>> Another issue I see, is that there is a deadlock or similar issue when
>>> receiving violations and running 'bridge fdb show' (it seemed that
>>> member violations also caused this, but not sure yet...), as the unit
>>> freezes, not to return...

I have now verified that it is only on miss violations that the problem
occurs, so it seems that there is a deadlock (with 'bridge fdb show')
somehow with the nl lock that the handling of ATU miss violations
acquires.

>>
>> Have you enabled lockdep, debug atomic sleep, detect hung tasks, things
>> like that?
>
> No, I haven't looked deeper into it yet. Maybe I was hoping someone had
> an idea... but I guess it cannot be a netlink deadlock?

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-22 11:08                                 ` Vladimir Oltean
  2022-03-22 13:21                                   ` Hans Schultz
@ 2022-03-23 10:13                                   ` Hans Schultz
  2022-03-23 10:16                                     ` Vladimir Oltean
  1 sibling, 1 reply; 63+ messages in thread
From: Hans Schultz @ 2022-03-23 10:13 UTC (permalink / raw)
  To: Vladimir Oltean, Hans Schultz
  Cc: Andrew Lunn, davem, kuba, netdev, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On tis, mar 22, 2022 at 13:08, Vladimir Oltean <olteanv@gmail.com> wrote:
> On Tue, Mar 22, 2022 at 12:01:13PM +0100, Hans Schultz wrote:
>> On fre, mar 18, 2022 at 15:19, Vladimir Oltean <olteanv@gmail.com> wrote:
>> > On Fri, Mar 18, 2022 at 02:10:26PM +0100, Hans Schultz wrote:
>> >> In the offloaded case there is no difference between static and dynamic
>> >> flags, which I see as a general issue. (The resulting ATU entry is static
>> >> in either case.)
>> >
>> > It _is_ a problem. We had the same problem with the is_local bit.
>> > Independently of this series, you can add the dynamic bit to struct
>> > switchdev_notifier_fdb_info and make drivers reject it.
>> >
>> >> These FDB entries are removed when link goes down (soft or hard). The
>> >> zero DPV entries that the new code introduces age out after 5 minutes,
>> >> while the locked flagged FDB entries are removed by link down (thus the
>> >> FDB and the ATU are not in sync in this case).
>> >
>> > Ok, so don't let them disappear from hardware, refresh them from the
>> > driver, since user space and the bridge driver expect that they are
>> > still there.
>> 
>> I have now tested with two extra unmanaged switches (each connected to a
>> seperate port on our managed switch, and when migrating from one port to
>> another, there is member violations, but as the initial entry ages out,
>> a new miss violation occurs and the new port adds the locked entry. In
>> this case I only see one locked entry, either on the initial port or
>> later on the port the host migrated to (via switch).
>> 
>> If I refresh the ATU entries indefinitly, then this migration will for
>> sure not work, and with the member violation suppressed, it will be
>> silent about it.
>
> Manual says that migrations should trigger miss violations if configured
> adequately, is this not the case?
>
>> So I don't think it is a good idea to refresh the ATU entries
>> indefinitely.
>> 
>> Another issue I see, is that there is a deadlock or similar issue when
>> receiving violations and running 'bridge fdb show' (it seemed that
>> member violations also caused this, but not sure yet...), as the unit
>> freezes, not to return...
>
> Have you enabled lockdep, debug atomic sleep, detect hung tasks, things
> like that?

I have now determined that it is the rtnl_lock() that causes the
"deadlock". The doit() in rtnetlink.c is under rtnl_lock() and is what
takes care of getting the fdb entries when running 'bridge fdb show'. In
principle there should be no problem with this, but I don't know if some
interrupt queue is getting jammed as they are blocked from rtnetlink.c?

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-23 10:13                                   ` Hans Schultz
@ 2022-03-23 10:16                                     ` Vladimir Oltean
  2022-03-23 10:46                                       ` Hans Schultz
  2022-03-23 10:57                                       ` Hans Schultz
  0 siblings, 2 replies; 63+ messages in thread
From: Vladimir Oltean @ 2022-03-23 10:16 UTC (permalink / raw)
  To: Hans Schultz
  Cc: Andrew Lunn, davem, kuba, netdev, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On Wed, Mar 23, 2022 at 11:13:51AM +0100, Hans Schultz wrote:
> On tis, mar 22, 2022 at 13:08, Vladimir Oltean <olteanv@gmail.com> wrote:
> > On Tue, Mar 22, 2022 at 12:01:13PM +0100, Hans Schultz wrote:
> >> On fre, mar 18, 2022 at 15:19, Vladimir Oltean <olteanv@gmail.com> wrote:
> >> > On Fri, Mar 18, 2022 at 02:10:26PM +0100, Hans Schultz wrote:
> >> >> In the offloaded case there is no difference between static and dynamic
> >> >> flags, which I see as a general issue. (The resulting ATU entry is static
> >> >> in either case.)
> >> >
> >> > It _is_ a problem. We had the same problem with the is_local bit.
> >> > Independently of this series, you can add the dynamic bit to struct
> >> > switchdev_notifier_fdb_info and make drivers reject it.
> >> >
> >> >> These FDB entries are removed when link goes down (soft or hard). The
> >> >> zero DPV entries that the new code introduces age out after 5 minutes,
> >> >> while the locked flagged FDB entries are removed by link down (thus the
> >> >> FDB and the ATU are not in sync in this case).
> >> >
> >> > Ok, so don't let them disappear from hardware, refresh them from the
> >> > driver, since user space and the bridge driver expect that they are
> >> > still there.
> >> 
> >> I have now tested with two extra unmanaged switches (each connected to a
> >> seperate port on our managed switch, and when migrating from one port to
> >> another, there is member violations, but as the initial entry ages out,
> >> a new miss violation occurs and the new port adds the locked entry. In
> >> this case I only see one locked entry, either on the initial port or
> >> later on the port the host migrated to (via switch).
> >> 
> >> If I refresh the ATU entries indefinitly, then this migration will for
> >> sure not work, and with the member violation suppressed, it will be
> >> silent about it.
> >
> > Manual says that migrations should trigger miss violations if configured
> > adequately, is this not the case?
> >
> >> So I don't think it is a good idea to refresh the ATU entries
> >> indefinitely.
> >> 
> >> Another issue I see, is that there is a deadlock or similar issue when
> >> receiving violations and running 'bridge fdb show' (it seemed that
> >> member violations also caused this, but not sure yet...), as the unit
> >> freezes, not to return...
> >
> > Have you enabled lockdep, debug atomic sleep, detect hung tasks, things
> > like that?
> 
> I have now determined that it is the rtnl_lock() that causes the
> "deadlock". The doit() in rtnetlink.c is under rtnl_lock() and is what
> takes care of getting the fdb entries when running 'bridge fdb show'. In
> principle there should be no problem with this, but I don't know if some
> interrupt queue is getting jammed as they are blocked from rtnetlink.c?

Sorry, I forgot to respond yesterday to this.
By any chance do you maybe have an AB/BA lock inversion, where from the
ATU interrupt handler you do mv88e6xxx_reg_lock() -> rtnl_lock(), while
from the port_fdb_dump() handler you do rtnl_lock() -> mv88e6xxx_reg_lock()?

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-23 10:16                                     ` Vladimir Oltean
@ 2022-03-23 10:46                                       ` Hans Schultz
  2022-03-23 10:57                                       ` Hans Schultz
  1 sibling, 0 replies; 63+ messages in thread
From: Hans Schultz @ 2022-03-23 10:46 UTC (permalink / raw)
  To: Vladimir Oltean, Hans Schultz
  Cc: Andrew Lunn, davem, kuba, netdev, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On ons, mar 23, 2022 at 12:16, Vladimir Oltean <olteanv@gmail.com> wrote:
> On Wed, Mar 23, 2022 at 11:13:51AM +0100, Hans Schultz wrote:
>> On tis, mar 22, 2022 at 13:08, Vladimir Oltean <olteanv@gmail.com> wrote:
>> > On Tue, Mar 22, 2022 at 12:01:13PM +0100, Hans Schultz wrote:
>> >> On fre, mar 18, 2022 at 15:19, Vladimir Oltean <olteanv@gmail.com> wrote:
>> >> > On Fri, Mar 18, 2022 at 02:10:26PM +0100, Hans Schultz wrote:
>> >> >> In the offloaded case there is no difference between static and dynamic
>> >> >> flags, which I see as a general issue. (The resulting ATU entry is static
>> >> >> in either case.)
>> >> >
>> >> > It _is_ a problem. We had the same problem with the is_local bit.
>> >> > Independently of this series, you can add the dynamic bit to struct
>> >> > switchdev_notifier_fdb_info and make drivers reject it.
>> >> >
>> >> >> These FDB entries are removed when link goes down (soft or hard). The
>> >> >> zero DPV entries that the new code introduces age out after 5 minutes,
>> >> >> while the locked flagged FDB entries are removed by link down (thus the
>> >> >> FDB and the ATU are not in sync in this case).
>> >> >
>> >> > Ok, so don't let them disappear from hardware, refresh them from the
>> >> > driver, since user space and the bridge driver expect that they are
>> >> > still there.
>> >> 
>> >> I have now tested with two extra unmanaged switches (each connected to a
>> >> seperate port on our managed switch, and when migrating from one port to
>> >> another, there is member violations, but as the initial entry ages out,
>> >> a new miss violation occurs and the new port adds the locked entry. In
>> >> this case I only see one locked entry, either on the initial port or
>> >> later on the port the host migrated to (via switch).
>> >> 
>> >> If I refresh the ATU entries indefinitly, then this migration will for
>> >> sure not work, and with the member violation suppressed, it will be
>> >> silent about it.
>> >
>> > Manual says that migrations should trigger miss violations if configured
>> > adequately, is this not the case?
>> >
>> >> So I don't think it is a good idea to refresh the ATU entries
>> >> indefinitely.
>> >> 
>> >> Another issue I see, is that there is a deadlock or similar issue when
>> >> receiving violations and running 'bridge fdb show' (it seemed that
>> >> member violations also caused this, but not sure yet...), as the unit
>> >> freezes, not to return...
>> >
>> > Have you enabled lockdep, debug atomic sleep, detect hung tasks, things
>> > like that?
>> 
>> I have now determined that it is the rtnl_lock() that causes the
>> "deadlock". The doit() in rtnetlink.c is under rtnl_lock() and is what
>> takes care of getting the fdb entries when running 'bridge fdb show'. In
>> principle there should be no problem with this, but I don't know if some
>> interrupt queue is getting jammed as they are blocked from rtnetlink.c?
>
> Sorry, I forgot to respond yesterday to this.
> By any chance do you maybe have an AB/BA lock inversion, where from the
> ATU interrupt handler you do mv88e6xxx_reg_lock() -> rtnl_lock(), while
> from the port_fdb_dump() handler you do rtnl_lock() -> mv88e6xxx_reg_lock()?

Yes, I forgot that the whole handler is under mv88e6xxx_reg_lock(). I
hope then that I can release the mv88e6xxx_reg_lock() before calling the
handler function with issues?

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-23 10:16                                     ` Vladimir Oltean
  2022-03-23 10:46                                       ` Hans Schultz
@ 2022-03-23 10:57                                       ` Hans Schultz
  2022-03-23 11:21                                         ` Vladimir Oltean
  1 sibling, 1 reply; 63+ messages in thread
From: Hans Schultz @ 2022-03-23 10:57 UTC (permalink / raw)
  To: Vladimir Oltean, Hans Schultz
  Cc: Andrew Lunn, davem, kuba, netdev, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On ons, mar 23, 2022 at 12:16, Vladimir Oltean <olteanv@gmail.com> wrote:
> On Wed, Mar 23, 2022 at 11:13:51AM +0100, Hans Schultz wrote:
>> On tis, mar 22, 2022 at 13:08, Vladimir Oltean <olteanv@gmail.com> wrote:
>> > On Tue, Mar 22, 2022 at 12:01:13PM +0100, Hans Schultz wrote:
>> >> On fre, mar 18, 2022 at 15:19, Vladimir Oltean <olteanv@gmail.com> wrote:
>> >> > On Fri, Mar 18, 2022 at 02:10:26PM +0100, Hans Schultz wrote:
>> >> >> In the offloaded case there is no difference between static and dynamic
>> >> >> flags, which I see as a general issue. (The resulting ATU entry is static
>> >> >> in either case.)
>> >> >
>> >> > It _is_ a problem. We had the same problem with the is_local bit.
>> >> > Independently of this series, you can add the dynamic bit to struct
>> >> > switchdev_notifier_fdb_info and make drivers reject it.
>> >> >
>> >> >> These FDB entries are removed when link goes down (soft or hard). The
>> >> >> zero DPV entries that the new code introduces age out after 5 minutes,
>> >> >> while the locked flagged FDB entries are removed by link down (thus the
>> >> >> FDB and the ATU are not in sync in this case).
>> >> >
>> >> > Ok, so don't let them disappear from hardware, refresh them from the
>> >> > driver, since user space and the bridge driver expect that they are
>> >> > still there.
>> >> 
>> >> I have now tested with two extra unmanaged switches (each connected to a
>> >> seperate port on our managed switch, and when migrating from one port to
>> >> another, there is member violations, but as the initial entry ages out,
>> >> a new miss violation occurs and the new port adds the locked entry. In
>> >> this case I only see one locked entry, either on the initial port or
>> >> later on the port the host migrated to (via switch).
>> >> 
>> >> If I refresh the ATU entries indefinitly, then this migration will for
>> >> sure not work, and with the member violation suppressed, it will be
>> >> silent about it.
>> >
>> > Manual says that migrations should trigger miss violations if configured
>> > adequately, is this not the case?
>> >
>> >> So I don't think it is a good idea to refresh the ATU entries
>> >> indefinitely.
>> >> 
>> >> Another issue I see, is that there is a deadlock or similar issue when
>> >> receiving violations and running 'bridge fdb show' (it seemed that
>> >> member violations also caused this, but not sure yet...), as the unit
>> >> freezes, not to return...
>> >
>> > Have you enabled lockdep, debug atomic sleep, detect hung tasks, things
>> > like that?
>> 
>> I have now determined that it is the rtnl_lock() that causes the
>> "deadlock". The doit() in rtnetlink.c is under rtnl_lock() and is what
>> takes care of getting the fdb entries when running 'bridge fdb show'. In
>> principle there should be no problem with this, but I don't know if some
>> interrupt queue is getting jammed as they are blocked from rtnetlink.c?
>
> Sorry, I forgot to respond yesterday to this.
> By any chance do you maybe have an AB/BA lock inversion, where from the
> ATU interrupt handler you do mv88e6xxx_reg_lock() -> rtnl_lock(), while
> from the port_fdb_dump() handler you do rtnl_lock() -> mv88e6xxx_reg_lock()?

If I release the mv88e6xxx_reg_lock() before calling the handler, I need
to get it again for the mv88e6xxx_g1_atu_loadpurge() call at least. But
maybe the vtu_walk also needs the mv88e6xxx_reg_lock()?
I could also just release the mv88e6xxx_reg_lock() before the
call_switchdev_notifiers() call and reacquire it immediately after?

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-23 10:57                                       ` Hans Schultz
@ 2022-03-23 11:21                                         ` Vladimir Oltean
  2022-03-23 11:43                                           ` Hans Schultz
  0 siblings, 1 reply; 63+ messages in thread
From: Vladimir Oltean @ 2022-03-23 11:21 UTC (permalink / raw)
  To: Hans Schultz
  Cc: Andrew Lunn, davem, kuba, netdev, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On Wed, Mar 23, 2022 at 11:57:16AM +0100, Hans Schultz wrote:
> >> >> Another issue I see, is that there is a deadlock or similar issue when
> >> >> receiving violations and running 'bridge fdb show' (it seemed that
> >> >> member violations also caused this, but not sure yet...), as the unit
> >> >> freezes, not to return...
> >> >
> >> > Have you enabled lockdep, debug atomic sleep, detect hung tasks, things
> >> > like that?
> >> 
> >> I have now determined that it is the rtnl_lock() that causes the
> >> "deadlock". The doit() in rtnetlink.c is under rtnl_lock() and is what
> >> takes care of getting the fdb entries when running 'bridge fdb show'. In
> >> principle there should be no problem with this, but I don't know if some
> >> interrupt queue is getting jammed as they are blocked from rtnetlink.c?
> >
> > Sorry, I forgot to respond yesterday to this.
> > By any chance do you maybe have an AB/BA lock inversion, where from the
> > ATU interrupt handler you do mv88e6xxx_reg_lock() -> rtnl_lock(), while
> > from the port_fdb_dump() handler you do rtnl_lock() -> mv88e6xxx_reg_lock()?
> 
> If I release the mv88e6xxx_reg_lock() before calling the handler, I need
> to get it again for the mv88e6xxx_g1_atu_loadpurge() call at least. But
> maybe the vtu_walk also needs the mv88e6xxx_reg_lock()?
> I could also just release the mv88e6xxx_reg_lock() before the
> call_switchdev_notifiers() call and reacquire it immediately after?

The cleanest way to go about this would be to have the call_switchdev_notifiers()
portion of the ATU interrupt handling at the very end of mv88e6xxx_g1_atu_prob_irq_thread_fn(),
with no hardware access needed, and therefore no reg_lock() held.

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-23 11:21                                         ` Vladimir Oltean
@ 2022-03-23 11:43                                           ` Hans Schultz
  2022-03-23 11:54                                             ` Vladimir Oltean
  0 siblings, 1 reply; 63+ messages in thread
From: Hans Schultz @ 2022-03-23 11:43 UTC (permalink / raw)
  To: Vladimir Oltean, Hans Schultz
  Cc: Andrew Lunn, davem, kuba, netdev, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On ons, mar 23, 2022 at 13:21, Vladimir Oltean <olteanv@gmail.com> wrote:
> On Wed, Mar 23, 2022 at 11:57:16AM +0100, Hans Schultz wrote:
>> >> >> Another issue I see, is that there is a deadlock or similar issue when
>> >> >> receiving violations and running 'bridge fdb show' (it seemed that
>> >> >> member violations also caused this, but not sure yet...), as the unit
>> >> >> freezes, not to return...
>> >> >
>> >> > Have you enabled lockdep, debug atomic sleep, detect hung tasks, things
>> >> > like that?
>> >> 
>> >> I have now determined that it is the rtnl_lock() that causes the
>> >> "deadlock". The doit() in rtnetlink.c is under rtnl_lock() and is what
>> >> takes care of getting the fdb entries when running 'bridge fdb show'. In
>> >> principle there should be no problem with this, but I don't know if some
>> >> interrupt queue is getting jammed as they are blocked from rtnetlink.c?
>> >
>> > Sorry, I forgot to respond yesterday to this.
>> > By any chance do you maybe have an AB/BA lock inversion, where from the
>> > ATU interrupt handler you do mv88e6xxx_reg_lock() -> rtnl_lock(), while
>> > from the port_fdb_dump() handler you do rtnl_lock() -> mv88e6xxx_reg_lock()?
>> 
>> If I release the mv88e6xxx_reg_lock() before calling the handler, I need
>> to get it again for the mv88e6xxx_g1_atu_loadpurge() call at least. But
>> maybe the vtu_walk also needs the mv88e6xxx_reg_lock()?
>> I could also just release the mv88e6xxx_reg_lock() before the
>> call_switchdev_notifiers() call and reacquire it immediately after?
>
> The cleanest way to go about this would be to have the call_switchdev_notifiers()
> portion of the ATU interrupt handling at the very end of mv88e6xxx_g1_atu_prob_irq_thread_fn(),
> with no hardware access needed, and therefore no reg_lock() held.

So something like?
	mv88e6xxx_reg_unlock(chip);
	rtnl_lock();
	err = call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE, brport, &info.info, NULL);
	rtnl_unlock();
	mv88e6xxx_reg_lock(chip);

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-03-23 11:43                                           ` Hans Schultz
@ 2022-03-23 11:54                                             ` Vladimir Oltean
  0 siblings, 0 replies; 63+ messages in thread
From: Vladimir Oltean @ 2022-03-23 11:54 UTC (permalink / raw)
  To: Hans Schultz
  Cc: Andrew Lunn, davem, kuba, netdev, Vivien Didelot,
	Florian Fainelli, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
	Nikolay Aleksandrov, Daniel Borkmann, Ido Schimmel, linux-kernel,
	bridge

On Wed, Mar 23, 2022 at 12:43:03PM +0100, Hans Schultz wrote:
> On ons, mar 23, 2022 at 13:21, Vladimir Oltean <olteanv@gmail.com> wrote:
> > On Wed, Mar 23, 2022 at 11:57:16AM +0100, Hans Schultz wrote:
> >> >> >> Another issue I see, is that there is a deadlock or similar issue when
> >> >> >> receiving violations and running 'bridge fdb show' (it seemed that
> >> >> >> member violations also caused this, but not sure yet...), as the unit
> >> >> >> freezes, not to return...
> >> >> >
> >> >> > Have you enabled lockdep, debug atomic sleep, detect hung tasks, things
> >> >> > like that?
> >> >> 
> >> >> I have now determined that it is the rtnl_lock() that causes the
> >> >> "deadlock". The doit() in rtnetlink.c is under rtnl_lock() and is what
> >> >> takes care of getting the fdb entries when running 'bridge fdb show'. In
> >> >> principle there should be no problem with this, but I don't know if some
> >> >> interrupt queue is getting jammed as they are blocked from rtnetlink.c?
> >> >
> >> > Sorry, I forgot to respond yesterday to this.
> >> > By any chance do you maybe have an AB/BA lock inversion, where from the
> >> > ATU interrupt handler you do mv88e6xxx_reg_lock() -> rtnl_lock(), while
> >> > from the port_fdb_dump() handler you do rtnl_lock() -> mv88e6xxx_reg_lock()?
> >> 
> >> If I release the mv88e6xxx_reg_lock() before calling the handler, I need
> >> to get it again for the mv88e6xxx_g1_atu_loadpurge() call at least. But
> >> maybe the vtu_walk also needs the mv88e6xxx_reg_lock()?
> >> I could also just release the mv88e6xxx_reg_lock() before the
> >> call_switchdev_notifiers() call and reacquire it immediately after?
> >
> > The cleanest way to go about this would be to have the call_switchdev_notifiers()
> > portion of the ATU interrupt handling at the very end of mv88e6xxx_g1_atu_prob_irq_thread_fn(),
> > with no hardware access needed, and therefore no reg_lock() held.
> 
> So something like?
> 	mv88e6xxx_reg_unlock(chip);
> 	rtnl_lock();
> 	err = call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE, brport, &info.info, NULL);
> 	rtnl_unlock();
> 	mv88e6xxx_reg_lock(chip);

No, call_switchdev_notifiers() should be the very end, no reg_lock() afterwards.
Do all the hardware handling you need, populate some variables to denote
that you need to notify switchdev, and if you do, lock the rtnetlink
mutex and do it.

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-12-08 16:03             ` netdev
@ 2022-12-08 16:09               ` Vladimir Oltean
  0 siblings, 0 replies; 63+ messages in thread
From: Vladimir Oltean @ 2022-12-08 16:09 UTC (permalink / raw)
  To: netdev
  Cc: Ido Schimmel, davem, kuba, netdev, Andrew Lunn, Florian Fainelli,
	Eric Dumazet, Paolo Abeni, open list

On Thu, Dec 08, 2022 at 05:03:59PM +0100, netdev@kapio-technology.com wrote:
> At leisure, do you have an idea why it will encounter a VTU miss violation
> at random?

Do you understand that any packets with a VID that isn't present in the
VTU will trigger a VTU miss, and also an ATU miss if the port is locked
and the ATU doesn't have an entry with that FID?

Your selftest creates a VLAN interface on top of $h1 with a VID that
isn't present in the VTU of the switch ("bridge vlan add .. vid 100" is
run elsewhere; we run "bridge vlan del ... vid 100" when we no longer
need it). But the $h1.100 interface is persistent across the selftest.
And it's not silent. Linux does all sorts of crap by default, like IPv6
neighbor discovery, even if you don't use the interface. So it will send
packets from time to time. And that's when you get those ATU and VTU
violations. The MAC address of $h1.100 is the same as the MAC address of
$h1, of course.

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-12-08 13:35           ` Vladimir Oltean
  2022-12-08 14:41             ` netdev
@ 2022-12-08 16:03             ` netdev
  2022-12-08 16:09               ` Vladimir Oltean
  1 sibling, 1 reply; 63+ messages in thread
From: netdev @ 2022-12-08 16:03 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Ido Schimmel, davem, kuba, netdev, Andrew Lunn, Florian Fainelli,
	Eric Dumazet, Paolo Abeni, open list

On 2022-12-08 14:35, Vladimir Oltean wrote:
> 
> So it appears that frames which get a VTU miss will still also cause an
> ATU miss, and that's what you're seeing.
> 
> The solution would be to acknowledge this fact, and not print any error
> message from the ATU IRQ handler for unknown FID/VID, which would just
> alarm the user.

Thanks for clearing that up!

At leisure, do you have an idea why it will encounter a VTU miss 
violation at random?

I guess I must check if FID != FID_STANDALONE instead then...

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-12-08 14:41             ` netdev
@ 2022-12-08 14:43               ` Vladimir Oltean
  0 siblings, 0 replies; 63+ messages in thread
From: Vladimir Oltean @ 2022-12-08 14:43 UTC (permalink / raw)
  To: netdev
  Cc: Ido Schimmel, davem, kuba, netdev, Andrew Lunn, Florian Fainelli,
	Eric Dumazet, Paolo Abeni, open list

On Thu, Dec 08, 2022 at 03:41:24PM +0100, netdev@kapio-technology.com wrote:
> What else conclusion than it is the ATU op that fails?

I don't have any more time than to say "read the rest of my email", sorry.

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-12-08 13:35           ` Vladimir Oltean
@ 2022-12-08 14:41             ` netdev
  2022-12-08 14:43               ` Vladimir Oltean
  2022-12-08 16:03             ` netdev
  1 sibling, 1 reply; 63+ messages in thread
From: netdev @ 2022-12-08 14:41 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Ido Schimmel, davem, kuba, netdev, Andrew Lunn, Florian Fainelli,
	Eric Dumazet, Paolo Abeni, open list

On 2022-12-08 14:35, Vladimir Oltean wrote:
> On Thu, Dec 08, 2022 at 01:28:27PM +0100, netdev@kapio-technology.com 
> wrote:
>> On 2022-12-07 21:29, Vladimir Oltean wrote:
>> > On Tue, Dec 06, 2022 at 05:36:42PM +0100, netdev@kapio-technology.com wrote:
>> > > > I was under the impression that we agreed that the locking change will
>> > > > be split to a separate patch.
>> > >
>> > > Sorry, I guess that because of the quite long time that has passed as I
>> > > needed to get this FID=0 issue sorted out, and had many other different
>> > > changes to attend, I forgot.
>> >
>> > Well, at least you got the FID=0 issue sorted out... right?
>> > What was the cause, what is the solution?
>> 
>> Well I got it sorted out in the way that I have identified that it is 
>> the
>> ATU op that fails some times. I don't think there is anything that can 
>> be
>> done about that, other than what I do and let the interrupt routing 
>> return
>> an error.
> 
> Yikes. But why would you call that "sorted out", though? Just to make 
> it
> appear as though you really spent some time on it, and use it as an
> excuse for something else?
> 
>> it is the ATU op that fails some times.
> 
> Let's start with the assumption that this is correct. A person with
> critical thinking will ask "can I prove that it is?".
> 
> If the ATU operation fails sometimes, I would expect that it always
> fails in the same way, by returning FID 0, where 0 is some kind of
> "invalid" value.
> 
> But if FID 0 is actually FID_STANDALONE, then you'd read FID_STANDALONE
> even if you change the value of FID_STANDALONE in the driver to
> something else, like 1.
> 
> Something ultra hackish like this will install VLAN 3050 as first VID 
> in
> the switch, and that will gain FID 0. Then, MV886XXX_VID_STANDALONE 
> will
> gain FID 1. So we need to adjust the definitions.
> 

Here is an example of the output I have when running the 
locked_port_mab() under the selftests...

mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU problem: error -22 while handling 
interrupt
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU problem: error -22 while handling 
interrupt
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU problem: error -22 while handling 
interrupt
mv88e6085 1002b000.ethernet-1:04: ATU problem: error -22 while handling 
interrupt
mv88e6085 1002b000.ethernet-1:04: ATU problem: error -22 while handling 
interrupt
mv88e6xxx_g1_atu_prob_irq_thread_fn: 13 callbacks suppressed
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU problem: error -22 while handling 
interrupt
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU problem: error -22 while handling 
interrupt
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2

the -22 errors are all when it returns FID=0, and it is the same mac all 
the way.


I have other logs, where the -22 occurs at random other times, f.ex. 
same test:

mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU problem: error -22 while handling 
interrupt
mv88e6xxx_g1_atu_prob_irq_thread_fn: 4 callbacks suppressed
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU problem: error -22 while handling 
interrupt
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU miss violation for 
8e:a9:fc:14:58:06 portvec 0 spid 2
mv88e6085 1002b000.ethernet-1:04: ATU problem: error -22 while handling 
interrupt

What else conclusion than it is the ATU op that fails?

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-12-08 12:28         ` netdev
@ 2022-12-08 13:35           ` Vladimir Oltean
  2022-12-08 14:41             ` netdev
  2022-12-08 16:03             ` netdev
  0 siblings, 2 replies; 63+ messages in thread
From: Vladimir Oltean @ 2022-12-08 13:35 UTC (permalink / raw)
  To: netdev
  Cc: Ido Schimmel, davem, kuba, netdev, Andrew Lunn, Florian Fainelli,
	Eric Dumazet, Paolo Abeni, open list

On Thu, Dec 08, 2022 at 01:28:27PM +0100, netdev@kapio-technology.com wrote:
> On 2022-12-07 21:29, Vladimir Oltean wrote:
> > On Tue, Dec 06, 2022 at 05:36:42PM +0100, netdev@kapio-technology.com wrote:
> > > > I was under the impression that we agreed that the locking change will
> > > > be split to a separate patch.
> > > 
> > > Sorry, I guess that because of the quite long time that has passed as I
> > > needed to get this FID=0 issue sorted out, and had many other different
> > > changes to attend, I forgot.
> > 
> > Well, at least you got the FID=0 issue sorted out... right?
> > What was the cause, what is the solution?
> 
> Well I got it sorted out in the way that I have identified that it is the
> ATU op that fails some times. I don't think there is anything that can be
> done about that, other than what I do and let the interrupt routing return
> an error.

Yikes. But why would you call that "sorted out", though? Just to make it
appear as though you really spent some time on it, and use it as an
excuse for something else?

> it is the ATU op that fails some times.

Let's start with the assumption that this is correct. A person with
critical thinking will ask "can I prove that it is?".

If the ATU operation fails sometimes, I would expect that it always
fails in the same way, by returning FID 0, where 0 is some kind of
"invalid" value.

But if FID 0 is actually FID_STANDALONE, then you'd read FID_STANDALONE
even if you change the value of FID_STANDALONE in the driver to
something else, like 1.

Something ultra hackish like this will install VLAN 3050 as first VID in
the switch, and that will gain FID 0. Then, MV886XXX_VID_STANDALONE will
gain FID 1. So we need to adjust the definitions.

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index ccfa4751d3b7..5923cbb172f9 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -3410,9 +3410,15 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
 	if (err)
 		return err;
 
+	err = mv88e6xxx_port_vlan_join(chip, port, 3050,
+				       MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED,
+				       false);
+	if (err)
+		return err;
+
 	/* Bind MV88E6XXX_VID_STANDALONE to MV88E6XXX_FID_STANDALONE by
 	 * virtue of the fact that mv88e6xxx_atu_new() will pick it as
-	 * the first free FID. This will be used as the private PVID for
+	 * the second free FID. This will be used as the private PVID for
 	 * unbridged ports. Shared (DSA and CPU) ports must also be
 	 * members of this VID, in order to trap all frames assigned to
 	 * it to the CPU.
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index e693154cf803..48d4db4f2adf 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -22,8 +22,8 @@
 #define MV88E6XXX_N_FID		4096
 #define MV88E6XXX_N_SID		64
 
-#define MV88E6XXX_FID_STANDALONE	0
-#define MV88E6XXX_FID_BRIDGED		1
+#define MV88E6XXX_FID_STANDALONE	1
+#define MV88E6XXX_FID_BRIDGED		2
 
 /* PVT limits for 4-bit port and 5-bit switch */
 #define MV88E6XXX_MAX_PVT_SWITCHES	32

Now back to running the ./bridge_locked_port.sh selftest. One can now
see that whereas before, the errors we got from time to time with FID 0
are now reported with FID 1.

So it is MV88E6XXX_FID_STANDALONE, after all, not just 0.

So why, then? And most importantly, when in the selftest does this
problem occur, and as a result of which traffic?

If you actually open the selftest and put some prints in the areas of
the failure, you might be tempted to think that it's the "ping_do $h1 192.0.2.2"
command that causes it.

locked_port_mab()
{
	RET=0
	check_port_mab_support || return 0

	ping_do $h1 192.0.2.2
	check_err $? "Ping did not work before locking port"

	bridge link set dev $swp1 learning on locked on

	ping_do $h1 192.0.2.2
	check_fail $? "Ping worked on a locked port without an FDB entry"

	bridge fdb get `mac_get $h1` br br0 vlan 1 &> /dev/null
	check_fail $? "FDB entry created before enabling MAB"

	bridge link set dev $swp1 learning on locked on mab on

	set -x

	ping_do $h1 192.0.2.2
	check_fail $? "Ping worked on MAB enabled port without an FDB entry"

	set +x
	bash

	bridge fdb get `mac_get $h1` br br0 vlan 1 | grep "dev $swp1" | grep -q "locked"
	check_err $? "Locked FDB entry not created"

	bridge fdb replace `mac_get $h1` dev $swp1 master static

	ping_do $h1 192.0.2.2
	check_err $? "Ping did not work after replacing FDB entry"

	bridge fdb get `mac_get $h1` br br0 vlan 1 | grep "dev $swp1" | grep -q "locked"
	check_fail $? "FDB entry marked as locked after replacement"

	bridge fdb del `mac_get $h1` dev $swp1 master
	bridge link set dev $swp1 learning off locked off mab off

	log_test "Locked port MAB"
}

"Interesting", you might say. So stop the selftest execution there, and
run that ping again, and again, and again.

But the packets from $h1 consistently get classified to the correct FID
(the FID of the bridge port's VLAN-aware PVID).

But from time to time, those ATU errors with FID_STANDALONE keep popping up.
Strangely, it doesn't seem to be related to the ping command, at all, in
that the errors appear even while there's no pinging going on.

And then you realize, but hey, there's also a VLAN interface in the
network, created by "vlan_create $h1 100 v$h1 198.51.100.1/24".
And VID 100, at the time of the locked_port_mab() selftest, is not
present in the bridge VLAN database of port $h2.

So instead of
	ping_do $h1 192.0.2.2

why don't we try to do

	ping_do $h1.100 198.51.100.2

and actually ping over that VLAN interface?

And surprise surprise, now every packet with VID 100 gets classified to
FID_STANDALONE, and the problem is 100% reproducible.

The reverse is also true. You delete the "vlan_create" commands and you
skip the selftests that use the $h1.100 interface, and the problem goes
away.

Then, the next step is opening the documentation. If you look at Figure 23
"Relationship between VTU, STU and ATU", it will say that "the port's
Default FID is used if 802.1Q is disabled on the port or if the VID
assigned to the frame points to an empty VTU entry".

VID 100 indeed points to an empty VTU entry.

The port Default FID is set with this call:

	/* Port based VLAN map: give each port the same default address
	 * database, and allow bidirectional communication between the
	 * CPU and DSA port(s), and the other ports.
	 */
	err = mv88e6xxx_port_set_fid(chip, port, MV88E6XXX_FID_STANDALONE);
	if (err)
		return err;

So it appears that frames which get a VTU miss will still also cause an
ATU miss, and that's what you're seeing.

The solution would be to acknowledge this fact, and not print any error
message from the ATU IRQ handler for unknown FID/VID, which would just
alarm the user.

What I wanted to say with this is that it doesn't take a mad scientist
to figure this stuff out, just somebody who is motivated not to throw
half assed stuff over the fence to the mainline kernel, and just call it
a day when his project is over. I don't even interact with Marvell
hardware on a day to day basis, what I know is just information gathered
during patch review, and I could still figure out what's going on.

There's actually a deeper problem which concerns me more. I'm extremely
fed up with seeing this patch set progress so slowly, to the point where
I've considered a few times to just say fsck it, it's good enough, it's
not going to get better in your hands, let it be merged, and I'll take a
second look when I'll have some time to spare and I'll clean up what I
can. Now with Ido's help for the software bridge and MAB offload part,
the patch set is really so small and so close to getting accepted, that
I don't see what's holding you up, really. The review comments are
absolutely actionable. My dilemma is that I don't think it's okay that
there exists this "merge patch set through reviewer exhaustion" loophole.
But on the other hand, if as a reviewer I don't want that to happen,
I have to waste my time with people who simply don't want to use their
critical thinking, test on actual hardware what they've done, find
problems that they didn't want to tackle. This is also the reason why I
sent the tracepoints patch set, which I really wanted *you* to do, not
later than the MAB/locked port support itself. I find the current state
of your patch set fairly unusable from the perspective of a user who
uses a serial console. But I can't waste an unlimited amount of time,
I have other stuff to do, too. I hope we can find a compromise where you
can be more responsive to what you're being told during review.

Thanks for listening.

^ permalink raw reply related	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-12-07 20:29       ` Vladimir Oltean
@ 2022-12-08 12:28         ` netdev
  2022-12-08 13:35           ` Vladimir Oltean
  0 siblings, 1 reply; 63+ messages in thread
From: netdev @ 2022-12-08 12:28 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Ido Schimmel, davem, kuba, netdev, Andrew Lunn, Florian Fainelli,
	Eric Dumazet, Paolo Abeni, open list

On 2022-12-07 21:29, Vladimir Oltean wrote:
> On Tue, Dec 06, 2022 at 05:36:42PM +0100, netdev@kapio-technology.com 
> wrote:
>> > I was under the impression that we agreed that the locking change will
>> > be split to a separate patch.
>> 
>> Sorry, I guess that because of the quite long time that has passed as 
>> I
>> needed to get this FID=0 issue sorted out, and had many other 
>> different
>> changes to attend, I forgot.
> 
> Well, at least you got the FID=0 issue sorted out... right?
> What was the cause, what is the solution?

Well I got it sorted out in the way that I have identified that it is 
the ATU op that fails some times. I don't think there is anything that 
can be done about that, other than what I do and let the interrupt 
routing return an error.

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-12-06 16:36     ` netdev
@ 2022-12-07 20:29       ` Vladimir Oltean
  2022-12-08 12:28         ` netdev
  0 siblings, 1 reply; 63+ messages in thread
From: Vladimir Oltean @ 2022-12-07 20:29 UTC (permalink / raw)
  To: netdev
  Cc: Ido Schimmel, davem, kuba, netdev, Andrew Lunn, Florian Fainelli,
	Eric Dumazet, Paolo Abeni, open list

On Tue, Dec 06, 2022 at 05:36:42PM +0100, netdev@kapio-technology.com wrote:
> > I was under the impression that we agreed that the locking change will
> > be split to a separate patch.
> 
> Sorry, I guess that because of the quite long time that has passed as I
> needed to get this FID=0 issue sorted out, and had many other different
> changes to attend, I forgot.

Well, at least you got the FID=0 issue sorted out... right?
What was the cause, what is the solution?

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-12-06 12:53   ` Ido Schimmel
@ 2022-12-06 16:36     ` netdev
  2022-12-07 20:29       ` Vladimir Oltean
  0 siblings, 1 reply; 63+ messages in thread
From: netdev @ 2022-12-06 16:36 UTC (permalink / raw)
  To: Ido Schimmel
  Cc: davem, kuba, netdev, Andrew Lunn, Florian Fainelli,
	Vladimir Oltean, Eric Dumazet, Paolo Abeni, open list

On 2022-12-06 13:53, Ido Schimmel wrote:
> On Mon, Dec 05, 2022 at 07:59:08PM +0100, Hans J. Schultz wrote:
>> This implementation for the Marvell mv88e6xxx chip series, is based on
>> handling ATU miss violations occurring when packets ingress on a port
>> that is locked with learning on. This will trigger a
>> SWITCHDEV_FDB_ADD_TO_BRIDGE event, which will result in the bridge 
>> module
>> adding a locked FDB entry. This bridge FDB entry will not age out as
>> it has the extern_learn flag set.
>> 
>> Userspace daemons can listen to these events and either accept or deny
>> access for the host, by either replacing the locked FDB entry with a
>> simple entry or leave the locked entry.
>> 
>> If the host MAC address is already present on another port, a ATU
>> member violation will occur, but to no real effect.
> 
> And the packet will be dropped in hardware, right?

Every packet that enters a locked port and does not have a matching ATU 
entry on the port will be dropped (in HW) afaik.

>> ---
> 
> The changelog from previous versions is missing.
> 

I am afraid because I made a mistake with the version string last, this 
should be regarded as a first. Therefore no changelog.

>>  	err = mv88e6xxx_g1_atu_mac_read(chip, &entry);
>>  	if (err)
>> -		goto out;
>> +		goto out_unlock;
>> +
>> +	mv88e6xxx_reg_unlock(chip);
> 
> I was under the impression that we agreed that the locking change will
> be split to a separate patch.
> 

Sorry, I guess that because of the quite long time that has passed as I 
needed to get this FID=0 issue sorted out, and had many other different 
changes to attend, I forgot. I see an updated version is needed anyhow, 
so I will do it there.

>> 
>>  	spid = entry.state;

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-12-05 18:59 ` [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation Hans J. Schultz
@ 2022-12-06 12:53   ` Ido Schimmel
  2022-12-06 16:36     ` netdev
  0 siblings, 1 reply; 63+ messages in thread
From: Ido Schimmel @ 2022-12-06 12:53 UTC (permalink / raw)
  To: Hans J. Schultz
  Cc: davem, kuba, netdev, Andrew Lunn, Florian Fainelli,
	Vladimir Oltean, Eric Dumazet, Paolo Abeni, open list

On Mon, Dec 05, 2022 at 07:59:08PM +0100, Hans J. Schultz wrote:
> This implementation for the Marvell mv88e6xxx chip series, is based on
> handling ATU miss violations occurring when packets ingress on a port
> that is locked with learning on. This will trigger a
> SWITCHDEV_FDB_ADD_TO_BRIDGE event, which will result in the bridge module
> adding a locked FDB entry. This bridge FDB entry will not age out as
> it has the extern_learn flag set.
> 
> Userspace daemons can listen to these events and either accept or deny
> access for the host, by either replacing the locked FDB entry with a
> simple entry or leave the locked entry.
> 
> If the host MAC address is already present on another port, a ATU
> member violation will occur, but to no real effect.

And the packet will be dropped in hardware, right?

> Statistics on these violations can be shown with the command and
> example output of interest:
> 
> ethtool -S ethX
> NIC statistics:
> ...
>      atu_member_violation: 5
>      atu_miss_violation: 23
> ...
> 
> Where ethX is the interface of the MAB enabled port.
> 
> An anomaly has been observed, where the ATU op to read the FID reports
> FID=0 even though it is not a valid read. An -EINVAL error will be logged
> in this case. This was seen on a mv88e6097.
> 
> Signed-off-by: Hans J. Schultz <netdev@kapio-technology.com>
> ---

The changelog from previous versions is missing.

>  drivers/net/dsa/mv88e6xxx/Makefile      |  1 +
>  drivers/net/dsa/mv88e6xxx/chip.c        | 18 ++++--
>  drivers/net/dsa/mv88e6xxx/chip.h        | 15 +++++
>  drivers/net/dsa/mv88e6xxx/global1_atu.c | 29 ++++++---
>  drivers/net/dsa/mv88e6xxx/switchdev.c   | 83 +++++++++++++++++++++++++
>  drivers/net/dsa/mv88e6xxx/switchdev.h   | 19 ++++++
>  6 files changed, 152 insertions(+), 13 deletions(-)
>  create mode 100644 drivers/net/dsa/mv88e6xxx/switchdev.c
>  create mode 100644 drivers/net/dsa/mv88e6xxx/switchdev.h
> 
> diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile
> index c8eca2b6f959..be903a983780 100644
> --- a/drivers/net/dsa/mv88e6xxx/Makefile
> +++ b/drivers/net/dsa/mv88e6xxx/Makefile
> @@ -15,3 +15,4 @@ mv88e6xxx-objs += port_hidden.o
>  mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += ptp.o
>  mv88e6xxx-objs += serdes.o
>  mv88e6xxx-objs += smi.o
> +mv88e6xxx-objs += switchdev.o
> diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
> index 66d7eae24ce0..732d7a2e2a07 100644
> --- a/drivers/net/dsa/mv88e6xxx/chip.c
> +++ b/drivers/net/dsa/mv88e6xxx/chip.c
> @@ -1726,11 +1726,11 @@ static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
>  	return err;
>  }
>  
> -static int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
> -			      int (*cb)(struct mv88e6xxx_chip *chip,
> -					const struct mv88e6xxx_vtu_entry *entry,
> -					void *priv),
> -			      void *priv)
> +int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
> +		       int (*cb)(struct mv88e6xxx_chip *chip,
> +				 const struct mv88e6xxx_vtu_entry *entry,
> +				 void *priv),
> +		       void *priv)
>  {
>  	struct mv88e6xxx_vtu_entry entry = {
>  		.vid = mv88e6xxx_max_vid(chip),
> @@ -6524,7 +6524,7 @@ static int mv88e6xxx_port_pre_bridge_flags(struct dsa_switch *ds, int port,
>  	const struct mv88e6xxx_ops *ops;
>  
>  	if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
> -			   BR_BCAST_FLOOD | BR_PORT_LOCKED))
> +			   BR_BCAST_FLOOD | BR_PORT_LOCKED | BR_PORT_MAB))
>  		return -EINVAL;
>  
>  	ops = chip->info->ops;
> @@ -6582,6 +6582,12 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
>  			goto out;
>  	}
>  
> +	if (flags.mask & BR_PORT_MAB) {
> +		bool mab = !!(flags.val & BR_PORT_MAB);
> +
> +		mv88e6xxx_port_set_mab(chip, port, mab);
> +	}
> +
>  	if (flags.mask & BR_PORT_LOCKED) {
>  		bool locked = !!(flags.val & BR_PORT_LOCKED);
>  
> diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
> index e693154cf803..f635a5bb47ce 100644
> --- a/drivers/net/dsa/mv88e6xxx/chip.h
> +++ b/drivers/net/dsa/mv88e6xxx/chip.h
> @@ -280,6 +280,9 @@ struct mv88e6xxx_port {
>  	unsigned int serdes_irq;
>  	char serdes_irq_name[64];
>  	struct devlink_region *region;
> +
> +	/* MacAuth Bypass control flag */
> +	bool mab;
>  };
>  
>  enum mv88e6xxx_region_id {
> @@ -784,6 +787,12 @@ static inline bool mv88e6xxx_is_invalid_port(struct mv88e6xxx_chip *chip, int po
>  	return (chip->info->invalid_port_mask & BIT(port)) != 0;
>  }
>  
> +static inline void mv88e6xxx_port_set_mab(struct mv88e6xxx_chip *chip,
> +					  int port, bool mab)
> +{
> +	chip->ports[port].mab = mab;
> +}
> +
>  int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val);
>  int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val);
>  int mv88e6xxx_wait_mask(struct mv88e6xxx_chip *chip, int addr, int reg,
> @@ -802,6 +811,12 @@ static inline void mv88e6xxx_reg_unlock(struct mv88e6xxx_chip *chip)
>  	mutex_unlock(&chip->reg_lock);
>  }
>  
> +int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
> +		       int (*cb)(struct mv88e6xxx_chip *chip,
> +				 const struct mv88e6xxx_vtu_entry *entry,
> +				 void *priv),
> +		       void *priv);
> +
>  int mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *bitmap);
>  
>  #endif /* _MV88E6XXX_CHIP_H */
> diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c
> index 8a874b6fc8e1..bb004df517b2 100644
> --- a/drivers/net/dsa/mv88e6xxx/global1_atu.c
> +++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c
> @@ -12,6 +12,7 @@
>  
>  #include "chip.h"
>  #include "global1.h"
> +#include "switchdev.h"
>  
>  /* Offset 0x01: ATU FID Register */
>  
> @@ -408,23 +409,25 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
>  
>  	err = mv88e6xxx_g1_read_atu_violation(chip);
>  	if (err)
> -		goto out;
> +		goto out_unlock;
>  
>  	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &val);
>  	if (err)
> -		goto out;
> +		goto out_unlock;
>  
>  	err = mv88e6xxx_g1_atu_fid_read(chip, &fid);
>  	if (err)
> -		goto out;
> +		goto out_unlock;
>  
>  	err = mv88e6xxx_g1_atu_data_read(chip, &entry);
>  	if (err)
> -		goto out;
> +		goto out_unlock;
>  
>  	err = mv88e6xxx_g1_atu_mac_read(chip, &entry);
>  	if (err)
> -		goto out;
> +		goto out_unlock;
> +
> +	mv88e6xxx_reg_unlock(chip);

I was under the impression that we agreed that the locking change will
be split to a separate patch.

>  
>  	spid = entry.state;

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation
  2022-12-05 18:59 [PATCH net-next 0/3] mv88e6xxx: Add MAB offload support Hans J. Schultz
@ 2022-12-05 18:59 ` Hans J. Schultz
  2022-12-06 12:53   ` Ido Schimmel
  0 siblings, 1 reply; 63+ messages in thread
From: Hans J. Schultz @ 2022-12-05 18:59 UTC (permalink / raw)
  To: davem, kuba
  Cc: netdev, Hans J. Schultz, Andrew Lunn, Florian Fainelli,
	Vladimir Oltean, Eric Dumazet, Paolo Abeni, open list

This implementation for the Marvell mv88e6xxx chip series, is based on
handling ATU miss violations occurring when packets ingress on a port
that is locked with learning on. This will trigger a
SWITCHDEV_FDB_ADD_TO_BRIDGE event, which will result in the bridge module
adding a locked FDB entry. This bridge FDB entry will not age out as
it has the extern_learn flag set.

Userspace daemons can listen to these events and either accept or deny
access for the host, by either replacing the locked FDB entry with a
simple entry or leave the locked entry.

If the host MAC address is already present on another port, a ATU
member violation will occur, but to no real effect. Statistics on these
violations can be shown with the command and example output of interest:

ethtool -S ethX
NIC statistics:
...
     atu_member_violation: 5
     atu_miss_violation: 23
...

Where ethX is the interface of the MAB enabled port.

An anomaly has been observed, where the ATU op to read the FID reports
FID=0 even though it is not a valid read. An -EINVAL error will be logged
in this case. This was seen on a mv88e6097.

Signed-off-by: Hans J. Schultz <netdev@kapio-technology.com>
---
 drivers/net/dsa/mv88e6xxx/Makefile      |  1 +
 drivers/net/dsa/mv88e6xxx/chip.c        | 18 ++++--
 drivers/net/dsa/mv88e6xxx/chip.h        | 15 +++++
 drivers/net/dsa/mv88e6xxx/global1_atu.c | 29 ++++++---
 drivers/net/dsa/mv88e6xxx/switchdev.c   | 83 +++++++++++++++++++++++++
 drivers/net/dsa/mv88e6xxx/switchdev.h   | 19 ++++++
 6 files changed, 152 insertions(+), 13 deletions(-)
 create mode 100644 drivers/net/dsa/mv88e6xxx/switchdev.c
 create mode 100644 drivers/net/dsa/mv88e6xxx/switchdev.h

diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile
index c8eca2b6f959..be903a983780 100644
--- a/drivers/net/dsa/mv88e6xxx/Makefile
+++ b/drivers/net/dsa/mv88e6xxx/Makefile
@@ -15,3 +15,4 @@ mv88e6xxx-objs += port_hidden.o
 mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += ptp.o
 mv88e6xxx-objs += serdes.o
 mv88e6xxx-objs += smi.o
+mv88e6xxx-objs += switchdev.o
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 66d7eae24ce0..732d7a2e2a07 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1726,11 +1726,11 @@ static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
 	return err;
 }
 
-static int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
-			      int (*cb)(struct mv88e6xxx_chip *chip,
-					const struct mv88e6xxx_vtu_entry *entry,
-					void *priv),
-			      void *priv)
+int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
+		       int (*cb)(struct mv88e6xxx_chip *chip,
+				 const struct mv88e6xxx_vtu_entry *entry,
+				 void *priv),
+		       void *priv)
 {
 	struct mv88e6xxx_vtu_entry entry = {
 		.vid = mv88e6xxx_max_vid(chip),
@@ -6524,7 +6524,7 @@ static int mv88e6xxx_port_pre_bridge_flags(struct dsa_switch *ds, int port,
 	const struct mv88e6xxx_ops *ops;
 
 	if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
-			   BR_BCAST_FLOOD | BR_PORT_LOCKED))
+			   BR_BCAST_FLOOD | BR_PORT_LOCKED | BR_PORT_MAB))
 		return -EINVAL;
 
 	ops = chip->info->ops;
@@ -6582,6 +6582,12 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
 			goto out;
 	}
 
+	if (flags.mask & BR_PORT_MAB) {
+		bool mab = !!(flags.val & BR_PORT_MAB);
+
+		mv88e6xxx_port_set_mab(chip, port, mab);
+	}
+
 	if (flags.mask & BR_PORT_LOCKED) {
 		bool locked = !!(flags.val & BR_PORT_LOCKED);
 
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index e693154cf803..f635a5bb47ce 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -280,6 +280,9 @@ struct mv88e6xxx_port {
 	unsigned int serdes_irq;
 	char serdes_irq_name[64];
 	struct devlink_region *region;
+
+	/* MacAuth Bypass control flag */
+	bool mab;
 };
 
 enum mv88e6xxx_region_id {
@@ -784,6 +787,12 @@ static inline bool mv88e6xxx_is_invalid_port(struct mv88e6xxx_chip *chip, int po
 	return (chip->info->invalid_port_mask & BIT(port)) != 0;
 }
 
+static inline void mv88e6xxx_port_set_mab(struct mv88e6xxx_chip *chip,
+					  int port, bool mab)
+{
+	chip->ports[port].mab = mab;
+}
+
 int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val);
 int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val);
 int mv88e6xxx_wait_mask(struct mv88e6xxx_chip *chip, int addr, int reg,
@@ -802,6 +811,12 @@ static inline void mv88e6xxx_reg_unlock(struct mv88e6xxx_chip *chip)
 	mutex_unlock(&chip->reg_lock);
 }
 
+int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
+		       int (*cb)(struct mv88e6xxx_chip *chip,
+				 const struct mv88e6xxx_vtu_entry *entry,
+				 void *priv),
+		       void *priv);
+
 int mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *bitmap);
 
 #endif /* _MV88E6XXX_CHIP_H */
diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c
index 8a874b6fc8e1..bb004df517b2 100644
--- a/drivers/net/dsa/mv88e6xxx/global1_atu.c
+++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c
@@ -12,6 +12,7 @@
 
 #include "chip.h"
 #include "global1.h"
+#include "switchdev.h"
 
 /* Offset 0x01: ATU FID Register */
 
@@ -408,23 +409,25 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
 
 	err = mv88e6xxx_g1_read_atu_violation(chip);
 	if (err)
-		goto out;
+		goto out_unlock;
 
 	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &val);
 	if (err)
-		goto out;
+		goto out_unlock;
 
 	err = mv88e6xxx_g1_atu_fid_read(chip, &fid);
 	if (err)
-		goto out;
+		goto out_unlock;
 
 	err = mv88e6xxx_g1_atu_data_read(chip, &entry);
 	if (err)
-		goto out;
+		goto out_unlock;
 
 	err = mv88e6xxx_g1_atu_mac_read(chip, &entry);
 	if (err)
-		goto out;
+		goto out_unlock;
+
+	mv88e6xxx_reg_unlock(chip);
 
 	spid = entry.state;
 
@@ -446,6 +449,18 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
 				    "ATU miss violation for %pM portvec %x spid %d\n",
 				    entry.mac, entry.portvec, spid);
 		chip->ports[spid].atu_miss_violation++;
+
+		if (!fid) {
+			err = -EINVAL;
+			goto out;
+		}
+
+		if (chip->ports[spid].mab) {
+			err = mv88e6xxx_handle_miss_violation(chip, spid,
+							      &entry, fid);
+			if (err)
+				goto out;
+		}
 	}
 
 	if (val & MV88E6XXX_G1_ATU_OP_FULL_VIOLATION) {
@@ -454,13 +469,13 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
 				    entry.mac, entry.portvec, spid);
 		chip->ports[spid].atu_full_violation++;
 	}
-	mv88e6xxx_reg_unlock(chip);
 
 	return IRQ_HANDLED;
 
-out:
+out_unlock:
 	mv88e6xxx_reg_unlock(chip);
 
+out:
 	dev_err(chip->dev, "ATU problem: error %d while handling interrupt\n",
 		err);
 	return IRQ_HANDLED;
diff --git a/drivers/net/dsa/mv88e6xxx/switchdev.c b/drivers/net/dsa/mv88e6xxx/switchdev.c
new file mode 100644
index 000000000000..4c346a884fb2
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/switchdev.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * switchdev.c
+ *
+ *	Authors:
+ *	Hans J. Schultz		<netdev@kapio-technology.com>
+ *
+ */
+
+#include <net/switchdev.h>
+#include "chip.h"
+#include "global1.h"
+#include "switchdev.h"
+
+struct mv88e6xxx_fid_search_ctx {
+	u16 fid_search;
+	u16 vid_found;
+};
+
+static int __mv88e6xxx_find_vid(struct mv88e6xxx_chip *chip,
+				const struct mv88e6xxx_vtu_entry *entry,
+				void *priv)
+{
+	struct mv88e6xxx_fid_search_ctx *ctx = priv;
+
+	if (ctx->fid_search == entry->fid) {
+		ctx->vid_found = entry->vid;
+		return 1;
+	}
+
+	return 0;
+}
+
+static int mv88e6xxx_find_vid(struct mv88e6xxx_chip *chip, u16 fid, u16 *vid)
+{
+	struct mv88e6xxx_fid_search_ctx ctx;
+	int err;
+
+	ctx.fid_search = fid;
+	mv88e6xxx_reg_lock(chip);
+	err = mv88e6xxx_vtu_walk(chip, __mv88e6xxx_find_vid, &ctx);
+	mv88e6xxx_reg_unlock(chip);
+	if (err < 0)
+		return err;
+	if (err == 1)
+		*vid = ctx.vid_found;
+	else
+		return -ENOENT;
+
+	return 0;
+}
+
+int mv88e6xxx_handle_miss_violation(struct mv88e6xxx_chip *chip, int port,
+				    struct mv88e6xxx_atu_entry *entry, u16 fid)
+{
+	struct switchdev_notifier_fdb_info info = {
+		.addr = entry->mac,
+		.locked = true,
+	};
+	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;
+	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_ADD_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
new file mode 100644
index 000000000000..62214f9d62b0
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/switchdev.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * switchdev.h
+ *
+ *	Authors:
+ *	Hans J. Schultz		<netdev@kapio-technology.com>
+ *
+ */
+
+#ifndef _MV88E6XXX_SWITCHDEV_H_
+#define _MV88E6XXX_SWITCHDEV_H_
+
+#include "chip.h"
+
+int mv88e6xxx_handle_miss_violation(struct mv88e6xxx_chip *chip, int port,
+				    struct mv88e6xxx_atu_entry *entry,
+				    u16 fid);
+
+#endif /* _MV88E6XXX_SWITCHDEV_H_ */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 63+ messages in thread

end of thread, other threads:[~2022-12-08 16:09 UTC | newest]

Thread overview: 63+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-10 14:23 [PATCH net-next 0/3] Extend locked port feature with FDB locked flag (MAC-Auth/MAB) Hans Schultz
2022-03-10 14:23 ` [PATCH net-next 1/3] net: bridge: add fdb flag to extent locked port feature Hans Schultz
2022-03-10 14:42   ` Nikolay Aleksandrov
2022-03-10 15:38     ` Hans Schultz
2022-03-10 15:57       ` Nikolay Aleksandrov
2022-03-10 16:11         ` Hans Schultz
2022-03-10 16:14           ` Nikolay Aleksandrov
2022-03-10 16:33             ` Hans Schultz
2022-03-14 15:30   ` Ido Schimmel
2022-03-15  8:48     ` Hans Schultz
2022-03-15 11:00       ` Ido Schimmel
2022-03-10 14:23 ` [PATCH net-next 2/3] net: switchdev: add support for offloading of fdb locked flag Hans Schultz
2022-03-10 14:23 ` [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation Hans Schultz
2022-03-10 14:28   ` Vladimir Oltean
2022-03-10 15:00     ` Hans Schultz
2022-03-10 15:07       ` Vladimir Oltean
2022-03-10 15:51         ` Hans Schultz
2022-03-10 16:05           ` Vladimir Oltean
2022-03-10 16:40             ` Hans Schultz
2022-03-10 15:57     ` Hans Schultz
2022-03-14 10:46     ` Hans Schultz
2022-03-16 23:34       ` Vladimir Oltean
2022-03-17  8:52         ` Hans Schultz
2022-03-17 14:19           ` Andrew Lunn
2022-03-17 15:36             ` Vladimir Oltean
2022-03-17 16:07               ` Hans Schultz
2022-03-17 16:18                 ` Vladimir Oltean
2022-03-17 16:58                   ` Hans Schultz
2022-03-17 17:20                     ` Vladimir Oltean
2022-03-18 10:04                       ` Hans Schultz
2022-03-18 12:14                         ` Vladimir Oltean
2022-03-18 13:10                           ` Hans Schultz
2022-03-18 13:19                             ` Vladimir Oltean
2022-03-22 11:01                               ` Hans Schultz
2022-03-22 11:08                                 ` Vladimir Oltean
2022-03-22 13:21                                   ` Hans Schultz
2022-03-22 14:47                                     ` Hans Schultz
2022-03-23 10:13                                   ` Hans Schultz
2022-03-23 10:16                                     ` Vladimir Oltean
2022-03-23 10:46                                       ` Hans Schultz
2022-03-23 10:57                                       ` Hans Schultz
2022-03-23 11:21                                         ` Vladimir Oltean
2022-03-23 11:43                                           ` Hans Schultz
2022-03-23 11:54                                             ` Vladimir Oltean
2022-03-21 14:51             ` Hans Schultz
2022-03-10 14:54   ` Andrew Lunn
2022-03-11  7:59     ` Hans Schultz
2022-03-14 15:50 ` [PATCH net-next 0/3] Extend locked port feature with FDB locked flag (MAC-Auth/MAB) Ido Schimmel
2022-03-15  8:59   ` Hans Schultz
2022-03-15 11:11     ` Ido Schimmel
2022-03-17  0:18 ` Florian Fainelli
2022-03-17  8:29   ` Hans Schultz
2022-03-17 18:42     ` Vladimir Oltean
2022-12-05 18:59 [PATCH net-next 0/3] mv88e6xxx: Add MAB offload support Hans J. Schultz
2022-12-05 18:59 ` [PATCH net-next 3/3] net: dsa: mv88e6xxx: mac-auth/MAB implementation Hans J. Schultz
2022-12-06 12:53   ` Ido Schimmel
2022-12-06 16:36     ` netdev
2022-12-07 20:29       ` Vladimir Oltean
2022-12-08 12:28         ` netdev
2022-12-08 13:35           ` Vladimir Oltean
2022-12-08 14:41             ` netdev
2022-12-08 14:43               ` Vladimir Oltean
2022-12-08 16:03             ` netdev
2022-12-08 16:09               ` Vladimir Oltean

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).