2022-10-09 18:05:21

by Hans Schultz

[permalink] [raw]
Subject: [PATCH v7 net-next 0/9] Extend locked port feature with FDB locked flag (MAC-Auth/MAB)

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.

Log:
v3: Added timers and lists in the driver (mv88e6xxx)
to keep track of and remove locked entries.

v4: Leave out enforcing a limit to the number of
locked entries in the bridge.
Removed the timers in the driver and use the
worker only. Add locked FDB flag to all drivers
using port_fdb_add() from the dsa api and let
all drivers ignore entries with this flag set.
Change how to get the ageing timeout of locked
entries. See global1_atu.c and switchdev.c.
Use struct mv88e6xxx_port for locked entries
variables instead of struct dsa_port.

v5: Added 'mab' flag to enable MAB/MacAuth feature,
in a similar way to the locked feature flag.

In these implementations for the mv88e6xxx, the
switchport must be configured with learning on.

To tell userspace about the behavior of the
locked entries in the driver, a 'blackhole'
FDB flag has been added, which locked FDB
entries coming from the driver gets. Also the
'sticky' flag comes with those locked entries,
as the drivers locked entries cannot roam.

Fixed issues with taking mutex locks, and added
a function to read the fid, that supports all
versions of the chipset family.

v6: Added blackhole FDB flag instead of using sticky
flag, as the blackhole flag corresponds to the
behaviour of the zero-DPV locked entries in the
driver.

Userspace can add blackhole FDB entries with:
# bridge fdb add MAC dev br0 blackhole

Added FDB flags towards driver in DSA layer as u16.

v7: Remove locked port and mab flags from DSA flags
inherit list as it messes with the learning
setting and those flags are not naturally meant
for enheriting, but should be set explicitly.

Fix blackhole implementation, selftests a.o small
fixes.

Hans J. Schultz (9):
net: bridge: add locked entry fdb flag to extend locked port feature
net: bridge: add blackhole fdb entry flag
net: switchdev: add support for offloading of the FDB locked flag
net: switchdev: support offloading of the FDB blackhole flag
drivers: net: dsa: add fdb entry flags to drivers
net: dsa: mv88e6xxx: allow reading FID when handling ATU violations
net: dsa: mv88e6xxx: mac-auth/MAB implementation
net: dsa: mv88e6xxx: add blackhole ATU entries
selftests: forwarding: add test of MAC-Auth Bypass to locked port
tests

drivers/net/dsa/b53/b53_common.c | 12 +-
drivers/net/dsa/b53/b53_priv.h | 4 +-
drivers/net/dsa/hirschmann/hellcreek.c | 12 +-
drivers/net/dsa/lan9303-core.c | 12 +-
drivers/net/dsa/lantiq_gswip.c | 12 +-
drivers/net/dsa/microchip/ksz9477.c | 8 +-
drivers/net/dsa/microchip/ksz9477.h | 8 +-
drivers/net/dsa/microchip/ksz_common.c | 14 +-
drivers/net/dsa/mt7530.c | 12 +-
drivers/net/dsa/mv88e6xxx/Makefile | 1 +
drivers/net/dsa/mv88e6xxx/chip.c | 140 ++++++++-
drivers/net/dsa/mv88e6xxx/chip.h | 19 ++
drivers/net/dsa/mv88e6xxx/global1.h | 1 +
drivers/net/dsa/mv88e6xxx/global1_atu.c | 72 ++++-
drivers/net/dsa/mv88e6xxx/port.c | 15 +-
drivers/net/dsa/mv88e6xxx/port.h | 6 +
drivers/net/dsa/mv88e6xxx/switchdev.c | 284 ++++++++++++++++++
drivers/net/dsa/mv88e6xxx/switchdev.h | 37 +++
drivers/net/dsa/ocelot/felix.c | 12 +-
drivers/net/dsa/qca/qca8k-common.c | 12 +-
drivers/net/dsa/qca/qca8k.h | 4 +-
drivers/net/dsa/sja1105/sja1105_main.c | 18 +-
include/linux/if_bridge.h | 1 +
include/net/dsa.h | 7 +-
include/net/switchdev.h | 2 +
include/uapi/linux/if_link.h | 1 +
include/uapi/linux/neighbour.h | 11 +-
net/bridge/br.c | 5 +-
net/bridge/br_fdb.c | 77 ++++-
net/bridge/br_input.c | 20 +-
net/bridge/br_netlink.c | 12 +-
net/bridge/br_private.h | 5 +-
net/bridge/br_switchdev.c | 4 +-
net/core/rtnetlink.c | 9 +
net/dsa/dsa_priv.h | 10 +-
net/dsa/port.c | 32 +-
net/dsa/slave.c | 16 +-
net/dsa/switch.c | 24 +-
.../selftests/drivers/net/dsa/Makefile | 1 +
.../testing/selftests/net/forwarding/Makefile | 1 +
.../net/forwarding/bridge_blackhole_fdb.sh | 134 +++++++++
.../net/forwarding/bridge_locked_port.sh | 101 ++++++-
tools/testing/selftests/net/forwarding/lib.sh | 17 ++
43 files changed, 1086 insertions(+), 119 deletions(-)
create mode 100644 drivers/net/dsa/mv88e6xxx/switchdev.c
create mode 100644 drivers/net/dsa/mv88e6xxx/switchdev.h
create mode 100755 tools/testing/selftests/net/forwarding/bridge_blackhole_fdb.sh

--
2.34.1


2022-10-09 18:11:57

by Hans Schultz

[permalink] [raw]
Subject: [PATCH v7 net-next 3/9] net: switchdev: add support for offloading of the FDB locked flag

Add support for offloading of the MAB/MacAuth feature flag and the FDB
locked flag which is used by the Mac-Auth/MAB feature.

Signed-off-by: Hans J. Schultz <[email protected]>
---
include/net/dsa.h | 2 ++
include/net/switchdev.h | 1 +
net/bridge/br.c | 4 ++--
net/bridge/br_fdb.c | 12 ++++++++++--
net/bridge/br_private.h | 2 +-
net/bridge/br_switchdev.c | 3 ++-
net/dsa/dsa_priv.h | 6 ++++--
net/dsa/port.c | 10 ++++++----
net/dsa/slave.c | 10 ++++++++--
net/dsa/switch.c | 16 ++++++++--------
10 files changed, 44 insertions(+), 22 deletions(-)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index ee369670e20e..e4b641b20713 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -821,6 +821,8 @@ static inline bool dsa_port_tree_same(const struct dsa_port *a,
return a->ds->dst == b->ds->dst;
}

+#define DSA_FDB_FLAG_LOCKED (1 << 0)
+
typedef int dsa_fdb_dump_cb_t(const unsigned char *addr, u16 vid,
bool is_static, void *data);
struct dsa_switch_ops {
diff --git a/include/net/switchdev.h b/include/net/switchdev.h
index 7dcdc97c0bc3..ca0312b78294 100644
--- a/include/net/switchdev.h
+++ b/include/net/switchdev.h
@@ -248,6 +248,7 @@ struct switchdev_notifier_fdb_info {
u16 vid;
u8 added_by_user:1,
is_local:1,
+ locked:1,
offloaded:1;
};

diff --git a/net/bridge/br.c b/net/bridge/br.c
index 96e91d69a9a8..e0e2df2fa278 100644
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -165,8 +165,8 @@ static int br_switchdev_event(struct notifier_block *unused,
switch (event) {
case SWITCHDEV_FDB_ADD_TO_BRIDGE:
fdb_info = ptr;
- err = br_fdb_external_learn_add(br, p, fdb_info->addr,
- fdb_info->vid, false);
+ err = br_fdb_external_learn_add(br, p, fdb_info->addr, fdb_info->vid,
+ fdb_info->locked, false);
if (err) {
err = notifier_from_errno(err);
break;
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 02243640fda3..86fa60cbc26c 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -1148,7 +1148,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, false, true);
} else if ((ext_flags & NTF_EXT_BLACKHOLE) && p) {
NL_SET_ERR_MSG_MOD(extack, "Blackhole FDB entry cannot be applied on a port");
return -EINVAL;
@@ -1389,7 +1389,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,
+ const unsigned char *addr, u16 vid, bool locked,
bool swdev_notify)
{
struct net_bridge_fdb_entry *fdb;
@@ -1410,6 +1410,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_LOCKED);
+
fdb = fdb_create(br, p, addr, vid, flags);
if (!fdb) {
err = -ENOMEM;
@@ -1433,6 +1436,11 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
modified = true;
}

+ if (locked != test_bit(BR_FDB_LOCKED, &fdb->flags)) {
+ change_bit(BR_FDB_LOCKED, &fdb->flags);
+ modified = true;
+ }
+
if (swdev_notify)
set_bit(BR_FDB_ADDED_BY_USER, &fdb->flags);

diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index e7a08657c7ed..3e9f4d1fbd60 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -812,7 +812,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 locked, bool swdev_notify);
int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p,
const unsigned char *addr, u16 vid,
bool swdev_notify);
diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c
index 8f3d76c751dd..ccf1b4cffdd0 100644
--- a/net/bridge/br_switchdev.c
+++ b/net/bridge/br_switchdev.c
@@ -71,7 +71,7 @@ bool nbp_switchdev_allowed_egress(const struct net_bridge_port *p,
}

/* Flags that can be offloaded to hardware */
-#define BR_PORT_FLAGS_HW_OFFLOAD (BR_LEARNING | BR_FLOOD | \
+#define BR_PORT_FLAGS_HW_OFFLOAD (BR_LEARNING | BR_FLOOD | BR_PORT_MAB | \
BR_MCAST_FLOOD | BR_BCAST_FLOOD | BR_PORT_LOCKED | \
BR_HAIRPIN_MODE | BR_ISOLATED | BR_MULTICAST_TO_UNICAST)

@@ -136,6 +136,7 @@ static void br_switchdev_fdb_populate(struct net_bridge *br,
item->added_by_user = test_bit(BR_FDB_ADDED_BY_USER, &fdb->flags);
item->offloaded = test_bit(BR_FDB_OFFLOADED, &fdb->flags);
item->is_local = test_bit(BR_FDB_LOCAL, &fdb->flags);
+ item->locked = test_bit(BR_FDB_LOCKED, &fdb->flags);
item->info.dev = (!p || item->is_local) ? br->dev : p->dev;
item->info.ctx = ctx;
}
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 6e65c7ffd6f3..c943e8934063 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -65,6 +65,7 @@ struct dsa_notifier_fdb_info {
const struct dsa_port *dp;
const unsigned char *addr;
u16 vid;
+ u16 fdb_flags;
struct dsa_db db;
};

@@ -131,6 +132,7 @@ struct dsa_switchdev_event_work {
*/
unsigned char addr[ETH_ALEN];
u16 vid;
+ u16 fdb_flags;
bool host_addr;
};

