ethdev: add device flag to bypass auto-filled queue xstats
[dpdk.git] / drivers / net / mlx5 / mlx5_flow_dv.c
index 98f73cd..361c32d 100644 (file)
@@ -76,6 +76,14 @@ flow_dv_tbl_resource_release(struct rte_eth_dev *dev,
 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);
+
+static int
+flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev,
+                                       uint32_t port_id);
+
 /**
  * Initialize flow attributes structure according to flow items' types.
  *
@@ -3370,6 +3378,8 @@ flow_dv_create_action_push_vlan(struct rte_eth_dev *dev,
                                            (dev, &res, dev_flow, error);
 }
 
+static int fdb_mirror;
+
 /**
  * Validate the modify-header actions.
  *
@@ -3397,6 +3407,12 @@ flow_dv_validate_action_modify_hdr(const uint64_t action_flags,
                                          RTE_FLOW_ERROR_TYPE_ACTION, NULL,
                                          "can't have encap action before"
                                          " modify action");
+       if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) && fdb_mirror)
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+                                         "can't support sample action before"
+                                         " modify action for E-Switch"
+                                         " mirroring");
        return 0;
 }
 
@@ -3720,6 +3736,12 @@ flow_dv_validate_action_jump(const struct rte_flow_action *action,
                return rte_flow_error_set(error, ENOTSUP,
                                          RTE_FLOW_ERROR_TYPE_ACTION, NULL,
                                          "jump with meter not support");
+       if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) && fdb_mirror)
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+                                         "E-Switch mirroring can't support"
+                                         " Sample action and jump action in"
+                                         " same flow now");
        if (!action->conf)
                return rte_flow_error_set(error, EINVAL,
                                          RTE_FLOW_ERROR_TYPE_ACTION_CONF,
@@ -4070,8 +4092,10 @@ flow_dv_validate_action_sample(uint64_t action_flags,
        const struct rte_flow_action_sample *sample = action->conf;
        const struct rte_flow_action *act;
        uint64_t sub_action_flags = 0;
+       uint16_t queue_index = 0xFFFF;
        int actions_n = 0;
        int ret;
+       fdb_mirror = 0;
 
        if (!sample)
                return rte_flow_error_set(error, EINVAL,
@@ -4115,6 +4139,8 @@ flow_dv_validate_action_sample(uint64_t action_flags,
                                                              attr, error);
                        if (ret < 0)
                                return ret;
+                       queue_index = ((const struct rte_flow_action_queue *)
+                                                       (act->conf))->index;
                        sub_action_flags |= MLX5_FLOW_ACTION_QUEUE;
                        ++actions_n;
                        break;
@@ -4138,6 +4164,25 @@ flow_dv_validate_action_sample(uint64_t action_flags,
                        sub_action_flags |= MLX5_FLOW_ACTION_COUNT;
                        ++actions_n;
                        break;
+               case RTE_FLOW_ACTION_TYPE_PORT_ID:
+                       ret = flow_dv_validate_action_port_id(dev,
+                                                             sub_action_flags,
+                                                             act,
+                                                             attr,
+                                                             error);
+                       if (ret)
+                               return ret;
+                       sub_action_flags |= MLX5_FLOW_ACTION_PORT_ID;
+                       ++actions_n;
+                       break;
+               case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
+                       ret = flow_dv_validate_action_raw_encap_decap
+                               (dev, NULL, act->conf, attr, &sub_action_flags,
+                                &actions_n, error);
+                       if (ret < 0)
+                               return ret;
+                       ++actions_n;
+                       break;
                default:
                        return rte_flow_error_set(error, ENOTSUP,
                                                  RTE_FLOW_ERROR_TYPE_ACTION,
@@ -4161,10 +4206,43 @@ flow_dv_validate_action_sample(uint64_t action_flags,
                                          "or E-Switch");
        } else if (sample->actions->type != RTE_FLOW_ACTION_TYPE_END) {
                MLX5_ASSERT(attr->transfer);
-               return rte_flow_error_set(error, ENOTSUP,
-                                         RTE_FLOW_ERROR_TYPE_ACTION, NULL,
-                                         "E-Switch doesn't support any "
-                                         "optional action for sampling");
+               if (sample->ratio > 1)
+                       return rte_flow_error_set(error, ENOTSUP,
+                                                 RTE_FLOW_ERROR_TYPE_ACTION,
+                                                 NULL,
+                                                 "E-Switch doesn't support "
+                                                 "any optional action "
+                                                 "for sampling");
+               fdb_mirror = 1;
+               if (sub_action_flags & MLX5_FLOW_ACTION_QUEUE)
+                       return rte_flow_error_set(error, ENOTSUP,
+                                                 RTE_FLOW_ERROR_TYPE_ACTION,
+                                                 NULL,
+                                                 "unsupported action QUEUE");
+               if (!(sub_action_flags & MLX5_FLOW_ACTION_PORT_ID))
+                       return rte_flow_error_set(error, EINVAL,
+                                                 RTE_FLOW_ERROR_TYPE_ACTION,
+                                                 NULL,
+                                                 "E-Switch must has a dest "
+                                                 "port for mirroring");
+       }
+       /* Continue validation for Xcap actions.*/
+       if ((sub_action_flags & MLX5_FLOW_XCAP_ACTIONS) &&
+           (queue_index == 0xFFFF ||
+            mlx5_rxq_get_type(dev, queue_index) != MLX5_RXQ_TYPE_HAIRPIN)) {
+               if ((sub_action_flags & MLX5_FLOW_XCAP_ACTIONS) ==
+                    MLX5_FLOW_XCAP_ACTIONS)
+                       return rte_flow_error_set(error, ENOTSUP,
+                                                 RTE_FLOW_ERROR_TYPE_ACTION,
+                                                 NULL, "encap and decap "
+                                                 "combination aren't "
+                                                 "supported");
+               if (!attr->transfer && attr->ingress && (sub_action_flags &
+                                                       MLX5_FLOW_ACTION_ENCAP))
+                       return rte_flow_error_set(error, ENOTSUP,
+                                                 RTE_FLOW_ERROR_TYPE_ACTION,
+                                                 NULL, "encap is not supported"
+                                                 " for ingress traffic");
        }
        return 0;
 }
