DPDK patches and discussions
 help / color / mirror / Atom feed
From: Gregory Etelson <getelson@nvidia.com>
To: <dev@dpdk.org>
Cc: getelson@nvidia.com,   <mkashani@nvidia.com>,
	rasland@nvidia.com, "Dariusz Sosnowski" <dsosnowski@nvidia.com>,
	"Viacheslav Ovsiienko" <viacheslavo@nvidia.com>,
	"Bing Zhao" <bingz@nvidia.com>, "Ori Kam" <orika@nvidia.com>,
	"Suanming Mou" <suanmingm@nvidia.com>,
	"Matan Azrad" <matan@nvidia.com>
Subject: [PATCH 5/5] net/mlx5: support non-template SAMPLE flow action
Date: Tue, 17 Jun 2025 16:39:33 +0300	[thread overview]
Message-ID: <20250617133933.313443-5-getelson@nvidia.com> (raw)
In-Reply-To: <20250617133933.313443-1-getelson@nvidia.com>

MLX5 HWS flow engine does not support the SAMPLE flow action.

The patch adds the SAMPLE action support to the non-template API.

Signed-off-by: Gregory Etelson <getelson@nvidia.com>
---
 drivers/net/mlx5/mlx5.c            |   1 +
 drivers/net/mlx5/mlx5_flow.h       |  26 +-
 drivers/net/mlx5/mlx5_flow_hw.c    |  40 ++-
 drivers/net/mlx5/mlx5_nta_sample.c | 401 ++++++++++++++++++++++++++---
 drivers/net/mlx5/mlx5_nta_sample.h |  25 ++
 5 files changed, 444 insertions(+), 49 deletions(-)
 create mode 100644 drivers/net/mlx5/mlx5_nta_sample.h

diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index b4bd43aae2..224f70994d 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -2368,6 +2368,7 @@ mlx5_dev_close(struct rte_eth_dev *dev)
 	mlx5_flex_item_port_cleanup(dev);
 	mlx5_indirect_list_handles_release(dev);
 #ifdef HAVE_MLX5_HWS_SUPPORT