@@ -241,9 +243,9 @@ int dsa_port_vlan_msti(struct dsa_port *dp,
const struct switchdev_vlan_msti *msti);
int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu);
int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr,
- u16 vid);
+ u16 vid, u16 fdb_flags);
int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr,
- u16 vid);
+ u16 vid, u16 fdb_flags);
int dsa_port_standalone_host_fdb_add(struct dsa_port *dp,
const unsigned char *addr, u16 vid);
int dsa_port_standalone_host_fdb_del(struct dsa_port *dp,
diff --git a/net/dsa/port.c b/net/dsa/port.c
index e4a0513816bb..eab32b7a945a 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -304,7 +304,7 @@ static int dsa_port_inherit_brport_flags(struct dsa_port *dp,
struct netlink_ext_ack *extack)
{
const unsigned long mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
- BR_BCAST_FLOOD | BR_PORT_LOCKED;
+ BR_BCAST_FLOOD;
struct net_device *brport_dev = dsa_port_to_bridge_port(dp);
int flag, err;

@@ -328,7 +328,7 @@ static void dsa_port_clear_brport_flags(struct dsa_port *dp)
{
const unsigned long val = BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;
const unsigned long mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
- BR_BCAST_FLOOD | BR_PORT_LOCKED;
+ BR_BCAST_FLOOD | BR_PORT_LOCKED | BR_PORT_MAB;
int flag, err;

for_each_set_bit(flag, &mask, 32) {
@@ -956,12 +956,13 @@ int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu)
}

int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr,
- u16 vid)
+ u16 vid, u16 fdb_flags)
{
struct dsa_notifier_fdb_info info = {
.dp = dp,
.addr = addr,
.vid = vid,
+ .fdb_flags = fdb_flags,
.db = {
.type = DSA_DB_BRIDGE,
.bridge = *dp->bridge,
@@ -979,12 +980,13 @@ int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr,
}

int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr,
- u16 vid)
+ u16 vid, u16 fdb_flags)
{
struct dsa_notifier_fdb_info info = {
.dp = dp,
.addr = addr,
.vid = vid,
+ .fdb_flags = fdb_flags,
.db = {
.type = DSA_DB_BRIDGE,
.bridge = *dp->bridge,
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 1a59918d3b30..65f0c578ef44 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -3246,6 +3246,7 @@ static void dsa_slave_switchdev_event_work(struct work_struct *work)
container_of(work, struct dsa_switchdev_event_work, work);
const unsigned char *addr = switchdev_work->addr;
struct net_device *dev = switchdev_work->dev;
+ u16 fdb_flags = switchdev_work->fdb_flags;
u16 vid = switchdev_work->vid;
struct dsa_switch *ds;
struct dsa_port *dp;
@@ -3261,7 +3262,7 @@ static void dsa_slave_switchdev_event_work(struct work_struct *work)
else if (dp->lag)
err = dsa_port_lag_fdb_add(dp, addr, vid);
else
- err = dsa_port_fdb_add(dp, addr, vid);
+ err = dsa_port_fdb_add(dp, addr, vid, fdb_flags);
if (err) {
dev_err(ds->dev,
"port %d failed to add %pM vid %d to fdb: %d\n",
@@ -3277,7 +3278,7 @@ static void dsa_slave_switchdev_event_work(struct work_struct *work)
else if (dp->lag)
err = dsa_port_lag_fdb_del(dp, addr, vid);
else
- err = dsa_port_fdb_del(dp, addr, vid);
+ err = dsa_port_fdb_del(dp, addr, vid, fdb_flags);
if (err) {
dev_err(ds->dev,
"port %d failed to delete %pM vid %d from fdb: %d\n",
@@ -3315,6 +3316,7 @@ static int dsa_slave_fdb_event(struct net_device *dev,
struct dsa_port *dp = dsa_slave_to_port(dev);
bool host_addr = fdb_info->is_local;
struct dsa_switch *ds = dp->ds;
+ u16 fdb_flags = 0;

if (ctx && ctx != dp)
return 0;
@@ -3361,6 +3363,9 @@ static int dsa_slave_fdb_event(struct net_device *dev,
orig_dev->name, fdb_info->addr, fdb_info->vid,
host_addr ? " as host address" : "");

+ if (fdb_info->locked)
+ fdb_flags |= DSA_FDB_FLAG_LOCKED;
+
INIT_WORK(&switchdev_work->work, dsa_slave_switchdev_event_work);
switchdev_work->event = event;
switchdev_work->dev = dev;
@@ -3369,6 +3374,7 @@ static int dsa_slave_fdb_event(struct net_device *dev,
ether_addr_copy(switchdev_work->addr, fdb_info->addr);
switchdev_work->vid = fdb_info->vid;
switchdev_work->host_addr = host_addr;
+ switchdev_work->fdb_flags = fdb_flags;

dsa_schedule_work(&switchdev_work->work);

diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index ce56acdba203..dd355556892e 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -234,7 +234,7 @@ static int dsa_port_do_mdb_del(struct dsa_port *dp,
}

static int dsa_port_do_fdb_add(struct dsa_port *dp, const unsigned char *addr,
- u16 vid, struct dsa_db db)
+ u16 vid, u16 fdb_flags, struct dsa_db db)
{
struct dsa_switch *ds = dp->ds;
struct dsa_mac_addr *a;
@@ -278,7 +278,7 @@ static int dsa_port_do_fdb_add(struct dsa_port *dp, const unsigned char *addr,
}

static int dsa_port_do_fdb_del(struct dsa_port *dp, const unsigned char *addr,
- u16 vid, struct dsa_db db)
+ u16 vid, u16 fdb_flags, struct dsa_db db)
{
struct dsa_switch *ds = dp->ds;
struct dsa_mac_addr *a;
@@ -404,8 +404,8 @@ static int dsa_switch_host_fdb_add(struct dsa_switch *ds,
info->vid,
info->db);
} else {
- err = dsa_port_do_fdb_add(dp, info->addr,
- info->vid, info->db);
+ err = dsa_port_do_fdb_add(dp, info->addr, info->vid,
+ info->fdb_flags, info->db);
}
if (err)
break;
@@ -432,8 +432,8 @@ static int dsa_switch_host_fdb_del(struct dsa_switch *ds,
info->vid,
info->db);
} else {
- err = dsa_port_do_fdb_del(dp, info->addr,
- info->vid, info->db);
+ err = dsa_port_do_fdb_del(dp, info->addr, info->vid,
+ info->fdb_flags, info->db);
}
if (err)
break;
@@ -452,7 +452,7 @@ static int dsa_switch_fdb_add(struct dsa_switch *ds,
if (!ds->ops->port_fdb_add)
return -EOPNOTSUPP;

- return dsa_port_do_fdb_add(dp, info->addr, info->vid, info->db);
+ return dsa_port_do_fdb_add(dp, info->addr, info->vid, info->fdb_flags, info->db);
}

static int dsa_switch_fdb_del(struct dsa_switch *ds,
@@ -464,7 +464,7 @@ static int dsa_switch_fdb_del(struct dsa_switch *ds,
if (!ds->ops->port_fdb_del)
return -EOPNOTSUPP;

- return dsa_port_do_fdb_del(dp, info->addr, info->vid, info->db);
+ return dsa_port_do_fdb_del(dp, info->addr, info->vid, info->fdb_flags, info->db);
}

static int dsa_switch_lag_fdb_add(struct dsa_switch *ds,
--
2.34.1

2022-10-09 18:12:49

by Hans Schultz

[permalink] [raw]
Subject: [PATCH v7 net-next 2/9] net: bridge: add blackhole fdb entry flag

Add a 'blackhole' fdb flag, ensuring that no forwarding from any port
to a destination MAC that has a FDB entry with this flag on will occur.
The packets will thus be dropped.

When the blackhole fdb flag is set, the 'local' flag will also be enabled
as blackhole entries are not associated with any port.

Thus the command will be alike to:
bridge fdb add MAC dev br0 local blackhole

Signed-off-by: Hans J. Schultz <[email protected]>
---
include/uapi/linux/neighbour.h | 4 ++++
net/bridge/br_fdb.c | 26 ++++++++++++++++++++------
net/bridge/br_input.c | 5 ++++-
net/bridge/br_private.h | 1 +
net/core/rtnetlink.c | 2 +-
5 files changed, 30 insertions(+), 8 deletions(-)

diff --git a/include/uapi/linux/neighbour.h b/include/uapi/linux/neighbour.h
index 4dda051b0ba8..cc7d540eb734 100644
--- a/include/uapi/linux/neighbour.h
+++ b/include/uapi/linux/neighbour.h
@@ -54,6 +54,7 @@ enum {
/* Extended flags under NDA_FLAGS_EXT: */
#define NTF_EXT_MANAGED (1 << 0)
#define NTF_EXT_LOCKED (1 << 1)
+#define NTF_EXT_BLACKHOLE (1 << 2)

/*
* Neighbor Cache Entry States.
@@ -91,6 +92,9 @@ enum {
* NTF_EXT_LOCKED flagged FDB entries are placeholder entries used with the
* locked port feature, that ensures that an entry exists while at the same
* time dropping packets on ingress with src MAC and VID matching the entry.
+ *
+ * NTF_EXT_BLACKHOLE flagged FDB entries ensure that no forwarding is allowed
+ * from any port to the destination MAC, VID pair associated with it.
*/

struct nda_cacheinfo {
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 2cf695ee61c5..02243640fda3 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -128,6 +128,8 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
ndm->ndm_flags |= NTF_STICKY;
if (test_bit(BR_FDB_LOCKED, &fdb->flags))
ext_flags |= NTF_EXT_LOCKED;
+ if (test_bit(BR_FDB_BLACKHOLE, &fdb->flags))
+ ext_flags |= NTF_EXT_BLACKHOLE;

if (nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->key.addr))
goto nla_put_failure;
@@ -1018,8 +1020,9 @@ static bool fdb_handle_notify(struct net_bridge_fdb_entry *fdb, u8 notify)
/* Update (create or replace) forwarding database entry */
static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source,
const u8 *addr, struct ndmsg *ndm, u16 flags, u16 vid,
- struct nlattr *nfea_tb[])
+ u32 ext_flags, struct nlattr *nfea_tb[])
{
+ bool blackhole = !!(ext_flags & NTF_EXT_BLACKHOLE);
bool is_sticky = !!(ndm->ndm_flags & NTF_STICKY);
bool refresh = !nfea_tb[NFEA_DONT_REFRESH];
struct net_bridge_fdb_entry *fdb;
@@ -1092,6 +1095,14 @@ static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source,
modified = true;
}

+ if (blackhole != test_bit(BR_FDB_BLACKHOLE, &fdb->flags)) {
+ change_bit(BR_FDB_BLACKHOLE, &fdb->flags);
+ modified = true;
+ }
+
+ if (blackhole)
+ set_bit(BR_FDB_LOCAL, &fdb->flags);
+
if (test_and_clear_bit(BR_FDB_LOCKED, &fdb->flags))
modified = true;

@@ -1113,7 +1124,7 @@ static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source,
static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge *br,
struct net_bridge_port *p, const unsigned char *addr,
u16 nlh_flags, u16 vid, struct nlattr *nfea_tb[],
- struct netlink_ext_ack *extack)
+ u32 ext_flags, struct netlink_ext_ack *extack)
{
int err = 0;

@@ -1138,9 +1149,12 @@ static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge *br,
return -EINVAL;
}
err = br_fdb_external_learn_add(br, p, addr, vid, true);
+ } else if ((ext_flags & NTF_EXT_BLACKHOLE) && p) {
+ NL_SET_ERR_MSG_MOD(extack, "Blackhole FDB entry cannot be applied on a port");
+ return -EINVAL;
} else {
spin_lock_bh(&br->hash_lock);
- err = fdb_add_entry(br, p, addr, ndm, nlh_flags, vid, nfea_tb);
+ err = fdb_add_entry(br, p, addr, ndm, nlh_flags, vid, ext_flags, nfea_tb);
spin_unlock_bh(&br->hash_lock);
}

@@ -1219,10 +1233,10 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],

/* VID was specified, so use it. */
err = __br_fdb_add(ndm, br, p, addr, nlh_flags, vid, nfea_tb,
- extack);
+ ext_flags, extack);
} else {
err = __br_fdb_add(ndm, br, p, addr, nlh_flags, 0, nfea_tb,
- extack);
+ ext_flags, extack);
if (err || !vg || !vg->num_vlans)
goto out;

@@ -1234,7 +1248,7 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
if (!br_vlan_should_use(v))
continue;
err = __br_fdb_add(ndm, br, p, addr, nlh_flags, v->vid,
- nfea_tb, extack);
+ nfea_tb, ext_flags, extack);
if (err)
goto out;
}
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 068fced7693c..665d1d6bdc75 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -193,8 +193,11 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
if (dst) {
unsigned long now = jiffies;

- if (test_bit(BR_FDB_LOCAL, &dst->flags))
+ if (test_bit(BR_FDB_LOCAL, &dst->flags)) {
+ if (unlikely(test_bit(BR_FDB_BLACKHOLE, &dst->flags)))
+ goto drop;
return br_pass_frame_up(skb);
+ }

if (now != dst->used)
dst->used = now;
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 4ce8b8e5ae0b..e7a08657c7ed 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -253,6 +253,7 @@ enum {
BR_FDB_NOTIFY,
BR_FDB_NOTIFY_INACTIVE,
BR_FDB_LOCKED,
+ BR_FDB_BLACKHOLE,
};

struct net_bridge_fdb_key {
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 8008ceb45605..ae641dfea5f2 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -4054,7 +4054,7 @@ int ndo_dflt_fdb_add(struct ndmsg *ndm,
if (tb[NDA_FLAGS_EXT])
ext_flags = nla_get_u32(tb[NDA_FLAGS_EXT]);

- if (ext_flags & NTF_EXT_LOCKED) {
+ if (ext_flags & (NTF_EXT_LOCKED | NTF_EXT_BLACKHOLE)) {
netdev_info(dev, "invalid flags given to default FDB implementation\n");
return err;
}
--
2.34.1

2022-10-09 18:21:34

by Hans Schultz

[permalink] [raw]
Subject: [PATCH v7 net-next 4/9] net: switchdev: support offloading of the FDB blackhole flag

Add support for offloading of the FDB blackhole flag.

Signed-off-by: Hans J. Schultz <[email protected]>
---
include/net/dsa.h | 1 +
include/net/switchdev.h | 1 +
net/bridge/br.c | 3 ++-
net/bridge/br_fdb.c | 19 ++++++++++++++++---
net/bridge/br_private.h | 3 ++-
net/bridge/br_switchdev.c | 1 +
net/dsa/dsa_priv.h | 4 ++--
net/dsa/port.c | 22 ++++++++++++----------
net/dsa/slave.c | 6 ++++--
9 files changed, 41 insertions(+), 19 deletions(-)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index e4b641b20713..d5b2aef52d93 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -822,6 +822,7 @@ static inline bool dsa_port_tree_same(const struct dsa_port *a,
}

#define DSA_FDB_FLAG_LOCKED (1 << 0)
+#define DSA_FDB_FLAG_BLACKHOLE (1 << 1)

typedef int dsa_fdb_dump_cb_t(const unsigned char *addr, u16 vid,
bool is_static, void *data);
diff --git a/include/net/switchdev.h b/include/net/switchdev.h
index ca0312b78294..39727902354e 100644
--- a/include/net/switchdev.h
+++ b/include/net/switchdev.h
@@ -249,6 +249,7 @@ struct switchdev_notifier_fdb_info {
u8 added_by_user:1,
is_local:1,
locked:1,
+ blackhole:1,
offloaded:1;
};

diff --git a/net/bridge/br.c b/net/bridge/br.c
index e0e2df2fa278..85fc529b6a9f 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,
- fdb_info->locked, false);
+ fdb_info->locked, fdb_info->is_local,
+ fdb_info->blackhole, false);
if (err) {
err = notifier_from_errno(err);
break;
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 86fa60cbc26c..d6f22e2e018a 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -1148,7 +1148,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, false, true);
+ err = br_fdb_external_learn_add(br, p, addr, vid, false, false, false, true);
} else if ((ext_flags & NTF_EXT_BLACKHOLE) && p) {
NL_SET_ERR_MSG_MOD(extack, "Blackhole FDB entry cannot be applied on a port");
return -EINVAL;
@@ -1390,7 +1390,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 locked,
- bool swdev_notify)
+ bool local, bool blackhole, bool swdev_notify)
{
struct net_bridge_fdb_entry *fdb;
bool modified = false;
@@ -1407,12 +1407,15 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
if (swdev_notify)
flags |= BIT(BR_FDB_ADDED_BY_USER);

- if (!p)
+ if (!p || local)
flags |= BIT(BR_FDB_LOCAL);

if (locked)
flags |= BIT(BR_FDB_LOCKED);

+ if (blackhole)
+ flags |= BIT(BR_FDB_BLACKHOLE);
+
fdb = fdb_create(br, p, addr, vid, flags);
if (!fdb) {
err = -ENOMEM;
@@ -1436,11 +1439,21 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
modified = true;
}

+ if (local != test_bit(BR_FDB_LOCAL, &fdb->flags)) {
+ change_bit(BR_FDB_LOCAL, &fdb->flags);
+ modified = true;
+ }
+
if (locked != test_bit(BR_FDB_LOCKED, &fdb->flags)) {
change_bit(BR_FDB_LOCKED, &fdb->flags);
modified = true;
}

+ if (blackhole != test_bit(BR_FDB_BLACKHOLE, &fdb->flags)) {
+ change_bit(BR_FDB_BLACKHOLE, &fdb->flags);
+ modified = true;
+ }
+
if (swdev_notify)
set_bit(BR_FDB_ADDED_BY_USER, &fdb->flags);

diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 3e9f4d1fbd60..4202c80e465e 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -812,7 +812,8 @@ 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 locked, bool swdev_notify);
+ bool locked, bool local, bool blackhole,
+ bool swdev_notify);
int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p,
const unsigned char *addr, u16 vid,
bool swdev_notify);
diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c
index ccf1b4cffdd0..ce7b80c782ec 100644
--- a/net/bridge/br_switchdev.c
+++ b/net/bridge/br_switchdev.c
@@ -137,6 +137,7 @@ static void br_switchdev_fdb_populate(struct net_bridge *br,
item->offloaded = test_bit(BR_FDB_OFFLOADED, &fdb->flags);
item->is_local = test_bit(BR_FDB_LOCAL, &fdb->flags);
item->locked = test_bit(BR_FDB_LOCKED, &fdb->flags);
+ item->blackhole = test_bit(BR_FDB_BLACKHOLE, &fdb->flags);
item->info.dev = (!p || item->is_local) ? br->dev : p->dev;
item->info.ctx = ctx;
}
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index c943e8934063..611833f162d1 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -251,9 +251,9 @@ int dsa_port_standalone_host_fdb_add(struct dsa_port *dp,
int dsa_port_standalone_host_fdb_del(struct dsa_port *dp,
const unsigned char *addr, u16 vid);
int dsa_port_bridge_host_fdb_add(struct dsa_port *dp, const unsigned char *addr,
- u16 vid);
+ u16 vid, u16 fdb_flags);
int dsa_port_bridge_host_fdb_del(struct dsa_port *dp, const unsigned char *addr,
- u16 vid);
+ u16 vid, u16 fdb_flags);
int dsa_port_lag_fdb_add(struct dsa_port *dp, const unsigned char *addr,
u16 vid);
int dsa_port_lag_fdb_del(struct dsa_port *dp, const unsigned char *addr,
diff --git a/net/dsa/port.c b/net/dsa/port.c
index eab32b7a945a..e4a79fd4a99e 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -1001,12 +1001,13 @@ int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr,

static int dsa_port_host_fdb_add(struct dsa_port *dp,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
struct dsa_notifier_fdb_info info = {
.dp = dp,
.addr = addr,
.vid = vid,
+ .fdb_flags = fdb_flags,
.db = db,
};

@@ -1024,11 +1025,11 @@ int dsa_port_standalone_host_fdb_add(struct dsa_port *dp,
.dp = dp,
};

- return dsa_port_host_fdb_add(dp, addr, vid, db);
+ return dsa_port_host_fdb_add(dp, addr, vid, 0, db);
}

-int dsa_port_bridge_host_fdb_add(struct dsa_port *dp,
- const unsigned char *addr, u16 vid)
+int dsa_port_bridge_host_fdb_add(struct dsa_port *dp, const unsigned char *addr,
+ u16 vid, u16 fdb_flags)
{
struct net_device *master = dsa_port_to_master(dp);
struct dsa_db db = {
@@ -1047,17 +1048,18 @@ int dsa_port_bridge_host_fdb_add(struct dsa_port *dp,
return err;
}

- return dsa_port_host_fdb_add(dp, addr, vid, db);
+ return dsa_port_host_fdb_add(dp, addr, vid, fdb_flags, db);
}

static int dsa_port_host_fdb_del(struct dsa_port *dp,
const unsigned char *addr, u16 vid,
- struct dsa_db db)
+ u16 fdb_flags, struct dsa_db db)
{
struct dsa_notifier_fdb_info info = {
.dp = dp,
.addr = addr,
.vid = vid,
+ .fdb_flags = fdb_flags,
.db = db,
};

@@ -1075,11 +1077,11 @@ int dsa_port_standalone_host_fdb_del(struct dsa_port *dp,
.dp = dp,
};

- return dsa_port_host_fdb_del(dp, addr, vid, db);
+ return dsa_port_host_fdb_del(dp, addr, vid, 0, db);
}

-int dsa_port_bridge_host_fdb_del(struct dsa_port *dp,
- const unsigned char *addr, u16 vid)
+int dsa_port_bridge_host_fdb_del(struct dsa_port *dp, const unsigned char *addr,
+ u16 vid, u16 fdb_flags)
{
struct net_device *master = dsa_port_to_master(dp);
struct dsa_db db = {
@@ -1094,7 +1096,7 @@ int dsa_port_bridge_host_fdb_del(struct dsa_port *dp,
return err;
}

- return dsa_port_host_fdb_del(dp, addr, vid, db);
+ return dsa_port_host_fdb_del(dp, addr, vid, fdb_flags, db);
}

int dsa_port_lag_fdb_add(struct dsa_port *dp, const unsigned char *addr,
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 65f0c578ef44..4e22014ec469 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -3258,7 +3258,7 @@ static void dsa_slave_switchdev_event_work(struct work_struct *work)
switch (switchdev_work->event) {
case SWITCHDEV_FDB_ADD_TO_DEVICE:
if (switchdev_work->host_addr)
- err = dsa_port_bridge_host_fdb_add(dp, addr, vid);
+ err = dsa_port_bridge_host_fdb_add(dp, addr, vid, fdb_flags);
else if (dp->lag)
err = dsa_port_lag_fdb_add(dp, addr, vid);
else
@@ -3274,7 +3274,7 @@ static void dsa_slave_switchdev_event_work(struct work_struct *work)

case SWITCHDEV_FDB_DEL_TO_DEVICE:
if (switchdev_work->host_addr)
- err = dsa_port_bridge_host_fdb_del(dp, addr, vid);
+ err = dsa_port_bridge_host_fdb_del(dp, addr, vid, fdb_flags);
else if (dp->lag)
err = dsa_port_lag_fdb_del(dp, addr, vid);
else
@@ -3365,6 +3365,8 @@ static int dsa_slave_fdb_event(struct net_device *dev,

if (fdb_info->locked)
fdb_flags |= DSA_FDB_FLAG_LOCKED;
+ if (fdb_info->blackhole)
+ fdb_flags |= DSA_FDB_FLAG_BLACKHOLE;

INIT_WORK(&switchdev_work->work, dsa_slave_switchdev_event_work);
switchdev_work->event = event;
--
2.34.1

2022-10-10 04:59:51

by Hans Schultz

[permalink] [raw]
Subject: [PATCH v7 net-next 9/9] selftests: forwarding: add test of MAC-Auth Bypass to locked port tests

Verify that the MAC-Auth mechanism works by adding a FDB entry with the
locked flag set, denying access until the FDB entry is replaced with a
FDB entry without the locked flag set.

Add test of blackhole fdb entries, verifying that there is no forwarding
to a blackhole entry from any port, and that the blackhole entry can be
replaced.

Also add a test that verifies that sticky FDB entries cannot roam (this
is not needed for now, but should in general be present anyhow for future
applications).

Signed-off-by: Hans J. Schultz <[email protected]>
---
.../selftests/drivers/net/dsa/Makefile | 1 +
.../testing/selftests/net/forwarding/Makefile | 1 +
.../net/forwarding/bridge_blackhole_fdb.sh | 134 ++++++++++++++++++
.../net/forwarding/bridge_locked_port.sh | 101 ++++++++++++-
tools/testing/selftests/net/forwarding/lib.sh | 17 +++
5 files changed, 253 insertions(+), 1 deletion(-)
create mode 100755 tools/testing/selftests/net/forwarding/bridge_blackhole_fdb.sh

diff --git a/tools/testing/selftests/drivers/net/dsa/Makefile b/tools/testing/selftests/drivers/net/dsa/Makefile
index c393e7b73805..c0a75d869763 100644
--- a/tools/testing/selftests/drivers/net/dsa/Makefile
+++ b/tools/testing/selftests/drivers/net/dsa/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+ OR MIT

TEST_PROGS = bridge_locked_port.sh \
+ bridge_blackhole_fdb.sh \
bridge_mdb.sh \
bridge_mld.sh \
bridge_vlan_aware.sh \
diff --git a/tools/testing/selftests/net/forwarding/Makefile b/tools/testing/selftests/net/forwarding/Makefile
index a9c5c1be5088..7d832020937f 100644
--- a/tools/testing/selftests/net/forwarding/Makefile
+++ b/tools/testing/selftests/net/forwarding/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+ OR MIT

TEST_PROGS = bridge_igmp.sh \
+ bridge_blackhole_fdb.sh \
bridge_locked_port.sh \
bridge_mdb.sh \
bridge_mdb_port_down.sh \
diff --git a/tools/testing/selftests/net/forwarding/bridge_blackhole_fdb.sh b/tools/testing/selftests/net/forwarding/bridge_blackhole_fdb.sh
new file mode 100755
index 000000000000..77d166180bc4
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/bridge_blackhole_fdb.sh
@@ -0,0 +1,134 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+ALL_TESTS="blackhole_fdb"
+NUM_NETIFS=4
+source tc_common.sh
+source lib.sh
+
+h1_create()
+{
+ simple_if_init $h1 192.0.2.1/24 2001:db8:1::1/64
+ vlan_create $h1 100 v$h1 198.51.100.1/24
+}
+
+h1_destroy()
+{
+ vlan_destroy $h1 100
+ simple_if_fini $h1 192.0.2.1/24 2001:db8:1::1/64
+}
+
+h2_create()
+{
+ simple_if_init $h2 192.0.2.2/24 2001:db8:1::2/64
+ vlan_create $h2 100 v$h2 198.51.100.2/24
+}
+
+h2_destroy()
+{
+ vlan_destroy $h2 100
+ simple_if_fini $h2 192.0.2.2/24 2001:db8:1::2/64
+}
+
+switch_create()
+{
+ ip link add dev br0 type bridge vlan_filtering 1
+
+ ip link set dev $swp1 master br0
+ ip link set dev $swp2 master br0
+
+ ip link set dev br0 up
+ ip link set dev $swp1 up
+ ip link set dev $swp2 up
+
+ tc qdisc add dev $swp2 clsact
+}
+
+switch_destroy()
+{
+ tc qdisc del dev $swp2 clsact
+
+ ip link set dev $swp2 down
+ ip link set dev $swp1 down
+
+ ip link del dev br0
+}
+
+setup_prepare()
+{
+ h1=${NETIFS[p1]}
+ swp1=${NETIFS[p2]}
+ h2=${NETIFS[p3]}
+ swp2=${NETIFS[p4]}
+
+ vrf_prepare
+
+ h1_create
+ h2_create
+
+ switch_create
+}
+
+cleanup()
+{
+ pre_cleanup
+
+ switch_destroy
+
+ h2_destroy
+ h1_destroy
+
+ vrf_cleanup
+}
+
+# Check that there is no egress with blackhole entry and that blackhole entries can be replaced
+blackhole_fdb()
+{
+ RET=0
+
+ check_blackhole_fdb_support || return 0
+
+ tc filter add dev $swp2 egress protocol ip pref 1 handle 1 flower \
+ dst_ip 192.0.2.2 ip_proto udp dst_port 12345 action pass
+
+ $MZ $h1 -c 1 -p 128 -t udp "sp=54321,dp=12345" \
+ -a own -b `mac_get $h2` -A 192.0.2.1 -B 192.0.2.2 -q
+
+ tc_check_packets "dev $swp2 egress" 1 1
+ check_err $? "Packet not seen on egress before adding blackhole entry"
+
+ bridge fdb replace `mac_get $h2` dev br0 blackhole
+ bridge fdb get `mac_get $h2` br br0 | grep -q blackhole
+ check_err $? "Blackhole entry not found"
+
+ $MZ $h1 -c 1 -p 128 -t udp "sp=54321,dp=12345" \
+ -a own -b `mac_get $h2` -A 192.0.2.1 -B 192.0.2.2 -q
+
+ tc_check_packets "dev $swp2 egress" 1 1
+ check_err $? "Packet seen on egress after adding blackhole entry"
+
+ # Check blackhole entries can be replaced.
+ bridge fdb replace `mac_get $h2` dev $swp2 master static
+ bridge fdb get `mac_get $h2` br br0 | grep -q blackhole
+ check_fail $? "Blackhole entry found after replacement"
+
+ $MZ $h1 -c 1 -p 128 -t udp "sp=54321,dp=12345" \
+ -a own -b `mac_get $h2` -A 192.0.2.1 -B 192.0.2.2 -q
+
+ tc_check_packets "dev $swp2 egress" 1 2
+ check_err $? "Packet not seen on egress after replacing blackhole entry"
+
+ bridge fdb del `mac_get $h2` dev $swp2 master static
+ tc filter del dev $swp2 egress protocol ip pref 1 handle 1 flower
+
+ log_test "Blackhole FDB entry"
+}
+
+trap cleanup EXIT
+
+setup_prepare
+setup_wait
+
+tests_run
+
+exit $EXIT_STATUS
diff --git a/tools/testing/selftests/net/forwarding/bridge_locked_port.sh b/tools/testing/selftests/net/forwarding/bridge_locked_port.sh
index 5b02b6b60ce7..fbe558f25e44 100755
--- a/tools/testing/selftests/net/forwarding/bridge_locked_port.sh
+++ b/tools/testing/selftests/net/forwarding/bridge_locked_port.sh
@@ -1,7 +1,15 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0

-ALL_TESTS="locked_port_ipv4 locked_port_ipv6 locked_port_vlan"
+ALL_TESTS="
+ locked_port_ipv4
+ locked_port_ipv6
+ locked_port_vlan
+ locked_port_mab
+ locked_port_station_move
+ locked_port_mab_station_move
+"
+
NUM_NETIFS=4
CHECK_TC="no"
source lib.sh
@@ -166,6 +174,97 @@ locked_port_ipv6()
log_test "Locked port ipv6"
}

+locked_port_mab()
+{
+ RET=0
+ check_port_mab_support || return 0
+
+ ping_do $h1 192.0.2.2
+ check_err $? "MAB: Ping did not work before locking port"
+
+ bridge link set dev $swp1 locked on mab on
+
+ ping_do $h1 192.0.2.2
+ check_fail $? "MAB: Ping worked on mab enabled port without FDB entry"
+
+ bridge fdb get `mac_get $h1` vlan 1 dev $swp1 | grep "dev $swp1 vlan 1" | grep -q "locked"
+ check_err $? "MAB: No locked FDB entry after ping on mab enabled port"
+
+ bridge fdb replace `mac_get $h1` dev $swp1 master static
+
+ ping_do $h1 192.0.2.2
+ check_err $? "MAB: Ping did not work with FDB entry without locked flag"
+
+ bridge fdb del `mac_get $h1` dev $swp1 master
+ bridge link set dev $swp1 locked off mab off
+
+ log_test "Locked port MAB"
+}
+
+# Check that entries cannot roam from an unlocked port to a locked port.
+locked_port_station_move()
+{
+ local mac=a0:b0:c0:c0:b0:a0
+
+ RET=0
+ check_locked_port_support || return 0
+
+ bridge link set dev $swp1 locked on learning on
+
+ $MZ $h1 -q -c 5 -d 100msec -t udp -a $mac -b rand
+ bridge fdb show dev $swp1 | grep -q $mac
+ check_fail $? "Locked port station move: FDB entry on first injection"
+
+ $MZ $h2 -q -c 5 -d 100msec -t udp -a $mac -b rand
+ bridge fdb get $mac vlan 1 dev $swp2 | grep "dev $swp2 vlan 1" | grep -q "master br0"
+ check_err $? "Locked port station move: Entry not found on unlocked port"
+
+ $MZ $h1 -q -c 5 -d 100msec -t udp -a $mac -b rand
+ bridge fdb get $mac vlan 1 dev $swp1 | grep "dev $swp1 vlan 1" | grep -q "master br0"
+ check_fail $? "Locked port station move: entry roamed to locked port"
+
+ bridge fdb del $mac vlan 1 dev $swp2 master
+ bridge link set dev $swp1 locked off learning off
+
+ log_test "Locked port station move"
+}
+
+# Roaming to and from a MAB enabled port should work if blackhole flag is not set
+locked_port_mab_station_move()
+{
+ local mac=10:20:30:30:20:10
+
+ RET=0
+ check_port_mab_support || return 0
+
+ bridge link set dev $swp1 locked on mab on
+
+ $MZ $h1 -q -c 5 -d 100 mesc -t udp -a $mac -b rand
+ if bridge fdb show dev $swp1 | grep "$mac vlan 1" | grep -q "blackhole"; then
+ echo "SKIP: Roaming not possible with blackhole flag, skipping test..."
+ bridge link set dev $swp1 locked off mab off
+ return $ksft_skip
+ fi
+
+ bridge fdb show dev $swp1 | grep "$mac vlan 1" | grep -q "locked"
+ check_err $? "MAB station move: no locked entry on first injection"
+
+ $MZ $h2 -q -c 5 -d 100msec -t udp -a $mac -b rand
+ bridge fdb get $mac vlan 1 dev $swp1 | grep "dev $swp1 vlan 1" | grep -q "locked"
+ check_fail $? "MAB station move: locked entry did not move"
+
+ bridge fdb get $mac vlan 1 dev $swp2 | grep "dev $swp2 vlan 1" | grep -q "locked"
+ check_fail $? "MAB station move: roamed entry to unlocked port had locked flag on"
+
+ bridge fdb get $mac vlan 1 dev $swp2 | grep "dev $swp2 vlan 1" | grep -q "master br0"
+ check_err $? "MAB station move: roamed entry not found"
+
+ bridge fdb del $mac vlan 1 dev $swp2 master
+ bridge link set dev $swp1 locked off mab off
+
+ log_test "Locked port MAB station move"
+}
+
trap cleanup EXIT

setup_prepare
diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh
index 3ffb9d6c0950..d6abe873665c 100755
--- a/tools/testing/selftests/net/forwarding/lib.sh
+++ b/tools/testing/selftests/net/forwarding/lib.sh
@@ -137,6 +137,23 @@ check_locked_port_support()
fi
}

+check_port_mab_support()
+{
+ if ! bridge -d link show | grep -q "mab"; then
+ echo "SKIP: iproute2 too old; MacAuth feature not supported."
+ return $ksft_skip
+ fi
+}
+
+check_blackhole_fdb_support()
+{
+ bridge fdb help 2>&1|grep blackhole &> /dev/null
+ if [[ $? -ne 0 ]]; then
+ echo "SKIP: Blackhole fdb feature not supported."
+ return $ksft_skip
+ fi
+}
+
if [[ "$(id -u)" -ne 0 ]]; then
echo "SKIP: need root privileges"
exit $ksft_skip
--
2.34.1

2022-10-10 04:59:56

by Hans Schultz

[permalink] [raw]
Subject: [PATCH v7 net-next 6/9] net: dsa: mv88e6xxx: allow reading FID when handling ATU violations

The FID is needed to get hold of which VID was involved in a violation,
thus the need to be able to read the FID.

For convenience the function mv88e6xxx_g1_atu_op() has been used to read
ATU violations, but the function invalidates reading the fid, so to both
read ATU violations without zeroing the fid, and read the fid, functions
have been added to ensure both are done correctly.

Signed-off-by: Hans J. Schultz <[email protected]>
---
drivers/net/dsa/mv88e6xxx/global1_atu.c | 60 ++++++++++++++++++++++---
1 file changed, 55 insertions(+), 5 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c
index 40bd67a5c8e9..d9dfa1159cde 100644
--- a/drivers/net/dsa/mv88e6xxx/global1_atu.c
+++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c
@@ -114,6 +114,19 @@ 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;
@@ -159,6 +172,41 @@ int mv88e6xxx_g1_atu_get_next(struct mv88e6xxx_chip *chip, u16 fid)
return mv88e6xxx_g1_atu_op(chip, fid, MV88E6XXX_G1_ATU_OP_GET_NEXT_DB);
}

+static int mv88e6xxx_g1_atu_fid_read(struct mv88e6xxx_chip *chip, u16 *fid)
+{
+ u16 val = 0, upper = 0, op = 0;
+ int err = -EOPNOTSUPP;
+
+ if (mv88e6xxx_num_databases(chip) > 256) {
+ err = mv88e6xxx_g1_read(chip, MV88E6352_G1_ATU_FID, &val);
+ val &= 0xfff;
+ if (err)
+ return err;
+ } else {
+ err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &op);
+ if (err)
+ return err;
+ if (mv88e6xxx_num_databases(chip) > 64) {
+ /* ATU DBNum[7:4] are located in ATU Control 15:12 */
+ err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, &upper);
+ if (err)
+ return err;
+
+ upper = (upper >> 8) & 0x00f0;
+ } else if (mv88e6xxx_num_databases(chip) > 16) {
+ /* ATU DBNum[5:4] are located in ATU Operation 9:8 */
+
+ upper = (op >> 4) & 0x30;
+ }
+ /* ATU DBNum[3:0] are located in ATU Operation 3:0 */
+
+ val = (op & 0xf) | upper;
+ }
+ *fid = val;
+
+ return err;
+}
+
/* Offset 0x0C: ATU Data Register */

