aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGal Pressman <galp@mellanox.com>2017-12-03 06:58:50 -0500
committerSaeed Mahameed <saeedm@mellanox.com>2017-12-19 16:24:03 -0500
commit23f4cc2cd9ed92570647220aca60d0197d8c1fa9 (patch)
tree7c51d35d7824b06a12e443e1cca739638553f603
parent6323514116404cc651df1b7fffa1311ddf8ce647 (diff)
net/mlx5e: Add refcount to VXLAN structure
A refcount mechanism must be implemented in order to prevent unwanted scenarios such as: - Open an IPv4 VXLAN interface - Open an IPv6 VXLAN interface (different socket) - Remove one of the interfaces With current implementation, the UDP port will be removed from our VXLAN database and turn off the offloads for the other interface, which is still active. The reference count mechanism will only allow UDP port removals once all consumers are gone. Fixes: b3f63c3d5e2c ("net/mlx5e: Add netdev support for VXLAN tunneling") Signed-off-by: Gal Pressman <galp@mellanox.com> Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/vxlan.c50
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/vxlan.h1
2 files changed, 28 insertions, 23 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vxlan.c b/drivers/net/ethernet/mellanox/mlx5/core/vxlan.c
index f8238275759f..25f782344667 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/vxlan.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/vxlan.c
@@ -88,8 +88,11 @@ static void mlx5e_vxlan_add_port(struct work_struct *work)
88 struct mlx5e_vxlan *vxlan; 88 struct mlx5e_vxlan *vxlan;
89 int err; 89 int err;
90 90
91 if (mlx5e_vxlan_lookup_port(priv, port)) 91 vxlan = mlx5e_vxlan_lookup_port(priv, port);
92 if (vxlan) {
93 atomic_inc(&vxlan->refcount);
92 goto free_work; 94 goto free_work;
95 }
93 96
94 if (mlx5e_vxlan_core_add_port_cmd(priv->mdev, port)) 97 if (mlx5e_vxlan_core_add_port_cmd(priv->mdev, port))
95 goto free_work; 98 goto free_work;
@@ -99,6 +102,7 @@ static void mlx5e_vxlan_add_port(struct work_struct *work)
99 goto err_delete_port; 102 goto err_delete_port;
100 103
101 vxlan->udp_port = port; 104 vxlan->udp_port = port;
105 atomic_set(&vxlan->refcount, 1);
102 106
103 spin_lock_bh(&vxlan_db->lock); 107 spin_lock_bh(&vxlan_db->lock);
104 err = radix_tree_insert(&vxlan_db->tree, vxlan->udp_port, vxlan); 108 err = radix_tree_insert(&vxlan_db->tree, vxlan->udp_port, vxlan);
@@ -116,32 +120,33 @@ free_work:
116 kfree(vxlan_work); 120 kfree(vxlan_work);
117} 121}
118 122
119static void __mlx5e_vxlan_core_del_port(struct mlx5e_priv *priv, u16 port) 123static void mlx5e_vxlan_del_port(struct work_struct *work)
120{ 124{
125 struct mlx5e_vxlan_work *vxlan_work =
126 container_of(work, struct mlx5e_vxlan_work, work);
127 struct mlx5e_priv *priv = vxlan_work->priv;
121 struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan; 128 struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan;
129 u16 port = vxlan_work->port;
122 struct mlx5e_vxlan *vxlan; 130 struct mlx5e_vxlan *vxlan;
131 bool remove = false;
123 132
124 spin_lock_bh(&vxlan_db->lock); 133 spin_lock_bh(&vxlan_db->lock);
125 vxlan = radix_tree_delete(&vxlan_db->tree, port); 134 vxlan = radix_tree_lookup(&vxlan_db->tree, port);
126 spin_unlock_bh(&vxlan_db->lock);
127
128 if (!vxlan) 135 if (!vxlan)
129 return; 136 goto out_unlock;
130
131 mlx5e_vxlan_core_del_port_cmd(priv->mdev, vxlan->udp_port);
132
133 kfree(vxlan);
134}
135 137
136static void mlx5e_vxlan_del_port(struct work_struct *work) 138 if (atomic_dec_and_test(&vxlan->refcount)) {
137{ 139 radix_tree_delete(&vxlan_db->tree, port);
138 struct mlx5e_vxlan_work *vxlan_work = 140 remove = true;
139 container_of(work, struct mlx5e_vxlan_work, work); 141 }
140 struct mlx5e_priv *priv = vxlan_work->priv;
141 u16 port = vxlan_work->port;
142 142
143 __mlx5e_vxlan_core_del_port(priv, port); 143out_unlock:
144 spin_unlock_bh(&vxlan_db->lock);
144 145
146 if (remove) {
147 mlx5e_vxlan_core_del_port_cmd(priv->mdev, port);
148 kfree(vxlan);
149 }
145 kfree(vxlan_work); 150 kfree(vxlan_work);
146} 151}
147 152
@@ -171,12 +176,11 @@ void mlx5e_vxlan_cleanup(struct mlx5e_priv *priv)
171 struct mlx5e_vxlan *vxlan; 176 struct mlx5e_vxlan *vxlan;
172 unsigned int port = 0; 177 unsigned int port = 0;
173 178
174 spin_lock_bh(&vxlan_db->lock); 179 /* Lockless since we are the only radix-tree consumers, wq is disabled */
175 while (radix_tree_gang_lookup(&vxlan_db->tree, (void **)&vxlan, port, 1)) { 180 while (radix_tree_gang_lookup(&vxlan_db->tree, (void **)&vxlan, port, 1)) {
176 port = vxlan->udp_port; 181 port = vxlan->udp_port;
177 spin_unlock_bh(&vxlan_db->lock); 182 radix_tree_delete(&vxlan_db->tree, port);
178 __mlx5e_vxlan_core_del_port(priv, (u16)port); 183 mlx5e_vxlan_core_del_port_cmd(priv->mdev, port);
179 spin_lock_bh(&vxlan_db->lock); 184 kfree(vxlan);
180 } 185 }
181 spin_unlock_bh(&vxlan_db->lock);
182} 186}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vxlan.h b/drivers/net/ethernet/mellanox/mlx5/core/vxlan.h
index 5def12c048e3..5ef6ae7d568a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/vxlan.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/vxlan.h
@@ -36,6 +36,7 @@
36#include "en.h" 36#include "en.h"
37 37
38struct mlx5e_vxlan { 38struct mlx5e_vxlan {
39 atomic_t refcount;
39 u16 udp_port; 40 u16 udp_port;
40}; 41};
41 42