net/mlx5: fix packet length assert in MPRQ
[dpdk.git] / drivers / net / mlx5 / mlx5_flow_dv.c
index 6b7f016..2fdd403 100644 (file)
@@ -73,12 +73,9 @@ union flow_dv_attr {
        uint32_t attr;
 };
 
-static struct mlx5_flow_counter_pool *
-flow_dv_find_pool_by_id(struct mlx5_pools_container *cont, bool fallback,
-                       int id);
-static struct mlx5_pools_container *
-flow_dv_pool_create(struct rte_eth_dev *dev, struct mlx5_devx_obj *dcs,
-                   uint32_t batch);
+static int
+flow_dv_tbl_resource_release(struct rte_eth_dev *dev,
+                            struct mlx5_flow_tbl_resource *tbl);
 
 /**
  * Initialize flow attributes structure according to flow items' types.
@@ -437,6 +434,7 @@ flow_dv_convert_modify_action(struct rte_flow_item *item,
                /* Fetch variable byte size mask from the array. */
                mask = flow_dv_fetch_field((const uint8_t *)item->mask +
                                           field->offset, field->size);
+               MLX5_ASSERT(mask);
                if (!mask) {
                        ++field;
                        continue;
@@ -1836,7 +1834,7 @@ flow_dev_get_vlan_info_from_items(const struct rte_flow_item *items,
 static int
 flow_dv_validate_action_push_vlan(struct rte_eth_dev *dev,
                                  uint64_t action_flags,
-                                 uint64_t item_flags __rte_unused,
+                                 const struct rte_flow_item_vlan *vlan_m,
                                  const struct rte_flow_action *action,
                                  const struct rte_flow_attr *attr,
                                  struct rte_flow_error *error)
@@ -1870,6 +1868,32 @@ flow_dv_validate_action_push_vlan(struct rte_eth_dev *dev,
                                          RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
                                          "push vlan action for VF representor "
                                          "not supported on NIC table");
+       if (vlan_m &&
+           (vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) &&
+           (vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) !=
+               MLX5DV_FLOW_VLAN_PCP_MASK_BE &&
+           !(action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_PCP) &&
+           !(mlx5_flow_find_action
+               (action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP)))
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ACTION, action,
+                                         "not full match mask on VLAN PCP and "
+                                         "there is no of_set_vlan_pcp action, "
+                                         "push VLAN action cannot figure out "
+                                         "PCP value");
+       if (vlan_m &&
+           (vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) &&
+           (vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) !=
+               MLX5DV_FLOW_VLAN_VID_MASK_BE &&
+           !(action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_VID) &&
+           !(mlx5_flow_find_action
+               (action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID)))
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ACTION, action,
+                                         "not full match mask on VLAN VID and "
+                                         "there is no of_set_vlan_vid action, "
+                                         "push VLAN action cannot figure out "
+                                         "VID value");
        (void)attr;
        return 0;
 }
@@ -2444,6 +2468,7 @@ flow_dv_encap_decap_resource_register
        struct mlx5_ibv_shared *sh = priv->sh;
        struct mlx5_flow_dv_encap_decap_resource *cache_resource;
        struct mlx5dv_dr_domain *domain;
+       uint32_t idx = 0;
 
        resource->flags = dev_flow->dv.group ? 0 : 1;
        if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
@@ -2453,7 +2478,8 @@ flow_dv_encap_decap_resource_register
        else
                domain = sh->tx_domain;
        /* Lookup a matching resource from cache. */
-       LIST_FOREACH(cache_resource, &sh->encaps_decaps, next) {
+       ILIST_FOREACH(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], sh->encaps_decaps, idx,
+                     cache_resource, next) {
                if (resource->reformat_type == cache_resource->reformat_type &&
                    resource->ft_type == cache_resource->ft_type &&
                    resource->flags == cache_resource->flags &&
@@ -2465,12 +2491,14 @@ flow_dv_encap_decap_resource_register
                                (void *)cache_resource,
                                rte_atomic32_read(&cache_resource->refcnt));
                        rte_atomic32_inc(&cache_resource->refcnt);
-                       dev_flow->handle->dvh.encap_decap = cache_resource;
+                       dev_flow->handle->dvh.rix_encap_decap = idx;
+                       dev_flow->dv.encap_decap = cache_resource;
                        return 0;
                }
        }
        /* Register new encap/decap resource. */
-       cache_resource = rte_calloc(__func__, 1, sizeof(*cache_resource), 0);
+       cache_resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DECAP_ENCAP],
+                                      &dev_flow->handle->dvh.rix_encap_decap);
        if (!cache_resource)
                return rte_flow_error_set(error, ENOMEM,
                                          RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
@@ -2490,8 +2518,10 @@ flow_dv_encap_decap_resource_register
        }
        rte_atomic32_init(&cache_resource->refcnt);
        rte_atomic32_inc(&cache_resource->refcnt);
-       LIST_INSERT_HEAD(&sh->encaps_decaps, cache_resource, next);
-       dev_flow->handle->dvh.encap_decap = cache_resource;
+       ILIST_INSERT(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], &sh->encaps_decaps,
+                    dev_flow->handle->dvh.rix_encap_decap, cache_resource,
+                    next);
+       dev_flow->dv.encap_decap = cache_resource;
        DRV_LOG(DEBUG, "new encap/decap resource %p: refcnt %d++",
                (void *)cache_resource,
                rte_atomic32_read(&cache_resource->refcnt));
@@ -2537,12 +2567,15 @@ flow_dv_jump_tbl_resource_register
                DRV_LOG(DEBUG, "new jump table resource %p: refcnt %d++",
                        (void *)&tbl_data->jump, cnt);
        } else {
+               /* old jump should not make the table ref++. */
+               flow_dv_tbl_resource_release(dev, &tbl_data->tbl);
                MLX5_ASSERT(tbl_data->jump.action);
                DRV_LOG(DEBUG, "existed jump table resource %p: refcnt %d++",
                        (void *)&tbl_data->jump, cnt);
        }
        rte_atomic32_inc(&tbl_data->jump.refcnt);
-       dev_flow->handle->dvh.jump = &tbl_data->jump;
+       dev_flow->handle->rix_jump = tbl_data->idx;
+       dev_flow->dv.jump = &tbl_data->jump;
        return 0;
 }
 
@@ -2571,21 +2604,25 @@ flow_dv_port_id_action_resource_register
        struct mlx5_priv *priv = dev->data->dev_private;
        struct mlx5_ibv_shared *sh = priv->sh;
        struct mlx5_flow_dv_port_id_action_resource *cache_resource;
+       uint32_t idx = 0;
 
        /* Lookup a matching resource from cache. */
-       LIST_FOREACH(cache_resource, &sh->port_id_action_list, next) {
+       ILIST_FOREACH(sh->ipool[MLX5_IPOOL_PORT_ID], sh->port_id_action_list,
+                     idx, cache_resource, next) {
                if (resource->port_id == cache_resource->port_id) {
                        DRV_LOG(DEBUG, "port id action resource resource %p: "
                                "refcnt %d++",
                                (void *)cache_resource,
                                rte_atomic32_read(&cache_resource->refcnt));
                        rte_atomic32_inc(&cache_resource->refcnt);
-                       dev_flow->handle->dvh.port_id_action = cache_resource;
+                       dev_flow->handle->rix_port_id_action = idx;
+                       dev_flow->dv.port_id_action = cache_resource;
                        return 0;
                }
        }
        /* Register new port id action resource. */
-       cache_resource = rte_calloc(__func__, 1, sizeof(*cache_resource), 0);
+       cache_resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PORT_ID],
+                                      &dev_flow->handle->rix_port_id_action);
        if (!cache_resource)
                return rte_flow_error_set(error, ENOMEM,
                                          RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
@@ -2607,8 +2644,10 @@ flow_dv_port_id_action_resource_register
        }
        rte_atomic32_init(&cache_resource->refcnt);
        rte_atomic32_inc(&cache_resource->refcnt);
-       LIST_INSERT_HEAD(&sh->port_id_action_list, cache_resource, next);
-       dev_flow->handle->dvh.port_id_action = cache_resource;
+       ILIST_INSERT(sh->ipool[MLX5_IPOOL_PORT_ID], &sh->port_id_action_list,
+                    dev_flow->handle->rix_port_id_action, cache_resource,
+                    next);
+       dev_flow->dv.port_id_action = cache_resource;
        DRV_LOG(DEBUG, "new port id action resource %p: refcnt %d++",
                (void *)cache_resource,
                rte_atomic32_read(&cache_resource->refcnt));
@@ -2641,9 +2680,11 @@ flow_dv_push_vlan_action_resource_register
        struct mlx5_ibv_shared *sh = priv->sh;
        struct mlx5_flow_dv_push_vlan_action_resource *cache_resource;
        struct mlx5dv_dr_domain *domain;
+       uint32_t idx = 0;
 
        /* Lookup a matching resource from cache. */
-       LIST_FOREACH(cache_resource, &sh->push_vlan_action_list, next) {
+       ILIST_FOREACH(sh->ipool[MLX5_IPOOL_PUSH_VLAN],
+                     sh->push_vlan_action_list, idx, cache_resource, next) {
                if (resource->vlan_tag == cache_resource->vlan_tag &&
                    resource->ft_type == cache_resource->ft_type) {
                        DRV_LOG(DEBUG, "push-VLAN action resource resource %p: "
@@ -2651,12 +2692,14 @@ flow_dv_push_vlan_action_resource_register
                                (void *)cache_resource,
                                rte_atomic32_read(&cache_resource->refcnt));
                        rte_atomic32_inc(&cache_resource->refcnt);
-                       dev_flow->handle->dvh.push_vlan_res = cache_resource;
+                       dev_flow->handle->dvh.rix_push_vlan = idx;
+                       dev_flow->dv.push_vlan_res = cache_resource;
                        return 0;
                }
        }
        /* Register new push_vlan action resource. */
-       cache_resource = rte_calloc(__func__, 1, sizeof(*cache_resource), 0);
+       cache_resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PUSH_VLAN],
+                                      &dev_flow->handle->dvh.rix_push_vlan);
        if (!cache_resource)
                return rte_flow_error_set(error, ENOMEM,
                                          RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
@@ -2679,8 +2722,11 @@ flow_dv_push_vlan_action_resource_register
        }
        rte_atomic32_init(&cache_resource->refcnt);
        rte_atomic32_inc(&cache_resource->refcnt);