static int mv88e6xxx_g1_atu_data_read(struct mv88e6xxx_chip *chip,
@@ -353,14 +401,12 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
{
struct mv88e6xxx_chip *chip = dev_id;
struct mv88e6xxx_atu_entry entry;
- int spid;
- int err;
- u16 val;
+ int err, spid;
+ u16 val, 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 +414,10 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
if (err)
goto out;

+ err = mv88e6xxx_g1_atu_fid_read(chip, &fid);
+ if (err)
+ goto out;
+
err = mv88e6xxx_g1_atu_data_read(chip, &entry);
if (err)
goto out;
--
2.34.1

2022-10-10 05:01:20

by Hans Schultz

[permalink] [raw]
Subject: [PATCH v7 net-next 8/9] net: dsa: mv88e6xxx: add blackhole ATU entries

Blackhole FDB entries can now be added, deleted or replaced in the
driver ATU.

Signed-off-by: Hans J. Schultz <[email protected]>
---
drivers/net/dsa/mv88e6xxx/chip.c | 60 +++++++++++++++++++++++++++++---
1 file changed, 56 insertions(+), 4 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 71843fe87f77..3c4ebb2a5301 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -2735,6 +2735,56 @@ static int mv88e6xxx_vlan_msti_set(struct dsa_switch *ds,
return err;
}

+static int mv88e6xxx_blackhole_fdb_loadpurge(struct dsa_switch *ds,
+ const unsigned char *addr, u16 vid, u8 state)
+{
+ struct mv88e6xxx_chip *chip = ds->priv;
+ struct mv88e6xxx_atu_entry entry;
+ struct mv88e6xxx_vtu_entry vlan;
+
+ u16 fid = 0;
+ int err;
+
+ if (vid == 0) {
+ fid = MV88E6XXX_FID_BRIDGED;
+ } else {
+ mv88e6xxx_reg_lock(chip);
+ err = mv88e6xxx_vtu_get(chip, vid, &vlan);
+ mv88e6xxx_reg_unlock(chip);
+ if (err)
+ return err;
+
+ /* switchdev expects -EOPNOTSUPP to honor software VLANs */
+ if (!vlan.valid)
+ return -EOPNOTSUPP;
+
+ fid = vlan.fid;
+ }
+
+ ether_addr_copy(entry.mac, addr);
+ entry.portvec = MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_NO_EGRESS;
+ entry.state = state;
+ entry.trunk = false;
+
+ mv88e6xxx_reg_lock(chip);
+ err = mv88e6xxx_g1_atu_loadpurge(chip, fid, &entry);
+ mv88e6xxx_reg_unlock(chip);
+
+ return err;
+}
+
+int mv88e6xxx_blackhole_fdb_add(struct dsa_switch *ds, const unsigned char *addr, u16 vid)
+{
+ return mv88e6xxx_blackhole_fdb_loadpurge(ds, addr, vid,
+ MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
+}
+
+int mv88e6xxx_blackhole_fdb_del(struct dsa_switch *ds, const unsigned char *addr, u16 vid)
+{
+ return mv88e6xxx_blackhole_fdb_loadpurge(ds, addr, vid,
+ MV88E6XXX_G1_ATU_DATA_STATE_UC_UNUSED);
+}
+
static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
u16 fdb_flags, struct dsa_db db)
@@ -2742,9 +2792,10 @@ static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int err;

- /* Ignore entries with flags set */
- if (fdb_flags)
+ if (fdb_flags & DSA_FDB_FLAG_LOCKED)
return 0;
+ if (fdb_flags & DSA_FDB_FLAG_BLACKHOLE)
+ return mv88e6xxx_blackhole_fdb_add(ds, addr, vid);

if (mv88e6xxx_port_is_locked(chip, port))
mv88e6xxx_atu_locked_entry_find_purge(ds, port, addr, vid);
@@ -2765,9 +2816,10 @@ static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
bool locked_found = false;
int err = 0;

- /* Ignore entries with flags set */
- if (fdb_flags)
+ if (fdb_flags & DSA_FDB_FLAG_LOCKED)
return 0;
+ if (fdb_flags & DSA_FDB_FLAG_BLACKHOLE)
+ return mv88e6xxx_blackhole_fdb_del(ds, addr, vid);

if (mv88e6xxx_port_is_locked(chip, port))
locked_found = mv88e6xxx_atu_locked_entry_find_purge(ds, port, addr, vid);
--
2.34.1

2022-10-10 05:11:49

by Hans Schultz

[permalink] [raw]
Subject: [PATCH v7 net-next 7/9] net: dsa: mv88e6xxx: mac-auth/MAB implementation

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 will be added to the ATU with a zero-DPV,
and is then communicated through switchdev to the bridge module,
which adds a fdb entry with the fdb locked flag set. The entry
is kept according to the bridges ageing time, thus simulating a
dynamic entry.

Additionally the driver will set the sticky and masked flags, as
the driver does not support roaming and forwarding from any port
to a locked entry.

As this is essentially a form of CPU based learning, the amount
of locked entries will be limited by a hardcoded value for now,
so as to prevent DOS attacks.

Signed-off-by: Hans J. Schultz <[email protected]>
---
drivers/net/dsa/mv88e6xxx/Makefile | 1 +
drivers/net/dsa/mv88e6xxx/chip.c | 76 +++++--
drivers/net/dsa/mv88e6xxx/chip.h | 19 ++
drivers/net/dsa/mv88e6xxx/global1.h | 1 +
drivers/net/dsa/mv88e6xxx/global1_atu.c | 12 +-
drivers/net/dsa/mv88e6xxx/port.c | 15 +-
drivers/net/dsa/mv88e6xxx/port.h | 6 +
drivers/net/dsa/mv88e6xxx/switchdev.c | 284 ++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/switchdev.h | 37 +++
9 files changed, 429 insertions(+), 22 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 352121cce77e..71843fe87f77 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -42,6 +42,7 @@
#include "ptp.h"
#include "serdes.h"
#include "smi.h"
+#include "switchdev.h"

static void assert_reg_lock(struct mv88e6xxx_chip *chip)
{
@@ -924,6 +925,13 @@ static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port,
if (err)
dev_err(chip->dev,
"p%d: failed to force MAC link down\n", port);
+ else
+ if (mv88e6xxx_port_is_locked(chip, port)) {
+ err = mv88e6xxx_atu_locked_entry_flush(ds, port);
+ if (err)
+ dev_err(chip->dev,
+ "p%d: failed to clear locked entries\n", port);
+ }
}

static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port,
@@ -1690,6 +1698,13 @@ static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)
struct mv88e6xxx_chip *chip = ds->priv;
int err;

+ if (mv88e6xxx_port_is_locked(chip, port)) {
+ err = mv88e6xxx_atu_locked_entry_flush(ds, port);
+ if (err)
+ dev_err(chip->ds->dev, "p%d: failed to clear locked entries: %d\n",
+ port, err);
+ }
+
mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_fast_age_fid(chip, port, 0);
mv88e6xxx_reg_unlock(chip);
@@ -1726,11 +1741,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),
@@ -2731,6 +2746,9 @@ static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
if (fdb_flags)
return 0;

