From: Hans Schultz <hidden> Date: 2022-02-18 15:52:44
This series starts by adding support for SA filtering to the bridge,
which is then allowed to be offloaded to switchdev devices. Furthermore
an offloading implementation is supplied for the mv88e6xxx driver.
Public Local Area Networks are often deployed such that there is a
risk of unauthorized or unattended clients getting access to the LAN.
To prevent such access we introduce SA filtering, such that ports
designated as secure ports are set in locked mode, so that only
authorized source MAC addresses are given access by adding them to
the bridges forwarding database. Incoming packets with source MAC
addresses that are not in the forwarding database of the bridge are
discarded. It is then the task of user space daemons to populate the
bridge's forwarding database with static entries of authorized entities.
The most common approach is to use the IEEE 802.1X protocol to take
care of the authorization of allowed users to gain access by opening
for the source address of the authorized host.
With the current use of the bridge parameter in hostapd, there is
a limitation in using this for IEEE 802.1X port authentication. It
depends on hostapd attaching the port on which it has a successful
authentication to the bridge, but that only allows for a single
authentication per port. This patch set allows for the use of
IEEE 802.1X port authentication in a more general network context with
multiple 802.1X aware hosts behind a single port as depicted, which is
a commonly used commercial use-case, as it is only the number of
available entries in the forwarding database that limits the number of
authenticated clients.
+--------------------------------+
| |
| Bridge/Authenticator |
| |
+-------------+------------------+
802.1X port |
|
|
+------+-------+
| |
| Hub/Switch |
| |
+-+----------+-+
| |
+--+--+ +--+--+
| | | |
Hosts | a | | b | . . .
| | | |
+-----+ +-----+
The 802.1X standard involves three different components, a Supplicant
(Host), an Authenticator (Network Access Point) and an Authentication
Server which is typically a Radius server. This patch set thus enables
the bridge module together with an authenticator application to serve
as an Authenticator on designated ports.
For the bridge to become an IEEE 802.1X Authenticator, a solution using
hostapd with the bridge driver can be found at
https://github.com/westermo/hostapd/tree/bridge_driver .
The relevant components work transparently in relation to if it is the
bridge module or the offloaded switchcore case that is in use.
Hans Schultz (5):
net: bridge: Add support for bridge port in locked mode
net: bridge: Add support for offloading of locked port flag
net: dsa: Add support for offloaded locked port flag
net: dsa: mv88e6xxx: Add support for bridge port locked mode
selftests: forwarding: tests of locked port feature
drivers/net/dsa/mv88e6xxx/chip.c | 9 +-
drivers/net/dsa/mv88e6xxx/port.c | 33 ++++
drivers/net/dsa/mv88e6xxx/port.h | 9 +-
include/linux/if_bridge.h | 1 +
include/uapi/linux/if_link.h | 1 +
net/bridge/br_input.c | 10 +-
net/bridge/br_netlink.c | 6 +-
net/bridge/br_switchdev.c | 2 +-
net/dsa/port.c | 4 +-
.../testing/selftests/net/forwarding/Makefile | 1 +
.../net/forwarding/bridge_locked_port.sh | 174 ++++++++++++++++++
tools/testing/selftests/net/forwarding/lib.sh | 16 ++
12 files changed, 259 insertions(+), 7 deletions(-)
create mode 100755 tools/testing/selftests/net/forwarding/bridge_locked_port.sh
--
2.30.2
From: Hans Schultz <hidden> Date: 2022-02-18 15:52:56
In a 802.1X scenario, clients connected to a bridge port shall not
be allowed to have traffic forwarded until fully authenticated.
A static fdb entry of the clients MAC address for the bridge port
unlocks the client and allows bidirectional communication.
This scenario is facilitated with setting the bridge port in locked
mode, which is also supported by various switchcore chipsets.
Signed-off-by: Hans Schultz <redacted>
---
include/linux/if_bridge.h | 1 +
include/uapi/linux/if_link.h | 1 +
net/bridge/br_input.c | 10 +++++++++-
net/bridge/br_netlink.c | 6 +++++-
4 files changed, 16 insertions(+), 2 deletions(-)
@@ -81,6 +81,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skbif(!p||p->state==BR_STATE_DISABLED)gotodrop;+br=p->br;brmctx=&p->br->multicast_ctx;pmctx=&p->multicast_ctx;state=p->state;
@@ -88,10 +89,17 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb&state,&vlan))gotoout;+if(p->flags&BR_PORT_LOCKED){+structnet_bridge_fdb_entry*fdb_src=+br_fdb_find_rcu(br,eth_hdr(skb)->h_source,vid);+if(!fdb_src||READ_ONCE(fdb_src->dst)!=p||+test_bit(BR_FDB_LOCAL,&fdb_src->flags))+gotodrop;+}+nbp_switchdev_frame_mark(p,skb);/* insert into forwarding database after filtering to avoid spoofing */-br=p->br;if(p->flags&BR_LEARNING)br_fdb_update(br,p,eth_hdr(skb)->h_source,vid,0);
From: Hans Schultz <hidden> Date: 2022-02-18 15:53:06
Various switchcores support setting ports in locked mode, so that
clients behind locked ports cannot send traffic through the port
unless a fdb entry is added with the clients MAC address.
Signed-off-by: Hans Schultz <redacted>
---
net/bridge/br_switchdev.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Hans Schultz <hidden> Date: 2022-02-18 15:53:21
Among the switchcores that support this feature is the Marvell
mv88e6xxx family.
Signed-off-by: Hans Schultz <redacted>
---
net/dsa/port.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
From: Hans Schultz <hidden> Date: 2022-02-18 15:53:31
Supporting bridge ports in locked mode using the drop on lock
feature in Marvell mv88e6xxx switchcores is described in the
'88E6096/88E6097/88E6097F Datasheet', sections 4.4.6, 4.4.7 and
5.1.2.1 (Drop on Lock).
This feature is implemented here facilitated by the locked port flag.
Signed-off-by: Hans Schultz <redacted>
---
drivers/net/dsa/mv88e6xxx/chip.c | 9 ++++++++-
drivers/net/dsa/mv88e6xxx/port.c | 33 ++++++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/port.h | 9 ++++++++-
3 files changed, 49 insertions(+), 2 deletions(-)
@@ -1234,6 +1234,39 @@ int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,returnerr;}+intmv88e6xxx_port_set_lock(structmv88e6xxx_chip*chip,intport,+boollocked)+{+u16reg;+interr;++err=mv88e6xxx_port_read(chip,port,MV88E6XXX_PORT_CTL0,®);+if(err)+returnerr;++reg&=~MV88E6XXX_PORT_CTL0_SA_FILT_MASK;+if(locked)+reg|=MV88E6XXX_PORT_CTL0_SA_FILT_DROP_ON_LOCK;++err=mv88e6xxx_port_write(chip,port,MV88E6XXX_PORT_CTL0,reg);+if(err)+returnerr;++err=mv88e6xxx_port_read(chip,port,MV88E6XXX_PORT_ASSOC_VECTOR,®);+if(err)+returnerr;++reg&=~MV88E6XXX_PORT_ASSOC_VECTOR_LOCKED_PORT;+if(locked)+reg|=MV88E6XXX_PORT_ASSOC_VECTOR_LOCKED_PORT;++err=mv88e6xxx_port_write(chip,port,MV88E6XXX_PORT_ASSOC_VECTOR,reg);+if(err)+returnerr;++return0;+}+intmv88e6xxx_port_set_8021q_mode(structmv88e6xxx_chip*chip,intport,u16mode){
From: Hans Schultz <hidden> Date: 2022-02-18 15:53:40
These tests check that the basic locked port feature works, so that no 'host'
can communicate (ping) through a locked port unless the MAC address of the
'host' interface is in the forwarding database of the bridge.
Signed-off-by: Hans Schultz <redacted>
---
.../testing/selftests/net/forwarding/Makefile | 1 +
.../net/forwarding/bridge_locked_port.sh | 174 ++++++++++++++++++
tools/testing/selftests/net/forwarding/lib.sh | 16 ++
3 files changed, 191 insertions(+)
create mode 100755 tools/testing/selftests/net/forwarding/bridge_locked_port.sh
@@ -0,0 +1,174 @@+#!/bin/bash+# SPDX-License-Identifier: GPL-2.0++ALL_TESTS="locked_port_ipv4 locked_port_ipv6 locked_port_vlan"+NUM_NETIFS=4+CHECK_TC="no"+sourcelib.sh++h1_create()+{+simple_if_init$h1192.0.2.1/242001:db8:1::1/64+vrf_create"vrf-vlan-h1"+iplinksetdevvrf-vlan-h1up+vlan_create$h1100vrf-vlan-h1192.0.3.1/242001:db8:3::1/64+}++h1_destroy()+{+vlan_destroy$h1100+simple_if_fini$h1192.0.2.1/242001:db8:1::1/64+}++h2_create()+{+simple_if_init$h2192.0.2.2/242001:db8:1::2/64+vrf_create"vrf-vlan-h2"+iplinksetdevvrf-vlan-h2up+vlan_create$h2100vrf-vlan-h2192.0.3.2/242001:db8:3::2/64+}++h2_destroy()+{+vlan_destroy$h2100+simple_if_fini$h2192.0.2.2/242001:db8:1::2/64+}++switch_create()+{+iplinkadddevbr0typebridgevlan_filtering1++iplinksetdev$swp1masterbr0+iplinksetdev$swp2masterbr0++iplinksetdevbr0up+iplinksetdev$swp1up+iplinksetdev$swp2up++bridgelinksetdev$swp1learningoff+}++switch_destroy()+{+iplinksetdev$swp2down+iplinksetdev$swp1down++iplinkdeldevbr0+}++setup_prepare()+{+h1=${NETIFS[p1]}+swp1=${NETIFS[p2]}++swp2=${NETIFS[p3]}+h2=${NETIFS[p4]}++vrf_prepare++h1_create+h2_create++switch_create+}++cleanup()+{+pre_cleanup++switch_destroy++h2_destroy+h1_destroy++vrf_cleanup+}++ifaddr()+{+ip-brlinkshowdev"$1"|awk'{ print($3); }'+}++locked_port_ipv4()+{+RET=0++check_locked_port_support||return0++ping_do$h1192.0.2.2+check_err$?"Ping didn't work when it should have"++bridgelinksetdev$swp1lockedon++ping_do$h1192.0.2.2+check_fail$?"Ping worked when it should not have"++bridgefdbadd`ifaddr$h1`dev$swp1masterstatic++ping_do$h1192.0.2.2+check_err$?"Ping didn't work when it should have"++bridgelinksetdev$swp1lockedoff+bridgefdbdel`ifaddr$h1`dev$swp1masterstatic+log_test"Locked port ipv4"+}++locked_port_vlan()+{+RET=0++check_locked_port_support||return0+check_vlan_filtering_support||return0++bridgevlanaddvid100dev$swp1tagged+bridgevlanaddvid100dev$swp2tagged++ping_do$h1.100192.0.3.2+check_err$?"Ping didn't work when it should have"++bridgelinksetdev$swp1lockedon+ping_do$h1.100192.0.3.2+check_fail$?"Ping worked when it should not have"++bridgefdbadd`ifaddr$h1`dev$swp1vlan100masterstatic++ping_do$h1.100192.0.3.2+check_err$?"Ping didn't work when it should have"++bridgelinksetdev$swp1lockedoff+bridgevlandelvid100dev$swp1+bridgevlandelvid100dev$swp2+bridgefdbdel`ifaddr$h1`dev$swp1vlan100masterstatic+log_test"Locked port vlan"+}++locked_port_ipv6()+{+RET=0+check_locked_port_support||return0++ping6_do$h12001:db8:1::2+check_err$?"Ping6 didn't work when it should have"++bridgelinksetdev$swp1lockedon++ping6_do$h12001:db8:1::2+check_fail$?"Ping worked when it should not have"++bridgefdbadd`ifaddr$h1`dev$swp1masterstatic+ping6_do$h12001:db8:1::2+check_err$?"Ping didn't work when it should have"++bridgelinksetdev$swp1lockedoff+bridgefdbdel`ifaddr$h1`dev$swp1masterstatic+log_test"Locked port ipv6"+}++trapcleanupEXIT++setup_prepare+setup_wait++tests_run++exit$EXIT_STATUS
@@ -125,6 +125,22 @@ check_ethtool_lanes_support()fi}+check_locked_port_support()+{+if!bridge-dlinkshow|grep-q" locked";then+echo"SKIP: iproute2 too old; Locked port feature not supported."+return$ksft_skip+fi+}++check_vlan_filtering_support()+{+if!bridge-dvlanshow|grep-q"state forwarding";then+echo"SKIP: vlan filtering not supported."+return$ksft_skip+fi+}+if[["$(id-u)"-ne0]];thenecho"SKIP: need root privileges"exit$ksft_skip
These tests check that the basic locked port feature works, so that no 'host'
can communicate (ping) through a locked port unless the MAC address of the
'host' interface is in the forwarding database of the bridge.
Signed-off-by: Hans Schultz <redacted>
---
.../testing/selftests/net/forwarding/Makefile | 1 +
.../net/forwarding/bridge_locked_port.sh | 174 ++++++++++++++++++
tools/testing/selftests/net/forwarding/lib.sh | 16 ++
3 files changed, 191 insertions(+)
create mode 100755 tools/testing/selftests/net/forwarding/bridge_locked_port.sh
From: Nikolay Aleksandrov <hidden> Date: 2022-02-19 09:47:12
On 18/02/2022 17:51, Hans Schultz wrote:
In a 802.1X scenario, clients connected to a bridge port shall not
be allowed to have traffic forwarded until fully authenticated.
A static fdb entry of the clients MAC address for the bridge port
unlocks the client and allows bidirectional communication.
This scenario is facilitated with setting the bridge port in locked
mode, which is also supported by various switchcore chipsets.
Signed-off-by: Hans Schultz <redacted>
---
include/linux/if_bridge.h | 1 +
include/uapi/linux/if_link.h | 1 +
net/bridge/br_input.c | 10 +++++++++-
net/bridge/br_netlink.c | 6 +++++-
4 files changed, 16 insertions(+), 2 deletions(-)
Hi Hans,
The patch looks good overall, I have one minor cosmetic comment below.
From: Nikolay Aleksandrov <hidden> Date: 2022-02-19 09:47:32
On 18/02/2022 17:51, Hans Schultz wrote:
quoted hunk
Various switchcores support setting ports in locked mode, so that
clients behind locked ports cannot send traffic through the port
unless a fdb entry is added with the clients MAC address.
Signed-off-by: Hans Schultz <redacted>
---
net/bridge/br_switchdev.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Nikolay Aleksandrov <hidden> Date: 2022-02-19 09:49:21
On 18/02/2022 17:51, Hans Schultz wrote:
quoted hunk
These tests check that the basic locked port feature works, so that no 'host'
can communicate (ping) through a locked port unless the MAC address of the
'host' interface is in the forwarding database of the bridge.
Signed-off-by: Hans Schultz <redacted>
---
.../testing/selftests/net/forwarding/Makefile | 1 +
.../net/forwarding/bridge_locked_port.sh | 174 ++++++++++++++++++
tools/testing/selftests/net/forwarding/lib.sh | 16 ++
3 files changed, 191 insertions(+)
create mode 100755 tools/testing/selftests/net/forwarding/bridge_locked_port.sh
From: Vladimir Oltean <olteanv@gmail.com> Date: 2022-02-19 09:57:04
On Fri, Feb 18, 2022 at 04:51:46PM +0100, Hans Schultz wrote:
Among the switchcores that support this feature is the Marvell
mv88e6xxx family.
Signed-off-by: Hans Schultz <redacted>
---
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
Although this doesn't "add support for offloaded locked ports", that
passes right through with no DSA-level filtering, from
SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS to dsa_port_bridge_flags(),
to ds->ops->port_bridge_flags().
Rather, a clearer description of what this does is:
net: dsa: include BR_PORT_LOCKED in the list of synced brport flags
Make sure the DSA switch driver gets notified of changes to the
BR_PORT_LOCKED flag as well, for the case when a DSA port joins or
leaves a LAG that is a bridge port.
@@ -1234,6 +1234,39 @@ int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,returnerr;}+intmv88e6xxx_port_set_lock(structmv88e6xxx_chip*chip,intport,+boollocked)+{+u16reg;+interr;++err=mv88e6xxx_port_read(chip,port,MV88E6XXX_PORT_CTL0,®);+if(err)+returnerr;++reg&=~MV88E6XXX_PORT_CTL0_SA_FILT_MASK;+if(locked)+reg|=MV88E6XXX_PORT_CTL0_SA_FILT_DROP_ON_LOCK;++err=mv88e6xxx_port_write(chip,port,MV88E6XXX_PORT_CTL0,reg);+if(err)+returnerr;++err=mv88e6xxx_port_read(chip,port,MV88E6XXX_PORT_ASSOC_VECTOR,®);+if(err)+returnerr;++reg&=~MV88E6XXX_PORT_ASSOC_VECTOR_LOCKED_PORT;+if(locked)+reg|=MV88E6XXX_PORT_ASSOC_VECTOR_LOCKED_PORT;++err=mv88e6xxx_port_write(chip,port,MV88E6XXX_PORT_ASSOC_VECTOR,reg);
On Fri, Feb 18, 2022 at 04:51:48PM +0100, Hans Schultz wrote:
These tests check that the basic locked port feature works, so that no 'host'
can communicate (ping) through a locked port unless the MAC address of the
'host' interface is in the forwarding database of the bridge.
Thanks for adding the test. I assume this was tested with both mv88e6xxx
and veth?
In the tests we try to use only addresses specified in RFC 5737. Instead
of 192.0.3.0/24 I suggest 198.51.100.0/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
+ vrf_create "vrf-vlan-h2"
+ ip link set dev vrf-vlan-h2 up
+ vlan_create $h2 100 vrf-vlan-h2 192.0.3.2/24 2001:db8:3::2/64
+}
+
+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
+
+ bridge link set dev $swp1 learning off
+}
+
+switch_destroy()
+{
+ 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]}
+
+ swp2=${NETIFS[p3]}
+ h2=${NETIFS[p4]}
+
+ vrf_prepare
+
+ h1_create
+ h2_create
+
+ switch_create
+}
+
+cleanup()
+{
+ pre_cleanup
+
+ switch_destroy
+
+ h2_destroy
+ h1_destroy
+
+ vrf_cleanup
+}
+
+ifaddr()
We already have mac_get()
+{
+ ip -br link show dev "$1" | awk '{ print($3); }'
+}
+
+locked_port_ipv4()
+{
+ RET=0
+
+ check_locked_port_support || return 0
+
+ ping_do $h1 192.0.2.2
+ check_err $? "Ping didn't work when it should have"
Better to use unique error messages that pinpoint the problem:
"Ping did not work before locking port"
+
+ bridge link set dev $swp1 locked on
+
+ ping_do $h1 192.0.2.2
+ check_fail $? "Ping worked when it should not have"
"Ping worked after locking port, but before adding a FDB entry"
bridge fdb add $(mac_get $h1) dev $swp1 master static
+
+ ping_do $h1 192.0.2.2
+ check_err $? "Ping didn't work when it should have"
"Ping did not work after locking port and adding a FDB entry"
+
+ bridge link set dev $swp1 locked off
+ bridge fdb del `ifaddr $h1` dev $swp1 master static
I suggest to add another test case here to see that ping works after
unlocking the port and removing the FDB entry
Same comments on the other test cases
Why this check is needed? The bridge was already created with
"vlan_filtering 1"
+
+ bridge vlan add vid 100 dev $swp1 tagged
Not familiar with "tagged" keyword. I believe iproute2 ignores it.
Please drop it
quoted hunk
+ bridge vlan add vid 100 dev $swp2 tagged
+
+ ping_do $h1.100 192.0.3.2
+ check_err $? "Ping didn't work when it should have"
+
+ bridge link set dev $swp1 locked on
+ ping_do $h1.100 192.0.3.2
+ check_fail $? "Ping worked when it should not have"
+
+ bridge fdb add `ifaddr $h1` dev $swp1 vlan 100 master static
+
+ ping_do $h1.100 192.0.3.2
+ check_err $? "Ping didn't work when it should have"
+
+ bridge link set dev $swp1 locked off
+ bridge vlan del vid 100 dev $swp1
+ bridge vlan del vid 100 dev $swp2
+ bridge fdb del `ifaddr $h1` dev $swp1 vlan 100 master static
+ log_test "Locked port vlan"
+}
+
+locked_port_ipv6()
+{
+ RET=0
+ check_locked_port_support || return 0
+
+ ping6_do $h1 2001:db8:1::2
+ check_err $? "Ping6 didn't work when it should have"
+
+ bridge link set dev $swp1 locked on
+
+ ping6_do $h1 2001:db8:1::2
+ check_fail $? "Ping worked when it should not have"
+
+ bridge fdb add `ifaddr $h1` dev $swp1 master static
+ ping6_do $h1 2001:db8:1::2
+ check_err $? "Ping didn't work when it should have"
+
+ bridge link set dev $swp1 locked off
+ bridge fdb del `ifaddr $h1` dev $swp1 master static
+ log_test "Locked port ipv6"
+}
+
+trap cleanup EXIT
+
+setup_prepare
+setup_wait
+
+tests_run
+
+exit $EXIT_STATUS
@@ -125,6 +125,22 @@ check_ethtool_lanes_support()fi}+check_locked_port_support()+{+if!bridge-dlinkshow|grep-q" locked";then+echo"SKIP: iproute2 too old; Locked port feature not supported."+return$ksft_skip+fi+}++check_vlan_filtering_support()+{+if!bridge-dvlanshow|grep-q"state forwarding";then+echo"SKIP: vlan filtering not supported."+return$ksft_skip+fi+}+if[["$(id-u)"-ne0]];thenecho"SKIP: need root privileges"exit$ksft_skip
On Fri, Feb 18, 2022 at 04:51:44PM +0100, Hans Schultz wrote:
In a 802.1X scenario, clients connected to a bridge port shall not
be allowed to have traffic forwarded until fully authenticated.
A static fdb entry of the clients MAC address for the bridge port
unlocks the client and allows bidirectional communication.
This scenario is facilitated with setting the bridge port in locked
mode, which is also supported by various switchcore chipsets.
Signed-off-by: Hans Schultz <redacted>
With Nik's comment fixed:
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
On Fri, Feb 18, 2022 at 04:51:45PM +0100, Hans Schultz wrote:
Various switchcores support setting ports in locked mode, so that
clients behind locked ports cannot send traffic through the port
unless a fdb entry is added with the clients MAC address.
Signed-off-by: Hans Schultz <redacted>
@@ -1234,6 +1234,39 @@ int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,returnerr;}+intmv88e6xxx_port_set_lock(structmv88e6xxx_chip*chip,intport,+boollocked)+{+u16reg;+interr;++err=mv88e6xxx_port_read(chip,port,MV88E6XXX_PORT_CTL0,®);+if(err)+returnerr;++reg&=~MV88E6XXX_PORT_CTL0_SA_FILT_MASK;+if(locked)+reg|=MV88E6XXX_PORT_CTL0_SA_FILT_DROP_ON_LOCK;++err=mv88e6xxx_port_write(chip,port,MV88E6XXX_PORT_CTL0,reg);+if(err)+returnerr;++err=mv88e6xxx_port_read(chip,port,MV88E6XXX_PORT_ASSOC_VECTOR,®);+if(err)+returnerr;++reg&=~MV88E6XXX_PORT_ASSOC_VECTOR_LOCKED_PORT;+if(locked)+reg|=MV88E6XXX_PORT_ASSOC_VECTOR_LOCKED_PORT;++err=mv88e6xxx_port_write(chip,port,MV88E6XXX_PORT_ASSOC_VECTOR,reg);
return mv88e6xxx_port_write(...);
Not familiar with mv88e6xxx, but shouldn't there be a rollback of
previous operations? Specifically mv88e6xxx_port_write()
From: Hans Schultz <hidden> Date: 2022-02-21 09:58:45
On sön, feb 20, 2022 at 11:12, Ido Schimmel [off-list ref] wrote:
On Fri, Feb 18, 2022 at 04:51:48PM +0100, Hans Schultz wrote:
quoted
These tests check that the basic locked port feature works, so that no 'host'
can communicate (ping) through a locked port unless the MAC address of the
'host' interface is in the forwarding database of the bridge.
Thanks for adding the test. I assume this was tested with both mv88e6xxx
and veth?
In the tests we try to use only addresses specified in RFC 5737. Instead
of 192.0.3.0/24 I suggest 198.51.100.0/24
quoted
+}
+
+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
+ vrf_create "vrf-vlan-h2"
+ ip link set dev vrf-vlan-h2 up
+ vlan_create $h2 100 vrf-vlan-h2 192.0.3.2/24 2001:db8:3::2/64
+}
+
+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
+
+ bridge link set dev $swp1 learning off
+}
+
+switch_destroy()
+{
+ 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]}
+
+ swp2=${NETIFS[p3]}
+ h2=${NETIFS[p4]}
+
+ vrf_prepare
+
+ h1_create
+ h2_create
+
+ switch_create
+}
+
+cleanup()
+{
+ pre_cleanup
+
+ switch_destroy
+
+ h2_destroy
+ h1_destroy
+
+ vrf_cleanup
+}
+
+ifaddr()
We already have mac_get()
quoted
+{
+ ip -br link show dev "$1" | awk '{ print($3); }'
+}
+
+locked_port_ipv4()
+{
+ RET=0
+
+ check_locked_port_support || return 0
+
+ ping_do $h1 192.0.2.2
+ check_err $? "Ping didn't work when it should have"
Better to use unique error messages that pinpoint the problem:
"Ping did not work before locking port"
quoted
+
+ bridge link set dev $swp1 locked on
+
+ ping_do $h1 192.0.2.2
+ check_fail $? "Ping worked when it should not have"
"Ping worked after locking port, but before adding a FDB entry"
bridge fdb add $(mac_get $h1) dev $swp1 master static
quoted
+
+ ping_do $h1 192.0.2.2
+ check_err $? "Ping didn't work when it should have"
"Ping did not work after locking port and adding a FDB entry"
quoted
+
+ bridge link set dev $swp1 locked off
+ bridge fdb del `ifaddr $h1` dev $swp1 master static
I suggest to add another test case here to see that ping works after
unlocking the port and removing the FDB entry
Same comments on the other test cases
Why this check is needed? The bridge was already created with
"vlan_filtering 1"
quoted
+
+ bridge vlan add vid 100 dev $swp1 tagged
Not familiar with "tagged" keyword. I believe iproute2 ignores it.
Please drop it
quoted
+ bridge vlan add vid 100 dev $swp2 tagged
+
+ ping_do $h1.100 192.0.3.2
+ check_err $? "Ping didn't work when it should have"
+
+ bridge link set dev $swp1 locked on
+ ping_do $h1.100 192.0.3.2
+ check_fail $? "Ping worked when it should not have"
+
+ bridge fdb add `ifaddr $h1` dev $swp1 vlan 100 master static
+
+ ping_do $h1.100 192.0.3.2
+ check_err $? "Ping didn't work when it should have"
+
+ bridge link set dev $swp1 locked off
+ bridge vlan del vid 100 dev $swp1
+ bridge vlan del vid 100 dev $swp2
+ bridge fdb del `ifaddr $h1` dev $swp1 vlan 100 master static
+ log_test "Locked port vlan"
+}
+
+locked_port_ipv6()
+{
+ RET=0
+ check_locked_port_support || return 0
+
+ ping6_do $h1 2001:db8:1::2
+ check_err $? "Ping6 didn't work when it should have"
+
+ bridge link set dev $swp1 locked on
+
+ ping6_do $h1 2001:db8:1::2
+ check_fail $? "Ping worked when it should not have"
+
+ bridge fdb add `ifaddr $h1` dev $swp1 master static
+ ping6_do $h1 2001:db8:1::2
+ check_err $? "Ping didn't work when it should have"
+
+ bridge link set dev $swp1 locked off
+ bridge fdb del `ifaddr $h1` dev $swp1 master static
+ log_test "Locked port ipv6"
+}
+
+trap cleanup EXIT
+
+setup_prepare
+setup_wait
+
+tests_run
+
+exit $EXIT_STATUS
@@ -125,6 +125,22 @@ check_ethtool_lanes_support()fi}+check_locked_port_support()+{+if!bridge-dlinkshow|grep-q" locked";then+echo"SKIP: iproute2 too old; Locked port feature not supported."+return$ksft_skip+fi+}++check_vlan_filtering_support()+{+if!bridge-dvlanshow|grep-q"state forwarding";then+echo"SKIP: vlan filtering not supported."+return$ksft_skip+fi+}+if[["$(id-u)"-ne0]];thenecho"SKIP: need root privileges"exit$ksft_skip
@@ -1234,6 +1234,39 @@ int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,returnerr;}+intmv88e6xxx_port_set_lock(structmv88e6xxx_chip*chip,intport,+boollocked)+{+u16reg;+interr;++err=mv88e6xxx_port_read(chip,port,MV88E6XXX_PORT_CTL0,®);+if(err)+returnerr;++reg&=~MV88E6XXX_PORT_CTL0_SA_FILT_MASK;+if(locked)+reg|=MV88E6XXX_PORT_CTL0_SA_FILT_DROP_ON_LOCK;++err=mv88e6xxx_port_write(chip,port,MV88E6XXX_PORT_CTL0,reg);+if(err)+returnerr;++err=mv88e6xxx_port_read(chip,port,MV88E6XXX_PORT_ASSOC_VECTOR,®);+if(err)+returnerr;++reg&=~MV88E6XXX_PORT_ASSOC_VECTOR_LOCKED_PORT;+if(locked)+reg|=MV88E6XXX_PORT_ASSOC_VECTOR_LOCKED_PORT;++err=mv88e6xxx_port_write(chip,port,MV88E6XXX_PORT_ASSOC_VECTOR,reg);
return mv88e6xxx_port_write(...);
Not familiar with mv88e6xxx, but shouldn't there be a rollback of
previous operations? Specifically mv88e6xxx_port_write()
If a register write function fails, I don't think that it would make
sense to try and resolve the situation by additional register write
calls (rollback).