Commit 7ee3f6d2 authored by Alex Vesker's avatar Alex Vesker Committed by Saeed Mahameed
Browse files

net/mlx5: DR, Create multiple destination action from dr_create_fte



Until now it was possible to pass a packet to a single destination such
as vport or flow table. With the new support if multiple vports or multiple
tables are provided as destinations, fs_dr will create a multiple
destination table action, this action should replace other destination
actions provided to mlx5dr_create_rule.
Each vport destination can be provided with a reformat actions which
will be done before forwarding the packet to the vport.

Signed-off-by: default avatarAlex Vesker <valex@mellanox.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@mellanox.com>
parent b8853c96
Loading
Loading
Loading
Loading
+72 −16
Original line number Diff line number Diff line
@@ -206,6 +206,12 @@ static struct mlx5dr_action *create_action_push_vlan(struct mlx5dr_domain *domai
	return mlx5dr_action_create_push_vlan(domain, htonl(vlan_hdr));
}

static bool contain_vport_reformat_action(struct mlx5_flow_rule *dst)
{
	return dst->dest_attr.type == MLX5_FLOW_DESTINATION_TYPE_VPORT &&
		dst->dest_attr.vport.flags & MLX5_FLOW_DEST_VPORT_REFORMAT_ID;
}

#define MLX5_FLOW_CONTEXT_ACTION_MAX  20
static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
				  struct mlx5_flow_table *ft,
@@ -213,7 +219,7 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
				  struct fs_fte *fte)
{
	struct mlx5dr_domain *domain = ns->fs_dr_domain.dr_domain;
	struct mlx5dr_action *term_action = NULL;
	struct mlx5dr_action_dest *term_actions;
	struct mlx5dr_match_parameters params;
	struct mlx5_core_dev *dev = ns->dev;
	struct mlx5dr_action **fs_dr_actions;
@@ -223,6 +229,7 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
	struct mlx5dr_rule *rule;
	struct mlx5_flow_rule *dst;
	int fs_dr_num_actions = 0;
	int num_term_actions = 0;
	int num_actions = 0;
	size_t match_sz;
	int err = 0;
@@ -233,18 +240,38 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,

	actions = kcalloc(MLX5_FLOW_CONTEXT_ACTION_MAX, sizeof(*actions),
			  GFP_KERNEL);
	if (!actions)
		return -ENOMEM;
	if (!actions) {
		err = -ENOMEM;
		goto out_err;
	}

	fs_dr_actions = kcalloc(MLX5_FLOW_CONTEXT_ACTION_MAX,
				sizeof(*fs_dr_actions), GFP_KERNEL);
	if (!fs_dr_actions) {
		kfree(actions);
		return -ENOMEM;
		err = -ENOMEM;
		goto free_actions_alloc;
	}

	term_actions = kcalloc(MLX5_FLOW_CONTEXT_ACTION_MAX,
			       sizeof(*term_actions), GFP_KERNEL);
	if (!term_actions) {
		err = -ENOMEM;
		goto free_fs_dr_actions_alloc;
	}

	match_sz = sizeof(fte->val);

	/* Drop reformat action bit if destination vport set with reformat */
	if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
		list_for_each_entry(dst, &fte->node.children, node.list) {
			if (!contain_vport_reformat_action(dst))
				continue;

			fte->action.action &= ~MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
			break;
		}
	}

	/* The order of the actions are must to be keep, only the following
	 * order is supported by SW steering:
	 * TX: push vlan -> modify header -> encap
@@ -335,7 +362,7 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
			goto free_actions;
		}
		fs_dr_actions[fs_dr_num_actions++] = tmp_action;
		term_action = tmp_action;
		term_actions[num_term_actions++].dest = tmp_action;
	}

	if (fte->flow_context.flow_tag) {
@@ -354,7 +381,8 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
			enum mlx5_flow_destination_type type = dst->dest_attr.type;
			u32 id;

			if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) {
			if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX ||
			    num_term_actions >= MLX5_FLOW_CONTEXT_ACTION_MAX) {
				err = -ENOSPC;
				goto free_actions;
			}
@@ -379,7 +407,7 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
					goto free_actions;
				}
				fs_dr_actions[fs_dr_num_actions++] = tmp_action;
				term_action = tmp_action;
				term_actions[num_term_actions++].dest = tmp_action;
				break;
			case MLX5_FLOW_DESTINATION_TYPE_VPORT:
				tmp_action = create_vport_action(domain, dst);
@@ -388,7 +416,14 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
					goto free_actions;
				}
				fs_dr_actions[fs_dr_num_actions++] = tmp_action;
				term_action = tmp_action;
				term_actions[num_term_actions].dest = tmp_action;

				if (dst->dest_attr.vport.flags &
				    MLX5_FLOW_DEST_VPORT_REFORMAT_ID)
					term_actions[num_term_actions].reformat =
						dst->dest_attr.vport.pkt_reformat->action.dr_action;

				num_term_actions++;
				break;
			default:
				err = -EOPNOTSUPP;
@@ -399,9 +434,22 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,

	params.match_sz = match_sz;
	params.match_buf = (u64 *)fte->val;

	if (term_action)
		actions[num_actions++] = term_action;
	if (num_term_actions == 1) {
		if (term_actions->reformat)
			actions[num_actions++] = term_actions->reformat;

		actions[num_actions++] = term_actions->dest;
	} else if (num_term_actions > 1) {
		tmp_action = mlx5dr_action_create_mult_dest_tbl(domain,
								term_actions,
								num_term_actions);
		if (!tmp_action) {
			err = -EOPNOTSUPP;
			goto free_actions;
		}
		fs_dr_actions[fs_dr_num_actions++] = tmp_action;
		actions[num_actions++] = tmp_action;
	}

	rule = mlx5dr_rule_create(group->fs_dr_matcher.dr_matcher,
				  &params,
@@ -412,7 +460,9 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
		goto free_actions;
	}

	kfree(term_actions);
	kfree(actions);

	fte->fs_dr_rule.dr_rule = rule;
	fte->fs_dr_rule.num_actions = fs_dr_num_actions;
	fte->fs_dr_rule.dr_actions = fs_dr_actions;
@@ -420,13 +470,18 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
	return 0;

free_actions:
	for (i = 0; i < fs_dr_num_actions; i++)
	/* Free in reverse order to handle action dependencies */
	for (i = fs_dr_num_actions - 1; i >= 0; i--)
		if (!IS_ERR_OR_NULL(fs_dr_actions[i]))
			mlx5dr_action_destroy(fs_dr_actions[i]);

	mlx5_core_err(dev, "Failed to create dr rule err(%d)\n", err);
	kfree(actions);
	kfree(term_actions);
free_fs_dr_actions_alloc:
	kfree(fs_dr_actions);
free_actions_alloc:
	kfree(actions);
out_err:
	mlx5_core_err(dev, "Failed to create dr rule err(%d)\n", err);
	return err;
}

@@ -533,7 +588,8 @@ static int mlx5_cmd_dr_delete_fte(struct mlx5_flow_root_namespace *ns,
	if (err)
		return err;

	for (i = 0; i < rule->num_actions; i++)
	/* Free in reverse order to handle action dependencies */
	for (i = rule->num_actions - 1; i >= 0; i--)
		if (!IS_ERR_OR_NULL(rule->dr_actions[i]))
			mlx5dr_action_destroy(rule->dr_actions[i]);