Commit d2faae25 authored by Vlad Buslov's avatar Vlad Buslov Committed by Saeed Mahameed
Browse files

net/mlx5e: Protect mod_hdr hash table with mutex



To remove dependency on rtnl lock, protect mod_hdr hash table from
concurrent modifications with new mutex.

Implement helper function to get flow namespace to prevent code
duplication.

Signed-off-by: default avatarVlad Buslov <vladbu@mellanox.com>
Reviewed-by: default avatarRoi Dayan <roid@mellanox.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@mellanox.com>
parent 83a52f0d
Loading
Loading
Loading
Loading
+25 −10
Original line number Diff line number Diff line
@@ -315,22 +315,31 @@ mlx5e_mod_hdr_get(struct mod_hdr_tbl *tbl, struct mod_hdr_key *key, u32 hash_key
}

static void mlx5e_mod_hdr_put(struct mlx5e_priv *priv,
			      struct mlx5e_mod_hdr_entry *mh)
			      struct mlx5e_mod_hdr_entry *mh,
			      int namespace)
{
	if (!refcount_dec_and_test(&mh->refcnt))
	struct mod_hdr_tbl *tbl = get_mod_hdr_table(priv, namespace);

	if (!refcount_dec_and_mutex_lock(&mh->refcnt, &tbl->lock))
		return;
	hash_del(&mh->mod_hdr_hlist);
	mutex_unlock(&tbl->lock);

	WARN_ON(!list_empty(&mh->flows));
	mlx5_modify_header_dealloc(priv->mdev, mh->mod_hdr_id);
	hash_del(&mh->mod_hdr_hlist);

	kfree(mh);
}

static int get_flow_name_space(struct mlx5e_tc_flow *flow)
{
	return mlx5e_is_eswitch_flow(flow) ?
		MLX5_FLOW_NAMESPACE_FDB : MLX5_FLOW_NAMESPACE_KERNEL;
}
static int mlx5e_attach_mod_hdr(struct mlx5e_priv *priv,
				struct mlx5e_tc_flow *flow,
				struct mlx5e_tc_flow_parse_attr *parse_attr)
{
	bool is_eswitch_flow = mlx5e_is_eswitch_flow(flow);
	int num_actions, actions_size, namespace, err;
	struct mlx5e_mod_hdr_entry *mh;
	struct mod_hdr_tbl *tbl;
@@ -345,17 +354,19 @@ static int mlx5e_attach_mod_hdr(struct mlx5e_priv *priv,

	hash_key = hash_mod_hdr_info(&key);

	namespace = is_eswitch_flow ?
		MLX5_FLOW_NAMESPACE_FDB : MLX5_FLOW_NAMESPACE_KERNEL;
	namespace = get_flow_name_space(flow);
	tbl = get_mod_hdr_table(priv, namespace);

	mutex_lock(&tbl->lock);
	mh = mlx5e_mod_hdr_get(tbl, &key, hash_key);
	if (mh)
		goto attach_flow;

	mh = kzalloc(sizeof(*mh) + actions_size, GFP_KERNEL);
	if (!mh)
		return -ENOMEM;
	if (!mh) {
		err = -ENOMEM;
		goto out_err;
	}

	mh->key.actions = (void *)mh + sizeof(*mh);
	memcpy(mh->key.actions, key.actions, actions_size);
@@ -374,11 +385,12 @@ static int mlx5e_attach_mod_hdr(struct mlx5e_priv *priv,
	hash_add(tbl->hlist, &mh->mod_hdr_hlist, hash_key);

attach_flow:
	mutex_unlock(&tbl->lock);
	flow->mh = mh;
	spin_lock(&mh->flows_lock);
	list_add(&flow->mod_hdr, &mh->flows);
	spin_unlock(&mh->flows_lock);
	if (is_eswitch_flow)
	if (mlx5e_is_eswitch_flow(flow))
		flow->esw_attr->mod_hdr_id = mh->mod_hdr_id;
	else
		flow->nic_attr->mod_hdr_id = mh->mod_hdr_id;
@@ -386,6 +398,7 @@ attach_flow:
	return 0;

out_err:
	mutex_unlock(&tbl->lock);
	kfree(mh);
	return err;
}
@@ -401,7 +414,7 @@ static void mlx5e_detach_mod_hdr(struct mlx5e_priv *priv,
	list_del(&flow->mod_hdr);
	spin_unlock(&flow->mh->flows_lock);

	mlx5e_mod_hdr_put(priv, flow->mh);
	mlx5e_mod_hdr_put(priv, flow->mh, get_flow_name_space(flow));
	flow->mh = NULL;
}

@@ -3865,6 +3878,7 @@ int mlx5e_tc_nic_init(struct mlx5e_priv *priv)
	int err;

	mutex_init(&tc->t_lock);
	mutex_init(&tc->mod_hdr.lock);
	hash_init(tc->mod_hdr.hlist);
	mutex_init(&tc->hairpin_tbl_lock);
	hash_init(tc->hairpin_tbl);
@@ -3898,6 +3912,7 @@ void mlx5e_tc_nic_cleanup(struct mlx5e_priv *priv)
	if (tc->netdevice_nb.notifier_call)
		unregister_netdevice_notifier(&tc->netdevice_nb);

	mutex_destroy(&tc->mod_hdr.lock);
	mutex_destroy(&tc->hairpin_tbl_lock);

	rhashtable_destroy(&tc->ht);
+2 −0
Original line number Diff line number Diff line
@@ -2000,6 +2000,7 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev)
		goto abort;

	hash_init(esw->offloads.encap_tbl);
	mutex_init(&esw->offloads.mod_hdr.lock);
	hash_init(esw->offloads.mod_hdr.hlist);
	atomic64_set(&esw->offloads.num_flows, 0);
	mutex_init(&esw->state_lock);
@@ -2037,6 +2038,7 @@ void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw)
	esw->dev->priv.eswitch = NULL;
	destroy_workqueue(esw->work_queue);
	esw_offloads_cleanup_reps(esw);
	mutex_destroy(&esw->offloads.mod_hdr.lock);
	kfree(esw->vports);
	kfree(esw);
}
+1 −0
Original line number Diff line number Diff line
@@ -127,6 +127,7 @@ struct mlx5_flow_destination {
};

struct mod_hdr_tbl {
	struct mutex lock; /* protects hlist */
	DECLARE_HASHTABLE(hlist, 8);
};