mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-27 06:34:11 +08:00
mlxsw: spectrum: Handle port leaving LAG while bridged
It is possible for a user to remove a port from a LAG device, while the
LAG device or VLAN devices on top of it are bridged. In these cases,
bridge's teardown sequence is never issued, so we need to take care of
it ourselves.
When LAG's unlinking event is received by port netdev:
1) Traverse its vPorts list and make those member in a bridge leave it.
They will be deleted later by LAG code.
2) Make the port netdev itself leave its bridge if member in one.
Fixes: 0d65fc1304
("mlxsw: spectrum: Implement LAG port join/leave")
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
3b9e948809
commit
4dc236c317
@ -2200,10 +2200,14 @@ err_col_port_enable:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mlxsw_sp_vport_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_vport,
|
||||||
|
struct net_device *br_dev);
|
||||||
|
|
||||||
static int mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port,
|
static int mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||||
struct net_device *lag_dev)
|
struct net_device *lag_dev)
|
||||||
{
|
{
|
||||||
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
||||||
|
struct mlxsw_sp_port *mlxsw_sp_vport;
|
||||||
struct mlxsw_sp_upper *lag;
|
struct mlxsw_sp_upper *lag;
|
||||||
u16 lag_id = mlxsw_sp_port->lag_id;
|
u16 lag_id = mlxsw_sp_port->lag_id;
|
||||||
int err;
|
int err;
|
||||||
@ -2220,6 +2224,29 @@ static int mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port,
|
|||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
/* In case we leave a LAG device that has bridges built on top,
|
||||||
|
* then their teardown sequence is never issued and we need to
|
||||||
|
* invoke the necessary cleanup routines ourselves.
|
||||||
|
*/
|
||||||
|
list_for_each_entry(mlxsw_sp_vport, &mlxsw_sp_port->vports_list,
|
||||||
|
vport.list) {
|
||||||
|
struct net_device *br_dev;
|
||||||
|
|
||||||
|
if (!mlxsw_sp_vport->bridged)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
br_dev = mlxsw_sp_vport_br_get(mlxsw_sp_vport);
|
||||||
|
mlxsw_sp_vport_bridge_leave(mlxsw_sp_vport, br_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mlxsw_sp_port->bridged) {
|
||||||
|
mlxsw_sp_port_active_vlans_del(mlxsw_sp_port);
|
||||||
|
mlxsw_sp_port_bridge_leave(mlxsw_sp_port);
|
||||||
|
|
||||||
|
if (lag->ref_count == 1)
|
||||||
|
mlxsw_sp_master_bridge_dec(mlxsw_sp, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (lag->ref_count == 1) {
|
if (lag->ref_count == 1) {
|
||||||
err = mlxsw_sp_lag_destroy(mlxsw_sp, lag_id);
|
err = mlxsw_sp_lag_destroy(mlxsw_sp, lag_id);
|
||||||
if (err)
|
if (err)
|
||||||
@ -2272,9 +2299,6 @@ static int mlxsw_sp_port_lag_changed(struct mlxsw_sp_port *mlxsw_sp_port,
|
|||||||
return mlxsw_sp_port_lag_tx_en_set(mlxsw_sp_port, info->tx_enabled);
|
return mlxsw_sp_port_lag_tx_en_set(mlxsw_sp_port, info->tx_enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mlxsw_sp_vport_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_vport,
|
|
||||||
struct net_device *br_dev);
|
|
||||||
|
|
||||||
static int mlxsw_sp_port_vlan_link(struct mlxsw_sp_port *mlxsw_sp_port,
|
static int mlxsw_sp_port_vlan_link(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||||
struct net_device *vlan_dev)
|
struct net_device *vlan_dev)
|
||||||
{
|
{
|
||||||
|
@ -254,5 +254,6 @@ int mlxsw_sp_port_kill_vid(struct net_device *dev,
|
|||||||
__be16 __always_unused proto, u16 vid);
|
__be16 __always_unused proto, u16 vid);
|
||||||
int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 vfid,
|
int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 vfid,
|
||||||
bool set, bool only_uc);
|
bool set, bool only_uc);
|
||||||
|
void mlxsw_sp_port_active_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -936,6 +936,14 @@ static int mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port,
|
|||||||
vlan->vid_begin, vlan->vid_end, false);
|
vlan->vid_begin, vlan->vid_end, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mlxsw_sp_port_active_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port)
|
||||||
|
{
|
||||||
|
u16 vid;
|
||||||
|
|
||||||
|
for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID)
|
||||||
|
__mlxsw_sp_port_vlans_del(mlxsw_sp_port, vid, vid, false);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
mlxsw_sp_port_fdb_static_del(struct mlxsw_sp_port *mlxsw_sp_port,
|
mlxsw_sp_port_fdb_static_del(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||||
const struct switchdev_obj_port_fdb *fdb)
|
const struct switchdev_obj_port_fdb *fdb)
|
||||||
|
Loading…
Reference in New Issue
Block a user