+ if (mv88e6xxx_port_is_locked(chip, port))
+ mv88e6xxx_atu_locked_entry_find_purge(ds, port, addr, vid);
+
mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
@@ -2744,16 +2762,21 @@ static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
u16 fdb_flags, struct dsa_db db)
{
struct mv88e6xxx_chip *chip = ds->priv;
- int err;
+ bool locked_found = false;
+ int err = 0;

/* Ignore entries with flags set */
if (fdb_flags)
return 0;

- mv88e6xxx_reg_lock(chip);
- err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 0);
- mv88e6xxx_reg_unlock(chip);
+ if (mv88e6xxx_port_is_locked(chip, port))
+ locked_found = mv88e6xxx_atu_locked_entry_find_purge(ds, port, addr, vid);

+ if (!locked_found) {
+ mv88e6xxx_reg_lock(chip);
+ err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 0);
+ mv88e6xxx_reg_unlock(chip);
+ }
return err;
}

@@ -3849,11 +3872,18 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)

static int mv88e6xxx_port_setup(struct dsa_switch *ds, int port)
{
- return mv88e6xxx_setup_devlink_regions_port(ds, port);
+ int err;
+
+ err = mv88e6xxx_setup_devlink_regions_port(ds, port);
+ if (!err)
+ return mv88e6xxx_init_violation_handler(ds, port);
+
+ return err;
}

