Commit 041861b4 authored by Yevgeny Kliteynik's avatar Yevgeny Kliteynik Committed by Jakub Kicinski
Browse files

net/mlx5: HWS, fix redundant extension of action templates



When a rule is inserted into a matcher, we search for the suitable
action template. If such template is not found, action template array
is extended with the new template. However, when several threads are
performing this in parallel, there is a race - we can end up with
extending the action templates array with the same template.

This patch is doing the following:
 - refactor the code to find action template index in rule create and
   update, have the common code in an auxiliary function
 - after locking all the queues, check again if the action template
   array still needs to be extended

Signed-off-by: default avatarVlad Dogaru <vdogaru@nvidia.com>
Signed-off-by: default avatarYevgeny Kliteynik <kliteyn@nvidia.com>
Reviewed-by: default avatarMark Bloch <mbloch@nvidia.com>
Signed-off-by: default avatarTariq Toukan <tariqt@nvidia.com>
Link: https://patch.msgid.link/1746992290-568936-9-git-send-email-tariqt@nvidia.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 4c56b5cb
Loading
Loading
Loading
Loading
+54 −51
Original line number Diff line number Diff line
@@ -789,51 +789,79 @@ hws_bwc_matcher_rehash_size(struct mlx5hws_bwc_matcher *bwc_matcher)
	return hws_bwc_matcher_move(bwc_matcher);
}

int mlx5hws_bwc_rule_create_simple(struct mlx5hws_bwc_rule *bwc_rule,
				   u32 *match_param,
static int hws_bwc_rule_get_at_idx(struct mlx5hws_bwc_rule *bwc_rule,
				   struct mlx5hws_rule_action rule_actions[],
				   u32 flow_source,
				   u16 bwc_queue_idx)
{
	struct mlx5hws_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher;
	struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx;
	struct mlx5hws_rule_attr rule_attr;
	struct mutex *queue_lock; /* Protect the queue */
	u32 num_of_rules;
	int ret = 0;
	int at_idx;

	mlx5hws_bwc_rule_fill_attr(bwc_matcher, bwc_queue_idx, flow_source, &rule_attr);

	queue_lock = hws_bwc_get_queue_lock(ctx, bwc_queue_idx);

	mutex_lock(queue_lock);
	int at_idx, ret;

	/* check if rehash needed due to missing action template */
	at_idx = hws_bwc_matcher_find_at(bwc_matcher, rule_actions);
	if (unlikely(at_idx < 0)) {
	if (likely(at_idx >= 0))
		return at_idx;

	/* we need to extend BWC matcher action templates array */
	queue_lock = hws_bwc_get_queue_lock(ctx, bwc_queue_idx);
	mutex_unlock(queue_lock);
	hws_bwc_lock_all_queues(ctx);

	/* check again - perhaps other thread already did extend_at */
	at_idx = hws_bwc_matcher_find_at(bwc_matcher, rule_actions);
	if (at_idx >= 0)
		goto out;

	ret = hws_bwc_matcher_extend_at(bwc_matcher, rule_actions);
	if (unlikely(ret)) {
			hws_bwc_unlock_all_queues(ctx);
			return ret;
		mlx5hws_err(ctx, "BWC rule: failed extending AT (%d)", ret);
		at_idx = -EINVAL;
		goto out;
	}

	/* action templates array was extended, we need the last idx */
	at_idx = bwc_matcher->num_of_at - 1;

	ret = mlx5hws_matcher_attach_at(bwc_matcher->matcher,
					bwc_matcher->at[at_idx]);
	if (unlikely(ret)) {
			hws_bwc_unlock_all_queues(ctx);
			return ret;
		mlx5hws_err(ctx, "BWC rule: failed attaching new AT (%d)", ret);
		at_idx = -EINVAL;
		goto out;
	}

out:
	hws_bwc_unlock_all_queues(ctx);
	mutex_lock(queue_lock);
	return at_idx;
}

int mlx5hws_bwc_rule_create_simple(struct mlx5hws_bwc_rule *bwc_rule,
				   u32 *match_param,
				   struct mlx5hws_rule_action rule_actions[],
				   u32 flow_source,
				   u16 bwc_queue_idx)
{
	struct mlx5hws_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher;
	struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx;
	struct mlx5hws_rule_attr rule_attr;
	struct mutex *queue_lock; /* Protect the queue */
	u32 num_of_rules;
	int ret = 0;
	int at_idx;

	mlx5hws_bwc_rule_fill_attr(bwc_matcher, bwc_queue_idx, flow_source, &rule_attr);

	queue_lock = hws_bwc_get_queue_lock(ctx, bwc_queue_idx);

	mutex_lock(queue_lock);

	at_idx = hws_bwc_rule_get_at_idx(bwc_rule, rule_actions, bwc_queue_idx);
	if (unlikely(at_idx < 0)) {
		mutex_unlock(queue_lock);
		mlx5hws_err(ctx, "BWC rule create: failed getting AT (%d)",
			    ret);
		return -EINVAL;
	}

	/* check if number of rules require rehash */
@@ -971,38 +999,13 @@ hws_bwc_rule_action_update(struct mlx5hws_bwc_rule *bwc_rule,

	mutex_lock(queue_lock);

	/* check if rehash needed due to missing action template */
	at_idx = hws_bwc_matcher_find_at(bwc_matcher, rule_actions);
	at_idx = hws_bwc_rule_get_at_idx(bwc_rule, rule_actions, idx);
	if (unlikely(at_idx < 0)) {
		/* we need to extend BWC matcher action templates array */
		mutex_unlock(queue_lock);
		hws_bwc_lock_all_queues(ctx);

		/* check again - perhaps other thread already did extend_at */
		at_idx = hws_bwc_matcher_find_at(bwc_matcher, rule_actions);
		if (likely(at_idx < 0)) {
			ret = hws_bwc_matcher_extend_at(bwc_matcher, rule_actions);
			if (unlikely(ret)) {
				hws_bwc_unlock_all_queues(ctx);
				mlx5hws_err(ctx, "BWC rule update: failed extending AT (%d)", ret);
		mlx5hws_err(ctx, "BWC rule update: failed getting AT\n");
		return -EINVAL;
	}

			/* action templates array was extended, we need the last idx */
			at_idx = bwc_matcher->num_of_at - 1;

			ret = mlx5hws_matcher_attach_at(bwc_matcher->matcher,
							bwc_matcher->at[at_idx]);
			if (unlikely(ret)) {
				hws_bwc_unlock_all_queues(ctx);
				return ret;
			}
		}

		hws_bwc_unlock_all_queues(ctx);
		mutex_lock(queue_lock);
	}

	ret = hws_bwc_rule_update_sync(bwc_rule,
				       at_idx,
				       rule_actions,