get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/77010/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 77010,
    "url": "http://patches.dpdk.org/api/patches/77010/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1599634114-148013-11-git-send-email-jiaweiw@nvidia.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1599634114-148013-11-git-send-email-jiaweiw@nvidia.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1599634114-148013-11-git-send-email-jiaweiw@nvidia.com",
    "date": "2020-09-09T06:48:32",
    "name": "[v6,10/12] net/mlx5: update translate function for mirror",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "6a43c4343820252fff2d8b8ee4e3b2ee219a222c",
    "submitter": {
        "id": 1939,
        "url": "http://patches.dpdk.org/api/people/1939/?format=api",
        "name": "Jiawei Wang",
        "email": "jiaweiw@nvidia.com"
    },
    "delegate": {
        "id": 319,
        "url": "http://patches.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@amd.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1599634114-148013-11-git-send-email-jiaweiw@nvidia.com/mbox/",
    "series": [
        {
            "id": 12045,
            "url": "http://patches.dpdk.org/api/series/12045/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=12045",
            "date": "2020-09-09T06:48:29",
            "name": "support the flow-based traffic sampling",
            "version": 6,
            "mbox": "http://patches.dpdk.org/series/12045/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/77010/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/77010/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id DA7B0A04B1;\n\tWed,  9 Sep 2020 08:50:36 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id B16561C1A0;\n\tWed,  9 Sep 2020 08:48:52 +0200 (CEST)",
            "from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129])\n by dpdk.org (Postfix) with ESMTP id AE7F91C0CF\n for <dev@dpdk.org>; Wed,  9 Sep 2020 08:48:36 +0200 (CEST)",
            "from Internal Mail-Server by MTLPINE1 (envelope-from\n jiaweiw@nvidia.com) with SMTP; 9 Sep 2020 09:48:34 +0300",
            "from nvidia.com (gen-l-vrt-280.mtl.labs.mlnx [10.237.45.1])\n by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 0896mYG5029471;\n Wed, 9 Sep 2020 09:48:34 +0300"
        ],
        "From": "Jiawei Wang <jiaweiw@nvidia.com>",
        "To": "orika@nvidia.com, viacheslavo@nvidia.com, matan@nvidia.com,\n thomas@monjalon.net, ferruh.yigit@intel.com, marko.kovacevic@intel.com,\n arybchenko@solarflare.com",
        "Cc": "dev@dpdk.org, rasland@nvidia.com, ian.stokes@intel.com, fbl@redhat.com,\n asafp@nvidia.com",
        "Date": "Wed,  9 Sep 2020 09:48:32 +0300",
        "Message-Id": "<1599634114-148013-11-git-send-email-jiaweiw@nvidia.com>",
        "X-Mailer": "git-send-email 1.8.3.1",
        "In-Reply-To": "<1599634114-148013-1-git-send-email-jiaweiw@nvidia.com>",
        "References": "<1598540492-406340-1-git-send-email-jiaweiw@nvidia.com>\n <1599634114-148013-1-git-send-email-jiaweiw@nvidia.com>",
        "Subject": "[dpdk-dev] [PATCH v6 10/12] net/mlx5: update translate function for\n\tmirror",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Translate the attribute of sample action that include sample ratio\nand sub actions list.\nPMD will check the destination action number in current flow,\nif found multiple destination action, then create the new group\nrdma action for each destination, these group rdma actions will\nbe used for creating the multiple destination DR action and add\nit into the flow.\n\nSigned-off-by: Jiawei Wang <jiaweiw@nvidia.com>\n---\n drivers/net/mlx5/mlx5.c         |  11 +\n drivers/net/mlx5/mlx5.h         |   2 +\n drivers/net/mlx5/mlx5_flow.h    |  24 +++\n drivers/net/mlx5/mlx5_flow_dv.c | 459 +++++++++++++++++++++++++++++++++++++---\n 4 files changed, 467 insertions(+), 29 deletions(-)",
    "diff": "diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c\nindex 8d5f517..adb27de 100644\n--- a/drivers/net/mlx5/mlx5.c\n+++ b/drivers/net/mlx5/mlx5.c\n@@ -252,6 +252,17 @@ static LIST_HEAD(, mlx5_dev_ctx_shared) mlx5_dev_ctx_list =\n \t\t.free = mlx5_free,\n \t\t.type = \"mlx5_sample_ipool\",\n \t},\n+\t{\n+\t\t.size = sizeof(struct mlx5_flow_dv_multi_dest_resource),\n+\t\t.trunk_size = 64,\n+\t\t.grow_trunk = 3,\n+\t\t.grow_shift = 2,\n+\t\t.need_lock = 0,\n+\t\t.release_mem_en = 1,\n+\t\t.malloc = mlx5_malloc,\n+\t\t.free = mlx5_free,\n+\t\t.type = \"mlx5_multi_dest_ipool\",\n+\t},\n #endif\n \t{\n \t\t.size = sizeof(struct mlx5_flow_meter),\ndiff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h\nindex 9115391..4bd0cdb 100644\n--- a/drivers/net/mlx5/mlx5.h\n+++ b/drivers/net/mlx5/mlx5.h\n@@ -40,6 +40,7 @@ enum mlx5_ipool_index {\n \tMLX5_IPOOL_PORT_ID, /* Pool for port id resource. */\n \tMLX5_IPOOL_JUMP, /* Pool for jump resource. */\n \tMLX5_IPOOL_SAMPLE, /* Pool for sample resource. */\n+\tMLX5_IPOOL_MULTI_DEST, /* Pool for multi-dest resource. */\n #endif\n \tMLX5_IPOOL_MTR, /* Pool for meter resource. */\n \tMLX5_IPOOL_MCP, /* Pool for metadata resource. */\n@@ -643,6 +644,7 @@ struct mlx5_dev_ctx_shared {\n \tuint32_t port_id_action_list; /* List of port ID actions. */\n \tuint32_t push_vlan_action_list; /* List of push VLAN actions. */\n \tuint32_t sample_action_list; /* List of sample actions. */\n+\tuint32_t multi_dest_list; /* List of multi_dest. */\n \tstruct mlx5_flow_counter_mng cmng; /* Counters management structure. */\n \tstruct mlx5_flow_default_miss_resource default_miss;\n \t/* Default miss action resource structure. */\ndiff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h\nindex 50e230f..33dd49b 100644\n--- a/drivers/net/mlx5/mlx5_flow.h\n+++ b/drivers/net/mlx5/mlx5_flow.h\n@@ -521,6 +521,8 @@ struct mlx5_flow_sub_actions_list {\n \tvoid *dr_queue_action;\n \tvoid *dr_tag_action;\n \tvoid *dr_cnt_action;\n+\tvoid *dr_port_id_action;\n+\tvoid *dr_encap_action;\n };\n \n /* Sample sub-actions resource list. */\n@@ -528,6 +530,8 @@ struct mlx5_flow_sub_actions_idx {\n \tuint32_t rix_hrxq; /**< Hash Rx queue object index. */\n \tuint32_t rix_tag; /**< Index to the tag action. */\n \tuint32_t cnt;\n+\tuint32_t rix_port_id_action; /**< Index to port ID action resource. */\n+\tuint32_t rix_encap_decap; /**< Index to encap/decap resource. */\n };\n \n /* Sample action resource structure. */\n@@ -547,6 +551,22 @@ struct mlx5_flow_dv_sample_resource {\n \t/**< Action resources. */\n };\n \n+#define MLX5_MAX_GROUP_NUM\t2\n+\n+/* Multi-dest action resource structure. */\n+struct mlx5_flow_dv_multi_dest_resource {\n+\tILIST_ENTRY(uint32_t)next; /**< Pointer to next element. */\n+\trte_atomic32_t refcnt; /**< Reference counter. */\n+\tuint8_t ft_type; /** Flow Table Type */\n+\tuint8_t num_of_group; /**< Number of group actions. */\n+\tvoid *action; /**< Pointer to the rdma core action. */\n+\tvoid *group_action[MLX5_MAX_GROUP_NUM];\n+\tstruct mlx5_flow_sub_actions_idx sample_idx[MLX5_MAX_GROUP_NUM];\n+\t/**< Action index resources. */\n+\tstruct mlx5_flow_sub_actions_list sample_act[MLX5_MAX_GROUP_NUM];\n+\t/**< Action resources. */\n+};\n+\n /* Verbs specification header. */\n struct ibv_spec_header {\n \tenum ibv_flow_spec_type type;\n@@ -581,6 +601,8 @@ struct mlx5_flow_handle_dv {\n \t/**< Index to the tag action. */\n \tuint32_t rix_sample;\n \t/**< Index to sample action resource in cache. */\n+\tuint32_t rix_multi_dest;\n+\t/**< Index to multi-dest resource in cache. */\n } __rte_packed;\n \n /** Device flow handle structure: used both for creating & destroying. */\n@@ -641,6 +663,8 @@ struct mlx5_flow_dv_workspace {\n \t/**< Holds the value that the packet is compared to. */\n \tstruct mlx5_flow_dv_sample_resource *sample_res;\n \t/**< Pointer to the sample action resource. */\n+\tstruct mlx5_flow_dv_multi_dest_resource *multi_dest_res;\n+\t/**< Pointer to the multi_dest resource. */\n };\n \n /*\ndiff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c\nindex 19ad9fc..cf85780 100644\n--- a/drivers/net/mlx5/mlx5_flow_dv.c\n+++ b/drivers/net/mlx5/mlx5_flow_dv.c\n@@ -80,6 +80,10 @@\n flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev,\n \t\t\t\t      uint32_t encap_decap_idx);\n \n+static int\n+flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev,\n+\t\t\t\t\tuint32_t port_id);\n+\n /**\n  * Initialize flow attributes structure according to flow items' types.\n  *\n@@ -8304,9 +8308,9 @@ struct field_modify_info modify_tcp[] = {\n  */\n static struct mlx5_hrxq *\n flow_dv_handle_rx_queue(struct rte_eth_dev *dev,\n-\t\t\t  struct mlx5_flow *dev_flow,\n-\t\t\t  struct mlx5_flow_rss_desc *rss_desc,\n-\t\t\t  uint32_t *hrxq_idx)\n+\t\t\tstruct mlx5_flow *dev_flow,\n+\t\t\tstruct mlx5_flow_rss_desc *rss_desc,\n+\t\t\tuint32_t *hrxq_idx)\n {\n \tstruct mlx5_priv *priv = dev->data->dev_private;\n \tstruct mlx5_flow_handle *dh = dev_flow->handle;\n@@ -8314,19 +8318,19 @@ struct field_modify_info modify_tcp[] = {\n \n \tMLX5_ASSERT(rss_desc->queue_num);\n \t*hrxq_idx = mlx5_hrxq_get(dev, rss_desc->key,\n-\t\t\t\t MLX5_RSS_HASH_KEY_LEN,\n-\t\t\t\t dev_flow->hash_fields,\n-\t\t\t\t rss_desc->queue,\n-\t\t\t\t rss_desc->queue_num);\n+\t\t\t\t  MLX5_RSS_HASH_KEY_LEN,\n+\t\t\t\t  dev_flow->hash_fields,\n+\t\t\t\t  rss_desc->queue,\n+\t\t\t\t  rss_desc->queue_num);\n \tif (!*hrxq_idx) {\n \t\t*hrxq_idx = mlx5_hrxq_new\n \t\t\t\t(dev, rss_desc->key,\n-\t\t\t\tMLX5_RSS_HASH_KEY_LEN,\n-\t\t\t\tdev_flow->hash_fields,\n-\t\t\t\trss_desc->queue,\n-\t\t\t\trss_desc->queue_num,\n-\t\t\t\t!!(dh->layers &\n-\t\t\t\tMLX5_FLOW_LAYER_TUNNEL));\n+\t\t\t\t MLX5_RSS_HASH_KEY_LEN,\n+\t\t\t\t dev_flow->hash_fields,\n+\t\t\t\t rss_desc->queue,\n+\t\t\t\t rss_desc->queue_num,\n+\t\t\t\t !!(dh->layers &\n+\t\t\t\t MLX5_FLOW_LAYER_TUNNEL));\n \t\tif (!*hrxq_idx)\n \t\t\treturn NULL;\n \t}\n@@ -8480,6 +8484,146 @@ struct field_modify_info modify_tcp[] = {\n }\n \n /**\n+ * Find existing multi_dest resource or create and register a new one.\n+ *\n+ * @param[in, out] dev\n+ *   Pointer to rte_eth_dev structure.\n+ * @param[in] attr\n+ *   Attributes of flow that includes this item.\n+ * @param[in] resource\n+ *   Pointer to multi_dest resource.\n+ * @param[in] sample_actions\n+ *   Pointer to sample path actions list.\n+ * @param[in] normal_actions\n+ *   Pointer to normal path actions list.\n+ * @parm[in, out] dev_flow\n+ *   Pointer to the dev_flow.\n+ * @param[out] error\n+ *   pointer to error structure.\n+ *\n+ * @return\n+ *   0 on success otherwise -errno and errno is set.\n+ */\n+static int\n+flow_dv_multi_dest_resource_register(struct rte_eth_dev *dev,\n+\t\t\t const struct rte_flow_attr *attr,\n+\t\t\t struct mlx5_flow_dv_multi_dest_resource *resource,\n+\t\t\t void **sample_actions,\n+\t\t\t void **normal_actions,\n+\t\t\t struct mlx5_flow *dev_flow,\n+\t\t\t struct rte_flow_error *error)\n+{\n+\tstruct mlx5_flow_dv_multi_dest_resource *cache_resource;\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_dev_ctx_shared *sh = priv->sh;\n+\tstruct mlx5_flow_sub_actions_list *sample_act;\n+\tstruct mlx5dv_dr_domain *domain;\n+\tuint32_t idx = 0;\n+\n+\t/* Lookup a matching resource from cache. */\n+\tILIST_FOREACH(sh->ipool[MLX5_IPOOL_MULTI_DEST],\n+\t\t      sh->multi_dest_list,\n+\t\t      idx, cache_resource, next) {\n+\t\tif (resource->num_of_group == cache_resource->num_of_group &&\n+\t\t    resource->ft_type == cache_resource->ft_type &&\n+\t\t    !memcmp((void *)cache_resource->sample_act,\n+\t\t\t    (void *)resource->sample_act,\n+\t\t\t   (resource->num_of_group *\n+\t\t\t   sizeof(struct mlx5_flow_sub_actions_list)))) {\n+\t\t\tDRV_LOG(DEBUG, \"sample resource %p: refcnt %d++\",\n+\t\t\t\t(void *)cache_resource,\n+\t\t\t\trte_atomic32_read(&cache_resource->refcnt));\n+\t\t\trte_atomic32_inc(&cache_resource->refcnt);\n+\t\t\tdev_flow->handle->dvh.rix_multi_dest = idx;\n+\t\t\tdev_flow->dv.multi_dest_res = cache_resource;\n+\t\t\treturn 0;\n+\t\t}\n+\t}\n+\t/* Register new sample resource. */\n+\tcache_resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_MULTI_DEST],\n+\t\t\t\t       &dev_flow->handle->dvh.rix_multi_dest);\n+\tif (!cache_resource)\n+\t\treturn rte_flow_error_set(error, ENOMEM,\n+\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t\t  NULL,\n+\t\t\t\t\t  \"cannot allocate resource memory\");\n+\t*cache_resource = *resource;\n+\t/* create the groups actions */\n+\tfor (idx = 0; idx < resource->num_of_group; idx++) {\n+\t\tsample_act = &resource->sample_act[idx];\n+\t\tuint32_t actions_num = sample_act->actions_num;\n+\t\tvoid **dr_actions = (idx == 0) ? normal_actions :\n+\t\t\t\t\t\t sample_actions;\n+\t\tcache_resource->group_action[idx] =\n+\t\t\tmlx5_glue->dr_create_flow_action_group(actions_num,\n+\t\t\t\t\tdr_actions);\n+\t\tif (!cache_resource->group_action[idx]) {\n+\t\t\trte_flow_error_set(error, ENOMEM,\n+\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t\t   NULL,\n+\t\t\t\t\t   \"cannot create group \"\n+\t\t\t\t\t   \"action\");\n+\t\t\tgoto error;\n+\t\t}\n+\t}\n+\tif (attr->transfer)\n+\t\tdomain = sh->fdb_domain;\n+\telse if (attr->ingress)\n+\t\tdomain = sh->rx_domain;\n+\telse\n+\t\tdomain = sh->tx_domain;\n+\t/* create a multi-dest actioin */\n+\tcache_resource->action =\n+\t\tmlx5_glue->dr_create_flow_action_multi_dest\n+\t\t\t(domain,\n+\t\t\tcache_resource->num_of_group,\n+\t\t\t&cache_resource->group_action[0]);\n+\tif (!cache_resource->action) {\n+\t\trte_flow_error_set(error, ENOMEM,\n+\t\t\t\t  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t  NULL,\n+\t\t\t\t  \"cannot create multi-dest \"\n+\t\t\t\t  \"action\");\n+\t\tgoto error;\n+\t}\n+\trte_atomic32_init(&cache_resource->refcnt);\n+\trte_atomic32_inc(&cache_resource->refcnt);\n+\tILIST_INSERT(sh->ipool[MLX5_IPOOL_MULTI_DEST],\n+\t\t     &sh->multi_dest_list,\n+\t\t     dev_flow->handle->dvh.rix_multi_dest, cache_resource,\n+\t\t     next);\n+\tdev_flow->dv.multi_dest_res = cache_resource;\n+\tDRV_LOG(DEBUG, \"new sample resource %p: refcnt %d++\",\n+\t\t(void *)cache_resource,\n+\t\trte_atomic32_read(&cache_resource->refcnt));\n+\treturn 0;\n+error:\n+\tfor (idx = 0; idx < resource->num_of_group; idx++) {\n+\t\tstruct mlx5_flow_sub_actions_idx *act_res =\n+\t\t\t\t\t&cache_resource->sample_idx[idx];\n+\t\tif (cache_resource->group_action[idx])\n+\t\t\tclaim_zero(mlx5_glue->destroy_flow_action\n+\t\t\t\t\t(cache_resource->group_action[idx]));\n+\t\tif (act_res->rix_hrxq &&\n+\t\t    !mlx5_hrxq_release(dev,\n+\t\t\t\tact_res->rix_hrxq))\n+\t\t\tact_res->rix_hrxq = 0;\n+\t\tif (act_res->rix_encap_decap &&\n+\t\t\tflow_dv_encap_decap_resource_release(dev,\n+\t\t\t\tact_res->rix_encap_decap))\n+\t\t\tact_res->rix_encap_decap = 0;\n+\t\tif (act_res->rix_port_id_action &&\n+\t\t\t!flow_dv_port_id_action_resource_release(dev,\n+\t\t\t\tact_res->rix_port_id_action))\n+\t\t\tact_res->rix_port_id_action = 0;\n+\t}\n+\tmlx5_ipool_free(sh->ipool[MLX5_IPOOL_MULTI_DEST],\n+\t\t\t\tdev_flow->handle->dvh.rix_multi_dest);\n+\tdev_flow->handle->dvh.rix_multi_dest = 0;\n+\treturn -rte_errno;\n+}\n+\n+/**\n  * Convert Sample action to DV specification.\n  *\n  * @param[in] dev\n@@ -8490,6 +8634,8 @@ struct field_modify_info modify_tcp[] = {\n  *   Pointer to the mlx5_flow.\n  * @param[in] attr\n  *   Pointer to the flow attributes.\n+ * @param[in, out] num_of_dest\n+ *   Pointer to the num of destination.\n  * @param[in, out] sample_actions\n  *   Pointer to sample actions list.\n  * @param[in, out] res\n@@ -8505,6 +8651,7 @@ struct field_modify_info modify_tcp[] = {\n \t\t\t\tconst struct rte_flow_action *action,\n \t\t\t\tstruct mlx5_flow *dev_flow,\n \t\t\t\tconst struct rte_flow_attr *attr,\n+\t\t\t\tuint32_t *num_of_dest,\n \t\t\t\tvoid **sample_actions,\n \t\t\t\tstruct mlx5_flow_dv_sample_resource *res,\n \t\t\t\tstruct rte_flow_error *error)\n@@ -8554,6 +8701,7 @@ struct field_modify_info modify_tcp[] = {\n \t\t\tsample_idx->rix_hrxq = hrxq_idx;\n \t\t\tsample_actions[sample_act->actions_num++] =\n \t\t\t\t\t\thrxq->action;\n+\t\t\t(*num_of_dest)++;\n \t\t\taction_flags |= MLX5_FLOW_ACTION_QUEUE;\n \t\t\tif (action_flags & MLX5_FLOW_ACTION_MARK)\n \t\t\t\tdev_flow->handle->rix_hrxq = hrxq_idx;\n@@ -8566,6 +8714,7 @@ struct field_modify_info modify_tcp[] = {\n \t\t\tuint32_t tag_be = mlx5_flow_mark_set\n \t\t\t\t(((const struct rte_flow_action_mark *)\n \t\t\t\t(sub_actions->conf))->id);\n+\n \t\t\tdev_flow->handle->mark = 1;\n \t\t\tpre_rix = dev_flow->handle->dvh.rix_tag;\n \t\t\t/* Save the mark resource before sample */\n@@ -8608,6 +8757,56 @@ struct field_modify_info modify_tcp[] = {\n \t\t\taction_flags |= MLX5_FLOW_ACTION_COUNT;\n \t\t\tbreak;\n \t\t}\n+\t\tcase RTE_FLOW_ACTION_TYPE_PORT_ID:\n+\t\t{\n+\t\t\tstruct mlx5_flow_dv_port_id_action_resource\n+\t\t\t\t\tport_id_resource;\n+\t\t\tuint32_t port_id = 0;\n+\n+\t\t\tmemset(&port_id_resource, 0, sizeof(port_id_resource));\n+\t\t\t/* Save the port id resource before sample */\n+\t\t\tpre_rix = dev_flow->handle->rix_port_id_action;\n+\t\t\tpre_r = dev_flow->dv.port_id_action;\n+\t\t\tif (flow_dv_translate_action_port_id(dev, sub_actions,\n+\t\t\t\t\t\t\t     &port_id, error))\n+\t\t\t\treturn -rte_errno;\n+\t\t\tport_id_resource.port_id = port_id;\n+\t\t\tif (flow_dv_port_id_action_resource_register\n+\t\t\t    (dev, &port_id_resource, dev_flow, error))\n+\t\t\t\treturn -rte_errno;\n+\t\t\tsample_act->dr_port_id_action =\n+\t\t\t\tdev_flow->dv.port_id_action->action;\n+\t\t\tsample_idx->rix_port_id_action =\n+\t\t\t\tdev_flow->handle->rix_port_id_action;\n+\t\t\tsample_actions[sample_act->actions_num++] =\n+\t\t\t\t\t\tsample_act->dr_port_id_action;\n+\t\t\t/* Recover the port id resource after sample */\n+\t\t\tdev_flow->dv.port_id_action = pre_r;\n+\t\t\tdev_flow->handle->rix_port_id_action = pre_rix;\n+\t\t\t(*num_of_dest)++;\n+\t\t\taction_flags |= MLX5_FLOW_ACTION_PORT_ID;\n+\t\t\tbreak;\n+\t\t}\n+\t\tcase RTE_FLOW_ACTION_TYPE_RAW_ENCAP:\n+\t\t\t/* Save the encap resource before sample */\n+\t\t\tpre_rix = dev_flow->handle->dvh.rix_encap_decap;\n+\t\t\tpre_r = dev_flow->dv.encap_decap;\n+\t\t\tif (flow_dv_create_action_l2_encap(dev, sub_actions,\n+\t\t\t\t\t\t\t   dev_flow,\n+\t\t\t\t\t\t\t   attr->transfer,\n+\t\t\t\t\t\t\t   error))\n+\t\t\t\treturn -rte_errno;\n+\t\t\tsample_act->dr_encap_action =\n+\t\t\t\tdev_flow->dv.encap_decap->action;\n+\t\t\tsample_idx->rix_encap_decap =\n+\t\t\t\tdev_flow->handle->dvh.rix_encap_decap;\n+\t\t\tsample_actions[sample_act->actions_num++] =\n+\t\t\t\t\t\tsample_act->dr_encap_action;\n+\t\t\t/* Recover the encap resource after sample */\n+\t\t\tdev_flow->dv.encap_decap = pre_r;\n+\t\t\tdev_flow->handle->dvh.rix_encap_decap = pre_rix;\n+\t\t\taction_flags |= MLX5_FLOW_ACTION_ENCAP;\n+\t\t\tbreak;\n \t\tdefault:\n \t\t\treturn rte_flow_error_set(error, EINVAL,\n \t\t\t\tRTE_FLOW_ERROR_TYPE_UNSPECIFIED,\n@@ -8641,10 +8840,16 @@ struct field_modify_info modify_tcp[] = {\n  *   Pointer to the mlx5_flow.\n  * @param[in] attr\n  *   Pointer to the flow attributes.\n+ * @param[in] num_of_dest\n+ *   The num of destination.\n  * @param[in, out] res\n  *   Pointer to sample resource.\n+ * @param[in, out] mdest_res\n+ *   Pointer to multi-dest resource.\n  * @param[in] sample_actions\n  *   Pointer to sample path actions list.\n+ * @param[in] action_flags\n+ *   Holds the actions detected until now.\n  * @param[out] error\n  *   Pointer to the error structure.\n  *\n@@ -8653,17 +8858,84 @@ struct field_modify_info modify_tcp[] = {\n  */\n static int\n flow_dv_create_action_sample(struct rte_eth_dev *dev,\n-\t\t\t\tstruct mlx5_flow *dev_flow,\n-\t\t\t\tconst struct rte_flow_attr *attr,\n-\t\t\t\tstruct mlx5_flow_dv_sample_resource *res,\n-\t\t\t\tvoid **sample_actions,\n-\t\t\t\tstruct rte_flow_error *error)\n+\t\t\t     struct mlx5_flow *dev_flow,\n+\t\t\t     const struct rte_flow_attr *attr,\n+\t\t\t     uint32_t num_of_dest,\n+\t\t\t     struct mlx5_flow_dv_sample_resource *res,\n+\t\t\t     struct mlx5_flow_dv_multi_dest_resource *mdest_res,\n+\t\t\t     void **sample_actions,\n+\t\t\t     uint64_t action_flags,\n+\t\t\t     struct rte_flow_error *error)\n {\n-\tif (flow_dv_sample_resource_register(dev, attr, res, dev_flow,\n-\t\t\t\t\t\tsample_actions, error))\n-\t\treturn rte_flow_error_set(error, EINVAL,\n-\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ACTION,\n-\t\t\t\t\t  NULL, \"can't create sample action\");\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_flow_sub_actions_list *sample_act =\n+\t\t\t\t\t&mdest_res->sample_act[0];\n+\tvoid *normal_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0};\n+\tstruct mlx5_flow_rss_desc *rss_desc = &((struct mlx5_flow_rss_desc *)\n+\t\t\t\t\t      priv->rss_desc)\n+\t\t\t\t\t      [!!priv->flow_nested_idx];\n+\tuint32_t normal_idx = 0;\n+\tstruct mlx5_hrxq *hrxq;\n+\tuint32_t hrxq_idx;\n+\n+\tif (num_of_dest > 1) {\n+\t\tif (sample_act->action_flags & MLX5_FLOW_ACTION_QUEUE) {\n+\t\t\t/* Handle QP action for mirroring */\n+\t\t\thrxq = flow_dv_handle_rx_queue(dev, dev_flow,\n+\t\t\t\t\t\t       rss_desc, &hrxq_idx);\n+\t\t\tif (!hrxq)\n+\t\t\t\treturn rte_flow_error_set\n+\t\t\t\t     (error, rte_errno,\n+\t\t\t\t      RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t      NULL,\n+\t\t\t\t      \"cannot create rx queue\");\n+\t\t\tnormal_actions[normal_idx++] = hrxq->action;\n+\t\t\tmdest_res->sample_idx[0].rix_hrxq = hrxq_idx;\n+\t\t\tsample_act->dr_queue_action = hrxq->action;\n+\t\t\tif (action_flags & MLX5_FLOW_ACTION_MARK)\n+\t\t\t\tdev_flow->handle->rix_hrxq = hrxq_idx;\n+\t\t\tdev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;\n+\t\t}\n+\t\tif (sample_act->action_flags & MLX5_FLOW_ACTION_ENCAP) {\n+\t\t\tnormal_actions[normal_idx++] =\n+\t\t\t\t\tdev_flow->dv.encap_decap->action;\n+\t\t\tmdest_res->sample_idx[0].rix_encap_decap =\n+\t\t\t\t\tdev_flow->handle->dvh.rix_encap_decap;\n+\t\t\tsample_act->dr_encap_action =\n+\t\t\t\t\tdev_flow->dv.encap_decap->action;\n+\t\t}\n+\t\tif (sample_act->action_flags & MLX5_FLOW_ACTION_PORT_ID) {\n+\t\t\tnormal_actions[normal_idx++] =\n+\t\t\t\tdev_flow->dv.port_id_action->action;\n+\t\t\tmdest_res->sample_idx[0].rix_port_id_action =\n+\t\t\t\tdev_flow->handle->rix_port_id_action;\n+\t\t\tsample_act->dr_port_id_action =\n+\t\t\t\tdev_flow->dv.port_id_action->action;\n+\t\t}\n+\t\tsample_act->actions_num = normal_idx;\n+\t\t/* update sample action resource into multi-dest index 1 */\n+\t\tmdest_res->ft_type = res->ft_type;\n+\t\tmemcpy(&mdest_res->sample_idx[1], &res->sample_idx,\n+\t\t\t\tsizeof(struct mlx5_flow_sub_actions_idx));\n+\t\tmemcpy(&mdest_res->sample_act[1], &res->sample_act,\n+\t\t\t\tsizeof(struct mlx5_flow_sub_actions_list));\n+\t\tmdest_res->num_of_group = num_of_dest;\n+\t\tif (flow_dv_multi_dest_resource_register(dev, attr, mdest_res,\n+\t\t\t\t\t\t\t sample_actions,\n+\t\t\t\t\t\t\t normal_actions,\n+\t\t\t\t\t\t\t dev_flow, error))\n+\t\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t\t\t  NULL, \"can't create sample \"\n+\t\t\t\t\t\t  \"action\");\n+\t} else {\n+\t\tif (flow_dv_sample_resource_register(dev, attr, res, dev_flow,\n+\t\t\t\t\t\t     sample_actions, error))\n+\t\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t\t\t  NULL,\n+\t\t\t\t\t\t  \"can't create sample action\");\n+\t}\n \treturn 0;\n }\n \n@@ -8731,15 +9003,21 @@ struct field_modify_info modify_tcp[] = {\n \tvoid *match_value = dev_flow->dv.value.buf;\n \tuint8_t next_protocol = 0xff;\n \tstruct rte_vlan_hdr vlan = { 0 };\n+\tstruct mlx5_flow_dv_multi_dest_resource mdest_res;\n \tstruct mlx5_flow_dv_sample_resource sample_res;\n \tvoid *sample_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0};\n+\tstruct mlx5_flow_sub_actions_list *sample_act;\n \tuint32_t sample_act_pos = UINT32_MAX;\n+\tuint32_t num_of_dest = 0;\n+\tint tmp_actions_n = 0;\n \tuint32_t table;\n \tint ret = 0;\n \n+\tmemset(&mdest_res, 0, sizeof(struct mlx5_flow_dv_multi_dest_resource));\n \tmemset(&sample_res, 0, sizeof(struct mlx5_flow_dv_sample_resource));\n \tmhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :\n \t\t\t\t\t   MLX5DV_FLOW_TABLE_TYPE_NIC_RX;\n+\tsample_act = &mdest_res.sample_act[0];\n \tret = mlx5_flow_group_to_table(attr, dev_flow->external, attr->group,\n \t\t\t\t       !!priv->fdb_def_rule, &table, error);\n \tif (ret)\n@@ -8786,6 +9064,8 @@ struct field_modify_info modify_tcp[] = {\n \t\t\t\t\tdev_flow->dv.port_id_action->action;\n \t\t\taction_flags |= MLX5_FLOW_ACTION_PORT_ID;\n \t\t\tdev_flow->handle->fate_action = MLX5_FLOW_FATE_PORT_ID;\n+\t\t\tsample_act->action_flags |= MLX5_FLOW_ACTION_PORT_ID;\n+\t\t\tnum_of_dest++;\n \t\t\tbreak;\n \t\tcase RTE_FLOW_ACTION_TYPE_FLAG:\n \t\t\taction_flags |= MLX5_FLOW_ACTION_FLAG;\n@@ -8871,6 +9151,8 @@ struct field_modify_info modify_tcp[] = {\n \t\t\trss_desc->queue[0] = queue->index;\n \t\t\taction_flags |= MLX5_FLOW_ACTION_QUEUE;\n \t\t\tdev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;\n+\t\t\tsample_act->action_flags |= MLX5_FLOW_ACTION_QUEUE;\n+\t\t\tnum_of_dest++;\n \t\t\tbreak;\n \t\tcase RTE_FLOW_ACTION_TYPE_RSS:\n \t\t\trss = actions->conf;\n@@ -8958,6 +9240,9 @@ struct field_modify_info modify_tcp[] = {\n \t\t\tdev_flow->dv.actions[actions_n++] =\n \t\t\t\t\tdev_flow->dv.encap_decap->action;\n \t\t\taction_flags |= MLX5_FLOW_ACTION_ENCAP;\n+\t\t\tif (action_flags & MLX5_FLOW_ACTION_SAMPLE)\n+\t\t\t\tsample_act->action_flags |=\n+\t\t\t\t\t\t\tMLX5_FLOW_ACTION_ENCAP;\n \t\t\tbreak;\n \t\tcase RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:\n \t\tcase RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:\n@@ -8987,6 +9272,9 @@ struct field_modify_info modify_tcp[] = {\n \t\t\t\t\tdev_flow->dv.encap_decap->action;\n \t\t\t}\n \t\t\taction_flags |= MLX5_FLOW_ACTION_ENCAP;\n+\t\t\tif (action_flags & MLX5_FLOW_ACTION_SAMPLE)\n+\t\t\t\tsample_act->action_flags |=\n+\t\t\t\t\t\t\tMLX5_FLOW_ACTION_ENCAP;\n \t\t\tbreak;\n \t\tcase RTE_FLOW_ACTION_TYPE_RAW_DECAP:\n \t\t\twhile ((++action)->type == RTE_FLOW_ACTION_TYPE_VOID)\n@@ -9179,6 +9467,7 @@ struct field_modify_info modify_tcp[] = {\n \t\t\tret = flow_dv_translate_action_sample(dev,\n \t\t\t\t\t\t\t      actions,\n \t\t\t\t\t\t\t      dev_flow, attr,\n+\t\t\t\t\t\t\t      &num_of_dest,\n \t\t\t\t\t\t\t      sample_actions,\n \t\t\t\t\t\t\t      &sample_res,\n \t\t\t\t\t\t\t      error);\n@@ -9186,6 +9475,11 @@ struct field_modify_info modify_tcp[] = {\n \t\t\t\treturn ret;\n \t\t\tactions_n++;\n \t\t\taction_flags |= MLX5_FLOW_ACTION_SAMPLE;\n+\t\t\t/* put encap action into group if work with port id */\n+\t\t\tif ((action_flags & MLX5_FLOW_ACTION_ENCAP) &&\n+\t\t\t    (action_flags & MLX5_FLOW_ACTION_PORT_ID))\n+\t\t\t\tsample_act->action_flags |=\n+\t\t\t\t\t\t\tMLX5_FLOW_ACTION_ENCAP;\n \t\t\tbreak;\n \t\tcase RTE_FLOW_ACTION_TYPE_END:\n \t\t\tactions_end = true;\n@@ -9209,15 +9503,19 @@ struct field_modify_info modify_tcp[] = {\n \t\t\t\t\t\tNULL,\n \t\t\t\t\t\t\"cannot create counter\"\n \t\t\t\t\t\t\" object.\");\n-\t\t\t\tdev_flow->dv.actions[actions_n++] =\n+\t\t\t\tdev_flow->dv.actions[actions_n] =\n \t\t\t\t\t  (flow_dv_counter_get_by_idx(dev,\n \t\t\t\t\t  flow->counter, NULL))->action;\n+\t\t\t\tactions_n++;\n \t\t\t}\n \t\t\tif (action_flags & MLX5_FLOW_ACTION_SAMPLE) {\n \t\t\t\tret = flow_dv_create_action_sample(dev,\n \t\t\t\t\t\t\t  dev_flow, attr,\n+\t\t\t\t\t\t\t  num_of_dest,\n \t\t\t\t\t\t\t  &sample_res,\n+\t\t\t\t\t\t\t  &mdest_res,\n \t\t\t\t\t\t\t  sample_actions,\n+\t\t\t\t\t\t\t  action_flags,\n \t\t\t\t\t\t\t  error);\n \t\t\t\tif (ret < 0)\n \t\t\t\t\treturn rte_flow_error_set\n@@ -9225,8 +9523,13 @@ struct field_modify_info modify_tcp[] = {\n \t\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION,\n \t\t\t\t\t\tNULL,\n \t\t\t\t\t\t\"cannot create sample action\");\n-\t\t\t\tdev_flow->dv.actions[sample_act_pos] =\n+\t\t\t\tif (num_of_dest > 1) {\n+\t\t\t\t\tdev_flow->dv.actions[sample_act_pos] =\n+\t\t\t\t\tdev_flow->dv.multi_dest_res->action;\n+\t\t\t\t} else {\n+\t\t\t\t\tdev_flow->dv.actions[sample_act_pos] =\n \t\t\t\t\tdev_flow->dv.sample_res->verbs_action;\n+\t\t\t\t}\n \t\t\t}\n \t\t\tbreak;\n \t\tdefault:\n@@ -9236,6 +9539,31 @@ struct field_modify_info modify_tcp[] = {\n \t\t    modify_action_position == UINT32_MAX)\n \t\t\tmodify_action_position = actions_n++;\n \t}\n+\t/*\n+\t * For multiple destination (sample action with ratio=1), the encap\n+\t * action and port id action will be combined into group action.\n+\t * So need remove the original these actions in the flow and only\n+\t * use the sample action instead of.\n+\t */\n+\tif (num_of_dest > 1 && sample_act->dr_port_id_action) {\n+\t\tint i;\n+\t\tvoid *temp_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0};\n+\n+\t\tfor (i = 0; i < actions_n; i++) {\n+\t\t\tif ((sample_act->dr_encap_action &&\n+\t\t\t\tsample_act->dr_encap_action ==\n+\t\t\t\tdev_flow->dv.actions[i]) ||\n+\t\t\t\t(sample_act->dr_port_id_action &&\n+\t\t\t\tsample_act->dr_port_id_action ==\n+\t\t\t\tdev_flow->dv.actions[i]))\n+\t\t\t\tcontinue;\n+\t\t\ttemp_actions[tmp_actions_n++] = dev_flow->dv.actions[i];\n+\t\t}\n+\t\tmemcpy((void *)dev_flow->dv.actions,\n+\t\t\t\t(void *)temp_actions,\n+\t\t\t\ttmp_actions_n * sizeof(void *));\n+\t\tactions_n = tmp_actions_n;\n+\t}\n \tdev_flow->dv.actions_n = actions_n;\n \tdev_flow->act_flags = action_flags;\n \tfor (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {\n@@ -9540,7 +9868,7 @@ struct field_modify_info modify_tcp[] = {\n \t\t\t\tdv->actions[n++] = drop_hrxq->action;\n \t\t\t}\n \t\t} else if (dh->fate_action == MLX5_FLOW_FATE_QUEUE &&\n-\t\t\t   !dv_h->rix_sample) {\n+\t\t\t   !dv_h->rix_sample && !dv_h->rix_multi_dest) {\n \t\t\tstruct mlx5_hrxq *hrxq;\n \t\t\tuint32_t hrxq_idx;\n \t\t\tstruct mlx5_flow_rss_desc *rss_desc =\n@@ -9827,11 +10155,11 @@ struct field_modify_info modify_tcp[] = {\n  */\n static int\n flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev,\n-\t\t\t\t\tstruct mlx5_flow_handle *handle)\n+\t\t\t\t\tuint32_t port_id)\n {\n \tstruct mlx5_priv *priv = dev->data->dev_private;\n \tstruct mlx5_flow_dv_port_id_action_resource *cache_resource;\n-\tuint32_t idx = handle->rix_port_id_action;\n+\tuint32_t idx = port_id;\n \n \tcache_resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PORT_ID],\n \t\t\t\t\tidx);\n@@ -9921,7 +10249,8 @@ struct field_modify_info modify_tcp[] = {\n \t\tflow_dv_jump_tbl_resource_release(dev, handle);\n \t\tbreak;\n \tcase MLX5_FLOW_FATE_PORT_ID:\n-\t\tflow_dv_port_id_action_resource_release(dev, handle);\n+\t\tflow_dv_port_id_action_resource_release(dev,\n+\t\t\t\thandle->rix_port_id_action);\n \t\tbreak;\n \tcase MLX5_FLOW_FATE_DEFAULT_MISS:\n \t\tflow_dv_default_miss_resource_release(dev);\n@@ -9999,6 +10328,76 @@ struct field_modify_info modify_tcp[] = {\n }\n \n /**\n+ * Release an multi-dest resource.\n+ *\n+ * @param dev\n+ *   Pointer to Ethernet device.\n+ * @param handle\n+ *   Pointer to mlx5_flow_handle.\n+ *\n+ * @return\n+ *   1 while a reference on it exists, 0 when freed.\n+ */\n+static int\n+flow_dv_multi_dest_resource_release(struct rte_eth_dev *dev,\n+\t\t\t\t     struct mlx5_flow_handle *handle)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_flow_dv_multi_dest_resource *cache_resource;\n+\tstruct mlx5_flow_sub_actions_idx *mdest_act_res;\n+\tuint32_t idx = handle->dvh.rix_multi_dest;\n+\tuint32_t i = 0;\n+\n+\tcache_resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MULTI_DEST],\n+\t\t\t idx);\n+\tif (!cache_resource)\n+\t\treturn 0;\n+\tMLX5_ASSERT(cache_resource->action);\n+\tDRV_LOG(DEBUG, \"multi-dest resource %p: refcnt %d--\",\n+\t\t(void *)cache_resource,\n+\t\trte_atomic32_read(&cache_resource->refcnt));\n+\tif (rte_atomic32_dec_and_test(&cache_resource->refcnt)) {\n+\t\tif (cache_resource->action)\n+\t\t\tclaim_zero(mlx5_glue->destroy_flow_action\n+\t\t\t\t\t\t(cache_resource->action));\n+\t\tfor (; i < cache_resource->num_of_group; i++) {\n+\t\t\tmdest_act_res = &cache_resource->sample_idx[i];\n+\t\t\tif (cache_resource->group_action[i])\n+\t\t\t\tclaim_zero(mlx5_glue->destroy_flow_action\n+\t\t\t\t\t(cache_resource->group_action[i]));\n+\t\t\tif (mdest_act_res->rix_hrxq) {\n+\t\t\t\tmlx5_hrxq_release(dev,\n+\t\t\t\t\tmdest_act_res->rix_hrxq);\n+\t\t\t\tmdest_act_res->rix_hrxq = 0;\n+\t\t\t}\n+\t\t\tif (mdest_act_res->rix_encap_decap) {\n+\t\t\t\tflow_dv_encap_decap_resource_release(dev,\n+\t\t\t\t\tmdest_act_res->rix_encap_decap);\n+\t\t\t\tmdest_act_res->rix_encap_decap = 0;\n+\t\t\t}\n+\t\t\tif (mdest_act_res->rix_port_id_action) {\n+\t\t\t\tflow_dv_port_id_action_resource_release(dev,\n+\t\t\t\t\tmdest_act_res->rix_port_id_action);\n+\t\t\t\tmdest_act_res->rix_port_id_action = 0;\n+\t\t\t}\n+\t\t\tif (mdest_act_res->rix_tag) {\n+\t\t\t\tflow_dv_tag_release(dev,\n+\t\t\t\t\tmdest_act_res->rix_tag);\n+\t\t\t\tmdest_act_res->rix_tag = 0;\n+\t\t\t}\n+\t\t}\n+\t\tILIST_REMOVE(priv->sh->ipool[MLX5_IPOOL_MULTI_DEST],\n+\t\t\t     &priv->sh->multi_dest_list, idx,\n+\t\t\t     cache_resource, next);\n+\t\tmlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MULTI_DEST], idx);\n+\t\tDRV_LOG(DEBUG, \"multi-dest resource %p: removed\",\n+\t\t\t(void *)cache_resource);\n+\t\treturn 0;\n+\t}\n+\treturn 1;\n+}\n+\n+/**\n  * Remove the flow from the NIC but keeps it in memory.\n  * Lock free, (mutex should be acquired by caller).\n  *\n@@ -10079,6 +10478,8 @@ struct field_modify_info modify_tcp[] = {\n \t\t\tflow_dv_matcher_release(dev, dev_handle);\n \t\tif (dev_handle->dvh.rix_sample)\n \t\t\tflow_dv_sample_resource_release(dev, dev_handle);\n+\t\tif (dev_handle->dvh.rix_multi_dest)\n+\t\t\tflow_dv_multi_dest_resource_release(dev, dev_handle);\n \t\tif (dev_handle->dvh.rix_encap_decap)\n \t\t\tflow_dv_encap_decap_resource_release(dev,\n \t\t\t\tdev_handle->dvh.rix_encap_decap);\n",
    "prefixes": [
        "v6",
        "10/12"
    ]
}