static void mv88e6xxx_port_teardown(struct dsa_switch *ds, int port)
{
+ mv88e6xxx_teardown_violation_handler(ds, port);
mv88e6xxx_teardown_devlink_regions_port(ds, port);
}

@@ -6528,7 +6558,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;
@@ -6549,13 +6579,13 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int err = -EOPNOTSUPP;

- mv88e6xxx_reg_lock(chip);
-
if (flags.mask & BR_LEARNING) {
bool learning = !!(flags.val & BR_LEARNING);
u16 pav = learning ? (1 << port) : 0;

+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_set_assoc_vector(chip, port, pav);
+ mv88e6xxx_reg_unlock(chip);
if (err)
goto out;
}
@@ -6563,8 +6593,10 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
if (flags.mask & BR_FLOOD) {
bool unicast = !!(flags.val & BR_FLOOD);

+ mv88e6xxx_reg_lock(chip);
err = chip->info->ops->port_set_ucast_flood(chip, port,
unicast);
+ mv88e6xxx_reg_unlock(chip);
if (err)
goto out;
}
@@ -6572,8 +6604,10 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
if (flags.mask & BR_MCAST_FLOOD) {
bool multicast = !!(flags.val & BR_MCAST_FLOOD);

+ mv88e6xxx_reg_lock(chip);
err = chip->info->ops->port_set_mcast_flood(chip, port,
multicast);
+ mv88e6xxx_reg_unlock(chip);
if (err)
goto out;
}
@@ -6581,20 +6615,34 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
if (flags.mask & BR_BCAST_FLOOD) {
bool broadcast = !!(flags.val & BR_BCAST_FLOOD);

+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_broadcast_sync(chip, port, broadcast);
+ mv88e6xxx_reg_unlock(chip);
if (err)
goto out;
}

+ if (flags.mask & BR_PORT_MAB) {
+ chip->ports[port].mab = !!(flags.val & BR_PORT_MAB);
+
+ if (!chip->ports[port].mab)
+ err = mv88e6xxx_atu_locked_entry_flush(ds, port);
+ else
+ err = 0;
+ }
+
if (flags.mask & BR_PORT_LOCKED) {
bool locked = !!(flags.val & BR_PORT_LOCKED);

+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_set_lock(chip, port, locked);
+ mv88e6xxx_reg_unlock(chip);
if (err)
goto out;
+
+ chip->ports[port].locked = locked;
}
out:
- mv88e6xxx_reg_unlock(chip);

return err;
}
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index e693154cf803..180fbcf596fa 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -280,6 +280,16 @@ struct mv88e6xxx_port {
unsigned int serdes_irq;
char serdes_irq_name[64];
struct devlink_region *region;
+
+ /* Locked port and MacAuth control flags */
+ bool locked;
+ bool mab;
+
+ /* List and maintenance of ATU locked entries */
+ struct mutex ale_list_lock;
+ struct list_head ale_list;
+ struct delayed_work ale_work;
+ int ale_cnt;
};

enum mv88e6xxx_region_id {
@@ -399,6 +409,9 @@ struct mv88e6xxx_chip {
int egress_dest_port;
int ingress_dest_port;

+ /* Keep the register written age time for easy access */
+ u8 age_time;
+
/* Per-port timestamping resources. */
struct mv88e6xxx_port_hwtstamp port_hwtstamp[DSA_MAX_PORTS];

@@ -802,6 +815,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.h b/drivers/net/dsa/mv88e6xxx/global1.h
index 65958b2a0d3a..503fbf216670 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 d9dfa1159cde..67907cd00b87 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 "switchdev.h"

/* Offset 0x01: ATU FID Register */

@@ -54,6 +56,7 @@ int mv88e6xxx_g1_atu_set_age_time(struct mv88e6xxx_chip *chip,

/* Round to nearest multiple of coeff */
age_time = (msecs + coeff / 2) / coeff;
+ chip->age_time = age_time;

err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, &val);
if (err)
@@ -426,6 +429,8 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
if (err)
goto out;

+ mv88e6xxx_reg_unlock(chip);
+
spid = entry.state;

if (val & MV88E6XXX_G1_ATU_OP_AGE_OUT_VIOLATION) {
@@ -446,6 +451,12 @@ 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 && chip->ports[spid].mab)
+ err = mv88e6xxx_handle_violation(chip, spid, &entry, fid,
+ MV88E6XXX_G1_ATU_OP_MISS_VIOLATION);
+ if (err)
+ goto out;
}

if (val & MV88E6XXX_G1_ATU_OP_FULL_VIOLATION) {
@@ -454,7 +465,6 @@ 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;

diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index 5c4195c635b0..67e457ce67ae 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -14,9 +14,11 @@
#include <linux/phylink.h>

#include "chip.h"
+#include "global1.h"
#include "global2.h"
#include "port.h"
#include "serdes.h"
+#include "switchdev.h"

int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
u16 *val)
@@ -1240,13 +1242,12 @@ int mv88e6xxx_port_set_lock(struct mv88e6xxx_chip *chip, int port,
if (err)
return err;

- err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, &reg);
- if (err)
- return err;
-
- reg &= ~MV88E6XXX_PORT_ASSOC_VECTOR_LOCKED_PORT;
- if (locked)
- reg |= MV88E6XXX_PORT_ASSOC_VECTOR_LOCKED_PORT;
+ reg = 0;
+ if (locked) {
+ reg = (1 << port);
+ reg |= MV88E6XXX_PORT_ASSOC_VECTOR_IGNORE_WRONG |
+ MV88E6XXX_PORT_ASSOC_VECTOR_LOCKED_PORT;
+ }

return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, reg);
}
diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h
index cb04243f37c1..9475bc6e95a2 100644
--- a/drivers/net/dsa/mv88e6xxx/port.h
+++ b/drivers/net/dsa/mv88e6xxx/port.h
@@ -231,6 +231,7 @@
#define MV88E6XXX_PORT_ASSOC_VECTOR_LOCKED_PORT 0x2000
#define MV88E6XXX_PORT_ASSOC_VECTOR_IGNORE_WRONG 0x1000
#define MV88E6XXX_PORT_ASSOC_VECTOR_REFRESH_LOCKED 0x0800
+#define MV88E6XXX_PORT_ASSOC_VECTOR_PAV_MASK 0x07ff

/* Offset 0x0C: Port ATU Control */
#define MV88E6XXX_PORT_ATU_CTL 0x0c
@@ -375,6 +376,11 @@ int mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid);
int mv88e6xxx_port_set_lock(struct mv88e6xxx_chip *chip, int port,
bool locked);

