Show a patch.

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

{
    "id": 45239,
    "url": "http://patches.dpdk.org/api/patches/45239/",
    "web_url": "http://patches.dpdk.org/patch/45239/",
    "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": "<20180924195503.18894-2-yskoh@mellanox.com>",
    "date": "2018-09-24T19:55:14",
    "name": "[v2,1/3] net/mlx5: add abstraction for multiple flow drivers",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "a3ac7d71e7584adf6d60b2899fb8008e7f25dd00",
    "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/45239/mbox/",
    "series": [
        {
            "id": 1474,
            "url": "http://patches.dpdk.org/api/series/1474/",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=1474",
            "date": "2018-09-24T19:55:12",
            "name": "net/mlx5: migrate Linux TC flower driver to new flow engine",
            "version": 2,
            "mbox": "http://patches.dpdk.org/series/1474/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/45239/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/45239/checks/",
    "tags": {},
    "headers": {
        "x-ms-office365-filtering-ht": "Tenant",
        "x-microsoft-antispam-message-info": "Ff1K1+tVhHzK0umo3Td7OMK7i2w5D38xIFL8vhi/eGyIaB3kWxLxb62QVjuvl9s2xDweHvlvkl5M7u1JzZxvuQ6lgobvT40Behp8DkOJEr935WkXGLwsSAbGtKYN0fCRsHn9lrWEpEJxlP5ur2ZyGjNEbS2IPthfPP5h/8Ifbl+U02um7LX0myiigrQyZrUd2k465JES8Psho6O54iBmIHe1CAsJhSRlT3UmfvRhwr4zrMOcOiOt1aNB05QHnJQixwLG5ZKFMX/t7w3lVhEp/s3ixKntBrGWzjso8OhP4Y6fabBEX96v0Z5zrZEnrIml3rE2O1xJuc5zy0B+Og9OBQzz+QxFwZRGwSJRb38nQ1w=",
        "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=9gbt8AtpcwS6Gb70b1QmpC88dT6ZkTw170fPE3BLT1Q=;\n\tb=IsLAVcPFSaWiENOSIyLJfUG8AcaAtMTxOrnogm7P7ODpvnBxX8vZfaYcRtLUf8UzWk4zz2sGboJhKcNFR8wjdDJHXbTfAPQ8oNIrsWLfujKVQmQVcaow6865aZBaPzFe8xmfEHKCdcOZEK/xcPIE+zS5+KmKsKr/pX13bd4VAC4=",
        "x-microsoft-exchange-diagnostics": "1; DB3PR0502MB3995;\n\t6:Y+K+Hj/cZaXev09vutOzAHqZU793QFvWmPAG/0LrnoqOixa1jLZB9H5Pgfa3twUJVkA4he7hzWIk5KAhimf3ud0CfHuwYirqq6wFOqSuA7D/ZxS4hCADvBVd/12AxOsO2wE6xABspip5E5yBPUyQNC0jdtgG5i989iNdzkqDqideLlgS3Ad1VJSF5btmXDSRabGnGhI9CFfYUxQMei3muQC0R97zdsPbG5vvbsMMUbex83CHrFPySYVTrcgymt9Sn+lBsE66HT5X7eGDFIJ8RxlBOxnSepmLBkbLuMFu/P7qBShmCq2jDCNKr3B5+zCqlGsz8QXl3VvR896WKmO32fyGY/2zhM4FbcVUDYbsADqD1h9uEJp09Vp/IP6lKMh2E6ko1908qYFL2BcSpdh2MufyOHtrx5/qfOATuWIOTRF3w5zjgk7MwQxT8YXkds6MgLUzrpkzsvrKl0r6dx9ddg==;\n\t5:CXxIU2f0Ur2y5piQIrLRnQcRafkKsV+bjSAFhYQN25PE0alEgb9eLUiY5k6ZYTs4hXIYmzZtZYTGXP0+AjhPjIWDlaDm832iYoMamO85kw9BG5A2nG5tfuY7IePOUsKT50nLrNfBGStPMtYyDHSfMFb7TwU9m43100Sp1SgRaRU=;\n\t7:FL+1jv8ScUQohd4e2Xs5j5nle8LlSqqoYbqIRKI9O3UrAI+jMjoJztjtx5lEO3VjsRZ0CfZdL1T9C5UkS0pykPBAbG68O0F3F+dQYmQH0mwra2tRPBY84QaFztQ73P/+rygG8mrV8ZxcVorCDgb/8akbdqd3KZ1MjEXjql7nxCqrYVQVrEeboAwedVWfskcJI0D4Fxk7Z0wieJwTBdZ9TATdJSgYlDutrSRlUbFI2aU6MtuwuMXcFz+Djc5DWmIo",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "x-ms-traffictypediagnostic": "DB3PR0502MB3995:",
        "Accept-Language": "en-US",
        "X-MS-Has-Attach": "",
        "x-forefront-prvs": "0805EC9467",
        "CC": "\"dev@dpdk.org\" <dev@dpdk.org>, Yongseok Koh <yskoh@mellanox.com>",
        "X-MS-TNEF-Correlator": "",
        "References": "<20180919072143.23211-1-yskoh@mellanox.com>\n\t<20180924195503.18894-1-yskoh@mellanox.com>",
        "x-exchange-antispam-report-cfa-test": "BCL:0; PCL:0;\n\tRULEID:(8211001083)(6040522)(2401047)(8121501046)(5005006)(10201501046)(3231355)(944501410)(52105095)(93006095)(93001095)(3002001)(6055026)(149066)(150027)(6041310)(20161123560045)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(20161123558120)(20161123564045)(20161123562045)(201708071742011)(7699051);\n\tSRVR:DB3PR0502MB3995; BCL:0; PCL:0; RULEID:; SRVR:DB3PR0502MB3995; ",
        "Return-Path": "<dev-bounces@dpdk.org>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "Subject": "[dpdk-dev] [PATCH v2 1/3] net/mlx5: add abstraction for multiple\n\tflow drivers",
        "spamdiagnosticmetadata": "NSPM",
        "Date": "Mon, 24 Sep 2018 19:55:14 +0000",
        "authentication-results": "spf=none (sender IP is )\n\tsmtp.mailfrom=yskoh@mellanox.com; ",
        "X-MS-Exchange-CrossTenant-originalarrivaltime": "24 Sep 2018 19:55:14.5132\n\t(UTC)",
        "x-ld-processed": "a652971c-7d2e-4d9b-a6a4-d149256f461b,ExtAddr",
        "In-Reply-To": "<20180924195503.18894-1-yskoh@mellanox.com>",
        "MIME-Version": "1.0",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Thread-Topic": "[PATCH v2 1/3] net/mlx5: add abstraction for multiple flow\n\tdrivers",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "d691e094-9705-4805-0169-08d62257a4b2",
        "Content-Language": "en-US",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "From": "Yongseok Koh <yskoh@mellanox.com>",
        "x-ms-exchange-senderadcheck": "1",
        "x-microsoft-antispam-prvs": "<DB3PR0502MB39951A6315CE5816B265EBDBC3170@DB3PR0502MB3995.eurprd05.prod.outlook.com>",
        "x-ms-publictraffictype": "Email",
        "Delivered-To": "patchwork@dpdk.org",
        "x-originating-ip": "[209.116.155.178]",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "To": "Thomas Monjalon <thomas@monjalon.net>,\n\tShahaf Shuler <shahafs@mellanox.com>",
        "X-MS-Exchange-CrossTenant-fromentityheader": "Hosted",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>",
        "x-forefront-antispam-report": "SFV:NSPM;\n\tSFS:(10009020)(136003)(346002)(396003)(376002)(366004)(39860400002)(199004)(189003)(486006)(2906002)(14444005)(99286004)(105586002)(106356001)(110136005)(71200400001)(68736007)(54906003)(107886003)(25786009)(5250100002)(316002)(11346002)(446003)(4326008)(7736002)(53936002)(476003)(2616005)(305945005)(66066001)(5660300001)(6436002)(26005)(6116002)(102836004)(1076002)(3846002)(8676002)(8936002)(478600001)(14454004)(6506007)(81156014)(386003)(81166006)(53946003)(36756003)(6636002)(6486002)(71190400001)(52116002)(86362001)(76176011)(97736004)(2900100001)(575784001)(256004)(186003)(6512007);\n\tDIR:OUT; SFP:1101; SCL:1; SRVR:DB3PR0502MB3995;\n\tH:DB3PR0502MB3980.eurprd05.prod.outlook.com; FPR:; SPF:None; LANG:en; \n\tPTR:InfoNoRecords; A:1; MX:1; ",
        "x-ms-office365-filtering-correlation-id": "d691e094-9705-4805-0169-08d62257a4b2",
        "Errors-To": "dev-bounces@dpdk.org",
        "x-exchange-antispam-report-test": "UriScan:;",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 25D3A1B126;\n\tMon, 24 Sep 2018 21:55:18 +0200 (CEST)",
            "from EUR03-DB5-obe.outbound.protection.outlook.com\n\t(mail-eopbgr40089.outbound.protection.outlook.com [40.107.4.89])\n\tby dpdk.org (Postfix) with ESMTP id C87901B116\n\tfor <dev@dpdk.org>; Mon, 24 Sep 2018 21:55:16 +0200 (CEST)",
            "from DB3PR0502MB3980.eurprd05.prod.outlook.com (52.134.72.27) by\n\tDB3PR0502MB3995.eurprd05.prod.outlook.com (52.134.72.30) 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 19:55:14 +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 19:55:14 +0000"
        ],
        "x-ms-exchange-messagesentrepresentingtype": "1",
        "Thread-Index": "AQHUVECCvK86LeA+1EKg3UsJkP17Lw==",
        "received-spf": "None (protection.outlook.com: mellanox.com does not designate\n\tpermitted sender hosts)",
        "Content-Type": "text/plain; charset=\"iso-8859-1\"",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "DB3PR0502MB3995",
        "X-OriginatorOrg": "Mellanox.com",
        "Message-ID": "<20180924195503.18894-2-yskoh@mellanox.com>",
        "Precedence": "list",
        "spamdiagnosticoutput": "1:99",
        "x-microsoft-antispam": "BCL:0; PCL:0;\n\tRULEID:(7020095)(4652040)(8989299)(4534165)(4627221)(201703031133081)(201702281549075)(8990200)(5600074)(711020)(4618075)(2017052603328)(7153060)(7193020);\n\tSRVR:DB3PR0502MB3995; ",
        "Content-Transfer-Encoding": "quoted-printable",
        "X-MS-Exchange-CrossTenant-id": "a652971c-7d2e-4d9b-a6a4-d149256f461b",
        "X-Original-To": "patchwork@dpdk.org",
        "x-clientproxiedby": "MWHPR2001CA0016.namprd20.prod.outlook.com\n\t(2603:10b6:301:15::26) To DB3PR0502MB3980.eurprd05.prod.outlook.com\n\t(2603:10a6:8:10::27)"
    },
    "content": "Flow engine has to support multiple driver paths. Verbs/DV for NIC flow\nsteering and Linux TC flower for E-Switch flow steering. In the future,\nanother flow driver could be added (devX).\n\nSigned-off-by: Yongseok Koh <yskoh@mellanox.com>\n---\n drivers/net/mlx5/mlx5.c            |   1 -\n drivers/net/mlx5/mlx5_flow.c       | 348 +++++++++++++++++++++++++++++++++----\n drivers/net/mlx5/mlx5_flow.h       |  17 +-\n drivers/net/mlx5/mlx5_flow_dv.c    |  26 +--\n drivers/net/mlx5/mlx5_flow_verbs.c |  20 +--\n 5 files changed, 335 insertions(+), 77 deletions(-)",
    "diff": "diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c\nindex 9b208109b..2f7d046e0 100644\n--- a/drivers/net/mlx5/mlx5.c\n+++ b/drivers/net/mlx5/mlx5.c\n@@ -1192,7 +1192,6 @@ 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 2119211f5..54008afa4 100644\n--- a/drivers/net/mlx5/mlx5_flow.c\n+++ b/drivers/net/mlx5/mlx5_flow.c\n@@ -37,6 +37,23 @@\n extern const struct eth_dev_ops mlx5_dev_ops;\n extern const struct eth_dev_ops mlx5_dev_ops_isolate;\n \n+/** Device flow drivers. */\n+#ifdef HAVE_IBV_FLOW_DV_SUPPORT\n+extern const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops;\n+#endif\n+extern const struct mlx5_flow_driver_ops mlx5_flow_verbs_drv_ops;\n+\n+const struct mlx5_flow_driver_ops mlx5_flow_null_drv_ops;\n+\n+const struct mlx5_flow_driver_ops *flow_drv_ops[] = {\n+\t[MLX5_FLOW_TYPE_MIN] = &mlx5_flow_null_drv_ops,\n+#ifdef HAVE_IBV_FLOW_DV_SUPPORT\n+\t[MLX5_FLOW_TYPE_DV] = &mlx5_flow_dv_drv_ops,\n+#endif\n+\t[MLX5_FLOW_TYPE_VERBS] = &mlx5_flow_verbs_drv_ops,\n+\t[MLX5_FLOW_TYPE_MAX] = &mlx5_flow_null_drv_ops\n+};\n+\n enum mlx5_expansion {\n \tMLX5_EXPANSION_ROOT,\n \tMLX5_EXPANSION_ROOT_OUTER,\n@@ -282,9 +299,6 @@ 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@@ -1510,6 +1524,284 @@ mlx5_flow_validate_item_mpls(const struct rte_flow_item *item __rte_unused,\n \t\t\t\t  \" update.\");\n }\n \n+static int\n+flow_null_validate(struct rte_eth_dev *dev __rte_unused,\n+\t\t   const struct rte_flow_attr *attr __rte_unused,\n+\t\t   const struct rte_flow_item items[] __rte_unused,\n+\t\t   const struct rte_flow_action actions[] __rte_unused,\n+\t\t   struct rte_flow_error *error __rte_unused)\n+{\n+\trte_errno = ENOTSUP;\n+\treturn -rte_errno;\n+}\n+\n+static struct mlx5_flow *\n+flow_null_prepare(const struct rte_flow_attr *attr __rte_unused,\n+\t\t  const struct rte_flow_item items[] __rte_unused,\n+\t\t  const struct rte_flow_action actions[] __rte_unused,\n+\t\t  uint64_t *item_flags __rte_unused,\n+\t\t  uint64_t *action_flags __rte_unused,\n+\t\t  struct rte_flow_error *error __rte_unused)\n+{\n+\trte_errno = ENOTSUP;\n+\treturn NULL;\n+}\n+\n+static int\n+flow_null_translate(struct rte_eth_dev *dev __rte_unused,\n+\t\t    struct mlx5_flow *dev_flow __rte_unused,\n+\t\t    const struct rte_flow_attr *attr __rte_unused,\n+\t\t    const struct rte_flow_item items[] __rte_unused,\n+\t\t    const struct rte_flow_action actions[] __rte_unused,\n+\t\t    struct rte_flow_error *error __rte_unused)\n+{\n+\trte_errno = ENOTSUP;\n+\treturn -rte_errno;\n+}\n+\n+static int\n+flow_null_apply(struct rte_eth_dev *dev __rte_unused,\n+\t\tstruct rte_flow *flow __rte_unused,\n+\t\tstruct rte_flow_error *error __rte_unused)\n+{\n+\trte_errno = ENOTSUP;\n+\treturn -rte_errno;\n+}\n+\n+static void\n+flow_null_remove(struct rte_eth_dev *dev __rte_unused,\n+\t\t struct rte_flow *flow __rte_unused)\n+{\n+}\n+\n+static void\n+flow_null_destroy(struct rte_eth_dev *dev __rte_unused,\n+\t\t  struct rte_flow *flow __rte_unused)\n+{\n+}\n+\n+/* Void driver to protect from null pointer reference. */\n+const struct mlx5_flow_driver_ops mlx5_flow_null_drv_ops = {\n+\t.validate = flow_null_validate,\n+\t.prepare = flow_null_prepare,\n+\t.translate = flow_null_translate,\n+\t.apply = flow_null_apply,\n+\t.remove = flow_null_remove,\n+\t.destroy = flow_null_destroy,\n+};\n+\n+/**\n+ * Select flow driver type according to flow attributes and device\n+ * configuration.\n+ *\n+ * @param[in] dev\n+ *   Pointer to the dev structure.\n+ * @param[in] attr\n+ *   Pointer to the flow attributes.\n+ *\n+ * @return\n+ *   flow driver type if supported, MLX5_FLOW_TYPE_MAX otherwise.\n+ */\n+static enum mlx5_flow_drv_type\n+flow_get_drv_type(struct rte_eth_dev *dev __rte_unused,\n+\t\t  const struct rte_flow_attr *attr)\n+{\n+\tstruct priv *priv __rte_unused = dev->data->dev_private;\n+\tenum mlx5_flow_drv_type type = MLX5_FLOW_TYPE_MAX;\n+\n+\tif (!attr->transfer) {\n+#ifdef HAVE_IBV_FLOW_DV_SUPPORT\n+\t\ttype = priv->config.dv_flow_en ?  MLX5_FLOW_TYPE_DV :\n+\t\t\t\t\t\t  MLX5_FLOW_TYPE_VERBS;\n+#else\n+\t\ttype = MLX5_FLOW_TYPE_VERBS;\n+#endif\n+\t}\n+\treturn type;\n+}\n+\n+#define flow_get_drv_ops(type) flow_drv_ops[type]\n+\n+/**\n+ * Flow driver validation API. This abstracts calling driver specific functions.\n+ * The type of flow driver is determined according to flow attributes.\n+ *\n+ * @param[in] dev\n+ *   Pointer to the dev 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 inline int\n+flow_drv_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+\tconst struct mlx5_flow_driver_ops *fops;\n+\tenum mlx5_flow_drv_type type = flow_get_drv_type(dev, attr);\n+\n+\tfops = flow_get_drv_ops(type);\n+\treturn fops->validate(dev, attr, items, actions, error);\n+}\n+\n+/**\n+ * Flow driver preparation API. This abstracts calling driver specific\n+ * functions. Parent flow (rte_flow) should have driver type (drv_type). It\n+ * calculates the size of memory required for device flow, allocates the memory,\n+ * initializes the device flow and returns the pointer.\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 device flow on success, otherwise NULL and rte_ernno is set.\n+ */\n+static inline struct mlx5_flow *\n+flow_drv_prepare(struct rte_flow *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 uint64_t *item_flags,\n+\t\t uint64_t *action_flags,\n+\t\t struct rte_flow_error *error)\n+{\n+\tconst struct mlx5_flow_driver_ops *fops;\n+\tenum mlx5_flow_drv_type type = flow->drv_type;\n+\n+\tassert(type > MLX5_FLOW_TYPE_MIN && type < MLX5_FLOW_TYPE_MAX);\n+\tfops = flow_get_drv_ops(type);\n+\treturn fops->prepare(attr, items, actions, item_flags, action_flags,\n+\t\t\t     error);\n+}\n+\n+/**\n+ * Flow driver translation API. This abstracts calling driver specific\n+ * functions. Parent flow (rte_flow) should have driver type (drv_type). It\n+ * translates a generic flow into a driver flow. flow_drv_prepare() must\n+ * precede.\n+ *\n+ *\n+ * @param[in] dev\n+ *   Pointer to the rte dev structure.\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, a negative errno value otherwise and rte_ernno is set.\n+ */\n+static inline int\n+flow_drv_translate(struct rte_eth_dev *dev, 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+\tconst struct mlx5_flow_driver_ops *fops;\n+\tenum mlx5_flow_drv_type type = dev_flow->flow->drv_type;\n+\n+\tassert(type > MLX5_FLOW_TYPE_MIN && type < MLX5_FLOW_TYPE_MAX);\n+\tfops = flow_get_drv_ops(type);\n+\treturn fops->translate(dev, dev_flow, attr, items, actions, error);\n+}\n+\n+/**\n+ * Flow driver apply API. This abstracts calling driver specific functions.\n+ * Parent flow (rte_flow) should have driver type (drv_type). It applies\n+ * translated driver flows on to device. flow_drv_translate() must precede.\n+ *\n+ * @param[in] dev\n+ *   Pointer to 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 inline int\n+flow_drv_apply(struct rte_eth_dev *dev, struct rte_flow *flow,\n+\t       struct rte_flow_error *error)\n+{\n+\tconst struct mlx5_flow_driver_ops *fops;\n+\tenum mlx5_flow_drv_type type = flow->drv_type;\n+\n+\tassert(type > MLX5_FLOW_TYPE_MIN && type < MLX5_FLOW_TYPE_MAX);\n+\tfops = flow_get_drv_ops(type);\n+\treturn fops->apply(dev, flow, error);\n+}\n+\n+/**\n+ * Flow driver remove API. This abstracts calling driver specific functions.\n+ * Parent flow (rte_flow) should have driver type (drv_type). It removes a flow\n+ * on device. All the resources of the flow should be freed by calling\n+ * flow_dv_destroy().\n+ *\n+ * @param[in] dev\n+ *   Pointer to Ethernet device.\n+ * @param[in, out] flow\n+ *   Pointer to flow structure.\n+ */\n+static inline void\n+flow_drv_remove(struct rte_eth_dev *dev, struct rte_flow *flow)\n+{\n+\tconst struct mlx5_flow_driver_ops *fops;\n+\tenum mlx5_flow_drv_type type = flow->drv_type;\n+\n+\tassert(type > MLX5_FLOW_TYPE_MIN && type < MLX5_FLOW_TYPE_MAX);\n+\tfops = flow_get_drv_ops(type);\n+\tfops->remove(dev, flow);\n+}\n+\n+/**\n+ * Flow driver destroy API. This abstracts calling driver specific functions.\n+ * Parent flow (rte_flow) should have driver type (drv_type). It removes a flow\n+ * on device and releases resources of the flow.\n+ *\n+ * @param[in] dev\n+ *   Pointer to Ethernet device.\n+ * @param[in, out] flow\n+ *   Pointer to flow structure.\n+ */\n+static inline void\n+flow_drv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)\n+{\n+\tconst struct mlx5_flow_driver_ops *fops;\n+\tenum mlx5_flow_drv_type type = flow->drv_type;\n+\n+\tassert(type > MLX5_FLOW_TYPE_MIN && type < MLX5_FLOW_TYPE_MAX);\n+\tfops = flow_get_drv_ops(type);\n+\tfops->destroy(dev, flow);\n+}\n+\n /**\n  * Validate a flow supported by the NIC.\n  *\n@@ -1525,7 +1817,7 @@ mlx5_flow_validate(struct rte_eth_dev *dev,\n {\n \tint ret;\n \n-\tret =  nic_ops.validate(dev, attr, items, actions, error);\n+\tret = flow_drv_validate(dev, attr, items, actions, error);\n \tif (ret < 0)\n \t\treturn ret;\n \treturn 0;\n@@ -1615,7 +1907,7 @@ mlx5_flow_list_create(struct rte_eth_dev *dev,\n \tuint32_t i;\n \tuint32_t flow_size;\n \n-\tret = mlx5_flow_validate(dev, attr, items, actions, error);\n+\tret = flow_drv_validate(dev, attr, items, actions, error);\n \tif (ret < 0)\n \t\treturn NULL;\n \tflow_size = sizeof(struct rte_flow);\n@@ -1626,6 +1918,9 @@ mlx5_flow_list_create(struct rte_eth_dev *dev,\n \telse\n \t\tflow_size += RTE_ALIGN_CEIL(sizeof(uint16_t), sizeof(void *));\n \tflow = rte_calloc(__func__, 1, flow_size, 0);\n+\tflow->drv_type = flow_get_drv_type(dev, attr);\n+\tassert(flow->drv_type > MLX5_FLOW_TYPE_MIN &&\n+\t       flow->drv_type < MLX5_FLOW_TYPE_MAX);\n \tflow->queue = (void *)(flow + 1);\n \tLIST_INIT(&flow->dev_flows);\n \tif (rss && rss->types) {\n@@ -1643,21 +1938,21 @@ 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 = 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\tdev_flow = flow_drv_prepare(flow, attr, buf->entry[i].pattern,\n+\t\t\t\t\t    actions, &item_flags, &action_flags,\n+\t\t\t\t\t    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\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\tret = flow_drv_translate(dev, dev_flow, attr,\n+\t\t\t\t\t buf->entry[i].pattern,\n+\t\t\t\t\t actions, error);\n \t\tif (ret < 0)\n \t\t\tgoto error;\n \t}\n \tif (dev->data->dev_started) {\n-\t\tret = nic_ops.apply(dev, flow, error);\n+\t\tret = flow_drv_apply(dev, flow, error);\n \t\tif (ret < 0)\n \t\t\tgoto error;\n \t}\n@@ -1667,7 +1962,7 @@ mlx5_flow_list_create(struct rte_eth_dev *dev,\n error:\n \tret = rte_errno; /* Save rte_errno before cleanup. */\n \tassert(flow);\n-\tnic_ops.destroy(dev, flow);\n+\tflow_drv_destroy(dev, flow);\n \trte_free(flow);\n \trte_errno = ret; /* Restore rte_errno. */\n \treturn NULL;\n@@ -1705,7 +2000,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-\tnic_ops.destroy(dev, flow);\n+\tflow_drv_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@@ -1749,7 +2044,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\tnic_ops.remove(dev, flow);\n+\t\tflow_drv_remove(dev, flow);\n \tmlx5_flow_rxq_flags_clear(dev);\n }\n \n@@ -1772,7 +2067,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 = nic_ops.apply(dev, flow, &error);\n+\t\tret = flow_drv_apply(dev, flow, &error);\n \t\tif (ret < 0)\n \t\t\tgoto error;\n \t\tmlx5_flow_rxq_flags_set(dev, flow);\n@@ -2463,24 +2758,3 @@ 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)\n-{\n-\tstruct priv *priv __rte_unused = dev->data->dev_private;\n-\n-#ifdef HAVE_IBV_FLOW_DV_SUPPORT\n-\tif (priv->config.dv_flow_en)\n-\t\tmlx5_flow_dv_get_driver_ops(&nic_ops);\n-\telse\n-\t\tmlx5_flow_verbs_get_driver_ops(&nic_ops);\n-#else\n-\tmlx5_flow_verbs_get_driver_ops(&nic_ops);\n-#endif\n-}\ndiff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h\nindex 53c0eeb56..2bc3bee8c 100644\n--- a/drivers/net/mlx5/mlx5_flow.h\n+++ b/drivers/net/mlx5/mlx5_flow.h\n@@ -128,6 +128,13 @@\n /* Max number of actions per DV flow. */\n #define MLX5_DV_MAX_NUMBER_OF_ACTIONS 8\n \n+enum mlx5_flow_drv_type {\n+\tMLX5_FLOW_TYPE_MIN,\n+\tMLX5_FLOW_TYPE_DV,\n+\tMLX5_FLOW_TYPE_VERBS,\n+\tMLX5_FLOW_TYPE_MAX,\n+};\n+\n /* Matcher PRM representation */\n struct mlx5_flow_dv_match_params {\n \tsize_t size;\n@@ -210,7 +217,7 @@ struct mlx5_flow_counter {\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+\tenum mlx5_flow_drv_type drv_type; /**< Drvier type. */\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@@ -314,13 +321,5 @@ 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_dv.c */\n-void mlx5_flow_dv_get_driver_ops(struct mlx5_flow_driver_ops *flow_ops);\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_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c\nindex 71af410b2..cf663cdb8 100644\n--- a/drivers/net/mlx5/mlx5_flow_dv.c\n+++ b/drivers/net/mlx5/mlx5_flow_dv.c\n@@ -1351,23 +1351,13 @@ flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)\n \t}\n }\n \n-/**\n- * Fills the flow_ops with the function pointers.\n- *\n- * @param[out] flow_ops\n- *   Pointer to driver_ops structure.\n- */\n-void\n-mlx5_flow_dv_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_dv_validate,\n-\t\t.prepare = flow_dv_prepare,\n-\t\t.translate = flow_dv_translate,\n-\t\t.apply = flow_dv_apply,\n-\t\t.remove = flow_dv_remove,\n-\t\t.destroy = flow_dv_destroy,\n-\t};\n-}\n+const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {\n+\t.validate = flow_dv_validate,\n+\t.prepare = flow_dv_prepare,\n+\t.translate = flow_dv_translate,\n+\t.apply = flow_dv_apply,\n+\t.remove = flow_dv_remove,\n+\t.destroy = flow_dv_destroy,\n+};\n \n #endif /* HAVE_IBV_FLOW_DV_SUPPORT */\ndiff --git a/drivers/net/mlx5/mlx5_flow_verbs.c b/drivers/net/mlx5/mlx5_flow_verbs.c\nindex f4a264232..05ab5fdad 100644\n--- a/drivers/net/mlx5/mlx5_flow_verbs.c\n+++ b/drivers/net/mlx5/mlx5_flow_verbs.c\n@@ -1638,15 +1638,11 @@ flow_verbs_apply(struct rte_eth_dev *dev, struct rte_flow *flow,\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+const struct mlx5_flow_driver_ops mlx5_flow_verbs_drv_ops = {\n+\t.validate = flow_verbs_validate,\n+\t.prepare = flow_verbs_prepare,\n+\t.translate = flow_verbs_translate,\n+\t.apply = flow_verbs_apply,\n+\t.remove = flow_verbs_remove,\n+\t.destroy = flow_verbs_destroy,\n+};\n",
    "prefixes": [
        "v2",
        "1/3"
    ]
}