Show a patch.

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

{
    "id": 45251,
    "url": "http://patches.dpdk.org/api/patches/45251/",
    "web_url": "http://patches.dpdk.org/patch/45251/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/",
        "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": "<20180924231721.15799-4-yskoh@mellanox.com>",
    "date": "2018-09-24T23:17:39",
    "name": "[v3,03/11] net/mlx5: add flow translate function",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "517bd5d4164d5a48cdedb4130a90ae2abff56b7a",
    "submitter": {
        "id": 636,
        "url": "http://patches.dpdk.org/api/people/636/",
        "name": "Yongseok Koh",
        "email": "yskoh@mellanox.com"
    },
    "delegate": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/users/1/",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patches.dpdk.org/patch/45251/mbox/",
    "series": [
        {
            "id": 1476,
            "url": "http://patches.dpdk.org/api/series/1476/",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=1476",
            "date": "2018-09-24T23:17:33",
            "name": "net/mlx5: add Direct Verbs flow driver support",
            "version": 3,
            "mbox": "http://patches.dpdk.org/series/1476/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/45251/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/45251/checks/",
    "tags": {},
    "headers": {
        "x-forefront-antispam-report": "SFV:NSPM;\n\tSFS:(10009020)(396003)(376002)(346002)(366004)(39860400002)(136003)(199004)(189003)(51234002)(66066001)(2616005)(476003)(446003)(486006)(11346002)(16200700003)(6436002)(305945005)(7736002)(53946003)(386003)(6506007)(6486002)(6512007)(186003)(102836004)(5250100002)(76176011)(25786009)(26005)(68736007)(6116002)(54906003)(110136005)(99286004)(1076002)(3846002)(71200400001)(52116002)(86362001)(53936002)(71190400001)(97736004)(8936002)(107886003)(14444005)(256004)(4326008)(316002)(2900100001)(81156014)(8676002)(36756003)(81166006)(105586002)(2906002)(106356001)(6636002)(478600001)(5660300001)(14454004)(579004)(559001)(569006);\n\tDIR:OUT; SFP:1101; SCL:1; SRVR:DB3PR0502MB3996;\n\tH:DB3PR0502MB3980.eurprd05.prod.outlook.com; FPR:; SPF:None; LANG:en; \n\tPTR:InfoNoRecords; A:1; MX:1; ",
        "X-Mailman-Version": "2.1.15",
        "In-Reply-To": "<20180924231721.15799-1-yskoh@mellanox.com>",
        "Errors-To": "dev-bounces@dpdk.org",
        "X-MS-Exchange-CrossTenant-originalarrivaltime": "24 Sep 2018 23:17:39.6858\n\t(UTC)",
        "x-ms-office365-filtering-correlation-id": "c620af02-aad6-4079-3595-08d62273eb96",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 1BA571B129;\n\tTue, 25 Sep 2018 01:17:46 +0200 (CEST)",
            "from EUR02-HE1-obe.outbound.protection.outlook.com\n\t(mail-eopbgr10089.outbound.protection.outlook.com [40.107.1.89])\n\tby dpdk.org (Postfix) with ESMTP id 049F91B10B\n\tfor <dev@dpdk.org>; Tue, 25 Sep 2018 01:17:42 +0200 (CEST)",
            "from DB3PR0502MB3980.eurprd05.prod.outlook.com (52.134.72.27) by\n\tDB3PR0502MB3996.eurprd05.prod.outlook.com (52.134.65.142) with\n\tMicrosoft SMTP Server (version=TLS1_2,\n\tcipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id\n\t15.20.1164.25; Mon, 24 Sep 2018 23:17:39 +0000",
            "from DB3PR0502MB3980.eurprd05.prod.outlook.com\n\t([fe80::1cb0:661b:ecab:6045]) by\n\tDB3PR0502MB3980.eurprd05.prod.outlook.com\n\t([fe80::1cb0:661b:ecab:6045%2]) with mapi id 15.20.1164.017;\n\tMon, 24 Sep 2018 23:17:39 +0000"
        ],
        "References": "<20180919072143.23211-1-yskoh@mellanox.com>\n\t<20180924231721.15799-1-yskoh@mellanox.com>",
        "spamdiagnosticmetadata": "NSPM",
        "x-ms-exchange-senderadcheck": "1",
        "MIME-Version": "1.0",
        "Accept-Language": "en-US",
        "Thread-Index": "AQHUVFzJ7rw7u0kbqEuuJsXc6ioAQg==",
        "x-microsoft-antispam": "BCL:0; PCL:0;\n\tRULEID:(7020095)(4652040)(8989299)(5600074)(711020)(4618075)(4534165)(4627221)(201703031133081)(201702281549075)(8990200)(2017052603328)(7153060)(7193020);\n\tSRVR:DB3PR0502MB3996; ",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "x-ms-traffictypediagnostic": "DB3PR0502MB3996:",
        "X-Original-To": "patchwork@dpdk.org",
        "Content-Type": "text/plain; charset=\"iso-8859-1\"",
        "x-ms-publictraffictype": "Email",
        "x-microsoft-antispam-prvs": "<DB3PR0502MB3996DDE586EB337DBB760BC3C3170@DB3PR0502MB3996.eurprd05.prod.outlook.com>",
        "x-clientproxiedby": "BN6PR03CA0021.namprd03.prod.outlook.com\n\t(2603:10b6:404:23::31) To DB3PR0502MB3980.eurprd05.prod.outlook.com\n\t(2603:10a6:8:10::27)",
        "CC": "\"dev@dpdk.org\" <dev@dpdk.org>, Ori Kam <orika@mellanox.com>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "received-spf": "None (protection.outlook.com: mellanox.com does not designate\n\tpermitted sender hosts)",
        "List-Post": "<mailto:dev@dpdk.org>",
        "To": "Thomas Monjalon <thomas@monjalon.net>,\n\tShahaf Shuler <shahafs@mellanox.com>",
        "x-exchange-antispam-report-cfa-test": "BCL:0; PCL:0;\n\tRULEID:(8211001083)(6040522)(2401047)(8121501046)(5005006)(10201501046)(3002001)(93006095)(93001095)(3231355)(944501410)(52105095)(6055026)(149066)(150027)(6041310)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(20161123558120)(20161123560045)(20161123562045)(20161123564045)(201708071742011)(7699051);\n\tSRVR:DB3PR0502MB3996; BCL:0; PCL:0; RULEID:; SRVR:DB3PR0502MB3996; ",
        "Delivered-To": "patchwork@dpdk.org",
        "X-MS-Exchange-CrossTenant-id": "a652971c-7d2e-4d9b-a6a4-d149256f461b",
        "x-forefront-prvs": "0805EC9467",
        "Precedence": "list",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "Date": "Mon, 24 Sep 2018 23:17:39 +0000",
        "x-ld-processed": "a652971c-7d2e-4d9b-a6a4-d149256f461b,ExtAddr",
        "From": "Yongseok Koh <yskoh@mellanox.com>",
        "Thread-Topic": "[PATCH v3 03/11] net/mlx5: add flow translate function",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "c620af02-aad6-4079-3595-08d62273eb96",
        "x-originating-ip": "[209.116.155.178]",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=Mellanox.com;\n\ts=selector1;\n\th=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n\tbh=aLuGNwy9UpscyPlVpI74Dks+R555UvoH3M2LnD/Dk+U=;\n\tb=jGyi9KcF3F0BvhBoZLiv5gysp+yMzZ0A3GszZVC/paAjx8CcY4HM+PJMhDZDhDX9jMkwkfU+g5H/bzxteju5oq5ddTRYQRdrvim7it5az3VR29R2ALcMEmPBoL2DyWj+hSSA1EabTQEKlFarFmJvDVhBZNXxnL/FL4h9emdfRuI=",
        "Message-ID": "<20180924231721.15799-4-yskoh@mellanox.com>",
        "spamdiagnosticoutput": "1:99",
        "x-ms-office365-filtering-ht": "Tenant",
        "Content-Language": "en-US",
        "Content-Transfer-Encoding": "quoted-printable",
        "X-MS-TNEF-Correlator": "",
        "x-exchange-antispam-report-test": "UriScan:(788757137089)(211171220733660)(269456686620040); ",
        "X-OriginatorOrg": "Mellanox.com",
        "Return-Path": "<dev-bounces@dpdk.org>",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>",
        "x-microsoft-exchange-diagnostics": "1; DB3PR0502MB3996;\n\t6:09duA4e/5eRYpPjhdni8yOdzLAAdSkHKJRmT4sif0DryHWqatEbTIxB7mWzirl/taRhvemx5i1l8Wf8N991sbWYP03iM6jL/VZtXzfFHF854K5ly62tBadY1oxQe1Jauc5oZoGVVLgBjY45Z7Neoj+koCJDSdDQM2thQ+g/zK6M1qIdo2uJBvuKaIoTM6qqmVeIB9eQlx7VMB6bDv0fTf9++2HyDZW4bK1yoA8DnwcYMKCfdusQcSdk/99QCUxOA/P4fWp7upw7HQaGLynS4YSgzFeSKgFVZ7gAb3LtTvt3dZQ5sHCT88k8RqxduNcJFkJ+b+7/cm9bTUr346AjhQXxIV0tEgpxDpiKxE/Sl8viBbp9ry/VZMY3BK3HmjXGg9vJX4JugoVRxulQe6n+SNV5dwN8jL9pmqNyLXsNGiyKnD5M0wZXHbhm6z25J7qEjTIhmw8xoqE1/wkwn/Wg55g==;\n\t5:Tf8byOmiesZhze1LvyJkrAickQsJ39gDeC5TOz67M1jORXnHCXJ344HeqdW6MDjx+CggkYDF2hyYG0vuN2gzjf0JaD5mw5QNY65TbaFxnw4W6lzPjHJGAYv9iT80eml08BL4B3APZeTKeX/pamW7CDYJRB6sYJ2/MZoDrOIqlxo=;\n\t7:3NWxCBr39XCULY1i/PVBkvj4UoaWQE0QGdkbdQBqCW8sb0SMuiEtgQhqN2lFHrPFk98megR2tbTtvUmOtLgcStcunNpaLGxSXplpbdLBdmszJWwOANyF1dYtL7CnuL8X3IUzgXAC2ikjBbuGLjZ6/1f+wC34wRv4MnYX0FJ8HNpcWMlClrfyBNemST3WiQmR+RdCIIu9M6/i4OUiAEq6M32fNGV7bvyMnG7SqKq7LvQNJbQAfy3uVexZX3i9xKL6",
        "X-MS-Exchange-CrossTenant-fromentityheader": "Hosted",
        "X-MS-Has-Attach": "",
        "authentication-results": "spf=none (sender IP is )\n\tsmtp.mailfrom=yskoh@mellanox.com; ",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "x-ms-exchange-messagesentrepresentingtype": "1",
        "X-BeenThere": "dev@dpdk.org",
        "x-microsoft-antispam-message-info": "ZHnMn7POEt3ZBqC0f9Sv1sWtyThBCIEjAfX2HMrsBqW6zJZ9HGdDRRm+eB0gc2vQVUARzfXi9FdGeqJYdgQ/WQHDK8pyOyAMEc7tU44lZLWqptrBedhjFv8oBCi9p2kKqok+qdFdMQgP044Es0Cg+DHfVw0evnDyOf1eASknPXAcc9JJchZYm3djTnTWdu0vh/vsUQUGm+IqW+aHcudg7ATtydY5jr7QmjOMdbF9QQSNUTIB4v/fh8EpmoetBzGeoBwhV2SK1lHuGsOCG9pGzJOqQ3lgnaMoBMvvHFfO5BugAg2SWEsNuq5s6LGEN6xxIG/wAiWVWrO2uhcnwbnUgp2TqUei8O0sX/TwBRTkJxg=",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "DB3PR0502MB3996",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Subject": "[dpdk-dev] [PATCH v3 03/11] net/mlx5: add flow translate function"
    },
    "content": "From: Ori Kam <orika@mellanox.com>\n\nThis commit modify the conversion of the input parameters into Verbs\nspec, in order to support all previous changes. Some of those changes\nare: removing the use of the parser, storing each flow in its own flow\nstructure.\n\nSigned-off-by: Ori Kam <orika@mellanox.com>\nAcked-by: Yongseok Koh <yskoh@mellanox.com>\n---\n drivers/net/mlx5/mlx5_flow.c | 1624 +++++++++++++++---------------------------\n 1 file changed, 580 insertions(+), 1044 deletions(-)",
    "diff": "diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c\nindex 166fee555..2d55f08b8 100644\n--- a/drivers/net/mlx5/mlx5_flow.c\n+++ b/drivers/net/mlx5/mlx5_flow.c\n@@ -296,6 +296,7 @@ struct mlx5_flow_verbs {\n struct mlx5_flow {\n \tLIST_ENTRY(mlx5_flow) next;\n \tstruct rte_flow *flow; /**< Pointer to the main flow. */\n+\tuint32_t layers; /**< Bit-fields that holds the detected layers. */\n \tunion {\n \t\tstruct mlx5_flow_verbs verbs; /**< Holds the verbs dev-flow. */\n \t};\n@@ -316,15 +317,8 @@ struct mlx5_flow_counter {\n struct rte_flow {\n \tTAILQ_ENTRY(rte_flow) next; /**< Pointer to the next flow structure. */\n \tstruct rte_flow_attr attributes; /**< User flow attribute. */\n-\tuint32_t layers;\n+\tuint32_t layers; /**< Bit-fields that holds the detected layers. */\n \t/**< Bit-fields of present layers see MLX5_FLOW_LAYER_*. */\n-\tuint32_t modifier;\n-\t/**< Bit-fields of present modifier see MLX5_FLOW_MOD_*. */\n-\tuint32_t fate;\n-\t/**< Bit-fields of present fate see MLX5_FLOW_FATE_*. */\n-\tLIST_HEAD(verbs, mlx5_flow_verbs) verbs; /**< Verbs flows list. */\n-\tstruct mlx5_flow_verbs *cur_verbs;\n-\t/**< Current Verbs flow structure being filled. */\n \tstruct mlx5_flow_counter *counter; /**< Holds Verbs flow counter. */\n \tstruct rte_flow_action_rss rss;/**< RSS context. */\n \tuint8_t key[MLX5_RSS_HASH_KEY_LEN]; /**< RSS hash key. */\n@@ -332,6 +326,7 @@ struct rte_flow {\n \tvoid *nl_flow; /**< Netlink flow buffer if relevant. */\n \tLIST_HEAD(dev_flows, mlx5_flow) dev_flows;\n \t/**< Device flows that are part of the flow. */\n+\tuint32_t actions; /**< Bit-fields which mark all detected actions. */\n };\n \n static const struct rte_flow_ops mlx5_flow_ops = {\n@@ -430,7 +425,7 @@ static struct mlx5_flow_tunnel_info tunnels_info[] = {\n  * Discover the maximum number of priority available.\n  *\n  * @param[in] dev\n- *   Pointer to Ethernet device.\n+ *   Pointer to the Ethernet device structure.\n  *\n  * @return\n  *   number of supported flow priority on success, a negative errno\n@@ -497,34 +492,40 @@ mlx5_flow_discover_priorities(struct rte_eth_dev *dev)\n /**\n  * Adjust flow priority.\n  *\n- * @param dev\n- *   Pointer to Ethernet device.\n- * @param flow\n- *   Pointer to an rte flow.\n+ * @param[in] dev\n+ *   Pointer to the Ethernet device structure.\n+ * @param[in] priority\n+ *   The rule base priority.\n+ * @param[in] subpriority\n+ *   The priority based on the items.\n+ *\n+ * @return\n+ *   The new priority.\n  */\n-static void\n-mlx5_flow_adjust_priority(struct rte_eth_dev *dev, struct rte_flow *flow)\n+static uint32_t\n+mlx5_flow_adjust_priority(struct rte_eth_dev *dev,\n+\t\t\tint32_t priority,\n+\t\t\tuint32_t subpriority)\n {\n+\tuint32_t res = 0;\n \tstruct priv *priv = dev->data->dev_private;\n-\tuint32_t priority = flow->attributes.priority;\n-\tuint32_t subpriority = flow->cur_verbs->attr->priority;\n \n \tswitch (priv->config.flow_prio) {\n \tcase RTE_DIM(priority_map_3):\n-\t\tpriority = priority_map_3[priority][subpriority];\n+\t\tres = priority_map_3[priority][subpriority];\n \t\tbreak;\n \tcase RTE_DIM(priority_map_5):\n-\t\tpriority = priority_map_5[priority][subpriority];\n+\t\tres = priority_map_5[priority][subpriority];\n \t\tbreak;\n \t}\n-\tflow->cur_verbs->attr->priority = priority;\n+\treturn  res;\n }\n \n /**\n  * Get a flow counter.\n  *\n  * @param[in] dev\n- *   Pointer to Ethernet device.\n+ *   Pointer to the Ethernet device structure.\n  * @param[in] shared\n  *   Indicate if this counter is shared with other flows.\n  * @param[in] id\n@@ -595,34 +596,6 @@ mlx5_flow_counter_release(struct mlx5_flow_counter *counter)\n }\n \n /**\n- * Verify the @p attributes will be correctly understood by the NIC and store\n- * them in the @p flow if everything is correct.\n- *\n- * @param[in] dev\n- *   Pointer to Ethernet device structure.\n- * @param[in] attributes\n- *   Pointer to flow attributes\n- * @param[in, out] flow\n- *   Pointer to the rte_flow structure.\n- *\n- * @return\n- *   0 on success.\n- */\n-static int\n-mlx5_flow_attributes(struct rte_eth_dev *dev,\n-\t\t     const struct rte_flow_attr *attributes,\n-\t\t     struct rte_flow *flow)\n-{\n-\tstruct priv *priv = dev->data->dev_private;\n-\tuint32_t priority_max = priv->config.flow_prio - 1;\n-\n-\tflow->attributes = *attributes;\n-\tif (attributes->priority == MLX5_FLOW_PRIO_RSVD)\n-\t\tflow->attributes.priority = priority_max;\n-\treturn 0;\n-}\n-\n-/**\n  * Verify the @p item specifications (spec, last, mask) are compatible with the\n  * NIC capabilities.\n  *\n@@ -693,9 +666,9 @@ mlx5_flow_item_acceptable(const struct rte_flow_item *item,\n  *   Size in bytes of the specification to copy.\n  */\n static void\n-mlx5_flow_spec_verbs_add(struct rte_flow *flow, void *src, unsigned int size)\n+mlx5_flow_spec_verbs_add(struct mlx5_flow *flow, void *src, unsigned int size)\n {\n-\tstruct mlx5_flow_verbs *verbs = flow->cur_verbs;\n+\tstruct mlx5_flow_verbs *verbs = &flow->verbs;\n \n \tif (verbs->specs) {\n \t\tvoid *dst;\n@@ -710,8 +683,8 @@ mlx5_flow_spec_verbs_add(struct rte_flow *flow, void *src, unsigned int size)\n /**\n  * Adjust verbs hash fields according to the @p flow information.\n  *\n- * @param[in, out] flow.\n- *   Pointer to flow structure.\n+ * @param[in] dev_flow.\n+ *   Pointer to dev flow structure.\n  * @param[in] tunnel\n  *   1 when the hash field is for a tunnel item.\n  * @param[in] layer_types\n@@ -720,49 +693,44 @@ mlx5_flow_spec_verbs_add(struct rte_flow *flow, void *src, unsigned int size)\n  *   Item hash fields.\n  */\n static void\n-mlx5_flow_verbs_hashfields_adjust(struct rte_flow *flow,\n+mlx5_flow_verbs_hashfields_adjust(struct mlx5_flow *dev_flow,\n \t\t\t\t  int tunnel __rte_unused,\n \t\t\t\t  uint32_t layer_types, uint64_t hash_fields)\n {\n #ifdef HAVE_IBV_DEVICE_TUNNEL_SUPPORT\n+\tint rss_request_inner = dev_flow->flow->rss.level >= 2;\n+\n \thash_fields |= (tunnel ? IBV_RX_HASH_INNER : 0);\n-\tif (flow->rss.level == 2 && !tunnel)\n+\tif (rss_request_inner && !tunnel)\n \t\thash_fields = 0;\n-\telse if (flow->rss.level < 2 && tunnel)\n+\telse if (!rss_request_inner && tunnel)\n \t\thash_fields = 0;\n #endif\n-\tif (!(flow->rss.types & layer_types))\n+\tif (!(dev_flow->flow->rss.types & layer_types))\n \t\thash_fields = 0;\n-\tflow->cur_verbs->hash_fields |= hash_fields;\n+\tdev_flow->verbs.hash_fields |= hash_fields;\n }\n \n /**\n- * Convert the @p item into a Verbs specification after ensuring the NIC\n- * will understand and process it correctly.\n- * If the necessary size for the conversion is greater than the @p flow_size,\n- * nothing is written in @p flow, the validation is still performed.\n+ * Convert the @p item into a Verbs specification. This function assumes that\n+ * the input is valid and that there is space to insert the requested item\n+ * into the flow.\n  *\n  * @param[in] item\n  *   Item specification.\n- * @param[in, out] flow\n- *   Pointer to flow structure.\n- * @param[in] flow_size\n- *   Size in bytes of the available space in @p flow, if too small, nothing is\n- *   written.\n- *\n- * @return\n- *   On success the number of bytes consumed/necessary, if the returned value\n- *   is lesser or equal to @p flow_size, the @p item has fully been converted,\n- *   otherwise another call with this returned memory size should be done.\n- *   On error, a negative errno value is returned and rte_errno is set.\n+ * @param[in] item_flags\n+ *   Bit field with all detected items.\n+ * @param[in, out] dev_flow\n+ *   Pointer to dev_flow structure.\n  */\n-static int\n-mlx5_flow_item_eth(const struct rte_flow_item *item, struct rte_flow *flow,\n-\t\t   const size_t flow_size)\n+static void\n+flow_verbs_translate_item_eth(const struct rte_flow_item *item,\n+\t\t\t      uint64_t *item_flags,\n+\t\t\t      struct mlx5_flow *dev_flow)\n {\n \tconst struct rte_flow_item_eth *spec = item->spec;\n \tconst struct rte_flow_item_eth *mask = item->mask;\n-\tconst int tunnel = !!(flow->layers & MLX5_FLOW_LAYER_TUNNEL);\n+\tconst int tunnel = !!(*item_flags & MLX5_FLOW_LAYER_TUNNEL);\n \tconst unsigned int size = sizeof(struct ibv_flow_spec_eth);\n \tstruct ibv_flow_spec_eth eth = {\n \t\t.type = IBV_FLOW_SPEC_ETH | (tunnel ? IBV_FLOW_SPEC_INNER : 0),\n@@ -771,10 +739,6 @@ mlx5_flow_item_eth(const struct rte_flow_item *item, struct rte_flow *flow,\n \n \tif (!mask)\n \t\tmask = &rte_flow_item_eth_mask;\n-\tflow->layers |= tunnel ? MLX5_FLOW_LAYER_INNER_L2 :\n-\t\tMLX5_FLOW_LAYER_OUTER_L2;\n-\tif (size > flow_size)\n-\t\treturn size;\n \tif (spec) {\n \t\tunsigned int i;\n \n@@ -790,14 +754,18 @@ mlx5_flow_item_eth(const struct rte_flow_item *item, struct rte_flow *flow,\n \t\t\teth.val.src_mac[i] &= eth.mask.src_mac[i];\n \t\t}\n \t\teth.val.ether_type &= eth.mask.ether_type;\n+\t\tdev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L2;\n \t}\n-\tflow->cur_verbs->attr->priority = MLX5_PRIORITY_MAP_L2;\n-\tmlx5_flow_spec_verbs_add(flow, &eth, size);\n-\treturn size;\n+\tmlx5_flow_spec_verbs_add(dev_flow, &eth, size);\n+\t*item_flags |= tunnel ?\n+\t\t\tMLX5_FLOW_LAYER_INNER_L2 :\n+\t\t\tMLX5_FLOW_LAYER_OUTER_L2;\n }\n \n /**\n  * Update the VLAN tag in the Verbs Ethernet specification.\n+ * This function assumes that the input is valid and there is space to add\n+ * the requested item.\n  *\n  * @param[in, out] attr\n  *   Pointer to Verbs attributes structure.\n@@ -829,34 +797,26 @@ mlx5_flow_item_vlan_update(struct ibv_flow_attr *attr,\n }\n \n /**\n- * Convert the @p item into @p flow (or by updating the already present\n- * Ethernet Verbs) specification after ensuring the NIC will understand and\n- * process it correctly.\n- * If the necessary size for the conversion is greater than the @p flow_size,\n- * nothing is written in @p flow, the validation is still performed.\n+ * Convert the @p item into a Verbs specification. This function assumes that\n+ * the input is valid and that there is space to insert the requested item\n+ * into the flow.\n  *\n  * @param[in] item\n  *   Item specification.\n- * @param[in, out] flow\n- *   Pointer to flow structure.\n- * @param[in] flow_size\n- *   Size in bytes of the available space in @p flow, if too small, nothing is\n- *   written.\n- *\n- * @return\n- *   On success the number of bytes consumed/necessary, if the returned value\n- *   is lesser or equal to @p flow_size, the @p item has fully been converted,\n- *   otherwise another call with this returned memory size should be done.\n- *   On error, a negative errno value is returned and rte_errno is set.\n+ * @param[in, out] item_flags\n+ *   Bit mask that holds all detected items.\n+ * @param[in, out] dev_flow\n+ *   Pointer to dev_flow structure.\n  */\n-static int\n-mlx5_flow_item_vlan(const struct rte_flow_item *item, struct rte_flow *flow,\n-\t\t    const size_t flow_size)\n+static void\n+flow_verbs_translate_item_vlan(const struct rte_flow_item *item,\n+\t\t\t       uint64_t *item_flags,\n+\t\t\t       struct mlx5_flow *dev_flow)\n {\n \tconst struct rte_flow_item_vlan *spec = item->spec;\n \tconst struct rte_flow_item_vlan *mask = item->mask;\n \tunsigned int size = sizeof(struct ibv_flow_spec_eth);\n-\tconst int tunnel = !!(flow->layers & MLX5_FLOW_LAYER_TUNNEL);\n+\tconst int tunnel = !!(*item_flags & MLX5_FLOW_LAYER_TUNNEL);\n \tstruct ibv_flow_spec_eth eth = {\n \t\t.type = IBV_FLOW_SPEC_ETH | (tunnel ? IBV_FLOW_SPEC_INNER : 0),\n \t\t.size = size,\n@@ -874,49 +834,40 @@ mlx5_flow_item_vlan(const struct rte_flow_item *item, struct rte_flow *flow,\n \t\teth.mask.ether_type = mask->inner_type;\n \t\teth.val.ether_type &= eth.mask.ether_type;\n \t}\n-\tif (!(flow->layers & l2m)) {\n-\t\tif (size <= flow_size) {\n-\t\t\tflow->cur_verbs->attr->priority = MLX5_PRIORITY_MAP_L2;\n-\t\t\tmlx5_flow_spec_verbs_add(flow, &eth, size);\n-\t\t}\n+\tif (!(*item_flags & l2m)) {\n+\t\tdev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L2;\n+\t\tmlx5_flow_spec_verbs_add(dev_flow, &eth, size);\n \t} else {\n-\t\tif (flow->cur_verbs)\n-\t\t\tmlx5_flow_item_vlan_update(flow->cur_verbs->attr,\n+\t\tmlx5_flow_item_vlan_update(dev_flow->verbs.attr,\n \t\t\t\t\t\t   &eth);\n \t\tsize = 0; /* Only an update is done in eth specification. */\n \t}\n-\tflow->layers |= tunnel ?\n-\t\t(MLX5_FLOW_LAYER_INNER_L2 | MLX5_FLOW_LAYER_INNER_VLAN) :\n-\t\t(MLX5_FLOW_LAYER_OUTER_L2 | MLX5_FLOW_LAYER_OUTER_VLAN);\n-\treturn size;\n+\t*item_flags |= tunnel ?\n+\t\t\t(MLX5_FLOW_LAYER_INNER_L2 |\n+\t\t\t MLX5_FLOW_LAYER_INNER_VLAN) :\n+\t\t\t(MLX5_FLOW_LAYER_OUTER_L2 | MLX5_FLOW_LAYER_OUTER_VLAN);\n }\n \n /**\n- * Convert the @p item into a Verbs specification after ensuring the NIC\n- * will understand and process it correctly.\n- * If the necessary size for the conversion is greater than the @p flow_size,\n- * nothing is written in @p flow, the validation is still performed.\n+ * Convert the @p item into a Verbs specification. This function assumes that\n+ * the input is valid and that there is space to insert the requested item\n+ * into the flow.\n  *\n  * @param[in] item\n  *   Item specification.\n- * @param[in, out] flow\n- *   Pointer to flow structure.\n- * @param[in] flow_size\n- *   Size in bytes of the available space in @p flow, if too small, nothing is\n- *   written.\n- *\n- * @return\n- *   On success the number of bytes consumed/necessary, if the returned value\n- *   is lesser or equal to @p flow_size, the @p item has fully been converted,\n- *   otherwise another call with this returned memory size should be done.\n+ * @param[in, out] item_flags\n+ *   Bit mask that marks all detected items.\n+ * @param[in, out] dev_flow\n+ *   Pointer to sepacific flow structure.\n  */\n-static int\n-mlx5_flow_item_ipv4(const struct rte_flow_item *item, struct rte_flow *flow,\n-\t\t    const size_t flow_size)\n+static void\n+flow_verbs_translate_item_ipv4(const struct rte_flow_item *item,\n+\t\t\t       uint64_t *item_flags,\n+\t\t\t       struct mlx5_flow *dev_flow)\n {\n \tconst struct rte_flow_item_ipv4 *spec = item->spec;\n \tconst struct rte_flow_item_ipv4 *mask = item->mask;\n-\tconst int tunnel = !!(flow->layers & MLX5_FLOW_LAYER_TUNNEL);\n+\tconst int tunnel = !!(*item_flags & MLX5_FLOW_LAYER_TUNNEL);\n \tunsigned int size = sizeof(struct ibv_flow_spec_ipv4_ext);\n \tstruct ibv_flow_spec_ipv4_ext ipv4 = {\n \t\t.type = IBV_FLOW_SPEC_IPV4_EXT |\n@@ -926,7 +877,7 @@ mlx5_flow_item_ipv4(const struct rte_flow_item *item, struct rte_flow *flow,\n \n \tif (!mask)\n \t\tmask = &rte_flow_item_ipv4_mask;\n-\tflow->layers |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :\n+\t*item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :\n \t\tMLX5_FLOW_LAYER_OUTER_L3_IPV4;\n \tif (spec) {\n \t\tipv4.val = (struct ibv_flow_ipv4_ext_filter){\n@@ -947,46 +898,37 @@ mlx5_flow_item_ipv4(const struct rte_flow_item *item, struct rte_flow *flow,\n \t\tipv4.val.proto &= ipv4.mask.proto;\n \t\tipv4.val.tos &= ipv4.mask.tos;\n \t}\n-\tif (size <= flow_size) {\n-\t\tmlx5_flow_verbs_hashfields_adjust\n-\t\t\t(flow, tunnel,\n-\t\t\t (ETH_RSS_IPV4 | ETH_RSS_FRAG_IPV4 |\n-\t\t\t  ETH_RSS_NONFRAG_IPV4_TCP |\n-\t\t\t  ETH_RSS_NONFRAG_IPV4_UDP |\n-\t\t\t  ETH_RSS_NONFRAG_IPV4_OTHER),\n-\t\t\t (IBV_RX_HASH_SRC_IPV4 | IBV_RX_HASH_DST_IPV4));\n-\t\tflow->cur_verbs->attr->priority = MLX5_PRIORITY_MAP_L3;\n-\t\tmlx5_flow_spec_verbs_add(flow, &ipv4, size);\n-\t}\n-\treturn size;\n+\tmlx5_flow_verbs_hashfields_adjust(dev_flow, tunnel,\n+\t\t\t\t\t  (ETH_RSS_IPV4 | ETH_RSS_FRAG_IPV4 |\n+\t\t\t\t\t   ETH_RSS_NONFRAG_IPV4_TCP |\n+\t\t\t\t\t   ETH_RSS_NONFRAG_IPV4_UDP |\n+\t\t\t\t\t   ETH_RSS_NONFRAG_IPV4_OTHER),\n+\t\t\t\t\t  (IBV_RX_HASH_SRC_IPV4 |\n+\t\t\t\t\t   IBV_RX_HASH_DST_IPV4));\n+\tdev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L3;\n+\tmlx5_flow_spec_verbs_add(dev_flow, &ipv4, size);\n }\n \n /**\n- * Convert the @p item into a Verbs specification after ensuring the NIC\n- * will understand and process it correctly.\n- * If the necessary size for the conversion is greater than the @p flow_size,\n- * nothing is written in @p flow, the validation is still performed.\n+ * Convert the @p item into a Verbs specification. This function assumes that\n+ * the input is valid and that there is space to insert the requested item\n+ * into the flow.\n  *\n  * @param[in] item\n  *   Item specification.\n- * @param[in, out] flow\n- *   Pointer to flow structure.\n- * @param[in] flow_size\n- *   Size in bytes of the available space in @p flow, if too small, nothing is\n- *   written.\n- *\n- * @return\n- *   On success the number of bytes consumed/necessary, if the returned value\n- *   is lesser or equal to @p flow_size, the @p item has fully been converted,\n- *   otherwise another call with this returned memory size should be done.\n+ * @param[in, out] item_flags\n+ *   Bit mask that marks all detected items.\n+ * @param[in, out] dev_flow\n+ *   Pointer to sepacific flow structure.\n  */\n-static int\n-mlx5_flow_item_ipv6(const struct rte_flow_item *item, struct rte_flow *flow,\n-\t\t    const size_t flow_size)\n+static void\n+flow_verbs_translate_item_ipv6(const struct rte_flow_item *item,\n+\t\t\t       uint64_t *item_flags,\n+\t\t\t       struct mlx5_flow *dev_flow)\n {\n \tconst struct rte_flow_item_ipv6 *spec = item->spec;\n \tconst struct rte_flow_item_ipv6 *mask = item->mask;\n-\tconst int tunnel = !!(flow->layers & MLX5_FLOW_LAYER_TUNNEL);\n+\tconst int tunnel = !!(dev_flow->flow->layers & MLX5_FLOW_LAYER_TUNNEL);\n \tunsigned int size = sizeof(struct ibv_flow_spec_ipv6);\n \tstruct ibv_flow_spec_ipv6 ipv6 = {\n \t\t.type = IBV_FLOW_SPEC_IPV6 | (tunnel ? IBV_FLOW_SPEC_INNER : 0),\n@@ -995,8 +937,8 @@ mlx5_flow_item_ipv6(const struct rte_flow_item *item, struct rte_flow *flow,\n \n \tif (!mask)\n \t\tmask = &rte_flow_item_ipv6_mask;\n-\tflow->layers |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :\n-\t\tMLX5_FLOW_LAYER_OUTER_L3_IPV6;\n+\t *item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :\n+\t\t\t\tMLX5_FLOW_LAYER_OUTER_L3_IPV6;\n \tif (spec) {\n \t\tunsigned int i;\n \t\tuint32_t vtc_flow_val;\n@@ -1036,46 +978,40 @@ mlx5_flow_item_ipv6(const struct rte_flow_item *item, struct rte_flow *flow,\n \t\tipv6.val.next_hdr &= ipv6.mask.next_hdr;\n \t\tipv6.val.hop_limit &= ipv6.mask.hop_limit;\n \t}\n-\tif (size <= flow_size) {\n-\t\tmlx5_flow_verbs_hashfields_adjust\n-\t\t\t(flow, tunnel,\n-\t\t\t (ETH_RSS_IPV6 | ETH_RSS_FRAG_IPV6 |\n-\t\t\t  ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_NONFRAG_IPV6_UDP |\n-\t\t\t  ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_IPV6_EX |\n-\t\t\t  ETH_RSS_IPV6_TCP_EX | ETH_RSS_IPV6_UDP_EX),\n-\t\t\t (IBV_RX_HASH_SRC_IPV6 | IBV_RX_HASH_DST_IPV6));\n-\t\tflow->cur_verbs->attr->priority = MLX5_PRIORITY_MAP_L3;\n-\t\tmlx5_flow_spec_verbs_add(flow, &ipv6, size);\n-\t}\n-\treturn size;\n+\tmlx5_flow_verbs_hashfields_adjust(dev_flow, tunnel,\n+\t\t\t\t\t  (ETH_RSS_IPV6 | ETH_RSS_FRAG_IPV6 |\n+\t\t\t\t\t   ETH_RSS_NONFRAG_IPV6_TCP |\n+\t\t\t\t\t   ETH_RSS_NONFRAG_IPV6_UDP |\n+\t\t\t\t\t   ETH_RSS_IPV6_EX  |\n+\t\t\t\t\t   ETH_RSS_IPV6_TCP_EX |\n+\t\t\t\t\t   ETH_RSS_IPV6_UDP_EX |\n+\t\t\t\t\t   ETH_RSS_NONFRAG_IPV6_OTHER),\n+\t\t\t\t\t  (IBV_RX_HASH_SRC_IPV6 |\n+\t\t\t\t\t   IBV_RX_HASH_DST_IPV6));\n+\tdev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L3;\n+\tmlx5_flow_spec_verbs_add(dev_flow, &ipv6, size);\n }\n \n /**\n- * Convert the @p item into a Verbs specification after ensuring the NIC\n- * will understand and process it correctly.\n- * If the necessary size for the conversion is greater than the @p flow_size,\n- * nothing is written in @p flow, the validation is still performed.\n+ * Convert the @p item into a Verbs specification. This function assumes that\n+ * the input is valid and that there is space to insert the requested item\n+ * into the flow.\n  *\n  * @param[in] item\n  *   Item specification.\n- * @param[in, out] flow\n- *   Pointer to flow structure.\n- * @param[in] flow_size\n- *   Size in bytes of the available space in @p flow, if too small, nothing is\n- *   written.\n- *\n- * @return\n- *   On success the number of bytes consumed/necessary, if the returned value\n- *   is lesser or equal to @p flow_size, the @p item has fully been converted,\n- *   otherwise another call with this returned memory size should be done.\n+ * @param[in, out] item_flags\n+ *   Bit mask that marks all detected items.\n+ * @param[in, out] dev_flow\n+ *   Pointer to sepacific flow structure.\n  */\n-static int\n-mlx5_flow_item_udp(const struct rte_flow_item *item, struct rte_flow *flow,\n-\t\t   const size_t flow_size)\n+static void\n+flow_verbs_translate_item_udp(const struct rte_flow_item *item,\n+\t\t\t      uint64_t *item_flags,\n+\t\t\t      struct mlx5_flow *dev_flow)\n {\n \tconst struct rte_flow_item_udp *spec = item->spec;\n \tconst struct rte_flow_item_udp *mask = item->mask;\n-\tconst int tunnel = !!(flow->layers & MLX5_FLOW_LAYER_TUNNEL);\n+\tconst int tunnel = !!(*item_flags & MLX5_FLOW_LAYER_TUNNEL);\n \tunsigned int size = sizeof(struct ibv_flow_spec_tcp_udp);\n \tstruct ibv_flow_spec_tcp_udp udp = {\n \t\t.type = IBV_FLOW_SPEC_UDP | (tunnel ? IBV_FLOW_SPEC_INNER : 0),\n@@ -1084,8 +1020,8 @@ mlx5_flow_item_udp(const struct rte_flow_item *item, struct rte_flow *flow,\n \n \tif (!mask)\n \t\tmask = &rte_flow_item_udp_mask;\n-\tflow->layers |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :\n-\t\tMLX5_FLOW_LAYER_OUTER_L4_UDP;\n+\t*item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :\n+\t\t\tMLX5_FLOW_LAYER_OUTER_L4_UDP;\n \tif (spec) {\n \t\tudp.val.dst_port = spec->hdr.dst_port;\n \t\tudp.val.src_port = spec->hdr.src_port;\n@@ -1095,44 +1031,34 @@ mlx5_flow_item_udp(const struct rte_flow_item *item, struct rte_flow *flow,\n \t\tudp.val.src_port &= udp.mask.src_port;\n \t\tudp.val.dst_port &= udp.mask.dst_port;\n \t}\n-\tif (size <= flow_size) {\n-\t\tmlx5_flow_verbs_hashfields_adjust(flow, tunnel, ETH_RSS_UDP,\n-\t\t\t\t\t\t  (IBV_RX_HASH_SRC_PORT_UDP |\n-\t\t\t\t\t\t   IBV_RX_HASH_DST_PORT_UDP));\n-\t\tflow->cur_verbs->attr->priority = MLX5_PRIORITY_MAP_L4;\n-\t\tmlx5_flow_spec_verbs_add(flow, &udp, size);\n-\t}\n-\treturn size;\n+\tmlx5_flow_verbs_hashfields_adjust(dev_flow,\n+\t\t\t\t\t  tunnel, ETH_RSS_UDP,\n+\t\t\t\t\t  (IBV_RX_HASH_SRC_PORT_UDP |\n+\t\t\t\t\t   IBV_RX_HASH_DST_PORT_UDP));\n+\tdev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L4;\n+\tmlx5_flow_spec_verbs_add(dev_flow, &udp, size);\n }\n \n /**\n- * Convert the @p item into a Verbs specification after ensuring the NIC\n- * will understand and process it correctly.\n- * If the necessary size for the conversion is greater than the @p flow_size,\n- * nothing is written in @p flow, the validation is still performed.\n+ * Convert the @p item into a Verbs specification. This function assumes that\n+ * the input is valid and that there is space to insert the requested item\n+ * into the flow.\n  *\n  * @param[in] item\n  *   Item specification.\n- * @param[in, out] flow\n- *   Pointer to flow structure.\n- * @param[in] flow_size\n- *   Size in bytes of the available space in @p flow, if too small, nothing is\n- *   written.\n- * @param[out] error\n- *   Pointer to error structure.\n- *\n- * @return\n- *   On success the number of bytes consumed/necessary, if the returned value\n- *   is lesser or equal to @p flow_size, the @p item has fully been converted,\n- *   otherwise another call with this returned memory size should be done.\n+ * @param[in, out] item_flags\n+ *   Bit mask that marks all detected items.\n+ * @param[in, out] dev_flow\n+ *   Pointer to sepacific flow structure.\n  */\n-static int\n-mlx5_flow_item_tcp(const struct rte_flow_item *item, struct rte_flow *flow,\n-\t\t   const size_t flow_size)\n+static void\n+flow_verbs_translate_item_tcp(const struct rte_flow_item *item,\n+\t\t\t      uint64_t *item_flags,\n+\t\t\t      struct mlx5_flow *dev_flow)\n {\n \tconst struct rte_flow_item_tcp *spec = item->spec;\n \tconst struct rte_flow_item_tcp *mask = item->mask;\n-\tconst int tunnel = !!(flow->layers & MLX5_FLOW_LAYER_TUNNEL);\n+\tconst int tunnel = !!(dev_flow->flow->layers & MLX5_FLOW_LAYER_TUNNEL);\n \tunsigned int size = sizeof(struct ibv_flow_spec_tcp_udp);\n \tstruct ibv_flow_spec_tcp_udp tcp = {\n \t\t.type = IBV_FLOW_SPEC_TCP | (tunnel ? IBV_FLOW_SPEC_INNER : 0),\n@@ -1141,8 +1067,8 @@ mlx5_flow_item_tcp(const struct rte_flow_item *item, struct rte_flow *flow,\n \n \tif (!mask)\n \t\tmask = &rte_flow_item_tcp_mask;\n-\tflow->layers |=  tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :\n-\t\tMLX5_FLOW_LAYER_OUTER_L4_TCP;\n+\t*item_flags |=  tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :\n+\t\t\t\tMLX5_FLOW_LAYER_OUTER_L4_TCP;\n \tif (spec) {\n \t\ttcp.val.dst_port = spec->hdr.dst_port;\n \t\ttcp.val.src_port = spec->hdr.src_port;\n@@ -1152,40 +1078,30 @@ mlx5_flow_item_tcp(const struct rte_flow_item *item, struct rte_flow *flow,\n \t\ttcp.val.src_port &= tcp.mask.src_port;\n \t\ttcp.val.dst_port &= tcp.mask.dst_port;\n \t}\n-\tif (size <= flow_size) {\n-\t\tmlx5_flow_verbs_hashfields_adjust(flow, tunnel, ETH_RSS_TCP,\n-\t\t\t\t\t\t  (IBV_RX_HASH_SRC_PORT_TCP |\n-\t\t\t\t\t\t   IBV_RX_HASH_DST_PORT_TCP));\n-\t\tflow->cur_verbs->attr->priority = MLX5_PRIORITY_MAP_L4;\n-\t\tmlx5_flow_spec_verbs_add(flow, &tcp, size);\n-\t}\n-\treturn size;\n+\tmlx5_flow_verbs_hashfields_adjust(dev_flow,\n+\t\t\t\t\t  tunnel, ETH_RSS_TCP,\n+\t\t\t\t\t  (IBV_RX_HASH_SRC_PORT_TCP |\n+\t\t\t\t\t   IBV_RX_HASH_DST_PORT_TCP));\n+\tdev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L4;\n+\tmlx5_flow_spec_verbs_add(dev_flow, &tcp, size);\n }\n \n /**\n- * Convert the @p item into a Verbs specification after ensuring the NIC\n- * will understand and process it correctly.\n- * If the necessary size for the conversion is greater than the @p flow_size,\n- * nothing is written in @p flow, the validation is still performed.\n+ * Convert the @p item into a Verbs specification. This function assumes that\n+ * the input is valid and that there is space to insert the requested item\n+ * into the flow.\n  *\n  * @param[in] item\n  *   Item specification.\n- * @param[in, out] flow\n- *   Pointer to flow structure.\n- * @param[in] flow_size\n- *   Size in bytes of the available space in @p flow, if too small, nothing is\n- *   written.\n- * @param[out] error\n- *   Pointer to error structure.\n- *\n- * @return\n- *   On success the number of bytes consumed/necessary, if the returned value\n- *   is lesser or equal to @p flow_size, the @p item has fully been converted,\n- *   otherwise another call with this returned memory size should be done.\n+ * @param[in, out] item_flags\n+ *   Bit mask that marks all detected items.\n+ * @param[in, out] dev_flow\n+ *   Pointer to sepacific flow structure.\n  */\n-static int\n-mlx5_flow_item_vxlan(const struct rte_flow_item *item, struct rte_flow *flow,\n-\t\t     const size_t flow_size)\n+static void\n+flow_verbs_translate_item_vxlan(const struct rte_flow_item *item,\n+\t\t\t\tuint64_t *item_flags,\n+\t\t\t\tstruct mlx5_flow *dev_flow)\n {\n \tconst struct rte_flow_item_vxlan *spec = item->spec;\n \tconst struct rte_flow_item_vxlan *mask = item->mask;\n@@ -1209,38 +1125,27 @@ mlx5_flow_item_vxlan(const struct rte_flow_item *item, struct rte_flow *flow,\n \t\t/* Remove unwanted bits from values. */\n \t\tvxlan.val.tunnel_id &= vxlan.mask.tunnel_id;\n \t}\n-\tif (size <= flow_size) {\n-\t\tmlx5_flow_spec_verbs_add(flow, &vxlan, size);\n-\t\tflow->cur_verbs->attr->priority = MLX5_PRIORITY_MAP_L2;\n-\t}\n-\tflow->layers |= MLX5_FLOW_LAYER_VXLAN;\n-\treturn size;\n+\tmlx5_flow_spec_verbs_add(dev_flow, &vxlan, size);\n+\tdev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L2;\n+\t*item_flags |= MLX5_FLOW_LAYER_VXLAN;\n }\n \n /**\n- * Convert the @p item into a Verbs specification after ensuring the NIC\n- * will understand and process it correctly.\n- * If the necessary size for the conversion is greater than the @p flow_size,\n- * nothing is written in @p flow, the validation is still performed.\n+ * Convert the @p item into a Verbs specification. This function assumes that\n+ * the input is valid and that there is space to insert the requested item\n+ * into the flow.\n  *\n  * @param[in] item\n  *   Item specification.\n- * @param[in, out] flow\n- *   Pointer to flow structure.\n- * @param[in] flow_size\n- *   Size in bytes of the available space in @p flow, if too small, nothing is\n- *   written.\n- * @param[out] error\n- *   Pointer to error structure.\n- *\n- * @return\n- *   On success the number of bytes consumed/necessary, if the returned value\n- *   is lesser or equal to @p flow_size, the @p item has fully been converted,\n- *   otherwise another call with this returned memory size should be done.\n+ * @param[in, out] item_flags\n+ *   Bit mask that marks all detected items.\n+ * @param[in, out] dev_flow\n+ *   Pointer to sepacific flow structure.\n  */\n-static int\n-mlx5_flow_item_vxlan_gpe(const struct rte_flow_item *item,\n-\t\t\t struct rte_flow *flow, const size_t flow_size)\n+static void\n+flow_verbs_translate_item_vxlan_gpe(const struct rte_flow_item *item,\n+\t\t\t\t    uint64_t *item_flags,\n+\t\t\t\t    struct mlx5_flow *dev_flow)\n {\n \tconst struct rte_flow_item_vxlan_gpe *spec = item->spec;\n \tconst struct rte_flow_item_vxlan_gpe *mask = item->mask;\n@@ -1264,12 +1169,9 @@ mlx5_flow_item_vxlan_gpe(const struct rte_flow_item *item,\n \t\t/* Remove unwanted bits from values. */\n \t\tvxlan_gpe.val.tunnel_id &= vxlan_gpe.mask.tunnel_id;\n \t}\n-\tif (size <= flow_size) {\n-\t\tmlx5_flow_spec_verbs_add(flow, &vxlan_gpe, size);\n-\t\tflow->cur_verbs->attr->priority = MLX5_PRIORITY_MAP_L2;\n-\t}\n-\tflow->layers |= MLX5_FLOW_LAYER_VXLAN_GPE;\n-\treturn size;\n+\tmlx5_flow_spec_verbs_add(dev_flow, &vxlan_gpe, size);\n+\tdev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L2;\n+\t*item_flags |= MLX5_FLOW_LAYER_VXLAN_GPE;\n }\n \n /**\n@@ -1325,34 +1227,30 @@ mlx5_flow_item_gre_ip_protocol_update(struct ibv_flow_attr *attr,\n }\n \n /**\n- * Convert the @p item into a Verbs specification after ensuring the NIC\n- * will understand and process it correctly.\n- * It will also update the previous L3 layer with the protocol value matching\n- * the GRE.\n- * If the necessary size for the conversion is greater than the @p flow_size,\n- * nothing is written in @p flow, the validation is still performed.\n+ * Convert the @p item into a Verbs specification. This function assumes that\n+ * the input is valid and that there is space to insert the requested item\n+ * into the flow.\n  *\n- * @param dev\n- *   Pointer to Ethernet device.\n  * @param[in] item\n  *   Item specification.\n- * @param[in, out] flow\n- *   Pointer to flow structure.\n- * @param[in] flow_size\n- *   Size in bytes of the available space in @p flow, if too small, nothing is\n- *   written.\n- *\n- * @return\n- *   On success the number of bytes consumed/necessary, if the returned value\n- *   is lesser or equal to @p flow_size, the @p item has fully been converted,\n- *   otherwise another call with this returned memory size should be done.\n+ * @param[in, out] item_flags\n+ *   Bit mask that marks all detected items.\n+ * @param[in, out] dev_flow\n+ *   Pointer to sepacific flow structure.\n  */\n-static int\n-mlx5_flow_item_gre(const struct rte_flow_item *item __rte_unused,\n-\t\t   struct rte_flow *flow, const size_t flow_size)\n+static void\n+flow_verbs_translate_item_gre(const struct rte_flow_item *item __rte_unused,\n+\t\t\t      uint64_t *item_flags,\n+\t\t\t      struct mlx5_flow *dev_flow)\n {\n-\tstruct mlx5_flow_verbs *verbs = flow->cur_verbs;\n-#ifdef HAVE_IBV_DEVICE_MPLS_SUPPORT\n+\tstruct mlx5_flow_verbs *verbs = &dev_flow->verbs;\n+#ifndef HAVE_IBV_DEVICE_MPLS_SUPPORT\n+\tunsigned int size = sizeof(struct ibv_flow_spec_tunnel);\n+\tstruct ibv_flow_spec_tunnel tunnel = {\n+\t\t.type = IBV_FLOW_SPEC_VXLAN_TUNNEL,\n+\t\t.size = size,\n+\t};\n+#else\n \tconst struct rte_flow_item_gre *spec = item->spec;\n \tconst struct rte_flow_item_gre *mask = item->mask;\n \tunsigned int size = sizeof(struct ibv_flow_spec_gre);\n@@ -1360,15 +1258,7 @@ mlx5_flow_item_gre(const struct rte_flow_item *item __rte_unused,\n \t\t.type = IBV_FLOW_SPEC_GRE,\n \t\t.size = size,\n \t};\n-#else\n-\tunsigned int size = sizeof(struct ibv_flow_spec_tunnel);\n-\tstruct ibv_flow_spec_tunnel tunnel = {\n-\t\t.type = IBV_FLOW_SPEC_VXLAN_TUNNEL,\n-\t\t.size = size,\n-\t};\n-#endif\n \n-#ifdef HAVE_IBV_DEVICE_MPLS_SUPPORT\n \tif (!mask)\n \t\tmask = &rte_flow_item_gre_mask;\n \tif (spec) {\n@@ -1381,51 +1271,36 @@ mlx5_flow_item_gre(const struct rte_flow_item *item __rte_unused,\n \t\ttunnel.val.protocol &= tunnel.mask.protocol;\n \t\ttunnel.val.key &= tunnel.mask.key;\n \t}\n-#else\n-#endif /* !HAVE_IBV_DEVICE_MPLS_SUPPORT */\n-\tif (size <= flow_size) {\n-\t\tif (flow->layers & MLX5_FLOW_LAYER_OUTER_L3_IPV4)\n-\t\t\tmlx5_flow_item_gre_ip_protocol_update\n-\t\t\t\t(verbs->attr, IBV_FLOW_SPEC_IPV4_EXT,\n-\t\t\t\t MLX5_IP_PROTOCOL_GRE);\n-\t\telse\n-\t\t\tmlx5_flow_item_gre_ip_protocol_update\n-\t\t\t\t(verbs->attr, IBV_FLOW_SPEC_IPV6,\n-\t\t\t\t MLX5_IP_PROTOCOL_GRE);\n-\t\tmlx5_flow_spec_verbs_add(flow, &tunnel, size);\n-\t\tflow->cur_verbs->attr->priority = MLX5_PRIORITY_MAP_L2;\n-\t}\n-\tflow->layers |= MLX5_FLOW_LAYER_GRE;\n-\treturn size;\n+#endif\n+\tif (*item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV4)\n+\t\tmlx5_flow_item_gre_ip_protocol_update\n+\t\t\t(verbs->attr, IBV_FLOW_SPEC_IPV4_EXT,\n+\t\t\t MLX5_IP_PROTOCOL_GRE);\n+\telse\n+\t\tmlx5_flow_item_gre_ip_protocol_update\n+\t\t\t(verbs->attr, IBV_FLOW_SPEC_IPV6,\n+\t\t\t MLX5_IP_PROTOCOL_GRE);\n+\tmlx5_flow_spec_verbs_add(dev_flow, &tunnel, size);\n+\tverbs->attr->priority = MLX5_PRIORITY_MAP_L2;\n+\t*item_flags |= MLX5_FLOW_LAYER_GRE;\n }\n \n /**\n- * Convert the @p item into a Verbs specification after ensuring the NIC\n- * will understand and process it correctly.\n- * If the necessary size for the conversion is greater than the @p flow_size,\n- * nothing is written in @p flow, the validation is still performed.\n+ * Convert the @p action into a Verbs specification. This function assumes that\n+ * the input is valid and that there is space to insert the requested action\n+ * into the flow. This function also return the action that was added.\n  *\n  * @param[in] item\n  *   Item specification.\n- * @param[in, out] flow\n- *   Pointer to flow structure.\n- * @param[in] flow_size\n- *   Size in bytes of the available space in @p flow, if too small, nothing is\n- *   written.\n- * @param[out] error\n- *   Pointer to error structure.\n- *\n- * @return\n- *   On success the number of bytes consumed/necessary, if the returned value\n- *   is lesser or equal to @p flow_size, the @p item has fully been converted,\n- *   otherwise another call with this returned memory size should be done.\n- *   On error, a negative errno value is returned and rte_errno is set.\n+ * @param[in, out] item_flags\n+ *   Bit mask that marks all detected items.\n+ * @param[in, out] dev_flow\n+ *   Pointer to sepacific flow structure.\n  */\n-static int\n-mlx5_flow_item_mpls(const struct rte_flow_item *item __rte_unused,\n-\t\t    struct rte_flow *flow __rte_unused,\n-\t\t    const size_t flow_size __rte_unused,\n-\t\t    struct rte_flow_error *error)\n+static void\n+flow_verbs_translate_item_mpls(const struct rte_flow_item *item __rte_unused,\n+\t\t\t       uint64_t *action_flags __rte_unused,\n+\t\t\t       struct mlx5_flow *dev_flow __rte_unused)\n {\n #ifdef HAVE_IBV_DEVICE_MPLS_SUPPORT\n \tconst struct rte_flow_item_mpls *spec = item->spec;\n@@ -1444,135 +1319,25 @@ mlx5_flow_item_mpls(const struct rte_flow_item *item __rte_unused,\n \t\t/* Remove unwanted bits from values.  */\n \t\tmpls.val.label &= mpls.mask.label;\n \t}\n-\tif (size <= flow_size) {\n-\t\tmlx5_flow_spec_verbs_add(flow, &mpls, size);\n-\t\tflow->cur_verbs->attr->priority = MLX5_PRIORITY_MAP_L2;\n-\t}\n-\tflow->layers |= MLX5_FLOW_LAYER_MPLS;\n-\treturn size;\n-#endif /* !HAVE_IBV_DEVICE_MPLS_SUPPORT */\n-\treturn rte_flow_error_set(error, ENOTSUP,\n-\t\t\t\t  RTE_FLOW_ERROR_TYPE_ITEM,\n-\t\t\t\t  item,\n-\t\t\t\t  \"MPLS is not supported by Verbs, please\"\n-\t\t\t\t  \" update.\");\n-}\n-\n-/**\n- * Convert the @p pattern into a Verbs specifications after ensuring the NIC\n- * will understand and process it correctly.\n- * The conversion is performed item per item, each of them is written into\n- * the @p flow if its size is lesser or equal to @p flow_size.\n- * Validation and memory consumption computation are still performed until the\n- * end of @p pattern, unless an error is encountered.\n- *\n- * @param[in] pattern\n- *   Flow pattern.\n- * @param[in, out] flow\n- *   Pointer to the rte_flow structure.\n- * @param[in] flow_size\n- *   Size in bytes of the available space in @p flow, if too small some\n- *   garbage may be present.\n- * @param[out] error\n- *   Pointer to error structure.\n- *\n- * @return\n- *   On success the number of bytes consumed/necessary, if the returned value\n- *   is lesser or equal to @p flow_size, the @pattern  has fully been\n- *   converted, otherwise another call with this returned memory size should\n- *   be done.\n- *   On error, a negative errno value is returned and rte_errno is set.\n- */\n-static int\n-mlx5_flow_items(const struct rte_flow_item pattern[],\n-\t\tstruct rte_flow *flow, const size_t flow_size,\n-\t\tstruct rte_flow_error *error)\n-{\n-\tint remain = flow_size;\n-\tsize_t size = 0;\n-\n-\tfor (; pattern->type != RTE_FLOW_ITEM_TYPE_END; pattern++) {\n-\t\tint ret = 0;\n-\n-\t\tswitch (pattern->type) {\n-\t\tcase RTE_FLOW_ITEM_TYPE_VOID:\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_ETH:\n-\t\t\tret = mlx5_flow_item_eth(pattern, flow, remain);\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_VLAN:\n-\t\t\tret = mlx5_flow_item_vlan(pattern, flow, remain);\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_IPV4:\n-\t\t\tret = mlx5_flow_item_ipv4(pattern, flow, remain);\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_IPV6:\n-\t\t\tret = mlx5_flow_item_ipv6(pattern, flow, remain);\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_UDP:\n-\t\t\tret = mlx5_flow_item_udp(pattern, flow, remain);\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_TCP:\n-\t\t\tret = mlx5_flow_item_tcp(pattern, flow, remain);\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_VXLAN:\n-\t\t\tret = mlx5_flow_item_vxlan(pattern, flow, remain);\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_VXLAN_GPE:\n-\t\t\tret = mlx5_flow_item_vxlan_gpe(pattern, flow,\n-\t\t\t\t\t\t       remain);\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_GRE:\n-\t\t\tret = mlx5_flow_item_gre(pattern, flow, remain);\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_MPLS:\n-\t\t\tret = mlx5_flow_item_mpls(pattern, flow, remain, error);\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\treturn rte_flow_error_set(error, ENOTSUP,\n-\t\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ITEM,\n-\t\t\t\t\t\t  pattern,\n-\t\t\t\t\t\t  \"item not supported\");\n-\t\t}\n-\t\tif (ret < 0)\n-\t\t\treturn ret;\n-\t\tif (remain > ret)\n-\t\t\tremain -= ret;\n-\t\telse\n-\t\t\tremain = 0;\n-\t\tsize += ret;\n-\t}\n-\tif (!flow->layers) {\n-\t\tconst struct rte_flow_item item = {\n-\t\t\t.type = RTE_FLOW_ITEM_TYPE_ETH,\n-\t\t};\n-\n-\t\treturn mlx5_flow_item_eth(&item, flow, flow_size);\n-\t}\n-\treturn size;\n+\tmlx5_flow_spec_verbs_add(dev_flow, &mpls, size);\n+\tdev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L2;\n+\t*action_flags |= MLX5_FLOW_LAYER_MPLS;\n+#endif\n }\n \n /**\n- * Convert the @p action into a Verbs specification after ensuring the NIC\n- * will understand and process it correctly.\n- * If the necessary size for the conversion is greater than the @p flow_size,\n- * nothing is written in @p flow, the validation is still performed.\n- *\n- * @param[in, out] flow\n- *   Pointer to flow structure.\n- * @param[in] flow_size\n- *   Size in bytes of the available space in @p flow, if too small, nothing is\n- *   written.\n+ * Convert the @p action into a Verbs specification. This function assumes that\n+ * the input is valid and that there is space to insert the requested action\n+ * into the flow. This function also return the action that was added.\n  *\n- * @return\n- *   On success the number of bytes consumed/necessary, if the returned value\n- *   is lesser or equal to @p flow_size, the @p action has fully been\n- *   converted, otherwise another call with this returned memory size should\n- *   be done.\n- *   On error, a negative errno value is returned and rte_errno is set.\n+ * @param[in, out] action_flags\n+ *   Pointer to the detected actions.\n+ * @param[in] dev_flow\n+ *   Pointer to mlx5_flow.\n  */\n-static int\n-mlx5_flow_action_drop(struct rte_flow *flow, const size_t flow_size)\n+static void\n+flow_verbs_translate_action_drop(uint64_t *action_flags,\n+\t\t\t\t struct mlx5_flow *dev_flow)\n {\n \tunsigned int size = sizeof(struct ibv_flow_spec_action_drop);\n \tstruct ibv_flow_spec_action_drop drop = {\n@@ -1580,53 +1345,55 @@ mlx5_flow_action_drop(struct rte_flow *flow, const size_t flow_size)\n \t\t\t.size = size,\n \t};\n \n-\tif (size < flow_size)\n-\t\tmlx5_flow_spec_verbs_add(flow, &drop, size);\n-\tflow->fate |= MLX5_FLOW_FATE_DROP;\n-\treturn size;\n+\tmlx5_flow_spec_verbs_add(dev_flow, &drop, size);\n+\t*action_flags |= MLX5_ACTION_DROP;\n }\n \n /**\n- * Convert the @p action into @p flow after ensuring the NIC will understand\n- * and process it correctly.\n+ * Convert the @p action into a Verbs specification. This function assumes that\n+ * the input is valid and that there is space to insert the requested action\n+ * into the flow. This function also return the action that was added.\n  *\n  * @param[in] action\n  *   Action configuration.\n- * @param[in, out] flow\n- *   Pointer to flow structure.\n- *\n- * @return\n- *   0 on success, a negative errno value otherwise and rte_errno is set.\n+ * @param[in, out] action_flags\n+ *   Pointer to the detected actions.\n+ * @param[in] dev_flow\n+ *   Pointer to mlx5_flow.\n  */\n-static int\n-mlx5_flow_action_queue(const struct rte_flow_action *action,\n-\t\t       struct rte_flow *flow)\n+static void\n+flow_verbs_translate_action_queue(const struct rte_flow_action *action,\n+\t\t\t\t  uint64_t *action_flags,\n+\t\t\t\t  struct mlx5_flow *dev_flow)\n {\n \tconst struct rte_flow_action_queue *queue = action->conf;\n+\tstruct rte_flow *flow = dev_flow->flow;\n \n \tif (flow->queue)\n \t\t(*flow->queue)[0] = queue->index;\n \tflow->rss.queue_num = 1;\n-\tflow->fate |= MLX5_FLOW_FATE_QUEUE;\n-\treturn 0;\n+\t*action_flags |= MLX5_ACTION_QUEUE;\n }\n \n /**\n- * Ensure the @p action will be understood and used correctly by the  NIC.\n+ * Convert the @p action into a Verbs specification. This function assumes that\n+ * the input is valid and that there is space to insert the requested action\n+ * into the flow. This function also return the action that was added.\n  *\n  * @param[in] action\n  *   Action configuration.\n- * @param flow[in, out]\n- *   Pointer to the rte_flow structure.\n- *\n- * @return\n- *   0 On success.\n+ * @param[in, out] action_flags\n+ *   Pointer to the detected actions.\n+ * @param[in] dev_flow\n+ *   Pointer to mlx5_flow.\n  */\n-static int\n-mlx5_flow_action_rss(const struct rte_flow_action *action,\n-\t\t\tstruct rte_flow *flow)\n+static void\n+flow_verbs_translate_action_rss(const struct rte_flow_action *action,\n+\t\t\t\tuint64_t *action_flags,\n+\t\t\t\tstruct mlx5_flow *dev_flow)\n {\n \tconst struct rte_flow_action_rss *rss = action->conf;\n+\tstruct rte_flow *flow = dev_flow->flow;\n \n \tif (flow->queue)\n \t\tmemcpy((*flow->queue), rss->queue,\n@@ -1635,30 +1402,26 @@ mlx5_flow_action_rss(const struct rte_flow_action *action,\n \tmemcpy(flow->key, rss->key, MLX5_RSS_HASH_KEY_LEN);\n \tflow->rss.types = rss->types;\n \tflow->rss.level = rss->level;\n-\tflow->fate |= MLX5_FLOW_FATE_RSS;\n-\treturn 0;\n+\t*action_flags |= MLX5_ACTION_RSS;\n }\n \n /**\n- * Convert the @p action into a Verbs specification after ensuring the NIC\n- * will understand and process it correctly.\n- * If the necessary size for the conversion is greater than the @p flow_size,\n- * nothing is written in @p flow, the validation is still performed.\n+ * Convert the @p action into a Verbs specification. This function assumes that\n+ * the input is valid and that there is space to insert the requested action\n+ * into the flow. This function also return the action that was added.\n  *\n- * @param[in, out] flow\n- *   Pointer to flow structure.\n- * @param[in] flow_size\n- *   Size in bytes of the available space in @p flow, if too small, nothing is\n- *   written.\n- *\n- * @return\n- *   On success the number of bytes consumed/necessary, if the returned value\n- *   is lesser or equal to @p flow_size, the @p action has fully been\n- *   converted, otherwise another call with this returned memory size should\n- *   be done.\n+ * @param[in] action\n+ *   Action configuration.\n+ * @param[in, out] action_flags\n+ *   Pointer to the detected actions.\n+ * @param[in] dev_flow\n+ *   Pointer to mlx5_flow.\n  */\n-static int\n-mlx5_flow_action_flag(struct rte_flow *flow, const size_t flow_size)\n+static void\n+flow_verbs_translate_action_flag\n+\t\t\t(const struct rte_flow_action *action __rte_unused,\n+\t\t\t uint64_t *action_flags,\n+\t\t\t struct mlx5_flow *dev_flow)\n {\n \tunsigned int size = sizeof(struct ibv_flow_spec_action_tag);\n \tstruct ibv_flow_spec_action_tag tag = {\n@@ -1666,14 +1429,8 @@ mlx5_flow_action_flag(struct rte_flow *flow, const size_t flow_size)\n \t\t.size = size,\n \t\t.tag_id = mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT),\n \t};\n-\tstruct mlx5_flow_verbs *verbs = flow->cur_verbs;\n-\n-\tif (flow->modifier & MLX5_FLOW_MOD_MARK)\n-\t\tsize = 0;\n-\telse if (size <= flow_size && verbs)\n-\t\tmlx5_flow_spec_verbs_add(flow, &tag, size);\n-\tflow->modifier |= MLX5_FLOW_MOD_FLAG;\n-\treturn size;\n+\t*action_flags |= MLX5_ACTION_MARK;\n+\tmlx5_flow_spec_verbs_add(dev_flow, &tag, size);\n }\n \n /**\n@@ -1685,499 +1442,115 @@ mlx5_flow_action_flag(struct rte_flow *flow, const size_t flow_size)\n  *   Mark identifier to replace the flag.\n  */\n static void\n-mlx5_flow_verbs_mark_update(struct mlx5_flow_verbs *verbs, uint32_t mark_id)\n+flow_verbs_mark_update(struct mlx5_flow_verbs *verbs, uint32_t mark_id)\n {\n \tstruct ibv_spec_header *hdr;\n \tint i;\n \n-\tif (!verbs)\n-\t\treturn;\n-\t/* Update Verbs specification. */\n-\thdr = (struct ibv_spec_header *)verbs->specs;\n-\tif (!hdr)\n-\t\treturn;\n-\tfor (i = 0; i != verbs->attr->num_of_specs; ++i) {\n-\t\tif (hdr->type == IBV_FLOW_SPEC_ACTION_TAG) {\n-\t\t\tstruct ibv_flow_spec_action_tag *t =\n-\t\t\t\t(struct ibv_flow_spec_action_tag *)hdr;\n-\n-\t\t\tt->tag_id = mlx5_flow_mark_set(mark_id);\n-\t\t}\n-\t\thdr = (struct ibv_spec_header *)((uintptr_t)hdr + hdr->size);\n-\t}\n-}\n-\n-/**\n- * Convert the @p action into @p flow (or by updating the already present\n- * Flag Verbs specification) after ensuring the NIC will understand and\n- * process it correctly.\n- * If the necessary size for the conversion is greater than the @p flow_size,\n- * nothing is written in @p flow, the validation is still performed.\n- *\n- * @param[in] action\n- *   Action configuration.\n- * @param[in, out] flow\n- *   Pointer to flow structure.\n- * @param[in] flow_size\n- *   Size in bytes of the available space in @p flow, if too small, nothing is\n- *   written.\n- *\n- * @return\n- *   On success the number of bytes consumed/necessary, if the returned value\n- *   is lesser or equal to @p flow_size, the @p action has fully been\n- *   converted, otherwise another call with this returned memory size should\n- *   be done.\n- */\n-static int\n-mlx5_flow_action_mark(const struct rte_flow_action *action,\n-\t\t      struct rte_flow *flow, const size_t flow_size)\n-{\n-\tconst struct rte_flow_action_mark *mark = action->conf;\n-\tunsigned int size = sizeof(struct ibv_flow_spec_action_tag);\n-\tstruct ibv_flow_spec_action_tag tag = {\n-\t\t.type = IBV_FLOW_SPEC_ACTION_TAG,\n-\t\t.size = size,\n-\t};\n-\tstruct mlx5_flow_verbs *verbs = flow->cur_verbs;\n-\n-\tif (flow->modifier & MLX5_FLOW_MOD_FLAG) {\n-\t\tmlx5_flow_verbs_mark_update(verbs, mark->id);\n-\t\tsize = 0;\n-\t} else if (size <= flow_size) {\n-\t\ttag.tag_id = mlx5_flow_mark_set(mark->id);\n-\t\tmlx5_flow_spec_verbs_add(flow, &tag, size);\n-\t}\n-\tflow->modifier |= MLX5_FLOW_MOD_MARK;\n-\treturn size;\n-}\n-\n-/**\n- * Convert the @p action into a Verbs specification after ensuring the NIC\n- * will understand and process it correctly.\n- * If the necessary size for the conversion is greater than the @p flow_size,\n- * nothing is written in @p flow, the validation is still performed.\n- *\n- * @param action[in]\n- *   Action configuration.\n- * @param flow[in, out]\n- *   Pointer to flow structure.\n- * @param flow_size[in]\n- *   Size in bytes of the available space in @p flow, if too small, nothing is\n- *   written.\n- * @param error[int, out]\n- *   Pointer to error structure.\n- *\n- * @return\n- *   On success the number of bytes consumed/necessary, if the returned value\n- *   is lesser or equal to @p flow_size, the @p action has fully been\n- *   converted, otherwise another call with this returned memory size should\n- *   be done.\n- *   On error, a negative errno value is returned and rte_errno is set.\n- */\n-static int\n-mlx5_flow_action_count(struct rte_eth_dev *dev,\n-\t\t       const struct rte_flow_action *action,\n-\t\t       struct rte_flow *flow,\n-\t\t       const size_t flow_size __rte_unused,\n-\t\t       struct rte_flow_error *error)\n-{\n-\tconst struct rte_flow_action_count *count = action->conf;\n-#ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT\n-\tunsigned int size = sizeof(struct ibv_flow_spec_counter_action);\n-\tstruct ibv_flow_spec_counter_action counter = {\n-\t\t.type = IBV_FLOW_SPEC_ACTION_COUNT,\n-\t\t.size = size,\n-\t};\n-#endif\n-\n-\tif (!flow->counter) {\n-\t\tflow->counter = mlx5_flow_counter_new(dev, count->shared,\n-\t\t\t\t\t\t      count->id);\n-\t\tif (!flow->counter)\n-\t\t\treturn rte_flow_error_set(error, ENOTSUP,\n-\t\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ACTION,\n-\t\t\t\t\t\t  action,\n-\t\t\t\t\t\t  \"cannot get counter\"\n-\t\t\t\t\t\t  \" context.\");\n-\t}\n-\tflow->modifier |= MLX5_FLOW_MOD_COUNT;\n-#ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT\n-\tcounter.counter_set_handle = flow->counter->cs->handle;\n-\tif (size <= flow_size)\n-\t\tmlx5_flow_spec_verbs_add(flow, &counter, size);\n-\treturn size;\n-#endif\n-\treturn 0;\n-}\n-\n-/**\n- * Convert the @p action into @p flow after ensuring the NIC will understand\n- * and process it correctly.\n- * The conversion is performed action per action, each of them is written into\n- * the @p flow if its size is lesser or equal to @p flow_size.\n- * Validation and memory consumption computation are still performed until the\n- * end of @p action, unless an error is encountered.\n- *\n- * @param[in] dev\n- *   Pointer to Ethernet device structure.\n- * @param[in] actions\n- *   Pointer to flow actions array.\n- * @param[in, out] flow\n- *   Pointer to the rte_flow structure.\n- * @param[in] flow_size\n- *   Size in bytes of the available space in @p flow, if too small some\n- *   garbage may be present.\n- * @param[out] error\n- *   Pointer to error structure.\n- *\n- * @return\n- *   On success the number of bytes consumed/necessary, if the returned value\n- *   is lesser or equal to @p flow_size, the @p actions has fully been\n- *   converted, otherwise another call with this returned memory size should\n- *   be done.\n- *   On error, a negative errno value is returned and rte_errno is set.\n- */\n-static int\n-mlx5_flow_actions(struct rte_eth_dev *dev,\n-\t\t  const struct rte_flow_action actions[],\n-\t\t  struct rte_flow *flow, const size_t flow_size,\n-\t\t  struct rte_flow_error *error)\n-{\n-\tsize_t size = 0;\n-\tint remain = flow_size;\n-\tint ret = 0;\n-\n-\tfor (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {\n-\t\tswitch (actions->type) {\n-\t\tcase RTE_FLOW_ACTION_TYPE_VOID:\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ACTION_TYPE_FLAG:\n-\t\t\tret = mlx5_flow_action_flag(flow, remain);\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ACTION_TYPE_MARK:\n-\t\t\tret = mlx5_flow_action_mark(actions, flow, remain);\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ACTION_TYPE_DROP:\n-\t\t\tret = mlx5_flow_action_drop(flow, remain);\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ACTION_TYPE_QUEUE:\n-\t\t\tret = mlx5_flow_action_queue(actions, flow);\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ACTION_TYPE_RSS:\n-\t\t\tret = mlx5_flow_action_rss(actions, flow);\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ACTION_TYPE_COUNT:\n-\t\t\tret = mlx5_flow_action_count(dev, actions, flow, remain,\n-\t\t\t\t\t\t     error);\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\treturn rte_flow_error_set(error, ENOTSUP,\n-\t\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ACTION,\n-\t\t\t\t\t\t  actions,\n-\t\t\t\t\t\t  \"action not supported\");\n-\t\t}\n-\t\tif (ret < 0)\n-\t\t\treturn ret;\n-\t\tif (remain > ret)\n-\t\t\tremain -= ret;\n-\t\telse\n-\t\t\tremain = 0;\n-\t\tsize += ret;\n-\t}\n-\tif (!flow->fate)\n-\t\treturn rte_flow_error_set(error, ENOTSUP,\n-\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,\n-\t\t\t\t\t  NULL,\n-\t\t\t\t\t  \"no fate action found\");\n-\treturn size;\n-}\n-\n-/**\n- * Validate flow rule and fill flow structure accordingly.\n- *\n- * @param dev\n- *   Pointer to Ethernet device.\n- * @param[out] flow\n- *   Pointer to flow structure.\n- * @param flow_size\n- *   Size of allocated space for @p flow.\n- * @param[in] attr\n- *   Flow rule attributes.\n- * @param[in] pattern\n- *   Pattern specification (list terminated by the END pattern item).\n- * @param[in] actions\n- *   Associated actions (list terminated by the END action).\n- * @param[out] error\n- *   Perform verbose error reporting if not NULL.\n- *\n- * @return\n- *   A positive value representing the size of the flow object in bytes\n- *   regardless of @p flow_size on success, a negative errno value otherwise\n- *   and rte_errno is set.\n- */\n-static int\n-mlx5_flow_merge_switch(struct rte_eth_dev *dev,\n-\t\t       struct rte_flow *flow,\n-\t\t       size_t flow_size,\n-\t\t       const struct rte_flow_attr *attr,\n-\t\t       const struct rte_flow_item pattern[],\n-\t\t       const struct rte_flow_action actions[],\n-\t\t       struct rte_flow_error *error)\n-{\n-\tunsigned int n = mlx5_dev_to_port_id(dev->device, NULL, 0);\n-\tuint16_t port_id[!n + n];\n-\tstruct mlx5_nl_flow_ptoi ptoi[!n + n + 1];\n-\tsize_t off = RTE_ALIGN_CEIL(sizeof(*flow), alignof(max_align_t));\n-\tunsigned int i;\n-\tunsigned int own = 0;\n-\tint ret;\n-\n-\t/* At least one port is needed when no switch domain is present. */\n-\tif (!n) {\n-\t\tn = 1;\n-\t\tport_id[0] = dev->data->port_id;\n-\t} else {\n-\t\tn = RTE_MIN(mlx5_dev_to_port_id(dev->device, port_id, n), n);\n-\t}\n-\tfor (i = 0; i != n; ++i) {\n-\t\tstruct rte_eth_dev_info dev_info;\n-\n-\t\trte_eth_dev_info_get(port_id[i], &dev_info);\n-\t\tif (port_id[i] == dev->data->port_id)\n-\t\t\town = i;\n-\t\tptoi[i].port_id = port_id[i];\n-\t\tptoi[i].ifindex = dev_info.if_index;\n-\t}\n-\t/* Ensure first entry of ptoi[] is the current device. */\n-\tif (own) {\n-\t\tptoi[n] = ptoi[0];\n-\t\tptoi[0] = ptoi[own];\n-\t\tptoi[own] = ptoi[n];\n-\t}\n-\t/* An entry with zero ifindex terminates ptoi[]. */\n-\tptoi[n].port_id = 0;\n-\tptoi[n].ifindex = 0;\n-\tif (flow_size < off)\n-\t\tflow_size = 0;\n-\tret = mlx5_nl_flow_transpose((uint8_t *)flow + off,\n-\t\t\t\t     flow_size ? flow_size - off : 0,\n-\t\t\t\t     ptoi, attr, pattern, actions, error);\n-\tif (ret < 0)\n-\t\treturn ret;\n-\tif (flow_size) {\n-\t\t*flow = (struct rte_flow){\n-\t\t\t.attributes = *attr,\n-\t\t\t.nl_flow = (uint8_t *)flow + off,\n-\t\t};\n-\t\t/*\n-\t\t * Generate a reasonably unique handle based on the address\n-\t\t * of the target buffer.\n-\t\t *\n-\t\t * This is straightforward on 32-bit systems where the flow\n-\t\t * pointer can be used directly. Otherwise, its least\n-\t\t * significant part is taken after shifting it by the\n-\t\t * previous power of two of the pointed buffer size.\n-\t\t */\n-\t\tif (sizeof(flow) <= 4)\n-\t\t\tmlx5_nl_flow_brand(flow->nl_flow, (uintptr_t)flow);\n-\t\telse\n-\t\t\tmlx5_nl_flow_brand\n-\t\t\t\t(flow->nl_flow,\n-\t\t\t\t (uintptr_t)flow >>\n-\t\t\t\t rte_log2_u32(rte_align32prevpow2(flow_size)));\n+\tif (!verbs)\n+\t\treturn;\n+\t/* Update Verbs specification. */\n+\thdr = (struct ibv_spec_header *)verbs->specs;\n+\tif (!hdr)\n+\t\treturn;\n+\tfor (i = 0; i != verbs->attr->num_of_specs; ++i) {\n+\t\tif (hdr->type == IBV_FLOW_SPEC_ACTION_TAG) {\n+\t\t\tstruct ibv_flow_spec_action_tag *t =\n+\t\t\t\t(struct ibv_flow_spec_action_tag *)hdr;\n+\n+\t\t\tt->tag_id = mlx5_flow_mark_set(mark_id);\n+\t\t}\n+\t\thdr = (struct ibv_spec_header *)((uintptr_t)hdr + hdr->size);\n \t}\n-\treturn off + ret;\n }\n \n-static unsigned int\n-mlx5_find_graph_root(const struct rte_flow_item pattern[], uint32_t rss_level)\n+/**\n+ * Convert the @p action into a Verbs specification. This function assumes that\n+ * the input is valid and that there is space to insert the requested action\n+ * into the flow. This function also return the action that was added.\n+ *\n+ * @param[in] action\n+ *   Action configuration.\n+ * @param[in, out] action_flags\n+ *   Pointer to the detected actions.\n+ * @param[in] dev_flow\n+ *   Pointer to mlx5_flow.\n+ */\n+static void\n+flow_verbs_translate_action_mark(const struct rte_flow_action *action,\n+\t\t\t\t uint64_t *action_flags,\n+\t\t\t\t struct mlx5_flow *dev_flow)\n {\n-\tconst struct rte_flow_item *item;\n-\tunsigned int has_vlan = 0;\n+\tconst struct rte_flow_action_mark *mark = action->conf;\n+\tunsigned int size = sizeof(struct ibv_flow_spec_action_tag);\n+\tstruct ibv_flow_spec_action_tag tag = {\n+\t\t.type = IBV_FLOW_SPEC_ACTION_TAG,\n+\t\t.size = size,\n+\t};\n+\tstruct mlx5_flow_verbs *verbs = &dev_flow->verbs;\n \n-\tfor (item = pattern; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {\n-\t\tif (item->type == RTE_FLOW_ITEM_TYPE_VLAN) {\n-\t\t\thas_vlan = 1;\n-\t\t\tbreak;\n-\t\t}\n+\tif (*action_flags & MLX5_ACTION_FLAG) {\n+\t\tflow_verbs_mark_update(verbs, mark->id);\n+\t\tsize = 0;\n+\t} else {\n+\t\ttag.tag_id = mlx5_flow_mark_set(mark->id);\n+\t\tmlx5_flow_spec_verbs_add(dev_flow, &tag, size);\n \t}\n-\tif (has_vlan)\n-\t\treturn rss_level < 2 ? MLX5_EXPANSION_ROOT_ETH_VLAN :\n-\t\t\t\t       MLX5_EXPANSION_ROOT_OUTER_ETH_VLAN;\n-\treturn rss_level < 2 ? MLX5_EXPANSION_ROOT :\n-\t\t\t       MLX5_EXPANSION_ROOT_OUTER;\n+\t*action_flags |= MLX5_ACTION_MARK;\n }\n \n /**\n- * Convert the @p attributes, @p pattern, @p action, into an flow for the NIC\n- * after ensuring the NIC will understand and process it correctly.\n- * The conversion is only performed item/action per item/action, each of\n- * them is written into the @p flow if its size is lesser or equal to @p\n- * flow_size.\n- * Validation and memory consumption computation are still performed until the\n- * end, unless an error is encountered.\n+ * Convert the @p action into a Verbs specification. This function assumes that\n+ * the input is valid and that there is space to insert the requested action\n+ * into the flow. This function also return the action that was added.\n  *\n  * @param[in] dev\n- *   Pointer to Ethernet device.\n- * @param[in, out] flow\n- *   Pointer to flow structure.\n- * @param[in] flow_size\n- *   Size in bytes of the available space in @p flow, if too small some\n- *   garbage may be present.\n- * @param[in] attributes\n- *   Flow rule attributes.\n- * @param[in] pattern\n- *   Pattern specification (list terminated by the END pattern item).\n- * @param[in] actions\n- *   Associated actions (list terminated by the END action).\n+ *   Pointer to the Ethernet device structure.\n+ * @param[in] action\n+ *   Action configuration.\n+ * @param[in, out] action_flags\n+ *   Pointer to the detected actions.\n+ * @param[in] dev_flow\n+ *   Pointer to mlx5_flow.\n  * @param[out] error\n- *   Perform verbose error reporting if not NULL.\n+ *   Pointer to error structure.\n  *\n  * @return\n- *   On success the number of bytes consumed/necessary, if the returned value\n- *   is lesser or equal to @p flow_size, the flow has fully been converted and\n- *   can be applied, otherwise another call with this returned memory size\n- *   should be done.\n- *   On error, a negative errno value is returned and rte_errno is set.\n+ *   0 On success else a negative errno value is returned and rte_errno is set.\n  */\n static int\n-mlx5_flow_merge(struct rte_eth_dev *dev, struct rte_flow *flow,\n-\t\tconst size_t flow_size,\n-\t\tconst struct rte_flow_attr *attributes,\n-\t\tconst struct rte_flow_item pattern[],\n-\t\tconst struct rte_flow_action actions[],\n-\t\tstruct rte_flow_error *error)\n+flow_verbs_translate_action_count(struct rte_eth_dev *dev,\n+\t\t\t\t  const struct rte_flow_action *action,\n+\t\t\t\t  uint64_t *action_flags,\n+\t\t\t\t  struct mlx5_flow *dev_flow,\n+\t\t\t\t  struct rte_flow_error *error)\n {\n-\tstruct rte_flow local_flow = { .layers = 0, };\n-\tsize_t size = sizeof(*flow);\n-\tunion {\n-\t\tstruct rte_flow_expand_rss buf;\n-\t\tuint8_t buffer[2048];\n-\t} expand_buffer;\n-\tstruct rte_flow_expand_rss *buf = &expand_buffer.buf;\n-\tstruct mlx5_flow_verbs *original_verbs = NULL;\n-\tsize_t original_verbs_size = 0;\n-\tuint32_t original_layers = 0;\n-\tint expanded_pattern_idx = 0;\n-\tint ret = 0;\n-\tuint32_t i;\n-\n-\tif (attributes->transfer)\n-\t\treturn mlx5_flow_merge_switch(dev, flow, flow_size,\n-\t\t\t\t\t      attributes, pattern,\n-\t\t\t\t\t      actions, error);\n-\tif (size > flow_size)\n-\t\tflow = &local_flow;\n-\tret = mlx5_flow_attributes(dev->data->dev_private, attributes, flow);\n-\tif (ret < 0)\n-\t\treturn ret;\n-\tret = mlx5_flow_actions(dev, actions, &local_flow, 0, error);\n-\tif (ret < 0)\n-\t\treturn ret;\n-\tif (local_flow.rss.types) {\n-\t\tunsigned int graph_root;\n+\tconst struct rte_flow_action_count *count = action->conf;\n+\tstruct rte_flow *flow = dev_flow->flow;\n+#ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT\n+\tunsigned int size = sizeof(struct ibv_flow_spec_counter_action);\n+\tstruct ibv_flow_spec_counter_action counter = {\n+\t\t.type = IBV_FLOW_SPEC_ACTION_COUNT,\n+\t\t.size = size,\n+\t};\n+#endif\n \n-\t\tgraph_root = mlx5_find_graph_root(pattern,\n-\t\t\t\t\t\t  local_flow.rss.level);\n-\t\tret = rte_flow_expand_rss(buf, sizeof(expand_buffer.buffer),\n-\t\t\t\t\t  pattern, local_flow.rss.types,\n-\t\t\t\t\t  mlx5_support_expansion,\n-\t\t\t\t\t  graph_root);\n-\t\tassert(ret > 0 &&\n-\t\t       (unsigned int)ret < sizeof(expand_buffer.buffer));\n-\t} else {\n-\t\tbuf->entries = 1;\n-\t\tbuf->entry[0].pattern = (void *)(uintptr_t)pattern;\n-\t}\n-\tsize += RTE_ALIGN_CEIL(local_flow.rss.queue_num * sizeof(uint16_t),\n-\t\t\t       sizeof(void *));\n-\tif (size <= flow_size)\n-\t\tflow->queue = (void *)(flow + 1);\n-\tLIST_INIT(&flow->verbs);\n-\tflow->layers = 0;\n-\tflow->modifier = 0;\n-\tflow->fate = 0;\n-\tfor (i = 0; i != buf->entries; ++i) {\n-\t\tsize_t off = size;\n-\t\tsize_t off2;\n-\n-\t\tflow->layers = original_layers;\n-\t\tsize += sizeof(struct ibv_flow_attr) +\n-\t\t\tsizeof(struct mlx5_flow_verbs);\n-\t\toff2 = size;\n-\t\tif (size < flow_size) {\n-\t\t\tflow->cur_verbs = (void *)((uintptr_t)flow + off);\n-\t\t\tflow->cur_verbs->attr = (void *)(flow->cur_verbs + 1);\n-\t\t\tflow->cur_verbs->specs =\n-\t\t\t\t(void *)(flow->cur_verbs->attr + 1);\n-\t\t}\n-\t\t/* First iteration convert the pattern into Verbs. */\n-\t\tif (i == 0) {\n-\t\t\t/* Actions don't need to be converted several time. */\n-\t\t\tret = mlx5_flow_actions(dev, actions, flow,\n-\t\t\t\t\t\t(size < flow_size) ?\n-\t\t\t\t\t\tflow_size - size : 0,\n-\t\t\t\t\t\terror);\n-\t\t\tif (ret < 0)\n-\t\t\t\treturn ret;\n-\t\t\tsize += ret;\n-\t\t} else {\n-\t\t\t/*\n-\t\t\t * Next iteration means the pattern has already been\n-\t\t\t * converted and an expansion is necessary to match\n-\t\t\t * the user RSS request.  For that only the expanded\n-\t\t\t * items will be converted, the common part with the\n-\t\t\t * user pattern are just copied into the next buffer\n-\t\t\t * zone.\n-\t\t\t */\n-\t\t\tsize += original_verbs_size;\n-\t\t\tif (size < flow_size) {\n-\t\t\t\trte_memcpy(flow->cur_verbs->attr,\n-\t\t\t\t\t   original_verbs->attr,\n-\t\t\t\t\t   original_verbs_size +\n-\t\t\t\t\t   sizeof(struct ibv_flow_attr));\n-\t\t\t\tflow->cur_verbs->size = original_verbs_size;\n-\t\t\t}\n-\t\t}\n-\t\tret = mlx5_flow_items\n-\t\t\t((const struct rte_flow_item *)\n-\t\t\t &buf->entry[i].pattern[expanded_pattern_idx],\n-\t\t\t flow,\n-\t\t\t (size < flow_size) ? flow_size - size : 0, error);\n-\t\tif (ret < 0)\n-\t\t\treturn ret;\n-\t\tsize += ret;\n-\t\tif (size <= flow_size) {\n-\t\t\tmlx5_flow_adjust_priority(dev, flow);\n-\t\t\tLIST_INSERT_HEAD(&flow->verbs, flow->cur_verbs, next);\n-\t\t}\n-\t\t/*\n-\t\t * Keep a pointer of the first verbs conversion and the layers\n-\t\t * it has encountered.\n-\t\t */\n-\t\tif (i == 0) {\n-\t\t\toriginal_verbs = flow->cur_verbs;\n-\t\t\toriginal_verbs_size = size - off2;\n-\t\t\toriginal_layers = flow->layers;\n-\t\t\t/*\n-\t\t\t * move the index of the expanded pattern to the\n-\t\t\t * first item not addressed yet.\n-\t\t\t */\n-\t\t\tif (pattern->type == RTE_FLOW_ITEM_TYPE_END) {\n-\t\t\t\texpanded_pattern_idx++;\n-\t\t\t} else {\n-\t\t\t\tconst struct rte_flow_item *item = pattern;\n-\n-\t\t\t\tfor (item = pattern;\n-\t\t\t\t     item->type != RTE_FLOW_ITEM_TYPE_END;\n-\t\t\t\t     ++item)\n-\t\t\t\t\texpanded_pattern_idx++;\n-\t\t\t}\n-\t\t}\n+\tif (!flow->counter) {\n+\t\tflow->counter = mlx5_flow_counter_new(dev, count->shared,\n+\t\t\t\t\t\t      count->id);\n+\t\tif (!flow->counter)\n+\t\t\treturn rte_flow_error_set(error, ENOTSUP,\n+\t\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t\t\t  action,\n+\t\t\t\t\t\t  \"cannot get counter\"\n+\t\t\t\t\t\t  \" context.\");\n \t}\n-\t/* Restore the origin layers in the flow. */\n-\tflow->layers = original_layers;\n-\treturn size;\n+\t*action_flags |= MLX5_ACTION_COUNT;\n+#ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT\n+\tcounter.counter_set_handle = flow->counter->cs->handle;\n+\tmlx5_flow_spec_verbs_add(dev_flow, &counter, size);\n+#endif\n+\treturn 0;\n }\n \n /**\n@@ -2212,7 +1585,7 @@ mlx5_flow_rxq_tunnel_ptype_update(struct mlx5_rxq_ctrl *rxq_ctrl)\n  * Set the Rx queue flags (Mark/Flag and Tunnel Ptypes) according to the flow.\n  *\n  * @param[in] dev\n- *   Pointer to Ethernet device.\n+ *   Pointer to the Ethernet device structure.\n  * @param[in] flow\n  *   Pointer to flow structure.\n  */\n@@ -2220,8 +1593,8 @@ static void\n mlx5_flow_rxq_flags_set(struct rte_eth_dev *dev, struct rte_flow *flow)\n {\n \tstruct priv *priv = dev->data->dev_private;\n-\tconst int mark = !!(flow->modifier &\n-\t\t\t    (MLX5_FLOW_MOD_FLAG | MLX5_FLOW_MOD_MARK));\n+\tconst int mark = !!(flow->actions &\n+\t\t\t    (MLX5_ACTION_FLAG | MLX5_ACTION_MARK));\n \tconst int tunnel = !!(flow->layers & MLX5_FLOW_LAYER_TUNNEL);\n \tunsigned int i;\n \n@@ -2264,8 +1637,8 @@ static void\n mlx5_flow_rxq_flags_trim(struct rte_eth_dev *dev, struct rte_flow *flow)\n {\n \tstruct priv *priv = dev->data->dev_private;\n-\tconst int mark = !!(flow->modifier &\n-\t\t\t    (MLX5_FLOW_MOD_FLAG | MLX5_FLOW_MOD_MARK));\n+\tconst int mark = !!(flow->actions &\n+\t\t\t    (MLX5_ACTION_FLAG | MLX5_ACTION_MARK));\n \tconst int tunnel = !!(flow->layers & MLX5_FLOW_LAYER_TUNNEL);\n \tunsigned int i;\n \n@@ -3574,21 +2947,21 @@ mlx5_flow_verbs_get_items_and_size(const struct rte_flow_item items[],\n \t\t\tsize += sizeof(struct ibv_flow_spec_tunnel);\n \t\t\tdetected_items |= MLX5_FLOW_LAYER_VXLAN_GPE;\n \t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_GRE:\n #ifdef HAVE_IBV_DEVICE_MPLS_SUPPORT\n+\t\tcase RTE_FLOW_ITEM_TYPE_GRE:\n \t\t\tsize += sizeof(struct ibv_flow_spec_gre);\n \t\t\tdetected_items |= MLX5_FLOW_LAYER_GRE;\n-#else\n-\t\t\tsize += sizeof(struct ibv_flow_spec_tunnel);\n-\t\t\tdetected_items |= MLX5_FLOW_LAYER_TUNNEL;\n-#endif\n \t\t\tbreak;\n \t\tcase RTE_FLOW_ITEM_TYPE_MPLS:\n-#ifdef HAVE_IBV_DEVICE_MPLS_SUPPORT\n \t\t\tsize += sizeof(struct ibv_flow_spec_mpls);\n \t\t\tdetected_items |= MLX5_FLOW_LAYER_MPLS;\n-#endif\n \t\t\tbreak;\n+#else\n+\t\tcase RTE_FLOW_ITEM_TYPE_GRE:\n+\t\t\tsize += sizeof(struct ibv_flow_spec_tunnel);\n+\t\t\tdetected_items |= MLX5_FLOW_LAYER_TUNNEL;\n+\t\t\tbreak;\n+#endif\n \t\tdefault:\n \t\t\tbreak;\n \t\t}\n@@ -3651,7 +3024,7 @@ mlx5_flow_verbs_prepare(const struct rte_flow_attr *attr __rte_unused,\n \t\t\tuint64_t *action_flags,\n \t\t\tstruct rte_flow_error *error)\n {\n-\tuint32_t size = sizeof(struct ibv_flow_attr);\n+\tuint32_t size = sizeof(struct mlx5_flow) + sizeof(struct ibv_flow_attr);\n \tstruct mlx5_flow *flow;\n \n \tsize += mlx5_flow_verbs_get_actions_and_size(actions, action_flags);\n@@ -3664,10 +3037,150 @@ mlx5_flow_verbs_prepare(const struct rte_flow_attr *attr __rte_unused,\n \t\t\t\t   \"not enough memory to create flow\");\n \t\treturn NULL;\n \t}\n+\tflow->verbs.attr = (void *)(flow + 1);\n+\tflow->verbs.specs = (uint8_t *)(flow + 1) +\n+\t\t\t\tsizeof(struct ibv_flow_attr);\n \treturn flow;\n }\n \n /**\n+ *\n+ * Fill the flow with verb spec.\n+ *\n+ * @param[in] dev\n+ *   Pointer to Ethernet device.\n+ * @param[in, out] dev_flow\n+ *   Pointer to the mlx5 flow.\n+ * @param[in] attr\n+ *   Pointer to the flow attributes.\n+ * @param[in] items\n+ *   Pointer to the list of items.\n+ * @param[in] actions\n+ *   Pointer to the list of actions.\n+ * @param[out] error\n+ *   Pointer to the error structure.\n+ *\n+ * @return\n+ *   0 on success, else a negative errno value otherwise and rte_ernno is set.\n+ */\n+static int mlx5_flow_verbs_translate(struct rte_eth_dev *dev,\n+\t\t\t\t     struct mlx5_flow *dev_flow,\n+\t\t\t\t     const struct rte_flow_attr *attr,\n+\t\t\t\t     const struct rte_flow_item items[],\n+\t\t\t\t     const struct rte_flow_action actions[],\n+\t\t\t\t     struct rte_flow_error *error)\n+{\n+\tuint64_t action_flags = 0;\n+\tuint64_t item_flags = 0;\n+\tuint64_t priority = attr->priority;\n+\tstruct priv *priv = dev->data->dev_private;\n+\n+\tif (priority == MLX5_FLOW_PRIO_RSVD)\n+\t\tpriority = priv->config.flow_prio - 1;\n+\tfor (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {\n+\t\tint ret;\n+\t\tswitch (actions->type) {\n+\t\tcase RTE_FLOW_ACTION_TYPE_VOID:\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_FLAG:\n+\t\t\tflow_verbs_translate_action_flag(actions,\n+\t\t\t\t\t\t\t &action_flags,\n+\t\t\t\t\t\t\t dev_flow);\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_MARK:\n+\t\t\tflow_verbs_translate_action_mark(actions,\n+\t\t\t\t\t\t\t &action_flags,\n+\t\t\t\t\t\t\t dev_flow);\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_DROP:\n+\t\t\tflow_verbs_translate_action_drop(&action_flags,\n+\t\t\t\t\t\t\t dev_flow);\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_QUEUE:\n+\t\t\tflow_verbs_translate_action_queue(actions,\n+\t\t\t\t\t\t\t  &action_flags,\n+\t\t\t\t\t\t\t  dev_flow);\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_RSS:\n+\t\t\tflow_verbs_translate_action_rss(actions,\n+\t\t\t\t\t\t\t&action_flags,\n+\t\t\t\t\t\t\tdev_flow);\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_COUNT:\n+\t\t\tret = flow_verbs_translate_action_count(dev,\n+\t\t\t\t\t\t\t\tactions,\n+\t\t\t\t\t\t\t\t&action_flags,\n+\t\t\t\t\t\t\t\tdev_flow,\n+\t\t\t\t\t\t\t\terror);\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\treturn rte_flow_error_set(error, ENOTSUP,\n+\t\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t\t\t  actions,\n+\t\t\t\t\t\t  \"action not supported\");\n+\t\t}\n+\t}\n+\tdev_flow->flow->actions |= action_flags;\n+\tfor (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {\n+\t\tswitch (items->type) {\n+\t\tcase RTE_FLOW_ITEM_TYPE_VOID:\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_ETH:\n+\t\t\tflow_verbs_translate_item_eth(items, &item_flags,\n+\t\t\t\t\t\t      dev_flow);\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_VLAN:\n+\t\t\tflow_verbs_translate_item_vlan(items, &item_flags,\n+\t\t\t\t\t\t       dev_flow);\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV4:\n+\t\t\tflow_verbs_translate_item_ipv4(items, &item_flags,\n+\t\t\t\t\t\t       dev_flow);\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV6:\n+\t\t\tflow_verbs_translate_item_ipv6(items, &item_flags,\n+\t\t\t\t\t\t       dev_flow);\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_UDP:\n+\t\t\tflow_verbs_translate_item_udp(items, &item_flags,\n+\t\t\t\t\t\t      dev_flow);\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_TCP:\n+\t\t\tflow_verbs_translate_item_tcp(items, &item_flags,\n+\t\t\t\t\t\t      dev_flow);\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_VXLAN:\n+\t\t\tflow_verbs_translate_item_vxlan(items, &item_flags,\n+\t\t\t\t\t\t\tdev_flow);\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_VXLAN_GPE:\n+\t\t\tflow_verbs_translate_item_vxlan_gpe(items, &item_flags,\n+\t\t\t\t\t\t\t    dev_flow);\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_GRE:\n+\t\t\tflow_verbs_translate_item_gre(items, &item_flags,\n+\t\t\t\t\t\t      dev_flow);\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_MPLS:\n+\t\t\tflow_verbs_translate_item_mpls(items, &item_flags,\n+\t\t\t\t\t\t       dev_flow);\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\treturn rte_flow_error_set(error, ENOTSUP,\n+\t\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t\t  NULL,\n+\t\t\t\t\t\t  \"item not supported\");\n+\t\t}\n+\t}\n+\tdev_flow->verbs.attr->priority = mlx5_flow_adjust_priority(dev,\n+\t\t\t\t\tpriority,\n+\t\t\t\t\tdev_flow->verbs.attr->priority);\n+\treturn 0;\n+}\n+\n+/**\n  * Remove the flow.\n  *\n  * @param[in] dev\n@@ -3680,16 +3193,18 @@ mlx5_flow_remove(struct rte_eth_dev *dev, struct rte_flow *flow)\n {\n \tstruct priv *priv = dev->data->dev_private;\n \tstruct mlx5_flow_verbs *verbs;\n+\tstruct mlx5_flow *dev_flow;\n \n \tif (flow->nl_flow && priv->mnl_socket)\n \t\tmlx5_nl_flow_destroy(priv->mnl_socket, flow->nl_flow, NULL);\n-\tLIST_FOREACH(verbs, &flow->verbs, next) {\n+\tLIST_FOREACH(dev_flow, &flow->dev_flows, next) {\n+\t\tverbs = &dev_flow->verbs;\n \t\tif (verbs->flow) {\n \t\t\tclaim_zero(mlx5_glue->destroy_flow(verbs->flow));\n \t\t\tverbs->flow = NULL;\n \t\t}\n \t\tif (verbs->hrxq) {\n-\t\t\tif (flow->fate & MLX5_FLOW_FATE_DROP)\n+\t\t\tif (flow->actions & MLX5_ACTION_DROP)\n \t\t\t\tmlx5_hrxq_drop_release(dev);\n \t\t\telse\n \t\t\t\tmlx5_hrxq_release(dev, verbs->hrxq);\n@@ -3721,10 +3236,12 @@ mlx5_flow_apply(struct rte_eth_dev *dev, struct rte_flow *flow,\n {\n \tstruct priv *priv = dev->data->dev_private;\n \tstruct mlx5_flow_verbs *verbs;\n+\tstruct mlx5_flow *dev_flow;\n \tint err;\n \n-\tLIST_FOREACH(verbs, &flow->verbs, next) {\n-\t\tif (flow->fate & MLX5_FLOW_FATE_DROP) {\n+\tLIST_FOREACH(dev_flow, &flow->dev_flows, next) {\n+\t\tverbs = &dev_flow->verbs;\n+\t\tif (flow->actions & MLX5_ACTION_DROP) {\n \t\t\tverbs->hrxq = mlx5_hrxq_drop_new(dev);\n \t\t\tif (!verbs->hrxq) {\n \t\t\t\trte_flow_error_set\n@@ -3760,8 +3277,8 @@ mlx5_flow_apply(struct rte_eth_dev *dev, struct rte_flow *flow,\n \t\t\t}\n \t\t\tverbs->hrxq = hrxq;\n \t\t}\n-\t\tverbs->flow =\n-\t\t\tmlx5_glue->create_flow(verbs->hrxq->qp, verbs->attr);\n+\t\tverbs->flow = mlx5_glue->create_flow(verbs->hrxq->qp,\n+\t\t\t\t\t\t     verbs->attr);\n \t\tif (!verbs->flow) {\n \t\t\trte_flow_error_set(error, errno,\n \t\t\t\t\t   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,\n@@ -3777,9 +3294,10 @@ mlx5_flow_apply(struct rte_eth_dev *dev, struct rte_flow *flow,\n \treturn 0;\n error:\n \terr = rte_errno; /* Save rte_errno before cleanup. */\n-\tLIST_FOREACH(verbs, &flow->verbs, next) {\n+\tLIST_FOREACH(dev_flow, &flow->dev_flows, next) {\n+\t\tverbs = &dev_flow->verbs;\n \t\tif (verbs->hrxq) {\n-\t\t\tif (flow->fate & MLX5_FLOW_FATE_DROP)\n+\t\t\tif (flow->actions & MLX5_ACTION_DROP)\n \t\t\t\tmlx5_hrxq_drop_release(dev);\n \t\t\telse\n \t\t\t\tmlx5_hrxq_release(dev, verbs->hrxq);\n@@ -3790,6 +3308,25 @@ mlx5_flow_apply(struct rte_eth_dev *dev, struct rte_flow *flow,\n \treturn -rte_errno;\n }\n \n+static unsigned int\n+mlx5_find_graph_root(const struct rte_flow_item pattern[], uint32_t rss_level)\n+{\n+\tconst struct rte_flow_item *item;\n+\tunsigned int has_vlan = 0;\n+\n+\tfor (item = pattern; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {\n+\t\tif (item->type == RTE_FLOW_ITEM_TYPE_VLAN) {\n+\t\t\thas_vlan = 1;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\tif (has_vlan)\n+\t\treturn rss_level < 2 ? MLX5_EXPANSION_ROOT_ETH_VLAN :\n+\t\t\t\t       MLX5_EXPANSION_ROOT_OUTER_ETH_VLAN;\n+\treturn rss_level < 2 ? MLX5_EXPANSION_ROOT :\n+\t\t\t       MLX5_EXPANSION_ROOT_OUTER;\n+}\n+\n /**\n  * Create a flow and add it to @p list.\n  *\n@@ -3819,7 +3356,6 @@ mlx5_flow_list_create(struct rte_eth_dev *dev,\n {\n \tstruct rte_flow *flow = NULL;\n \tstruct mlx5_flow *dev_flow;\n-\tsize_t size = 0;\n \tuint64_t action_flags = 0;\n \tuint64_t item_flags = 0;\n \tconst struct rte_flow_action_rss *rss;\n@@ -3830,13 +3366,21 @@ mlx5_flow_list_create(struct rte_eth_dev *dev,\n \tstruct rte_flow_expand_rss *buf = &expand_buffer.buf;\n \tint ret;\n \tuint32_t i;\n+\tuint32_t flow_size;\n \n \tret = mlx5_flow_validate(dev, attr, items, actions, error);\n \tif (ret < 0)\n \t\treturn NULL;\n-\tflow = rte_calloc(__func__, 1, sizeof(*flow), 0);\n-\tLIST_INIT(&flow->dev_flows);\n+\tflow_size = sizeof(struct rte_flow);\n \trss = mlx5_flow_get_rss_action(actions);\n+\tif (rss)\n+\t\tflow_size += RTE_ALIGN_CEIL(rss->queue_num * sizeof(uint16_t),\n+\t\t\t\t\t    sizeof(void *));\n+\telse\n+\t\tflow_size += RTE_ALIGN_CEIL(sizeof(uint16_t), sizeof(void *));\n+\tflow = rte_calloc(__func__, 1, flow_size, 0);\n+\tflow->queue = (void *)(flow + 1);\n+\tLIST_INIT(&flow->dev_flows);\n \tif (rss && rss->types) {\n \t\tunsigned int graph_root;\n \n@@ -3857,25 +3401,11 @@ mlx5_flow_list_create(struct rte_eth_dev *dev,\n \t\t\t\t\t\t   &action_flags, error);\n \t\tdev_flow->flow = flow;\n \t\tLIST_INSERT_HEAD(&flow->dev_flows, dev_flow, next);\n+\t\tmlx5_flow_verbs_translate(dev, dev_flow, attr,\n+\t\t\t\t\t  buf->entry[i].pattern,\n+\t\t\t\t\t  actions,\n+\t\t\t\t\t  error);\n \t}\n-\tret = mlx5_flow_merge(dev, flow, size, attr, items, actions, error);\n-\tif (ret < 0)\n-\t\treturn NULL;\n-\tsize = ret;\n-\tflow = rte_calloc(__func__, 1, size, 0);\n-\tif (!flow) {\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   \"not enough memory to create flow\");\n-\t\treturn NULL;\n-\t}\n-\tret = mlx5_flow_merge(dev, flow, size, attr, items, actions, error);\n-\tif (ret < 0) {\n-\t\trte_free(flow);\n-\t\treturn NULL;\n-\t}\n-\tassert((size_t)ret == size);\n \tif (dev->data->dev_started) {\n \t\tret = mlx5_flow_apply(dev, flow, error);\n \t\tif (ret < 0) {\n@@ -3933,6 +3463,12 @@ mlx5_flow_list_destroy(struct rte_eth_dev *dev, struct mlx5_flows *list,\n \t */\n \tif (dev->data->dev_started)\n \t\tmlx5_flow_rxq_flags_trim(dev, flow);\n+\twhile (!LIST_EMPTY(&flow->dev_flows)) {\n+\t\tstruct mlx5_flow *dev_flow;\n+\t\tdev_flow = LIST_FIRST(&flow->dev_flows);\n+\t\tLIST_REMOVE(dev_flow, next);\n+\t\trte_free(dev_flow);\n+\t}\n \trte_free(flow);\n }\n \n@@ -4208,7 +3744,7 @@ mlx5_flow_query_count(struct rte_flow *flow __rte_unused,\n \t\t      struct rte_flow_error *error)\n {\n #ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT\n-\tif (flow->modifier & MLX5_FLOW_MOD_COUNT) {\n+\tif (flow->actions & MLX5_ACTION_COUNT) {\n \t\tstruct rte_flow_query_count *qc = data;\n \t\tuint64_t counters[2] = {0, 0};\n \t\tstruct ibv_query_counter_set_attr query_cs_attr = {\n",
    "prefixes": [
        "v3",
        "03/11"
    ]
}