+static inline bool mv88e6xxx_port_is_locked(struct mv88e6xxx_chip *chip, int port)
+{
+ return chip->ports[port].locked;
+}
+
int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port,
u16 mode);
int mv88e6095_port_tag_remap(struct mv88e6xxx_chip *chip, int port);
diff --git a/drivers/net/dsa/mv88e6xxx/switchdev.c b/drivers/net/dsa/mv88e6xxx/switchdev.c
new file mode 100644
index 000000000000..327dbc0cfc3c
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/switchdev.c
@@ -0,0 +1,284 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * switchdev.c
+ *
+ * Authors:
+ * Hans J. Schultz <[email protected]>
+ *
+ */
+
+#include <net/switchdev.h>
+#include <linux/list.h>
+#include "chip.h"
+#include "global1.h"
+#include "switchdev.h"
+
+static void mv88e6xxx_atu_locked_entry_purge(struct mv88e6xxx_atu_locked_entry *ale,
+ bool notify, bool take_nl_lock)
+{
+ struct switchdev_notifier_fdb_info info = {
+ .addr = ale->mac,
+ .vid = ale->vid,
+ .locked = true,
+ .offloaded = true,
+ };
+ struct mv88e6xxx_atu_entry entry;
+ struct net_device *brport;
+ struct dsa_port *dp;
+
+ entry.portvec = MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_NO_EGRESS;
+ entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UC_UNUSED;
+ entry.trunk = false;
+ ether_addr_copy(entry.mac, ale->mac);
+
+ mv88e6xxx_reg_lock(ale->chip);
+ mv88e6xxx_g1_atu_loadpurge(ale->chip, ale->fid, &entry);
+ mv88e6xxx_reg_unlock(ale->chip);
+
+ dp = dsa_to_port(ale->chip->ds, ale->port);
+
+ if (notify) {
+ if (take_nl_lock)
+ rtnl_lock();
+ brport = dsa_port_to_bridge_port(dp);
+
+ if (brport) {
+ call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE,
+ brport, &info.info, NULL);
+ } else {
+ dev_err(ale->chip->dev, "No bridge port for dsa port belonging to port %d\n",
+ ale->port);
+ }
+ if (take_nl_lock)
+ rtnl_unlock();
+ }
+
+ list_del(&ale->list);
+ kfree(ale);
+}
+
+static void mv88e6xxx_atu_locked_entry_cleanup(struct work_struct *work)
+{
+ struct mv88e6xxx_port *p = container_of(work, struct mv88e6xxx_port, ale_work.work);
+ struct mv88e6xxx_atu_locked_entry *ale, *tmp;
+
+ mutex_lock(&p->ale_list_lock);
+ list_for_each_entry_safe(ale, tmp, &p->ale_list, list) {
+ if (time_after(jiffies, ale->expires)) {
+ mv88e6xxx_atu_locked_entry_purge(ale, true, true);
+ p->ale_cnt--;
+ }
+ }
+ mutex_unlock(&p->ale_list_lock);
+
+ mod_delayed_work(system_long_wq, &p->ale_work, msecs_to_jiffies(100));
+}
+
+static int mv88e6xxx_new_atu_locked_entry(struct mv88e6xxx_chip *chip, const unsigned char *addr,
+ int port, u16 fid, u16 vid,
+ struct mv88e6xxx_atu_locked_entry **alep)
+{
+ struct mv88e6xxx_atu_locked_entry *ale;
+ unsigned long now, age_time;
+
+ ale = kmalloc(sizeof(*ale), GFP_ATOMIC);
+ if (!ale)
+ return -ENOMEM;
+
+ ether_addr_copy(ale->mac, addr);
+ ale->chip = chip;
+ ale->port = port;
+ ale->fid = fid;
+ ale->vid = vid;
+ now = jiffies;
+ age_time = chip->age_time * chip->info->age_time_coeff;
+ ale->expires = now + age_time;
+
+ *alep = ale;
+ return 0;
+}
+
+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_handle_violation(struct mv88e6xxx_chip *chip, int port,
+ struct mv88e6xxx_atu_entry *entry,
+ u16 fid, u16 type)
+{
+ struct switchdev_notifier_fdb_info info = {
+ .addr = entry->mac,
+ .vid = 0,
+ .is_local = true,
+ .locked = true,
+ .blackhole = true,
+ .offloaded = true,
+ };
+ struct mv88e6xxx_atu_locked_entry *ale;
+ struct mv88e6xxx_fid_search_ctx ctx;
+ struct net_device *brport;
+ struct mv88e6xxx_port *p;
+ struct dsa_port *dp;
+ int err;
+
+ if (!mv88e6xxx_is_invalid_port(chip, port))
+ p = &chip->ports[port];
+ else
+ return -ENODEV;
+
+ ctx.fid_search = fid;
+ mv88e6xxx_reg_lock(chip);
+ err = mv88e6xxx_vtu_walk(chip, mv88e6xxx_find_vid_on_matching_fid, &ctx);
+ mv88e6xxx_reg_unlock(chip);
+ if (err < 0)
+ return err;
+ if (err == 1)
+ info.vid = ctx.vid_found;
+ else
+ return -ENODATA;
+
+ switch (type) {
+ case MV88E6XXX_G1_ATU_OP_MISS_VIOLATION:
+ mutex_lock(&p->ale_list_lock);
+ if (p->ale_cnt >= ATU_LOCKED_ENTRIES_MAX)
+ goto exit;
+ mutex_unlock(&p->ale_list_lock);
+ entry->portvec = MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_NO_EGRESS;
+ entry->state = MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC;
+ entry->trunk = false;
+
+ mv88e6xxx_reg_lock(chip);
+ err = mv88e6xxx_g1_atu_loadpurge(chip, fid, entry);
+ if (err)
+ goto fail;
+ mv88e6xxx_reg_unlock(chip);
+
+ dp = dsa_to_port(chip->ds, port);
+ err = mv88e6xxx_new_atu_locked_entry(chip, entry->mac, port, fid,
+ info.vid, &ale);
+ if (err)
+ return err;
+
+ mutex_lock(&p->ale_list_lock);
+ list_add(&ale->list, &p->ale_list);
+ p->ale_cnt++;
+ mutex_unlock(&p->ale_list_lock);
+
+ 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();
+ break;
+ }
+
+ return err;
+
+fail:
+ mv88e6xxx_reg_unlock(chip);
+ return err;
+
+exit:
+ mutex_unlock(&p->ale_list_lock);
+ return 0;
+}
+
+bool mv88e6xxx_atu_locked_entry_find_purge(struct dsa_switch *ds, int port,
+ const unsigned char *addr, u16 vid)
+{
+ struct mv88e6xxx_atu_locked_entry *ale, *tmp;
+ struct mv88e6xxx_chip *chip = ds->priv;
+ struct mv88e6xxx_port *p;
+ bool found = false;
+
+ p = &chip->ports[port];
+ mutex_lock(&p->ale_list_lock);
+ list_for_each_entry_safe(ale, tmp, &p->ale_list, list) {
+ if (ether_addr_equal(ale->mac, addr) == 0) {
+ if (ale->vid == vid) {
+ mv88e6xxx_atu_locked_entry_purge(ale, false, false);
+ p->ale_cnt--;
+ found = true;
+ break;
+ }
+ }
+ }
+ mutex_unlock(&p->ale_list_lock);
+ return found;
+}
+
+int mv88e6xxx_atu_locked_entry_flush(struct dsa_switch *ds, int port)
+{
+ struct mv88e6xxx_atu_locked_entry *ale, *tmp;
+ struct mv88e6xxx_chip *chip = ds->priv;
+ struct mv88e6xxx_port *p;
+
+ if (!mv88e6xxx_is_invalid_port(chip, port))
+ p = &chip->ports[port];
+ else
+ return -ENODEV;
+
+ mutex_lock(&p->ale_list_lock);
+ list_for_each_entry_safe(ale, tmp, &p->ale_list, list) {
+ mv88e6xxx_atu_locked_entry_purge(ale, true, false);
+ p->ale_cnt--;
+ }
+ mutex_unlock(&p->ale_list_lock);
+
+ return 0;
+}
+
+int mv88e6xxx_init_violation_handler(struct dsa_switch *ds, int port)
+{
+ struct mv88e6xxx_chip *chip = ds->priv;
+ struct mv88e6xxx_port *p;
+
+ if (!mv88e6xxx_is_invalid_port(chip, port))
+ p = &chip->ports[port];
+ else
+ return -ENODEV;
+
+ INIT_LIST_HEAD(&p->ale_list);
+ mutex_init(&p->ale_list_lock);
+ p->ale_cnt = 0;
+ INIT_DELAYED_WORK(&p->ale_work, mv88e6xxx_atu_locked_entry_cleanup);
+ mod_delayed_work(system_long_wq, &p->ale_work, msecs_to_jiffies(500));
+
+ return 0;
+}
+
+int mv88e6xxx_teardown_violation_handler(struct dsa_switch *ds, int port)
+{
+ struct mv88e6xxx_chip *chip = ds->priv;
+ struct mv88e6xxx_port *p;
+
+ if (!mv88e6xxx_is_invalid_port(chip, port))
+ p = &chip->ports[port];
+ else
+ return -ENODEV;
+
+ cancel_delayed_work(&p->ale_work);
+ mv88e6xxx_atu_locked_entry_flush(ds, port);
+ mutex_destroy(&p->ale_list_lock);
+
+ return 0;
+}
diff --git a/drivers/net/dsa/mv88e6xxx/switchdev.h b/drivers/net/dsa/mv88e6xxx/switchdev.h
new file mode 100644
index 000000000000..df2005c36f47
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/switchdev.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * switchdev.h
+ *
+ * Authors:
+ * Hans J. Schultz <[email protected]>
+ *
+ */
+
+#ifndef DRIVERS_NET_DSA_MV88E6XXX_SWITCHDEV_H_
+#define DRIVERS_NET_DSA_MV88E6XXX_SWITCHDEV_H_
+
+#include <net/switchdev.h>
+#include "chip.h"
+
+#define ATU_LOCKED_ENTRIES_MAX 64
+
+struct mv88e6xxx_atu_locked_entry {
+ struct list_head list;
+ struct mv88e6xxx_chip *chip;
+ int port;
+ u8 mac[ETH_ALEN];
+ u16 fid;
+ u16 vid;
+ unsigned long expires;
+};
+
+int mv88e6xxx_handle_violation(struct mv88e6xxx_chip *chip, int port,
+ struct mv88e6xxx_atu_entry *entry,
+ u16 fid, u16 type);
+bool mv88e6xxx_atu_locked_entry_find_purge(struct dsa_switch *ds, int port,
+ const unsigned char *addr, u16 vid);
+int mv88e6xxx_atu_locked_entry_flush(struct dsa_switch *ds, int port);
+int mv88e6xxx_init_violation_handler(struct dsa_switch *ds, int port);
+int mv88e6xxx_teardown_violation_handler(struct dsa_switch *ds, int port);
+
+#endif /* DRIVERS_NET_DSA_MV88E6XXX_SWITCHDEV_H_ */
--
2.34.1

2022-10-12 10:29:50

by Hans Schultz

[permalink] [raw]
Subject: Re: [PATCH v7 net-next 9/9] selftests: forwarding: add test of MAC-Auth Bypass to locked port tests

On 2022-10-09 19:40, Hans J. Schultz wrote:
> Verify that the MAC-Auth mechanism works by adding a FDB entry with the
> locked flag set, denying access until the FDB entry is replaced with a
> FDB entry without the locked flag set.
>
> Add test of blackhole fdb entries, verifying that there is no
> forwarding
> to a blackhole entry from any port, and that the blackhole entry can be
> replaced.
>

Ido, have you had time to look at this patch set, and do I need to
release a v8 to fix those two forgotten statics and maybe also this new
switchcore driver that was not there when I posted this patch set?

2022-10-13 12:45:04

by Ido Schimmel

[permalink] [raw]
Subject: Re: [PATCH v7 net-next 9/9] selftests: forwarding: add test of MAC-Auth Bypass to locked port tests

On Sun, Oct 09, 2022 at 07:40:52PM +0200, Hans J. Schultz wrote:
> +++ b/tools/testing/selftests/net/forwarding/bridge_blackhole_fdb.sh
> @@ -0,0 +1,134 @@
> +#!/bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +
> +ALL_TESTS="blackhole_fdb"
> +NUM_NETIFS=4
> +source tc_common.sh
> +source lib.sh
> +
> +h1_create()
> +{
> + simple_if_init $h1 192.0.2.1/24 2001:db8:1::1/64
> + vlan_create $h1 100 v$h1 198.51.100.1/24
> +}
> +
> +h1_destroy()
> +{
> + vlan_destroy $h1 100
> + simple_if_fini $h1 192.0.2.1/24 2001:db8:1::1/64
> +}
> +
> +h2_create()
> +{
> + simple_if_init $h2 192.0.2.2/24 2001:db8:1::2/64
> + vlan_create $h2 100 v$h2 198.51.100.2/24
> +}
> +
> +h2_destroy()
> +{
> + vlan_destroy $h2 100
> + simple_if_fini $h2 192.0.2.2/24 2001:db8:1::2/64
> +}

There is unnecessary configuration here. Can be simplified:

diff --git a/tools/testing/selftests/net/forwarding/bridge_blackhole_fdb.sh b/tools/testing/selftests/net/forwarding/bridge_blackhole_fdb.sh
index 77d166180bc4..cc2145ea1968 100755
--- a/tools/testing/selftests/net/forwarding/bridge_blackhole_fdb.sh
+++ b/tools/testing/selftests/net/forwarding/bridge_blackhole_fdb.sh
@@ -8,26 +8,22 @@ source lib.sh

h1_create()
{
- simple_if_init $h1 192.0.2.1/24 2001:db8:1::1/64
- vlan_create $h1 100 v$h1 198.51.100.1/24
+ simple_if_init $h1 192.0.2.1/24
}

h1_destroy()
{
- vlan_destroy $h1 100
- simple_if_fini $h1 192.0.2.1/24 2001:db8:1::1/64
+ simple_if_fini $h1 192.0.2.1/24
}

h2_create()
{
- simple_if_init $h2 192.0.2.2/24 2001:db8:1::2/64
- vlan_create $h2 100 v$h2 198.51.100.2/24
+ simple_if_init $h2 192.0.2.2/24
}

h2_destroy()
{
- vlan_destroy $h2 100
- simple_if_fini $h2 192.0.2.2/24 2001:db8:1::2/64
+ simple_if_fini $h2 192.0.2.2/24
}

switch_create()

> +
> +switch_create()
> +{
> + ip link add dev br0 type bridge vlan_filtering 1
> +
> + ip link set dev $swp1 master br0
> + ip link set dev $swp2 master br0
> +
> + ip link set dev br0 up
> + ip link set dev $swp1 up
> + ip link set dev $swp2 up
> +
> + tc qdisc add dev $swp2 clsact
> +}
> +
> +switch_destroy()
> +{
> + tc qdisc del dev $swp2 clsact
> +
> + ip link set dev $swp2 down
> + ip link set dev $swp1 down
> +
> + ip link del dev br0
> +}
> +
> +setup_prepare()
> +{
> + h1=${NETIFS[p1]}
> + swp1=${NETIFS[p2]}
> + h2=${NETIFS[p3]}
> + swp2=${NETIFS[p4]}
> +
> + vrf_prepare
> +
> + h1_create
> + h2_create
> +
> + switch_create
> +}
> +
> +cleanup()
> +{
> + pre_cleanup
> +
> + switch_destroy
> +
> + h2_destroy
> + h1_destroy
> +
> + vrf_cleanup
> +}
> +
> +# Check that there is no egress with blackhole entry and that blackhole entries can be replaced

Wrap this to 80 columns:

# Check that there is no egress with blackhole entry and that blackhole entries
# can be replaced.

> +blackhole_fdb()
> +{
> + RET=0
> +
> + check_blackhole_fdb_support || return 0
> +
> + tc filter add dev $swp2 egress protocol ip pref 1 handle 1 flower \
> + dst_ip 192.0.2.2 ip_proto udp dst_port 12345 action pass
> +
> + $MZ $h1 -c 1 -p 128 -t udp "sp=54321,dp=12345" \
> + -a own -b `mac_get $h2` -A 192.0.2.1 -B 192.0.2.2 -q
> +
> + tc_check_packets "dev $swp2 egress" 1 1
> + check_err $? "Packet not seen on egress before adding blackhole entry"
> +
> + bridge fdb replace `mac_get $h2` dev br0 blackhole

vlan 1

> + bridge fdb get `mac_get $h2` br br0 | grep -q blackhole

vlan 1

> + check_err $? "Blackhole entry not found"
> +
> + $MZ $h1 -c 1 -p 128 -t udp "sp=54321,dp=12345" \
> + -a own -b `mac_get $h2` -A 192.0.2.1 -B 192.0.2.2 -q
> +
> + tc_check_packets "dev $swp2 egress" 1 1
> + check_err $? "Packet seen on egress after adding blackhole entry"
> +
> + # Check blackhole entries can be replaced.
> + bridge fdb replace `mac_get $h2` dev $swp2 master static

vlan 1

> + bridge fdb get `mac_get $h2` br br0 | grep -q blackhole

vlan 1

> + check_fail $? "Blackhole entry found after replacement"
> +
> + $MZ $h1 -c 1 -p 128 -t udp "sp=54321,dp=12345" \
> + -a own -b `mac_get $h2` -A 192.0.2.1 -B 192.0.2.2 -q
> +
> + tc_check_packets "dev $swp2 egress" 1 2
> + check_err $? "Packet not seen on egress after replacing blackhole entry"
> +
> + bridge fdb del `mac_get $h2` dev $swp2 master static

vlan 1

> + tc filter del dev $swp2 egress protocol ip pref 1 handle 1 flower
> +
> + log_test "Blackhole FDB entry"
> +}

Tested with veth pairs. Looks OK to me.

2022-10-13 12:46:18

by Ido Schimmel

[permalink] [raw]
Subject: Re: [PATCH v7 net-next 9/9] selftests: forwarding: add test of MAC-Auth Bypass to locked port tests

