]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-4.14/mlxsw-spectrum-properly-cleanup-lag-uppers-when-remo.patch
autosel patches for 4.14
[thirdparty/kernel/stable-queue.git] / queue-4.14 / mlxsw-spectrum-properly-cleanup-lag-uppers-when-remo.patch
1 From 3b659d59e601f82ba6f1ae4e2392e0ad365021b6 Mon Sep 17 00:00:00 2001
2 From: Ido Schimmel <idosch@mellanox.com>
3 Date: Wed, 19 Dec 2018 06:08:45 +0000
4 Subject: mlxsw: spectrum: Properly cleanup LAG uppers when removing port from
5 LAG
6
7 [ Upstream commit be2d6f421f680e01d58f7cd452646e0d8586d49b ]
8
9 When a LAG device or a VLAN device on top of it is enslaved to a bridge,
10 the driver propagates the CHANGEUPPER event to the LAG's slaves.
11
12 This causes each physical port to increase the reference count of the
13 internal representation of the bridge port by calling
14 mlxsw_sp_port_bridge_join().
15
16 However, when a port is removed from a LAG, the corresponding leave()
17 function is not called and the reference count is not decremented. This
18 leads to ugly hacks such as mlxsw_sp_bridge_port_should_destroy() that
19 try to understand if the bridge port should be destroyed even when its
20 reference count is not 0.
21
22 Instead, make sure that when a port is unlinked from a LAG it would see
23 the same events as if the LAG (or its uppers) were unlinked from a
24 bridge.
25
26 The above is achieved by walking the LAG's uppers when a port is
27 unlinked and calling mlxsw_sp_port_bridge_leave() for each upper that is
28 enslaved to a bridge.
29
30 Signed-off-by: Ido Schimmel <idosch@mellanox.com>
31 Reviewed-by: Petr Machata <petrm@mellanox.com>
32 Signed-off-by: David S. Miller <davem@davemloft.net>
33 Signed-off-by: Sasha Levin <sashal@kernel.org>
34 ---
35 .../net/ethernet/mellanox/mlxsw/spectrum.c | 23 ++++++++++++++++
36 .../mellanox/mlxsw/spectrum_switchdev.c | 27 +------------------
37 2 files changed, 24 insertions(+), 26 deletions(-)
38
39 diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
40 index cf65b2ee8b95..7892e6b8d2e8 100644
41 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
42 +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
43 @@ -3907,6 +3907,25 @@ void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port)
44 dev_put(mlxsw_sp_port->dev);
45 }
46
47 +static void
48 +mlxsw_sp_port_lag_uppers_cleanup(struct mlxsw_sp_port *mlxsw_sp_port,
49 + struct net_device *lag_dev)
50 +{
51 + struct net_device *br_dev = netdev_master_upper_dev_get(lag_dev);
52 + struct net_device *upper_dev;
53 + struct list_head *iter;
54 +
55 + if (netif_is_bridge_port(lag_dev))
56 + mlxsw_sp_port_bridge_leave(mlxsw_sp_port, lag_dev, br_dev);
57 +
58 + netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) {
59 + if (!netif_is_bridge_port(upper_dev))
60 + continue;
61 + br_dev = netdev_master_upper_dev_get(upper_dev);
62 + mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev, br_dev);
63 + }
64 +}
65 +
66 static int mlxsw_sp_lag_create(struct mlxsw_sp *mlxsw_sp, u16 lag_id)
67 {
68 char sldr_pl[MLXSW_REG_SLDR_LEN];
69 @@ -4094,6 +4113,10 @@ static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port,
70
71 /* Any VLANs configured on the port are no longer valid */
72 mlxsw_sp_port_vlan_flush(mlxsw_sp_port);
73 + /* Make the LAG and its directly linked uppers leave bridges they
74 + * are memeber in
75 + */
76 + mlxsw_sp_port_lag_uppers_cleanup(mlxsw_sp_port, lag_dev);
77
78 if (lag->ref_count == 1)
79 mlxsw_sp_lag_destroy(mlxsw_sp, lag_id);
80 diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
81 index 9052e93e1925..f33fb95c4189 100644
82 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
83 +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
84 @@ -291,30 +291,6 @@ mlxsw_sp_bridge_port_destroy(struct mlxsw_sp_bridge_port *bridge_port)
85 kfree(bridge_port);
86 }
87
88 -static bool
89 -mlxsw_sp_bridge_port_should_destroy(const struct mlxsw_sp_bridge_port *
90 - bridge_port)
91 -{
92 - struct net_device *dev = bridge_port->dev;
93 - struct mlxsw_sp *mlxsw_sp;
94 -
95 - if (is_vlan_dev(dev))
96 - mlxsw_sp = mlxsw_sp_lower_get(vlan_dev_real_dev(dev));
97 - else
98 - mlxsw_sp = mlxsw_sp_lower_get(dev);
99 -
100 - /* In case ports were pulled from out of a bridged LAG, then
101 - * it's possible the reference count isn't zero, yet the bridge
102 - * port should be destroyed, as it's no longer an upper of ours.
103 - */
104 - if (!mlxsw_sp && list_empty(&bridge_port->vlans_list))
105 - return true;
106 - else if (bridge_port->ref_count == 0)
107 - return true;
108 - else
109 - return false;
110 -}
111 -
112 static struct mlxsw_sp_bridge_port *
113 mlxsw_sp_bridge_port_get(struct mlxsw_sp_bridge *bridge,
114 struct net_device *brport_dev)
115 @@ -352,8 +328,7 @@ static void mlxsw_sp_bridge_port_put(struct mlxsw_sp_bridge *bridge,
116 {
117 struct mlxsw_sp_bridge_device *bridge_device;
118
119 - bridge_port->ref_count--;
120 - if (!mlxsw_sp_bridge_port_should_destroy(bridge_port))
121 + if (--bridge_port->ref_count != 0)
122 return;
123 bridge_device = bridge_port->bridge_device;
124 mlxsw_sp_bridge_port_destroy(bridge_port);
125 --
126 2.19.1
127