-       LIST_INSERT_HEAD(&sh->push_vlan_action_list, cache_resource, next);
-       dev_flow->handle->dvh.push_vlan_res = cache_resource;
+       ILIST_INSERT(sh->ipool[MLX5_IPOOL_PUSH_VLAN],
+                    &sh->push_vlan_action_list,
+                    dev_flow->handle->dvh.rix_push_vlan,
+                    cache_resource, next);
+       dev_flow->dv.push_vlan_res = cache_resource;
        DRV_LOG(DEBUG, "new push vlan action resource %p: refcnt %d++",
                (void *)cache_resource,
                rte_atomic32_read(&cache_resource->refcnt));
@@ -3087,6 +3133,7 @@ flow_dv_create_action_raw_encap(struct rte_eth_dev *dev,
        const struct rte_flow_action_raw_encap *encap_data;
        struct mlx5_flow_dv_encap_decap_resource res;
 
+       memset(&res, 0, sizeof(res));
        encap_data = (const struct rte_flow_action_raw_encap *)action->conf;
        res.size = encap_data->size;
        memcpy(res.buf, encap_data->data, res.size);
@@ -3131,6 +3178,7 @@ flow_dv_create_action_push_vlan(struct rte_eth_dev *dev,
 {
        struct mlx5_flow_dv_push_vlan_action_resource res;
 
+       memset(&res, 0, sizeof(res));
        res.vlan_tag =
                rte_cpu_to_be_32(((uint32_t)vlan->eth_proto) << 16 |
                                 vlan->vlan_tci);
@@ -3660,9 +3708,9 @@ mlx5_flow_validate_action_meter(struct rte_eth_dev *dev,
                return rte_flow_error_set(error, EINVAL,
                                          RTE_FLOW_ERROR_TYPE_ACTION, NULL,
                                          "Meter not found");
-       if (fm->ref_cnt && (!(fm->attr.transfer == attr->transfer ||
-             (!fm->attr.ingress && !attr->ingress && attr->egress) ||
-             (!fm->attr.egress && !attr->egress && attr->ingress))))
+       if (fm->ref_cnt && (!(fm->transfer == attr->transfer ||
+             (!fm->ingress && !attr->ingress && attr->egress) ||
+             (!fm->egress && !attr->egress && attr->ingress))))
                return rte_flow_error_set(error, EINVAL,
                                          RTE_FLOW_ERROR_TYPE_ACTION, NULL,
                                          "Flow attributes are either invalid "
@@ -3827,105 +3875,6 @@ flow_dv_modify_hdr_resource_register
        return 0;
 }
 
-/**
- * Get or create a flow counter.
- *
- * @param[in] dev
- *   Pointer to the Ethernet device structure.
- * @param[in] shared
- *   Indicate if this counter is shared with other flows.
- * @param[in] id
- *   Counter identifier.
- *
- * @return
- *   Index to flow counter on success, 0 otherwise and rte_errno is set.
- */
-static uint32_t
-flow_dv_counter_alloc_fallback(struct rte_eth_dev *dev, uint32_t shared,
-                              uint32_t id)
-{
-       struct mlx5_priv *priv = dev->data->dev_private;
-       struct mlx5_pools_container *cont = MLX5_CNT_CONTAINER(priv->sh, 0, 0);
-       struct mlx5_flow_counter_pool *pool;
-       struct mlx5_flow_counter_ext *cnt_ext;
-       struct mlx5_devx_obj *dcs = NULL;
-       uint32_t offset;
-
-       if (!priv->config.devx) {
-               rte_errno = ENOTSUP;
-               return 0;
-       }
-       dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->ctx, 0);
-       if (!dcs)
-               return 0;
-       pool = flow_dv_find_pool_by_id(cont, true, dcs->id);
-       if (!pool) {
-               cont = flow_dv_pool_create(dev, dcs, 0);
-               if (!cont) {
-                       mlx5_devx_cmd_destroy(dcs);
-                       rte_errno = ENOMEM;
-                       return 0;
-               }
-               pool = TAILQ_FIRST(&cont->pool_list);
-       }
-       offset = dcs->id % MLX5_COUNTERS_PER_POOL;
-       cnt_ext = MLX5_GET_POOL_CNT_EXT(pool, offset);
-       cnt_ext->shared = shared;
-       cnt_ext->ref_cnt = 1;
-       cnt_ext->id = id;
-       cnt_ext->dcs = dcs;
-       pool->counters_raw[offset].action =
-             mlx5_glue->dv_create_flow_action_counter(dcs->obj, 0);
-       if (!pool->counters_raw[offset].action) {
-               claim_zero(mlx5_devx_cmd_destroy(dcs));
-               rte_errno = errno;
-               return 0;
-       }
-       return MLX5_MAKE_CNT_IDX(pool->index, offset);
-}
-
-/**
- * Release a flow counter.
- *
- * @param[in] dev
- *   Pointer to the Ethernet device structure.
- * @param[in] counter
- *   Extend counter handler.
- */
-static void
-flow_dv_counter_release_fallback(struct rte_eth_dev *dev __rte_unused,
-                                struct mlx5_flow_counter_ext *counter)
-{
-       if (!counter)
-               return;
-       claim_zero(mlx5_devx_cmd_destroy(counter->dcs));
-       counter->dcs = NULL;
-}
-
-/**
- * Query a devx flow counter.
- *
- * @param[in] dev
- *   Pointer to the Ethernet device structure.
- * @param[in] cnt
- *   Pointer to the flow counter.
- * @param[out] pkts
- *   The statistics value of packets.
- * @param[out] bytes
- *   The statistics value of bytes.
- *
- * @return
- *   0 on success, otherwise a negative errno value and rte_errno is set.
- */
-static inline int
-_flow_dv_query_count_fallback(struct rte_eth_dev *dev __rte_unused,
-                    struct mlx5_flow_counter_ext *cnt, uint64_t *pkts,
-                    uint64_t *bytes)
-{
-       return mlx5_devx_cmd_flow_counter_query(cnt->dcs, 0, 0, pkts, bytes,
-                                               0, NULL, NULL, 0);
-}
-
 /**
  * Get DV flow counter by index.
  *
@@ -3968,8 +3917,6 @@ flow_dv_counter_get_by_idx(struct rte_eth_dev *dev,
  *
  * @param[in] cont
  *   Pointer to the counter container.
- * @param[in] fallback
- *   Fallback mode.
  * @param[in] id
  *   The counter devx ID.
  *
@@ -3977,16 +3924,15 @@ flow_dv_counter_get_by_idx(struct rte_eth_dev *dev,
  *   The counter pool pointer if exists, NULL otherwise,
  */
 static struct mlx5_flow_counter_pool *
-flow_dv_find_pool_by_id(struct mlx5_pools_container *cont, bool fallback,
-                       int id)
+flow_dv_find_pool_by_id(struct mlx5_pools_container *cont, int id)
 {
        uint32_t i;
        uint32_t n_valid = rte_atomic16_read(&cont->n_valid);
 
        for (i = 0; i < n_valid; i++) {
                struct mlx5_flow_counter_pool *pool = cont->pools[i];
-               int base = ((fallback ? pool->dcs_id : pool->min_dcs->id) /
-                          MLX5_COUNTERS_PER_POOL) * MLX5_COUNTERS_PER_POOL;
+               int base = (pool->min_dcs->id / MLX5_COUNTERS_PER_POOL) *
+                          MLX5_COUNTERS_PER_POOL;
 
                if (id >= base && id < base + MLX5_COUNTERS_PER_POOL) {
                        /*
@@ -4089,12 +4035,14 @@ flow_dv_container_resize(struct rte_eth_dev *dev, uint32_t batch)
                        MLX5_CNT_CONTAINER(priv->sh, batch, 0);
        struct mlx5_pools_container *new_cont =
                        MLX5_CNT_CONTAINER_UNUSED(priv->sh, batch, 0);
-       struct mlx5_counter_stats_mem_mng *mem_mng;
+       struct mlx5_counter_stats_mem_mng *mem_mng = NULL;
        uint32_t resize = cont->n + MLX5_CNT_CONTAINER_RESIZE;
        uint32_t mem_size = sizeof(struct mlx5_flow_counter_pool *) * resize;
        int i;
 
-       if (cont != MLX5_CNT_CONTAINER(priv->sh, batch, 1)) {
+       /* Fallback mode has no background thread. Skip the check. */
+       if (!priv->counter_fallback &&
+           cont != MLX5_CNT_CONTAINER(priv->sh, batch, 1)) {
                /* The last resize still hasn't detected by the host thread. */
                rte_errno = EAGAIN;
                return NULL;
@@ -4107,16 +4055,29 @@ flow_dv_container_resize(struct rte_eth_dev *dev, uint32_t batch)
        if (cont->n)
                memcpy(new_cont->pools, cont->pools, cont->n *
                       sizeof(struct mlx5_flow_counter_pool *));
-       mem_mng = flow_dv_create_counter_stat_mem_mng(dev,
-               MLX5_CNT_CONTAINER_RESIZE + MLX5_MAX_PENDING_QUERIES);
-       if (!mem_mng) {
-               rte_free(new_cont->pools);
-               return NULL;
+       /*
+        * Fallback mode query the counter directly, no background query
+        * resources are needed.
+        */
+       if (!priv->counter_fallback) {
+               mem_mng = flow_dv_create_counter_stat_mem_mng(dev,
+                       MLX5_CNT_CONTAINER_RESIZE + MLX5_MAX_PENDING_QUERIES);
+               if (!mem_mng) {
+                       rte_free(new_cont->pools);
+                       return NULL;
+               }
+               for (i = 0; i < MLX5_MAX_PENDING_QUERIES; ++i)
+                       LIST_INSERT_HEAD(&priv->sh->cmng.free_stat_raws,
+                                        mem_mng->raws +
+                                        MLX5_CNT_CONTAINER_RESIZE +
+                                        i, next);
+       } else {
+               /*
+                * Release the old container pools directly as no background
+                * thread helps that.
+                */
+               rte_free(cont->pools);
        }
-       for (i = 0; i < MLX5_MAX_PENDING_QUERIES; ++i)
-               LIST_INSERT_HEAD(&priv->sh->cmng.free_stat_raws,
-                                mem_mng->raws + MLX5_CNT_CONTAINER_RESIZE +
-                                i, next);
        new_cont->n = resize;
        rte_atomic16_set(&new_cont->n_valid, rte_atomic16_read(&cont->n_valid));
        TAILQ_INIT(&new_cont->pool_list);
@@ -4158,8 +4119,8 @@ _flow_dv_query_count(struct rte_eth_dev *dev, uint32_t counter, uint64_t *pkts,
        if (counter < MLX5_CNT_BATCH_OFFSET) {
                cnt_ext = MLX5_CNT_TO_CNT_EXT(pool, cnt);
                if (priv->counter_fallback)
-                       return _flow_dv_query_count_fallback(dev, cnt_ext,
-                                                            pkts, bytes);
+                       return mlx5_devx_cmd_flow_counter_query(cnt_ext->dcs, 0,
+                                       0, pkts, bytes, 0, NULL, NULL, 0);
        }
 
        rte_spinlock_lock(&pool->sl);
@@ -4220,11 +4181,9 @@ flow_dv_pool_create(struct rte_eth_dev *dev, struct mlx5_devx_obj *dcs,
                rte_errno = ENOMEM;
                return NULL;
        }
-       if (priv->counter_fallback)
-               pool->dcs_id = dcs->id;
-       else
-               pool->min_dcs = dcs;
-       pool->raw = cont->init_mem_mng->raws + n_valid %
+       pool->min_dcs = dcs;
+       if (!priv->counter_fallback)
+               pool->raw = cont->init_mem_mng->raws + n_valid %
                                                     MLX5_CNT_CONTAINER_RESIZE;
        pool->raw_hw = NULL;
        rte_spinlock_init(&pool->sl);
@@ -4236,7 +4195,13 @@ flow_dv_pool_create(struct rte_eth_dev *dev, struct mlx5_devx_obj *dcs,
         * without the last query finished and stats updated to the memory.
         */
        rte_atomic64_set(&pool->start_query_gen, 0x2);
-       rte_atomic64_set(&pool->end_query_gen, 0x2);
+       /*
+        * There's no background query thread for fallback mode, set the
+        * end_query_gen to the maximum value since no need to wait for
+        * statistics update.
+        */
+       rte_atomic64_set(&pool->end_query_gen, priv->counter_fallback ?
+                        INT64_MAX : 0x2);
        TAILQ_INIT(&pool->counters);
        TAILQ_INSERT_HEAD(&cont->pool_list, pool, next);
        pool->index = n_valid;
@@ -4279,7 +4244,7 @@ flow_dv_counter_pool_prepare(struct rte_eth_dev *dev,
                dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->ctx, 0);
                if (!dcs)
                        return NULL;
-               pool = flow_dv_find_pool_by_id(cont, false, dcs->id);
+               pool = flow_dv_find_pool_by_id(cont, dcs->id);
                if (!pool) {
                        cont = flow_dv_pool_create(dev, dcs, batch);
                        if (!cont) {
@@ -4386,7 +4351,7 @@ flow_dv_counter_alloc(struct rte_eth_dev *dev, uint32_t shared, uint32_t id,
         * A counter can be shared between different groups so need to take
         * shared counters from the single container.
         */
-       uint32_t batch = (group && !shared) ? 1 : 0;
+       uint32_t batch = (group && !shared && !priv->counter_fallback) ? 1 : 0;
        struct mlx5_pools_container *cont = MLX5_CNT_CONTAINER(priv->sh, batch,
                                                               0);
        uint32_t cnt_idx;
@@ -4409,9 +4374,6 @@ flow_dv_counter_alloc(struct rte_eth_dev *dev, uint32_t shared, uint32_t id,
                        return cnt_idx;
                }
        }
-       if (priv->counter_fallback)
-               return flow_dv_counter_alloc_fallback(dev, shared, id);
-
        /* Pools which has a free counters are in the start. */
        TAILQ_FOREACH(pool, &cont->pool_list, next) {
                /*
@@ -4468,7 +4430,7 @@ flow_dv_counter_alloc(struct rte_eth_dev *dev, uint32_t shared, uint32_t id,
                cnt_ext->ref_cnt = 1;
                cnt_ext->id = id;
        }
-       if (!priv->sh->cmng.query_thread_on)
+       if (!priv->counter_fallback && !priv->sh->cmng.query_thread_on)
                /* Start the asynchronous batch query by the host thread. */
                mlx5_set_query_alarm(priv->sh);
        TAILQ_REMOVE(&pool->counters, cnt_free, next);
@@ -4491,7 +4453,6 @@ flow_dv_counter_alloc(struct rte_eth_dev *dev, uint32_t shared, uint32_t id,
 static void
 flow_dv_counter_release(struct rte_eth_dev *dev, uint32_t counter)
 {
-       struct mlx5_priv *priv = dev->data->dev_private;
        struct mlx5_flow_counter_pool *pool = NULL;
        struct mlx5_flow_counter *cnt;
        struct mlx5_flow_counter_ext *cnt_ext = NULL;
@@ -4500,15 +4461,10 @@ flow_dv_counter_release(struct rte_eth_dev *dev, uint32_t counter)
                return;
        cnt = flow_dv_counter_get_by_idx(dev, counter, &pool);
        MLX5_ASSERT(pool);
-       if (counter < MLX5_CNT_BATCH_OFFSET)
+       if (counter < MLX5_CNT_BATCH_OFFSET) {
                cnt_ext = MLX5_CNT_TO_CNT_EXT(pool, cnt);
-       if (cnt_ext && --cnt_ext->ref_cnt)
-               return;
-       if (priv->counter_fallback) {
-               claim_zero(mlx5_glue->destroy_flow_action(cnt->action));
-               flow_dv_counter_release_fallback(dev, cnt_ext);
-               cnt->action = NULL;
-               return;
+               if (cnt_ext && --cnt_ext->ref_cnt)
+                       return;
        }
        /* Put the counter in the end - the last updated one. */
        TAILQ_INSERT_TAIL(&pool->counters, cnt, next);
@@ -4535,7 +4491,9 @@ flow_dv_counter_release(struct rte_eth_dev *dev, uint32_t counter)
  *   Pointer to error structure.
  *
  * @return
- *   0 on success, a negative errno value otherwise and rte_errno is set.
+ *   - 0 on success and non root table.
+ *   - 1 on success and root table.
+ *   - a negative errno value otherwise and rte_errno is set.
  */
 static int
 flow_dv_validate_attributes(struct rte_eth_dev *dev,
@@ -4545,6 +4503,7 @@ flow_dv_validate_attributes(struct rte_eth_dev *dev,
 {
        struct mlx5_priv *priv = dev->data->dev_private;
        uint32_t priority_max = priv->config.flow_prio - 1;
+       int ret = 0;
 
 #ifndef HAVE_MLX5DV_DR
        if (attributes->group)
@@ -4553,14 +4512,15 @@ flow_dv_validate_attributes(struct rte_eth_dev *dev,
                                          NULL,
                                          "groups are not supported");
 #else
-       uint32_t table;
-       int ret;
+       uint32_t table = 0;
 
        ret = mlx5_flow_group_to_table(attributes, external,
                                       attributes->group, !!priv->fdb_def_rule,
                                       &table, error);
        if (ret)
                return ret;
+       if (!table)
+               ret = MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL;
 #endif
        if (attributes->priority != MLX5_FLOW_PRIO_RSVD &&
            attributes->priority >= priority_max)
@@ -4590,7 +4550,7 @@ flow_dv_validate_attributes(struct rte_eth_dev *dev,
                                          RTE_FLOW_ERROR_TYPE_ATTR, NULL,
                                          "must specify exactly one of "
                                          "ingress or egress");
-       return 0;
+       return ret;
 }
 
 /**
@@ -4606,6 +4566,8 @@ flow_dv_validate_attributes(struct rte_eth_dev *dev,
  *   Pointer to the list of actions.
  * @param[in] external
  *   This flow rule is created by request external to PMD.
+ * @param[in] hairpin
+ *   Number of hairpin TX actions, 0 means classic flow.
  * @param[out] error
  *   Pointer to the error structure.
  *
@@ -4616,7 +4578,7 @@ static int
 flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                 const struct rte_flow_item items[],
                 const struct rte_flow_action actions[],
-                bool external, struct rte_flow_error *error)
+                bool external, int hairpin, struct rte_flow_error *error)
 {
        int ret;
        uint64_t action_flags = 0;
@@ -4662,12 +4624,16 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
        struct mlx5_priv *priv = dev->data->dev_private;
        struct mlx5_dev_config *dev_conf = &priv->config;
        uint16_t queue_index = 0xFFFF;
+       const struct rte_flow_item_vlan *vlan_m = NULL;
+       int16_t rw_act_num = 0;
+       uint64_t is_root;
 
        if (items == NULL)
                return -1;
        ret = flow_dv_validate_attributes(dev, attr, external, error);
        if (ret < 0)
                return ret;
+       is_root = (uint64_t)ret;
        for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
                int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
                int type = items->type;
@@ -4719,6 +4685,9 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                        } else {
                                ether_type = 0;
                        }
+                       /* Store outer VLAN mask for of_push_vlan action. */
+                       if (!tunnel)
+                               vlan_m = items->mask;
                        break;
                case RTE_FLOW_ITEM_TYPE_IPV4:
                        mlx5_flow_tunnel_ip_check(items, next_protocol,
@@ -4941,6 +4910,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                                action_flags |= MLX5_FLOW_ACTION_FLAG;
                                ++actions_n;
                        }
+                       rw_act_num += MLX5_ACT_NUM_SET_MARK;
                        break;
                case RTE_FLOW_ACTION_TYPE_MARK:
                        ret = flow_dv_validate_action_mark(dev, actions,
@@ -4959,6 +4929,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                                action_flags |= MLX5_FLOW_ACTION_MARK;
                                ++actions_n;
                        }
+                       rw_act_num += MLX5_ACT_NUM_SET_MARK;
                        break;
                case RTE_FLOW_ACTION_TYPE_SET_META:
                        ret = flow_dv_validate_action_set_meta(dev, actions,
@@ -4970,6 +4941,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                        if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
                                ++actions_n;
                        action_flags |= MLX5_FLOW_ACTION_SET_META;
+                       rw_act_num += MLX5_ACT_NUM_SET_META;
                        break;
                case RTE_FLOW_ACTION_TYPE_SET_TAG:
                        ret = flow_dv_validate_action_set_tag(dev, actions,
@@ -4981,6 +4953,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                        if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
                                ++actions_n;
                        action_flags |= MLX5_FLOW_ACTION_SET_TAG;
+                       rw_act_num += MLX5_ACT_NUM_SET_TAG;
                        break;
                case RTE_FLOW_ACTION_TYPE_DROP:
                        ret = mlx5_flow_validate_action_drop(action_flags,
@@ -5034,7 +5007,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
                        ret = flow_dv_validate_action_push_vlan(dev,
                                                                action_flags,
-                                                               item_flags,
+                                                               vlan_m,
                                                                actions, attr,
                                                                error);
                        if (ret < 0)
@@ -5058,6 +5031,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                                return ret;
                        /* Count VID with push_vlan command. */
                        action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID;
+                       rw_act_num += MLX5_ACT_NUM_MDF_VID;
                        break;
                case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
                case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
@@ -5119,8 +5093,15 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                                        RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ?
                                                MLX5_FLOW_ACTION_SET_MAC_SRC :
                                                MLX5_FLOW_ACTION_SET_MAC_DST;
+                       /*
+                        * Even if the source and destination MAC addresses have
+                        * overlap in the header with 4B alignment, the convert
+                        * function will handle them separately and 4 SW actions
+                        * will be created. And 2 actions will be added each
+                        * time no matter how many bytes of address will be set.
+                        */
+                       rw_act_num += MLX5_ACT_NUM_MDF_MAC;
                        break;
-
                case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
                case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
                        ret = flow_dv_validate_action_modify_ipv4(action_flags,
@@ -5136,6 +5117,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                                        RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ?
                                                MLX5_FLOW_ACTION_SET_IPV4_SRC :
                                                MLX5_FLOW_ACTION_SET_IPV4_DST;
+                       rw_act_num += MLX5_ACT_NUM_MDF_IPV4;
                        break;
                case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
                case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
@@ -5158,6 +5140,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                                        RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ?
                                                MLX5_FLOW_ACTION_SET_IPV6_SRC :
                                                MLX5_FLOW_ACTION_SET_IPV6_DST;
+                       rw_act_num += MLX5_ACT_NUM_MDF_IPV6;
                        break;
                case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
                case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
@@ -5174,6 +5157,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                                        RTE_FLOW_ACTION_TYPE_SET_TP_SRC ?
                                                MLX5_FLOW_ACTION_SET_TP_SRC :
                                                MLX5_FLOW_ACTION_SET_TP_DST;
+                       rw_act_num += MLX5_ACT_NUM_MDF_PORT;
                        break;
                case RTE_FLOW_ACTION_TYPE_DEC_TTL:
                case RTE_FLOW_ACTION_TYPE_SET_TTL:
@@ -5190,6 +5174,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                                        RTE_FLOW_ACTION_TYPE_SET_TTL ?
                                                MLX5_FLOW_ACTION_SET_TTL :
                                                MLX5_FLOW_ACTION_DEC_TTL;
+                       rw_act_num += MLX5_ACT_NUM_MDF_TTL;
                        break;
                case RTE_FLOW_ACTION_TYPE_JUMP:
                        ret = flow_dv_validate_action_jump(actions,
@@ -5217,6 +5202,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                                        RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ?
                                                MLX5_FLOW_ACTION_INC_TCP_SEQ :
                                                MLX5_FLOW_ACTION_DEC_TCP_SEQ;
+                       rw_act_num += MLX5_ACT_NUM_MDF_TCPSEQ;
                        break;
                case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
                case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
@@ -5234,10 +5220,13 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                                        RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ?
                                                MLX5_FLOW_ACTION_INC_TCP_ACK :
                                                MLX5_FLOW_ACTION_DEC_TCP_ACK;
+                       rw_act_num += MLX5_ACT_NUM_MDF_TCPACK;
                        break;
-               case MLX5_RTE_FLOW_ACTION_TYPE_TAG:
                case MLX5_RTE_FLOW_ACTION_TYPE_MARK:
+                       break;
+               case MLX5_RTE_FLOW_ACTION_TYPE_TAG:
                case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG:
+                       rw_act_num += MLX5_ACT_NUM_SET_TAG;
                        break;
                case RTE_FLOW_ACTION_TYPE_METER:
                        ret = mlx5_flow_validate_action_meter(dev,
@@ -5248,6 +5237,8 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                                return ret;
                        action_flags |= MLX5_FLOW_ACTION_METER;
                        ++actions_n;
+                       /* Meter action will add one more TAG action. */
+                       rw_act_num += MLX5_ACT_NUM_SET_TAG;
                        break;
                case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
                        ret = flow_dv_validate_action_modify_ipv4_dscp
@@ -5261,6 +5252,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                        if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
                                ++actions_n;
                        action_flags |= MLX5_FLOW_ACTION_SET_IPV4_DSCP;
+                       rw_act_num += MLX5_ACT_NUM_SET_DSCP;
                        break;
                case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP:
                        ret = flow_dv_validate_action_modify_ipv6_dscp
@@ -5274,6 +5266,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                        if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
                                ++actions_n;
                        action_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP;
+                       rw_act_num += MLX5_ACT_NUM_SET_DSCP;
                        break;
                default:
                        return rte_flow_error_set(error, ENOTSUP,
@@ -5346,6 +5339,21 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                                                  NULL, "encap is not supported"
                                                  " for ingress traffic");
        }
+       /* Hairpin flow will add one more TAG action. */
+       if (hairpin > 0)
+               rw_act_num += MLX5_ACT_NUM_SET_TAG;
+       /* extra metadata enabled: one more TAG action will be add. */
+       if (dev_conf->dv_flow_en &&
+           dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY &&
+           mlx5_flow_ext_mreg_supported(dev))
+               rw_act_num += MLX5_ACT_NUM_SET_TAG;
+       if ((uint32_t)rw_act_num >=
+                       flow_dv_modify_hdr_action_max(dev, is_root)) {
+               return rte_flow_error_set(error, ENOTSUP,
+                                         RTE_FLOW_ERROR_TYPE_ACTION,
+                                         NULL, "too many header modify"
+                                         " actions to support");
+       }
        return 0;
 }
 
@@ -5375,7 +5383,7 @@ flow_dv_prepare(struct rte_eth_dev *dev,
                const struct rte_flow_action actions[] __rte_unused,
                struct rte_flow_error *error)
 {
-       size_t size = sizeof(struct mlx5_flow_handle);
+       uint32_t handle_idx = 0;
        struct mlx5_flow *dev_flow;
        struct mlx5_flow_handle *dev_handle;
        struct mlx5_priv *priv = dev->data->dev_private;
@@ -5387,7 +5395,8 @@ flow_dv_prepare(struct rte_eth_dev *dev,
                                   "not free temporary device flow");
                return NULL;
        }
-       dev_handle = rte_calloc(__func__, 1, size, 0);
+       dev_handle = mlx5_ipool_zmalloc(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
+                                  &handle_idx);
        if (!dev_handle) {
                rte_flow_error_set(error, ENOMEM,
                                   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
@@ -5397,6 +5406,7 @@ flow_dv_prepare(struct rte_eth_dev *dev,
        /* No multi-thread supporting. */
        dev_flow = &((struct mlx5_flow *)priv->inter_flows)[priv->flow_idx++];
        dev_flow->handle = dev_handle;
+       dev_flow->handle_idx = handle_idx;
        dev_flow->dv.value.size = MLX5_ST_SZ_BYTES(fte_match_param);
        /*
         * The matching value needs to be cleared to 0 before using. In the
@@ -6918,6 +6928,7 @@ flow_dv_tbl_resource_get(struct rte_eth_dev *dev,
        struct mlx5_hlist_entry *pos = mlx5_hlist_lookup(sh->flow_tbls,
                                                         table_key.v64);
        struct mlx5_flow_tbl_data_entry *tbl_data;
+       uint32_t idx = 0;
        int ret;
        void *domain;
 
@@ -6928,7 +6939,7 @@ flow_dv_tbl_resource_get(struct rte_eth_dev *dev,
                rte_atomic32_inc(&tbl->refcnt);
                return tbl;
        }
-       tbl_data = rte_zmalloc(NULL, sizeof(*tbl_data), 0);
+       tbl_data = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_JUMP], &idx);
        if (!tbl_data) {
                rte_flow_error_set(error, ENOMEM,
                                   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
@@ -6936,6 +6947,7 @@ flow_dv_tbl_resource_get(struct rte_eth_dev *dev,
                                   "cannot allocate flow table data entry");
                return NULL;
        }
+       tbl_data->idx = idx;
        tbl = &tbl_data->tbl;
        pos = &tbl_data->entry;
        if (transfer)
@@ -6949,7 +6961,7 @@ flow_dv_tbl_resource_get(struct rte_eth_dev *dev,
                rte_flow_error_set(error, ENOMEM,
                                   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
                                   NULL, "cannot create flow table object");
-               rte_free(tbl_data);
+               mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx);
                return NULL;
        }
        /*
@@ -6966,7 +6978,7 @@ flow_dv_tbl_resource_get(struct rte_eth_dev *dev,
                                   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
                                   "cannot insert flow table data entry");
                mlx5_glue->dr_destroy_flow_tbl(tbl->obj);
-               rte_free(tbl_data);
+               mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx);
        }
        rte_atomic32_inc(&tbl->refcnt);
        return tbl;
@@ -7001,7 +7013,8 @@ flow_dv_tbl_resource_release(struct rte_eth_dev *dev,
                tbl->obj = NULL;
                /* remove the entry from the hash list and free memory. */
                mlx5_hlist_remove(sh->flow_tbls, pos);
-               rte_free(tbl_data);
+               mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_JUMP],
+                               tbl_data->idx);
                return 0;
        }
        return 1;
@@ -7141,14 +7154,16 @@ flow_dv_tag_resource_register
                cache_resource = container_of
                        (entry, struct mlx5_flow_dv_tag_resource, entry);
                rte_atomic32_inc(&cache_resource->refcnt);
-               dev_flow->handle->dvh.tag_resource = cache_resource;
+               dev_flow->handle->dvh.rix_tag = cache_resource->idx;
+               dev_flow->dv.tag_resource = cache_resource;
                DRV_LOG(DEBUG, "cached tag resource %p: refcnt now %d++",
                        (void *)cache_resource,
                        rte_atomic32_read(&cache_resource->refcnt));
                return 0;
        }
        /* Register new resource. */
-       cache_resource = rte_calloc(__func__, 1, sizeof(*cache_resource), 0);
+       cache_resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_TAG],
+                                      &dev_flow->handle->dvh.rix_tag);
        if (!cache_resource)
                return rte_flow_error_set(error, ENOMEM,
                                          RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
@@ -7170,7 +7185,7 @@ flow_dv_tag_resource_register
                                          RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
                                          NULL, "cannot insert tag");
        }
-       dev_flow->handle->dvh.tag_resource = cache_resource;
+       dev_flow->dv.tag_resource = cache_resource;
        DRV_LOG(DEBUG, "new tag resource %p: refcnt now %d++",
                (void *)cache_resource,
                rte_atomic32_read(&cache_resource->refcnt));
@@ -7182,20 +7197,23 @@ flow_dv_tag_resource_register
  *
  * @param dev
  *   Pointer to Ethernet device.
- * @param flow
- *   Pointer to mlx5_flow.
+ * @param tag_idx
+ *   Tag index.
  *
  * @return
  *   1 while a reference on it exists, 0 when freed.
  */
 static int
 flow_dv_tag_release(struct rte_eth_dev *dev,
-                   struct mlx5_flow_dv_tag_resource *tag)
+                   uint32_t tag_idx)
 {
        struct mlx5_priv *priv = dev->data->dev_private;
        struct mlx5_ibv_shared *sh = priv->sh;
+       struct mlx5_flow_dv_tag_resource *tag;
 
-       MLX5_ASSERT(tag);
+       tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG], tag_idx);
+       if (!tag)
+               return 0;
        DRV_LOG(DEBUG, "port %u tag %p: refcnt %d--",
                dev->data->port_id, (void *)tag,
                rte_atomic32_read(&tag->refcnt));
@@ -7204,7 +7222,7 @@ flow_dv_tag_release(struct rte_eth_dev *dev,
                mlx5_hlist_remove(sh->tag_table, &tag->entry);
                DRV_LOG(DEBUG, "port %u tag %p: removed",
                        dev->data->port_id, (void *)tag);
-               rte_free(tag);
+               mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_TAG], tag_idx);
                return 0;
        }
        return 1;
@@ -7310,18 +7328,20 @@ flow_dv_translate_item_tx_queue(struct rte_eth_dev *dev,
  *
  * @param[in] dev_flow
  *   Pointer to the mlx5_flow.
+ * @param[in] rss_desc
+ *   Pointer to the mlx5_flow_rss_desc.
  */
 static void
-flow_dv_hashfields_set(struct mlx5_flow *dev_flow)
+flow_dv_hashfields_set(struct mlx5_flow *dev_flow,
+                      struct mlx5_flow_rss_desc *rss_desc)
 {
-       struct rte_flow *flow = dev_flow->flow;
        uint64_t items = dev_flow->handle->layers;
        int rss_inner = 0;
-       uint64_t rss_types = rte_eth_rss_hf_refine(flow->rss.types);
+       uint64_t rss_types = rte_eth_rss_hf_refine(rss_desc->types);
 
        dev_flow->hash_fields = 0;
 #ifdef HAVE_IBV_DEVICE_TUNNEL_SUPPORT
-       if (flow->rss.level >= 2) {
+       if (rss_desc->level >= 2) {
                dev_flow->hash_fields |= IBV_RX_HASH_INNER;
                rss_inner = 1;
        }
@@ -7406,6 +7426,9 @@ __flow_dv_translate(struct rte_eth_dev *dev,
        struct mlx5_dev_config *dev_conf = &priv->config;
        struct rte_flow *flow = dev_flow->flow;
        struct mlx5_flow_handle *handle = dev_flow->handle;
+       struct mlx5_flow_rss_desc *rss_desc = &((struct mlx5_flow_rss_desc *)
+                                             priv->rss_desc)
+                                             [!!priv->flow_nested_idx];
        uint64_t item_flags = 0;
        uint64_t last_item = 0;
        uint64_t action_flags = 0;
@@ -7461,6 +7484,7 @@ __flow_dv_translate(struct rte_eth_dev *dev,
                struct mlx5_flow_dv_port_id_action_resource port_id_resource;
                int action_type = actions->type;
                const struct rte_flow_action *found_action = NULL;
+               struct mlx5_flow_meter *fm = NULL;
 
                switch (action_type) {
                case RTE_FLOW_ACTION_TYPE_VOID:
@@ -7469,16 +7493,20 @@ __flow_dv_translate(struct rte_eth_dev *dev,
                        if (flow_dv_translate_action_port_id(dev, action,
                                                             &port_id, error))
                                return -rte_errno;
+                       memset(&port_id_resource, 0, sizeof(port_id_resource));
                        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;
+                       MLX5_ASSERT(!handle->rix_port_id_action);
                        dev_flow->dv.actions[actions_n++] =
-                                       handle->dvh.port_id_action->action;
+                                       dev_flow->dv.port_id_action->action;
                        action_flags |= MLX5_FLOW_ACTION_PORT_ID;
+                       dev_flow->handle->fate_action = MLX5_FLOW_FATE_PORT_ID;
                        break;
                case RTE_FLOW_ACTION_TYPE_FLAG:
                        action_flags |= MLX5_FLOW_ACTION_FLAG;
+                       dev_flow->handle->mark = 1;
                        if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
                                struct rte_flow_action_mark mark = {
                                        .id = MLX5_FLOW_MARK_DEFAULT,
@@ -7497,15 +7525,17 @@ __flow_dv_translate(struct rte_eth_dev *dev,
                         * right now. So the pointer to the tag resource must be
                         * zero before the register process.
                         */
-                       MLX5_ASSERT(!handle->dvh.tag_resource);
+                       MLX5_ASSERT(!handle->dvh.rix_tag);
                        if (flow_dv_tag_resource_register(dev, tag_be,
                                                          dev_flow, error))
                                return -rte_errno;
+                       MLX5_ASSERT(dev_flow->dv.tag_resource);
                        dev_flow->dv.actions[actions_n++] =
-                                       handle->dvh.tag_resource->action;
+                                       dev_flow->dv.tag_resource->action;
                        break;
                case RTE_FLOW_ACTION_TYPE_MARK:
                        action_flags |= MLX5_FLOW_ACTION_MARK;
+                       dev_flow->handle->mark = 1;
                        if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
                                const struct rte_flow_action_mark *mark =
                                        (const struct rte_flow_action_mark *)
@@ -7524,12 +7554,13 @@ __flow_dv_translate(struct rte_eth_dev *dev,
                        tag_be = mlx5_flow_mark_set
                              (((const struct rte_flow_action_mark *)
                               (actions->conf))->id);
-                       MLX5_ASSERT(!handle->dvh.tag_resource);
+                       MLX5_ASSERT(!handle->dvh.rix_tag);
                        if (flow_dv_tag_resource_register(dev, tag_be,
                                                          dev_flow, error))
                                return -rte_errno;
+                       MLX5_ASSERT(dev_flow->dv.tag_resource);
                        dev_flow->dv.actions[actions_n++] =
-                                       handle->dvh.tag_resource->action;
+                                       dev_flow->dv.tag_resource->action;
                        break;
                case RTE_FLOW_ACTION_TYPE_SET_META:
                        if (flow_dv_convert_action_set_meta
@@ -7549,29 +7580,29 @@ __flow_dv_translate(struct rte_eth_dev *dev,
                        break;
                case RTE_FLOW_ACTION_TYPE_DROP:
                        action_flags |= MLX5_FLOW_ACTION_DROP;
+                       dev_flow->handle->fate_action = MLX5_FLOW_FATE_DROP;
                        break;
                case RTE_FLOW_ACTION_TYPE_QUEUE:
-                       MLX5_ASSERT(flow->rss.queue);
                        queue = actions->conf;
-                       flow->rss.queue_num = 1;
-                       (*flow->rss.queue)[0] = queue->index;
+                       rss_desc->queue_num = 1;
+                       rss_desc->queue[0] = queue->index;
                        action_flags |= MLX5_FLOW_ACTION_QUEUE;
+                       dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;
                        break;
                case RTE_FLOW_ACTION_TYPE_RSS:
-                       MLX5_ASSERT(flow->rss.queue);
                        rss = actions->conf;
-                       if (flow->rss.queue)
-                               memcpy((*flow->rss.queue), rss->queue,
-                                      rss->queue_num * sizeof(uint16_t));
-                       flow->rss.queue_num = rss->queue_num;
+                       memcpy(rss_desc->queue, rss->queue,
+                              rss->queue_num * sizeof(uint16_t));
+                       rss_desc->queue_num = rss->queue_num;
                        /* NULL RSS key indicates default RSS key. */
                        rss_key = !rss->key ? rss_hash_default_key : rss->key;
-                       memcpy(flow->rss.key, rss_key, MLX5_RSS_HASH_KEY_LEN);
+                       memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
                        /*
                         * rss->level and rss.types should be set in advance
                         * when expanding items for RSS.
                         */
                        action_flags |= MLX5_FLOW_ACTION_RSS;
+                       dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;
                        break;
                case RTE_FLOW_ACTION_TYPE_COUNT:
                        if (!dev_conf->devx) {
@@ -7610,7 +7641,9 @@ cnt_err:
                        action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN;
                        break;
                case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
-                       flow_dev_get_vlan_info_from_items(items, &vlan);
+                       if (!(action_flags &
+                             MLX5_FLOW_ACTION_OF_SET_VLAN_VID))
+                               flow_dev_get_vlan_info_from_items(items, &vlan);
                        vlan.eth_proto = rte_be_to_cpu_16
                             ((((const struct rte_flow_action_of_push_vlan *)
                                                   actions->conf)->ethertype));
@@ -7628,7 +7661,7 @@ cnt_err:
                                            (dev, attr, &vlan, dev_flow, error))
                                return -rte_errno;
                        dev_flow->dv.actions[actions_n++] =
-                                       handle->dvh.push_vlan_res->action;
+                                       dev_flow->dv.push_vlan_res->action;
                        action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN;
                        break;
                case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
@@ -7655,7 +7688,7 @@ cnt_err:
                                                           error))
                                return -rte_errno;
                        dev_flow->dv.actions[actions_n++] =
-                                       handle->dvh.encap_decap->verbs_action;
+                                       dev_flow->dv.encap_decap->verbs_action;
                        action_flags |= MLX5_FLOW_ACTION_ENCAP;
                        break;
                case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
@@ -7665,7 +7698,7 @@ cnt_err:
                                                           error))
                                return -rte_errno;
                        dev_flow->dv.actions[actions_n++] =
-                                       handle->dvh.encap_decap->verbs_action;
+                                       dev_flow->dv.encap_decap->verbs_action;
                        action_flags |= MLX5_FLOW_ACTION_DECAP;
                        break;
                case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
@@ -7675,7 +7708,7 @@ cnt_err:
                                        (dev, actions, dev_flow, attr, error))
                                        return -rte_errno;
                                dev_flow->dv.actions[actions_n++] =
-                                       handle->dvh.encap_decap->verbs_action;
+                                       dev_flow->dv.encap_decap->verbs_action;
                        } else {
                                /* Handle encap without preceding decap. */
                                if (flow_dv_create_action_l2_encap
@@ -7683,7 +7716,7 @@ cnt_err:
                                     error))
                                        return -rte_errno;
                                dev_flow->dv.actions[actions_n++] =
-                                       handle->dvh.encap_decap->verbs_action;
+                                       dev_flow->dv.encap_decap->verbs_action;
                        }
                        action_flags |= MLX5_FLOW_ACTION_ENCAP;
                        break;
@@ -7695,7 +7728,7 @@ cnt_err:
                                    (dev, dev_flow, attr->transfer, error))
                                        return -rte_errno;
                                dev_flow->dv.actions[actions_n++] =
-                                       handle->dvh.encap_decap->verbs_action;
+                                       dev_flow->dv.encap_decap->verbs_action;
                        }
                        /* If decap is followed by encap, handle it at encap. */
                        action_flags |= MLX5_FLOW_ACTION_DECAP;
@@ -7727,8 +7760,9 @@ cnt_err:
                                                 "cannot create jump action.");
                        }
                        dev_flow->dv.actions[actions_n++] =
-                                       handle->dvh.jump->action;
+                                       dev_flow->dv.jump->action;
                        action_flags |= MLX5_FLOW_ACTION_JUMP;
+                       dev_flow->handle->fate_action = MLX5_FLOW_FATE_JUMP;
                        break;
                case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
                case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
@@ -7824,20 +7858,31 @@ cnt_err:
                case RTE_FLOW_ACTION_TYPE_METER:
                        mtr = actions->conf;
                        if (!flow->meter) {
-                               flow->meter = mlx5_flow_meter_attach(priv,
-                                                       mtr->mtr_id, attr,
-                                                       error);
-                               if (!flow->meter)
+                               fm = mlx5_flow_meter_attach(priv, mtr->mtr_id,
+                                                           attr, error);
+                               if (!fm)
                                        return rte_flow_error_set(error,
                                                rte_errno,
                                                RTE_FLOW_ERROR_TYPE_ACTION,
                                                NULL,
                                                "meter not found "
                                                "or invalid parameters");
+                               flow->meter = fm->idx;
                        }
                        /* Set the meter action. */
+                       if (!fm) {
+                               fm = mlx5_ipool_get(priv->sh->ipool
+                                               [MLX5_IPOOL_MTR], flow->meter);
+                               if (!fm)
+                                       return rte_flow_error_set(error,
+                                               rte_errno,
+                                               RTE_FLOW_ERROR_TYPE_ACTION,
+                                               NULL,
+                                               "meter not found "
+                                               "or invalid parameters");
+                       }
                        dev_flow->dv.actions[actions_n++] =
-                               flow->meter->mfts->meter_action;
+                               fm->mfts->meter_action;
                        action_flags |= MLX5_FLOW_ACTION_METER;
                        break;
                case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
@@ -7871,7 +7916,7 @@ cnt_err:
                        modify_action_position = actions_n++;
        }
        dev_flow->dv.actions_n = actions_n;
-       handle->act_flags = action_flags;
+       dev_flow->act_flags = action_flags;
        for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
                int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
                int item_type = items->type;
@@ -7962,7 +8007,7 @@ cnt_err:
                case RTE_FLOW_ITEM_TYPE_GRE:
                        flow_dv_translate_item_gre(match_mask, match_value,
                                                   items, tunnel);
-                       matcher.priority = flow->rss.level >= 2 ?
+                       matcher.priority = rss_desc->level >= 2 ?
                                    MLX5_PRIORITY_MAP_L2 : MLX5_PRIORITY_MAP_L4;
                        last_item = MLX5_FLOW_LAYER_GRE;
                        break;
@@ -7974,14 +8019,14 @@ cnt_err:
                case RTE_FLOW_ITEM_TYPE_NVGRE:
                        flow_dv_translate_item_nvgre(match_mask, match_value,
                                                     items, tunnel);
-                       matcher.priority = flow->rss.level >= 2 ?
+                       matcher.priority = rss_desc->level >= 2 ?
                                    MLX5_PRIORITY_MAP_L2 : MLX5_PRIORITY_MAP_L4;
                        last_item = MLX5_FLOW_LAYER_GRE;
                        break;
                case RTE_FLOW_ITEM_TYPE_VXLAN:
                        flow_dv_translate_item_vxlan(match_mask, match_value,
                                                     items, tunnel);
-                       matcher.priority = flow->rss.level >= 2 ?
+                       matcher.priority = rss_desc->level >= 2 ?
                                    MLX5_PRIORITY_MAP_L2 : MLX5_PRIORITY_MAP_L4;
                        last_item = MLX5_FLOW_LAYER_VXLAN;
                        break;
@@ -7989,21 +8034,21 @@ cnt_err:
                        flow_dv_translate_item_vxlan_gpe(match_mask,
                                                         match_value, items,
                                                         tunnel);
-                       matcher.priority = flow->rss.level >= 2 ?
+                       matcher.priority = rss_desc->level >= 2 ?
                                    MLX5_PRIORITY_MAP_L2 : MLX5_PRIORITY_MAP_L4;
                        last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
                        break;
                case RTE_FLOW_ITEM_TYPE_GENEVE:
                        flow_dv_translate_item_geneve(match_mask, match_value,
                                                      items, tunnel);
-                       matcher.priority = flow->rss.level >= 2 ?
+                       matcher.priority = rss_desc->level >= 2 ?
                                    MLX5_PRIORITY_MAP_L2 : MLX5_PRIORITY_MAP_L4;
                        last_item = MLX5_FLOW_LAYER_GENEVE;
                        break;
                case RTE_FLOW_ITEM_TYPE_MPLS:
                        flow_dv_translate_item_mpls(match_mask, match_value,
                                                    items, last_item, tunnel);
-                       matcher.priority = flow->rss.level >= 2 ?
+                       matcher.priority = rss_desc->level >= 2 ?
                                    MLX5_PRIORITY_MAP_L2 : MLX5_PRIORITY_MAP_L4;
                        last_item = MLX5_FLOW_LAYER_MPLS;
                        break;
@@ -8046,7 +8091,7 @@ cnt_err:
                case RTE_FLOW_ITEM_TYPE_GTP:
                        flow_dv_translate_item_gtp(match_mask, match_value,
                                                   items, tunnel);
-                       matcher.priority = flow->rss.level >= 2 ?
+                       matcher.priority = rss_desc->level >= 2 ?
                                    MLX5_PRIORITY_MAP_L2 : MLX5_PRIORITY_MAP_L4;
                        last_item = MLX5_FLOW_LAYER_GTP;
                        break;
@@ -8078,7 +8123,7 @@ cnt_err:
         */
        handle->layers |= item_flags;
        if (action_flags & MLX5_FLOW_ACTION_RSS)
-               flow_dv_hashfields_set(dev_flow);
+               flow_dv_hashfields_set(dev_flow, rss_desc);
        /* Register matcher. */
        matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
                                    matcher.mask.size);
@@ -8116,22 +8161,24 @@ __flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
        struct mlx5_flow_handle_dv *dv_h;
        struct mlx5_flow *dev_flow;
        struct mlx5_priv *priv = dev->data->dev_private;
+       uint32_t handle_idx;
        int n;
        int err;
        int idx;
 
-       for (idx = priv->flow_idx - 1; idx >= 0; idx--) {
+       for (idx = priv->flow_idx - 1; idx >= priv->flow_nested_idx; idx--) {
                dev_flow = &((struct mlx5_flow *)priv->inter_flows)[idx];
                dv = &dev_flow->dv;
                dh = dev_flow->handle;
                dv_h = &dh->dvh;
                n = dv->actions_n;
-               if (dh->act_flags & MLX5_FLOW_ACTION_DROP) {
+               if (dh->fate_action == MLX5_FLOW_FATE_DROP) {
                        if (dv->transfer) {
                                dv->actions[n++] = priv->sh->esw_drop_action;
                        } else {
-                               dh->hrxq = mlx5_hrxq_drop_new(dev);
-                               if (!dh->hrxq) {
+                               struct mlx5_hrxq *drop_hrxq;
+                               drop_hrxq = mlx5_hrxq_drop_new(dev);
+                               if (!drop_hrxq) {
                                        rte_flow_error_set
                                                (error, errno,
                                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
@@ -8139,28 +8186,40 @@ __flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
                                                 "cannot get drop hash queue");
                                        goto error;
                                }
-                               dv->actions[n++] = dh->hrxq->action;
+                               /*
+                                * Drop queues will be released by the specify
+                                * mlx5_hrxq_drop_release() function. Assign
+                                * the special index to hrxq to mark the queue
+                                * has been allocated.
+                                */
+                               dh->rix_hrxq = UINT32_MAX;
+                               dv->actions[n++] = drop_hrxq->action;
                        }
-               } else if (dh->act_flags &
-                          (MLX5_FLOW_ACTION_QUEUE | MLX5_FLOW_ACTION_RSS)) {
+               } else if (dh->fate_action == MLX5_FLOW_FATE_QUEUE) {
                        struct mlx5_hrxq *hrxq;
-
-                       MLX5_ASSERT(flow->rss.queue);
-                       hrxq = mlx5_hrxq_get(dev, flow->rss.key,
-                                            MLX5_RSS_HASH_KEY_LEN,
-                                            dev_flow->hash_fields,
-                                            (*flow->rss.queue),
-                                            flow->rss.queue_num);
-                       if (!hrxq) {
-                               hrxq = mlx5_hrxq_new
-                                       (dev, flow->rss.key,
-                                        MLX5_RSS_HASH_KEY_LEN,
-                                        dev_flow->hash_fields,
-                                        (*flow->rss.queue),
-                                        flow->rss.queue_num,
-                                        !!(dh->layers &
-                                           MLX5_FLOW_LAYER_TUNNEL));
+                       uint32_t hrxq_idx;
+                       struct mlx5_flow_rss_desc *rss_desc =
+                               &((struct mlx5_flow_rss_desc *)priv->rss_desc)
+                               [!!priv->flow_nested_idx];
+
+                       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));
                        }
+                       hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],
+                                             hrxq_idx);
                        if (!hrxq) {
                                rte_flow_error_set
                                        (error, rte_errno,
@@ -8168,8 +8227,8 @@ __flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
                                         "cannot get hash queue");
                                goto error;
                        }
-                       dh->hrxq = hrxq;
-                       dv->actions[n++] = dh->hrxq->action;
+                       dh->rix_hrxq = hrxq_idx;
+                       dv->actions[n++] = hrxq->action;
                }
                dh->ib_flow =
                        mlx5_glue->dv_create_flow(dv_h->matcher->matcher_object,
@@ -8196,13 +8255,17 @@ __flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
        return 0;
 error:
        err = rte_errno; /* Save rte_errno before cleanup. */
-       LIST_FOREACH(dh, &flow->dev_handles, next) {
-               if (dh->hrxq) {
-                       if (dh->act_flags & MLX5_FLOW_ACTION_DROP)
+       SILIST_FOREACH(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], flow->dev_handles,
+                      handle_idx, dh, next) {
+               /* hrxq is union, don't clear it if the flag is not set. */
+               if (dh->rix_hrxq) {
+                       if (dh->fate_action == MLX5_FLOW_FATE_DROP) {
                                mlx5_hrxq_drop_release(dev);
-                       else
-                               mlx5_hrxq_release(dev, dh->hrxq);
-                       dh->hrxq = NULL;
+                               dh->rix_hrxq = 0;
+                       } else if (dh->fate_action == MLX5_FLOW_FATE_QUEUE) {
+                               mlx5_hrxq_release(dev, dh->rix_hrxq);
+                               dh->rix_hrxq = 0;
+                       }
                }
                if (dh->vf_vlan.tag && dh->vf_vlan.created)
                        mlx5_vlan_vmwa_release(dev, &dh->vf_vlan);
@@ -8249,6 +8312,8 @@ flow_dv_matcher_release(struct rte_eth_dev *dev,
 /**
  * Release an encap/decap resource.
  *
+ * @param dev
+ *   Pointer to Ethernet device.
  * @param handle
  *   Pointer to mlx5_flow_handle.
  *
@@ -8256,11 +8321,17 @@ flow_dv_matcher_release(struct rte_eth_dev *dev,
  *   1 while a reference on it exists, 0 when freed.
  */
 static int
-flow_dv_encap_decap_resource_release(struct mlx5_flow_handle *handle)
+flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev,
+                                    struct mlx5_flow_handle *handle)
 {
-       struct mlx5_flow_dv_encap_decap_resource *cache_resource =
-                                               handle->dvh.encap_decap;
+       struct mlx5_priv *priv = dev->data->dev_private;
+       uint32_t idx = handle->dvh.rix_encap_decap;
+       struct mlx5_flow_dv_encap_decap_resource *cache_resource;
 
+       cache_resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DECAP_ENCAP],
+                        idx);
+       if (!cache_resource)
+               return 0;
        MLX5_ASSERT(cache_resource->verbs_action);
        DRV_LOG(DEBUG, "encap/decap resource %p: refcnt %d--",
                (void *)cache_resource,
@@ -8268,8 +8339,10 @@ flow_dv_encap_decap_resource_release(struct mlx5_flow_handle *handle)
        if (rte_atomic32_dec_and_test(&cache_resource->refcnt)) {
                claim_zero(mlx5_glue->destroy_flow_action
                                (cache_resource->verbs_action));
-               LIST_REMOVE(cache_resource, next);
-               rte_free(cache_resource);
+               ILIST_REMOVE(priv->sh->ipool[MLX5_IPOOL_DECAP_ENCAP],
+                            &priv->sh->encaps_decaps, idx,
+                            cache_resource, next);
+               mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_DECAP_ENCAP], idx);
                DRV_LOG(DEBUG, "encap/decap resource %p: removed",
                        (void *)cache_resource);
                return 0;
@@ -8292,12 +8365,15 @@ static int
 flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev,
                                  struct mlx5_flow_handle *handle)
 {
-       struct mlx5_flow_dv_jump_tbl_resource *cache_resource =
-                                                       handle->dvh.jump;
-       struct mlx5_flow_tbl_data_entry *tbl_data =
-                       container_of(cache_resource,
-                                    struct mlx5_flow_tbl_data_entry, jump);
+       struct mlx5_priv *priv = dev->data->dev_private;
+       struct mlx5_flow_dv_jump_tbl_resource *cache_resource;
+       struct mlx5_flow_tbl_data_entry *tbl_data;
 
+       tbl_data = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_JUMP],
+                            handle->rix_jump);
+       if (!tbl_data)
+               return 0;
+       cache_resource = &tbl_data->jump;
        MLX5_ASSERT(cache_resource->action);
        DRV_LOG(DEBUG, "jump table resource %p: refcnt %d--",
                (void *)cache_resource,
@@ -8348,6 +8424,8 @@ flow_dv_modify_hdr_resource_release(struct mlx5_flow_handle *handle)
 /**
  * Release port ID action resource.
  *
+ * @param dev
+ *   Pointer to Ethernet device.
  * @param handle
  *   Pointer to mlx5_flow_handle.
  *
@@ -8355,11 +8433,17 @@ flow_dv_modify_hdr_resource_release(struct mlx5_flow_handle *handle)
  *   1 while a reference on it exists, 0 when freed.
  */
 static int
-flow_dv_port_id_action_resource_release(struct mlx5_flow_handle *handle)
+flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev,
+                                       struct mlx5_flow_handle *handle)
 {
-       struct mlx5_flow_dv_port_id_action_resource *cache_resource =
-                                               handle->dvh.port_id_action;
+       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;
 
+       cache_resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PORT_ID],
+                                       idx);
+       if (!cache_resource)
+               return 0;
        MLX5_ASSERT(cache_resource->action);
        DRV_LOG(DEBUG, "port ID action resource %p: refcnt %d--",
                (void *)cache_resource,
@@ -8367,8 +8451,10 @@ flow_dv_port_id_action_resource_release(struct mlx5_flow_handle *handle)
        if (rte_atomic32_dec_and_test(&cache_resource->refcnt)) {
                claim_zero(mlx5_glue->destroy_flow_action
                                (cache_resource->action));
-               LIST_REMOVE(cache_resource, next);
-               rte_free(cache_resource);
+               ILIST_REMOVE(priv->sh->ipool[MLX5_IPOOL_PORT_ID],
+                            &priv->sh->port_id_action_list, idx,
+                            cache_resource, next);
+               mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_PORT_ID], idx);
                DRV_LOG(DEBUG, "port id action resource %p: removed",
                        (void *)cache_resource);
                return 0;
@@ -8379,6 +8465,8 @@ flow_dv_port_id_action_resource_release(struct mlx5_flow_handle *handle)
 /**
  * Release push vlan action resource.
  *
+ * @param dev
+ *   Pointer to Ethernet device.
  * @param handle
  *   Pointer to mlx5_flow_handle.
  *
@@ -8386,11 +8474,17 @@ flow_dv_port_id_action_resource_release(struct mlx5_flow_handle *handle)
  *   1 while a reference on it exists, 0 when freed.
  */
 static int
-flow_dv_push_vlan_action_resource_release(struct mlx5_flow_handle *handle)
+flow_dv_push_vlan_action_resource_release(struct rte_eth_dev *dev,
+                                         struct mlx5_flow_handle *handle)
 {
-       struct mlx5_flow_dv_push_vlan_action_resource *cache_resource =
-                                               handle->dvh.push_vlan_res;
+       struct mlx5_priv *priv = dev->data->dev_private;
+       uint32_t idx = handle->dvh.rix_push_vlan;
+       struct mlx5_flow_dv_push_vlan_action_resource *cache_resource;
 
+       cache_resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PUSH_VLAN],
+                                       idx);
+       if (!cache_resource)
+               return 0;
        MLX5_ASSERT(cache_resource->action);
        DRV_LOG(DEBUG, "push VLAN action resource %p: refcnt %d--",
                (void *)cache_resource,
@@ -8398,8 +8492,10 @@ flow_dv_push_vlan_action_resource_release(struct mlx5_flow_handle *handle)
        if (rte_atomic32_dec_and_test(&cache_resource->refcnt)) {
                claim_zero(mlx5_glue->destroy_flow_action
                                (cache_resource->action));
-               LIST_REMOVE(cache_resource, next);
-               rte_free(cache_resource);
+               ILIST_REMOVE(priv->sh->ipool[MLX5_IPOOL_PUSH_VLAN],
+                            &priv->sh->push_vlan_action_list, idx,
+                            cache_resource, next);
+               mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_PUSH_VLAN], idx);
                DRV_LOG(DEBUG, "push vlan action resource %p: removed",
                        (void *)cache_resource);
                return 0;
@@ -8407,6 +8503,33 @@ flow_dv_push_vlan_action_resource_release(struct mlx5_flow_handle *handle)
        return 1;
 }
 
+/**
+ * Release the fate resource.
+ *
+ * @param dev
+ *   Pointer to Ethernet device.
+ * @param handle
+ *   Pointer to mlx5_flow_handle.
+ */
+static void
+flow_dv_fate_resource_release(struct rte_eth_dev *dev,
+                              struct mlx5_flow_handle *handle)
+{
+       if (!handle->rix_fate)
+               return;
+       if (handle->fate_action == MLX5_FLOW_FATE_DROP)
+               mlx5_hrxq_drop_release(dev);
+       else if (handle->fate_action == MLX5_FLOW_FATE_QUEUE)
+               mlx5_hrxq_release(dev, handle->rix_hrxq);
+       else if (handle->fate_action == MLX5_FLOW_FATE_JUMP)
+               flow_dv_jump_tbl_resource_release(dev, handle);
+       else if (handle->fate_action == MLX5_FLOW_FATE_PORT_ID)
+               flow_dv_port_id_action_resource_release(dev, handle);
+       else
+               DRV_LOG(DEBUG, "Incorrect fate action:%d", handle->fate_action);
+       handle->rix_fate = 0;
+}
+
 /**
  * Remove the flow from the NIC but keeps it in memory.
  * Lock free, (mutex should be acquired by caller).
@@ -8420,23 +8543,27 @@ static void
 __flow_dv_remove(struct rte_eth_dev *dev, struct rte_flow *flow)
 {
        struct mlx5_flow_handle *dh;
+       uint32_t handle_idx;
+       struct mlx5_priv *priv = dev->data->dev_private;
 
        if (!flow)
                return;
-       LIST_FOREACH(dh, &flow->dev_handles, next) {
+       handle_idx = flow->dev_handles;
+       while (handle_idx) {
+               dh = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
+                                   handle_idx);
+               if (!dh)
+                       return;
                if (dh->ib_flow) {
                        claim_zero(mlx5_glue->dv_destroy_flow(dh->ib_flow));
                        dh->ib_flow = NULL;
                }
-               if (dh->hrxq) {
-                       if (dh->act_flags & MLX5_FLOW_ACTION_DROP)
-                               mlx5_hrxq_drop_release(dev);
-                       else
-                               mlx5_hrxq_release(dev, dh->hrxq);
-                       dh->hrxq = NULL;
-               }
+               if (dh->fate_action == MLX5_FLOW_FATE_DROP ||
+                   dh->fate_action == MLX5_FLOW_FATE_QUEUE)
+                       flow_dv_fate_resource_release(dev, dh);
                if (dh->vf_vlan.tag && dh->vf_vlan.created)
                        mlx5_vlan_vmwa_release(dev, &dh->vf_vlan);
+               handle_idx = dh->next.next;
        }
 }
 
@@ -8453,6 +8580,7 @@ static void
 __flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
 {
        struct mlx5_flow_handle *dev_handle;
+       struct mlx5_priv *priv = dev->data->dev_private;
 
        if (!flow)
                return;
@@ -8462,28 +8590,37 @@ __flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
                flow->counter = 0;
        }
        if (flow->meter) {
-               mlx5_flow_meter_detach(flow->meter);
-               flow->meter = NULL;
+               struct mlx5_flow_meter *fm;
+
+               fm = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR],
+                                   flow->meter);
+               if (fm)
+                       mlx5_flow_meter_detach(fm);
+               flow->meter = 0;
        }
-       while (!LIST_EMPTY(&flow->dev_handles)) {
-               dev_handle = LIST_FIRST(&flow->dev_handles);
-               LIST_REMOVE(dev_handle, next);
+       while (flow->dev_handles) {
+               uint32_t tmp_idx = flow->dev_handles;
+
+               dev_handle = mlx5_ipool_get(priv->sh->ipool
+                                           [MLX5_IPOOL_MLX5_FLOW], tmp_idx);
+               if (!dev_handle)
+                       return;
+               flow->dev_handles = dev_handle->next.next;
                if (dev_handle->dvh.matcher)
                        flow_dv_matcher_release(dev, dev_handle);
-               if (dev_handle->dvh.encap_decap)
-                       flow_dv_encap_decap_resource_release(dev_handle);
+               if (dev_handle->dvh.rix_encap_decap)
+                       flow_dv_encap_decap_resource_release(dev, dev_handle);
                if (dev_handle->dvh.modify_hdr)
                        flow_dv_modify_hdr_resource_release(dev_handle);
-               if (dev_handle->dvh.jump)
-                       flow_dv_jump_tbl_resource_release(dev, dev_handle);
-               if (dev_handle->dvh.port_id_action)
-                       flow_dv_port_id_action_resource_release(dev_handle);
-               if (dev_handle->dvh.push_vlan_res)
-                       flow_dv_push_vlan_action_resource_release(dev_handle);
-               if (dev_handle->dvh.tag_resource)
+               if (dev_handle->dvh.rix_push_vlan)
+                       flow_dv_push_vlan_action_resource_release(dev,
+                                                                 dev_handle);
+               if (dev_handle->dvh.rix_tag)
                        flow_dv_tag_release(dev,
-                                           dev_handle->dvh.tag_resource);
-               rte_free(dev_handle);
+                                           dev_handle->dvh.rix_tag);
+               flow_dv_fate_resource_release(dev, dev_handle);
+               mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
+                          tmp_idx);
        }
 }
 
@@ -8613,8 +8750,9 @@ flow_dv_destroy_mtr_tbl(struct rte_eth_dev *dev,
                claim_zero(mlx5_glue->dv_destroy_flow_matcher
                          (mtd->egress.any_matcher));
        if (mtd->egress.tbl)
-               claim_zero(flow_dv_tbl_resource_release(dev,
-                                                       mtd->egress.tbl));
+               flow_dv_tbl_resource_release(dev, mtd->egress.tbl);
+       if (mtd->egress.sfx_tbl)
+               flow_dv_tbl_resource_release(dev, mtd->egress.sfx_tbl);
        if (mtd->ingress.color_matcher)
                claim_zero(mlx5_glue->dv_destroy_flow_matcher
                          (mtd->ingress.color_matcher));
@@ -8622,8 +8760,9 @@ flow_dv_destroy_mtr_tbl(struct rte_eth_dev *dev,
                claim_zero(mlx5_glue->dv_destroy_flow_matcher
                          (mtd->ingress.any_matcher));
        if (mtd->ingress.tbl)
-               claim_zero(flow_dv_tbl_resource_release(dev,
-                                                       mtd->ingress.tbl));
+               flow_dv_tbl_resource_release(dev, mtd->ingress.tbl);
+       if (mtd->ingress.sfx_tbl)
+               flow_dv_tbl_resource_release(dev, mtd->ingress.sfx_tbl);
        if (mtd->transfer.color_matcher)
                claim_zero(mlx5_glue->dv_destroy_flow_matcher
                          (mtd->transfer.color_matcher));
@@ -8631,8 +8770,9 @@ flow_dv_destroy_mtr_tbl(struct rte_eth_dev *dev,
                claim_zero(mlx5_glue->dv_destroy_flow_matcher
                          (mtd->transfer.any_matcher));
        if (mtd->transfer.tbl)
-               claim_zero(flow_dv_tbl_resource_release(dev,
-                                                       mtd->transfer.tbl));
+               flow_dv_tbl_resource_release(dev, mtd->transfer.tbl);
+       if (mtd->transfer.sfx_tbl)
+               flow_dv_tbl_resource_release(dev, mtd->transfer.sfx_tbl);
        if (mtd->drop_actn)
                claim_zero(mlx5_glue->destroy_flow_action(mtd->drop_actn));
        rte_free(mtd);
@@ -8680,31 +8820,16 @@ flow_dv_prepare_mtr_tables(struct rte_eth_dev *dev,
                .match_mask = (void *)&mask,
        };
        void *actions[METER_ACTIONS];
-       struct mlx5_flow_tbl_resource **sfx_tbl;
        struct mlx5_meter_domain_info *dtb;
        struct rte_flow_error error;
        int i = 0;
 
-       if (transfer) {
-               sfx_tbl = &sh->fdb_mtr_sfx_tbl;
+       if (transfer)
                dtb = &mtb->transfer;
-       } else if (egress) {
-               sfx_tbl = &sh->tx_mtr_sfx_tbl;
+       else if (egress)
                dtb = &mtb->egress;
-       } else {
-               sfx_tbl = &sh->rx_mtr_sfx_tbl;
+       else
                dtb = &mtb->ingress;
-       }
-       /* If the suffix table in missing, create it. */
-       if (!(*sfx_tbl)) {
-               *sfx_tbl = flow_dv_tbl_resource_get(dev,
-                                               MLX5_FLOW_TABLE_LEVEL_SUFFIX,
-                                               egress, transfer, &error);
-               if (!(*sfx_tbl)) {
-                       DRV_LOG(ERR, "Failed to create meter suffix table.");
-                       return -1;
-               }
-       }
        /* Create the meter table with METER level. */
        dtb->tbl = flow_dv_tbl_resource_get(dev, MLX5_FLOW_TABLE_LEVEL_METER,
                                            egress, transfer, &error);
@@ -8712,6 +8837,14 @@ flow_dv_prepare_mtr_tables(struct rte_eth_dev *dev,
                DRV_LOG(ERR, "Failed to create meter policer table.");
                return -1;
        }
+       /* Create the meter suffix table with SUFFIX level. */
+       dtb->sfx_tbl = flow_dv_tbl_resource_get(dev,
+                                           MLX5_FLOW_TABLE_LEVEL_SUFFIX,
+                                           egress, transfer, &error);
+       if (!dtb->sfx_tbl) {
+               DRV_LOG(ERR, "Failed to create meter suffix table.");
+               return -1;
+       }
        /* Create matchers, Any and Color. */
        dv_attr.priority = 3;
        dv_attr.match_criteria_enable = 0;
@@ -8885,8 +9018,6 @@ flow_dv_destroy_policer_rules(struct rte_eth_dev *dev __rte_unused,
  *   Pointer to flow meter structure.
  * @param[in] mtb
  *   Pointer to DV meter table set.
- * @param[in] sfx_tb
- *   Pointer to suffix table.
  * @param[in] mtr_reg_c
  *   Color match REG_C.
  *
@@ -8896,7 +9027,6 @@ flow_dv_destroy_policer_rules(struct rte_eth_dev *dev __rte_unused,
 static int
 flow_dv_create_policer_forward_rule(struct mlx5_flow_meter *fm,
                                    struct mlx5_meter_domain_info *dtb,
-                                   struct mlx5_flow_tbl_resource *sfx_tb,
                                    uint8_t mtr_reg_c)
 {
        struct mlx5_flow_dv_match_params matcher = {
@@ -8910,12 +9040,10 @@ flow_dv_create_policer_forward_rule(struct mlx5_flow_meter *fm,
        int i;
 
        /* Create jump action. */
-       if (!sfx_tb)
-               return -1;
        if (!dtb->jump_actn)
                dtb->jump_actn =
                        mlx5_glue->dr_create_flow_action_dest_flow_tbl
-                                                       (sfx_tb->obj);
+                                                       (dtb->sfx_tbl->obj);
        if (!dtb->jump_actn) {
                DRV_LOG(ERR, "Failed to create policer jump action.");
                goto error;
@@ -8927,7 +9055,7 @@ flow_dv_create_policer_forward_rule(struct mlx5_flow_meter *fm,
                                       rte_col_2_mlx5_col(i), UINT8_MAX);
                if (mtb->count_actns[i])
                        actions[j++] = mtb->count_actns[i];
-               if (fm->params.action[i] == MTR_POLICER_ACTION_DROP)
+               if (fm->action[i] == MTR_POLICER_ACTION_DROP)
                        actions[j++] = mtb->drop_actn;
                else
                        actions[j++] = dtb->jump_actn;
@@ -8970,7 +9098,6 @@ flow_dv_create_policer_rules(struct rte_eth_dev *dev,
 
        if (attr->egress) {
                ret = flow_dv_create_policer_forward_rule(fm, &mtb->egress,
-                                               priv->sh->tx_mtr_sfx_tbl,
                                                priv->mtr_color_reg);
                if (ret) {
                        DRV_LOG(ERR, "Failed to create egress policer.");
@@ -8979,7 +9106,6 @@ flow_dv_create_policer_rules(struct rte_eth_dev *dev,
        }
        if (attr->ingress) {
                ret = flow_dv_create_policer_forward_rule(fm, &mtb->ingress,
-                                               priv->sh->rx_mtr_sfx_tbl,
                                                priv->mtr_color_reg);
                if (ret) {
                        DRV_LOG(ERR, "Failed to create ingress policer.");
@@ -8988,7 +9114,6 @@ flow_dv_create_policer_rules(struct rte_eth_dev *dev,
        }
        if (attr->transfer) {
                ret = flow_dv_create_policer_forward_rule(fm, &mtb->transfer,
-                                               priv->sh->fdb_mtr_sfx_tbl,
                                                priv->mtr_color_reg);
                if (ret) {
                        DRV_LOG(ERR, "Failed to create transfer policer.");