On Sun, Oct 09, 2022 at 07:40:52PM +0200, Hans J. Schultz wrote:
> +locked_port_mab()
> +{
> + RET=0
> + check_port_mab_support || return 0
> +
> + ping_do $h1 192.0.2.2
> + check_err $? "MAB: Ping did not work before locking port"
> +
> + bridge link set dev $swp1 locked on mab on
> +
> + ping_do $h1 192.0.2.2
> + check_fail $? "MAB: Ping worked on mab enabled port without FDB entry"
> +
> + bridge fdb get `mac_get $h1` vlan 1 dev $swp1 | grep "dev $swp1 vlan 1" | grep -q "locked"
> + check_err $? "MAB: No locked FDB entry after ping on mab enabled port"
> +
> + bridge fdb replace `mac_get $h1` dev $swp1 master static
> +
> + ping_do $h1 192.0.2.2
> + check_err $? "MAB: Ping did not work with FDB entry without locked flag"
> +
> + bridge fdb del `mac_get $h1` dev $swp1 master
> + bridge link set dev $swp1 locked off mab off
> +
> + log_test "Locked port MAB"
> +}
> +
> +# Check that entries cannot roam from an unlocked port to a locked port.
> +locked_port_station_move()
> +{
> + local mac=a0:b0:c0:c0:b0:a0
> +
> + RET=0
> + check_locked_port_support || return 0
> +
> + bridge link set dev $swp1 locked on learning on
> +
> + $MZ $h1 -q -c 5 -d 100msec -t udp -a $mac -b rand
> + bridge fdb show dev $swp1 | grep -q $mac
> + check_fail $? "Locked port station move: FDB entry on first injection"
> +
> + $MZ $h2 -q -c 5 -d 100msec -t udp -a $mac -b rand
> + bridge fdb get $mac vlan 1 dev $swp2 | grep "dev $swp2 vlan 1" | grep -q "master br0"
> + check_err $? "Locked port station move: Entry not found on unlocked port"
> +
> + $MZ $h1 -q -c 5 -d 100msec -t udp -a $mac -b rand
> + bridge fdb get $mac vlan 1 dev $swp1 | grep "dev $swp1 vlan 1" | grep -q "master br0"
> + check_fail $? "Locked port station move: entry roamed to locked port"
> +
> + bridge fdb del $mac vlan 1 dev $swp2 master
> + bridge link set dev $swp1 locked off learning off
> +
> + log_test "Locked port station move"
> +}
> +
> +# Roaming to and from a MAB enabled port should work if blackhole flag is not set
> +locked_port_mab_station_move()
> +{
> + local mac=10:20:30:30:20:10
> +
> + RET=0
> + check_port_mab_support || return 0
> +
> + bridge link set dev $swp1 locked on mab on
> +
> + $MZ $h1 -q -c 5 -d 100 mesc -t udp -a $mac -b rand
> + if bridge fdb show dev $swp1 | grep "$mac vlan 1" | grep -q "blackhole"; then
> + echo "SKIP: Roaming not possible with blackhole flag, skipping test..."
> + bridge link set dev $swp1 locked off mab off
> + return $ksft_skip
> + fi
> +
> + bridge fdb show dev $swp1 | grep "$mac vlan 1" | grep -q "locked"
> + check_err $? "MAB station move: no locked entry on first injection"
> +
> + $MZ $h2 -q -c 5 -d 100msec -t udp -a $mac -b rand
> + bridge fdb get $mac vlan 1 dev $swp1 | grep "dev $swp1 vlan 1" | grep -q "locked"
> + check_fail $? "MAB station move: locked entry did not move"
> +
> + bridge fdb get $mac vlan 1 dev $swp2 | grep "dev $swp2 vlan 1" | grep -q "locked"
> + check_fail $? "MAB station move: roamed entry to unlocked port had locked flag on"
> +
> + bridge fdb get $mac vlan 1 dev $swp2 | grep "dev $swp2 vlan 1" | grep -q "master br0"
> + check_err $? "MAB station move: roamed entry not found"
> +
> + bridge fdb del $mac vlan 1 dev $swp2 master
> + bridge link set dev $swp1 locked off mab off
> +
> + log_test "Locked port MAB station move"
> +}

Looks OK to me. I made some change to make sure we are using "bridge fdb
get" in a consistent manner instead of relying on iproute2 dump output
too much. Please consider including them in the next version.

FYI, I ran your version and mine with veth pairs and both are OK.

diff --git a/tools/testing/selftests/net/forwarding/bridge_locked_port.sh b/tools/testing/selftests/net/forwarding/bridge_locked_port.sh
index fbe558f25e44..f0bc0bcbc246 100755
--- a/tools/testing/selftests/net/forwarding/bridge_locked_port.sh
+++ b/tools/testing/selftests/net/forwarding/bridge_locked_port.sh
@@ -187,7 +187,7 @@ locked_port_mab()
ping_do $h1 192.0.2.2
check_fail $? "MAB: Ping worked on mab enabled port without FDB entry"

- bridge fdb get `mac_get $h1` vlan 1 dev $swp1 | grep "dev $swp1 vlan 1" | grep -q "locked"
+ bridge fdb get `mac_get $h1` br br0 vlan 1 | grep "dev $swp1" | grep -q "locked"
check_err $? "MAB: No locked FDB entry after ping on mab enabled port"

bridge fdb replace `mac_get $h1` dev $swp1 master static
@@ -212,15 +212,15 @@ locked_port_station_move()
bridge link set dev $swp1 locked on learning on

$MZ $h1 -q -c 5 -d 100msec -t udp -a $mac -b rand
- bridge fdb show dev $swp1 | grep -q $mac
+ bridge fdb get $mac br br0 vlan 1 &> /dev/null
check_fail $? "Locked port station move: FDB entry on first injection"

$MZ $h2 -q -c 5 -d 100msec -t udp -a $mac -b rand
- bridge fdb get $mac vlan 1 dev $swp2 | grep "dev $swp2 vlan 1" | grep -q "master br0"
+ bridge fdb get $mac br br0 vlan 1 | grep -q "dev $swp2"
check_err $? "Locked port station move: Entry not found on unlocked port"

$MZ $h1 -q -c 5 -d 100msec -t udp -a $mac -b rand
- bridge fdb get $mac vlan 1 dev $swp1 | grep "dev $swp1 vlan 1" | grep -q "master br0"
+ bridge fdb get $mac br br0 vlan 1 | grep -q "dev $swp1"
check_fail $? "Locked port station move: entry roamed to locked port"

bridge fdb del $mac vlan 1 dev $swp2 master
@@ -229,7 +229,8 @@ locked_port_station_move()
log_test "Locked port station move"
}

-# Roaming to and from a MAB enabled port should work if blackhole flag is not set
+# Check that entries can roam from a locked port if blackhole FDB flag is not
+# set.
locked_port_mab_station_move()
{
local mac=10:20:30:30:20:10
@@ -246,19 +247,16 @@ locked_port_mab_station_move()
return $ksft_skip
fi

- bridge fdb show dev $swp1 | grep "$mac vlan 1" | grep -q "locked"
+ bridge fdb get $mac br br0 vlan 1 | grep "dev $swp1" | grep -q "locked"
check_err $? "MAB station move: no locked entry on first injection"

$MZ $h2 -q -c 5 -d 100msec -t udp -a $mac -b rand
- bridge fdb get $mac vlan 1 dev $swp1 | grep "dev $swp1 vlan 1" | grep -q "locked"
- check_fail $? "MAB station move: locked entry did not move"
+ bridge fdb get $mac br br0 vlan 1 | grep -q "dev $swp2"
+ check_err $? "MAB station move: roamed entry not found"

- bridge fdb get $mac vlan 1 dev $swp2 | grep "dev $swp2 vlan 1" | grep -q "locked"
+ bridge fdb get $mac br br0 vlan 1 | grep -q "locked"
check_fail $? "MAB station move: roamed entry to unlocked port had locked flag on"

- bridge fdb get $mac vlan 1 dev $swp2 | grep "dev $swp2 vlan 1" | grep -q "master br0"
- check_err $? "MAB station move: roamed entry not found"
-
bridge fdb del $mac vlan 1 dev $swp2 master
bridge link set dev $swp1 locked off mab off

2022-10-13 13:49:58

by Ido Schimmel

[permalink] [raw]
Subject: Re: [PATCH v7 net-next 2/9] net: bridge: add blackhole fdb entry flag

On Sun, Oct 09, 2022 at 07:40:45PM +0200, Hans J. Schultz wrote:
> @@ -1018,8 +1020,9 @@ static bool fdb_handle_notify(struct net_bridge_fdb_entry *fdb, u8 notify)
> /* Update (create or replace) forwarding database entry */
> static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source,
> const u8 *addr, struct ndmsg *ndm, u16 flags, u16 vid,
> - struct nlattr *nfea_tb[])
> + u32 ext_flags, struct nlattr *nfea_tb[])
> {
> + bool blackhole = !!(ext_flags & NTF_EXT_BLACKHOLE);
> bool is_sticky = !!(ndm->ndm_flags & NTF_STICKY);
> bool refresh = !nfea_tb[NFEA_DONT_REFRESH];
> struct net_bridge_fdb_entry *fdb;
> @@ -1092,6 +1095,14 @@ static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source,
> modified = true;
> }
>
> + if (blackhole != test_bit(BR_FDB_BLACKHOLE, &fdb->flags)) {
> + change_bit(BR_FDB_BLACKHOLE, &fdb->flags);
> + modified = true;
> + }
> +
> + if (blackhole)
> + set_bit(BR_FDB_LOCAL, &fdb->flags);

We should instead validate earlier that NTF_EXT_BLACKHOLE is only
specified with NUD_PERMANENT. See more below.

> +
> if (test_and_clear_bit(BR_FDB_LOCKED, &fdb->flags))
> modified = true;
>
> @@ -1113,7 +1124,7 @@ static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source,
> static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge *br,
> struct net_bridge_port *p, const unsigned char *addr,
> u16 nlh_flags, u16 vid, struct nlattr *nfea_tb[],
> - struct netlink_ext_ack *extack)
> + u32 ext_flags, struct netlink_ext_ack *extack)
> {
> int err = 0;
>
> @@ -1138,9 +1149,12 @@ static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge *br,
> return -EINVAL;
> }
> err = br_fdb_external_learn_add(br, p, addr, vid, true);
> + } else if ((ext_flags & NTF_EXT_BLACKHOLE) && p) {
> + NL_SET_ERR_MSG_MOD(extack, "Blackhole FDB entry cannot be applied on a port");
> + return -EINVAL;

This is too late. I can do:

# bridge fdb add 00:aa:bb:cc:dd:ee dev dummy1 master extern_learn blackhole
# bridge fdb get 00:aa:bb:cc:dd:ee br br0
00:aa:bb:cc:dd:ee dev dummy1 extern_learn master br0

Nothing will explode, but it's not ideal either.

Since we force blackhole entries to be permanent they cannot be aged by
the kernel. I'm not sure what is the use case for user space adding
externally learned blackhole entries.

How about:

diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index d6f22e2e018a..9257a46544dd 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -1100,9 +1100,6 @@ static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source,
modified = true;
}

- if (blackhole)
- set_bit(BR_FDB_LOCAL, &fdb->flags);
-
if (test_and_clear_bit(BR_FDB_LOCKED, &fdb->flags))
modified = true;

@@ -1149,9 +1146,6 @@ static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge *br,
return -EINVAL;
}
err = br_fdb_external_learn_add(br, p, addr, vid, false, false, false, true);
- } else if ((ext_flags & NTF_EXT_BLACKHOLE) && p) {
- NL_SET_ERR_MSG_MOD(extack, "Blackhole FDB entry cannot be applied on a port");
- return -EINVAL;
} else {
spin_lock_bh(&br->hash_lock);
err = fdb_add_entry(br, p, addr, ndm, nlh_flags, vid, ext_flags, nfea_tb);
@@ -1214,6 +1208,21 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
return -EINVAL;
}

