mlxsw: Manage RIF across PVID changes
Subsystems (5)
Petr Machata
maintainercover mlxsw: Manage RIF across PVID changes
The mlxsw driver currently makes the assumption that the user applies configuration in a bottom-up manner. Thus netdevices need to be added to the bridge before IP addresses are configured on that bridge or SVI added on top of it. Enslaving a netdevice to another netdevice that already has uppers is in fact forbidden by mlxsw for this reason. Despite this safety, it is rather easy to get into situations where the offloaded configuration is just plain wrong.
As an example, take a front panel port, configure an IP address: it gets a RIF. Now enslave the port to the bridge, and the RIF is gone. Remove the port from the bridge again, but the RIF never comes back. There is a number of similar situations, where changing the configuration there and back utterly breaks the offload.
The situation is going to be made better by implementing a range of replays and post-hoc offloads.
In this patch set, address the ordering issues related to creation of bridge RIFs. Currently, mlxsw has several shortcomings with regards to RIF handling due to PVID changes:
- In order to cause RIF for a bridge device to be created, the user is expected first to set PVID, then to add an IP address. The reverse ordering is disallowed, which is not very user-friendly.
- When such bridge gets a VLAN upper whose VID was the same as the existing PVID, and this VLAN netdevice gets an IP address, a RIF is created for this netdevice. The new RIF is then assigned to the 802.1Q FID for the given VID. This results in a working configuration. However, then, when the VLAN netdevice is removed again, the RIF for the bridge itself is never reassociated to the PVID.
- PVID cannot be changed once the bridge has uppers. Presumably this is because the driver does not manage RIFs properly in face of PVID changes. However, as the previous point shows, it is still possible to get into invalid configurations.
This patch set addresses these issues and relaxes some of the ordering requirements that mlxsw had. The patch set proceeds as follows:
- In patch #1, pass extack to mlxsw_sp_br_ban_rif_pvid_change()
- To relax ordering between setting PVID and adding an IP address to a bridge, mlxsw must be able to request that a RIF is created with a given VLAN ID, instead of trying to deduce it from the current netdevice settings, which do not reflect the user-requested values yet. This is done in patches #2 and #3.
- Similarly, mlxsw_sp_inetaddr_bridge_event() will need to make decisions based on the user-requested value of PVID, not the current value. Thus in patches #4 and #5, add a new argument which carries the requested PVID value.
- Finally in patch #6 relax the ban on PVID changes when a bridge has uppers. Instead, add the logic necessary for creation of a RIF as a result of PVID change.
- Relevant selftests are presented afterwards. In patch #7 a preparatory helper is added to lib.sh. Patches #8, #9, #10 and #11 include selftests themselves.
Petr Machata (11):
mlxsw: spectrum_switchdev: Pass extack to
mlxsw_sp_br_ban_rif_pvid_change()
mlxsw: spectrum_router: Pass struct mlxsw_sp_rif_params to fid_get
mlxsw: spectrum_router: Take VID for VLAN FIDs from RIF params
mlxsw: spectrum_router: Adjust mlxsw_sp_inetaddr_vlan_event() coding
style
mlxsw: spectrum_router: mlxsw_sp_inetaddr_bridge_event: Add an
argument
mlxsw: spectrum_switchdev: Manage RIFs on PVID change
selftests: forwarding: lib: Add ping6_, ping_test_fails()
selftests: router_bridge: Add tests to remove and add PVID
selftests: router_bridge_vlan: Add PVID change test
selftests: router_bridge_vlan_upper_pvid: Add a new selftest
selftests: router_bridge_pvid_vlan_upper: Add a new selftest
.../ethernet/mellanox/mlxsw/spectrum_router.c | 169 +++++++++++++++-- .../ethernet/mellanox/mlxsw/spectrum_router.h | 4 + .../mellanox/mlxsw/spectrum_switchdev.c | 32 +--- .../testing/selftests/net/forwarding/Makefile | 2 + tools/testing/selftests/net/forwarding/lib.sh | 18 ++ .../selftests/net/forwarding/router_bridge.sh | 50 +++++ .../router_bridge_pvid_vlan_upper.sh | 155 ++++++++++++++++ .../net/forwarding/router_bridge_vlan.sh | 100 ++++++++-- .../router_bridge_vlan_upper_pvid.sh | 171 ++++++++++++++++++ 9 files changed, 643 insertions(+), 58 deletions(-) create mode 100755 tools/testing/selftests/net/forwarding/router_bridge_pvid_vlan_upper.sh create mode 100755 tools/testing/selftests/net/forwarding/router_bridge_vlan_upper_pvid.sh
Signature · 1 line
2.40.1
Petr Machata
maintainerPATCH 1/11 mlxsw: spectrum_switchdev: Pass extack to mlxsw_sp_br_ban_rif_pvid_change()
Currently the reason for rejection of PVID manipulation is dumped to syslog, and a generic -EBUSY is returned to the userspace. But switchdev_handle_port_obj_add(), through which we get to mlxsw_sp_port_vlans_add(), handles extack just fine, and we can pass the message this way.
This improves visibility into reasons why the request to change PVID was rejected. Before the change:
# bridge vlan add dev br vid 2 self pvid untagged RTNETLINK answers: Device or resource busy (plus a syslog line)
After the change:
# bridge vlan add dev br vid 2 self pvid untagged Error: mlxsw_spectrum: Can't change PVID, it's used by router interface.
Note that this particular error message is going away in the following patches. However the ability to pass error messages through extack will be useful more broadly for communicating in particular reasons why a RIF failed to be created.
--- .../net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +6 -4
@@ -1481,7 +1481,8 @@ mlxsw_sp_bridge_port_vlan_add(struct mlxsw_sp_port *mlxsw_sp_port,static int mlxsw_sp_br_ban_rif_pvid_change (struct mlxsw_sp *mlxsw_sp,const struct net_device *br_dev, -const struct switchdev_obj_port_vlan *vlan) +const struct switchdev_obj_port_vlan *vlan, +struct netlink_ext_ack *extack) {u16 pvid;
@@ -1491,12 +1492,12 @@ mlxsw_sp_br_ban_rif_pvid_change(struct mlxsw_sp *mlxsw_sp,if (vlan->flags &BRIDGE_VLAN_INFO_PVID ) {if (vlan->vid != pvid) { -netdev_err (br_dev,"Can't change PVID, it's used by router interface\n" ); +NL_SET_ERR_MSG_MOD (extack,"Can't change PVID, it's used by router interface" );return -EBUSY ; } }else {if (vlan->vid == pvid) { -netdev_err (br_dev,"Can't remove PVID, it's used by router interface\n" ); +NL_SET_ERR_MSG_MOD (extack,"Can't remove PVID, it's used by router interface" );return -EBUSY ; } }
@@ -1519,7 +1520,8 @@ static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,if (br_vlan_enabled (orig_dev)) err =mlxsw_sp_br_ban_rif_pvid_change (mlxsw_sp, - orig_dev, vlan); + orig_dev, vlan, + extack);if (!err) err = -EOPNOTSUPP ;return err;
Signature · 1 line
2.40.1
Petr Machata
maintainerPATCH 2/11 mlxsw: spectrum_router: Pass struct mlxsw_sp_rif_params to fid_get
In reply to Petr MachataThe fid_get callback is called to allocate a FID for the newly-created RIF. In a following patch, the fid_get implementation for VLANs will be modified to take the VLAN ID from the parameters instead of deducing it from the netdevice. To that end, propagate the RIF parameters to the fid_get callback.
--- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +6 -2
@@ -139,6 +139,7 @@ struct mlxsw_sp_rif_ops { struct netlink_ext_ack *extack);void (*deconfigure)(struct mlxsw_sp_rif *rif);struct mlxsw_sp_fid * (*fid_get)(struct mlxsw_sp_rif *rif, +const struct mlxsw_sp_rif_params *params,struct netlink_ext_ack *extack);void (*fdb_del)(struct mlxsw_sp_rif *rif,const char *mac); };
@@ -8300,7 +8301,7 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp, rif->rif_entries = rif_entries;if (ops->fid_get) { - fid = ops->fid_get (rif, extack); + fid = ops->fid_get (rif, params, extack);if (IS_ERR (fid)) { err =PTR_ERR (fid); goto err_fid_get;
@@ -8678,7 +8679,7 @@ __mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,return PTR_ERR (rif);/* FID was already created, just take a reference */ - fid = rif->ops->fid_get (rif, extack); + fid = rif->ops->fid_get (rif, ¶ms, extack); err =mlxsw_sp_fid_port_vid_map (fid, mlxsw_sp_port, vid);if (err) goto err_fid_port_vid_map;
@@ -9724,6 +9725,7 @@ static void mlxsw_sp_rif_subport_deconfigure(struct mlxsw_sp_rif *rif)static struct mlxsw_sp_fid *mlxsw_sp_rif_subport_fid_get (struct mlxsw_sp_rif *rif, +const struct mlxsw_sp_rif_params *params,struct netlink_ext_ack *extack) {return mlxsw_sp_fid_rfid_get (rif->mlxsw_sp, rif->rif_index);
@@ -9836,6 +9838,7 @@ static void mlxsw_sp_rif_fid_deconfigure(struct mlxsw_sp_rif *rif)static struct mlxsw_sp_fid *mlxsw_sp_rif_fid_fid_get (struct mlxsw_sp_rif *rif, +const struct mlxsw_sp_rif_params *params,struct netlink_ext_ack *extack) {int rif_ifindex =mlxsw_sp_rif_dev_ifindex (rif);
@@ -9869,6 +9872,7 @@ static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_fid_ops = {static struct mlxsw_sp_fid *mlxsw_sp_rif_vlan_fid_get (struct mlxsw_sp_rif *rif, +const struct mlxsw_sp_rif_params *params,struct netlink_ext_ack *extack) {struct net_device *dev =mlxsw_sp_rif_dev (rif);
Signature · 1 line
2.40.1
Petr Machata
maintainerPATCH 3/11 mlxsw: spectrum_router: Take VID for VLAN FIDs from RIF params
In reply to Petr MachataCurrently, when an IP address is added to a bridge that has no PVID, the operation is rejected. An IP address addition is interpreted as a request to create a RIF for the bridge device, but without a PVID there is no VLAN for which the RIF should be created. Thus the correct way to create a RIF for a bridge as a user is to first add a PVID, and then add the IP address.
Ideally this ordering requirement would not exist. RIF would be created either because an IP address is added, or because a PVID is added, depending on which comes last.
For that, the switchdev code (which notices the PVID change request) must be able to request that a RIF is created with a given VLAN ID, because at the time that the PVID notification is distributed, the PVID setting is not yet visible for querying.
Therefore when creating a VLAN-based RIF, use mlxsw_sp_rif_params.vid to communicate the VID, and do not determine it ad-hoc in the fid_get callback.
--- .../ethernet/mellanox/mlxsw/spectrum_router.c | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +18 -13
@@ -8665,14 +8665,17 @@ __mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, {struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; -struct mlxsw_sp_rif_params params = { - .dev = l3_dev, - }; +struct mlxsw_sp_rif_params params;u16 vid = mlxsw_sp_port_vlan->vid;struct mlxsw_sp_rif *rif;struct mlxsw_sp_fid *fid;int err; + params = (struct mlxsw_sp_rif_params ) { + .dev = l3_dev, + .vid = vid, + }; +mlxsw_sp_rif_subport_params_init (¶ms, mlxsw_sp_port_vlan); rif =mlxsw_sp_rif_subport_get (mlxsw_sp, ¶ms, extack);if (IS_ERR (rif))
@@ -8830,6 +8833,7 @@ static int mlxsw_sp_inetaddr_bridge_event(struct mlxsw_sp *mlxsw_sp, .dev = l3_dev, };struct mlxsw_sp_rif *rif; +int err;switch (event) {case NETDEV_UP :
@@ -8841,6 +8845,13 @@ static int mlxsw_sp_inetaddr_bridge_event(struct mlxsw_sp *mlxsw_sp,NL_SET_ERR_MSG_MOD (extack,"Adding an IP address to 802.1ad bridge is not supported" );return -EOPNOTSUPP ; } + err =br_vlan_get_pvid (l3_dev, ¶ms.vid); +if (err <0 || !params.vid) { +NL_SET_ERR_MSG_MOD (extack,"Couldn't determine bridge PVID" ); +return -EINVAL ; + } + }else if (is_vlan_dev (l3_dev)) { + params.vid =vlan_dev_vlan_id (l3_dev); } rif =mlxsw_sp_rif_create (mlxsw_sp, ¶ms, extack);if (IS_ERR (rif))
@@ -9877,23 +9888,17 @@ mlxsw_sp_rif_vlan_fid_get(struct mlxsw_sp_rif *rif, {struct net_device *dev =mlxsw_sp_rif_dev (rif);struct net_device *br_dev; -u16 vid; -int err; + +if (WARN_ON (!params->vid)) +return ERR_PTR (-EINVAL );if (is_vlan_dev (dev)) { - vid =vlan_dev_vlan_id (dev); br_dev =vlan_dev_real_dev (dev);if (WARN_ON (!netif_is_bridge_master (br_dev)))return ERR_PTR (-EINVAL ); - }else { - err =br_vlan_get_pvid (dev, &vid); -if (err <0 || !vid) { -NL_SET_ERR_MSG_MOD (extack,"Couldn't determine bridge PVID" ); -return ERR_PTR (-EINVAL ); - } } -return mlxsw_sp_fid_8021q_get (rif->mlxsw_sp, vid); +return mlxsw_sp_fid_8021q_get (rif->mlxsw_sp, params->vid); }static void mlxsw_sp_rif_vlan_fdb_del (struct mlxsw_sp_rif *rif,const char *mac)
Signature · 1 line
2.40.1
Petr Machata
maintainerPATCH 4/11 mlxsw: spectrum_router: Adjust mlxsw_sp_inetaddr_vlan_event() coding style
In reply to Petr MachataThe bridge branch of the dispatch in this function is going to get more code and will need curly braces. Per the doctrine, that means the whole if-else chain should get them.
--- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +5 -3
@@ -8877,15 +8877,17 @@ static int mlxsw_sp_inetaddr_vlan_event(struct mlxsw_sp *mlxsw_sp,if (netif_is_bridge_port (vlan_dev))return 0 ; -if (mlxsw_sp_port_dev_check (real_dev)) +if (mlxsw_sp_port_dev_check (real_dev)) {return mlxsw_sp_inetaddr_port_vlan_event (vlan_dev, real_dev, event, vid, extack); -else if (netif_is_lag_master (real_dev)) + }else if (netif_is_lag_master (real_dev)) {return __mlxsw_sp_inetaddr_lag_event (vlan_dev, real_dev, event, vid, extack); -else if (netif_is_bridge_master (real_dev) &&br_vlan_enabled (real_dev)) + }else if (netif_is_bridge_master (real_dev) && +br_vlan_enabled (real_dev)) {return mlxsw_sp_inetaddr_bridge_event (mlxsw_sp, vlan_dev, event, extack); + }return 0 ; }
Signature · 1 line
2.40.1
Petr Machata
maintainerPATCH 5/11 mlxsw: spectrum_router: mlxsw_sp_inetaddr_bridge_event: Add an argument
In reply to Petr MachataFor purposes of replay, mlxsw_sp_inetaddr_bridge_event() will need to make decisions based on the proposed value of PVID. Querying PVID reveals the current settings, not the in-flight values that the user requested and that the notifiers are acting upon. Add a parameter, lower_pvid, which carries the proposed PVID of the lower bridge, or -1 if the lower is not a bridge.
--- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +9 -2
@@ -8826,6 +8826,7 @@ static int mlxsw_sp_inetaddr_lag_event(struct net_device *lag_dev,static int mlxsw_sp_inetaddr_bridge_event (struct mlxsw_sp *mlxsw_sp,struct net_device *l3_dev, +int lower_pvid,unsigned long event,struct netlink_ext_ack *extack) {
@@ -8873,6 +8874,8 @@ static int mlxsw_sp_inetaddr_vlan_event(struct mlxsw_sp *mlxsw_sp, {struct net_device *real_dev =vlan_dev_real_dev (vlan_dev);u16 vid =vlan_dev_vlan_id (vlan_dev); +u16 lower_pvid; +int err;if (netif_is_bridge_port (vlan_dev))return 0 ;
@@ -8885,7 +8888,11 @@ static int mlxsw_sp_inetaddr_vlan_event(struct mlxsw_sp *mlxsw_sp, vid, extack); }else if (netif_is_bridge_master (real_dev) &&br_vlan_enabled (real_dev)) { -return mlxsw_sp_inetaddr_bridge_event (mlxsw_sp, vlan_dev, event, + err =br_vlan_get_pvid (real_dev, &lower_pvid); +if (err) +return err; +return mlxsw_sp_inetaddr_bridge_event (mlxsw_sp, vlan_dev, + lower_pvid, event, extack); }
@@ -9022,7 +9029,7 @@ static int __mlxsw_sp_inetaddr_event(struct mlxsw_sp *mlxsw_sp,else if (netif_is_lag_master (dev))return mlxsw_sp_inetaddr_lag_event (dev, event, extack);else if (netif_is_bridge_master (dev)) -return mlxsw_sp_inetaddr_bridge_event (mlxsw_sp, dev, event, +return mlxsw_sp_inetaddr_bridge_event (mlxsw_sp, dev,-1 , event, extack);else if (is_vlan_dev (dev)) return mlxsw_sp_inetaddr_vlan_event(mlxsw_sp, dev, event,
Signature · 1 line
2.40.1
Petr Machata
maintainerPATCH 6/11 mlxsw: spectrum_switchdev: Manage RIFs on PVID change
In reply to Petr MachataCurrently, mlxsw has several shortcomings with regards to RIF handling due to PVID changes:
- In order to cause RIF for a bridge device to be created, the user is expected first to set PVID, then to add an IP address. The reverse ordering is disallowed, which is not very user-friendly.
- When such bridge gets a VLAN upper whose VID was the same as the existing PVID, and this VLAN netdevice gets an IP address, a RIF is created for this netdevice. The new RIF is then assigned to the 802.1Q FID for the given VID. This results in a working configuration. However, then, when the VLAN netdevice is removed again, the RIF for the bridge itself is never reassociated to the VLAN.
- PVID cannot be changed once the bridge has uppers. Presumably this is because the driver does not manage RIFs properly in face of PVID changes. However, as the previous point shows, it is still possible to get into invalid configurations.
In this patch, add the logic necessary for creation of a RIF as a result of PVID change. Moreover, when a VLAN upper is created whose VID matches lower PVID, do not create RIF for this netdevice.
These changes obviate the need for ordering of IP address additions and PVID configuration, so stop forbidding addition of an IP address to a PVID-less bridge. Instead, bail out quietly. Also stop preventing PVID changes when the bridge has uppers.
--- .../ethernet/mellanox/mlxsw/spectrum_router.c | 119 +++++++++++++++++- .../ethernet/mellanox/mlxsw/spectrum_router.h | 4 + .../mellanox/mlxsw/spectrum_switchdev.c | 34 ++--- 3 files changed, 128 insertions(+), 29 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +115 -4
@@ -8411,6 +8411,110 @@ void mlxsw_sp_rif_destroy_by_dev(struct mlxsw_sp *mlxsw_sp,mutex_unlock (&mlxsw_sp->router->lock); } +static void mlxsw_sp_rif_destroy_vlan_upper (struct mlxsw_sp *mlxsw_sp, +struct net_device *br_dev, +u16 vid) +{ +struct net_device *upper_dev; +struct mlxsw_sp_crif *crif; + +rcu_read_lock (); + upper_dev =__vlan_find_dev_deep_rcu (br_dev,htons (ETH_P_8021Q ), vid); +rcu_read_unlock (); + +if (!upper_dev) +return ; + + crif =mlxsw_sp_crif_lookup (mlxsw_sp->router, upper_dev); +if (!crif || !crif->rif) +return ; + +mlxsw_sp_rif_destroy (crif->rif); +} + +static int mlxsw_sp_inetaddr_bridge_event (struct mlxsw_sp *mlxsw_sp, +struct net_device *l3_dev, +int lower_pvid, +unsigned long event, +struct netlink_ext_ack *extack); + +int mlxsw_sp_router_bridge_vlan_add (struct mlxsw_sp *mlxsw_sp, +struct net_device *br_dev, +u16 new_vid,bool is_pvid, +struct netlink_ext_ack *extack) +{ +struct mlxsw_sp_rif *old_rif; +struct mlxsw_sp_rif *new_rif; +struct net_device *upper_dev; +u16 old_pvid =0 ; +u16 new_pvid; +int err =0 ; + +mutex_lock (&mlxsw_sp->router->lock); + old_rif =mlxsw_sp_rif_find_by_dev (mlxsw_sp, br_dev); +if (old_rif) { +/* If the RIF on the bridge is not a VLAN RIF, we shouldn't have +* gotten a PVID notification. +*/ +if (WARN_ON (old_rif->ops->type !=MLXSW_SP_RIF_TYPE_VLAN )) + old_rif =NULL ; +else + old_pvid =mlxsw_sp_fid_8021q_vid (old_rif->fid); + } + +if (is_pvid) + new_pvid = new_vid; +else if (old_pvid == new_vid) + new_pvid =0 ; +else + goto out; + +if (old_pvid == new_pvid) + goto out; + +if (new_pvid) { +struct mlxsw_sp_rif_params params = { + .dev = br_dev, + .vid = new_pvid, + }; + +/* If there is a VLAN upper with the same VID as the new PVID, +* kill its RIF, if there is one. +*/ +mlxsw_sp_rif_destroy_vlan_upper (mlxsw_sp, br_dev, new_pvid); + +if (mlxsw_sp_dev_addr_list_empty (br_dev)) + goto out; + new_rif =mlxsw_sp_rif_create (mlxsw_sp, ¶ms, extack); +if (IS_ERR (new_rif)) { + err =PTR_ERR (new_rif); + goto out; + } + +if (old_pvid) +mlxsw_sp_rif_migrate_destroy (mlxsw_sp, old_rif, new_rif, + true); + }else { +mlxsw_sp_rif_destroy (old_rif); + } + +if (old_pvid) { +rcu_read_lock (); + upper_dev =__vlan_find_dev_deep_rcu (br_dev,htons (ETH_P_8021Q ), + old_pvid); +rcu_read_unlock (); +if (upper_dev) + err =mlxsw_sp_inetaddr_bridge_event (mlxsw_sp, + upper_dev, + new_pvid, +NETDEV_UP , extack); + } + +out: +mutex_unlock (&mlxsw_sp->router->lock); +return err; +} +static void mlxsw_sp_rif_subport_params_init (struct mlxsw_sp_rif_params *params,struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
@@ -8847,13 +8951,20 @@ static int mlxsw_sp_inetaddr_bridge_event(struct mlxsw_sp *mlxsw_sp,return -EOPNOTSUPP ; } err =br_vlan_get_pvid (l3_dev, ¶ms.vid); -if (err <0 || !params.vid) { -NL_SET_ERR_MSG_MOD (extack,"Couldn't determine bridge PVID" ); -return -EINVAL ; - } +if (err) +return err; +if (!params.vid) +return 0 ; }else if (is_vlan_dev (l3_dev)) { params.vid =vlan_dev_vlan_id (l3_dev); + +/* If the VID matches PVID of the bridge below, the +* bridge owns the RIF for this VLAN. Don't do anything. +*/ +if ((int )params.vid == lower_pvid) +return 0 ; } + rif =mlxsw_sp_rif_create (mlxsw_sp, ¶ms, extack);if (IS_ERR (rif))return PTR_ERR (rif);
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h +4 -0
@@ -171,6 +171,10 @@ int mlxsw_sp_ipip_ecn_encap_init(struct mlxsw_sp *mlxsw_sp);int mlxsw_sp_ipip_ecn_decap_init (struct mlxsw_sp *mlxsw_sp);struct net_device *mlxsw_sp_ipip_netdev_ul_dev_get (const struct net_device *ol_dev); +int mlxsw_sp_router_bridge_vlan_add (struct mlxsw_sp *mlxsw_sp, +struct net_device *dev, +u16 new_vid,bool is_pvid, +struct netlink_ext_ack *extack);int mlxsw_sp_router_port_join_lag (struct mlxsw_sp_port *mlxsw_sp_port,struct net_device *lag_dev,struct netlink_ext_ack *extack);
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +9 -25
@@ -1479,30 +1479,15 @@ mlxsw_sp_bridge_port_vlan_add(struct mlxsw_sp_port *mlxsw_sp_port, }static int -mlxsw_sp_br_ban_rif_pvid_change (struct mlxsw_sp *mlxsw_sp, -const struct net_device *br_dev, -const struct switchdev_obj_port_vlan *vlan, -struct netlink_ext_ack *extack) +mlxsw_sp_br_rif_pvid_change (struct mlxsw_sp *mlxsw_sp, +struct net_device *br_dev, +const struct switchdev_obj_port_vlan *vlan, +struct netlink_ext_ack *extack) { -u16 pvid; +bool flag_pvid = vlan->flags &BRIDGE_VLAN_INFO_PVID ; - pvid =mlxsw_sp_rif_vid (mlxsw_sp, br_dev); -if (!pvid) -return 0 ; - -if (vlan->flags &BRIDGE_VLAN_INFO_PVID ) { -if (vlan->vid != pvid) { -NL_SET_ERR_MSG_MOD (extack,"Can't change PVID, it's used by router interface" ); -return -EBUSY ; - } - }else { -if (vlan->vid == pvid) { -NL_SET_ERR_MSG_MOD (extack,"Can't remove PVID, it's used by router interface" ); -return -EBUSY ; - } - } - -return 0 ; +return mlxsw_sp_router_bridge_vlan_add (mlxsw_sp, br_dev, vlan->vid, + flag_pvid, extack); } static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
@@ -1519,9 +1504,8 @@ static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,int err =0 ;if (br_vlan_enabled (orig_dev)) - err =mlxsw_sp_br_ban_rif_pvid_change (mlxsw_sp, - orig_dev, vlan, - extack); + err =mlxsw_sp_br_rif_pvid_change (mlxsw_sp, orig_dev, + vlan, extack);if (!err) err = -EOPNOTSUPP ;return err;
Signature · 1 line
2.40.1
Petr Machata
maintainerPATCH 7/11 selftests: forwarding: lib: Add ping6_, ping_test_fails()
In reply to Petr MachataAdd two helpers to run a ping test that succeeds when the pings themselves fail.
--- tools/testing/selftests/net/forwarding/lib.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
tools/testing/selftests/net/forwarding/lib.sh +18 -0
@@ -1215,6 +1215,15 @@ ping_test() log_test "ping$3" } +ping_test_fails() +{ + RET=0 + + ping_do $1 $2 + check_fail $? + log_test "ping fails$3" +} + ping6_do() { local if_name=$1
@@ -1237,6 +1246,15 @@ ping6_test() log_test "ping6$3" } +ping6_test_fails() +{ + RET=0 + + ping6_do $1 $2 + check_fail $? + log_test "ping6 fails$3" +} + learning_test() { local bridge=$1
Signature · 1 line
2.40.1
Petr Machata
maintainerPATCH 8/11 selftests: router_bridge: Add tests to remove and add PVID
In reply to Petr MachataThis test relies on PVID being configured on the bridge itself. Thus when it is deconfigured, the system should lose the ability to forward traffic. Later when it is added again, the ability to forward traffic should be regained. Add tests to exercise these configuration changes and verify results.
--- .../selftests/net/forwarding/router_bridge.sh | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+)
tools/testing/selftests/net/forwarding/router_bridge.sh +50 -0
@@ -1,9 +1,33 @@ #!/bin/bash # SPDX-License-Identifier: GPL-2.0 +# +------------------------+ +----------------------+ +# | H1 (vrf) | | H2 (vrf) | +# | + $h1 | | + $h2 | +# | | 192.0.2.1/28 | | | 192.0.2.130/28 | +# | | 2001:db8:1::1/64 | | | 2001:db8:2::2/64 | +# | | | | | | +# +----|-------------------+ +--|-------------------+ +# | | +# +----|--------------------------------------------------|-------------------+ +# | SW | | | +# | +--|-----------------------------+ + $swp2 | +# | | + $swp1 BR1 (802.1q) | 192.0.2.129/28 | +# | | 192.0.2.2/28 | 2001:db8:2::1/64 | +# | | 2001:db8:1::1/64 | | +# | | | | +# | +--------------------------------+ | +# +---------------------------------------------------------------------------+ + ALL_TESTS=" ping_ipv4 ping_ipv6 + config_remove_pvid + ping_ipv4_fails + ping_ipv6_fails + config_add_pvid + ping_ipv4 + ping_ipv6 " NUM_NETIFS=4 source lib.sh
@@ -62,6 +86,22 @@ router_destroy() ip link del dev br1 } +config_remove_pvid() +{ + log_info "Remove PVID from the bridge" + + bridge vlan add dev br1 vid 1 self + sleep 2 +} + +config_add_pvid() +{ + log_info "Add PVID to the bridge" + + bridge vlan add dev br1 vid 1 self pvid untagged + sleep 2 +} + setup_prepare() { h1=${NETIFS[p1]}
@@ -104,6 +144,16 @@ ping_ipv6() ping6_test $h1 2001:db8:2::2 } +ping_ipv4_fails() +{ + ping_test_fails $h1 192.0.2.130 +} + +ping_ipv6_fails() +{ + ping6_test_fails $h1 2001:db8:2::2 +} + trap cleanup EXIT setup_prepare
Signature · 1 line
2.40.1
Petr Machata
maintainerPATCH 9/11 selftests: router_bridge_vlan: Add PVID change test
In reply to Petr MachataAdd an alternative path involving VLAN 777 instead of the current 555. Then add tests that verify that marking 777 as PVID makes the 555 path not work, and the 777 path work.
--- .../net/forwarding/router_bridge_vlan.sh | 100 +++++++++++++++--- 1 file changed, 85 insertions(+), 15 deletions(-)
tools/testing/selftests/net/forwarding/router_bridge_vlan.sh +85 -15
@@ -1,25 +1,28 @@ #!/bin/bash # SPDX-License-Identifier: GPL-2.0 -# +------------------------+ +----------------------+ -# | H1 (vrf) | | H2 (vrf) | -# | + $h1.555 | | + $h2 | -# | | 192.0.2.1/28 | | | 192.0.2.130/28 | -# | | 2001:db8:1::1/64 | | | 2001:db8:2::2/64 | -# | | | | | | -# | + $h1 | | | | -# +----|-------------------+ +--|-------------------+ +# +------------------------------------------------+ +----------------------+ +# | H1 (vrf) | | H2 (vrf) | +# | + $h1.555 + $h1.777 | | + $h2 | +# | | 192.0.2.1/28 | 192.0.2.17/28 | | | 192.0.2.130/28 | +# | | 2001:db8:1::1/64 | 2001:db8:3::1/64 | | | 192.0.2.146/28 | +# | | .-----------------' | | | 2001:db8:2::2/64 | +# | |/ | | | 2001:db8:4::2/64 | +# | + $h1 | | | | +# +----|-------------------------------------------+ +--|-------------------+ # | | # +----|--------------------------------------------------|-------------------+ # | SW | | | # | +--|-------------------------------+ + $swp2 | # | | + $swp1 | 192.0.2.129/28 | -# | | vid 555 | 2001:db8:2::1/64 | -# | | | | -# | | + BR1 (802.1q) | | +# | | vid 555 777 | 192.0.2.145/28 | +# | | | 2001:db8:2::1/64 | +# | | + BR1 (802.1q) | 2001:db8:4::1/64 | # | | vid 555 pvid untagged | | # | | 192.0.2.2/28 | | +# | | 192.0.2.18/28 | | # | | 2001:db8:1::2/64 | | +# | | 2001:db8:3::2/64 | | # | +----------------------------------+ | # +---------------------------------------------------------------------------+
@@ -27,6 +30,14 @@ ALL_TESTS=" ping_ipv4 ping_ipv6 vlan + config_777 + ping_ipv4_fails + ping_ipv6_fails + ping_ipv4_777 + ping_ipv6_777 + config_555 + ping_ipv4 + ping_ipv6 " NUM_NETIFS=4 source lib.sh
@@ -34,31 +45,47 @@ source lib.sh h1_create() { simple_if_init $h1 + vlan_create $h1 555 v$h1 192.0.2.1/28 2001:db8:1::1/64 ip -4 route add 192.0.2.128/28 vrf v$h1 nexthop via 192.0.2.2 ip -6 route add 2001:db8:2::/64 vrf v$h1 nexthop via 2001:db8:1::2 + + vlan_create $h1 777 v$h1 192.0.2.17/28 2001:db8:3::1/64 + ip -4 route add 192.0.2.144/28 vrf v$h1 nexthop via 192.0.2.18 + ip -6 route add 2001:db8:4::/64 vrf v$h1 nexthop via 2001:db8:3::2 } h1_destroy() { + ip -6 route del 2001:db8:4::/64 vrf v$h1 + ip -4 route del 192.0.2.144/28 vrf v$h1 + vlan_destroy $h1 777 + ip -6 route del 2001:db8:2::/64 vrf v$h1 ip -4 route del 192.0.2.128/28 vrf v$h1 vlan_destroy $h1 555 + simple_if_fini $h1 } h2_create() { - simple_if_init $h2 192.0.2.130/28 2001:db8:2::2/64 + simple_if_init $h2 192.0.2.130/28 2001:db8:2::2/64 \ + 192.0.2.146/28 2001:db8:4::2/64 ip -4 route add 192.0.2.0/28 vrf v$h2 nexthop via 192.0.2.129 + ip -4 route add 192.0.2.16/28 vrf v$h2 nexthop via 192.0.2.145 ip -6 route add 2001:db8:1::/64 vrf v$h2 nexthop via 2001:db8:2::1 + ip -6 route add 2001:db8:3::/64 vrf v$h2 nexthop via 2001:db8:4::1 } h2_destroy() { + ip -6 route del 2001:db8:3::/64 vrf v$h2 ip -6 route del 2001:db8:1::/64 vrf v$h2 + ip -4 route del 192.0.2.16/28 vrf v$h2 ip -4 route del 192.0.2.0/28 vrf v$h2 - simple_if_fini $h2 192.0.2.130/28 2001:db8:2::2/64 + simple_if_fini $h2 192.0.2.146/28 2001:db8:4::2/64 \ + 192.0.2.130/28 2001:db8:2::2/64 } router_create()
@@ -71,18 +98,23 @@ router_create() bridge vlan add dev br1 vid 555 self pvid untagged bridge vlan add dev $swp1 vid 555 + bridge vlan add dev $swp1 vid 777 __addr_add_del br1 add 192.0.2.2/28 2001:db8:1::2/64 + __addr_add_del br1 add 192.0.2.18/28 2001:db8:3::2/64 ip link set dev $swp2 up __addr_add_del $swp2 add 192.0.2.129/28 2001:db8:2::1/64 + __addr_add_del $swp2 add 192.0.2.145/28 2001:db8:4::1/64 } router_destroy() { + __addr_add_del $swp2 del 192.0.2.145/28 2001:db8:4::1/64 __addr_add_del $swp2 del 192.0.2.129/28 2001:db8:2::1/64 ip link set dev $swp2 down + __addr_add_del br1 del 192.0.2.18/28 2001:db8:3::2/64 __addr_add_del br1 del 192.0.2.2/28 2001:db8:1::2/64 ip link set dev $swp1 down ip link set dev $swp1 nomaster
@@ -108,6 +140,24 @@ setup_prepare() forwarding_enable } +config_555() +{ + log_info "Configure VLAN 555 as PVID" + + bridge vlan add dev br1 vid 555 self pvid untagged + bridge vlan del dev br1 vid 777 self + sleep 2 +} + +config_777() +{ + log_info "Configure VLAN 777 as PVID" + + bridge vlan add dev br1 vid 777 self pvid untagged + bridge vlan del dev br1 vid 555 self + sleep 2 +} + cleanup() { pre_cleanup
@@ -136,12 +186,32 @@ vlan() ping_ipv4() { - ping_test $h1 192.0.2.130 + ping_test $h1.555 192.0.2.130 } ping_ipv6() { - ping6_test $h1 2001:db8:2::2 + ping6_test $h1.555 2001:db8:2::2 +} + +ping_ipv4_fails() +{ + ping_test_fails $h1.555 192.0.2.130 ": via 555" +} + +ping_ipv6_fails() +{ + ping6_test_fails $h1.555 2001:db8:2::2 ": via 555" +} + +ping_ipv4_777() +{ + ping_test $h1.777 192.0.2.146 ": via 777" +} + +ping_ipv6_777() +{ + ping6_test $h1.777 2001:db8:4::2 ": via 777" } trap cleanup EXIT
Signature · 1 line
2.40.1
Petr Machata
maintainerPATCH 10/11 selftests: router_bridge_vlan_upper_pvid: Add a new selftest
In reply to Petr MachataThis tests whether changes to PVID that coincide with an existing VLAN upper throw off forwarding. This selftests is specifically geared towards offloading drivers, but since there's nothing HW-specific in the test itself (it absolutely is supposed to pass on SW datapath), it is put into the generic forwarding directory.
--- .../testing/selftests/net/forwarding/Makefile | 1 + .../router_bridge_vlan_upper_pvid.sh | 171 ++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100755 tools/testing/selftests/net/forwarding/router_bridge_vlan_upper_pvid.sh
tools/testing/selftests/net/forwarding/Makefile +1 -0
@@ -65,6 +65,7 @@ TEST_PROGS = bridge_igmp.sh \ q_in_vni.sh \ router_bridge.sh \ router_bridge_vlan.sh \ + router_bridge_vlan_upper_pvid.sh \ router_broadcast.sh \ router_mpath_nh_res.sh \ router_mpath_nh.sh \
tools/testing/selftests/net/forwarding/router_bridge_vlan_upper_pvid.sh new file +171 -0
171 lines not on this page · raw message
Signature · 1 line
2.40.1
Petr Machata
maintainerPATCH 11/11 selftests: router_bridge_pvid_vlan_upper: Add a new selftest
In reply to Petr MachataThis tests whether addition and deletion of a VLAN upper that coincides with the current PVID setting throws off forwarding.
This selftests is specifically geared towards offloading drivers. In particular, mlxsw used to fail this selftest, and an earlier patch in this patchset fixes the issue. However, there's nothing HW-specific in the test itself (it absolutely is supposed to pass on SW datapath), and therefore it is put into the generic forwarding directory.
--- .../testing/selftests/net/forwarding/Makefile | 1 + .../router_bridge_pvid_vlan_upper.sh | 155 ++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100755 tools/testing/selftests/net/forwarding/router_bridge_pvid_vlan_upper.sh
tools/testing/selftests/net/forwarding/Makefile +1 -0
@@ -65,6 +65,7 @@ TEST_PROGS = bridge_igmp.sh \ q_in_vni.sh \ router_bridge.sh \ router_bridge_vlan.sh \ + router_bridge_pvid_vlan_upper.sh \ router_bridge_vlan_upper_pvid.sh \ router_broadcast.sh \ router_mpath_nh_res.sh \
tools/testing/selftests/net/forwarding/router_bridge_pvid_vlan_upper.sh new file +155 -0
155 lines not on this page · raw message
Signature · 1 line
2.40.1
This series was applied to netdev/net-next.git (main) by David S. Miller <[email protected]>:
Hello:
This series was applied to netdev/net-next.git (main) by David S. Miller <[email protected]>:
Quoted 9 lines · On Thu, 13 Jul 2023 18:15:23 +0200 you wrote:
The mlxsw driver currently makes the assumption that the user applies configuration in a bottom-up manner. Thus netdevices need to be added to the bridge before IP addresses are configured on that bridge or SVI added on top of it. Enslaving a netdevice to another netdevice that already has uppers is in fact forbidden by mlxsw for this reason. Despite this safety, it is rather easy to get into situations where the offloaded configuration is just plain wrong.
[...]
Here is the summary with links:
- [net-next,01/11] mlxsw: spectrum_switchdev: Pass extack to mlxsw_sp_br_ban_rif_pvid_change()
https://git.kernel.org/netdev/net-next/c/352be882deda - [net-next,02/11] mlxsw: spectrum_router: Pass struct mlxsw_sp_rif_params to fid_get https://git.kernel.org/netdev/net-next/c/5ca9f42caf81 - [net-next,03/11] mlxsw: spectrum_router: Take VID for VLAN FIDs from RIF params https://git.kernel.org/netdev/net-next/c/a0944b24d278 - [net-next,04/11] mlxsw: spectrum_router: Adjust mlxsw_sp_inetaddr_vlan_event() coding style https://git.kernel.org/netdev/net-next/c/a24a4d29ff0a - [net-next,05/11] mlxsw: spectrum_router: mlxsw_sp_inetaddr_bridge_event: Add an argument https://git.kernel.org/netdev/net-next/c/3430f2cf91a4 - [net-next,06/11] mlxsw: spectrum_switchdev: Manage RIFs on PVID change https://git.kernel.org/netdev/net-next/c/a5b52692e693 - [net-next,07/11] selftests: forwarding: lib: Add ping6_, ping_test_fails() https://git.kernel.org/netdev/net-next/c/5f44a7144cc5 - [net-next,08/11] selftests: router_bridge: Add tests to remove and add PVID https://git.kernel.org/netdev/net-next/c/c7203a2981dc - [net-next,09/11] selftests: router_bridge_vlan: Add PVID change test https://git.kernel.org/netdev/net-next/c/d4172a93b279 - [net-next,10/11] selftests: router_bridge_vlan_upper_pvid: Add a new selftest https://git.kernel.org/netdev/net-next/c/b0307b77265b - [net-next,11/11] selftests: router_bridge_pvid_vlan_upper: Add a new selftest https://git.kernel.org/netdev/net-next/c/9cbb3da4f4f7
You are awesome, thank you!
Signature · 2 lines
Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html