Show a patch.

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

{
    "id": 73559,
    "url": "https://patches.dpdk.org/api/patches/73559/?format=api",
    "web_url": "https://patches.dpdk.org/patch/73559/",
    "project": {
        "id": 1,
        "url": "https://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"
    },
    "msgid": "<20200708213946.30108-6-andreyv@mellanox.com>",
    "date": "2020-07-08T21:39:44",
    "name": "[v2,5/6] net/mlx5: driver support for shared action",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "a52462271447f3fb51f1414ab9b99ae78d565270",
    "submitter": {
        "id": 1809,
        "url": "https://patches.dpdk.org/api/people/1809/?format=api",
        "name": "Andrey Vesnovaty",
        "email": "andreyv@mellanox.com"
    },
    "delegate": {
        "id": 319,
        "url": "https://patches.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@intel.com"
    },
    "mbox": "https://patches.dpdk.org/patch/73559/mbox/",
    "series": [
        {
            "id": 10899,
            "url": "https://patches.dpdk.org/api/series/10899/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=10899",
            "date": "2020-07-08T21:39:39",
            "name": "add flow shared action API + PMD",
            "version": 2,
            "mbox": "https://patches.dpdk.org/series/10899/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/73559/comments/",
    "check": "success",
    "checks": "https://patches.dpdk.org/api/patches/73559/checks/",
    "tags": {},
    "headers": {
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "List-Post": "<mailto:dev@dpdk.org>",
        "MIME-Version": "1.0",
        "References": "<20200702120511.16315-1-andreyv@mellanox.com>\n <20200708213946.30108-1-andreyv@mellanox.com>",
        "X-BeenThere": "dev@dpdk.org",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "Subject": "[dpdk-dev] [PATCH v2 5/6] net/mlx5: driver support for shared action",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>",
        "From": "Andrey Vesnovaty <andreyv@mellanox.com>",
        "Received": [
            "from dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 6E6C5A0526;\n\tWed,  8 Jul 2020 23:40:39 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 8E5761E545;\n\tWed,  8 Jul 2020 23:40:06 +0200 (CEST)",
            "from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129])\n by dpdk.org (Postfix) with ESMTP id E12F81E496\n for <dev@dpdk.org>; Wed,  8 Jul 2020 23:39:57 +0200 (CEST)",
            "from Internal Mail-Server by MTLPINE1 (envelope-from\n andreyv@mellanox.com) with SMTP; 9 Jul 2020 00:39:54 +0300",
            "from r-arch-host11.mtr.labs.mlnx. (r-arch-host11.mtr.labs.mlnx\n [10.213.43.60])\n by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 068LdrB6032740;\n Thu, 9 Jul 2020 00:39:54 +0300"
        ],
        "To": "dev@dpdk.org",
        "X-Mailer": "git-send-email 2.26.2",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "Date": "Thu,  9 Jul 2020 00:39:44 +0300",
        "Content-Transfer-Encoding": "8bit",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "In-Reply-To": "<20200708213946.30108-1-andreyv@mellanox.com>",
        "Cc": "jer@marvell.com, jerinjacobk@gmail.com, thomas@monjalon.net,\n ferruh.yigit@intel.com, stephen@networkplumber.org,\n bruce.richardson@intel.com, orika@mellanox.com,\n viacheslavo@mellanox.com, andrey.vesnovaty@gmail.com,\n Matan Azrad <matan@mellanox.com>, Shahaf Shuler <shahafs@mellanox.com>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Message-Id": "<20200708213946.30108-6-andreyv@mellanox.com>",
        "Return-Path": "<dev-bounces@dpdk.org>"
    },
    "content": "Implement shared action create/destroy/update/query.\nImplement RSS shared action and handle shared RSS on\nflow apply and release.\n\nNote: currently implemented for sharede RSS action only\n\nSigned-off-by: Andrey Vesnovaty <andreyv@mellanox.com>\n---\n drivers/net/mlx5/mlx5_flow_dv.c | 671 ++++++++++++++++++++++++++++++--\n 1 file changed, 647 insertions(+), 24 deletions(-)",
    "diff": "diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c\nindex d1eb65b01b..93fbfbddab 100644\n--- a/drivers/net/mlx5/mlx5_flow_dv.c\n+++ b/drivers/net/mlx5/mlx5_flow_dv.c\n@@ -8570,6 +8570,156 @@ __flow_dv_translate(struct rte_eth_dev *dev,\n \treturn 0;\n }\n \n+/**\n+ * Set hash RX queue by hash fields (see enum ibv_rx_hash_fields)\n+ * and tunnel.\n+ *\n+ * @param[in, out] action\n+ *   Shred RSS action holding hash RX queue objects.\n+ * @param[in] hash_fields\n+ *   Defines combination of packet fields to participate in RX hash.\n+ * @param[in] tunnel\n+ *   Tunnel type\n+ * @param[in] hrxq_idx\n+ *   Hash RX queue index to set.\n+ *\n+ * @return\n+ *   0 on success, otherwise negative errno value.\n+ */\n+static int\n+__flow_dv_action_rss_hrxq_set(struct mlx5_shared_action_rss *action,\n+\t\t\t      const uint64_t hash_fields,\n+\t\t\t      const int tunnel,\n+\t\t\t      uint32_t hrxq_idx)\n+{\n+\tuint32_t *hrxqs = (tunnel) ? action->hrxq : action->hrxq_tunnel;\n+\n+\tswitch (hash_fields & ~IBV_RX_HASH_INNER) {\n+\tcase MLX5_RSS_HASH_IPV4:\n+\t\thrxqs[0] = hrxq_idx;\n+\t\treturn 0;\n+\tcase MLX5_RSS_HASH_IPV4_TCP:\n+\t\thrxqs[1] = hrxq_idx;\n+\t\treturn 0;\n+\tcase MLX5_RSS_HASH_IPV4_UDP:\n+\t\thrxqs[2] = hrxq_idx;\n+\t\treturn 0;\n+\tcase MLX5_RSS_HASH_IPV6:\n+\t\thrxqs[3] = hrxq_idx;\n+\t\treturn 0;\n+\tcase MLX5_RSS_HASH_IPV6_TCP:\n+\t\thrxqs[4] = hrxq_idx;\n+\t\treturn 0;\n+\tcase MLX5_RSS_HASH_IPV6_UDP:\n+\t\thrxqs[5] = hrxq_idx;\n+\t\treturn 0;\n+\tcase MLX5_RSS_HASH_NONE:\n+\t\thrxqs[6] = hrxq_idx;\n+\t\treturn 0;\n+\tdefault:\n+\t\treturn -1;\n+\t}\n+}\n+\n+/**\n+ * Look up for hash RX queue by hash fields (see enum ibv_rx_hash_fields)\n+ * and tunnel.\n+ *\n+ * @param[in] action\n+ *   Shred RSS action holding hash RX queue objects.\n+ * @param[in] hash_fields\n+ *   Defines combination of packet fields to participate in RX hash.\n+ * @param[in] tunnel\n+ *   Tunnel type\n+ *\n+ * @return\n+ *   Valid hash RX queue index, otherwise 0.\n+ */\n+static uint32_t\n+__flow_dv_action_rss_hrxq_lookup(const struct mlx5_shared_action_rss *action,\n+\t\t\t\t const uint64_t hash_fields,\n+\t\t\t\t const int tunnel)\n+{\n+\tconst uint32_t *hrxqs = (tunnel) ? action->hrxq : action->hrxq_tunnel;\n+\n+\tswitch (hash_fields & ~IBV_RX_HASH_INNER) {\n+\tcase MLX5_RSS_HASH_IPV4:\n+\t\treturn hrxqs[0];\n+\tcase MLX5_RSS_HASH_IPV4_TCP:\n+\t\treturn hrxqs[1];\n+\tcase MLX5_RSS_HASH_IPV4_UDP:\n+\t\treturn hrxqs[2];\n+\tcase MLX5_RSS_HASH_IPV6:\n+\t\treturn hrxqs[3];\n+\tcase MLX5_RSS_HASH_IPV6_TCP:\n+\t\treturn hrxqs[4];\n+\tcase MLX5_RSS_HASH_IPV6_UDP:\n+\t\treturn hrxqs[5];\n+\tcase MLX5_RSS_HASH_NONE:\n+\t\treturn hrxqs[6];\n+\tdefault:\n+\t\treturn 0;\n+\t}\n+}\n+\n+/**\n+ * Retrieves hash RX queue suitable for the *flow*.\n+ * If shared action configured for *flow* suitable hash RX queue will be\n+ * retrieved from attached shared action.\n+ *\n+ * @param[in] flow\n+ *   Shred RSS action holding hash RX queue objects.\n+ * @param[in] dev_flow\n+ *   Pointer to the sub flow.\n+ * @param[out] hrxq\n+ *   Pointer to retrieved hash RX queue object.\n+ *\n+ * @return\n+ *   Valid hash RX queue index, otherwise 0 and rte_errno is set.\n+ */\n+static uint32_t\n+__flow_dv_rss_get_hrxq(struct rte_eth_dev *dev, struct rte_flow *flow,\n+\t\t\t   struct mlx5_flow *dev_flow,\n+\t\t\t   struct mlx5_hrxq **hrxq)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tuint32_t hrxq_idx;\n+\tstruct mlx5_flow_rss_desc *rss_desc = NULL;\n+\n+\tif (flow->shared_rss) {\n+\t\thrxq_idx = __flow_dv_action_rss_hrxq_lookup\n+\t\t\t\t(flow->shared_rss, dev_flow->hash_fields,\n+\t\t\t\t !!(dev_flow->handle->layers &\n+\t\t\t\t    MLX5_FLOW_LAYER_TUNNEL));\n+\t\tif (hrxq_idx) {\n+\t\t\t*hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],\n+\t\t\t\t\t       hrxq_idx);\n+\t\t\trte_atomic32_inc(&(*hrxq)->refcnt);\n+\t\t}\n+\t} else {\n+\t\trss_desc = &((struct mlx5_flow_rss_desc *)priv->rss_desc)\n+\t\t\t   [!!priv->flow_nested_idx];\n+\t\tMLX5_ASSERT(rss_desc->queue_num);\n+\t\thrxq_idx = mlx5_hrxq_get(dev, rss_desc->key,\n+\t\t\t\t\t MLX5_RSS_HASH_KEY_LEN,\n+\t\t\t\t\t dev_flow->hash_fields,\n+\t\t\t\t\t rss_desc->queue, rss_desc->queue_num);\n+\t\tif (!hrxq_idx) {\n+\t\t\thrxq_idx = mlx5_hrxq_new(dev,\n+\t\t\t\t\t\t rss_desc->key,\n+\t\t\t\t\t\t MLX5_RSS_HASH_KEY_LEN,\n+\t\t\t\t\t\t dev_flow->hash_fields,\n+\t\t\t\t\t\t rss_desc->queue,\n+\t\t\t\t\t\t rss_desc->queue_num,\n+\t\t\t\t\t\t !!(dev_flow->handle->layers &\n+\t\t\t\t\t\t    MLX5_FLOW_LAYER_TUNNEL));\n+\t\t}\n+\t\t*hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],\n+\t\t\t\t       hrxq_idx);\n+\t}\n+\treturn hrxq_idx;\n+}\n+\n /**\n  * Apply the flow to the NIC, lock free,\n  * (mutex should be acquired by caller).\n@@ -8628,30 +8778,10 @@ __flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow,\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\tstruct mlx5_hrxq *hrxq;\n-\t\t\tuint32_t hrxq_idx;\n-\t\t\tstruct mlx5_flow_rss_desc *rss_desc =\n-\t\t\t\t&((struct mlx5_flow_rss_desc *)priv->rss_desc)\n-\t\t\t\t[!!priv->flow_nested_idx];\n-\n-\t\t\tMLX5_ASSERT(rss_desc->queue_num);\n-\t\t\thrxq_idx = mlx5_hrxq_get(dev, rss_desc->key,\n-\t\t\t\t\t\t MLX5_RSS_HASH_KEY_LEN,\n-\t\t\t\t\t\t dev_flow->hash_fields,\n-\t\t\t\t\t\t rss_desc->queue,\n-\t\t\t\t\t\t rss_desc->queue_num);\n-\t\t\tif (!hrxq_idx) {\n-\t\t\t\thrxq_idx = mlx5_hrxq_new\n-\t\t\t\t\t\t(dev, rss_desc->key,\n-\t\t\t\t\t\tMLX5_RSS_HASH_KEY_LEN,\n-\t\t\t\t\t\tdev_flow->hash_fields,\n-\t\t\t\t\t\trss_desc->queue,\n-\t\t\t\t\t\trss_desc->queue_num,\n-\t\t\t\t\t\t!!(dh->layers &\n-\t\t\t\t\t\tMLX5_FLOW_LAYER_TUNNEL));\n-\t\t\t}\n-\t\t\thrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],\n-\t\t\t\t\t      hrxq_idx);\n+\t\t\tstruct mlx5_hrxq *hrxq = NULL;\n+\t\t\tuint32_t hrxq_idx = __flow_dv_rss_get_hrxq\n+\t\t\t\t\t\t\t(dev, flow, dev_flow,\n+\t\t\t\t\t\t\t&hrxq);\n \t\t\tif (!hrxq) {\n \t\t\t\trte_flow_error_set\n \t\t\t\t\t(error, rte_errno,\n@@ -9067,12 +9197,16 @@ __flow_dv_remove(struct rte_eth_dev *dev, struct rte_flow *flow)\n static void\n __flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)\n {\n+\tstruct rte_flow_shared_action *shared;\n \tstruct mlx5_flow_handle *dev_handle;\n \tstruct mlx5_priv *priv = dev->data->dev_private;\n \n \tif (!flow)\n \t\treturn;\n \t__flow_dv_remove(dev, flow);\n+\tshared = mlx5_flow_get_shared_rss(flow);\n+\tif (shared)\n+\t\trte_atomic32_dec(&shared->refcnt);\n \tif (flow->counter) {\n \t\tflow_dv_counter_release(dev, flow->counter);\n \t\tflow->counter = 0;\n@@ -9112,6 +9246,410 @@ __flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)\n \t}\n }\n \n+/**\n+ * Release array of hash RX queue objects.\n+ * Helper function.\n+ *\n+ * @param[in] dev\n+ *   Pointer to the Ethernet device structure.\n+ * @param[in, out] hrxqs\n+ *   Array of hash RX queue objects.\n+ *\n+ * @return\n+ *   Total number of references to hash RX queue objects in *hrxqs* array\n+ *   after this operation.\n+ */\n+static int\n+__flow_dv_hrxqs_release(struct rte_eth_dev *dev,\n+\t\t\tuint32_t (*hrxqs)[MLX5_RSS_HASH_FIELDS_LEN])\n+{\n+\tsize_t i;\n+\tint remaining = 0, ret = 0, ret_tunnel = 0;\n+\n+\tfor (i = 0; i < RTE_DIM(*hrxqs); i++) {\n+\t\tret = mlx5_hrxq_release(dev, (*hrxqs)[i]);\n+\t\tif (!ret)\n+\t\t\t(*hrxqs)[i] = 0;\n+\t\tremaining += ret + ret_tunnel;\n+\t}\n+\treturn remaining;\n+}\n+\n+/**\n+ * Release all hash RX queue objects representing shared RSS action.\n+ *\n+ * @param[in] dev\n+ *   Pointer to the Ethernet device structure.\n+ * @param[in, out] action\n+ *   Shared RSS action to remove hash RX queue objects from.\n+ *\n+ * @return\n+ *   Total number of references to hash RX queue objects stored in *action*\n+ *   after this operation.\n+ *   Expected to be 0 if no external references held.\n+ */\n+static int\n+__flow_dv_action_rss_hrxqs_release(struct rte_eth_dev *dev,\n+\t\t\t\t struct mlx5_shared_action_rss *action)\n+{\n+\treturn __flow_dv_hrxqs_release(dev, &action->hrxq) +\n+\t\t__flow_dv_hrxqs_release(dev, &action->hrxq_tunnel);\n+}\n+\n+/**\n+ * Setup shared RSS action.\n+ * Prepare set of hash RX queue objects sufficient to handle all valid\n+ * hash_fields combinations (see enum ibv_rx_hash_fields).\n+ *\n+ * @param[in] dev\n+ *   Pointer to the Ethernet device structure.\n+ * @param[in, out] action\n+ *   Partially initialized shared RSS action.\n+ * @param[out] error\n+ *   Perform verbose error reporting if not NULL. Initialized in case of\n+ *   error only.\n+ *\n+ * @return\n+ *   0 on success, otherwise negative errno value.\n+ */\n+static int\n+__flow_dv_action_rss_setup(struct rte_eth_dev *dev,\n+\t\t\tstruct mlx5_shared_action_rss *action,\n+\t\t\tstruct rte_flow_error *error)\n+{\n+\tsize_t i;\n+\tint err;\n+\n+\tfor (i = 0; i < MLX5_RSS_HASH_FIELDS_LEN; i++) {\n+\t\tuint32_t hrxq_idx;\n+\t\tuint64_t hash_fields = mlx5_rss_hash_fields[i];\n+\t\tint tunnel;\n+\n+\t\tfor (tunnel = 0; tunnel < 2; tunnel++) {\n+\t\t\thrxq_idx = mlx5_hrxq_new(dev, action->origin.key,\n+\t\t\t\t\tMLX5_RSS_HASH_KEY_LEN,\n+\t\t\t\t\thash_fields,\n+\t\t\t\t\taction->origin.queue,\n+\t\t\t\t\taction->origin.queue_num,\n+\t\t\t\t\ttunnel);\n+\t\t\tif (!hrxq_idx) {\n+\t\t\t\trte_flow_error_set\n+\t\t\t\t\t(error, rte_errno,\n+\t\t\t\t\t RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\t\t \"cannot get hash queue\");\n+\t\t\t\tgoto error_hrxq_new;\n+\t\t\t}\n+\t\t\terr = __flow_dv_action_rss_hrxq_set\n+\t\t\t\t(action, hash_fields, tunnel, hrxq_idx);\n+\t\t\tMLX5_ASSERT(!err);\n+\t\t}\n+\t}\n+\treturn 0;\n+error_hrxq_new:\n+\terr = rte_errno;\n+\t__flow_dv_action_rss_hrxqs_release(dev, action);\n+\trte_errno = err;\n+\treturn -rte_errno;\n+}\n+\n+/**\n+ * Create shared RSS action.\n+ *\n+ * @param[in] dev\n+ *   Pointer to the Ethernet device structure.\n+ * @param[in] rss\n+ *   RSS action specification used to create shared action.\n+ * @param[out] error\n+ *   Perform verbose error reporting if not NULL. Initialized in case of\n+ *   error only.\n+ *\n+ * @return\n+ *   A valid shared action handle in case of success, NULL otherwise and\n+ *   rte_errno is set.\n+ */\n+static struct rte_flow_shared_action *\n+__flow_dv_action_rss_create(struct rte_eth_dev *dev,\n+\t\t\tconst struct rte_flow_action_rss *rss,\n+\t\t\tstruct rte_flow_error *error)\n+{\n+\tstruct rte_flow_shared_action *shared_action = NULL;\n+\tvoid *queue = NULL;\n+\tuint32_t queue_size;\n+\tstruct mlx5_shared_action_rss *shared_rss;\n+\tstruct rte_flow_action_rss *origin;\n+\tconst uint8_t *rss_key;\n+\n+\tqueue_size = RTE_ALIGN_CEIL(rss->queue_num * sizeof(uint16_t),\n+\t\t\t\t    sizeof(void *));\n+\tqueue = rte_calloc(__func__, 1, queue_size, 0);\n+\tshared_action = rte_calloc(__func__, 1, sizeof(*shared_action), 0);\n+\tif (!shared_action || !queue) {\n+\t\trte_flow_error_set(error, ENOMEM,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\t   \"cannot allocate resource memory\");\n+\t\tgoto error_rss_init;\n+\t}\n+\tshared_rss = &shared_action->rss;\n+\tshared_rss->queue = queue;\n+\torigin = &shared_rss->origin;\n+\torigin->func = rss->func;\n+\torigin->level = rss->level;\n+\t/* RSS type 0 indicates default RSS type (ETH_RSS_IP). */\n+\torigin->types = !rss->types ? ETH_RSS_IP : rss->types;\n+\t/* NULL RSS key indicates default RSS key. */\n+\trss_key = !rss->key ? rss_hash_default_key : rss->key;\n+\trte_memcpy(shared_rss->key, rss_key, MLX5_RSS_HASH_KEY_LEN);\n+\torigin->key = &shared_rss->key[0];\n+\torigin->key_len = MLX5_RSS_HASH_KEY_LEN;\n+\trte_memcpy(shared_rss->queue, rss->queue, queue_size);\n+\torigin->queue = shared_rss->queue;\n+\torigin->queue_num = rss->queue_num;\n+\tif (__flow_dv_action_rss_setup(dev, shared_rss, error))\n+\t\tgoto error_rss_init;\n+\treturn shared_action;\n+error_rss_init:\n+\trte_free(shared_action);\n+\trte_free(queue);\n+\treturn NULL;\n+}\n+\n+/**\n+ * Destroy the shared RSS action.\n+ * Release related hash RX queue objects.\n+ *\n+ * @param[in] dev\n+ *   Pointer to the Ethernet device structure.\n+ * @param[in] shared_rss\n+ *   The shared RSS action object to be removed.\n+ * @param[out] error\n+ *   Perform verbose error reporting if not NULL. Initialized in case of\n+ *   error only.\n+ *\n+ * @return\n+ *   0 on success, otherwise negative errno value.\n+ */\n+static int\n+__flow_dv_action_rss_release(struct rte_eth_dev *dev,\n+\t\t\t struct mlx5_shared_action_rss *shared_rss,\n+\t\t\t struct rte_flow_error *error)\n+{\n+\tstruct rte_flow_shared_action *shared_action = NULL;\n+\tint remaining = __flow_dv_action_rss_hrxqs_release(dev, shared_rss);\n+\n+\tif (remaining) {\n+\t\treturn rte_flow_error_set(error, ETOOMANYREFS,\n+\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t\t  NULL,\n+\t\t\t\t\t  \"shared rss hrxq has references\");\n+\t}\n+\tshared_action = container_of(shared_rss,\n+\t\t\t\t     struct rte_flow_shared_action, rss);\n+\tif (!rte_atomic32_dec_and_test(&shared_action->refcnt)) {\n+\t\treturn rte_flow_error_set(error, ETOOMANYREFS,\n+\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t\t  NULL,\n+\t\t\t\t\t  \"shared rss has references\");\n+\t}\n+\trte_free(shared_rss->queue);\n+\treturn 0;\n+}\n+\n+/**\n+ * Create shared action, lock free,\n+ * (mutex should be acquired by caller).\n+ * Dispatcher for action type specific call.\n+ *\n+ * @param[in] dev\n+ *   Pointer to the Ethernet device structure.\n+ * @param[in] action\n+ *   Action specification used to create shared action.\n+ * @param[out] error\n+ *   Perform verbose error reporting if not NULL. Initialized in case of\n+ *   error only.\n+ *\n+ * @return\n+ *   A valid shared action handle in case of success, NULL otherwise and\n+ *   rte_errno is set.\n+ */\n+static struct rte_flow_shared_action *\n+__flow_dv_action_create(struct rte_eth_dev *dev,\n+\t\t\tconst struct rte_flow_action *action,\n+\t\t\tstruct rte_flow_error *error)\n+{\n+\tstruct rte_flow_shared_action *shared_action = NULL;\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\n+\tswitch (action->type) {\n+\tcase RTE_FLOW_ACTION_TYPE_RSS:\n+\t\tshared_action = __flow_dv_action_rss_create(dev, action->conf,\n+\t\t\t\t\t\t\t    error);\n+\t\tbreak;\n+\tdefault:\n+\t\trte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t   NULL, \"action type not supported\");\n+\t\tbreak;\n+\t}\n+\tif (shared_action) {\n+\t\trte_atomic32_inc(&shared_action->refcnt);\n+\t\tLIST_INSERT_HEAD(&priv->shared_actions, shared_action, next);\n+\t}\n+\treturn shared_action;\n+}\n+\n+/**\n+ * Destroy the shared action.\n+ * Release action related resources on the NIC and the memory.\n+ * Lock free, (mutex should be acquired by caller).\n+ * Dispatcher for action type specific call.\n+ *\n+ * @param[in] dev\n+ *   Pointer to the Ethernet device structure.\n+ * @param[in] action\n+ *   The shared action object to be removed.\n+ * @param[out] error\n+ *   Perform verbose error reporting if not NULL. Initialized in case of\n+ *   error only.\n+ *\n+ * @return\n+ *   0 on success, otherwise negative errno value.\n+ */\n+static int\n+__flow_dv_action_destroy(struct rte_eth_dev *dev,\n+\t\t\t struct rte_flow_shared_action *action,\n+\t\t\t struct rte_flow_error *error)\n+{\n+\tint ret;\n+\n+\tswitch (action->type) {\n+\tcase MLX5_FLOW_ACTION_SHARED_RSS:\n+\t\tret = __flow_dv_action_rss_release(dev, &action->rss, error);\n+\t\tbreak;\n+\tdefault:\n+\t\treturn rte_flow_error_set(error, ENOTSUP,\n+\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t\t  NULL,\n+\t\t\t\t\t  \"action type not supported\");\n+\t}\n+\tif (ret)\n+\t\treturn ret;\n+\tLIST_REMOVE(action, next);\n+\trte_free(action);\n+\treturn 0;\n+}\n+\n+/**\n+ * Updates in place shared RSS action configuration.\n+ *\n+ * @param[in] dev\n+ *   Pointer to the Ethernet device structure.\n+ * @param[in] shared_rss\n+ *   The shared RSS action object to be updated.\n+ * @param[in] action_conf\n+ *   RSS action specification used to modify *shared_rss*.\n+ * @param[out] error\n+ *   Perform verbose error reporting if not NULL. Initialized in case of\n+ *   error only.\n+ *\n+ * @return\n+ *   0 on success, otherwise negative errno value.\n+ * @note: currently only support update of RSS queues.\n+ */\n+static int\n+__flow_dv_action_rss_update(struct rte_eth_dev *dev,\n+\t\t\t    struct mlx5_shared_action_rss *shared_rss,\n+\t\t\t    const struct rte_flow_action_rss *action_conf,\n+\t\t\t    struct rte_flow_error *error)\n+{\n+\tsize_t i;\n+\tint ret;\n+\tvoid *queue = NULL;\n+\tuint32_t queue_size;\n+\tconst uint8_t *rss_key;\n+\tuint32_t rss_key_len;\n+\n+\tqueue_size = RTE_ALIGN_CEIL(action_conf->queue_num * sizeof(uint16_t),\n+\t\t\t\t    sizeof(void *));\n+\tqueue = rte_calloc(__func__, 1, queue_size, 0);\n+\tif (!queue) {\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}\n+\tif (action_conf->key) {\n+\t\trss_key = action_conf->key;\n+\t\trss_key_len = action_conf->key_len;\n+\t} else {\n+\t\trss_key = rss_hash_default_key;\n+\t\trss_key_len = MLX5_RSS_HASH_KEY_LEN;\n+\t}\n+\tfor (i = 0; i < MLX5_RSS_HASH_FIELDS_LEN; i++) {\n+\t\tuint32_t hrxq_idx;\n+\t\tuint64_t hash_fields = mlx5_rss_hash_fields[i];\n+\t\tint tunnel;\n+\n+\t\tfor (tunnel = 0; tunnel < 2; tunnel++) {\n+\t\t\thrxq_idx = __flow_dv_action_rss_hrxq_lookup\n+\t\t\t\t\t(shared_rss, hash_fields, tunnel);\n+\t\t\tMLX5_ASSERT(hrxq_idx);\n+\t\t\tret = mlx5_hrxq_modify\n+\t\t\t\t(dev, hrxq_idx,\n+\t\t\t\t rss_key, rss_key_len,\n+\t\t\t\t hash_fields,\n+\t\t\t\t action_conf->queue, action_conf->queue_num);\n+\t\t\tif (ret) {\n+\t\t\t\trte_free(queue);\n+\t\t\t\treturn rte_flow_error_set\n+\t\t\t\t\t(error, rte_errno,\n+\t\t\t\t\t RTE_FLOW_ERROR_TYPE_ACTION, NULL,\n+\t\t\t\t\t \"cannot update hash queue\");\n+\t\t\t}\n+\t\t}\n+\t}\n+\trte_free(shared_rss->queue);\n+\tshared_rss->queue = queue;\n+\trte_memcpy(shared_rss->queue, action_conf->queue, queue_size);\n+\tshared_rss->origin.queue = shared_rss->queue;\n+\tshared_rss->origin.queue_num = action_conf->queue_num;\n+\treturn 0;\n+}\n+\n+/**\n+ * Updates in place shared action configuration, lock free,\n+ * (mutex should be acquired by caller).\n+ *\n+ * @param[in] dev\n+ *   Pointer to the Ethernet device structure.\n+ * @param[in] action\n+ *   The shared action object to be updated.\n+ * @param[in] action_conf\n+ *   Action specification used to modify *action*.\n+ *   *action_conf* should be of type correlating with type of the *action*,\n+ *   otherwise considered as invalid.\n+ * @param[out] error\n+ *   Perform verbose error reporting if not NULL. Initialized in case of\n+ *   error only.\n+ *\n+ * @return\n+ *   0 on success, otherwise negative errno value.\n+ */\n+static int\n+__flow_dv_action_update(struct rte_eth_dev *dev,\n+\t\t\tstruct rte_flow_shared_action *action,\n+\t\t\tconst void *action_conf,\n+\t\t\tstruct rte_flow_error *error)\n+{\n+\tswitch (action->type) {\n+\tcase MLX5_FLOW_ACTION_SHARED_RSS:\n+\t\treturn __flow_dv_action_rss_update(dev, &action->rss,\n+\t\t\t\t\t\t   action_conf, error);\n+\tdefault:\n+\t\treturn rte_flow_error_set(error, ENOTSUP,\n+\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t\t  NULL,\n+\t\t\t\t\t  \"action type not supported\");\n+\t}\n+}\n /**\n  * Query a dv flow  rule for its statistics via devx.\n  *\n@@ -9792,6 +10330,87 @@ flow_dv_counter_free(struct rte_eth_dev *dev, uint32_t cnt)\n \tflow_dv_shared_unlock(dev);\n }\n \n+/**\n+ * Validate shared action.\n+ * Dispatcher for action type specific validation.\n+ *\n+ * @param[in] dev\n+ *   Pointer to the Ethernet device structure.\n+ * @param[in] action\n+ *   The shared action object to validate.\n+ * @param[out] error\n+ *   Perform verbose error reporting if not NULL. Initialized in case of\n+ *   error only.\n+ *\n+ * @return\n+ *   0 on success, otherwise negative errno value.\n+ */\n+static int\n+flow_dv_action_validate(struct rte_eth_dev *dev,\n+\t\t\tconst struct rte_flow_action *action,\n+\t\t\tstruct rte_flow_error *error)\n+{\n+\tswitch (action->type) {\n+\tcase RTE_FLOW_ACTION_TYPE_RSS:\n+\t\treturn mlx5_validate_action_rss(dev, action, error);\n+\tdefault:\n+\t\treturn rte_flow_error_set(error, ENOTSUP,\n+\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t\t  NULL,\n+\t\t\t\t\t  \"action type not supported\");\n+\t}\n+}\n+\n+/*\n+ * Mutex-protected thunk to lock-free  __flow_dv_action_create().\n+ */\n+static struct rte_flow_shared_action *\n+flow_dv_action_create(struct rte_eth_dev *dev,\n+\t\t      const struct rte_flow_action *action,\n+\t\t      struct rte_flow_error *error)\n+{\n+\tstruct rte_flow_shared_action *shared_action = NULL;\n+\n+\tflow_dv_shared_lock(dev);\n+\tshared_action = __flow_dv_action_create(dev, action, error);\n+\tflow_dv_shared_unlock(dev);\n+\treturn shared_action;\n+}\n+\n+/*\n+ * Mutex-protected thunk to lock-free  __flow_dv_action_destroy().\n+ */\n+static int\n+flow_dv_action_destroy(struct rte_eth_dev *dev,\n+\t\t       struct rte_flow_shared_action *action,\n+\t\t       struct rte_flow_error *error)\n+{\n+\tint ret;\n+\n+\tflow_dv_shared_lock(dev);\n+\tret = __flow_dv_action_destroy(dev, action, error);\n+\tflow_dv_shared_unlock(dev);\n+\treturn ret;\n+}\n+\n+/*\n+ * Mutex-protected thunk to lock-free  __flow_dv_action_update().\n+ */\n+static int\n+flow_dv_action_update(struct rte_eth_dev *dev,\n+\t\t      struct rte_flow_shared_action *action,\n+\t\t      const void *action_conf,\n+\t\t      struct rte_flow_error *error)\n+{\n+\tint ret;\n+\n+\tflow_dv_shared_lock(dev);\n+\tret = __flow_dv_action_update(dev, action, action_conf,\n+\t\t\t\t      error);\n+\tflow_dv_shared_unlock(dev);\n+\treturn ret;\n+}\n+\n const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {\n \t.validate = flow_dv_validate,\n \t.prepare = flow_dv_prepare,\n@@ -9808,6 +10427,10 @@ const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {\n \t.counter_free = flow_dv_counter_free,\n \t.counter_query = flow_dv_counter_query,\n \t.get_aged_flows = flow_get_aged_flows,\n+\t.action_validate = flow_dv_action_validate,\n+\t.action_create = flow_dv_action_create,\n+\t.action_destroy = flow_dv_action_destroy,\n+\t.action_update = flow_dv_action_update,\n };\n \n #endif /* HAVE_IBV_FLOW_DV_SUPPORT */\n",
    "prefixes": [
        "v2",
        "5/6"
    ]
}