Show a patch.

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

{
    "id": 45253,
    "url": "http://patches.dpdk.org/api/patches/45253/",
    "web_url": "http://patches.dpdk.org/patch/45253/",
    "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-5-yskoh@mellanox.com>",
    "date": "2018-09-24T23:17:42",
    "name": "[v3,04/11] net/mlx5: add support for multiple flow drivers",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "813339a1c92c9ee1ba721aac2b1268c348aed929",
    "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/45253/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/45253/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/45253/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:42.1233\n\t(UTC)",
        "x-ms-office365-filtering-correlation-id": "5698c8a2-3577-49e2-751b-08d62273ecda",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 48A351B125;\n\tTue, 25 Sep 2018 01:17:53 +0200 (CEST)",
            "from EUR02-HE1-obe.outbound.protection.outlook.com\n\t(mail-eopbgr10043.outbound.protection.outlook.com [40.107.1.43])\n\tby dpdk.org (Postfix) with ESMTP id CE5D41B125\n\tfor <dev@dpdk.org>; Tue, 25 Sep 2018 01:17:45 +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:42 +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:42 +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": "AQHUVFzKJgiuVuFmXUq6v/YvQGZ9CA==",
        "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": "<DB3PR0502MB3996FCADE1E63D2ED205E4A3C3170@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:42 +0000",
        "x-ld-processed": "a652971c-7d2e-4d9b-a6a4-d149256f461b,ExtAddr",
        "From": "Yongseok Koh <yskoh@mellanox.com>",
        "Thread-Topic": "[PATCH v3 04/11] net/mlx5: add support for multiple flow\n\tdrivers",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "5698c8a2-3577-49e2-751b-08d62273ecda",
        "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=rqHYjmmojJ+5/nIxxfo7W19coWJKDlsyP1Rd3GVn6MA=;\n\tb=nGE+ihV4KSWvMBlb54wPGVsDJb/ShJ4AVxresi5Arp9ilhjRcMOWJYxRMMLQ9kbnP7oCtYQgh+iHD7kuPFKay2LC0+XulOKjst0L0gmmRAc+o3xRJDy8EO0MGjgaI8u0bHGPsFuN6M5aZA4pV04dc5DeTBj3YzSbiIFUq0HtWVQ=",
        "Message-ID": "<20180924231721.15799-5-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);",
        "X-OriginatorOrg": "Mellanox.com",
        "Return-Path": "<dev-bounces@dpdk.org>",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>",
        "x-microsoft-exchange-diagnostics": "1; DB3PR0502MB3996;\n\t6:wYhM/RvXvRIBEELjZRRLAx+aGaroqh+n1gC4FucbAWLWMeHgEAiDauVgFnOmNzZHIqSLeYFKb50RCxwnlURozzX3eXInSns4VVXQGIjC6MkVgftbGbsoL5XTBxZ0cVSKRHmo39EbbPILjqsOz6wvXHgVo85Ds9EztKQki7WQAkZov/mGqxENwvSh3j6yBAN1JTQofAKsAQZYuo8ZiwmlIHzXpNaR75Zf+lKuzWWG28wuKyMJ4ihk8NatGBvkWriOxDZfkvgMNoLk3ENb7jidbLt3HNsLma/7SYJgkldf+2bv8mHPkmZyRABxEjUW56zlHF2QYuYGNV5byoH6gP9RXvUxRssAyU/dyP9aAUsmd884FZ9X8t7dZtfsjWqDJm+OZzytNOjWO6o1flXntZtiC7ky0tdfAya1QPf3yIfLLM81b1bzCiTbBqo2QanVUvN58BSbSVeyn1MrFsT1ySnLlQ==;\n\t5:s3NymtKLVR145TnnE6PuOt0jM+1l4lJ4Xqz7S3dVDppXddZ8fTzhVxe29Z+ByJ0soZyscV+Sox7Ahwo7sd+Cun5DN8RMsCl+Rgg4D6D2bk1gdYqyFj8UUBZDnJzUcrotBqXdQL4xGLMFUfDJJnqLEI99Jen5CFgDTrMozjjMrfQ=;\n\t7:1A0LQW+3nSF6WUoqdfIs/Yx7NLjgVjiS4VccmIWI3nocMkzP207Xkk4D8fxsaOKbI2xWKdoKHz7tXX90pxqtxb1Bft6mH4c7f1bjX7U652RPnyZhHvXrjZHVDwFU6AeODAoipFgVxNx4pT2GEiuon44c9jeD7E9F1M+rvqcFPfxxFcrlwosPLiqNwHb3cR/kRkNcM9FGojz57u2Rtby4y8zvUbhkAI0jcMAXllLpa9Nvn+kZ7zm5D99ibr/gZPfk",
        "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": "dQRtDcTIHdqEkLz5ZB/fzyJ2QAuZ5vwRb/8xd8G1reqay4aEWx3MGMzNOKNb0Pj2pGIU0Ohwy2GpJEtjWU3HhZIIXhcjcfzyDMQb9z1eN38Cps1rnFl1H7Hw7TuSiqPVdTXqfjwXM8k7JzBHbktUo7oiGswySPRPqAAcoqNkaB8sknEsTP+gf4s6+wGVItChVpw3H27MBzZzcOTn5/b8fVFOnXGjvpiTQ92D+0LADbZXuu3cBUrKTx2Gfan6BRxKekIdvVtvAvlL4/cgAVYDK9H17AMUr+pspz/RPjhPCCBQtWsZwmRPq9nKXA89ikJE/fsFfI9S1AhcA2vVHdyP2ASRALlp7pcVwQ4liWw/UP4=",
        "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 04/11] net/mlx5: add support for multiple flow\n\tdrivers"
    },
    "content": "From: Ori Kam <orika@mellanox.com>\n\nIn the current PMD there is only support for Verbs driver API, to\nconfigure NIC rules and TC driver API, to configure eswitch rules.\nIn order to support new drivers that will enable the use of new features\nfor example the Direct Verbs driver API. There is a need to split each\ndriver to a dedicated file and use function pointer to access the driver.\n\nThis commit moves the Verbs API to a detected file and introduce the\nuse of function pointers in the flow handling.\n\nThe functions pointers that are in use:\n* validate - handle the validation of the flow. It can use both\n             specific functions or shared functions that will be located\n             in the mlx5_flow.c.\n* prepare - allocate a the device flow. There can be number of device\n            flows that are connected to a single requested flow.\n* translate - converts the requested device flow into the driver flow.\n* apply - insert the flow into the NIC.\n* remove - remove the flow from the NIC but keeps it in memory.\n* destroy - remove the flow from memory.\n\nSigned-off-by: Ori Kam <orika@mellanox.com>\nAcked-by: Yongseok Koh <yskoh@mellanox.com>\n---\n drivers/net/mlx5/Makefile          |    1 +\n drivers/net/mlx5/meson.build       |    1 +\n drivers/net/mlx5/mlx5.c            |    2 +\n drivers/net/mlx5/mlx5_flow.c       | 1910 ++----------------------------------\n drivers/net/mlx5/mlx5_flow.h       |  257 +++++\n drivers/net/mlx5/mlx5_flow_verbs.c | 1692 ++++++++++++++++++++++++++++++++\n 6 files changed, 2026 insertions(+), 1837 deletions(-)\n create mode 100644 drivers/net/mlx5/mlx5_flow.h\n create mode 100644 drivers/net/mlx5/mlx5_flow_verbs.c",
    "diff": "diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile\nindex 2e70dec5b..9bd6bfb82 100644\n--- a/drivers/net/mlx5/Makefile\n+++ b/drivers/net/mlx5/Makefile\n@@ -31,6 +31,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_stats.c\n SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_rss.c\n SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_mr.c\n SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_flow.c\n+SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_flow_verbs.c\n SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_socket.c\n SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_nl.c\n SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_nl_flow.c\ndiff --git a/drivers/net/mlx5/meson.build b/drivers/net/mlx5/meson.build\nindex 289c7a4c0..40cc95038 100644\n--- a/drivers/net/mlx5/meson.build\n+++ b/drivers/net/mlx5/meson.build\n@@ -31,6 +31,7 @@ if build\n \t\t'mlx5.c',\n \t\t'mlx5_ethdev.c',\n \t\t'mlx5_flow.c',\n+\t\t'mlx5_flow_verbs.c',\n \t\t'mlx5_mac.c',\n \t\t'mlx5_mr.c',\n \t\t'mlx5_nl.c',\ndiff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c\nindex fd89e2af3..ab44864e9 100644\n--- a/drivers/net/mlx5/mlx5.c\n+++ b/drivers/net/mlx5/mlx5.c\n@@ -46,6 +46,7 @@\n #include \"mlx5_defs.h\"\n #include \"mlx5_glue.h\"\n #include \"mlx5_mr.h\"\n+#include \"mlx5_flow.h\"\n \n /* Device parameter to enable RX completion queue compression. */\n #define MLX5_RXQ_CQE_COMP_EN \"rxq_cqe_comp_en\"\n@@ -1185,6 +1186,7 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,\n \tif (err < 0)\n \t\tgoto error;\n \tpriv->config.flow_prio = err;\n+\tmlx5_flow_init_driver_ops(eth_dev);\n \t/*\n \t * Once the device is added to the list of memory event\n \t * callback, its global MR cache table cannot be expanded\ndiff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c\nindex 2d55f08b8..1c177b9c8 100644\n--- a/drivers/net/mlx5/mlx5_flow.c\n+++ b/drivers/net/mlx5/mlx5_flow.c\n@@ -31,83 +31,12 @@\n #include \"mlx5_defs.h\"\n #include \"mlx5_prm.h\"\n #include \"mlx5_glue.h\"\n+#include \"mlx5_flow.h\"\n \n /* Dev ops structure defined in mlx5.c */\n extern const struct eth_dev_ops mlx5_dev_ops;\n extern const struct eth_dev_ops mlx5_dev_ops_isolate;\n \n-/* Pattern outer Layer bits. */\n-#define MLX5_FLOW_LAYER_OUTER_L2 (1u << 0)\n-#define MLX5_FLOW_LAYER_OUTER_L3_IPV4 (1u << 1)\n-#define MLX5_FLOW_LAYER_OUTER_L3_IPV6 (1u << 2)\n-#define MLX5_FLOW_LAYER_OUTER_L4_UDP (1u << 3)\n-#define MLX5_FLOW_LAYER_OUTER_L4_TCP (1u << 4)\n-#define MLX5_FLOW_LAYER_OUTER_VLAN (1u << 5)\n-\n-/* Pattern inner Layer bits. */\n-#define MLX5_FLOW_LAYER_INNER_L2 (1u << 6)\n-#define MLX5_FLOW_LAYER_INNER_L3_IPV4 (1u << 7)\n-#define MLX5_FLOW_LAYER_INNER_L3_IPV6 (1u << 8)\n-#define MLX5_FLOW_LAYER_INNER_L4_UDP (1u << 9)\n-#define MLX5_FLOW_LAYER_INNER_L4_TCP (1u << 10)\n-#define MLX5_FLOW_LAYER_INNER_VLAN (1u << 11)\n-\n-/* Pattern tunnel Layer bits. */\n-#define MLX5_FLOW_LAYER_VXLAN (1u << 12)\n-#define MLX5_FLOW_LAYER_VXLAN_GPE (1u << 13)\n-#define MLX5_FLOW_LAYER_GRE (1u << 14)\n-#define MLX5_FLOW_LAYER_MPLS (1u << 15)\n-\n-/* Outer Masks. */\n-#define MLX5_FLOW_LAYER_OUTER_L3 \\\n-\t(MLX5_FLOW_LAYER_OUTER_L3_IPV4 | MLX5_FLOW_LAYER_OUTER_L3_IPV6)\n-#define MLX5_FLOW_LAYER_OUTER_L4 \\\n-\t(MLX5_FLOW_LAYER_OUTER_L4_UDP | MLX5_FLOW_LAYER_OUTER_L4_TCP)\n-#define MLX5_FLOW_LAYER_OUTER \\\n-\t(MLX5_FLOW_LAYER_OUTER_L2 | MLX5_FLOW_LAYER_OUTER_L3 | \\\n-\t MLX5_FLOW_LAYER_OUTER_L4)\n-\n-/* Tunnel Masks. */\n-#define MLX5_FLOW_LAYER_TUNNEL \\\n-\t(MLX5_FLOW_LAYER_VXLAN | MLX5_FLOW_LAYER_VXLAN_GPE | \\\n-\t MLX5_FLOW_LAYER_GRE | MLX5_FLOW_LAYER_MPLS)\n-\n-/* Inner Masks. */\n-#define MLX5_FLOW_LAYER_INNER_L3 \\\n-\t(MLX5_FLOW_LAYER_INNER_L3_IPV4 | MLX5_FLOW_LAYER_INNER_L3_IPV6)\n-#define MLX5_FLOW_LAYER_INNER_L4 \\\n-\t(MLX5_FLOW_LAYER_INNER_L4_UDP | MLX5_FLOW_LAYER_INNER_L4_TCP)\n-#define MLX5_FLOW_LAYER_INNER \\\n-\t(MLX5_FLOW_LAYER_INNER_L2 | MLX5_FLOW_LAYER_INNER_L3 | \\\n-\t MLX5_FLOW_LAYER_INNER_L4)\n-\n-/* Actions that modify the fate of matching traffic. */\n-#define MLX5_FLOW_FATE_DROP (1u << 0)\n-#define MLX5_FLOW_FATE_QUEUE (1u << 1)\n-#define MLX5_FLOW_FATE_RSS (1u << 2)\n-\n-/* Modify a packet. */\n-#define MLX5_FLOW_MOD_FLAG (1u << 0)\n-#define MLX5_FLOW_MOD_MARK (1u << 1)\n-#define MLX5_FLOW_MOD_COUNT (1u << 2)\n-\n-/* Actions */\n-#define MLX5_ACTION_DROP (1u << 0)\n-#define MLX5_ACTION_QUEUE (1u << 1)\n-#define MLX5_ACTION_RSS (1u << 2)\n-#define MLX5_ACTION_FLAG (1u << 3)\n-#define MLX5_ACTION_MARK (1u << 4)\n-#define MLX5_ACTION_COUNT (1u << 5)\n-\n-/* possible L3 layers protocols filtering. */\n-#define MLX5_IP_PROTOCOL_TCP 6\n-#define MLX5_IP_PROTOCOL_UDP 17\n-#define MLX5_IP_PROTOCOL_GRE 47\n-#define MLX5_IP_PROTOCOL_MPLS 147\n-\n-/* Priority reserved for default flows. */\n-#define MLX5_FLOW_PRIO_RSVD ((uint32_t)-1)\n-\n enum mlx5_expansion {\n \tMLX5_EXPANSION_ROOT,\n \tMLX5_EXPANSION_ROOT_OUTER,\n@@ -278,57 +207,6 @@ static const struct rte_flow_expand_node mlx5_support_expansion[] = {\n \t},\n };\n \n-/** Handles information leading to a drop fate. */\n-struct mlx5_flow_verbs {\n-\tLIST_ENTRY(mlx5_flow_verbs) next;\n-\tunsigned int size; /**< Size of the attribute. */\n-\tstruct {\n-\t\tstruct ibv_flow_attr *attr;\n-\t\t/**< Pointer to the Specification buffer. */\n-\t\tuint8_t *specs; /**< Pointer to the specifications. */\n-\t};\n-\tstruct ibv_flow *flow; /**< Verbs flow pointer. */\n-\tstruct mlx5_hrxq *hrxq; /**< Hash Rx queue object. */\n-\tuint64_t hash_fields; /**< Verbs hash Rx queue hash fields. */\n-};\n-\n-/** Device flow structure. */\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-};\n-\n-/* Counters information. */\n-struct mlx5_flow_counter {\n-\tLIST_ENTRY(mlx5_flow_counter) next; /**< Pointer to the next counter. */\n-\tuint32_t shared:1; /**< Share counter ID with other flow rules. */\n-\tuint32_t ref_cnt:31; /**< Reference counter. */\n-\tuint32_t id; /**< Counter ID. */\n-\tstruct ibv_counter_set *cs; /**< Holds the counters for the rule. */\n-\tuint64_t hits; /**< Number of packets matched by the rule. */\n-\tuint64_t bytes; /**< Number of bytes matched by the rule. */\n-};\n-\n-/* Flow structure. */\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; /**< Bit-fields that holds the detected layers. */\n-\t/**< Bit-fields of present layers see MLX5_FLOW_LAYER_*. */\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-\tuint16_t (*queue)[]; /**< Destination queues to redirect traffic to. */\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 \t.validate = mlx5_flow_validate,\n \t.create = mlx5_flow_create,\n@@ -364,23 +242,6 @@ struct mlx5_fdir {\n \tstruct rte_flow_action_queue queue;\n };\n \n-/* Verbs specification header. */\n-struct ibv_spec_header {\n-\tenum ibv_flow_spec_type type;\n-\tuint16_t size;\n-};\n-\n-/*\n- * Number of sub priorities.\n- * For each kind of pattern matching i.e. L2, L3, L4 to have a correct\n- * matching on the NIC (firmware dependent) L4 most have the higher priority\n- * followed by L3 and ending with L2.\n- */\n-#define MLX5_PRIORITY_MAP_L2 2\n-#define MLX5_PRIORITY_MAP_L3 1\n-#define MLX5_PRIORITY_MAP_L4 0\n-#define MLX5_PRIORITY_MAP_MAX 3\n-\n /* Map of Verbs to Flow priority with 8 Verbs priorities. */\n static const uint32_t priority_map_3[][MLX5_PRIORITY_MAP_MAX] = {\n \t{ 0, 1, 2 }, { 2, 3, 4 }, { 5, 6, 7 },\n@@ -421,6 +282,9 @@ static struct mlx5_flow_tunnel_info tunnels_info[] = {\n \t},\n };\n \n+/* Holds the nic operations that should be used. */\n+struct mlx5_flow_driver_ops nic_ops;\n+\n /**\n  * Discover the maximum number of priority available.\n  *\n@@ -490,7 +354,7 @@ mlx5_flow_discover_priorities(struct rte_eth_dev *dev)\n }\n \n /**\n- * Adjust flow priority.\n+ * Adjust flow priority based on the highest layer and the request priority.\n  *\n  * @param[in] dev\n  *   Pointer to the Ethernet device structure.\n@@ -502,10 +366,8 @@ mlx5_flow_discover_priorities(struct rte_eth_dev *dev)\n  * @return\n  *   The new priority.\n  */\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+uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,\n+\t\t\t\t   uint32_t subpriority)\n {\n \tuint32_t res = 0;\n \tstruct priv *priv = dev->data->dev_private;\n@@ -522,80 +384,6 @@ mlx5_flow_adjust_priority(struct rte_eth_dev *dev,\n }\n \n /**\n- * Get a flow counter.\n- *\n- * @param[in] dev\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- *   Counter identifier.\n- *\n- * @return\n- *   A pointer to the counter, NULL otherwise and rte_errno is set.\n- */\n-static struct mlx5_flow_counter *\n-mlx5_flow_counter_new(struct rte_eth_dev *dev, uint32_t shared, uint32_t id)\n-{\n-\tstruct priv *priv = dev->data->dev_private;\n-\tstruct mlx5_flow_counter *cnt;\n-\n-\tLIST_FOREACH(cnt, &priv->flow_counters, next) {\n-\t\tif (!cnt->shared || cnt->shared != shared)\n-\t\t\tcontinue;\n-\t\tif (cnt->id != id)\n-\t\t\tcontinue;\n-\t\tcnt->ref_cnt++;\n-\t\treturn cnt;\n-\t}\n-#ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT\n-\n-\tstruct mlx5_flow_counter tmpl = {\n-\t\t.shared = shared,\n-\t\t.id = id,\n-\t\t.cs = mlx5_glue->create_counter_set\n-\t\t\t(priv->ctx,\n-\t\t\t &(struct ibv_counter_set_init_attr){\n-\t\t\t\t .counter_set_id = id,\n-\t\t\t }),\n-\t\t.hits = 0,\n-\t\t.bytes = 0,\n-\t};\n-\n-\tif (!tmpl.cs) {\n-\t\trte_errno = errno;\n-\t\treturn NULL;\n-\t}\n-\tcnt = rte_calloc(__func__, 1, sizeof(*cnt), 0);\n-\tif (!cnt) {\n-\t\trte_errno = ENOMEM;\n-\t\treturn NULL;\n-\t}\n-\t*cnt = tmpl;\n-\tLIST_INSERT_HEAD(&priv->flow_counters, cnt, next);\n-\treturn cnt;\n-#endif\n-\trte_errno = ENOTSUP;\n-\treturn NULL;\n-}\n-\n-/**\n- * Release a flow counter.\n- *\n- * @param[in] counter\n- *   Pointer to the counter handler.\n- */\n-static void\n-mlx5_flow_counter_release(struct mlx5_flow_counter *counter)\n-{\n-\tif (--counter->ref_cnt == 0) {\n-\t\tclaim_zero(mlx5_glue->destroy_counter_set(counter->cs));\n-\t\tLIST_REMOVE(counter, next);\n-\t\trte_free(counter);\n-\t}\n-}\n-\n-/**\n  * Verify the @p item specifications (spec, last, mask) are compatible with the\n  * NIC capabilities.\n  *\n@@ -656,904 +444,6 @@ mlx5_flow_item_acceptable(const struct rte_flow_item *item,\n }\n \n /**\n- * Add a verbs item specification into @p flow.\n- *\n- * @param[in, out] flow\n- *   Pointer to flow structure.\n- * @param[in] src\n- *   Create specification.\n- * @param[in] size\n- *   Size in bytes of the specification to copy.\n- */\n-static void\n-mlx5_flow_spec_verbs_add(struct mlx5_flow *flow, void *src, unsigned int size)\n-{\n-\tstruct mlx5_flow_verbs *verbs = &flow->verbs;\n-\n-\tif (verbs->specs) {\n-\t\tvoid *dst;\n-\n-\t\tdst = (void *)(verbs->specs + verbs->size);\n-\t\tmemcpy(dst, src, size);\n-\t\t++verbs->attr->num_of_specs;\n-\t}\n-\tverbs->size += size;\n-}\n-\n-/**\n- * Adjust verbs hash fields according to the @p flow information.\n- *\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- *   ETH_RSS_* types.\n- * @param[in] hash_fields\n- *   Item hash fields.\n- */\n-static void\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 (rss_request_inner && !tunnel)\n-\t\thash_fields = 0;\n-\telse if (!rss_request_inner && tunnel)\n-\t\thash_fields = 0;\n-#endif\n-\tif (!(dev_flow->flow->rss.types & layer_types))\n-\t\thash_fields = 0;\n-\tdev_flow->verbs.hash_fields |= hash_fields;\n-}\n-\n-/**\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] item_flags\n- *   Bit field with all detected items.\n- * @param[in, out] dev_flow\n- *   Pointer to dev_flow structure.\n- */\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 = !!(*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-\t\t.size = size,\n-\t};\n-\n-\tif (!mask)\n-\t\tmask = &rte_flow_item_eth_mask;\n-\tif (spec) {\n-\t\tunsigned int i;\n-\n-\t\tmemcpy(&eth.val.dst_mac, spec->dst.addr_bytes, ETHER_ADDR_LEN);\n-\t\tmemcpy(&eth.val.src_mac, spec->src.addr_bytes, ETHER_ADDR_LEN);\n-\t\teth.val.ether_type = spec->type;\n-\t\tmemcpy(&eth.mask.dst_mac, mask->dst.addr_bytes, ETHER_ADDR_LEN);\n-\t\tmemcpy(&eth.mask.src_mac, mask->src.addr_bytes, ETHER_ADDR_LEN);\n-\t\teth.mask.ether_type = mask->type;\n-\t\t/* Remove unwanted bits from values. */\n-\t\tfor (i = 0; i < ETHER_ADDR_LEN; ++i) {\n-\t\t\teth.val.dst_mac[i] &= eth.mask.dst_mac[i];\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-\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- * @param[in] eth\n- *   Verbs structure containing the VLAN information to copy.\n- */\n-static void\n-mlx5_flow_item_vlan_update(struct ibv_flow_attr *attr,\n-\t\t\t   struct ibv_flow_spec_eth *eth)\n-{\n-\tunsigned int i;\n-\tconst enum ibv_flow_spec_type search = eth->type;\n-\tstruct ibv_spec_header *hdr = (struct ibv_spec_header *)\n-\t\t((uint8_t *)attr + sizeof(struct ibv_flow_attr));\n-\n-\tfor (i = 0; i != attr->num_of_specs; ++i) {\n-\t\tif (hdr->type == search) {\n-\t\t\tstruct ibv_flow_spec_eth *e =\n-\t\t\t\t(struct ibv_flow_spec_eth *)hdr;\n-\n-\t\t\te->val.vlan_tag = eth->val.vlan_tag;\n-\t\t\te->mask.vlan_tag = eth->mask.vlan_tag;\n-\t\t\te->val.ether_type = eth->val.ether_type;\n-\t\t\te->mask.ether_type = eth->mask.ether_type;\n-\t\t\tbreak;\n-\t\t}\n-\t\thdr = (struct ibv_spec_header *)((uint8_t *)hdr + hdr->size);\n-\t}\n-}\n-\n-/**\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] 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 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 = !!(*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-\t};\n-\tconst uint32_t l2m = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :\n-\t\tMLX5_FLOW_LAYER_OUTER_L2;\n-\n-\tif (!mask)\n-\t\tmask = &rte_flow_item_vlan_mask;\n-\tif (spec) {\n-\t\teth.val.vlan_tag = spec->tci;\n-\t\teth.mask.vlan_tag = mask->tci;\n-\t\teth.val.vlan_tag &= eth.mask.vlan_tag;\n-\t\teth.val.ether_type = spec->inner_type;\n-\t\teth.mask.ether_type = mask->inner_type;\n-\t\teth.val.ether_type &= eth.mask.ether_type;\n-\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\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-\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. 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] 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 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 = !!(*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-\t\t\t(tunnel ? IBV_FLOW_SPEC_INNER : 0),\n-\t\t.size = size,\n-\t};\n-\n-\tif (!mask)\n-\t\tmask = &rte_flow_item_ipv4_mask;\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-\t\t\t.src_ip = spec->hdr.src_addr,\n-\t\t\t.dst_ip = spec->hdr.dst_addr,\n-\t\t\t.proto = spec->hdr.next_proto_id,\n-\t\t\t.tos = spec->hdr.type_of_service,\n-\t\t};\n-\t\tipv4.mask = (struct ibv_flow_ipv4_ext_filter){\n-\t\t\t.src_ip = mask->hdr.src_addr,\n-\t\t\t.dst_ip = mask->hdr.dst_addr,\n-\t\t\t.proto = mask->hdr.next_proto_id,\n-\t\t\t.tos = mask->hdr.type_of_service,\n-\t\t};\n-\t\t/* Remove unwanted bits from values. */\n-\t\tipv4.val.src_ip &= ipv4.mask.src_ip;\n-\t\tipv4.val.dst_ip &= ipv4.mask.dst_ip;\n-\t\tipv4.val.proto &= ipv4.mask.proto;\n-\t\tipv4.val.tos &= ipv4.mask.tos;\n-\t}\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. 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] 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 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 = !!(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-\t\t.size = size,\n-\t};\n-\n-\tif (!mask)\n-\t\tmask = &rte_flow_item_ipv6_mask;\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-\t\tuint32_t vtc_flow_mask;\n-\n-\t\tmemcpy(&ipv6.val.src_ip, spec->hdr.src_addr,\n-\t\t       RTE_DIM(ipv6.val.src_ip));\n-\t\tmemcpy(&ipv6.val.dst_ip, spec->hdr.dst_addr,\n-\t\t       RTE_DIM(ipv6.val.dst_ip));\n-\t\tmemcpy(&ipv6.mask.src_ip, mask->hdr.src_addr,\n-\t\t       RTE_DIM(ipv6.mask.src_ip));\n-\t\tmemcpy(&ipv6.mask.dst_ip, mask->hdr.dst_addr,\n-\t\t       RTE_DIM(ipv6.mask.dst_ip));\n-\t\tvtc_flow_val = rte_be_to_cpu_32(spec->hdr.vtc_flow);\n-\t\tvtc_flow_mask = rte_be_to_cpu_32(mask->hdr.vtc_flow);\n-\t\tipv6.val.flow_label =\n-\t\t\trte_cpu_to_be_32((vtc_flow_val & IPV6_HDR_FL_MASK) >>\n-\t\t\t\t\t IPV6_HDR_FL_SHIFT);\n-\t\tipv6.val.traffic_class = (vtc_flow_val & IPV6_HDR_TC_MASK) >>\n-\t\t\t\t\t IPV6_HDR_TC_SHIFT;\n-\t\tipv6.val.next_hdr = spec->hdr.proto;\n-\t\tipv6.val.hop_limit = spec->hdr.hop_limits;\n-\t\tipv6.mask.flow_label =\n-\t\t\trte_cpu_to_be_32((vtc_flow_mask & IPV6_HDR_FL_MASK) >>\n-\t\t\t\t\t IPV6_HDR_FL_SHIFT);\n-\t\tipv6.mask.traffic_class = (vtc_flow_mask & IPV6_HDR_TC_MASK) >>\n-\t\t\t\t\t  IPV6_HDR_TC_SHIFT;\n-\t\tipv6.mask.next_hdr = mask->hdr.proto;\n-\t\tipv6.mask.hop_limit = mask->hdr.hop_limits;\n-\t\t/* Remove unwanted bits from values. */\n-\t\tfor (i = 0; i < RTE_DIM(ipv6.val.src_ip); ++i) {\n-\t\t\tipv6.val.src_ip[i] &= ipv6.mask.src_ip[i];\n-\t\t\tipv6.val.dst_ip[i] &= ipv6.mask.dst_ip[i];\n-\t\t}\n-\t\tipv6.val.flow_label &= ipv6.mask.flow_label;\n-\t\tipv6.val.traffic_class &= ipv6.mask.traffic_class;\n-\t\tipv6.val.next_hdr &= ipv6.mask.next_hdr;\n-\t\tipv6.val.hop_limit &= ipv6.mask.hop_limit;\n-\t}\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. 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] 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 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 = !!(*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-\t\t.size = size,\n-\t};\n-\n-\tif (!mask)\n-\t\tmask = &rte_flow_item_udp_mask;\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-\t\tudp.mask.dst_port = mask->hdr.dst_port;\n-\t\tudp.mask.src_port = mask->hdr.src_port;\n-\t\t/* Remove unwanted bits from values. */\n-\t\tudp.val.src_port &= udp.mask.src_port;\n-\t\tudp.val.dst_port &= udp.mask.dst_port;\n-\t}\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. 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] 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 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 = !!(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-\t\t.size = size,\n-\t};\n-\n-\tif (!mask)\n-\t\tmask = &rte_flow_item_tcp_mask;\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-\t\ttcp.mask.dst_port = mask->hdr.dst_port;\n-\t\ttcp.mask.src_port = mask->hdr.src_port;\n-\t\t/* Remove unwanted bits from values. */\n-\t\ttcp.val.src_port &= tcp.mask.src_port;\n-\t\ttcp.val.dst_port &= tcp.mask.dst_port;\n-\t}\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. 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] 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 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-\tunsigned int size = sizeof(struct ibv_flow_spec_tunnel);\n-\tstruct ibv_flow_spec_tunnel vxlan = {\n-\t\t.type = IBV_FLOW_SPEC_VXLAN_TUNNEL,\n-\t\t.size = size,\n-\t};\n-\tunion vni {\n-\t\tuint32_t vlan_id;\n-\t\tuint8_t vni[4];\n-\t} id = { .vlan_id = 0, };\n-\n-\tif (!mask)\n-\t\tmask = &rte_flow_item_vxlan_mask;\n-\tif (spec) {\n-\t\tmemcpy(&id.vni[1], spec->vni, 3);\n-\t\tvxlan.val.tunnel_id = id.vlan_id;\n-\t\tmemcpy(&id.vni[1], mask->vni, 3);\n-\t\tvxlan.mask.tunnel_id = id.vlan_id;\n-\t\t/* Remove unwanted bits from values. */\n-\t\tvxlan.val.tunnel_id &= vxlan.mask.tunnel_id;\n-\t}\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. 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] 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 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-\tunsigned int size = sizeof(struct ibv_flow_spec_tunnel);\n-\tstruct ibv_flow_spec_tunnel vxlan_gpe = {\n-\t\t.type = IBV_FLOW_SPEC_VXLAN_TUNNEL,\n-\t\t.size = size,\n-\t};\n-\tunion vni {\n-\t\tuint32_t vlan_id;\n-\t\tuint8_t vni[4];\n-\t} id = { .vlan_id = 0, };\n-\n-\tif (!mask)\n-\t\tmask = &rte_flow_item_vxlan_gpe_mask;\n-\tif (spec) {\n-\t\tmemcpy(&id.vni[1], spec->vni, 3);\n-\t\tvxlan_gpe.val.tunnel_id = id.vlan_id;\n-\t\tmemcpy(&id.vni[1], mask->vni, 3);\n-\t\tvxlan_gpe.mask.tunnel_id = id.vlan_id;\n-\t\t/* Remove unwanted bits from values. */\n-\t\tvxlan_gpe.val.tunnel_id &= vxlan_gpe.mask.tunnel_id;\n-\t}\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- * Update the protocol in Verbs IPv4/IPv6 spec.\n- *\n- * @param[in, out] attr\n- *   Pointer to Verbs attributes structure.\n- * @param[in] search\n- *   Specification type to search in order to update the IP protocol.\n- * @param[in] protocol\n- *   Protocol value to set if none is present in the specification.\n- */\n-static void\n-mlx5_flow_item_gre_ip_protocol_update(struct ibv_flow_attr *attr,\n-\t\t\t\t      enum ibv_flow_spec_type search,\n-\t\t\t\t      uint8_t protocol)\n-{\n-\tunsigned int i;\n-\tstruct ibv_spec_header *hdr = (struct ibv_spec_header *)\n-\t\t((uint8_t *)attr + sizeof(struct ibv_flow_attr));\n-\n-\tif (!attr)\n-\t\treturn;\n-\tfor (i = 0; i != attr->num_of_specs; ++i) {\n-\t\tif (hdr->type == search) {\n-\t\t\tunion {\n-\t\t\t\tstruct ibv_flow_spec_ipv4_ext *ipv4;\n-\t\t\t\tstruct ibv_flow_spec_ipv6 *ipv6;\n-\t\t\t} ip;\n-\n-\t\t\tswitch (search) {\n-\t\t\tcase IBV_FLOW_SPEC_IPV4_EXT:\n-\t\t\t\tip.ipv4 = (struct ibv_flow_spec_ipv4_ext *)hdr;\n-\t\t\t\tif (!ip.ipv4->val.proto) {\n-\t\t\t\t\tip.ipv4->val.proto = protocol;\n-\t\t\t\t\tip.ipv4->mask.proto = 0xff;\n-\t\t\t\t}\n-\t\t\t\tbreak;\n-\t\t\tcase IBV_FLOW_SPEC_IPV6:\n-\t\t\t\tip.ipv6 = (struct ibv_flow_spec_ipv6 *)hdr;\n-\t\t\t\tif (!ip.ipv6->val.next_hdr) {\n-\t\t\t\t\tip.ipv6->val.next_hdr = protocol;\n-\t\t\t\t\tip.ipv6->mask.next_hdr = 0xff;\n-\t\t\t\t}\n-\t\t\t\tbreak;\n-\t\t\tdefault:\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tbreak;\n-\t\t}\n-\t\thdr = (struct ibv_spec_header *)((uint8_t *)hdr + hdr->size);\n-\t}\n-}\n-\n-/**\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] 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 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 = &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-\tstruct ibv_flow_spec_gre tunnel = {\n-\t\t.type = IBV_FLOW_SPEC_GRE,\n-\t\t.size = size,\n-\t};\n-\n-\tif (!mask)\n-\t\tmask = &rte_flow_item_gre_mask;\n-\tif (spec) {\n-\t\ttunnel.val.c_ks_res0_ver = spec->c_rsvd0_ver;\n-\t\ttunnel.val.protocol = spec->protocol;\n-\t\ttunnel.mask.c_ks_res0_ver = mask->c_rsvd0_ver;\n-\t\ttunnel.mask.protocol = mask->protocol;\n-\t\t/* Remove unwanted bits from values. */\n-\t\ttunnel.val.c_ks_res0_ver &= tunnel.mask.c_ks_res0_ver;\n-\t\ttunnel.val.protocol &= tunnel.mask.protocol;\n-\t\ttunnel.val.key &= tunnel.mask.key;\n-\t}\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 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] 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 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-\tconst struct rte_flow_item_mpls *mask = item->mask;\n-\tunsigned int size = sizeof(struct ibv_flow_spec_mpls);\n-\tstruct ibv_flow_spec_mpls mpls = {\n-\t\t.type = IBV_FLOW_SPEC_MPLS,\n-\t\t.size = size,\n-\t};\n-\n-\tif (!mask)\n-\t\tmask = &rte_flow_item_mpls_mask;\n-\tif (spec) {\n-\t\tmemcpy(&mpls.val.label, spec, sizeof(mpls.val.label));\n-\t\tmemcpy(&mpls.mask.label, mask, sizeof(mpls.mask.label));\n-\t\t/* Remove unwanted bits from values.  */\n-\t\tmpls.val.label &= mpls.mask.label;\n-\t}\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. 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] 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_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-\t\t\t.type = IBV_FLOW_SPEC_ACTION_DROP,\n-\t\t\t.size = size,\n-\t};\n-\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 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_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-\t*action_flags |= MLX5_ACTION_QUEUE;\n-}\n-\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_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-\t\t       rss->queue_num * sizeof(uint16_t));\n-\tflow->rss.queue_num = rss->queue_num;\n-\tmemcpy(flow->key, rss->key, MLX5_RSS_HASH_KEY_LEN);\n-\tflow->rss.types = rss->types;\n-\tflow->rss.level = rss->level;\n-\t*action_flags |= MLX5_ACTION_RSS;\n-}\n-\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_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-\t\t.type = IBV_FLOW_SPEC_ACTION_TAG,\n-\t\t.size = size,\n-\t\t.tag_id = mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT),\n-\t};\n-\t*action_flags |= MLX5_ACTION_MARK;\n-\tmlx5_flow_spec_verbs_add(dev_flow, &tag, size);\n-}\n-\n-/**\n- * Update verbs specification to modify the flag to mark.\n- *\n- * @param[in, out] verbs\n- *   Pointer to the mlx5_flow_verbs structure.\n- * @param[in] mark_id\n- *   Mark identifier to replace the flag.\n- */\n-static void\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 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_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-\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-\t*action_flags |= MLX5_ACTION_MARK;\n-}\n-\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] dev\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- *   Pointer to error structure.\n- *\n- * @return\n- *   0 On success else a negative errno value is returned and rte_errno is set.\n- */\n-static int\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-\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-\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*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  * Lookup and set the ptype in the data Rx part.  A single Ptype can be used,\n  * if several tunnel rules are used on this queue, the tunnel ptype will be\n  * cleared.\n@@ -1708,7 +598,7 @@ mlx5_flow_rxq_flags_clear(struct rte_eth_dev *dev)\n  * @return\n  *   0 on success, a negative errno value otherwise and rte_errno is set.\n  */\n-static int\n+int\n mlx5_flow_validate_action_flag(uint64_t action_flags,\n \t\t\t       struct rte_flow_error *error)\n {\n@@ -1742,7 +632,7 @@ mlx5_flow_validate_action_flag(uint64_t action_flags,\n  * @return\n  *   0 on success, a negative errno value otherwise and rte_errno is set.\n  */\n-static int\n+int\n mlx5_flow_validate_action_mark(const struct rte_flow_action *action,\n \t\t\t       uint64_t action_flags,\n \t\t\t       struct rte_flow_error *error)\n@@ -1787,7 +677,7 @@ mlx5_flow_validate_action_mark(const struct rte_flow_action *action,\n  * @return\n  *   0 on success, a negative errno value otherwise and rte_ernno is set.\n  */\n-static int\n+int\n mlx5_flow_validate_action_drop(uint64_t action_flags,\n \t\t\t       struct rte_flow_error *error)\n {\n@@ -1823,7 +713,7 @@ mlx5_flow_validate_action_drop(uint64_t action_flags,\n  * @return\n  *   0 on success, a negative errno value otherwise and rte_ernno is set.\n  */\n-static int\n+int\n mlx5_flow_validate_action_queue(const struct rte_flow_action *action,\n \t\t\t\tuint64_t action_flags,\n \t\t\t\tstruct rte_eth_dev *dev,\n@@ -1866,7 +756,7 @@ mlx5_flow_validate_action_queue(const struct rte_flow_action *action,\n  * @return\n  *   0 on success, a negative errno value otherwise and rte_ernno is set.\n  */\n-static int\n+int\n mlx5_flow_validate_action_rss(const struct rte_flow_action *action,\n \t\t\t      uint64_t action_flags,\n \t\t\t      struct rte_eth_dev *dev,\n@@ -1938,7 +828,7 @@ mlx5_flow_validate_action_rss(const struct rte_flow_action *action,\n  * @return\n  *   0 on success, a negative errno value otherwise and rte_ernno is set.\n  */\n-static int\n+int\n mlx5_flow_validate_action_count(struct rte_eth_dev *dev,\n \t\t\t\tstruct rte_flow_error *error)\n {\n@@ -1965,7 +855,7 @@ mlx5_flow_validate_action_count(struct rte_eth_dev *dev,\n  * @return\n  *   0 on success, a negative errno value otherwise and rte_errno is set.\n  */\n-static int\n+int\n mlx5_flow_validate_attributes(struct rte_eth_dev *dev,\n \t\t\t      const struct rte_flow_attr *attributes,\n \t\t\t      struct rte_flow_error *error)\n@@ -2011,7 +901,7 @@ mlx5_flow_validate_attributes(struct rte_eth_dev *dev,\n  * @return\n  *   0 on success, a negative errno value otherwise and rte_errno is set.\n  */\n-static int\n+int\n mlx5_flow_validate_item_eth(const struct rte_flow_item *item,\n \t\t\t    uint64_t item_flags,\n \t\t\t    struct rte_flow_error *error)\n@@ -2055,7 +945,7 @@ mlx5_flow_validate_item_eth(const struct rte_flow_item *item,\n  * @return\n  *   0 on success, a negative errno value otherwise and rte_errno is set.\n  */\n-static int\n+int\n mlx5_flow_validate_item_vlan(const struct rte_flow_item *item,\n \t\t\t     int64_t item_flags,\n \t\t\t     struct rte_flow_error *error)\n@@ -2116,7 +1006,7 @@ mlx5_flow_validate_item_vlan(const struct rte_flow_item *item,\n  * @return\n  *   0 on success, a negative errno value otherwise and rte_errno is set.\n  */\n-static int\n+int\n mlx5_flow_validate_item_ipv4(const struct rte_flow_item *item,\n \t\t\t     int64_t item_flags,\n \t\t\t     struct rte_flow_error *error)\n@@ -2167,7 +1057,7 @@ mlx5_flow_validate_item_ipv4(const struct rte_flow_item *item,\n  * @return\n  *   0 on success, a negative errno value otherwise and rte_errno is set.\n  */\n-static int\n+int\n mlx5_flow_validate_item_ipv6(const struct rte_flow_item *item,\n \t\t\t     uint64_t item_flags,\n \t\t\t     struct rte_flow_error *error)\n@@ -2236,7 +1126,7 @@ mlx5_flow_validate_item_ipv6(const struct rte_flow_item *item,\n  * @return\n  *   0 on success, a negative errno value otherwise and rte_errno is set.\n  */\n-static int\n+int\n mlx5_flow_validate_item_udp(const struct rte_flow_item *item,\n \t\t\t    uint64_t item_flags,\n \t\t\t    uint8_t target_protocol,\n@@ -2287,7 +1177,7 @@ mlx5_flow_validate_item_udp(const struct rte_flow_item *item,\n  * @return\n  *   0 on success, a negative errno value otherwise and rte_errno is set.\n  */\n-static int\n+int\n mlx5_flow_validate_item_tcp(const struct rte_flow_item *item,\n \t\t\t    uint64_t item_flags,\n \t\t\t    uint8_t target_protocol,\n@@ -2338,7 +1228,7 @@ mlx5_flow_validate_item_tcp(const struct rte_flow_item *item,\n  * @return\n  *   0 on success, a negative errno value otherwise and rte_errno is set.\n  */\n-static int\n+int\n mlx5_flow_validate_item_vxlan(const struct rte_flow_item *item,\n \t\t\t      uint64_t item_flags,\n \t\t\t      struct rte_flow_error *error)\n@@ -2417,7 +1307,7 @@ mlx5_flow_validate_item_vxlan(const struct rte_flow_item *item,\n  * @return\n  *   0 on success, a negative errno value otherwise and rte_errno is set.\n  */\n-static int\n+int\n mlx5_flow_validate_item_vxlan_gpe(const struct rte_flow_item *item,\n \t\t\t\t  uint64_t item_flags,\n \t\t\t\t  struct rte_eth_dev *dev,\n@@ -2507,7 +1397,7 @@ mlx5_flow_validate_item_vxlan_gpe(const struct rte_flow_item *item,\n  * @return\n  *   0 on success, a negative errno value otherwise and rte_errno is set.\n  */\n-static int\n+int\n mlx5_flow_validate_item_gre(const struct rte_flow_item *item,\n \t\t\t    uint64_t item_flags,\n \t\t\t    uint8_t target_protocol,\n@@ -2564,7 +1454,7 @@ mlx5_flow_validate_item_gre(const struct rte_flow_item *item,\n  * @return\n  *   0 on success, a negative errno value otherwise and rte_errno is set.\n  */\n-static int\n+int\n mlx5_flow_validate_item_mpls(const struct rte_flow_item *item __rte_unused,\n \t\t\t     uint64_t item_flags __rte_unused,\n \t\t\t     uint8_t target_protocol __rte_unused,\n@@ -2582,225 +1472,22 @@ mlx5_flow_validate_item_mpls(const struct rte_flow_item *item __rte_unused,\n \tif (item_flags & MLX5_FLOW_LAYER_TUNNEL)\n \t\treturn rte_flow_error_set(error, ENOTSUP,\n \t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ITEM, item,\n-\t\t\t\t\t  \"a tunnel is already\"\n-\t\t\t\t\t  \" present\");\n-\tif (!mask)\n-\t\tmask = &rte_flow_item_mpls_mask;\n-\tret = mlx5_flow_item_acceptable\n-\t\t(item, (const uint8_t *)mask,\n-\t\t (const uint8_t *)&rte_flow_item_mpls_mask,\n-\t\t sizeof(struct rte_flow_item_mpls), error);\n-\tif (ret < 0)\n-\t\treturn ret;\n-\treturn 0;\n-#endif\n-\treturn rte_flow_error_set(error, ENOTSUP,\n-\t\t\t\t  RTE_FLOW_ERROR_TYPE_ITEM, item,\n-\t\t\t\t  \"MPLS is not supported by Verbs, please\"\n-\t\t\t\t  \" update.\");\n-}\n-\n-/**\n- * Internal validation function.\n- *\n- * @param[in] dev\n- *   Pointer to the Ethernet device structure.\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, a negative errno value otherwise and rte_ernno is set.\n- */\n-static int mlx5_flow_verbs_validate(struct rte_eth_dev *dev,\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-\tint ret;\n-\tuint32_t action_flags = 0;\n-\tuint32_t item_flags = 0;\n-\tint tunnel = 0;\n-\tuint8_t next_protocol = 0xff;\n-\n-\tif (items == NULL)\n-\t\treturn -1;\n-\tret = mlx5_flow_validate_attributes(dev, attr, error);\n+\t\t\t\t\t  \"a tunnel is already\"\n+\t\t\t\t\t  \" present\");\n+\tif (!mask)\n+\t\tmask = &rte_flow_item_mpls_mask;\n+\tret = mlx5_flow_item_acceptable\n+\t\t(item, (const uint8_t *)mask,\n+\t\t (const uint8_t *)&rte_flow_item_mpls_mask,\n+\t\t sizeof(struct rte_flow_item_mpls), error);\n \tif (ret < 0)\n \t\treturn ret;\n-\tfor (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {\n-\t\tint ret = 0;\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\tret = mlx5_flow_validate_item_eth(items, item_flags,\n-\t\t\t\t\t\t\t  error);\n-\t\t\tif (ret < 0)\n-\t\t\t\treturn ret;\n-\t\t\titem_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L2 :\n-\t\t\t\t\t       MLX5_FLOW_LAYER_OUTER_L2;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_VLAN:\n-\t\t\tret = mlx5_flow_validate_item_vlan(items, item_flags,\n-\t\t\t\t\t\t\t   error);\n-\t\t\tif (ret < 0)\n-\t\t\t\treturn ret;\n-\t\t\titem_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_VLAN :\n-\t\t\t\t\t       MLX5_FLOW_LAYER_OUTER_VLAN;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_IPV4:\n-\t\t\tret = mlx5_flow_validate_item_ipv4(items, item_flags,\n-\t\t\t\t\t\t\t   error);\n-\t\t\tif (ret < 0)\n-\t\t\t\treturn ret;\n-\t\t\titem_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :\n-\t\t\t\t\t       MLX5_FLOW_LAYER_OUTER_L3_IPV4;\n-\t\t\tif (items->mask != NULL &&\n-\t\t\t    ((const struct rte_flow_item_ipv4 *)\n-\t\t\t     items->mask)->hdr.next_proto_id)\n-\t\t\t\tnext_protocol =\n-\t\t\t\t\t((const struct rte_flow_item_ipv4 *)\n-\t\t\t\t\t (items->spec))->hdr.next_proto_id;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_IPV6:\n-\t\t\tret = mlx5_flow_validate_item_ipv6(items, item_flags,\n-\t\t\t\t\t\t\t   error);\n-\t\t\tif (ret < 0)\n-\t\t\t\treturn ret;\n-\t\t\titem_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :\n-\t\t\t\t\t       MLX5_FLOW_LAYER_OUTER_L3_IPV6;\n-\t\t\tif (items->mask != NULL &&\n-\t\t\t    ((const struct rte_flow_item_ipv6 *)\n-\t\t\t     items->mask)->hdr.proto)\n-\t\t\t\tnext_protocol =\n-\t\t\t\t\t((const struct rte_flow_item_ipv6 *)\n-\t\t\t\t\t items->spec)->hdr.proto;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_UDP:\n-\t\t\tret = mlx5_flow_validate_item_udp(items, item_flags,\n-\t\t\t\t\t\t\t  next_protocol,\n-\t\t\t\t\t\t\t  error);\n-\t\t\tif (ret < 0)\n-\t\t\t\treturn ret;\n-\t\t\titem_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :\n-\t\t\t\t\t       MLX5_FLOW_LAYER_OUTER_L4_UDP;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_TCP:\n-\t\t\tret = mlx5_flow_validate_item_tcp(items, item_flags,\n-\t\t\t\t\t\t\t  next_protocol, error);\n-\t\t\tif (ret < 0)\n-\t\t\t\treturn ret;\n-\t\t\titem_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :\n-\t\t\t\t\t       MLX5_FLOW_LAYER_OUTER_L4_TCP;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_VXLAN:\n-\t\t\tret = mlx5_flow_validate_item_vxlan(items, item_flags,\n-\t\t\t\t\t\t\t    error);\n-\t\t\tif (ret < 0)\n-\t\t\t\treturn ret;\n-\t\t\titem_flags |= MLX5_FLOW_LAYER_VXLAN;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_VXLAN_GPE:\n-\t\t\tret = mlx5_flow_validate_item_vxlan_gpe(items,\n-\t\t\t\t\t\t\t\titem_flags,\n-\t\t\t\t\t\t\t\tdev, error);\n-\t\t\tif (ret < 0)\n-\t\t\t\treturn ret;\n-\t\t\titem_flags |= MLX5_FLOW_LAYER_VXLAN_GPE;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_GRE:\n-\t\t\tret = mlx5_flow_validate_item_gre(items, item_flags,\n-\t\t\t\t\t\t\t  next_protocol, error);\n-\t\t\tif (ret < 0)\n-\t\t\t\treturn ret;\n-\t\t\titem_flags |= MLX5_FLOW_LAYER_GRE;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_MPLS:\n-\t\t\tret = mlx5_flow_validate_item_mpls(items, item_flags,\n-\t\t\t\t\t\t\t   next_protocol,\n-\t\t\t\t\t\t\t   error);\n-\t\t\tif (ret < 0)\n-\t\t\t\treturn ret;\n-\t\t\tif (next_protocol != 0xff &&\n-\t\t\t    next_protocol != MLX5_IP_PROTOCOL_MPLS)\n-\t\t\t\treturn rte_flow_error_set\n-\t\t\t\t\t(error, ENOTSUP,\n-\t\t\t\t\t RTE_FLOW_ERROR_TYPE_ITEM, items,\n-\t\t\t\t\t \"protocol filtering not compatible\"\n-\t\t\t\t\t \" with MPLS layer\");\n-\t\t\titem_flags |= MLX5_FLOW_LAYER_MPLS;\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-\tfor (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {\n-\t\ttunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);\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_validate_action_flag(action_flags,\n-\t\t\t\t\t\t\t     error);\n-\t\t\tif (ret < 0)\n-\t\t\t\treturn ret;\n-\t\t\taction_flags |= MLX5_ACTION_FLAG;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ACTION_TYPE_MARK:\n-\t\t\tret = mlx5_flow_validate_action_mark(actions,\n-\t\t\t\t\t\t\t     action_flags,\n-\t\t\t\t\t\t\t     error);\n-\t\t\tif (ret < 0)\n-\t\t\t\treturn ret;\n-\t\t\taction_flags |= MLX5_ACTION_MARK;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ACTION_TYPE_DROP:\n-\t\t\tret = mlx5_flow_validate_action_drop(action_flags,\n-\t\t\t\t\t\t\t     error);\n-\t\t\tif (ret < 0)\n-\t\t\t\treturn ret;\n-\t\t\taction_flags |= MLX5_ACTION_DROP;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ACTION_TYPE_QUEUE:\n-\t\t\tret = mlx5_flow_validate_action_queue(actions,\n-\t\t\t\t\t\t\t      action_flags, dev,\n-\t\t\t\t\t\t\t      error);\n-\t\t\tif (ret < 0)\n-\t\t\t\treturn ret;\n-\t\t\taction_flags |= MLX5_ACTION_QUEUE;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ACTION_TYPE_RSS:\n-\t\t\tret = mlx5_flow_validate_action_rss(actions,\n-\t\t\t\t\t\t\t    action_flags, dev,\n-\t\t\t\t\t\t\t    error);\n-\t\t\tif (ret < 0)\n-\t\t\t\treturn ret;\n-\t\t\taction_flags |= MLX5_ACTION_RSS;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ACTION_TYPE_COUNT:\n-\t\t\tret = mlx5_flow_validate_action_count(dev, error);\n-\t\t\tif (ret < 0)\n-\t\t\t\treturn ret;\n-\t\t\taction_flags |= MLX5_ACTION_COUNT;\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 \treturn 0;\n+#endif\n+\treturn rte_flow_error_set(error, ENOTSUP,\n+\t\t\t\t  RTE_FLOW_ERROR_TYPE_ITEM, item,\n+\t\t\t\t  \"MPLS is not supported by Verbs, please\"\n+\t\t\t\t  \" update.\");\n }\n \n /**\n@@ -2818,159 +1505,13 @@ mlx5_flow_validate(struct rte_eth_dev *dev,\n {\n \tint ret;\n \n-\tret =  mlx5_flow_verbs_validate(dev, attr, items, actions, error);\n+\tret =  nic_ops.validate(dev, attr, items, actions, error);\n \tif (ret < 0)\n \t\treturn ret;\n \treturn 0;\n }\n \n /**\n- * Calculate the required bytes that are needed for the action part of the verbs\n- * flow, in addtion returns bit-fields with all the detected action, in order to\n- * avoid another interation over the actions.\n- *\n- * @param[in] actions\n- *   Pointer to the list of actions.\n- * @param[out] action_flags\n- *   Pointer to the detected actions.\n- *\n- * @return\n- *   The size of the memory needed for all actions.\n- */\n-static int\n-mlx5_flow_verbs_get_actions_and_size(const struct rte_flow_action actions[],\n-\t\t\t\t     uint64_t *action_flags)\n-{\n-\tint size = 0;\n-\tuint64_t detected_actions = 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\tsize += sizeof(struct ibv_flow_spec_action_tag);\n-\t\t\tdetected_actions |= MLX5_ACTION_FLAG;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ACTION_TYPE_MARK:\n-\t\t\tsize += sizeof(struct ibv_flow_spec_action_tag);\n-\t\t\tdetected_actions |= MLX5_ACTION_MARK;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ACTION_TYPE_DROP:\n-\t\t\tsize += sizeof(struct ibv_flow_spec_action_drop);\n-\t\t\tdetected_actions |= MLX5_ACTION_DROP;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ACTION_TYPE_QUEUE:\n-\t\t\tdetected_actions |= MLX5_ACTION_QUEUE;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ACTION_TYPE_RSS:\n-\t\t\tdetected_actions |= MLX5_ACTION_RSS;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ACTION_TYPE_COUNT:\n-#ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT\n-\t\t\tsize += sizeof(struct ibv_flow_spec_counter_action);\n-#endif\n-\t\t\tdetected_actions |= MLX5_ACTION_COUNT;\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\t*action_flags = detected_actions;\n-\treturn size;\n-}\n-\n-/**\n- * Calculate the required bytes that are needed for the item part of the verbs\n- * flow, in addtion returns bit-fields with all the detected action, in order to\n- * avoid another interation over the actions.\n- *\n- * @param[in] actions\n- *   Pointer to the list of items.\n- * @param[in, out] item_flags\n- *   Pointer to the detected items.\n- *\n- * @return\n- *   The size of the memory needed for all items.\n- */\n-static int\n-mlx5_flow_verbs_get_items_and_size(const struct rte_flow_item items[],\n-\t\t\t\t   uint64_t *item_flags)\n-{\n-\tint size = 0;\n-\tuint64_t detected_items = 0;\n-\tconst int tunnel = !!(*item_flags & MLX5_FLOW_LAYER_TUNNEL);\n-\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\tsize += sizeof(struct ibv_flow_spec_eth);\n-\t\t\tdetected_items |= tunnel ? MLX5_FLOW_LAYER_INNER_L2 :\n-\t\t\t\t\tMLX5_FLOW_LAYER_OUTER_L2;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_VLAN:\n-\t\t\tsize += sizeof(struct ibv_flow_spec_eth);\n-\t\t\tdetected_items |= tunnel ? MLX5_FLOW_LAYER_INNER_VLAN :\n-\t\t\t\t\tMLX5_FLOW_LAYER_OUTER_VLAN;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_IPV4:\n-\t\t\tsize += sizeof(struct ibv_flow_spec_ipv4_ext);\n-\t\t\tdetected_items |= tunnel ?\n-\t\t\t\t\tMLX5_FLOW_LAYER_INNER_L3_IPV4 :\n-\t\t\t\t\tMLX5_FLOW_LAYER_OUTER_L3_IPV4;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_IPV6:\n-\t\t\tsize += sizeof(struct ibv_flow_spec_ipv6);\n-\t\t\tdetected_items |= tunnel ?\n-\t\t\t\tMLX5_FLOW_LAYER_INNER_L3_IPV6 :\n-\t\t\t\tMLX5_FLOW_LAYER_OUTER_L3_IPV6;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_UDP:\n-\t\t\tsize += sizeof(struct ibv_flow_spec_tcp_udp);\n-\t\t\tdetected_items |= tunnel ?\n-\t\t\t\t\tMLX5_FLOW_LAYER_INNER_L4_UDP :\n-\t\t\t\t\tMLX5_FLOW_LAYER_OUTER_L4_UDP;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_TCP:\n-\t\t\tsize += sizeof(struct ibv_flow_spec_tcp_udp);\n-\t\t\tdetected_items |= tunnel ?\n-\t\t\t\t\tMLX5_FLOW_LAYER_INNER_L4_TCP :\n-\t\t\t\t\tMLX5_FLOW_LAYER_OUTER_L4_TCP;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_VXLAN:\n-\t\t\tsize += sizeof(struct ibv_flow_spec_tunnel);\n-\t\t\tdetected_items |= MLX5_FLOW_LAYER_VXLAN;\n-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_VXLAN_GPE:\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-#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-\t\t\tbreak;\n-\t\tcase RTE_FLOW_ITEM_TYPE_MPLS:\n-\t\t\tsize += sizeof(struct ibv_flow_spec_mpls);\n-\t\t\tdetected_items |= MLX5_FLOW_LAYER_MPLS;\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-\t}\n-\t*item_flags = detected_items;\n-\treturn size;\n-}\n-\n-/**\n  * Get RSS action from the action list.\n  *\n  * @param[in] actions\n@@ -2994,320 +1535,6 @@ mlx5_flow_get_rss_action(const struct rte_flow_action actions[])\n \treturn NULL;\n }\n \n-/**\n- * Internal preparation function. Allocate mlx5_flow with the required size.\n- * The required size is calculate based on the actions and items. This function\n- * also returns the detected actions and items for later use.\n- *\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] item_flags\n- *   Pointer to bit mask of all items detected.\n- * @param[out] action_flags\n- *   Pointer to bit mask of all actions detected.\n- * @param[out] error\n- *   Pointer to the error structure.\n- *\n- * @return\n- *   Pointer to mlx5_flow object on success, otherwise NULL and rte_errno\n- *   is set.\n- */\n-static struct mlx5_flow *\n-mlx5_flow_verbs_prepare(const struct rte_flow_attr *attr __rte_unused,\n-\t\t\tconst struct rte_flow_item items[],\n-\t\t\tconst struct rte_flow_action actions[],\n-\t\t\tuint64_t *item_flags,\n-\t\t\tuint64_t *action_flags,\n-\t\t\tstruct rte_flow_error *error)\n-{\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-\tsize += mlx5_flow_verbs_get_items_and_size(items, item_flags);\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-\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- *   Pointer to the Ethernet device structure.\n- * @param[in, out] flow\n- *   Pointer to flow structure.\n- */\n-static void\n-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(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->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-\t\t\tverbs->hrxq = NULL;\n-\t\t}\n-\t}\n-\tif (flow->counter) {\n-\t\tmlx5_flow_counter_release(flow->counter);\n-\t\tflow->counter = NULL;\n-\t}\n-}\n-\n-/**\n- * Apply the flow.\n- *\n- * @param[in] dev\n- *   Pointer to the Ethernet device structure.\n- * @param[in, out] flow\n- *   Pointer to flow structure.\n- * @param[out] error\n- *   Pointer to error structure.\n- *\n- * @return\n- *   0 on success, a negative errno value otherwise and rte_errno is set.\n- */\n-static int\n-mlx5_flow_apply(struct rte_eth_dev *dev, struct rte_flow *flow,\n-\t\tstruct rte_flow_error *error)\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(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-\t\t\t\t\t(error, errno,\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 get drop hash queue\");\n-\t\t\t\tgoto error;\n-\t\t\t}\n-\t\t} else {\n-\t\t\tstruct mlx5_hrxq *hrxq;\n-\n-\t\t\thrxq = mlx5_hrxq_get(dev, flow->key,\n-\t\t\t\t\t     MLX5_RSS_HASH_KEY_LEN,\n-\t\t\t\t\t     verbs->hash_fields,\n-\t\t\t\t\t     (*flow->queue),\n-\t\t\t\t\t     flow->rss.queue_num);\n-\t\t\tif (!hrxq)\n-\t\t\t\thrxq = mlx5_hrxq_new(dev, flow->key,\n-\t\t\t\t\t\t     MLX5_RSS_HASH_KEY_LEN,\n-\t\t\t\t\t\t     verbs->hash_fields,\n-\t\t\t\t\t\t     (*flow->queue),\n-\t\t\t\t\t\t     flow->rss.queue_num,\n-\t\t\t\t\t\t     !!(flow->layers &\n-\t\t\t\t\t\t      MLX5_FLOW_LAYER_TUNNEL));\n-\t\t\tif (!hrxq) {\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,\n-\t\t\t\t\t NULL,\n-\t\t\t\t\t \"cannot get hash queue\");\n-\t\t\t\tgoto error;\n-\t\t\t}\n-\t\t\tverbs->hrxq = hrxq;\n-\t\t}\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-\t\t\t\t\t   NULL,\n-\t\t\t\t\t   \"hardware refuses to create flow\");\n-\t\t\tgoto error;\n-\t\t}\n-\t}\n-\tif (flow->nl_flow &&\n-\t    priv->mnl_socket &&\n-\t    mlx5_nl_flow_create(priv->mnl_socket, flow->nl_flow, error))\n-\t\tgoto error;\n-\treturn 0;\n-error:\n-\terr = rte_errno; /* Save rte_errno before cleanup. */\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->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-\t\t\tverbs->hrxq = NULL;\n-\t\t}\n-\t}\n-\trte_errno = err; /* Restore rte_errno. */\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@@ -3396,31 +1623,34 @@ mlx5_flow_list_create(struct rte_eth_dev *dev,\n \t\tbuf->entry[0].pattern = (void *)(uintptr_t)items;\n \t}\n \tfor (i = 0; i < buf->entries; ++i) {\n-\t\tdev_flow = mlx5_flow_verbs_prepare(attr, buf->entry[i].pattern,\n-\t\t\t\t\t\t   actions, &item_flags,\n-\t\t\t\t\t\t   &action_flags, error);\n+\t\tdev_flow = nic_ops.prepare(attr, buf->entry[i].pattern,\n+\t\t\t\t\t   actions, &item_flags,\n+\t\t\t\t\t   &action_flags, error);\n+\t\tif (!dev_flow)\n+\t\t\tgoto 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\tret = nic_ops.translate(dev, dev_flow, attr,\n+\t\t\t\t\tbuf->entry[i].pattern,\n+\t\t\t\t\tactions, error);\n+\t\tif (ret < 0)\n+\t\t\tgoto error;\n \t}\n \tif (dev->data->dev_started) {\n-\t\tret = mlx5_flow_apply(dev, flow, error);\n-\t\tif (ret < 0) {\n-\t\t\tret = rte_errno; /* Save rte_errno before cleanup. */\n-\t\t\tif (flow) {\n-\t\t\t\tmlx5_flow_remove(dev, flow);\n-\t\t\t\trte_free(flow);\n-\t\t\t}\n-\t\t\trte_errno = ret; /* Restore rte_errno. */\n-\t\t\treturn NULL;\n-\t\t}\n+\t\tret = nic_ops.apply(dev, flow, error);\n+\t\tif (ret < 0)\n+\t\t\tgoto error;\n \t}\n \tTAILQ_INSERT_TAIL(list, flow, next);\n \tmlx5_flow_rxq_flags_set(dev, flow);\n \treturn flow;\n+error:\n+\tret = rte_errno; /* Save rte_errno before cleanup. */\n+\tassert(flow);\n+\tnic_ops.destroy(dev, flow);\n+\trte_free(flow);\n+\trte_errno = ret; /* Restore rte_errno. */\n+\treturn NULL;\n }\n \n /**\n@@ -3455,7 +1685,7 @@ static void\n mlx5_flow_list_destroy(struct rte_eth_dev *dev, struct mlx5_flows *list,\n \t\t       struct rte_flow *flow)\n {\n-\tmlx5_flow_remove(dev, flow);\n+\tnic_ops.destroy(dev, flow);\n \tTAILQ_REMOVE(list, flow, next);\n \t/*\n \t * Update RX queue flags only if port is started, otherwise it is\n@@ -3463,12 +1693,6 @@ 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@@ -3505,7 +1729,7 @@ mlx5_flow_stop(struct rte_eth_dev *dev, struct mlx5_flows *list)\n \tstruct rte_flow *flow;\n \n \tTAILQ_FOREACH_REVERSE(flow, list, mlx5_flows, next)\n-\t\tmlx5_flow_remove(dev, flow);\n+\t\tnic_ops.remove(dev, flow);\n \tmlx5_flow_rxq_flags_clear(dev);\n }\n \n@@ -3528,7 +1752,7 @@ mlx5_flow_start(struct rte_eth_dev *dev, struct mlx5_flows *list)\n \tint ret = 0;\n \n \tTAILQ_FOREACH(flow, list, next) {\n-\t\tret = mlx5_flow_apply(dev, flow, &error);\n+\t\tret = nic_ops.apply(dev, flow, &error);\n \t\tif (ret < 0)\n \t\t\tgoto error;\n \t\tmlx5_flow_rxq_flags_set(dev, flow);\n@@ -4219,3 +2443,15 @@ mlx5_dev_filter_ctrl(struct rte_eth_dev *dev,\n \t}\n \treturn 0;\n }\n+\n+/**\n+ * Init the driver ops structure.\n+ *\n+ * @param dev\n+ *   Pointer to Ethernet device structure.\n+ */\n+void\n+mlx5_flow_init_driver_ops(struct rte_eth_dev *dev __rte_unused)\n+{\n+\tmlx5_flow_verbs_get_driver_ops(&nic_ops);\n+}\ndiff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h\nnew file mode 100644\nindex 000000000..4df60db92\n--- /dev/null\n+++ b/drivers/net/mlx5/mlx5_flow.h\n@@ -0,0 +1,257 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright 2018 Mellanox Technologies, Ltd\n+ */\n+\n+#ifndef RTE_PMD_MLX5_FLOW_H_\n+#define RTE_PMD_MLX5_FLOW_H_\n+\n+#include <sys/queue.h>\n+#include <stdalign.h>\n+#include <stdint.h>\n+#include <string.h>\n+\n+/* Verbs header. */\n+/* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */\n+#ifdef PEDANTIC\n+#pragma GCC diagnostic ignored \"-Wpedantic\"\n+#endif\n+#include <infiniband/verbs.h>\n+#ifdef PEDANTIC\n+#pragma GCC diagnostic error \"-Wpedantic\"\n+#endif\n+\n+/* Pattern outer Layer bits. */\n+#define MLX5_FLOW_LAYER_OUTER_L2 (1u << 0)\n+#define MLX5_FLOW_LAYER_OUTER_L3_IPV4 (1u << 1)\n+#define MLX5_FLOW_LAYER_OUTER_L3_IPV6 (1u << 2)\n+#define MLX5_FLOW_LAYER_OUTER_L4_UDP (1u << 3)\n+#define MLX5_FLOW_LAYER_OUTER_L4_TCP (1u << 4)\n+#define MLX5_FLOW_LAYER_OUTER_VLAN (1u << 5)\n+\n+/* Pattern inner Layer bits. */\n+#define MLX5_FLOW_LAYER_INNER_L2 (1u << 6)\n+#define MLX5_FLOW_LAYER_INNER_L3_IPV4 (1u << 7)\n+#define MLX5_FLOW_LAYER_INNER_L3_IPV6 (1u << 8)\n+#define MLX5_FLOW_LAYER_INNER_L4_UDP (1u << 9)\n+#define MLX5_FLOW_LAYER_INNER_L4_TCP (1u << 10)\n+#define MLX5_FLOW_LAYER_INNER_VLAN (1u << 11)\n+\n+/* Pattern tunnel Layer bits. */\n+#define MLX5_FLOW_LAYER_VXLAN (1u << 12)\n+#define MLX5_FLOW_LAYER_VXLAN_GPE (1u << 13)\n+#define MLX5_FLOW_LAYER_GRE (1u << 14)\n+#define MLX5_FLOW_LAYER_MPLS (1u << 15)\n+\n+/* Outer Masks. */\n+#define MLX5_FLOW_LAYER_OUTER_L3 \\\n+\t(MLX5_FLOW_LAYER_OUTER_L3_IPV4 | MLX5_FLOW_LAYER_OUTER_L3_IPV6)\n+#define MLX5_FLOW_LAYER_OUTER_L4 \\\n+\t(MLX5_FLOW_LAYER_OUTER_L4_UDP | MLX5_FLOW_LAYER_OUTER_L4_TCP)\n+#define MLX5_FLOW_LAYER_OUTER \\\n+\t(MLX5_FLOW_LAYER_OUTER_L2 | MLX5_FLOW_LAYER_OUTER_L3 | \\\n+\t MLX5_FLOW_LAYER_OUTER_L4)\n+\n+/* Tunnel Masks. */\n+#define MLX5_FLOW_LAYER_TUNNEL \\\n+\t(MLX5_FLOW_LAYER_VXLAN | MLX5_FLOW_LAYER_VXLAN_GPE | \\\n+\t MLX5_FLOW_LAYER_GRE | MLX5_FLOW_LAYER_MPLS)\n+\n+/* Inner Masks. */\n+#define MLX5_FLOW_LAYER_INNER_L3 \\\n+\t(MLX5_FLOW_LAYER_INNER_L3_IPV4 | MLX5_FLOW_LAYER_INNER_L3_IPV6)\n+#define MLX5_FLOW_LAYER_INNER_L4 \\\n+\t(MLX5_FLOW_LAYER_INNER_L4_UDP | MLX5_FLOW_LAYER_INNER_L4_TCP)\n+#define MLX5_FLOW_LAYER_INNER \\\n+\t(MLX5_FLOW_LAYER_INNER_L2 | MLX5_FLOW_LAYER_INNER_L3 | \\\n+\t MLX5_FLOW_LAYER_INNER_L4)\n+\n+/* Actions that modify the fate of matching traffic. */\n+#define MLX5_FLOW_FATE_DROP (1u << 0)\n+#define MLX5_FLOW_FATE_QUEUE (1u << 1)\n+#define MLX5_FLOW_FATE_RSS (1u << 2)\n+\n+/* Modify a packet. */\n+#define MLX5_FLOW_MOD_FLAG (1u << 0)\n+#define MLX5_FLOW_MOD_MARK (1u << 1)\n+#define MLX5_FLOW_MOD_COUNT (1u << 2)\n+\n+/* Actions */\n+#define MLX5_ACTION_DROP (1u << 0)\n+#define MLX5_ACTION_QUEUE (1u << 1)\n+#define MLX5_ACTION_RSS (1u << 2)\n+#define MLX5_ACTION_FLAG (1u << 3)\n+#define MLX5_ACTION_MARK (1u << 4)\n+#define MLX5_ACTION_COUNT (1u << 5)\n+\n+/* possible L3 layers protocols filtering. */\n+#define MLX5_IP_PROTOCOL_TCP 6\n+#define MLX5_IP_PROTOCOL_UDP 17\n+#define MLX5_IP_PROTOCOL_GRE 47\n+#define MLX5_IP_PROTOCOL_MPLS 147\n+\n+/* Priority reserved for default flows. */\n+#define MLX5_FLOW_PRIO_RSVD ((uint32_t)-1)\n+\n+/*\n+ * Number of sub priorities.\n+ * For each kind of pattern matching i.e. L2, L3, L4 to have a correct\n+ * matching on the NIC (firmware dependent) L4 most have the higher priority\n+ * followed by L3 and ending with L2.\n+ */\n+#define MLX5_PRIORITY_MAP_L2 2\n+#define MLX5_PRIORITY_MAP_L3 1\n+#define MLX5_PRIORITY_MAP_L4 0\n+#define MLX5_PRIORITY_MAP_MAX 3\n+\n+/* Verbs specification header. */\n+struct ibv_spec_header {\n+\tenum ibv_flow_spec_type type;\n+\tuint16_t size;\n+};\n+\n+/** Handles information leading to a drop fate. */\n+struct mlx5_flow_verbs {\n+\tLIST_ENTRY(mlx5_flow_verbs) next;\n+\tunsigned int size; /**< Size of the attribute. */\n+\tstruct {\n+\t\tstruct ibv_flow_attr *attr;\n+\t\t/**< Pointer to the Specification buffer. */\n+\t\tuint8_t *specs; /**< Pointer to the specifications. */\n+\t};\n+\tstruct ibv_flow *flow; /**< Verbs flow pointer. */\n+\tstruct mlx5_hrxq *hrxq; /**< Hash Rx queue object. */\n+\tuint64_t hash_fields; /**< Verbs hash Rx queue hash fields. */\n+};\n+\n+/** Device flow structure. */\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+};\n+\n+/* Counters information. */\n+struct mlx5_flow_counter {\n+\tLIST_ENTRY(mlx5_flow_counter) next; /**< Pointer to the next counter. */\n+\tuint32_t shared:1; /**< Share counter ID with other flow rules. */\n+\tuint32_t ref_cnt:31; /**< Reference counter. */\n+\tuint32_t id; /**< Counter ID. */\n+\tstruct ibv_counter_set *cs; /**< Holds the counters for the rule. */\n+\tuint64_t hits; /**< Number of packets matched by the rule. */\n+\tuint64_t bytes; /**< Number of bytes matched by the rule. */\n+};\n+\n+/* Flow structure. */\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+\t/**< Bit-fields of present layers see MLX5_FLOW_LAYER_*. */\n+\tstruct mlx5_flow_counter *counter; /**< Holds flow counter. */\n+\tstruct rte_flow_action_rss rss;/**< RSS context. */\n+\tuint8_t key[MLX5_RSS_HASH_KEY_LEN]; /**< RSS hash key. */\n+\tuint16_t (*queue)[]; /**< Destination queues to redirect traffic to. */\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+typedef int (*mlx5_flow_validate_t)(struct rte_eth_dev *dev,\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+typedef struct mlx5_flow *(*mlx5_flow_prepare_t)\n+\t(const struct rte_flow_attr *attr, const struct rte_flow_item items[],\n+\t const struct rte_flow_action actions[], uint64_t *item_flags,\n+\t uint64_t *action_flags, struct rte_flow_error *error);\n+typedef int (*mlx5_flow_translate_t)(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+typedef int (*mlx5_flow_apply_t)(struct rte_eth_dev *dev, struct rte_flow *flow,\n+\t\t\t\t struct rte_flow_error *error);\n+typedef void (*mlx5_flow_remove_t)(struct rte_eth_dev *dev,\n+\t\t\t\t   struct rte_flow *flow);\n+typedef void (*mlx5_flow_destroy_t)(struct rte_eth_dev *dev,\n+\t\t\t\t    struct rte_flow *flow);\n+struct mlx5_flow_driver_ops {\n+\tmlx5_flow_validate_t validate;\n+\tmlx5_flow_prepare_t prepare;\n+\tmlx5_flow_translate_t translate;\n+\tmlx5_flow_apply_t apply;\n+\tmlx5_flow_remove_t remove;\n+\tmlx5_flow_destroy_t destroy;\n+};\n+\n+/* mlx5_flow.c */\n+\n+uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,\n+\t\t\t\t   uint32_t subpriority);\n+int mlx5_flow_validate_action_count(struct rte_eth_dev *dev,\n+\t\t\t\t    struct rte_flow_error *error);\n+int mlx5_flow_validate_action_drop(uint64_t action_flags,\n+\t\t\t\t   struct rte_flow_error *error);\n+int mlx5_flow_validate_action_flag(uint64_t action_flags,\n+\t\t\t\t   struct rte_flow_error *error);\n+int mlx5_flow_validate_action_mark(const struct rte_flow_action *action,\n+\t\t\t\t   uint64_t action_flags,\n+\t\t\t\t   struct rte_flow_error *error);\n+int mlx5_flow_validate_action_queue(const struct rte_flow_action *action,\n+\t\t\t\t    uint64_t action_flags,\n+\t\t\t\t    struct rte_eth_dev *dev,\n+\t\t\t\t    struct rte_flow_error *error);\n+int mlx5_flow_validate_action_rss(const struct rte_flow_action *action,\n+\t\t\t\t  uint64_t action_flags,\n+\t\t\t\t  struct rte_eth_dev *dev,\n+\t\t\t\t  struct rte_flow_error *error);\n+int mlx5_flow_validate_attributes(struct rte_eth_dev *dev,\n+\t\t\t\t  const struct rte_flow_attr *attributes,\n+\t\t\t\t  struct rte_flow_error *error);\n+int mlx5_flow_validate_item_eth(const struct rte_flow_item *item,\n+\t\t\t\tuint64_t item_flags,\n+\t\t\t\tstruct rte_flow_error *error);\n+int mlx5_flow_validate_item_gre(const struct rte_flow_item *item,\n+\t\t\t\tuint64_t item_flags,\n+\t\t\t\tuint8_t target_protocol,\n+\t\t\t\tstruct rte_flow_error *error);\n+int mlx5_flow_validate_item_ipv4(const struct rte_flow_item *item,\n+\t\t\t\t int64_t item_flags,\n+\t\t\t\t struct rte_flow_error *error);\n+int mlx5_flow_validate_item_ipv6(const struct rte_flow_item *item,\n+\t\t\t\t uint64_t item_flags,\n+\t\t\t\t struct rte_flow_error *error);\n+int mlx5_flow_validate_item_mpls(const struct rte_flow_item *item,\n+\t\t\t\t uint64_t item_flags,\n+\t\t\t\t uint8_t target_protocol,\n+\t\t\t\t struct rte_flow_error *error);\n+int mlx5_flow_validate_item_tcp(const struct rte_flow_item *item,\n+\t\t\t\tuint64_t item_flags,\n+\t\t\t\tuint8_t target_protocol,\n+\t\t\t\tstruct rte_flow_error *error);\n+int mlx5_flow_validate_item_udp(const struct rte_flow_item *item,\n+\t\t\t\tuint64_t item_flags,\n+\t\t\t\tuint8_t target_protocol,\n+\t\t\t\tstruct rte_flow_error *error);\n+int mlx5_flow_validate_item_vlan(const struct rte_flow_item *item,\n+\t\t\t\t int64_t item_flags,\n+\t\t\t\t struct rte_flow_error *error);\n+int mlx5_flow_validate_item_vxlan(const struct rte_flow_item *item,\n+\t\t\t\t  uint64_t item_flags,\n+\t\t\t\t  struct rte_flow_error *error);\n+int mlx5_flow_validate_item_vxlan_gpe(const struct rte_flow_item *item,\n+\t\t\t\t      uint64_t item_flags,\n+\t\t\t\t      struct rte_eth_dev *dev,\n+\t\t\t\t      struct rte_flow_error *error);\n+void mlx5_flow_init_driver_ops(struct rte_eth_dev *dev);\n+\n+/* mlx5_flow_verbs.c */\n+\n+void mlx5_flow_verbs_get_driver_ops(struct mlx5_flow_driver_ops *flow_ops);\n+\n+#endif /* RTE_PMD_MLX5_FLOW_H_ */\ndiff --git a/drivers/net/mlx5/mlx5_flow_verbs.c b/drivers/net/mlx5/mlx5_flow_verbs.c\nnew file mode 100644\nindex 000000000..e8e16cc37\n--- /dev/null\n+++ b/drivers/net/mlx5/mlx5_flow_verbs.c\n@@ -0,0 +1,1692 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright 2018 Mellanox Technologies, Ltd\n+ */\n+\n+#include <sys/queue.h>\n+#include <stdalign.h>\n+#include <stdint.h>\n+#include <string.h>\n+\n+/* Verbs header. */\n+/* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */\n+#ifdef PEDANTIC\n+#pragma GCC diagnostic ignored \"-Wpedantic\"\n+#endif\n+#include <infiniband/verbs.h>\n+#ifdef PEDANTIC\n+#pragma GCC diagnostic error \"-Wpedantic\"\n+#endif\n+\n+#include <rte_common.h>\n+#include <rte_ether.h>\n+#include <rte_eth_ctrl.h>\n+#include <rte_ethdev_driver.h>\n+#include <rte_flow.h>\n+#include <rte_flow_driver.h>\n+#include <rte_malloc.h>\n+#include <rte_ip.h>\n+\n+#include \"mlx5.h\"\n+#include \"mlx5_defs.h\"\n+#include \"mlx5_prm.h\"\n+#include \"mlx5_glue.h\"\n+#include \"mlx5_flow.h\"\n+\n+/**\n+ * Get a flow counter.\n+ *\n+ * @param[in] dev\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+ *   Counter identifier.\n+ *\n+ * @return\n+ *   A pointer to the counter, NULL otherwise and rte_errno is set.\n+ */\n+static struct mlx5_flow_counter *\n+flow_verbs_counter_new(struct rte_eth_dev *dev, uint32_t shared, uint32_t id)\n+{\n+\tstruct priv *priv = dev->data->dev_private;\n+\tstruct mlx5_flow_counter *cnt;\n+\n+\tLIST_FOREACH(cnt, &priv->flow_counters, next) {\n+\t\tif (!cnt->shared || cnt->shared != shared)\n+\t\t\tcontinue;\n+\t\tif (cnt->id != id)\n+\t\t\tcontinue;\n+\t\tcnt->ref_cnt++;\n+\t\treturn cnt;\n+\t}\n+#ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT\n+\n+\tstruct mlx5_flow_counter tmpl = {\n+\t\t.shared = shared,\n+\t\t.id = id,\n+\t\t.cs = mlx5_glue->create_counter_set\n+\t\t\t(priv->ctx,\n+\t\t\t &(struct ibv_counter_set_init_attr){\n+\t\t\t\t .counter_set_id = id,\n+\t\t\t }),\n+\t\t.hits = 0,\n+\t\t.bytes = 0,\n+\t};\n+\n+\tif (!tmpl.cs) {\n+\t\trte_errno = errno;\n+\t\treturn NULL;\n+\t}\n+\tcnt = rte_calloc(__func__, 1, sizeof(*cnt), 0);\n+\tif (!cnt) {\n+\t\trte_errno = ENOMEM;\n+\t\treturn NULL;\n+\t}\n+\t*cnt = tmpl;\n+\tLIST_INSERT_HEAD(&priv->flow_counters, cnt, next);\n+\treturn cnt;\n+#endif\n+\trte_errno = ENOTSUP;\n+\treturn NULL;\n+}\n+\n+/**\n+ * Release a flow counter.\n+ *\n+ * @param[in] counter\n+ *   Pointer to the counter handler.\n+ */\n+static void\n+flow_verbs_counter_release(struct mlx5_flow_counter *counter)\n+{\n+\tif (--counter->ref_cnt == 0) {\n+\t\tclaim_zero(mlx5_glue->destroy_counter_set(counter->cs));\n+\t\tLIST_REMOVE(counter, next);\n+\t\trte_free(counter);\n+\t}\n+}\n+\n+/**\n+ * Add a verbs item specification into @p flow.\n+ *\n+ * @param[in, out] flow\n+ *   Pointer to flow structure.\n+ * @param[in] src\n+ *   Create specification.\n+ * @param[in] size\n+ *   Size in bytes of the specification to copy.\n+ */\n+static void\n+flow_verbs_spec_add(struct mlx5_flow *flow, void *src, unsigned int size)\n+{\n+\tstruct mlx5_flow_verbs *verbs = &flow->verbs;\n+\n+\tif (verbs->specs) {\n+\t\tvoid *dst;\n+\n+\t\tdst = (void *)(verbs->specs + verbs->size);\n+\t\tmemcpy(dst, src, size);\n+\t\t++verbs->attr->num_of_specs;\n+\t}\n+\tverbs->size += size;\n+}\n+\n+/**\n+ * Adjust verbs hash fields according to the @p flow information.\n+ *\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+ *   ETH_RSS_* types.\n+ * @param[in] hash_fields\n+ *   Item hash fields.\n+ */\n+static void\n+flow_verbs_hashfields_adjust(struct mlx5_flow *dev_flow,\n+\t\t\t     int tunnel __rte_unused,\n+\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 (rss_request_inner && !tunnel)\n+\t\thash_fields = 0;\n+\telse if (rss_request_inner < 2 && tunnel)\n+\t\thash_fields = 0;\n+#endif\n+\tif (!(dev_flow->flow->rss.types & layer_types))\n+\t\thash_fields = 0;\n+\tdev_flow->verbs.hash_fields |= hash_fields;\n+}\n+\n+/**\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] item_flags\n+ *   Bit field with all detected items.\n+ * @param[in, out] dev_flow\n+ *   Pointer to dev_flow structure.\n+ */\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 = !!(*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+\t\t.size = size,\n+\t};\n+\n+\tif (!mask)\n+\t\tmask = &rte_flow_item_eth_mask;\n+\tif (spec) {\n+\t\tunsigned int i;\n+\n+\t\tmemcpy(&eth.val.dst_mac, spec->dst.addr_bytes, ETHER_ADDR_LEN);\n+\t\tmemcpy(&eth.val.src_mac, spec->src.addr_bytes, ETHER_ADDR_LEN);\n+\t\teth.val.ether_type = spec->type;\n+\t\tmemcpy(&eth.mask.dst_mac, mask->dst.addr_bytes, ETHER_ADDR_LEN);\n+\t\tmemcpy(&eth.mask.src_mac, mask->src.addr_bytes, ETHER_ADDR_LEN);\n+\t\teth.mask.ether_type = mask->type;\n+\t\t/* Remove unwanted bits from values. */\n+\t\tfor (i = 0; i < ETHER_ADDR_LEN; ++i) {\n+\t\t\teth.val.dst_mac[i] &= eth.mask.dst_mac[i];\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_verbs_spec_add(dev_flow, &eth, size);\n+\t*item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L2 :\n+\t\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+ * @param[in] eth\n+ *   Verbs structure containing the VLAN information to copy.\n+ */\n+static void\n+flow_verbs_item_vlan_update(struct ibv_flow_attr *attr,\n+\t\t\t    struct ibv_flow_spec_eth *eth)\n+{\n+\tunsigned int i;\n+\tconst enum ibv_flow_spec_type search = eth->type;\n+\tstruct ibv_spec_header *hdr = (struct ibv_spec_header *)\n+\t\t((uint8_t *)attr + sizeof(struct ibv_flow_attr));\n+\n+\tfor (i = 0; i != attr->num_of_specs; ++i) {\n+\t\tif (hdr->type == search) {\n+\t\t\tstruct ibv_flow_spec_eth *e =\n+\t\t\t\t(struct ibv_flow_spec_eth *)hdr;\n+\n+\t\t\te->val.vlan_tag = eth->val.vlan_tag;\n+\t\t\te->mask.vlan_tag = eth->mask.vlan_tag;\n+\t\t\te->val.ether_type = eth->val.ether_type;\n+\t\t\te->mask.ether_type = eth->mask.ether_type;\n+\t\t\tbreak;\n+\t\t}\n+\t\thdr = (struct ibv_spec_header *)((uint8_t *)hdr + hdr->size);\n+\t}\n+}\n+\n+/**\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] 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 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 = !!(*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+\t};\n+\tconst uint32_t l2m = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :\n+\t\t\t\t      MLX5_FLOW_LAYER_OUTER_L2;\n+\n+\tif (!mask)\n+\t\tmask = &rte_flow_item_vlan_mask;\n+\tif (spec) {\n+\t\teth.val.vlan_tag = spec->tci;\n+\t\teth.mask.vlan_tag = mask->tci;\n+\t\teth.val.vlan_tag &= eth.mask.vlan_tag;\n+\t\teth.val.ether_type = spec->inner_type;\n+\t\teth.mask.ether_type = mask->inner_type;\n+\t\teth.val.ether_type &= eth.mask.ether_type;\n+\t}\n+\tif (!(*item_flags & l2m)) {\n+\t\tdev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L2;\n+\t\tflow_verbs_spec_add(dev_flow, &eth, size);\n+\t} else {\n+\t\tflow_verbs_item_vlan_update(dev_flow->verbs.attr, &eth);\n+\t\tsize = 0; /* Only an update is done in eth specification. */\n+\t}\n+\t*item_flags |= 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+}\n+\n+/**\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] 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 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 = !!(*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+\t\t\t(tunnel ? IBV_FLOW_SPEC_INNER : 0),\n+\t\t.size = size,\n+\t};\n+\n+\tif (!mask)\n+\t\tmask = &rte_flow_item_ipv4_mask;\n+\t*item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :\n+\t\t\t\tMLX5_FLOW_LAYER_OUTER_L3_IPV4;\n+\tif (spec) {\n+\t\tipv4.val = (struct ibv_flow_ipv4_ext_filter){\n+\t\t\t.src_ip = spec->hdr.src_addr,\n+\t\t\t.dst_ip = spec->hdr.dst_addr,\n+\t\t\t.proto = spec->hdr.next_proto_id,\n+\t\t\t.tos = spec->hdr.type_of_service,\n+\t\t};\n+\t\tipv4.mask = (struct ibv_flow_ipv4_ext_filter){\n+\t\t\t.src_ip = mask->hdr.src_addr,\n+\t\t\t.dst_ip = mask->hdr.dst_addr,\n+\t\t\t.proto = mask->hdr.next_proto_id,\n+\t\t\t.tos = mask->hdr.type_of_service,\n+\t\t};\n+\t\t/* Remove unwanted bits from values. */\n+\t\tipv4.val.src_ip &= ipv4.mask.src_ip;\n+\t\tipv4.val.dst_ip &= ipv4.mask.dst_ip;\n+\t\tipv4.val.proto &= ipv4.mask.proto;\n+\t\tipv4.val.tos &= ipv4.mask.tos;\n+\t}\n+\tflow_verbs_hashfields_adjust(dev_flow, tunnel,\n+\t\t\t\t     (ETH_RSS_IPV4 | ETH_RSS_FRAG_IPV4 |\n+\t\t\t\t      ETH_RSS_NONFRAG_IPV4_TCP |\n+\t\t\t\t      ETH_RSS_NONFRAG_IPV4_UDP |\n+\t\t\t\t      ETH_RSS_NONFRAG_IPV4_OTHER),\n+\t\t\t\t     (IBV_RX_HASH_SRC_IPV4 |\n+\t\t\t\t      IBV_RX_HASH_DST_IPV4));\n+\tdev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L3;\n+\tflow_verbs_spec_add(dev_flow, &ipv4, size);\n+}\n+\n+/**\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] 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 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 = !!(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+\t\t.size = size,\n+\t};\n+\n+\tif (!mask)\n+\t\tmask = &rte_flow_item_ipv6_mask;\n+\t *item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :\n+\t\t\t\t MLX5_FLOW_LAYER_OUTER_L3_IPV6;\n+\tif (spec) {\n+\t\tunsigned int i;\n+\t\tuint32_t vtc_flow_val;\n+\t\tuint32_t vtc_flow_mask;\n+\n+\t\tmemcpy(&ipv6.val.src_ip, spec->hdr.src_addr,\n+\t\t       RTE_DIM(ipv6.val.src_ip));\n+\t\tmemcpy(&ipv6.val.dst_ip, spec->hdr.dst_addr,\n+\t\t       RTE_DIM(ipv6.val.dst_ip));\n+\t\tmemcpy(&ipv6.mask.src_ip, mask->hdr.src_addr,\n+\t\t       RTE_DIM(ipv6.mask.src_ip));\n+\t\tmemcpy(&ipv6.mask.dst_ip, mask->hdr.dst_addr,\n+\t\t       RTE_DIM(ipv6.mask.dst_ip));\n+\t\tvtc_flow_val = rte_be_to_cpu_32(spec->hdr.vtc_flow);\n+\t\tvtc_flow_mask = rte_be_to_cpu_32(mask->hdr.vtc_flow);\n+\t\tipv6.val.flow_label =\n+\t\t\trte_cpu_to_be_32((vtc_flow_val & IPV6_HDR_FL_MASK) >>\n+\t\t\t\t\t IPV6_HDR_FL_SHIFT);\n+\t\tipv6.val.traffic_class = (vtc_flow_val & IPV6_HDR_TC_MASK) >>\n+\t\t\t\t\t IPV6_HDR_TC_SHIFT;\n+\t\tipv6.val.next_hdr = spec->hdr.proto;\n+\t\tipv6.val.hop_limit = spec->hdr.hop_limits;\n+\t\tipv6.mask.flow_label =\n+\t\t\trte_cpu_to_be_32((vtc_flow_mask & IPV6_HDR_FL_MASK) >>\n+\t\t\t\t\t IPV6_HDR_FL_SHIFT);\n+\t\tipv6.mask.traffic_class = (vtc_flow_mask & IPV6_HDR_TC_MASK) >>\n+\t\t\t\t\t  IPV6_HDR_TC_SHIFT;\n+\t\tipv6.mask.next_hdr = mask->hdr.proto;\n+\t\tipv6.mask.hop_limit = mask->hdr.hop_limits;\n+\t\t/* Remove unwanted bits from values. */\n+\t\tfor (i = 0; i < RTE_DIM(ipv6.val.src_ip); ++i) {\n+\t\t\tipv6.val.src_ip[i] &= ipv6.mask.src_ip[i];\n+\t\t\tipv6.val.dst_ip[i] &= ipv6.mask.dst_ip[i];\n+\t\t}\n+\t\tipv6.val.flow_label &= ipv6.mask.flow_label;\n+\t\tipv6.val.traffic_class &= ipv6.mask.traffic_class;\n+\t\tipv6.val.next_hdr &= ipv6.mask.next_hdr;\n+\t\tipv6.val.hop_limit &= ipv6.mask.hop_limit;\n+\t}\n+\tflow_verbs_hashfields_adjust(dev_flow, tunnel,\n+\t\t\t\t     (ETH_RSS_IPV6 | ETH_RSS_FRAG_IPV6 |\n+\t\t\t\t      ETH_RSS_NONFRAG_IPV6_TCP |\n+\t\t\t\t      ETH_RSS_NONFRAG_IPV6_UDP |\n+\t\t\t\t      ETH_RSS_IPV6_EX  |\n+\t\t\t\t      ETH_RSS_IPV6_TCP_EX |\n+\t\t\t\t      ETH_RSS_IPV6_UDP_EX |\n+\t\t\t\t      ETH_RSS_NONFRAG_IPV6_OTHER),\n+\t\t\t\t     (IBV_RX_HASH_SRC_IPV6 |\n+\t\t\t\t      IBV_RX_HASH_DST_IPV6));\n+\tdev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L3;\n+\tflow_verbs_spec_add(dev_flow, &ipv6, size);\n+}\n+\n+/**\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] 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 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 = !!(*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+\t\t.size = size,\n+\t};\n+\n+\tif (!mask)\n+\t\tmask = &rte_flow_item_udp_mask;\n+\t*item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :\n+\t\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+\t\tudp.mask.dst_port = mask->hdr.dst_port;\n+\t\tudp.mask.src_port = mask->hdr.src_port;\n+\t\t/* Remove unwanted bits from values. */\n+\t\tudp.val.src_port &= udp.mask.src_port;\n+\t\tudp.val.dst_port &= udp.mask.dst_port;\n+\t}\n+\tflow_verbs_hashfields_adjust(dev_flow,\n+\t\t\t\t     tunnel, ETH_RSS_UDP,\n+\t\t\t\t     (IBV_RX_HASH_SRC_PORT_UDP |\n+\t\t\t\t      IBV_RX_HASH_DST_PORT_UDP));\n+\tdev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L4;\n+\tflow_verbs_spec_add(dev_flow, &udp, size);\n+}\n+\n+/**\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] 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 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 = !!(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+\t\t.size = size,\n+\t};\n+\n+\tif (!mask)\n+\t\tmask = &rte_flow_item_tcp_mask;\n+\t*item_flags |=  tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :\n+\t\t\t\t MLX5_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+\t\ttcp.mask.dst_port = mask->hdr.dst_port;\n+\t\ttcp.mask.src_port = mask->hdr.src_port;\n+\t\t/* Remove unwanted bits from values. */\n+\t\ttcp.val.src_port &= tcp.mask.src_port;\n+\t\ttcp.val.dst_port &= tcp.mask.dst_port;\n+\t}\n+\tflow_verbs_hashfields_adjust(dev_flow,\n+\t\t\t\t     tunnel, ETH_RSS_TCP,\n+\t\t\t\t     (IBV_RX_HASH_SRC_PORT_TCP |\n+\t\t\t\t      IBV_RX_HASH_DST_PORT_TCP));\n+\tdev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L4;\n+\tflow_verbs_spec_add(dev_flow, &tcp, size);\n+}\n+\n+/**\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] 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 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+\tunsigned int size = sizeof(struct ibv_flow_spec_tunnel);\n+\tstruct ibv_flow_spec_tunnel vxlan = {\n+\t\t.type = IBV_FLOW_SPEC_VXLAN_TUNNEL,\n+\t\t.size = size,\n+\t};\n+\tunion vni {\n+\t\tuint32_t vlan_id;\n+\t\tuint8_t vni[4];\n+\t} id = { .vlan_id = 0, };\n+\n+\tif (!mask)\n+\t\tmask = &rte_flow_item_vxlan_mask;\n+\tif (spec) {\n+\t\tmemcpy(&id.vni[1], spec->vni, 3);\n+\t\tvxlan.val.tunnel_id = id.vlan_id;\n+\t\tmemcpy(&id.vni[1], mask->vni, 3);\n+\t\tvxlan.mask.tunnel_id = id.vlan_id;\n+\t\t/* Remove unwanted bits from values. */\n+\t\tvxlan.val.tunnel_id &= vxlan.mask.tunnel_id;\n+\t}\n+\tflow_verbs_spec_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. 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] 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 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+\tunsigned int size = sizeof(struct ibv_flow_spec_tunnel);\n+\tstruct ibv_flow_spec_tunnel vxlan_gpe = {\n+\t\t.type = IBV_FLOW_SPEC_VXLAN_TUNNEL,\n+\t\t.size = size,\n+\t};\n+\tunion vni {\n+\t\tuint32_t vlan_id;\n+\t\tuint8_t vni[4];\n+\t} id = { .vlan_id = 0, };\n+\n+\tif (!mask)\n+\t\tmask = &rte_flow_item_vxlan_gpe_mask;\n+\tif (spec) {\n+\t\tmemcpy(&id.vni[1], spec->vni, 3);\n+\t\tvxlan_gpe.val.tunnel_id = id.vlan_id;\n+\t\tmemcpy(&id.vni[1], mask->vni, 3);\n+\t\tvxlan_gpe.mask.tunnel_id = id.vlan_id;\n+\t\t/* Remove unwanted bits from values. */\n+\t\tvxlan_gpe.val.tunnel_id &= vxlan_gpe.mask.tunnel_id;\n+\t}\n+\tflow_verbs_spec_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+ * Update the protocol in Verbs IPv4/IPv6 spec.\n+ *\n+ * @param[in, out] attr\n+ *   Pointer to Verbs attributes structure.\n+ * @param[in] search\n+ *   Specification type to search in order to update the IP protocol.\n+ * @param[in] protocol\n+ *   Protocol value to set if none is present in the specification.\n+ */\n+static void\n+flow_verbs_item_gre_ip_protocol_update(struct ibv_flow_attr *attr,\n+\t\t\t\t       enum ibv_flow_spec_type search,\n+\t\t\t\t       uint8_t protocol)\n+{\n+\tunsigned int i;\n+\tstruct ibv_spec_header *hdr = (struct ibv_spec_header *)\n+\t\t((uint8_t *)attr + sizeof(struct ibv_flow_attr));\n+\n+\tif (!attr)\n+\t\treturn;\n+\tfor (i = 0; i != attr->num_of_specs; ++i) {\n+\t\tif (hdr->type == search) {\n+\t\t\tunion {\n+\t\t\t\tstruct ibv_flow_spec_ipv4_ext *ipv4;\n+\t\t\t\tstruct ibv_flow_spec_ipv6 *ipv6;\n+\t\t\t} ip;\n+\n+\t\t\tswitch (search) {\n+\t\t\tcase IBV_FLOW_SPEC_IPV4_EXT:\n+\t\t\t\tip.ipv4 = (struct ibv_flow_spec_ipv4_ext *)hdr;\n+\t\t\t\tif (!ip.ipv4->val.proto) {\n+\t\t\t\t\tip.ipv4->val.proto = protocol;\n+\t\t\t\t\tip.ipv4->mask.proto = 0xff;\n+\t\t\t\t}\n+\t\t\t\tbreak;\n+\t\t\tcase IBV_FLOW_SPEC_IPV6:\n+\t\t\t\tip.ipv6 = (struct ibv_flow_spec_ipv6 *)hdr;\n+\t\t\t\tif (!ip.ipv6->val.next_hdr) {\n+\t\t\t\t\tip.ipv6->val.next_hdr = protocol;\n+\t\t\t\t\tip.ipv6->mask.next_hdr = 0xff;\n+\t\t\t\t}\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\t}\n+\t\thdr = (struct ibv_spec_header *)((uint8_t *)hdr + hdr->size);\n+\t}\n+}\n+\n+/**\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] 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 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 = &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+\tstruct ibv_flow_spec_gre tunnel = {\n+\t\t.type = IBV_FLOW_SPEC_GRE,\n+\t\t.size = size,\n+\t};\n+\n+\tif (!mask)\n+\t\tmask = &rte_flow_item_gre_mask;\n+\tif (spec) {\n+\t\ttunnel.val.c_ks_res0_ver = spec->c_rsvd0_ver;\n+\t\ttunnel.val.protocol = spec->protocol;\n+\t\ttunnel.mask.c_ks_res0_ver = mask->c_rsvd0_ver;\n+\t\ttunnel.mask.protocol = mask->protocol;\n+\t\t/* Remove unwanted bits from values. */\n+\t\ttunnel.val.c_ks_res0_ver &= tunnel.mask.c_ks_res0_ver;\n+\t\ttunnel.val.protocol &= tunnel.mask.protocol;\n+\t\ttunnel.val.key &= tunnel.mask.key;\n+\t}\n+#endif\n+\tif (*item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV4)\n+\t\tflow_verbs_item_gre_ip_protocol_update(verbs->attr,\n+\t\t\t\t\t\t       IBV_FLOW_SPEC_IPV4_EXT,\n+\t\t\t\t\t\t       MLX5_IP_PROTOCOL_GRE);\n+\telse\n+\t\tflow_verbs_item_gre_ip_protocol_update(verbs->attr,\n+\t\t\t\t\t\t       IBV_FLOW_SPEC_IPV6,\n+\t\t\t\t\t\t       MLX5_IP_PROTOCOL_GRE);\n+\tflow_verbs_spec_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 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] 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 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+\tconst struct rte_flow_item_mpls *mask = item->mask;\n+\tunsigned int size = sizeof(struct ibv_flow_spec_mpls);\n+\tstruct ibv_flow_spec_mpls mpls = {\n+\t\t.type = IBV_FLOW_SPEC_MPLS,\n+\t\t.size = size,\n+\t};\n+\n+\tif (!mask)\n+\t\tmask = &rte_flow_item_mpls_mask;\n+\tif (spec) {\n+\t\tmemcpy(&mpls.val.label, spec, sizeof(mpls.val.label));\n+\t\tmemcpy(&mpls.mask.label, mask, sizeof(mpls.mask.label));\n+\t\t/* Remove unwanted bits from values.  */\n+\t\tmpls.val.label &= mpls.mask.label;\n+\t}\n+\tflow_verbs_spec_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. 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] 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_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+\t\t\t.type = IBV_FLOW_SPEC_ACTION_DROP,\n+\t\t\t.size = size,\n+\t};\n+\n+\tflow_verbs_spec_add(dev_flow, &drop, size);\n+\t*action_flags |= MLX5_ACTION_DROP;\n+}\n+\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_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+\t*action_flags |= MLX5_ACTION_QUEUE;\n+}\n+\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_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+\t\t       rss->queue_num * sizeof(uint16_t));\n+\tflow->rss.queue_num = rss->queue_num;\n+\tmemcpy(flow->key, rss->key, MLX5_RSS_HASH_KEY_LEN);\n+\tflow->rss.types = rss->types;\n+\tflow->rss.level = rss->level;\n+\t*action_flags |= MLX5_ACTION_RSS;\n+}\n+\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_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+\t\t.type = IBV_FLOW_SPEC_ACTION_TAG,\n+\t\t.size = size,\n+\t\t.tag_id = mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT),\n+\t};\n+\t*action_flags |= MLX5_ACTION_MARK;\n+\tflow_verbs_spec_add(dev_flow, &tag, size);\n+}\n+\n+/**\n+ * Update verbs specification to modify the flag to mark.\n+ *\n+ * @param[in, out] verbs\n+ *   Pointer to the mlx5_flow_verbs structure.\n+ * @param[in] mark_id\n+ *   Mark identifier to replace the flag.\n+ */\n+static void\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 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_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+\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\tflow_verbs_spec_add(dev_flow, &tag, size);\n+\t}\n+\t*action_flags |= MLX5_ACTION_MARK;\n+}\n+\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] dev\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+ *   Pointer to error structure.\n+ *\n+ * @return\n+ *   0 On success else a negative errno value is returned and rte_errno is set.\n+ */\n+static int\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+\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+\tif (!flow->counter) {\n+\t\tflow->counter = flow_verbs_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*action_flags |= MLX5_ACTION_COUNT;\n+#ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT\n+\tcounter.counter_set_handle = flow->counter->cs->handle;\n+\tflow_verbs_spec_add(dev_flow, &counter, size);\n+#endif\n+\treturn 0;\n+}\n+\n+/**\n+ * Internal validation function. For validating both actions and items.\n+ *\n+ * @param[in] dev\n+ *   Pointer to the Ethernet device structure.\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, a negative errno value otherwise and rte_errno is set.\n+ */\n+static int\n+flow_verbs_validate(struct rte_eth_dev *dev,\n+\t\t    const struct rte_flow_attr *attr,\n+\t\t    const struct rte_flow_item items[],\n+\t\t    const struct rte_flow_action actions[],\n+\t\t    struct rte_flow_error *error)\n+{\n+\tint ret;\n+\tuint32_t action_flags = 0;\n+\tuint32_t item_flags = 0;\n+\tint tunnel = 0;\n+\tuint8_t next_protocol = 0xff;\n+\n+\tif (items == NULL)\n+\t\treturn -1;\n+\tret = mlx5_flow_validate_attributes(dev, attr, error);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\tfor (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {\n+\t\tint ret = 0;\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\tret = mlx5_flow_validate_item_eth(items, item_flags,\n+\t\t\t\t\t\t\t  error);\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\t\t\titem_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L2 :\n+\t\t\t\t\t       MLX5_FLOW_LAYER_OUTER_L2;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_VLAN:\n+\t\t\tret = mlx5_flow_validate_item_vlan(items, item_flags,\n+\t\t\t\t\t\t\t   error);\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\t\t\titem_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_VLAN :\n+\t\t\t\t\t       MLX5_FLOW_LAYER_OUTER_VLAN;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV4:\n+\t\t\tret = mlx5_flow_validate_item_ipv4(items, item_flags,\n+\t\t\t\t\t\t\t   error);\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\t\t\titem_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :\n+\t\t\t\t\t       MLX5_FLOW_LAYER_OUTER_L3_IPV4;\n+\t\t\tif (items->mask != NULL &&\n+\t\t\t    ((const struct rte_flow_item_ipv4 *)\n+\t\t\t     items->mask)->hdr.next_proto_id)\n+\t\t\t\tnext_protocol =\n+\t\t\t\t\t((const struct rte_flow_item_ipv4 *)\n+\t\t\t\t\t (items->spec))->hdr.next_proto_id;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV6:\n+\t\t\tret = mlx5_flow_validate_item_ipv6(items, item_flags,\n+\t\t\t\t\t\t\t   error);\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\t\t\titem_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :\n+\t\t\t\t\t       MLX5_FLOW_LAYER_OUTER_L3_IPV6;\n+\t\t\tif (items->mask != NULL &&\n+\t\t\t    ((const struct rte_flow_item_ipv6 *)\n+\t\t\t     items->mask)->hdr.proto)\n+\t\t\t\tnext_protocol =\n+\t\t\t\t\t((const struct rte_flow_item_ipv6 *)\n+\t\t\t\t\t items->spec)->hdr.proto;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_UDP:\n+\t\t\tret = mlx5_flow_validate_item_udp(items, item_flags,\n+\t\t\t\t\t\t\t  next_protocol,\n+\t\t\t\t\t\t\t  error);\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\t\t\titem_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :\n+\t\t\t\t\t       MLX5_FLOW_LAYER_OUTER_L4_UDP;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_TCP:\n+\t\t\tret = mlx5_flow_validate_item_tcp(items, item_flags,\n+\t\t\t\t\t\t\t  next_protocol, error);\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\t\t\titem_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :\n+\t\t\t\t\t       MLX5_FLOW_LAYER_OUTER_L4_TCP;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_VXLAN:\n+\t\t\tret = mlx5_flow_validate_item_vxlan(items, item_flags,\n+\t\t\t\t\t\t\t    error);\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\t\t\titem_flags |= MLX5_FLOW_LAYER_VXLAN;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_VXLAN_GPE:\n+\t\t\tret = mlx5_flow_validate_item_vxlan_gpe(items,\n+\t\t\t\t\t\t\t\titem_flags,\n+\t\t\t\t\t\t\t\tdev, error);\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\t\t\titem_flags |= MLX5_FLOW_LAYER_VXLAN_GPE;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_GRE:\n+\t\t\tret = mlx5_flow_validate_item_gre(items, item_flags,\n+\t\t\t\t\t\t\t  next_protocol, error);\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\t\t\titem_flags |= MLX5_FLOW_LAYER_GRE;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_MPLS:\n+\t\t\tret = mlx5_flow_validate_item_mpls(items, item_flags,\n+\t\t\t\t\t\t\t   next_protocol,\n+\t\t\t\t\t\t\t   error);\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\t\t\tif (next_protocol != 0xff &&\n+\t\t\t    next_protocol != MLX5_IP_PROTOCOL_MPLS)\n+\t\t\t\treturn rte_flow_error_set\n+\t\t\t\t\t(error, ENOTSUP,\n+\t\t\t\t\t RTE_FLOW_ERROR_TYPE_ITEM, items,\n+\t\t\t\t\t \"protocol filtering not compatible\"\n+\t\t\t\t\t \" with MPLS layer\");\n+\t\t\titem_flags |= MLX5_FLOW_LAYER_MPLS;\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, \"item not supported\");\n+\t\t}\n+\t}\n+\tfor (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {\n+\t\ttunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);\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_validate_action_flag(action_flags,\n+\t\t\t\t\t\t\t     error);\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\t\t\taction_flags |= MLX5_ACTION_FLAG;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_MARK:\n+\t\t\tret = mlx5_flow_validate_action_mark(actions,\n+\t\t\t\t\t\t\t     action_flags,\n+\t\t\t\t\t\t\t     error);\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\t\t\taction_flags |= MLX5_ACTION_MARK;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_DROP:\n+\t\t\tret = mlx5_flow_validate_action_drop(action_flags,\n+\t\t\t\t\t\t\t     error);\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\t\t\taction_flags |= MLX5_ACTION_DROP;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_QUEUE:\n+\t\t\tret = mlx5_flow_validate_action_queue(actions,\n+\t\t\t\t\t\t\t      action_flags, dev,\n+\t\t\t\t\t\t\t      error);\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\t\t\taction_flags |= MLX5_ACTION_QUEUE;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_RSS:\n+\t\t\tret = mlx5_flow_validate_action_rss(actions,\n+\t\t\t\t\t\t\t    action_flags, dev,\n+\t\t\t\t\t\t\t    error);\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\t\t\taction_flags |= MLX5_ACTION_RSS;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_COUNT:\n+\t\t\tret = mlx5_flow_validate_action_count(dev, error);\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\t\t\taction_flags |= MLX5_ACTION_COUNT;\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+\treturn 0;\n+}\n+\n+/**\n+ * Calculate the required bytes that are needed for the action part of the verbs\n+ * flow, in addtion returns bit-fields with all the detected action, in order to\n+ * avoid another interation over the actions.\n+ *\n+ * @param[in] actions\n+ *   Pointer to the list of actions.\n+ * @param[out] action_flags\n+ *   Pointer to the detected actions.\n+ *\n+ * @return\n+ *   The size of the memory needed for all actions.\n+ */\n+static int\n+flow_verbs_get_actions_and_size(const struct rte_flow_action actions[],\n+\t\t\t\tuint64_t *action_flags)\n+{\n+\tint size = 0;\n+\tuint64_t detected_actions = 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\tsize += sizeof(struct ibv_flow_spec_action_tag);\n+\t\t\tdetected_actions |= MLX5_ACTION_FLAG;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_MARK:\n+\t\t\tsize += sizeof(struct ibv_flow_spec_action_tag);\n+\t\t\tdetected_actions |= MLX5_ACTION_MARK;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_DROP:\n+\t\t\tsize += sizeof(struct ibv_flow_spec_action_drop);\n+\t\t\tdetected_actions |= MLX5_ACTION_DROP;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_QUEUE:\n+\t\t\tdetected_actions |= MLX5_ACTION_QUEUE;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_RSS:\n+\t\t\tdetected_actions |= MLX5_ACTION_RSS;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_COUNT:\n+#ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT\n+\t\t\tsize += sizeof(struct ibv_flow_spec_counter_action);\n+#endif\n+\t\t\tdetected_actions |= MLX5_ACTION_COUNT;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\t*action_flags = detected_actions;\n+\treturn size;\n+}\n+\n+/**\n+ * Calculate the required bytes that are needed for the item part of the verbs\n+ * flow, in addtion returns bit-fields with all the detected action, in order to\n+ * avoid another interation over the actions.\n+ *\n+ * @param[in] actions\n+ *   Pointer to the list of items.\n+ * @param[in, out] item_flags\n+ *   Pointer to the detected items.\n+ *\n+ * @return\n+ *   The size of the memory needed for all items.\n+ */\n+static int\n+flow_verbs_get_items_and_size(const struct rte_flow_item items[],\n+\t\t\t      uint64_t *item_flags)\n+{\n+\tint size = 0;\n+\tuint64_t detected_items = 0;\n+\tconst int tunnel = !!(*item_flags & MLX5_FLOW_LAYER_TUNNEL);\n+\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\tsize += sizeof(struct ibv_flow_spec_eth);\n+\t\t\tdetected_items |= tunnel ? MLX5_FLOW_LAYER_INNER_L2 :\n+\t\t\t\t\t\t   MLX5_FLOW_LAYER_OUTER_L2;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_VLAN:\n+\t\t\tsize += sizeof(struct ibv_flow_spec_eth);\n+\t\t\tdetected_items |= tunnel ? MLX5_FLOW_LAYER_INNER_VLAN :\n+\t\t\t\t\t\t   MLX5_FLOW_LAYER_OUTER_VLAN;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV4:\n+\t\t\tsize += sizeof(struct ibv_flow_spec_ipv4_ext);\n+\t\t\tdetected_items |= tunnel ?\n+\t\t\t\t\t  MLX5_FLOW_LAYER_INNER_L3_IPV4 :\n+\t\t\t\t\t  MLX5_FLOW_LAYER_OUTER_L3_IPV4;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV6:\n+\t\t\tsize += sizeof(struct ibv_flow_spec_ipv6);\n+\t\t\tdetected_items |= tunnel ?\n+\t\t\t\t\t  MLX5_FLOW_LAYER_INNER_L3_IPV6 :\n+\t\t\t\t\t  MLX5_FLOW_LAYER_OUTER_L3_IPV6;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_UDP:\n+\t\t\tsize += sizeof(struct ibv_flow_spec_tcp_udp);\n+\t\t\tdetected_items |= tunnel ?\n+\t\t\t\t\t  MLX5_FLOW_LAYER_INNER_L4_UDP :\n+\t\t\t\t\t  MLX5_FLOW_LAYER_OUTER_L4_UDP;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_TCP:\n+\t\t\tsize += sizeof(struct ibv_flow_spec_tcp_udp);\n+\t\t\tdetected_items |= tunnel ?\n+\t\t\t\t\t  MLX5_FLOW_LAYER_INNER_L4_TCP :\n+\t\t\t\t\t  MLX5_FLOW_LAYER_OUTER_L4_TCP;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_VXLAN:\n+\t\t\tsize += sizeof(struct ibv_flow_spec_tunnel);\n+\t\t\tdetected_items |= MLX5_FLOW_LAYER_VXLAN;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_VXLAN_GPE:\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+#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+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_MPLS:\n+\t\t\tsize += sizeof(struct ibv_flow_spec_mpls);\n+\t\t\tdetected_items |= MLX5_FLOW_LAYER_MPLS;\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+\t}\n+\t*item_flags = detected_items;\n+\treturn size;\n+}\n+\n+/**\n+ * Internal preparation function. Allocate mlx5_flow with the required size.\n+ * The required size is calculate based on the actions and items. This function\n+ * also returns the detected actions and items for later use.\n+ *\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] item_flags\n+ *   Pointer to bit mask of all items detected.\n+ * @param[out] action_flags\n+ *   Pointer to bit mask of all actions detected.\n+ * @param[out] error\n+ *   Pointer to the error structure.\n+ *\n+ * @return\n+ *   Pointer to mlx5_flow object on success, otherwise NULL and rte_errno\n+ *   is set.\n+ */\n+static struct mlx5_flow *\n+flow_verbs_prepare(const struct rte_flow_attr *attr __rte_unused,\n+\t\t   const struct rte_flow_item items[],\n+\t\t   const struct rte_flow_action actions[],\n+\t\t   uint64_t *item_flags,\n+\t\t   uint64_t *action_flags,\n+\t\t   struct rte_flow_error *error)\n+{\n+\tuint32_t size = sizeof(struct mlx5_flow) + sizeof(struct ibv_flow_attr);\n+\tstruct mlx5_flow *flow;\n+\n+\tsize += flow_verbs_get_actions_and_size(actions, action_flags);\n+\tsize += flow_verbs_get_items_and_size(items, item_flags);\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, NULL,\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 =\n+\t\t(uint8_t *)(flow + 1) + sizeof(struct ibv_flow_attr);\n+\treturn flow;\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\n+flow_verbs_translate(struct rte_eth_dev *dev,\n+\t\t     struct mlx5_flow *dev_flow,\n+\t\t     const struct rte_flow_attr *attr,\n+\t\t     const struct rte_flow_item items[],\n+\t\t     const struct rte_flow_action actions[],\n+\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 =\n+\t\tmlx5_flow_adjust_priority(dev, priority,\n+\t\t\t\t\t  dev_flow->verbs.attr->priority);\n+\treturn 0;\n+}\n+\n+/**\n+ * Remove the flow from the NIC but keeps it in memory.\n+ *\n+ * @param[in] dev\n+ *   Pointer to the Ethernet device structure.\n+ * @param[in, out] flow\n+ *   Pointer to flow structure.\n+ */\n+static void\n+flow_verbs_remove(struct rte_eth_dev *dev, struct rte_flow *flow)\n+{\n+\tstruct mlx5_flow_verbs *verbs;\n+\tstruct mlx5_flow *dev_flow;\n+\n+\tif (!flow)\n+\t\treturn;\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->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+\t\t\tverbs->hrxq = NULL;\n+\t\t}\n+\t}\n+\tif (flow->counter) {\n+\t\tflow_verbs_counter_release(flow->counter);\n+\t\tflow->counter = NULL;\n+\t}\n+}\n+\n+/**\n+ * Remove the flow from the NIC and the memory.\n+ *\n+ * @param[in] dev\n+ *   Pointer to the Ethernet device structure.\n+ * @param[in, out] flow\n+ *   Pointer to flow structure.\n+ */\n+static void\n+flow_verbs_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)\n+{\n+\tstruct mlx5_flow *dev_flow;\n+\n+\tif (!flow)\n+\t\treturn;\n+\tflow_verbs_remove(dev, flow);\n+\twhile (!LIST_EMPTY(&flow->dev_flows)) {\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+}\n+\n+/**\n+ * Apply the flow to the NIC.\n+ *\n+ * @param[in] dev\n+ *   Pointer to the Ethernet device structure.\n+ * @param[in, out] flow\n+ *   Pointer to flow structure.\n+ * @param[out] error\n+ *   Pointer to error structure.\n+ *\n+ * @return\n+ *   0 on success, a negative errno value otherwise and rte_errno is set.\n+ */\n+static int\n+flow_verbs_apply(struct rte_eth_dev *dev, struct rte_flow *flow,\n+\t\t struct rte_flow_error *error)\n+{\n+\tstruct mlx5_flow_verbs *verbs;\n+\tstruct mlx5_flow *dev_flow;\n+\tint err;\n+\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+\t\t\t\t\t(error, errno,\n+\t\t\t\t\t RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\t\t \"cannot get drop hash queue\");\n+\t\t\t\tgoto error;\n+\t\t\t}\n+\t\t} else {\n+\t\t\tstruct mlx5_hrxq *hrxq;\n+\n+\t\t\thrxq = mlx5_hrxq_get(dev, flow->key,\n+\t\t\t\t\t     MLX5_RSS_HASH_KEY_LEN,\n+\t\t\t\t\t     verbs->hash_fields,\n+\t\t\t\t\t     (*flow->queue),\n+\t\t\t\t\t     flow->rss.queue_num);\n+\t\t\tif (!hrxq)\n+\t\t\t\thrxq = mlx5_hrxq_new(dev, flow->key,\n+\t\t\t\t\t\t     MLX5_RSS_HASH_KEY_LEN,\n+\t\t\t\t\t\t     verbs->hash_fields,\n+\t\t\t\t\t\t     (*flow->queue),\n+\t\t\t\t\t\t     flow->rss.queue_num,\n+\t\t\t\t\t\t     !!(flow->layers &\n+\t\t\t\t\t\t      MLX5_FLOW_LAYER_TUNNEL));\n+\t\t\tif (!hrxq) {\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;\n+\t\t\t}\n+\t\t\tverbs->hrxq = hrxq;\n+\t\t}\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+\t\t\t\t\t   NULL,\n+\t\t\t\t\t   \"hardware refuses to create flow\");\n+\t\t\tgoto error;\n+\t\t}\n+\t}\n+\treturn 0;\n+error:\n+\terr = rte_errno; /* Save rte_errno before cleanup. */\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->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+\t\t\tverbs->hrxq = NULL;\n+\t\t}\n+\t}\n+\trte_errno = err; /* Restore rte_errno. */\n+\treturn -rte_errno;\n+}\n+\n+void\n+mlx5_flow_verbs_get_driver_ops(struct mlx5_flow_driver_ops *flow_ops)\n+{\n+\t*flow_ops = (struct mlx5_flow_driver_ops) {\n+\t\t.validate = flow_verbs_validate,\n+\t\t.prepare = flow_verbs_prepare,\n+\t\t.translate = flow_verbs_translate,\n+\t\t.apply = flow_verbs_apply,\n+\t\t.remove = flow_verbs_remove,\n+\t\t.destroy = flow_verbs_destroy,\n+\t};\n+}\n",
    "prefixes": [
        "v3",
        "04/11"
    ]
}