@@ -8299,6 +8377,661 @@ flow_dv_hashfields_set(struct mlx5_flow *dev_flow,
        }
 }
 
+/**
+ * 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,
+                               __atomic_load_n(&cache_resource->refcnt,
+                                               __ATOMIC_RELAXED));
+                       __atomic_fetch_add(&cache_resource->refcnt, 1,
+                                          __ATOMIC_RELAXED);
+                       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;
+       }
+       __atomic_store_n(&cache_resource->refcnt, 1, __ATOMIC_RELAXED);
+       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,
+               __atomic_load_n(&cache_resource->refcnt, __ATOMIC_RELAXED));
+       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;
+}
+
+/**
+ * Find existing destination array 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 destination array resource.
+ * @parm[in, out] dev_flow
+ *   Pointer to the dev_flow.
+ * @param[out] error
+ *   pointer to error structure.
+ *
+ * @return
+ *   0 on success otherwise -errno and errno is set.
+ */
+static int
+flow_dv_dest_array_resource_register(struct rte_eth_dev *dev,
+                        const struct rte_flow_attr *attr,
+                        struct mlx5_flow_dv_dest_array_resource *resource,
+                        struct mlx5_flow *dev_flow,
+                        struct rte_flow_error *error)
+{
+       struct mlx5_flow_dv_dest_array_resource *cache_resource;
+       struct mlx5dv_dr_action_dest_attr *dest_attr[MLX5_MAX_DEST_NUM] = { 0 };
+       struct mlx5dv_dr_action_dest_reformat dest_reformat[MLX5_MAX_DEST_NUM];
+       struct mlx5_priv *priv = dev->data->dev_private;
+       struct mlx5_dev_ctx_shared *sh = priv->sh;
+       struct mlx5_flow_sub_actions_list *sample_act;
+       struct mlx5dv_dr_domain *domain;
+       uint32_t idx = 0;
+
+       /* Lookup a matching resource from cache. */
+       ILIST_FOREACH(sh->ipool[MLX5_IPOOL_DEST_ARRAY],
+                     sh->dest_array_list,
+                     idx, cache_resource, next) {
+               if (resource->num_of_dest == cache_resource->num_of_dest &&
+                   resource->ft_type == cache_resource->ft_type &&
+                   !memcmp((void *)cache_resource->sample_act,
+                           (void *)resource->sample_act,
+                          (resource->num_of_dest *
+                          sizeof(struct mlx5_flow_sub_actions_list)))) {
+                       DRV_LOG(DEBUG, "dest array resource %p: refcnt %d++",
+                               (void *)cache_resource,
+                               __atomic_load_n(&cache_resource->refcnt,
+                                               __ATOMIC_RELAXED));
+                       __atomic_fetch_add(&cache_resource->refcnt, 1,
+                                          __ATOMIC_RELAXED);
+                       dev_flow->handle->dvh.rix_dest_array = idx;
+                       dev_flow->dv.dest_array_res = cache_resource;
+                       return 0;
+               }
+       }
+       /* Register new destination array resource. */
+       cache_resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DEST_ARRAY],
+                                      &dev_flow->handle->dvh.rix_dest_array);
+       if (!cache_resource)
+               return rte_flow_error_set(error, ENOMEM,
+                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                         NULL,
+                                         "cannot allocate resource memory");
+       *cache_resource = *resource;
+       if (attr->transfer)
+               domain = sh->fdb_domain;
+       else if (attr->ingress)
+               domain = sh->rx_domain;
+       else
+               domain = sh->tx_domain;
+       for (idx = 0; idx < resource->num_of_dest; idx++) {
+               dest_attr[idx] = (struct mlx5dv_dr_action_dest_attr *)
+                                mlx5_malloc(MLX5_MEM_ZERO,
+                                sizeof(struct mlx5dv_dr_action_dest_attr),
+                                0, SOCKET_ID_ANY);
+               if (!dest_attr[idx]) {
+                       rte_flow_error_set(error, ENOMEM,
+                                          RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                          NULL,
+                                          "cannot allocate resource memory");
+                       goto error;
+               }
+               dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST;
+               sample_act = &resource->sample_act[idx];
+               if (sample_act->action_flags == MLX5_FLOW_ACTION_QUEUE) {
+                       dest_attr[idx]->dest = sample_act->dr_queue_action;
+               } else if (sample_act->action_flags ==
+                         (MLX5_FLOW_ACTION_PORT_ID | MLX5_FLOW_ACTION_ENCAP)) {
+                       dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST_REFORMAT;
+                       dest_attr[idx]->dest_reformat = &dest_reformat[idx];
+                       dest_attr[idx]->dest_reformat->reformat =
+                                       sample_act->dr_encap_action;
+                       dest_attr[idx]->dest_reformat->dest =
+                                       sample_act->dr_port_id_action;
+               } else if (sample_act->action_flags ==
+                          MLX5_FLOW_ACTION_PORT_ID) {
+                       dest_attr[idx]->dest = sample_act->dr_port_id_action;
+               }
+       }
+       /* create a dest array actioin */
+       cache_resource->action = mlx5_glue->dr_create_flow_action_dest_array
+                                               (domain,
+                                                cache_resource->num_of_dest,
+                                                dest_attr);
+       if (!cache_resource->action) {
+               rte_flow_error_set(error, ENOMEM,
+                                  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                  NULL,
+                                  "cannot create destination array action");
+               goto error;
+       }
+       __atomic_store_n(&cache_resource->refcnt, 1, __ATOMIC_RELAXED);
+       ILIST_INSERT(sh->ipool[MLX5_IPOOL_DEST_ARRAY],
+                    &sh->dest_array_list,
+                    dev_flow->handle->dvh.rix_dest_array, cache_resource,
+                    next);
+       dev_flow->dv.dest_array_res = cache_resource;
+       DRV_LOG(DEBUG, "new destination array resource %p: refcnt %d++",
+               (void *)cache_resource,
+               __atomic_load_n(&cache_resource->refcnt, __ATOMIC_RELAXED));
+       for (idx = 0; idx < resource->num_of_dest; idx++)
+               mlx5_free(dest_attr[idx]);
+       return 0;
+error:
+       for (idx = 0; idx < resource->num_of_dest; idx++) {
+               struct mlx5_flow_sub_actions_idx *act_res =
+                                       &cache_resource->sample_idx[idx];
+               if (act_res->rix_hrxq &&
+                   !mlx5_hrxq_release(dev,
+                               act_res->rix_hrxq))
+                       act_res->rix_hrxq = 0;
+               if (act_res->rix_encap_decap &&
+                       !flow_dv_encap_decap_resource_release(dev,
+                               act_res->rix_encap_decap))
+                       act_res->rix_encap_decap = 0;
+               if (act_res->rix_port_id_action &&
+                       !flow_dv_port_id_action_resource_release(dev,
+                               act_res->rix_port_id_action))
+                       act_res->rix_port_id_action = 0;
+               if (dest_attr[idx])
+                       mlx5_free(dest_attr[idx]);
+       }
+
+       mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DEST_ARRAY],
+                               dev_flow->handle->dvh.rix_dest_array);
+       dev_flow->handle->dvh.rix_dest_array = 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] num_of_dest
+ *   Pointer to the num of destination.
+ * @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,
+                               uint32_t *num_of_dest,
+                               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;
+                       (*num_of_dest)++;
+                       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;
+               }
+               case RTE_FLOW_ACTION_TYPE_PORT_ID:
+               {
+                       struct mlx5_flow_dv_port_id_action_resource
+                                       port_id_resource;
+                       uint32_t port_id = 0;
+
+                       memset(&port_id_resource, 0, sizeof(port_id_resource));
+                       /* Save the port id resource before sample */
+                       pre_rix = dev_flow->handle->rix_port_id_action;
+                       pre_r = dev_flow->dv.port_id_action;
+                       if (flow_dv_translate_action_port_id(dev, sub_actions,
+                                                            &port_id, error))
+                               return -rte_errno;
+                       port_id_resource.port_id = port_id;
+                       if (flow_dv_port_id_action_resource_register
+                           (dev, &port_id_resource, dev_flow, error))
+                               return -rte_errno;
+                       sample_act->dr_port_id_action =
+                               dev_flow->dv.port_id_action->action;
+                       sample_idx->rix_port_id_action =
+                               dev_flow->handle->rix_port_id_action;
+                       sample_actions[sample_act->actions_num++] =
+                                               sample_act->dr_port_id_action;
+                       /* Recover the port id resource after sample */
+                       dev_flow->dv.port_id_action = pre_r;
+                       dev_flow->handle->rix_port_id_action = pre_rix;
+                       (*num_of_dest)++;
+                       action_flags |= MLX5_FLOW_ACTION_PORT_ID;
+                       break;
+               }
+               case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
+                       /* Save the encap resource before sample */
+                       pre_rix = dev_flow->handle->dvh.rix_encap_decap;
+                       pre_r = dev_flow->dv.encap_decap;
+                       if (flow_dv_create_action_l2_encap(dev, sub_actions,
+                                                          dev_flow,
+                                                          attr->transfer,
+                                                          error))
+                               return -rte_errno;
+                       sample_act->dr_encap_action =
+                               dev_flow->dv.encap_decap->action;
+                       sample_idx->rix_encap_decap =
+                               dev_flow->handle->dvh.rix_encap_decap;
+                       sample_actions[sample_act->actions_num++] =
+                                               sample_act->dr_encap_action;
+                       /* Recover the encap resource after sample */
+                       dev_flow->dv.encap_decap = pre_r;
+                       dev_flow->handle->dvh.rix_encap_decap = pre_rix;
+                       action_flags |= MLX5_FLOW_ACTION_ENCAP;
+                       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] num_of_dest
+ *   The num of destination.
+ * @param[in, out] res
+ *   Pointer to sample resource.
+ * @param[in, out] mdest_res
+ *   Pointer to destination array resource.
+ * @param[in] sample_actions
+ *   Pointer to sample path actions list.
+ * @param[in] action_flags
+ *   Holds the actions detected until now.
+ * @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,
+                            uint32_t num_of_dest,
+                            struct mlx5_flow_dv_sample_resource *res,
+                            struct mlx5_flow_dv_dest_array_resource *mdest_res,
+                            void **sample_actions,
+                            uint64_t action_flags,
+                            struct rte_flow_error *error)
+{
+       struct mlx5_priv *priv = dev->data->dev_private;
+       /* update normal path action resource into last index of array */
+       uint32_t dest_index = MLX5_MAX_DEST_NUM - 1;
+       struct mlx5_flow_sub_actions_list *sample_act =
+                                       &mdest_res->sample_act[dest_index];
+       struct mlx5_flow_rss_desc *rss_desc = &((struct mlx5_flow_rss_desc *)
+                                             priv->rss_desc)
+                                             [!!priv->flow_nested_idx];
+       uint32_t normal_idx = 0;
+       struct mlx5_hrxq *hrxq;
+       uint32_t hrxq_idx;
+
+       if (num_of_dest > 1) {
+               if (sample_act->action_flags & MLX5_FLOW_ACTION_QUEUE) {
+                       /* Handle QP action for mirroring */
+                       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 rx queue");
+                       normal_idx++;
+                       mdest_res->sample_idx[dest_index].rix_hrxq = hrxq_idx;
+                       sample_act->dr_queue_action = hrxq->action;
+                       if (action_flags & MLX5_FLOW_ACTION_MARK)
+                               dev_flow->handle->rix_hrxq = hrxq_idx;
+                       dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;
+               }
+               if (sample_act->action_flags & MLX5_FLOW_ACTION_ENCAP) {
+                       normal_idx++;
+                       mdest_res->sample_idx[dest_index].rix_encap_decap =
+                               dev_flow->handle->dvh.rix_encap_decap;
+                       sample_act->dr_encap_action =
+                               dev_flow->dv.encap_decap->action;
+               }
+               if (sample_act->action_flags & MLX5_FLOW_ACTION_PORT_ID) {
+                       normal_idx++;
+                       mdest_res->sample_idx[dest_index].rix_port_id_action =
+                               dev_flow->handle->rix_port_id_action;
+                       sample_act->dr_port_id_action =
+                               dev_flow->dv.port_id_action->action;
+               }
+               sample_act->actions_num = normal_idx;
+               /* update sample action resource into first index of array */
+               mdest_res->ft_type = res->ft_type;
+               memcpy(&mdest_res->sample_idx[0], &res->sample_idx,
+                               sizeof(struct mlx5_flow_sub_actions_idx));
+               memcpy(&mdest_res->sample_act[0], &res->sample_act,
+                               sizeof(struct mlx5_flow_sub_actions_list));
+               mdest_res->num_of_dest = num_of_dest;
+               if (flow_dv_dest_array_resource_register(dev, attr, mdest_res,
+                                                        dev_flow, error))
+                       return rte_flow_error_set(error, EINVAL,
+                                                 RTE_FLOW_ERROR_TYPE_ACTION,
+                                                 NULL, "can't create sample "
+                                                 "action");
+       } else {
+               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).
@@ -8363,11 +9096,22 @@ __flow_dv_translate(struct rte_eth_dev *dev,
        void *match_value = dev_flow->dv.value.buf;
        uint8_t next_protocol = 0xff;
        struct rte_vlan_hdr vlan = { 0 };
+       struct mlx5_flow_dv_dest_array_resource mdest_res;
+       struct mlx5_flow_dv_sample_resource sample_res;
+       void *sample_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0};
+       struct mlx5_flow_sub_actions_list *sample_act;
+       uint32_t sample_act_pos = UINT32_MAX;
+       uint32_t num_of_dest = 0;
+       int tmp_actions_n = 0;
        uint32_t table;
        int ret = 0;
 
+       memset(&mdest_res, 0, sizeof(struct mlx5_flow_dv_dest_array_resource));
+       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;
+       /* update normal path action resource into last index of array */
+       sample_act = &mdest_res.sample_act[MLX5_MAX_DEST_NUM - 1];
        ret = mlx5_flow_group_to_table(attr, dev_flow->external, attr->group,
                                       !!priv->fdb_def_rule, &table, error);
        if (ret)
@@ -8384,7 +9128,6 @@ __flow_dv_translate(struct rte_eth_dev *dev,
                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;
@@ -8392,6 +9135,7 @@ __flow_dv_translate(struct rte_eth_dev *dev,
                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,
@@ -8414,6 +9158,8 @@ __flow_dv_translate(struct rte_eth_dev *dev,
                                        dev_flow->dv.port_id_action->action;
                        action_flags |= MLX5_FLOW_ACTION_PORT_ID;
                        dev_flow->handle->fate_action = MLX5_FLOW_FATE_PORT_ID;
+                       sample_act->action_flags |= MLX5_FLOW_ACTION_PORT_ID;
+                       num_of_dest++;
                        break;
                case RTE_FLOW_ACTION_TYPE_FLAG:
                        action_flags |= MLX5_FLOW_ACTION_FLAG;
@@ -8499,6 +9245,8 @@ __flow_dv_translate(struct rte_eth_dev *dev,
                        rss_desc->queue[0] = queue->index;
                        action_flags |= MLX5_FLOW_ACTION_QUEUE;
                        dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;
+                       sample_act->action_flags |= MLX5_FLOW_ACTION_QUEUE;
+                       num_of_dest++;
                        break;
                case RTE_FLOW_ACTION_TYPE_RSS:
                        rss = actions->conf;
@@ -8586,6 +9334,9 @@ __flow_dv_translate(struct rte_eth_dev *dev,
                        dev_flow->dv.actions[actions_n++] =
                                        dev_flow->dv.encap_decap->action;
                        action_flags |= MLX5_FLOW_ACTION_ENCAP;
+                       if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
+                               sample_act->action_flags |=
+                                                       MLX5_FLOW_ACTION_ENCAP;
                        break;
                case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
                case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
@@ -8615,6 +9366,9 @@ __flow_dv_translate(struct rte_eth_dev *dev,
                                        dev_flow->dv.encap_decap->action;
                        }
                        action_flags |= MLX5_FLOW_ACTION_ENCAP;
+                       if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
+                               sample_act->action_flags |=
+                                                       MLX5_FLOW_ACTION_ENCAP;
                        break;
                case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
                        while ((++action)->type == RTE_FLOW_ACTION_TYPE_VOID)
@@ -8630,9 +9384,13 @@ __flow_dv_translate(struct rte_eth_dev *dev,
                        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)
@@ -8798,6 +9556,25 @@ __flow_dv_translate(struct rte_eth_dev *dev,
                                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,
+                                                             &num_of_dest,
+                                                             sample_actions,
+                                                             &sample_res,
+                                                             error);
+                       if (ret < 0)
+                               return ret;
+                       actions_n++;
+                       action_flags |= MLX5_FLOW_ACTION_SAMPLE;
+                       /* put encap action into group if work with port id */
+                       if ((action_flags & MLX5_FLOW_ACTION_ENCAP) &&
+                           (action_flags & MLX5_FLOW_ACTION_PORT_ID))
+                               sample_act->action_flags |=
+                                                       MLX5_FLOW_ACTION_ENCAP;
+                       break;
                case RTE_FLOW_ACTION_TYPE_END:
                        actions_end = true;
                        if (mhdr_res->actions_num) {
@@ -8820,9 +9597,33 @@ __flow_dv_translate(struct rte_eth_dev *dev,
                                                NULL,
                                                "cannot create counter"
                                                " object.");
-                               dev_flow->dv.actions[actions_n++] =
+                               dev_flow->dv.actions[actions_n] =
                                          (flow_dv_counter_get_by_idx(dev,
                                          flow->counter, NULL))->action;
+                               actions_n++;
+                       }
+                       if (action_flags & MLX5_FLOW_ACTION_SAMPLE) {
+                               ret = flow_dv_create_action_sample(dev,
+                                                         dev_flow, attr,
+                                                         num_of_dest,
+                                                         &sample_res,
+                                                         &mdest_res,
+                                                         sample_actions,
+                                                         action_flags,
+                                                         error);
+                               if (ret < 0)
+                                       return rte_flow_error_set
+                                               (error, rte_errno,
+                                               RTE_FLOW_ERROR_TYPE_ACTION,
+                                               NULL,
+                                               "cannot create sample action");
+                               if (num_of_dest > 1) {
+                                       dev_flow->dv.actions[sample_act_pos] =
+                                       dev_flow->dv.dest_array_res->action;
+                               } else {
+                                       dev_flow->dv.actions[sample_act_pos] =
+                                       dev_flow->dv.sample_res->verbs_action;
+                               }
                        }
                        break;
                default:
@@ -8832,6 +9633,31 @@ __flow_dv_translate(struct rte_eth_dev *dev,
                    modify_action_position == UINT32_MAX)
                        modify_action_position = actions_n++;
        }
+       /*
+        * For multiple destination (sample action with ratio=1), the encap
+        * action and port id action will be combined into group action.
+        * So need remove the original these actions in the flow and only
+        * use the sample action instead of.
+        */
+       if (num_of_dest > 1 && sample_act->dr_port_id_action) {
+               int i;
+               void *temp_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0};
+
+               for (i = 0; i < actions_n; i++) {
+                       if ((sample_act->dr_encap_action &&
+                               sample_act->dr_encap_action ==
+                               dev_flow->dv.actions[i]) ||
+                               (sample_act->dr_port_id_action &&
+                               sample_act->dr_port_id_action ==
+                               dev_flow->dv.actions[i]))
+                               continue;
+                       temp_actions[tmp_actions_n++] = dev_flow->dv.actions[i];
+               }
+               memcpy((void *)dev_flow->dv.actions,
+                               (void *)temp_actions,
+                               tmp_actions_n * sizeof(void *));
+               actions_n = tmp_actions_n;
+       }
        dev_flow->dv.actions_n = actions_n;
        dev_flow->act_flags = action_flags;
        for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
@@ -9135,7 +9961,8 @@ __flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
                                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 && !dv_h->rix_dest_array) {
                        struct mlx5_hrxq *hrxq;
                        uint32_t hrxq_idx;
                        struct mlx5_flow_rss_desc *rss_desc =
@@ -9267,18 +10094,18 @@ flow_dv_matcher_release(struct rte_eth_dev *dev,
  *
  * @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],
@@ -9421,11 +10248,11 @@ flow_dv_modify_hdr_resource_release(struct rte_eth_dev *dev,
  */
 static int
 flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev,
-                                       struct mlx5_flow_handle *handle)
+                                       uint32_t port_id)
 {
        struct mlx5_priv *priv = dev->data->dev_private;
        struct mlx5_flow_dv_port_id_action_resource *cache_resource;
-       uint32_t idx = handle->rix_port_id_action;
+       uint32_t idx = port_id;
 
        cache_resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PORT_ID],
                                        idx);
@@ -9515,7 +10342,8 @@ flow_dv_fate_resource_release(struct rte_eth_dev *dev,
                flow_dv_jump_tbl_resource_release(dev, handle);
                break;
        case MLX5_FLOW_FATE_PORT_ID:
-               flow_dv_port_id_action_resource_release(dev, handle);
+               flow_dv_port_id_action_resource_release(dev,
+                               handle->rix_port_id_action);
                break;
        case MLX5_FLOW_FATE_DEFAULT_MISS:
                flow_dv_default_miss_resource_release(dev);
@@ -9527,6 +10355,140 @@ flow_dv_fate_resource_release(struct rte_eth_dev *dev,
        handle->rix_fate = 0;
 }
 
+/**
+ * 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,
+               __atomic_load_n(&cache_resource->refcnt, __ATOMIC_RELAXED));
+       if (__atomic_sub_fetch(&cache_resource->refcnt, 1,
+                              __ATOMIC_RELAXED) == 0) {
+               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 (!__atomic_load_n(&cache_resource->refcnt, __ATOMIC_RELAXED)) {
+               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;
+}
+
+/**
+ * Release an destination array 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_dest_array_resource_release(struct rte_eth_dev *dev,
+                                    struct mlx5_flow_handle *handle)
+{
+       struct mlx5_priv *priv = dev->data->dev_private;
+       struct mlx5_flow_dv_dest_array_resource *cache_resource;
+       struct mlx5_flow_sub_actions_idx *mdest_act_res;
+       uint32_t idx = handle->dvh.rix_dest_array;
+       uint32_t i = 0;
+
+       cache_resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY],
+                        idx);
+       if (!cache_resource)
+               return 0;
+       MLX5_ASSERT(cache_resource->action);
+       DRV_LOG(DEBUG, "destination array resource %p: refcnt %d--",
+               (void *)cache_resource,
+               __atomic_load_n(&cache_resource->refcnt, __ATOMIC_RELAXED));
+       if (__atomic_sub_fetch(&cache_resource->refcnt, 1,
+                              __ATOMIC_RELAXED) == 0) {
+               if (cache_resource->action)
+                       claim_zero(mlx5_glue->destroy_flow_action
+                                               (cache_resource->action));
+               for (; i < cache_resource->num_of_dest; i++) {
+                       mdest_act_res = &cache_resource->sample_idx[i];
+                       if (mdest_act_res->rix_hrxq) {
+                               mlx5_hrxq_release(dev,
+                                       mdest_act_res->rix_hrxq);
+                               mdest_act_res->rix_hrxq = 0;
+                       }
+                       if (mdest_act_res->rix_encap_decap) {
+                               flow_dv_encap_decap_resource_release(dev,
+                                       mdest_act_res->rix_encap_decap);
+                               mdest_act_res->rix_encap_decap = 0;
+                       }
+                       if (mdest_act_res->rix_port_id_action) {
+                               flow_dv_port_id_action_resource_release(dev,
+                                       mdest_act_res->rix_port_id_action);
+                               mdest_act_res->rix_port_id_action = 0;
+                       }
+                       if (mdest_act_res->rix_tag) {
+                               flow_dv_tag_release(dev,
+                                       mdest_act_res->rix_tag);
+                               mdest_act_res->rix_tag = 0;
+                       }
+               }
+               ILIST_REMOVE(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY],
+                            &priv->sh->dest_array_list, idx,
+                            cache_resource, next);
+               mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], idx);
+               DRV_LOG(DEBUG, "destination array 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).
@@ -9606,8 +10568,13 @@ __flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
                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_dest_array)
+                       flow_dv_dest_array_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)