[v8,06/13] net/mlx5: update translate function for sample action
diff mbox series

Message ID 1601187539-112694-7-git-send-email-jiaweiw@nvidia.com
State Superseded
Delegated to: Raslan Darawsheh
Headers show
Series
  • support the flow-based traffic sampling
Related show

Checks

Context Check Description
ci/checkpatch warning coding style issues

Commit Message

Jiawei Wang Sept. 27, 2020, 6:18 a.m. UTC
Translate the attribute of sample action that include sample ratio
and sub actions list, then create the sample DR action.

The metadata register value will be lost in the default path after
Sampler in FDB due to CX5 HW limitation.

Since source vport also be shared with metadata register c0, MLX5
PMD would set the source vport to rdma-core and rdma-core will
restore the regc0 value after sampler.

Signed-off-by: Jiawei Wang <jiaweiw@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>
---
 drivers/net/mlx5/mlx5_flow.c    |  16 +-
 drivers/net/mlx5/mlx5_flow_dv.c | 508 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 509 insertions(+), 15 deletions(-)

Patch
diff mbox series

diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 3b18d71..8fd5d23 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -4682,10 +4682,14 @@  struct mlx5_flow_tunnel_info {
 	int hairpin_flow;
 	uint32_t hairpin_id = 0;
 	struct rte_flow_attr attr_tx = { .priority = 0 };
+	struct rte_flow_attr attr_factor = {0};
 	int ret;
 
-	hairpin_flow = flow_check_hairpin_split(dev, attr, actions);
-	ret = flow_drv_validate(dev, attr, items, p_actions_rx,
+	memcpy((void *)&attr_factor, (const void *)attr, sizeof(*attr));
+	if (external)
+		attr_factor.group *= MLX5_FLOW_TABLE_FACTOR;
+	hairpin_flow = flow_check_hairpin_split(dev, &attr_factor, actions);
+	ret = flow_drv_validate(dev, &attr_factor, items, p_actions_rx,
 				external, hairpin_flow, error);
 	if (ret < 0)
 		return 0;
@@ -4704,7 +4708,7 @@  struct mlx5_flow_tunnel_info {
 		rte_errno = ENOMEM;
 		goto error_before_flow;
 	}
-	flow->drv_type = flow_get_drv_type(dev, attr);
+	flow->drv_type = flow_get_drv_type(dev, &attr_factor);
 	if (hairpin_id != 0)
 		flow->hairpin_flow_id = hairpin_id;
 	MLX5_ASSERT(flow->drv_type > MLX5_FLOW_TYPE_MIN &&
@@ -4750,7 +4754,7 @@  struct mlx5_flow_tunnel_info {
 		 * depending on configuration. In the simplest
 		 * case it just creates unmodified original flow.
 		 */
-		ret = flow_create_split_outer(dev, flow, attr,
+		ret = flow_create_split_outer(dev, flow, &attr_factor,
 					      buf->entry[i].pattern,
 					      p_actions_rx, external, idx,
 					      error);
@@ -4787,8 +4791,8 @@  struct mlx5_flow_tunnel_info {
 	 * the egress Flows belong to the different device and
 	 * copy table should be updated in peer NIC Rx domain.
 	 */
-	if (attr->ingress &&
-	    (external || attr->group != MLX5_FLOW_MREG_CP_TABLE_GROUP)) {
+	if (attr_factor.ingress &&
+	    (external || attr_factor.group != MLX5_FLOW_MREG_CP_TABLE_GROUP)) {
 		ret = flow_mreg_update_copy_table(dev, flow, actions, error);
 		if (ret)
 			goto error;
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index 7809db1..a9a57f0 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -76,6 +76,10 @@ 
 static int
 flow_dv_default_miss_resource_release(struct rte_eth_dev *dev);
 
+static int
+flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev,
+				      uint32_t encap_decap_idx);
+
 /**
  * Initialize flow attributes structure according to flow items' types.
  *
@@ -8287,6 +8291,387 @@  struct field_modify_info modify_tcp[] = {
 }
 
 /**
+ * Create an Rx Hash queue.
+ *
+ * @param dev
+ *   Pointer to Ethernet device.
+ * @param[in] dev_flow
+ *   Pointer to the mlx5_flow.
+ * @param[in] rss_desc
+ *   Pointer to the mlx5_flow_rss_desc.
+ * @param[out] hrxq_idx
+ *   Hash Rx queue index.
+ *
+ * @return
+ *   The Verbs/DevX object initialised, NULL otherwise and rte_errno is set.
+ */
+static struct mlx5_hrxq *
+flow_dv_handle_rx_queue(struct rte_eth_dev *dev,
+			  struct mlx5_flow *dev_flow,
+			  struct mlx5_flow_rss_desc *rss_desc,
+			  uint32_t *hrxq_idx)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_handle *dh = dev_flow->handle;
+	struct mlx5_hrxq *hrxq;
+
+	MLX5_ASSERT(rss_desc->queue_num);
+	*hrxq_idx = mlx5_hrxq_get(dev, rss_desc->key,
+				 MLX5_RSS_HASH_KEY_LEN,
+				 dev_flow->hash_fields,
+				 rss_desc->queue,
+				 rss_desc->queue_num);
+	if (!*hrxq_idx) {
+		*hrxq_idx = mlx5_hrxq_new
+				(dev, rss_desc->key,
+				MLX5_RSS_HASH_KEY_LEN,
+				dev_flow->hash_fields,
+				rss_desc->queue,
+				rss_desc->queue_num,
+				!!(dh->layers &
+				MLX5_FLOW_LAYER_TUNNEL));
+		if (!*hrxq_idx)
+			return NULL;
+	}
+	hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],
+			      *hrxq_idx);
+	return hrxq;
+}
+
+/**
+ * Find existing sample resource or create and register a new one.
+ *
+ * @param[in, out] dev
+ *   Pointer to rte_eth_dev structure.
+ * @param[in] attr
+ *   Attributes of flow that includes this item.
+ * @param[in] resource
+ *   Pointer to sample resource.
+ * @parm[in, out] dev_flow
+ *   Pointer to the dev_flow.
+ * @param[in, out] sample_dv_actions
+ *   Pointer to sample actions list.
+ * @param[out] error
+ *   pointer to error structure.
+ *
+ * @return
+ *   0 on success otherwise -errno and errno is set.
+ */
+static int
+flow_dv_sample_resource_register(struct rte_eth_dev *dev,
+			 const struct rte_flow_attr *attr,
+			 struct mlx5_flow_dv_sample_resource *resource,
+			 struct mlx5_flow *dev_flow,
+			 void **sample_dv_actions,
+			 struct rte_flow_error *error)
+{
+	struct mlx5_flow_dv_sample_resource *cache_resource;
+	struct mlx5dv_dr_flow_sampler_attr sampler_attr;
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_dev_ctx_shared *sh = priv->sh;
+	struct mlx5_flow_tbl_resource *tbl;
+	uint32_t idx = 0;
+	const uint32_t next_ft_step = 1;
+	uint32_t next_ft_id = resource->ft_id +	next_ft_step;
+
+	/* Lookup a matching resource from cache. */
+	ILIST_FOREACH(sh->ipool[MLX5_IPOOL_SAMPLE], sh->sample_action_list,
+		      idx, cache_resource, next) {
+		if (resource->ratio == cache_resource->ratio &&
+		    resource->ft_type == cache_resource->ft_type &&
+		    resource->ft_id == cache_resource->ft_id &&
+		    resource->set_action == cache_resource->set_action &&
+		    !memcmp((void *)&resource->sample_act,
+			    (void *)&cache_resource->sample_act,
+			    sizeof(struct mlx5_flow_sub_actions_list))) {
+			DRV_LOG(DEBUG, "sample resource %p: refcnt %d++",
+				(void *)cache_resource,
+				rte_atomic32_read(&cache_resource->refcnt));
+			rte_atomic32_inc(&cache_resource->refcnt);
+			dev_flow->handle->dvh.rix_sample = idx;
+			dev_flow->dv.sample_res = cache_resource;
+			return 0;
+		}
+	}
+	/* Register new sample resource. */
+	cache_resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_SAMPLE],
+				       &dev_flow->handle->dvh.rix_sample);
+	if (!cache_resource)
+		return rte_flow_error_set(error, ENOMEM,
+					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+					  NULL,
+					  "cannot allocate resource memory");
+	*cache_resource = *resource;
+	/* Create normal path table level */
+	tbl = flow_dv_tbl_resource_get(dev, next_ft_id,
+					attr->egress, attr->transfer, error);
+	if (!tbl) {
+		rte_flow_error_set(error, ENOMEM,
+					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+					  NULL,
+					  "fail to create normal path table "
+					  "for sample");
+		goto error;
+	}
+	cache_resource->normal_path_tbl = tbl;
+	if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) {
+		cache_resource->default_miss =
+				mlx5_glue->dr_create_flow_action_default_miss();
+		if (!cache_resource->default_miss) {
+			rte_flow_error_set(error, ENOMEM,
+						RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						NULL,
+						"cannot create default miss "
+						"action");
+			goto error;
+		}
+		sample_dv_actions[resource->sample_act.actions_num++] =
+						cache_resource->default_miss;
+	}
+	/* Create a DR sample action */
+	sampler_attr.sample_ratio = cache_resource->ratio;
+	sampler_attr.default_next_table = tbl->obj;
+	sampler_attr.num_sample_actions = resource->sample_act.actions_num;
+	sampler_attr.sample_actions = (struct mlx5dv_dr_action **)
+							&sample_dv_actions[0];
+	sampler_attr.action = cache_resource->set_action;
+	cache_resource->verbs_action =
+		mlx5_glue->dr_create_flow_action_sampler(&sampler_attr);
+	if (!cache_resource->verbs_action) {
+		rte_flow_error_set(error, ENOMEM,
+					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+					NULL, "cannot create sample action");
+		goto error;
+	}
+	rte_atomic32_init(&cache_resource->refcnt);
+	rte_atomic32_inc(&cache_resource->refcnt);
+	ILIST_INSERT(sh->ipool[MLX5_IPOOL_SAMPLE], &sh->sample_action_list,
+		     dev_flow->handle->dvh.rix_sample, cache_resource,
+		     next);
+	dev_flow->dv.sample_res = cache_resource;
+	DRV_LOG(DEBUG, "new sample resource %p: refcnt %d++",
+		(void *)cache_resource,
+		rte_atomic32_read(&cache_resource->refcnt));
+	return 0;
+error:
+	if (cache_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) {
+		if (cache_resource->default_miss)
+			claim_zero(mlx5_glue->destroy_flow_action
+				(cache_resource->default_miss));
+	} else {
+		if (cache_resource->sample_idx.rix_hrxq &&
+		    !mlx5_hrxq_release(dev,
+				cache_resource->sample_idx.rix_hrxq))
+			cache_resource->sample_idx.rix_hrxq = 0;
+		if (cache_resource->sample_idx.rix_tag &&
+		    !flow_dv_tag_release(dev,
+				cache_resource->sample_idx.rix_tag))
+			cache_resource->sample_idx.rix_tag = 0;
+		if (cache_resource->sample_idx.cnt) {
+			flow_dv_counter_release(dev,
+				cache_resource->sample_idx.cnt);
+			cache_resource->sample_idx.cnt = 0;
+		}
+	}
+	if (cache_resource->normal_path_tbl)
+		flow_dv_tbl_resource_release(dev,
+				cache_resource->normal_path_tbl);
+	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_SAMPLE],
+				dev_flow->handle->dvh.rix_sample);
+	dev_flow->handle->dvh.rix_sample = 0;
+	return -rte_errno;
+}
+
+/**
+ * Convert Sample action to DV specification.
+ *
+ * @param[in] dev
+ *   Pointer to rte_eth_dev structure.
+ * @param[in] action
+ *   Pointer to action structure.
+ * @param[in, out] dev_flow
+ *   Pointer to the mlx5_flow.
+ * @param[in] attr
+ *   Pointer to the flow attributes.
+ * @param[in, out] sample_actions
+ *   Pointer to sample actions list.
+ * @param[in, out] res
+ *   Pointer to sample resource.
+ * @param[out] error
+ *   Pointer to the error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+flow_dv_translate_action_sample(struct rte_eth_dev *dev,
+				const struct rte_flow_action *action,
+				struct mlx5_flow *dev_flow,
+				const struct rte_flow_attr *attr,
+				void **sample_actions,
+				struct mlx5_flow_dv_sample_resource *res,
+				struct rte_flow_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	const struct rte_flow_action_sample *sample_action;
+	const struct rte_flow_action *sub_actions;
+	const struct rte_flow_action_queue *queue;
+	struct mlx5_flow_sub_actions_list *sample_act;
+	struct mlx5_flow_sub_actions_idx *sample_idx;
+	struct mlx5_flow_rss_desc *rss_desc = &((struct mlx5_flow_rss_desc *)
+					      priv->rss_desc)
+					      [!!priv->flow_nested_idx];
+	uint64_t action_flags = 0;
+
+	sample_act = &res->sample_act;
+	sample_idx = &res->sample_idx;
+	sample_action = (const struct rte_flow_action_sample *)action->conf;
+	res->ratio = sample_action->ratio;
+	sub_actions = sample_action->actions;
+	for (; sub_actions->type != RTE_FLOW_ACTION_TYPE_END; sub_actions++) {
+		int type = sub_actions->type;
+		uint32_t pre_rix = 0;
+		void *pre_r;
+		switch (type) {
+		case RTE_FLOW_ACTION_TYPE_QUEUE:
+		{
+			struct mlx5_hrxq *hrxq;
+			uint32_t hrxq_idx;
+
+			queue = sub_actions->conf;
+			rss_desc->queue_num = 1;
+			rss_desc->queue[0] = queue->index;
+			hrxq = flow_dv_handle_rx_queue(dev, dev_flow,
+					rss_desc, &hrxq_idx);
+			if (!hrxq)
+				return rte_flow_error_set
+					(error, rte_errno,
+					 RTE_FLOW_ERROR_TYPE_ACTION,
+					 NULL,
+					 "cannot create fate queue");
+			sample_act->dr_queue_action = hrxq->action;
+			sample_idx->rix_hrxq = hrxq_idx;
+			sample_actions[sample_act->actions_num++] =
+						hrxq->action;
+			action_flags |= MLX5_FLOW_ACTION_QUEUE;
+			if (action_flags & MLX5_FLOW_ACTION_MARK)
+				dev_flow->handle->rix_hrxq = hrxq_idx;
+			dev_flow->handle->fate_action =
+					MLX5_FLOW_FATE_QUEUE;
+			break;
+		}
+		case RTE_FLOW_ACTION_TYPE_MARK:
+		{
+			uint32_t tag_be = mlx5_flow_mark_set
+				(((const struct rte_flow_action_mark *)
+				(sub_actions->conf))->id);
+			dev_flow->handle->mark = 1;
+			pre_rix = dev_flow->handle->dvh.rix_tag;
+			/* Save the mark resource before sample */
+			pre_r = dev_flow->dv.tag_resource;
+			if (flow_dv_tag_resource_register(dev, tag_be,
+						  dev_flow, error))
+				return -rte_errno;
+			MLX5_ASSERT(dev_flow->dv.tag_resource);
+			sample_act->dr_tag_action =
+				dev_flow->dv.tag_resource->action;
+			sample_idx->rix_tag =
+				dev_flow->handle->dvh.rix_tag;
+			sample_actions[sample_act->actions_num++] =
+						sample_act->dr_tag_action;
+			/* Recover the mark resource after sample */
+			dev_flow->dv.tag_resource = pre_r;
+			dev_flow->handle->dvh.rix_tag = pre_rix;
+			action_flags |= MLX5_FLOW_ACTION_MARK;
+			break;
+		}
+		case RTE_FLOW_ACTION_TYPE_COUNT:
+		{
+			uint32_t counter;
+
+			counter = flow_dv_translate_create_counter(dev,
+					dev_flow, sub_actions->conf, 0);
+			if (!counter)
+				return rte_flow_error_set
+						(error, rte_errno,
+						 RTE_FLOW_ERROR_TYPE_ACTION,
+						 NULL,
+						 "cannot create counter"
+						 " object.");
+			sample_idx->cnt = counter;
+			sample_act->dr_cnt_action =
+				  (flow_dv_counter_get_by_idx(dev,
+				  counter, NULL))->action;
+			sample_actions[sample_act->actions_num++] =
+						sample_act->dr_cnt_action;
+			action_flags |= MLX5_FLOW_ACTION_COUNT;
+			break;
+		}
+		default:
+			return rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+				NULL,
+				"Not support for sampler action");
+		}
+	}
+	sample_act->action_flags = action_flags;
+	res->ft_id = dev_flow->dv.group;
+	if (attr->transfer) {
+		union {
+			uint32_t action_in[MLX5_ST_SZ_DW(set_action_in)];
+			uint64_t set_action;
+		} action_ctx = { .set_action = 0 };
+
+		res->ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
+		MLX5_SET(set_action_in, action_ctx.action_in, action_type,
+			 MLX5_MODIFICATION_TYPE_SET);
+		MLX5_SET(set_action_in, action_ctx.action_in, field,
+			 MLX5_MODI_META_REG_C_0);
+		MLX5_SET(set_action_in, action_ctx.action_in, data,
+			 priv->vport_meta_tag);
+		res->set_action = action_ctx.set_action;
+	} else if (attr->ingress) {
+		res->ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
+	}
+	return 0;
+}
+
+/**
+ * Convert Sample action to DV specification.
+ *
+ * @param[in] dev
+ *   Pointer to rte_eth_dev structure.
+ * @param[in, out] dev_flow
+ *   Pointer to the mlx5_flow.
+ * @param[in] attr
+ *   Pointer to the flow attributes.
+ * @param[in, out] res
+ *   Pointer to sample resource.
+ * @param[in] sample_actions
+ *   Pointer to sample path actions list.
+ * @param[out] error
+ *   Pointer to the error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+flow_dv_create_action_sample(struct rte_eth_dev *dev,
+				struct mlx5_flow *dev_flow,
+				const struct rte_flow_attr *attr,
+				struct mlx5_flow_dv_sample_resource *res,
+				void **sample_actions,
+				struct rte_flow_error *error)
+{
+	if (flow_dv_sample_resource_register(dev, attr, res, dev_flow,
+						sample_actions, error))
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION,
+					  NULL, "can't create sample action");
+	return 0;
+}
+
+/**
  * Fill the flow with DV spec, lock free
  * (mutex should be acquired by caller).
  *
@@ -8350,9 +8735,13 @@  struct field_modify_info modify_tcp[] = {
 	void *match_value = dev_flow->dv.value.buf;
 	uint8_t next_protocol = 0xff;
 	struct rte_vlan_hdr vlan = { 0 };
+	struct mlx5_flow_dv_sample_resource sample_res;
+	void *sample_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0};
+	uint32_t sample_act_pos = UINT32_MAX;
 	uint32_t table;
 	int ret = 0;
 
+	memset(&sample_res, 0, sizeof(struct mlx5_flow_dv_sample_resource));
 	mhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
 					   MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
 	ret = mlx5_flow_group_to_table(attr, dev_flow->external, attr->group,
@@ -8371,7 +8760,6 @@  struct field_modify_info modify_tcp[] = {
 		const struct rte_flow_action_rss *rss;
 		const struct rte_flow_action *action = actions;
 		const uint8_t *rss_key;
-		const struct rte_flow_action_jump *jump_data;
 		const struct rte_flow_action_meter *mtr;
 		struct mlx5_flow_tbl_resource *tbl;
 		uint32_t port_id = 0;
@@ -8379,6 +8767,7 @@  struct field_modify_info modify_tcp[] = {
 		int action_type = actions->type;
 		const struct rte_flow_action *found_action = NULL;
 		struct mlx5_flow_meter *fm = NULL;
+		uint32_t jump_group = 0;
 
 		if (!mlx5_flow_os_action_supported(action_type))
 			return rte_flow_error_set(error, ENOTSUP,
@@ -8617,9 +9006,13 @@  struct field_modify_info modify_tcp[] = {
 			action_flags |= MLX5_FLOW_ACTION_DECAP;
 			break;
 		case RTE_FLOW_ACTION_TYPE_JUMP:
-			jump_data = action->conf;
+			jump_group = ((const struct rte_flow_action_jump *)
+							action->conf)->group;
+			if (dev_flow->external && jump_group <
+					MLX5_MAX_TABLES_EXTERNAL)
+				jump_group *= MLX5_FLOW_TABLE_FACTOR;
 			ret = mlx5_flow_group_to_table(attr, dev_flow->external,
-						       jump_data->group,
+						       jump_group,
 						       !!priv->fdb_def_rule,
 						       &table, error);
 			if (ret)
@@ -8785,6 +9178,19 @@  struct field_modify_info modify_tcp[] = {
 				return -rte_errno;
 			action_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP;
 			break;
+		case RTE_FLOW_ACTION_TYPE_SAMPLE:
+			sample_act_pos = actions_n;
+			ret = flow_dv_translate_action_sample(dev,
+							      actions,
+							      dev_flow, attr,
+							      sample_actions,
+							      &sample_res,
+							      error);
+			if (ret < 0)
+				return ret;
+			actions_n++;
+			action_flags |= MLX5_FLOW_ACTION_SAMPLE;
+			break;
 		case RTE_FLOW_ACTION_TYPE_END:
 			actions_end = true;
 			if (mhdr_res->actions_num) {
@@ -8811,6 +9217,21 @@  struct field_modify_info modify_tcp[] = {
 					  (flow_dv_counter_get_by_idx(dev,
 					  flow->counter, NULL))->action;
 			}
+			if (action_flags & MLX5_FLOW_ACTION_SAMPLE) {
+				ret = flow_dv_create_action_sample(dev,
+							  dev_flow, attr,
+							  &sample_res,
+							  sample_actions,
+							  error);
+				if (ret < 0)
+					return rte_flow_error_set
+						(error, rte_errno,
+						RTE_FLOW_ERROR_TYPE_ACTION,
+						NULL,
+						"cannot create sample action");
+				dev_flow->dv.actions[sample_act_pos] =
+					dev_flow->dv.sample_res->verbs_action;
+			}
 			break;
 		default:
 			break;
@@ -9122,7 +9543,8 @@  struct field_modify_info modify_tcp[] = {
 				dh->rix_hrxq = UINT32_MAX;
 				dv->actions[n++] = drop_hrxq->action;
 			}
-		} else if (dh->fate_action == MLX5_FLOW_FATE_QUEUE) {
+		} else if (dh->fate_action == MLX5_FLOW_FATE_QUEUE &&
+			   !dv_h->rix_sample) {
 			struct mlx5_hrxq *hrxq;
 			uint32_t hrxq_idx;
 			struct mlx5_flow_rss_desc *rss_desc =
@@ -9254,18 +9676,18 @@  struct field_modify_info modify_tcp[] = {
  *
  * @param dev
  *   Pointer to Ethernet device.
- * @param handle
- *   Pointer to mlx5_flow_handle.
+ * @param encap_decap_idx
+ *   Index of encap decap resource.
  *
  * @return
  *   1 while a reference on it exists, 0 when freed.
  */
 static int
 flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev,