+ if (ext_flags & NTF_EXT_BLACKHOLE) {
+ if (!(ndm->ndm_state & NUD_PERMANENT)) {
+ NL_SET_ERR_MSG_MOD(extack, "Blackhole FDB entry must be permanent");
+ return -EINVAL;
+ }
+ if (p) {
+ NL_SET_ERR_MSG_MOD(extack, "Blackhole FDB entry cannot be applied on a port");
+ return -EINVAL;
+ }
+ if (ndm->ndm_flags & NTF_EXT_LEARNED) {
+ NL_SET_ERR_MSG_MOD(extack, "Blackhole FDB entry cannot be added as externally learned");
+ return -EINVAL;
+ }
+ }
+
if (tb[NDA_FDB_EXT_ATTRS]) {
attr = tb[NDA_FDB_EXT_ATTRS];
err = nla_parse_nested(nfea_tb, NFEA_MAX, attr,

With which I get:

# bridge fdb add 00:aa:bb:cc:dd:ee dev dummy1 master extern_learn blackhole
Error: bridge: Blackhole FDB entry cannot be applied on a port.

# bridge fdb add 00:aa:bb:cc:dd:ee dev br0 self extern_learn blackhole
Error: bridge: Blackhole FDB entry cannot be added as externally learned.

> } else {
> spin_lock_bh(&br->hash_lock);
> - err = fdb_add_entry(br, p, addr, ndm, nlh_flags, vid, nfea_tb);
> + err = fdb_add_entry(br, p, addr, ndm, nlh_flags, vid, ext_flags, nfea_tb);
> spin_unlock_bh(&br->hash_lock);
> }
>
> @@ -1219,10 +1233,10 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
>
> /* VID was specified, so use it. */
> err = __br_fdb_add(ndm, br, p, addr, nlh_flags, vid, nfea_tb,
> - extack);
> + ext_flags, extack);
> } else {
> err = __br_fdb_add(ndm, br, p, addr, nlh_flags, 0, nfea_tb,
> - extack);
> + ext_flags, extack);
> if (err || !vg || !vg->num_vlans)
> goto out;
>
> @@ -1234,7 +1248,7 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
> if (!br_vlan_should_use(v))
> continue;
> err = __br_fdb_add(ndm, br, p, addr, nlh_flags, v->vid,
> - nfea_tb, extack);
> + nfea_tb, ext_flags, extack);
> if (err)
> goto out;
> }
> diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
> index 068fced7693c..665d1d6bdc75 100644
> --- a/net/bridge/br_input.c
> +++ b/net/bridge/br_input.c
> @@ -193,8 +193,11 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
> if (dst) {
> unsigned long now = jiffies;
>
> - if (test_bit(BR_FDB_LOCAL, &dst->flags))
> + if (test_bit(BR_FDB_LOCAL, &dst->flags)) {
> + if (unlikely(test_bit(BR_FDB_BLACKHOLE, &dst->flags)))
> + goto drop;
> return br_pass_frame_up(skb);
> + }
>
> if (now != dst->used)
> dst->used = now;
> diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
> index 4ce8b8e5ae0b..e7a08657c7ed 100644
> --- a/net/bridge/br_private.h
> +++ b/net/bridge/br_private.h
> @@ -253,6 +253,7 @@ enum {
> BR_FDB_NOTIFY,
> BR_FDB_NOTIFY_INACTIVE,
> BR_FDB_LOCKED,
> + BR_FDB_BLACKHOLE,
> };
>
> struct net_bridge_fdb_key {
> diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
> index 8008ceb45605..ae641dfea5f2 100644
> --- a/net/core/rtnetlink.c
> +++ b/net/core/rtnetlink.c
> @@ -4054,7 +4054,7 @@ int ndo_dflt_fdb_add(struct ndmsg *ndm,
> if (tb[NDA_FLAGS_EXT])
> ext_flags = nla_get_u32(tb[NDA_FLAGS_EXT]);
>
> - if (ext_flags & NTF_EXT_LOCKED) {
> + if (ext_flags & (NTF_EXT_LOCKED | NTF_EXT_BLACKHOLE)) {
> netdev_info(dev, "invalid flags given to default FDB implementation\n");
> return err;
> }
> --
> 2.34.1
>

2022-10-13 14:59:17

by Ido Schimmel

[permalink] [raw]
Subject: Re: [PATCH v7 net-next 3/9] net: switchdev: add support for offloading of the FDB locked flag

On Sun, Oct 09, 2022 at 07:40:46PM +0200, Hans J. Schultz wrote:
> Add support for offloading of the MAB/MacAuth feature flag and the FDB
> locked flag which is used by the Mac-Auth/MAB feature.
>
> Signed-off-by: Hans J. Schultz <[email protected]>
> ---
> include/net/dsa.h | 2 ++
> include/net/switchdev.h | 1 +
> net/bridge/br.c | 4 ++--
> net/bridge/br_fdb.c | 12 ++++++++++--
> net/bridge/br_private.h | 2 +-
> net/bridge/br_switchdev.c | 3 ++-
> net/dsa/dsa_priv.h | 6 ++++--
> net/dsa/port.c | 10 ++++++----
> net/dsa/slave.c | 10 ++++++++--
> net/dsa/switch.c | 16 ++++++++--------
> 10 files changed, 44 insertions(+), 22 deletions(-)

There is more than one logical change here. I suggest splitting it to
make review easier:

1. A patch allowing the bridge driver to install locked entries notified
from device drivers. These changes:

include/net/switchdev.h | 1 +
net/bridge/br.c | 4 ++--
net/bridge/br_fdb.c | 12 ++++++++++--
net/bridge/br_private.h | 2 +-

And the br_switchdev_fdb_populate() hunk

2. A patch allowing DSA core to report locked entries to the bridge
driver

3. A patch adding the new MAB flag to BR_PORT_FLAGS_HW_OFFLOAD

4. A patch allowing DSA core to propagate the MAB flag to device drivers

[...]

> diff --git a/net/dsa/port.c b/net/dsa/port.c
> index e4a0513816bb..eab32b7a945a 100644
> --- a/net/dsa/port.c
> +++ b/net/dsa/port.c
> @@ -304,7 +304,7 @@ static int dsa_port_inherit_brport_flags(struct dsa_port *dp,
> struct netlink_ext_ack *extack)
> {
> const unsigned long mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
> - BR_BCAST_FLOOD | BR_PORT_LOCKED;
> + BR_BCAST_FLOOD;

Not sure how this is related to the patchset.

> struct net_device *brport_dev = dsa_port_to_bridge_port(dp);
> int flag, err;

2022-10-13 15:03:32

by Ido Schimmel

[permalink] [raw]
Subject: Re: [PATCH v7 net-next 4/9] net: switchdev: support offloading of the FDB blackhole flag

On Sun, Oct 09, 2022 at 07:40:47PM +0200, Hans J. Schultz wrote:
> Add support for offloading of the FDB blackhole flag.
>
> Signed-off-by: Hans J. Schultz <[email protected]>
> ---
> include/net/dsa.h | 1 +
> include/net/switchdev.h | 1 +
> net/bridge/br.c | 3 ++-
> net/bridge/br_fdb.c | 19 ++++++++++++++++---
> net/bridge/br_private.h | 3 ++-
> net/bridge/br_switchdev.c | 1 +
> net/dsa/dsa_priv.h | 4 ++--
> net/dsa/port.c | 22 ++++++++++++----------
> net/dsa/slave.c | 6 ++++--
> 9 files changed, 41 insertions(+), 19 deletions(-)

Too many changes at once. I suggest to split into:

1. A patch that allows the bridge driver to be notified about blackhole
entries from device drivers and also notifying it to drivers when added
from user space. These changes:

include/net/switchdev.h | 1 +
net/bridge/br.c | 3 ++-
net/bridge/br_fdb.c | 19 ++++++++++++++++---
net/bridge/br_private.h | 3 ++-
net/bridge/br_switchdev.c | 1 +

2. The DSA changes

2022-10-13 15:07:13

by Ido Schimmel

[permalink] [raw]
Subject: Re: [PATCH v7 net-next 9/9] selftests: forwarding: add test of MAC-Auth Bypass to locked port tests

On Wed, Oct 12, 2022 at 11:46:55AM +0200, [email protected] wrote:
> Ido, have you had time to look at this patch set, and do I need to release a
> v8 to fix those two forgotten statics and maybe also this new switchcore
> driver that was not there when I posted this patch set?

I don't know which changes you are referring to, but v8 should
incorporate all the changes requested so far. Do not post it as long as
net-next is closed (unless marked as RFC):

https://www.kernel.org/doc/html/latest/process/maintainer-netdev.html#how-often-do-changes-from-these-trees-make-it-to-the-mainline-linus-tree

2022-10-13 15:41:09

by Hans Schultz

[permalink] [raw]
Subject: Re: [PATCH v7 net-next 9/9] selftests: forwarding: add test of MAC-Auth Bypass to locked port tests

On 2022-10-13 16:28, Ido Schimmel wrote:
> On Wed, Oct 12, 2022 at 11:46:55AM +0200, [email protected]
> wrote:
>> Ido, have you had time to look at this patch set, and do I need to
>> release a
>> v8 to fix those two forgotten statics and maybe also this new
>> switchcore
>> driver that was not there when I posted this patch set?
>
> I don't know which changes you are referring to, but v8 should
> incorporate all the changes requested so far. Do not post it as long as
> net-next is closed (unless marked as RFC):

Ohh, I missed declaring two functions as static in chip.c, and
unfortunately my compiler did not give me any warnings...

What is the schedule for net-next to be open (I guess that it is closed
as of now)?

>
> https://www.kernel.org/doc/html/latest/process/maintainer-netdev.html#how-often-do-changes-from-these-trees-make-it-to-the-mainline-linus-tree

2022-10-13 18:44:43

by Ido Schimmel

[permalink] [raw]
Subject: Re: [PATCH v7 net-next 9/9] selftests: forwarding: add test of MAC-Auth Bypass to locked port tests

On Thu, Oct 13, 2022 at 05:17:42PM +0200, [email protected] wrote:
> What is the schedule for net-next to be open (I guess that it is closed as
> of now)?

After the merge window closes and 6.1-rc1 is released. Probably on
Monday.

2022-10-13 19:20:28

by Hans Schultz

[permalink] [raw]
Subject: Re: [PATCH v7 net-next 3/9] net: switchdev: add support for offloading of the FDB locked flag

On 2022-10-13 16:06, Ido Schimmel wrote:
>> diff --git a/net/dsa/port.c b/net/dsa/port.c
>> index e4a0513816bb..eab32b7a945a 100644
>> --- a/net/dsa/port.c
>> +++ b/net/dsa/port.c
>> @@ -304,7 +304,7 @@ static int dsa_port_inherit_brport_flags(struct
>> dsa_port *dp,
>> struct netlink_ext_ack *extack)
>> {
>> const unsigned long mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
>> - BR_BCAST_FLOOD | BR_PORT_LOCKED;
>> + BR_BCAST_FLOOD;
>
> Not sure how this is related to the patchset.
>

In general it is needed as a fix because of the way learning with locked
port is handled in the driver,
so as with MAB and also locked port in the future needing a non-zero
Port Association Vector (PAV)
for refresh etc to work, inheritance of the locked port flag is a bad
idea (say bug) and shouldn't have
been in the first place.

2022-10-18 07:07:04

by Ido Schimmel

[permalink] [raw]
Subject: Re: [PATCH v7 net-next 3/9] net: switchdev: add support for offloading of the FDB locked flag

On Thu, Oct 13, 2022 at 08:58:57PM +0200, [email protected] wrote:
> On 2022-10-13 16:06, Ido Schimmel wrote:
> > > diff --git a/net/dsa/port.c b/net/dsa/port.c
> > > index e4a0513816bb..eab32b7a945a 100644
> > > --- a/net/dsa/port.c
> > > +++ b/net/dsa/port.c
> > > @@ -304,7 +304,7 @@ static int dsa_port_inherit_brport_flags(struct
> > > dsa_port *dp,
> > > struct netlink_ext_ack *extack)
> > > {
> > > const unsigned long mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
> > > - BR_BCAST_FLOOD | BR_PORT_LOCKED;
> > > + BR_BCAST_FLOOD;
> >
> > Not sure how this is related to the patchset.
> >
>
> In general it is needed as a fix because of the way learning with locked
> port is handled in the driver,
> so as with MAB and also locked port in the future needing a non-zero Port
> Association Vector (PAV)
> for refresh etc to work, inheritance of the locked port flag is a bad idea
> (say bug) and shouldn't have
> been in the first place.

If it's a fix, then it needs to be submitted to 'net' tree.

2022-10-18 14:48:23

by Hans Schultz

[permalink] [raw]
Subject: Re: [PATCH v7 net-next 3/9] net: switchdev: add support for offloading of the FDB locked flag

On 2022-10-18 08:22, Ido Schimmel wrote:
> On Thu, Oct 13, 2022 at 08:58:57PM +0200, [email protected]
> wrote:
>> On 2022-10-13 16:06, Ido Schimmel wrote:
>> > > diff --git a/net/dsa/port.c b/net/dsa/port.c
>> > > index e4a0513816bb..eab32b7a945a 100644
>> > > --- a/net/dsa/port.c
>> > > +++ b/net/dsa/port.c
>> > > @@ -304,7 +304,7 @@ static int dsa_port_inherit_brport_flags(struct
>> > > dsa_port *dp,
>> > > struct netlink_ext_ack *extack)
>> > > {
>> > > const unsigned long mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
>> > > - BR_BCAST_FLOOD | BR_PORT_LOCKED;
>> > > + BR_BCAST_FLOOD;
>> >
>> > Not sure how this is related to the patchset.
>> >
>>
>> In general it is needed as a fix because of the way learning with
>> locked
>> port is handled in the driver,
>> so as with MAB and also locked port in the future needing a non-zero
>> Port
>> Association Vector (PAV)
>> for refresh etc to work, inheritance of the locked port flag is a bad
>> idea
>> (say bug) and shouldn't have
>> been in the first place.
>
> If it's a fix, then it needs to be submitted to 'net' tree.

It is a 'fix' for this patch set, as it changes
mv88e6xxx_port_set_lock() to need this change.
It is not strictly necessary to change it for earlier hehaviour.

2022-10-18 14:53:18

by Hans Schultz

[permalink] [raw]
Subject: Re: [PATCH v7 net-next 3/9] net: switchdev: add support for offloading of the FDB locked flag

On 2022-10-13 16:06, Ido Schimmel wrote:
> On Sun, Oct 09, 2022 at 07:40:46PM +0200, Hans J. Schultz wrote:
>> Add support for offloading of the MAB/MacAuth feature flag and the FDB
>> locked flag which is used by the Mac-Auth/MAB feature.
>>
>> Signed-off-by: Hans J. Schultz <[email protected]>
>> ---
>> include/net/dsa.h | 2 ++
>> include/net/switchdev.h | 1 +
>> net/bridge/br.c | 4 ++--
>> net/bridge/br_fdb.c | 12 ++++++++++--
>> net/bridge/br_private.h | 2 +-
>> net/bridge/br_switchdev.c | 3 ++-
>> net/dsa/dsa_priv.h | 6 ++++--
>> net/dsa/port.c | 10 ++++++----
>> net/dsa/slave.c | 10 ++++++++--
>> net/dsa/switch.c | 16 ++++++++--------
>> 10 files changed, 44 insertions(+), 22 deletions(-)
>
> There is more than one logical change here. I suggest splitting it to
> make review easier:
>
> 1. A patch allowing the bridge driver to install locked entries
> notified
> from device drivers. These changes:
>
> include/net/switchdev.h | 1 +
> net/bridge/br.c | 4 ++--
> net/bridge/br_fdb.c | 12 ++++++++++--
> net/bridge/br_private.h | 2 +-
>
> And the br_switchdev_fdb_populate() hunk
>
> 2. A patch allowing DSA core to report locked entries to the bridge
> driver

2. This requires no code in the DSA layer as the bridge listens directly
to the
kernel switchdev notifications.

>
> 3. A patch adding the new MAB flag to BR_PORT_FLAGS_HW_OFFLOAD
>
> 4. A patch allowing DSA core to propagate the MAB flag to device
> drivers
>
> [...]
>
>> diff --git a/net/dsa/port.c b/net/dsa/port.c
>> index e4a0513816bb..eab32b7a945a 100644
>> --- a/net/dsa/port.c
>> +++ b/net/dsa/port.c
>> @@ -304,7 +304,7 @@ static int dsa_port_inherit_brport_flags(struct
>> dsa_port *dp,
>> struct netlink_ext_ack *extack)
>> {
>> const unsigned long mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
>> - BR_BCAST_FLOOD | BR_PORT_LOCKED;
>> + BR_BCAST_FLOOD;
>
> Not sure how this is related to the patchset.
>
>> struct net_device *brport_dev = dsa_port_to_bridge_port(dp);
>> int flag, err;