+	mlx5_free_sample_context(dev);
 	flow_hw_destroy_vport_action(dev);
 	/* dr context will be closed after mlx5_os_free_shared_dr. */
 	flow_hw_resource_release(dev);
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 8186b85ae1..e9a981707d 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -54,6 +54,8 @@ enum mlx5_rte_flow_action_type {
 
 struct mlx5_rte_flow_action_mirror {
 	struct mlx5_mirror *mirror;
+	uint32_t sample_group;
+	uint32_t suffix_group;
 };
 
 /* Private (internal) Field IDs for MODIFY_FIELD action. */
@@ -1356,6 +1358,8 @@ struct rte_flow_nt2hws {
 	struct rte_flow_hw_aux *flow_aux;
 	/** Modify header pointer. */
 	struct mlx5_flow_dv_modify_hdr_resource *modify_hdr;
+	/** Group Id used in SAMPLE flow action */
+	uint32_t sample_group;
 	/** Chain NTA flows. */
 	SLIST_ENTRY(rte_flow_hw) next;
 	/** Encap/decap index. */
@@ -3748,12 +3752,22 @@ mlx5_hw_create_mirror(struct rte_eth_dev *dev,
 		      const struct rte_flow_action *actions,
 		      struct rte_flow_error *error);
 
-struct rte_flow_hw *
-mlx5_flow_nta_handle_sample(struct rte_eth_dev *dev,
-			    const struct rte_flow_attr *attr,
-			    const struct rte_flow_item pattern[],
-			    const struct rte_flow_action actions[],
-			    struct rte_flow_error *error);
+int
+mlx5_flow_hw_group_set_miss_actions(struct rte_eth_dev *dev,
+				    uint32_t group_id,
+				    const struct rte_flow_group_attr *attr,
+				    const struct rte_flow_action actions[],
+				    struct rte_flow_error *error);
+
+uint64_t
+mlx5_flow_hw_action_flags_get(const struct rte_flow_action actions[],
+			      const struct rte_flow_action **qrss,
+			      const struct rte_flow_action **mark,
+			      int *encap_idx,
+			      int *act_cnt,
+			      struct rte_flow_error *error);
+
+#include "mlx5_nta_sample.h"
 
 #endif
 #endif /* RTE_PMD_MLX5_FLOW_H_ */
diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c
index f1b90d6e56..db162e5a4f 100644
--- a/drivers/net/mlx5/mlx5_flow_hw.c
+++ b/drivers/net/mlx5/mlx5_flow_hw.c
@@ -574,8 +574,8 @@ flow_hw_hashfields_set(struct mlx5_flow_rss_desc *rss_desc,
 	*hash_fields |= fields;
 }
 
-static uint64_t
-flow_hw_action_flags_get(const struct rte_flow_action actions[],
+uint64_t
+mlx5_flow_hw_action_flags_get(const struct rte_flow_action actions[],
 			 const struct rte_flow_action **qrss,
 			 const struct rte_flow_action **mark,
 			 int *encap_idx,
@@ -1987,6 +1987,7 @@ hws_table_tmpl_translate_indirect_mirror(struct rte_eth_dev *dev,
 			 action_src, action_dst,
 			 flow_hw_translate_indirect_mirror);
 	}
+
 	return ret;
 }
 
@@ -2903,6 +2904,12 @@ __flow_hw_translate_actions_template(struct rte_eth_dev *dev,
 				goto err;
 			}
 			break;
+		case MLX5_RTE_FLOW_ACTION_TYPE_MIRROR:
+			if (__flow_hw_act_data_general_append(priv, acts,
+							      actions->type,
+							      src_pos, dr_pos))
+				goto err;
+			break;
 		case RTE_FLOW_ACTION_TYPE_END:
 			actions_end = true;
 			break;
@@ -3743,6 +3750,12 @@ flow_hw_actions_construct(struct rte_eth_dev *dev,
 				((const struct rte_flow_action_jump_to_table_index *)
 				action->conf)->index;
 			break;
+		case MLX5_RTE_FLOW_ACTION_TYPE_MIRROR: {
+			const struct mlx5_rte_flow_action_mirror *mirror_conf = action->conf;
+
+			rule_acts[act_data->action_dst].action = mirror_conf->mirror->mirror_action;
+		}
+			break;
 		default:
 			break;
 		}
@@ -3995,6 +4008,7 @@ flow_hw_async_flow_create_generic(struct rte_eth_dev *dev,
 		aux->matcher_selector = selector;
 		flow->flags |= MLX5_FLOW_HW_FLOW_FLAG_MATCHER_SELECTOR;
 	}
+
 	if (likely(!ret)) {
 		flow_hw_q_inc_flow_ops(priv, queue);
 		return (struct rte_flow *)flow;
@@ -5694,8 +5708,8 @@ flow_hw_group_unset_miss_group(struct rte_eth_dev *dev,
  *   0 on success, a negative errno value otherwise and rte_errno is set.
  */
 
-static int
-flow_hw_group_set_miss_actions(struct rte_eth_dev *dev,
+int
+mlx5_flow_hw_group_set_miss_actions(struct rte_eth_dev *dev,
 			       uint32_t group_id,
 			       const struct rte_flow_group_attr *attr,
 			       const struct rte_flow_action actions[],
@@ -7623,6 +7637,10 @@ flow_hw_parse_flow_actions_to_dr_actions(struct rte_eth_dev *dev,
 			at->dr_off[i] = curr_off;
 			action_types[curr_off++] = MLX5DR_ACTION_TYP_JUMP_TO_MATCHER;
 			break;
+		case MLX5_RTE_FLOW_ACTION_TYPE_MIRROR:
+			at->dr_off[i] = curr_off;
+			action_types[curr_off++] = MLX5DR_ACTION_TYP_DEST_ARRAY;
+				break;
 		default:
 			type = mlx5_hw_dr_action_types[at->actions[i].type];
 			at->dr_off[i] = curr_off;
@@ -14107,6 +14125,8 @@ flow_hw_destroy(struct rte_eth_dev *dev, struct rte_flow_hw *flow)
 	}
 	if (flow->nt2hws->matcher)
 		flow_hw_unregister_matcher(dev, flow->nt2hws->matcher);
+	if (flow->nt2hws->sample_group != 0)
+		mlx5_nta_release_sample_group(dev, flow->nt2hws->sample_group);
 }
 
 #ifdef HAVE_MLX5_HWS_SUPPORT
@@ -14180,7 +14200,7 @@ static uintptr_t flow_hw_list_create(struct rte_eth_dev *dev,
 	const struct rte_flow_action *qrss = NULL;
 	const struct rte_flow_action *mark = NULL;
 	uint64_t item_flags = 0;
-	uint64_t action_flags = flow_hw_action_flags_get(actions, &qrss, &mark,
+	uint64_t action_flags = mlx5_flow_hw_action_flags_get(actions, &qrss, &mark,
 							 &encap_idx, &actions_n, error);
 	struct mlx5_flow_hw_split_resource resource = {
 		.suffix = {
@@ -14220,7 +14240,13 @@ static uintptr_t flow_hw_list_create(struct rte_eth_dev *dev,
 			goto free;
 	}
 	if (action_flags & MLX5_FLOW_ACTION_SAMPLE) {
-		mlx5_flow_nta_handle_sample(dev, attr, items, actions, error);
+		flow = mlx5_flow_nta_handle_sample(dev, type, attr, items,
+						   actions,
+						   item_flags, action_flags,
+						   error);
+		if (flow != NULL)
+			return (uintptr_t)flow;
+		goto free;
 	}
 	if (action_flags & MLX5_FLOW_ACTION_RSS) {
 		const struct rte_flow_action_rss
@@ -15378,7 +15404,7 @@ const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = {
 	.template_table_create = flow_hw_template_table_create,
 	.template_table_destroy = flow_hw_table_destroy,
 	.table_resize = flow_hw_table_resize,
-	.group_set_miss_actions = flow_hw_group_set_miss_actions,
+	.group_set_miss_actions = mlx5_flow_hw_group_set_miss_actions,
 	.async_flow_create = flow_hw_async_flow_create,
 	.async_flow_create_by_index = flow_hw_async_flow_create_by_index,
 	.async_flow_update = flow_hw_async_flow_update,
diff --git a/drivers/net/mlx5/mlx5_nta_sample.c b/drivers/net/mlx5/mlx5_nta_sample.c
index d6ffbd8e33..c6012ca5c9 100644
--- a/drivers/net/mlx5/mlx5_nta_sample.c
+++ b/drivers/net/mlx5/mlx5_nta_sample.c
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright (c) 2024 NVIDIA Corporation & Affiliates
+ * Copyright (c) 2025 NVIDIA Corporation & Affiliates
  */
 
 #include <rte_flow.h>
@@ -9,6 +9,8 @@
 #include "mlx5_flow.h"
 #include "mlx5_rx.h"
 
+SLIST_HEAD(mlx5_flow_head, rte_flow_hw);
+
 struct mlx5_nta_sample_ctx {
 	uint32_t groups_num;
 	struct mlx5_indexed_pool *group_ids;
@@ -17,6 +19,18 @@ struct mlx5_nta_sample_ctx {
 	struct mlx5_list *suffix_groups; /* cache groups for suffix actions */
 };
 
+static void
+release_chained_flows(struct rte_eth_dev *dev, struct mlx5_flow_head *flow_head,
+		      enum mlx5_flow_type type)
+{
+	struct rte_flow_hw *flow = SLIST_FIRST(flow_head);
+
+	if (flow) {
+		flow->nt2hws->chaned_flow = 0;
+		flow_hw_list_destroy(dev, type, (uintptr_t)flow);
+	}
+}
+
 static uint32_t
 alloc_cached_group(struct rte_eth_dev *dev)
 {
@@ -40,7 +54,13 @@ release_cached_group(struct rte_eth_dev *dev, uint32_t group)
 	mlx5_ipool_free(sample_ctx->group_ids, group - MLX5_FLOW_TABLE_SAMPLE_BASE);
 }
 
-static void
+void
+mlx5_nta_release_sample_group(struct rte_eth_dev *dev, uint32_t group)
+{
+	release_cached_group(dev, group);
+}
+
+void
 mlx5_free_sample_context(struct rte_eth_dev *dev)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
@@ -364,42 +384,68 @@ get_registered_group(struct rte_flow_action *actions, struct mlx5_list *cache)
 	return ent ? container_of(ent, struct mlx5_nta_sample_cached_group, entry)->group : 0;
 }
 
-static struct mlx5_mirror *
-mlx5_create_nta_mirror(struct rte_eth_dev *dev,
-		       const struct rte_flow_attr *attr,
-		       struct rte_flow_action *sample_actions,
-		       struct rte_flow_action *suffix_actions,
-		       struct rte_flow_error *error)
+static int
+mlx5_nta_create_mirror_action(struct rte_eth_dev *dev,
+			      const struct rte_flow_attr *attr,
+			      struct rte_flow_action *sample_actions,
+			      struct rte_flow_action *suffix_actions,
+			      struct mlx5_rte_flow_action_mirror *mirror_conf,
+			      struct rte_flow_error *error)
 {
-	struct mlx5_mirror *mirror;
-	uint32_t sample_group, suffix_group;
 	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_nta_sample_ctx *ctx = priv->nta_sample_ctx;
 	struct mlx5_flow_template_table_cfg table_cfg = {
 		.external = true,
 		.attr = {
-			.flow_attr = {
-				.ingress = attr->ingress,
-				.egress = attr->egress,
-				.transfer = attr->transfer
-			}
+			.flow_attr = *attr
 		}
 	};
 
-	sample_group = get_registered_group(sample_actions, ctx->sample_groups);
-	if (sample_group == 0) {
-		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
-					   NULL, "Failed to register sample group");
-		return NULL;
+	mirror_conf->sample_group = get_registered_group(sample_actions, ctx->sample_groups);
+	if (mirror_conf->sample_group == 0)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+					  NULL, "Failed to register sample group");
+	mirror_conf->suffix_group = get_registered_group(suffix_actions, ctx->suffix_groups);
+	if (mirror_conf->suffix_group == 0)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+					  NULL, "Failed to register suffix group");
+	mirror_conf->mirror = get_registered_mirror(&table_cfg, ctx->mirror_actions,
+						    mirror_conf->sample_group,
+						    mirror_conf->suffix_group);
+	return 0;
+}
+
+static void
+save_sample_group(struct rte_flow_hw *flow, uint32_t group)
+{
+	flow->nt2hws->sample_group = group;
+}
+
+static uint32_t
+generate_random_mask(uint32_t ratio)
+{
+	uint32_t i;
+	double goal = 1.0 / ratio;
+
+	/* Check if the ratio value is power of 2 */
+	if (rte_popcount32(ratio) == 1) {
+		for (i = 2; i < UINT32_WIDTH; i++) {
+			if (RTE_BIT32(i) == ratio)
+				return RTE_BIT32(i) - 1;
+		}
 	}
-	suffix_group = get_registered_group(suffix_actions, ctx->suffix_groups);
-	if (suffix_group == 0) {
-		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
-					   NULL, "Failed to register suffix group");
-		return NULL;
+
+	/*
+	 * Find the last power of 2 with ratio larger then the goal.
+	 */
+	for (i = 2; i < UINT32_WIDTH; i++) {
+		double res = 1.0 / RTE_BIT32(i);
+
+		if (res < goal)
+			return RTE_BIT32(i - 1) - 1;
 	}
-	mirror = get_registered_mirror(&table_cfg, ctx->mirror_actions, sample_group, suffix_group);
-	return mirror;
+
+	return UINT32_MAX;
 }
 
 static void
@@ -427,18 +473,287 @@ mlx5_nta_parse_sample_actions(const struct rte_flow_action *action,
 	} while ((action++)->type != RTE_FLOW_ACTION_TYPE_END);
 }
 
+static bool
+validate_prefix_actions(const struct rte_flow_action *actions)
+{
+	uint32_t i = 0;
+
+	while (actions[i].type != RTE_FLOW_ACTION_TYPE_END)
+		i++;
+	return i < MLX5_HW_MAX_ACTS - 1;
+}
+
+static void
+action_append(struct rte_flow_action *actions, const struct rte_flow_action *last)
+{
+	uint32_t i = 0;
+
+	while (actions[i].type != RTE_FLOW_ACTION_TYPE_END)
+		i++;
+	actions[i] = *last;
+}
+
+static int
+create_mirror_aux_flows(struct rte_eth_dev *dev,
+			enum mlx5_flow_type type,
+			const struct rte_flow_attr *attr,
+			struct rte_flow_action *suffix_actions,
+			struct rte_flow_action *sample_actions,
+			struct mlx5_rte_flow_action_mirror *mirror_conf,
+			struct mlx5_flow_head *flow_head,
+			struct rte_flow_error *error)
+{
+	const struct rte_flow_attr suffix_attr = {
+		.ingress = attr->ingress,
+		.egress = attr->egress,
+		.transfer = attr->transfer,
+		.group = mirror_conf->suffix_group,
+	};
+	const struct rte_flow_attr sample_attr = {
+		.ingress = attr->ingress,
+		.egress = attr->egress,
+		.transfer = attr->transfer,
+		.group = mirror_conf->sample_group,
+	};
+	const struct rte_flow_item secondary_pattern[1] = {
+		[0] = { .type = RTE_FLOW_ITEM_TYPE_END }
+	};
+	int ret, encap_idx, actions_num;
+	uint64_t suffix_action_flags, sample_action_flags;
+	const struct rte_flow_action *qrss_action = NULL, *mark_action = NULL;
+	struct rte_flow_hw *suffix_flow = NULL, *sample_flow = NULL;
+
+	suffix_action_flags = mlx5_flow_hw_action_flags_get(suffix_actions,
+						       &qrss_action, &mark_action,
+						       &encap_idx, &actions_num, error);
+	if (qrss_action != NULL && qrss_action->type == RTE_FLOW_ACTION_TYPE_RSS)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+			"RSS action is not supported in suffix sample action");
+	sample_action_flags = mlx5_flow_hw_action_flags_get(sample_actions,
+						       &qrss_action, &mark_action,
+						       &encap_idx, &actions_num, error);
+	if (qrss_action != NULL && qrss_action->type == RTE_FLOW_ACTION_TYPE_RSS)
+		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+			"RSS action is not supported in sample action");
+	ret = flow_hw_create_flow(dev, type, &suffix_attr,
+				  secondary_pattern, suffix_actions,
+				  MLX5_FLOW_LAYER_OUTER_L2, suffix_action_flags,
+				  true, &suffix_flow, error);
+	if (ret != 0)
+		return ret;
+	save_sample_group(suffix_flow, mirror_conf->suffix_group);
+	ret = flow_hw_create_flow(dev, type, &sample_attr,
+				  secondary_pattern, sample_actions,
+				  MLX5_FLOW_LAYER_OUTER_L2, sample_action_flags,
+				  true, &sample_flow, error);
+	if (ret != 0) {
+		flow_hw_destroy(dev, suffix_flow);
+		return ret;
+	}
+	save_sample_group(sample_flow, mirror_conf->sample_group);
+	suffix_flow->nt2hws->chaned_flow = 1;
+	SLIST_INSERT_HEAD(flow_head, suffix_flow, nt2hws->next);
+	sample_flow->nt2hws->chaned_flow = 1;
+	SLIST_INSERT_HEAD(flow_head, sample_flow, nt2hws->next);
+	return 0;
+}
+
+static struct rte_flow_hw *
+create_sample_flow(struct rte_eth_dev *dev,
+		   enum mlx5_flow_type type,
+		   const struct rte_flow_attr *attr,
+		   uint32_t ratio,
+		   uint32_t sample_group,
+		   struct mlx5_rte_flow_action_mirror *mirror_conf,
+		   struct rte_flow_error *error)
+{
+	struct rte_flow_hw *sample_flow = NULL;
+	uint32_t random_mask = generate_random_mask(ratio);
+	const struct rte_flow_attr sample_attr = {
+		.ingress = attr->ingress,
+		.egress = attr->egress,
+		.transfer = attr->transfer,
+		.group = sample_group,
+	};
+	const struct rte_flow_item sample_pattern[2] = {
+		[0] = {
+			.type = RTE_FLOW_ITEM_TYPE_RANDOM,
+			.mask = &(struct rte_flow_item_random) {
+				.value = random_mask
+			},
+			.spec = &(struct rte_flow_item_random) {
+				.value = 1
+			},
+		},
+		[1] = { .type = RTE_FLOW_ITEM_TYPE_END }
+	};
+	const struct rte_flow_action sample_actions[2] = {
+		[0] = {
+			.type = (enum rte_flow_action_type)MLX5_RTE_FLOW_ACTION_TYPE_MIRROR,
+			.conf = mirror_conf
+		},
+		[1] = { .type = RTE_FLOW_ACTION_TYPE_END }
+	};
+
+	if (random_mask > UINT16_MAX)
+		return NULL;
+	flow_hw_create_flow(dev, type, &sample_attr, sample_pattern, sample_actions,
+			    0, 0, true, &sample_flow, error);
+	save_sample_group(sample_flow, sample_group);
+	return sample_flow;
+}
+
+static struct rte_flow_hw *
+create_sample_miss_flow(struct rte_eth_dev *dev,
+			enum mlx5_flow_type type,
+			const struct rte_flow_attr *attr,
+			uint32_t sample_group, uint32_t suffix_group,
+			const struct rte_flow_action *miss_actions,
+			struct rte_flow_error *error)
+{
+	int ret;
+	struct rte_flow_hw *miss_flow = NULL;
+	const struct rte_flow_attr miss_attr = {
+		.ingress = attr->ingress,
+		.egress = attr->egress,
+		.transfer = attr->transfer,
+		.group = suffix_group,
+	};
+	const struct rte_flow_item miss_pattern[1] = {
+		[0] = { .type = RTE_FLOW_ITEM_TYPE_END }
+	};
+	const struct rte_flow_group_attr sample_group_attr = {
+		.ingress = attr->ingress,
+		.egress = attr->egress,
+		.transfer = attr->transfer,
+	};
+	const struct rte_flow_action sample_miss_actions[2] = {
+		[0] = {
+			.type = RTE_FLOW_ACTION_TYPE_JUMP,
+			.conf = &(struct rte_flow_action_jump) { .group = suffix_group }
+		},
+		[1] = { .type = RTE_FLOW_ACTION_TYPE_END }
+	};
+
+	ret = mlx5_flow_hw_group_set_miss_actions(dev, sample_group, &sample_group_attr,
+					     sample_miss_actions, error);
+	if (ret != 0)
+		return NULL;
+	flow_hw_create_flow(dev, type, &miss_attr, miss_pattern, miss_actions,
+			    0, 0, true, &miss_flow, error);
+	return miss_flow;
+}
+
+static struct rte_flow_hw *
+mlx5_nta_create_sample_flow(struct rte_eth_dev *dev,
+			     enum mlx5_flow_type type,
+			     const struct rte_flow_attr *attr,
+			     uint32_t sample_ratio,
+			     uint64_t item_flags, uint64_t action_flags,
+			     const struct rte_flow_item *pattern,
+			     struct rte_flow_action *prefix_actions,
+			     struct rte_flow_action *suffix_actions,
+			     struct rte_flow_action *sample_actions,
+			     struct mlx5_rte_flow_action_mirror *mirror_conf,
+			     struct rte_flow_error *error)
+{
+	int ret;
+	uint32_t sample_group = alloc_cached_group(dev);
+	struct mlx5_flow_head flow_head = SLIST_HEAD_INITIALIZER(NULL);
+	struct rte_flow_hw *base_flow = NULL, *sample_flow, *miss_flow = NULL;
+
+	if (sample_group == 0)
+		goto error;
+	ret = create_mirror_aux_flows(dev, type, attr,
+				      suffix_actions, sample_actions,
+				      mirror_conf, &flow_head, error);
+	if (ret != 0)
+		return NULL;
+	miss_flow = create_sample_miss_flow(dev, type, attr,
+					    sample_group, mirror_conf->suffix_group,
+					    suffix_actions, error);
+	if (miss_flow == NULL)
+		goto error;
+	miss_flow->nt2hws->chaned_flow = 1;
+	SLIST_INSERT_HEAD(&flow_head, miss_flow, nt2hws->next);
+	sample_flow = create_sample_flow(dev, type, attr, sample_ratio, sample_group,
+					 mirror_conf, error);
+	if (sample_flow == NULL)
+		goto error;
+	sample_flow->nt2hws->chaned_flow = 1;
+	SLIST_INSERT_HEAD(&flow_head, sample_flow, nt2hws->next);
+	action_append(prefix_actions,
+		&(struct rte_flow_action) {
+			.type = RTE_FLOW_ACTION_TYPE_JUMP,
+			.conf = &(struct rte_flow_action_jump) { .group = sample_group }
+		});
+	ret = flow_hw_create_flow(dev, type, attr, pattern, prefix_actions,
+				  item_flags, action_flags, true, &base_flow, error);
+	if (ret != 0)
+		goto error;
+	SLIST_INSERT_HEAD(&flow_head, base_flow, nt2hws->next);
+	return base_flow;
+
+error:
+	release_chained_flows(dev, &flow_head, type);
+	return NULL;
+}
+
+static struct rte_flow_hw *
+mlx5_nta_create_mirror_flow(struct rte_eth_dev *dev,
+			     enum mlx5_flow_type type,
+			     const struct rte_flow_attr *attr,
+			     uint64_t item_flags, uint64_t action_flags,
+			     const struct rte_flow_item *pattern,
+			     struct rte_flow_action *prefix_actions,
+			     struct rte_flow_action *suffix_actions,
+			     struct rte_flow_action *sample_actions,
+			     struct mlx5_rte_flow_action_mirror *mirror_conf,
+			     struct rte_flow_error *error)
+{
+	int ret;
+	struct rte_flow_hw *base_flow = NULL;
+	struct mlx5_flow_head flow_head = SLIST_HEAD_INITIALIZER(NULL);
+
+	ret = create_mirror_aux_flows(dev, type, attr,
+				      suffix_actions, sample_actions,
+				      mirror_conf, &flow_head, error);
+	if (ret != 0)
+		return NULL;
+	action_append(prefix_actions,
+		&(struct rte_flow_action) {
+			.type = (enum rte_flow_action_type)MLX5_RTE_FLOW_ACTION_TYPE_MIRROR,
+			.conf = mirror_conf
+		});
+	ret = flow_hw_create_flow(dev, type, attr, pattern, prefix_actions,
+				  item_flags, action_flags,
+				  true, &base_flow, error);
+	if (ret != 0)
+		goto error;
+	SLIST_INSERT_HEAD(&flow_head, base_flow, nt2hws->next);
+	return base_flow;
+
+error:
+	release_chained_flows(dev, &flow_head, type);
+	return NULL;
+}
+
 struct rte_flow_hw *
 mlx5_flow_nta_handle_sample(struct rte_eth_dev *dev,
+			    enum mlx5_flow_type type,
 			    const struct rte_flow_attr *attr,
-			    const struct rte_flow_item pattern[] __rte_unused,
-			    const struct rte_flow_action actions[] __rte_unused,
+			    const struct rte_flow_item pattern[],
+			    const struct rte_flow_action actions[],
+			    uint64_t item_flags, uint64_t action_flags,
 			    struct rte_flow_error *error)
 {
+	int ret;
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_mirror *mirror;
+	struct rte_flow_hw *flow = NULL;
 	const struct rte_flow_action *sample;
 	struct rte_flow_action *sample_actions;
 	const struct rte_flow_action_sample *sample_conf;
+	struct mlx5_rte_flow_action_mirror mirror_conf = { NULL };
 	struct rte_flow_action prefix_actions[MLX5_HW_MAX_ACTS] = { 0 };
 	struct rte_flow_action suffix_actions[MLX5_HW_MAX_ACTS] = { 0 };
 
@@ -451,12 +766,26 @@ mlx5_flow_nta_handle_sample(struct rte_eth_dev *dev,
 		}
 	}
 	mlx5_nta_parse_sample_actions(actions, &sample, prefix_actions, suffix_actions);
+	if (!validate_prefix_actions(prefix_actions)) {
+		rte_flow_error_set(error, -EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+				   NULL, "Too many actions");
+		return NULL;
+	}
 	sample_conf = (const struct rte_flow_action_sample *)sample->conf;
 	sample_actions = (struct rte_flow_action *)(uintptr_t)sample_conf->actions;
-	mirror = mlx5_create_nta_mirror(dev, attr, sample_actions,
-					suffix_actions, error);
-	if (mirror == NULL)
-		goto error;
-error:
-	return NULL;
+	ret = mlx5_nta_create_mirror_action(dev, attr, sample_actions,
+					    suffix_actions, &mirror_conf, error);
+	if (ret != 0)
+		return NULL;
+	if (sample_conf->ratio == 1) {
+		flow = mlx5_nta_create_mirror_flow(dev, type, attr, item_flags, action_flags,
+						   pattern, prefix_actions, suffix_actions,
+						   sample_actions, &mirror_conf, error);
+	} else {
+		flow = mlx5_nta_create_sample_flow(dev, type, attr, sample_conf->ratio,
+						   item_flags, action_flags, pattern,
+						   prefix_actions, suffix_actions,
+						   sample_actions, &mirror_conf, error);
+	}
+	return flow;
 }
diff --git a/drivers/net/mlx5/mlx5_nta_sample.h b/drivers/net/mlx5/mlx5_nta_sample.h
new file mode 100644
index 0000000000..129d534b33
--- /dev/null
+++ b/drivers/net/mlx5/mlx5_nta_sample.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2025 NVIDIA Corporation & Affiliates
+ */
+
+#ifndef MLX5_NTA_SAMPLE_H
+#define MLX5_NTA_SAMPLE_H
+
+#include <stdint.h>
+
+struct rte_flow_hw *
+mlx5_flow_nta_handle_sample(struct rte_eth_dev *dev,
+			    enum mlx5_flow_type type,
+			    const struct rte_flow_attr *attr,
+			    const struct rte_flow_item pattern[],
+			    const struct rte_flow_action actions[],
+			    uint64_t item_flags, uint64_t action_flags,
+			    struct rte_flow_error *error);
+
+void
+mlx5_nta_release_sample_group(struct rte_eth_dev *dev, uint32_t group);
+
+void
+mlx5_free_sample_context(struct rte_eth_dev *dev);
+
+#endif /* MLX5_NTA_SAMPLE_H */
-- 
2.48.1


      parent reply	other threads:[~2025-06-17 13:40 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-06-17 13:39 [PATCH 1/5] net/mlx5: fix the table flags of mirror action Gregory Etelson
2025-06-17 13:39 ` [PATCH 2/5] net/mlx5: add mlx5_hw_create_mirror function Gregory Etelson
2025-06-17 13:39 ` [PATCH 3/5] net/mlx5: create utility functions for non-template sample action Gregory Etelson
2025-06-17 13:39 ` [PATCH 4/5] net/mlx5: add MLX5 mirror flow action Gregory Etelson
2025-06-17 13:39 ` Gregory Etelson [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250617133933.313443-5-getelson@nvidia.com \
    --to=getelson@nvidia.com \
    --cc=bingz@nvidia.com \
    --cc=dev@dpdk.org \
    --cc=dsosnowski@nvidia.com \
    --cc=matan@nvidia.com \
    --cc=mkashani@nvidia.com \
    --cc=orika@nvidia.com \
    --cc=rasland@nvidia.com \
    --cc=suanmingm@nvidia.com \
    --cc=viacheslavo@nvidia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).