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
next prev parent reply other threads:[~2025-06-17 13:40 UTC|newest]
Thread overview: 11+ 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]
2025-06-26 7:59 ` [PATCH v2 0/4] net/mlx5: support non template SAMPLE " Gregory Etelson
2025-06-26 7:59 ` [PATCH v2 1/4] net/mlx5: fix the table flags of mirror action Gregory Etelson
2025-06-26 7:59 ` [PATCH v2 2/4] net/mlx5: add a stand alone function for mirror creation Gregory Etelson
2025-06-26 7:59 ` [PATCH v2 3/4] net/mlx5: add functions for non template sample action Gregory Etelson
2025-06-26 7:59 ` [PATCH v2 4/4] net/mlx5: support non-template SAMPLE flow action Gregory Etelson
2025-06-26 15:28 ` [PATCH v2 0/4] net/mlx5: support non template " Thomas Monjalon
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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.