-				     struct mlx5_flow_handle *handle)
+				     uint32_t encap_decap_idx)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	uint32_t idx = handle->dvh.rix_encap_decap;
+	uint32_t idx = encap_decap_idx;
 	struct mlx5_flow_dv_encap_decap_resource *cache_resource;
 
 	cache_resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DECAP_ENCAP],
@@ -9515,6 +9937,71 @@  struct field_modify_info modify_tcp[] = {
 }
 
 /**
+ * Release an sample resource.
+ *
+ * @param dev
+ *   Pointer to Ethernet device.
+ * @param handle
+ *   Pointer to mlx5_flow_handle.
+ *
+ * @return
+ *   1 while a reference on it exists, 0 when freed.
+ */
+static int
+flow_dv_sample_resource_release(struct rte_eth_dev *dev,
+				     struct mlx5_flow_handle *handle)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	uint32_t idx = handle->dvh.rix_sample;
+	struct mlx5_flow_dv_sample_resource *cache_resource;
+
+	cache_resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_SAMPLE],
+			 idx);
+	if (!cache_resource)
+		return 0;
+	MLX5_ASSERT(cache_resource->verbs_action);
+	DRV_LOG(DEBUG, "sample resource %p: refcnt %d--",
+		(void *)cache_resource,
+		rte_atomic32_read(&cache_resource->refcnt));
+	if (rte_atomic32_dec_and_test(&cache_resource->refcnt)) {
+		if (cache_resource->verbs_action)
+			claim_zero(mlx5_glue->destroy_flow_action
+					(cache_resource->verbs_action));
+		if (cache_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) {
+			if (cache_resource->default_miss)
+				claim_zero(mlx5_glue->destroy_flow_action
+				  (cache_resource->default_miss));
+		}
+		if (cache_resource->normal_path_tbl)
+			flow_dv_tbl_resource_release(dev,
+				cache_resource->normal_path_tbl);
+	}
+	if (cache_resource->sample_idx.rix_hrxq &&
+		!mlx5_hrxq_release(dev,
+			cache_resource->sample_idx.rix_hrxq))
+		cache_resource->sample_idx.rix_hrxq = 0;
+	if (cache_resource->sample_idx.rix_tag &&
+		!flow_dv_tag_release(dev,
+			cache_resource->sample_idx.rix_tag))
+		cache_resource->sample_idx.rix_tag = 0;
+	if (cache_resource->sample_idx.cnt) {
+		flow_dv_counter_release(dev,
+			cache_resource->sample_idx.cnt);
+		cache_resource->sample_idx.cnt = 0;
+	}
+	if (!rte_atomic32_read(&cache_resource->refcnt)) {
+		ILIST_REMOVE(priv->sh->ipool[MLX5_IPOOL_SAMPLE],
+			     &priv->sh->sample_action_list, idx,
+			     cache_resource, next);
+		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_SAMPLE], idx);
+		DRV_LOG(DEBUG, "sample resource %p: removed",
+			(void *)cache_resource);
+		return 0;
+	}
+	return 1;
+}
+
+/**
  * Remove the flow from the NIC but keeps it in memory.
  * Lock free, (mutex should be acquired by caller).
  *
@@ -9593,8 +10080,11 @@  struct field_modify_info modify_tcp[] = {
 		flow->dev_handles = dev_handle->next.next;
 		if (dev_handle->dvh.matcher)
 			flow_dv_matcher_release(dev, dev_handle);
+		if (dev_handle->dvh.rix_sample)
+			flow_dv_sample_resource_release(dev, dev_handle);
 		if (dev_handle->dvh.rix_encap_decap)
-			flow_dv_encap_decap_resource_release(dev, dev_handle);
+			flow_dv_encap_decap_resource_release(dev,
+				dev_handle->dvh.rix_encap_decap);
 		if (dev_handle->dvh.modify_hdr)
 			flow_dv_modify_hdr_resource_release(dev, dev_handle);
 		if (dev_handle->dvh.rix_push_vlan)