aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIdo Schimmel <idosch@mellanox.com>2018-08-24 08:41:35 -0400
committerDavid S. Miller <davem@davemloft.net>2018-08-25 19:28:20 -0400
commit602b74eda81311dbdb5dbab08c30f789f648ebdc (patch)
tree1816e9657a29bf4540bb5f522bd4442bfe93e836
parentae923785bc3af418b913bda7f92d247255a7b541 (diff)
mlxsw: spectrum_switchdev: Do not leak RIFs when removing bridge
When a bridge device is removed, the VLANs are flushed from each configured port. This causes the ports to decrement the reference count on the associated FIDs (filtering identifier). If the reference count of a FID is 1 and it has a RIF (router interface), then this RIF is destroyed. However, if no port is member in the VLAN for which a RIF exists, then the RIF will continue to exist after the removal of the bridge. To reproduce: # ip link add name br0 type bridge vlan_filtering 1 # ip link set dev swp1 master br0 # ip link add link br0 name br0.10 type vlan id 10 # ip address add 192.0.2.0/24 dev br0.10 # ip link del dev br0 The RIF associated with br0.10 continues to exist. Fix this by iterating over all the bridge device uppers when it is destroyed and take care of destroying their RIFs. Fixes: 99f44bb3527b ("mlxsw: spectrum: Enable L3 interfaces on top of bridge devices") Signed-off-by: Ido Schimmel <idosch@mellanox.com> Reviewed-by: Petr Machata <petrm@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c11
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c20
3 files changed, 33 insertions, 0 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 3ae930196741..3cdb7aca90b7 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -414,6 +414,8 @@ mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp,
414void 414void
415mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); 415mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan);
416void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif); 416void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif);
417void mlxsw_sp_rif_destroy_by_dev(struct mlxsw_sp *mlxsw_sp,
418 struct net_device *dev);
417 419
418/* spectrum_kvdl.c */ 420/* spectrum_kvdl.c */
419enum mlxsw_sp_kvdl_entry_type { 421enum mlxsw_sp_kvdl_entry_type {
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 3a96307f51b0..2ab9cf25a08a 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -6234,6 +6234,17 @@ void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif)
6234 mlxsw_sp_vr_put(mlxsw_sp, vr); 6234 mlxsw_sp_vr_put(mlxsw_sp, vr);
6235} 6235}
6236 6236
6237void mlxsw_sp_rif_destroy_by_dev(struct mlxsw_sp *mlxsw_sp,
6238 struct net_device *dev)
6239{
6240 struct mlxsw_sp_rif *rif;
6241
6242 rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
6243 if (!rif)
6244 return;
6245 mlxsw_sp_rif_destroy(rif);
6246}
6247
6237static void 6248static void
6238mlxsw_sp_rif_subport_params_init(struct mlxsw_sp_rif_params *params, 6249mlxsw_sp_rif_subport_params_init(struct mlxsw_sp_rif_params *params,
6239 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) 6250 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index 0d8444aaba01..db715da7bab7 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -127,6 +127,24 @@ bool mlxsw_sp_bridge_device_is_offloaded(const struct mlxsw_sp *mlxsw_sp,
127 return !!mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev); 127 return !!mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev);
128} 128}
129 129
130static int mlxsw_sp_bridge_device_upper_rif_destroy(struct net_device *dev,
131 void *data)
132{
133 struct mlxsw_sp *mlxsw_sp = data;
134
135 mlxsw_sp_rif_destroy_by_dev(mlxsw_sp, dev);
136 return 0;
137}
138
139static void mlxsw_sp_bridge_device_rifs_destroy(struct mlxsw_sp *mlxsw_sp,
140 struct net_device *dev)
141{
142 mlxsw_sp_rif_destroy_by_dev(mlxsw_sp, dev);
143 netdev_walk_all_upper_dev_rcu(dev,
144 mlxsw_sp_bridge_device_upper_rif_destroy,
145 mlxsw_sp);
146}
147
130static struct mlxsw_sp_bridge_device * 148static struct mlxsw_sp_bridge_device *
131mlxsw_sp_bridge_device_create(struct mlxsw_sp_bridge *bridge, 149mlxsw_sp_bridge_device_create(struct mlxsw_sp_bridge *bridge,
132 struct net_device *br_dev) 150 struct net_device *br_dev)
@@ -165,6 +183,8 @@ static void
165mlxsw_sp_bridge_device_destroy(struct mlxsw_sp_bridge *bridge, 183mlxsw_sp_bridge_device_destroy(struct mlxsw_sp_bridge *bridge,
166 struct mlxsw_sp_bridge_device *bridge_device) 184 struct mlxsw_sp_bridge_device *bridge_device)
167{ 185{
186 mlxsw_sp_bridge_device_rifs_destroy(bridge->mlxsw_sp,
187 bridge_device->dev);
168 list_del(&bridge_device->list); 188 list_del(&bridge_device->list);
169 if (bridge_device->vlan_enabled) 189 if (bridge_device->vlan_enabled)
170 bridge->vlan_enabled_exists = false; 190 bridge->vlan_enabled_exists = false;