Skip to content

Commit c5d326b

Browse files
w1ldptrSaeed Mahameed
authored andcommitted
net/mlx5e: Protect tc flows hashtable with rcu
In order to remove dependency on rtnl lock, access to tc flows hashtable must be explicitly protected from concurrent flows removal. Extend tc flow structure with rcu to allow concurrent parallel access. Use rcu read lock to safely lookup flow in tc flows hash table, and take reference to it. Use rcu free for flow deletion to accommodate concurrent stats requests. Add new DELETED flow flag. Imlement new flow_flag_test_and_set() helper that is used to set a flag and return its previous value. Use it to atomically set the flag in mlx5e_delete_flower() to guarantee that flow can only be deleted once, even when same flow is deleted concurrently by multiple tasks. Signed-off-by: Vlad Buslov <[email protected]> Reviewed-by: Jianbo Liu <[email protected]> Reviewed-by: Roi Dayan <[email protected]> Signed-off-by: Saeed Mahameed <[email protected]>
1 parent 226f2ca commit c5d326b

File tree

1 file changed

+40
-7
lines changed
  • drivers/net/ethernet/mellanox/mlx5/core

1 file changed

+40
-7
lines changed

drivers/net/ethernet/mellanox/mlx5/core/en_tc.c

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ enum {
7979
MLX5E_TC_FLOW_FLAG_SLOW = MLX5E_TC_FLOW_BASE + 3,
8080
MLX5E_TC_FLOW_FLAG_DUP = MLX5E_TC_FLOW_BASE + 4,
8181
MLX5E_TC_FLOW_FLAG_NOT_READY = MLX5E_TC_FLOW_BASE + 5,
82+
MLX5E_TC_FLOW_FLAG_DELETED = MLX5E_TC_FLOW_BASE + 6,
8283
};
8384

8485
#define MLX5E_TC_MAX_SPLITS 1
@@ -122,6 +123,7 @@ struct mlx5e_tc_flow {
122123
struct list_head peer; /* flows with peer flow */
123124
struct list_head unready; /* flows not ready to be offloaded (e.g due to missing route) */
124125
refcount_t refcnt;
126+
struct rcu_head rcu_head;
125127
union {
126128
struct mlx5_esw_flow_attr esw_attr[0];
127129
struct mlx5_nic_flow_attr nic_attr[0];
@@ -201,7 +203,7 @@ static void mlx5e_flow_put(struct mlx5e_priv *priv,
201203
{
202204
if (refcount_dec_and_test(&flow->refcnt)) {
203205
mlx5e_tc_del_flow(priv, flow);
204-
kfree(flow);
206+
kfree_rcu(flow, rcu_head);
205207
}
206208
}
207209

@@ -214,6 +216,17 @@ static void __flow_flag_set(struct mlx5e_tc_flow *flow, unsigned long flag)
214216

215217
#define flow_flag_set(flow, flag) __flow_flag_set(flow, MLX5E_TC_FLOW_FLAG_##flag)
216218

219+
static bool __flow_flag_test_and_set(struct mlx5e_tc_flow *flow,
220+
unsigned long flag)
221+
{
222+
/* test_and_set_bit() provides all necessary barriers */
223+
return test_and_set_bit(flag, &flow->flags);
224+
}
225+
226+
#define flow_flag_test_and_set(flow, flag) \
227+
__flow_flag_test_and_set(flow, \
228+
MLX5E_TC_FLOW_FLAG_##flag)
229+
217230
static void __flow_flag_clear(struct mlx5e_tc_flow *flow, unsigned long flag)
218231
{
219232
/* Complete all memory stores before clearing bit. */
@@ -3451,7 +3464,9 @@ int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
34513464
struct mlx5e_tc_flow *flow;
34523465
int err = 0;
34533466

3454-
flow = rhashtable_lookup_fast(tc_ht, &f->cookie, tc_ht_params);
3467+
rcu_read_lock();
3468+
flow = rhashtable_lookup(tc_ht, &f->cookie, tc_ht_params);
3469+
rcu_read_unlock();
34553470
if (flow) {
34563471
NL_SET_ERR_MSG_MOD(extack,
34573472
"flow cookie already exists, ignoring");
@@ -3466,7 +3481,7 @@ int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
34663481
if (err)
34673482
goto out;
34683483

3469-
err = rhashtable_insert_fast(tc_ht, &flow->node, tc_ht_params);
3484+
err = rhashtable_lookup_insert_fast(tc_ht, &flow->node, tc_ht_params);
34703485
if (err)
34713486
goto err_free;
34723487

@@ -3492,16 +3507,32 @@ int mlx5e_delete_flower(struct net_device *dev, struct mlx5e_priv *priv,
34923507
{
34933508
struct rhashtable *tc_ht = get_tc_ht(priv, flags);
34943509
struct mlx5e_tc_flow *flow;
3510+
int err;
34953511

3512+
rcu_read_lock();
34963513
flow = rhashtable_lookup_fast(tc_ht, &f->cookie, tc_ht_params);
3497-
if (!flow || !same_flow_direction(flow, flags))
3498-
return -EINVAL;
3514+
if (!flow || !same_flow_direction(flow, flags)) {
3515+
err = -EINVAL;
3516+
goto errout;
3517+
}
34993518

3519+
/* Only delete the flow if it doesn't have MLX5E_TC_FLOW_DELETED flag
3520+
* set.
3521+
*/
3522+
if (flow_flag_test_and_set(flow, DELETED)) {
3523+
err = -EINVAL;
3524+
goto errout;
3525+
}
35003526
rhashtable_remove_fast(tc_ht, &flow->node, tc_ht_params);
3527+
rcu_read_unlock();
35013528

35023529
mlx5e_flow_put(priv, flow);
35033530

35043531
return 0;
3532+
3533+
errout:
3534+
rcu_read_unlock();
3535+
return err;
35053536
}
35063537

35073538
int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv,
@@ -3517,8 +3548,10 @@ int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv,
35173548
u64 bytes = 0;
35183549
int err = 0;
35193550

3520-
flow = mlx5e_flow_get(rhashtable_lookup_fast(tc_ht, &f->cookie,
3521-
tc_ht_params));
3551+
rcu_read_lock();
3552+
flow = mlx5e_flow_get(rhashtable_lookup(tc_ht, &f->cookie,
3553+
tc_ht_params));
3554+
rcu_read_unlock();
35223555
if (IS_ERR(flow))
35233556
return PTR_ERR(flow);
35243557

0 commit comments

Comments
 (0)