Show a patch.

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

{
    "id": 45241,
    "url": "http://patches.dpdk.org/api/patches/45241/",
    "web_url": "http://patches.dpdk.org/patch/45241/",
    "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-4-yskoh@mellanox.com>",
    "date": "2018-09-24T19:55:17",
    "name": "[v2,3/3] net/mlx5: add Linux TC flower driver for E-Switch flow",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "3e9e5255bd5c2d443fd46dfc04c2ffda0330a52f",
    "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/45241/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/45241/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/45241/checks/",
    "tags": {},
    "headers": {
        "x-ms-office365-filtering-ht": "Tenant",
        "x-microsoft-antispam-message-info": "UxfiV6ta1xvPOZwqmCZy2uRpRMd1dfb00tZh/qqS5eFk47HlU4nueV6kseX91pv+6ywt1YtealI1L8apbMTaE2SuyBhZL9h7zEpup0w/ZjyITh/kjMLUAheirctKGbhwmeDRxsbt6Ef1m7RGuOy9GB20pi5AsraGZ0KxVlBlFTSEQOl8JGA21L4qjhWMIvv5rElyUId1AAl+KSAickUsabxdS8i1W361h+9d7tFfHzOH25Zv8XiqbgkWiOMQd4ylLQ6JqDlimMZflF9nDW4jBf/hLCpYLxwZsMrZiuEH3+vyF+6VMzX2O5rgALxlKCC+FGp+2W/3ZlyTgnZ8+sS1yVi1QK6+a5CVzNysih/p40w=",
        "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=A1VQFOtIf78fIjCrT99ajLWD2KnJSfWrQ3VJf4wGlR0=;\n\tb=jfUoPeLVskHHe2+Xvif1TV19x3KOkMKov7RWeZ1ytPJbZJYqUfbFsvG8A7cdg/6bawjgPIrTWahwlpY+7ErhnW3AFCcUS9AU3VtEy/Eay/ia4qSxU7gEFkC6J/sDn39oxl2CYSTKIsAalXW5eyvCwqczOg2YrbNY2lDvsailrW4=",
        "x-microsoft-exchange-diagnostics": "1; DB3PR0502MB3995;\n\t6:a6V5+RCZ48K2BMXuiei77y7f7NZtr73s5TII173NJ13MMbO/cgJpssI6MvUMJ9wQDfjEoGOGB5cKTsajN2uTJfyEhQ+9iLlvq5jKXnUDcx2uFUBJcLbzFWlcV2qfm+19WkPAWjEfUULzHfdVfIvBbB4BM/rNnKpkhn25XPZqT9hT0pJqWhzh1N3JLrmAbx3kAsMn3AXeLFG/AtnFHdxRWQpuX8U6262/6x1Bl0Vf2oBCaWR8y6Hh47oVq+g0p1EM/APH9BGPIq/qMMkfZg6djfn84sJxZlkTzf8QRJKJ/IWYpMa2UEh8nGuWGgL1Bbu5W63PEXdJK6/keLiXjIPVlDYlnKEaQX3nR8IWmnBHO52qj8FlAXHgOGdMnIjWF1WAhhxv3AHTY6r+Pmy2Y+pq3SlmTMO9Ic0c9dnL/L80gV1GcvLg/hFeTz6Knfy1Uy/QMvYP1QQTwDHCANPDqckdUw==;\n\t5:Vhj7uK+78+J4G4drYRc0Utsm3o3AWjXYdWEUIrvOGXsuwWZC5WTEgVXT2ZoakTD4x6IRp6xPHlc6ws/SVp/MmtijLhoUxxpNqnyNAW6Fg87mJDsV+4pTUMibg0zJjRecTP8rcIZXY+5Eoiukf3VDHa4ZDwLPO6O2un/A7oA3w/g=;\n\t7:pa31u2iJFxvR7+2fOMlALhjh0X/n43/9nwZr9BdapqL8wGeQFgWZqF68CagHJ/WcYg9tQ4flpJhYq1yg66Ukn5QebYt8gXU5WinADmhUeKkmL2wIFgzCKGmN12Mwfv5dGmt/MEXwPn7Xc2oJTG5MaVsbEqsdT6EeDcbToSwko6oh7YxzprzIcL5/qMysV+f5G6V9Lp9pm+/dcrz8I75rN44Sc0HvTeNJjdrOMivXSX+qCVwZnLnd0pHbRgDHo7pl",
        "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 3/3] net/mlx5: add Linux TC flower driver for\n\tE-Switch flow",
        "spamdiagnosticmetadata": "NSPM",
        "Date": "Mon, 24 Sep 2018 19:55:17 +0000",
        "authentication-results": "spf=none (sender IP is )\n\tsmtp.mailfrom=yskoh@mellanox.com; ",
        "X-MS-Exchange-CrossTenant-originalarrivaltime": "24 Sep 2018 19:55:18.0288\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 3/3] net/mlx5: add Linux TC flower driver for\n\tE-Switch flow",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "76b8f6cd-8cce-47f0-5f40-08d62257a6b7",
        "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": "<DB3PR0502MB399518542312227FBFB8B371C3170@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)(16200700003)(6636002)(6486002)(71190400001)(52116002)(86362001)(76176011)(97736004)(5024004)(2900100001)(575784001)(256004)(186003)(6512007)(579004)(559001)(569006);\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": "76b8f6cd-8cce-47f0-5f40-08d62257a6b7",
        "Errors-To": "dev-bounces@dpdk.org",
        "x-exchange-antispam-report-test": "UriScan:(269456686620040)(211171220733660); ",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 125171B183;\n\tMon, 24 Sep 2018 21:55:24 +0200 (CEST)",
            "from EUR03-DB5-obe.outbound.protection.outlook.com\n\t(mail-eopbgr40087.outbound.protection.outlook.com [40.107.4.87])\n\tby dpdk.org (Postfix) with ESMTP id 0F2E81B136\n\tfor <dev@dpdk.org>; Mon, 24 Sep 2018 21:55:20 +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:18 +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:18 +0000"
        ],
        "x-ms-exchange-messagesentrepresentingtype": "1",
        "Thread-Index": "AQHUVECEVd3FAqlQAk+L1PTZBkOIsg==",
        "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-4-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": "Flows having 'transfer' attribute have to be inserted to E-Switch on the\nNIC and the control path uses Linux TC flower interface via Netlink socket.\nThis patch adds the flow driver on top of the new flow engine.\n\nSigned-off-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          |   33 +\n drivers/net/mlx5/mlx5_flow.c     |    6 +-\n drivers/net/mlx5/mlx5_flow.h     |   20 +\n drivers/net/mlx5/mlx5_flow_tcf.c | 1608 ++++++++++++++++++++++++++++++++++++++\n 6 files changed, 1668 insertions(+), 1 deletion(-)\n create mode 100644 drivers/net/mlx5/mlx5_flow_tcf.c",
    "diff": "diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile\nindex 9c1044808..ca1de9f21 100644\n--- a/drivers/net/mlx5/Makefile\n+++ b/drivers/net/mlx5/Makefile\n@@ -32,6 +32,7 @@ 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_dv.c\n+SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_flow_tcf.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\ndiff --git a/drivers/net/mlx5/meson.build b/drivers/net/mlx5/meson.build\nindex e5376291c..fd93ac162 100644\n--- a/drivers/net/mlx5/meson.build\n+++ b/drivers/net/mlx5/meson.build\n@@ -32,6 +32,7 @@ if build\n \t\t'mlx5_ethdev.c',\n \t\t'mlx5_flow.c',\n \t\t'mlx5_flow_dv.c',\n+\t\t'mlx5_flow_tcf.c',\n \t\t'mlx5_flow_verbs.c',\n \t\t'mlx5_mac.c',\n \t\t'mlx5_mr.c',\ndiff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c\nindex bb9a63fba..4be6a1cc9 100644\n--- a/drivers/net/mlx5/mlx5.c\n+++ b/drivers/net/mlx5/mlx5.c\n@@ -44,6 +44,7 @@\n #include \"mlx5_rxtx.h\"\n #include \"mlx5_autoconf.h\"\n #include \"mlx5_defs.h\"\n+#include \"mlx5_flow.h\"\n #include \"mlx5_glue.h\"\n #include \"mlx5_mr.h\"\n #include \"mlx5_flow.h\"\n@@ -286,6 +287,8 @@ mlx5_dev_close(struct rte_eth_dev *dev)\n \t\tclose(priv->nl_socket_route);\n \tif (priv->nl_socket_rdma >= 0)\n \t\tclose(priv->nl_socket_rdma);\n+\tif (priv->mnl_socket)\n+\t\tmlx5_flow_tcf_socket_destroy(priv->mnl_socket);\n \tret = mlx5_hrxq_ibv_verify(dev);\n \tif (ret)\n \t\tDRV_LOG(WARNING, \"port %u some hash Rx queue still remain\",\n@@ -1135,6 +1138,34 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,\n \tclaim_zero(mlx5_mac_addr_add(eth_dev, &mac, 0, 0));\n \tif (vf && config.vf_nl_en)\n \t\tmlx5_nl_mac_addr_sync(eth_dev);\n+\tpriv->mnl_socket = mlx5_flow_tcf_socket_create();\n+\tif (!priv->mnl_socket) {\n+\t\terr = -rte_errno;\n+\t\tDRV_LOG(WARNING,\n+\t\t\t\"flow rules relying on switch offloads will not be\"\n+\t\t\t\" supported: cannot open libmnl socket: %s\",\n+\t\t\tstrerror(rte_errno));\n+\t} else {\n+\t\tstruct rte_flow_error error;\n+\t\tunsigned int ifindex = mlx5_ifindex(eth_dev);\n+\n+\t\tif (!ifindex) {\n+\t\t\terr = -rte_errno;\n+\t\t\terror.message =\n+\t\t\t\t\"cannot retrieve network interface index\";\n+\t\t} else {\n+\t\t\terr = mlx5_flow_tcf_init(priv->mnl_socket, ifindex,\n+\t\t\t\t\t\t&error);\n+\t\t}\n+\t\tif (err) {\n+\t\t\tDRV_LOG(WARNING,\n+\t\t\t\t\"flow rules relying on switch offloads will\"\n+\t\t\t\t\" not be supported: %s: %s\",\n+\t\t\t\terror.message, strerror(rte_errno));\n+\t\t\tmlx5_flow_tcf_socket_destroy(priv->mnl_socket);\n+\t\t\tpriv->mnl_socket = NULL;\n+\t\t}\n+\t}\n \tTAILQ_INIT(&priv->flows);\n \tTAILQ_INIT(&priv->ctrl_flows);\n \t/* Hint libmlx5 to use PMD allocator for data plane resources */\n@@ -1187,6 +1218,8 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,\n \t\t\tclose(priv->nl_socket_route);\n \t\tif (priv->nl_socket_rdma >= 0)\n \t\t\tclose(priv->nl_socket_rdma);\n+\t\tif (priv->mnl_socket)\n+\t\t\tmlx5_flow_tcf_socket_destroy(priv->mnl_socket);\n \t\tif (own_domain_id)\n \t\t\tclaim_zero(rte_eth_switch_domain_free(priv->domain_id));\n \t\trte_free(priv);\ndiff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c\nindex 54008afa4..7660bee30 100644\n--- a/drivers/net/mlx5/mlx5_flow.c\n+++ b/drivers/net/mlx5/mlx5_flow.c\n@@ -41,6 +41,7 @@ extern const struct eth_dev_ops mlx5_dev_ops_isolate;\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_tcf_drv_ops;\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@@ -50,6 +51,7 @@ const struct mlx5_flow_driver_ops *flow_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_TCF] = &mlx5_flow_tcf_drv_ops,\n \t[MLX5_FLOW_TYPE_VERBS] = &mlx5_flow_verbs_drv_ops,\n \t[MLX5_FLOW_TYPE_MAX] = &mlx5_flow_null_drv_ops\n };\n@@ -1609,7 +1611,9 @@ flow_get_drv_type(struct rte_eth_dev *dev __rte_unused,\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+\tif (attr->transfer) {\n+\t\ttype = MLX5_FLOW_TYPE_TCF;\n+\t} else {\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;\ndiff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h\nindex 2bc3bee8c..10d700a7f 100644\n--- a/drivers/net/mlx5/mlx5_flow.h\n+++ b/drivers/net/mlx5/mlx5_flow.h\n@@ -82,6 +82,11 @@\n #define MLX5_ACTION_FLAG (1u << 3)\n #define MLX5_ACTION_MARK (1u << 4)\n #define MLX5_ACTION_COUNT (1u << 5)\n+#define MLX5_ACTION_PORT_ID (1u << 6)\n+#define MLX5_ACTION_OF_POP_VLAN (1u << 7)\n+#define MLX5_ACTION_OF_PUSH_VLAN (1u << 8)\n+#define MLX5_ACTION_OF_SET_VLAN_VID (1u << 9)\n+#define MLX5_ACTION_OF_SET_VLAN_PCP (1u << 10)\n \n /* possible L3 layers protocols filtering. */\n #define MLX5_IP_PROTOCOL_TCP 6\n@@ -131,6 +136,7 @@\n enum mlx5_flow_drv_type {\n \tMLX5_FLOW_TYPE_MIN,\n \tMLX5_FLOW_TYPE_DV,\n+\tMLX5_FLOW_TYPE_TCF,\n \tMLX5_FLOW_TYPE_VERBS,\n \tMLX5_FLOW_TYPE_MAX,\n };\n@@ -170,6 +176,12 @@ struct mlx5_flow_dv {\n \tint actions_n; /**< number of actions. */\n };\n \n+/** Linux TC flower driver for E-Switch flow. */\n+struct mlx5_flow_tcf {\n+\tstruct nlmsghdr *nlh;\n+\tstruct tcmsg *tcm;\n+};\n+\n /* Verbs specification header. */\n struct ibv_spec_header {\n \tenum ibv_flow_spec_type type;\n@@ -199,6 +211,7 @@ struct mlx5_flow {\n #ifdef HAVE_IBV_FLOW_DV_SUPPORT\n \t\tstruct mlx5_flow_dv dv;\n #endif\n+\t\tstruct mlx5_flow_tcf tcf;\n \t\tstruct mlx5_flow_verbs verbs;\n \t};\n };\n@@ -322,4 +335,11 @@ int mlx5_flow_validate_item_vxlan_gpe(const struct rte_flow_item *item,\n \t\t\t\t      struct rte_eth_dev *dev,\n \t\t\t\t      struct rte_flow_error *error);\n \n+/* mlx5_flow_tcf.c */\n+\n+int mlx5_flow_tcf_init(struct mnl_socket *nl, unsigned int ifindex,\n+\t\t       struct rte_flow_error *error);\n+struct mnl_socket *mlx5_flow_tcf_socket_create(void);\n+void mlx5_flow_tcf_socket_destroy(struct mnl_socket *nl);\n+\n #endif /* RTE_PMD_MLX5_FLOW_H_ */\ndiff --git a/drivers/net/mlx5/mlx5_flow_tcf.c b/drivers/net/mlx5/mlx5_flow_tcf.c\nnew file mode 100644\nindex 000000000..14376188e\n--- /dev/null\n+++ b/drivers/net/mlx5/mlx5_flow_tcf.c\n@@ -0,0 +1,1608 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright 2018 6WIND S.A.\n+ * Copyright 2018 Mellanox Technologies, Ltd\n+ */\n+\n+#include <assert.h>\n+#include <errno.h>\n+#include <libmnl/libmnl.h>\n+#include <linux/if_ether.h>\n+#include <linux/netlink.h>\n+#include <linux/pkt_cls.h>\n+#include <linux/pkt_sched.h>\n+#include <linux/rtnetlink.h>\n+#include <linux/tc_act/tc_gact.h>\n+#include <linux/tc_act/tc_mirred.h>\n+#include <netinet/in.h>\n+#include <stdalign.h>\n+#include <stdbool.h>\n+#include <stddef.h>\n+#include <stdint.h>\n+#include <stdlib.h>\n+#include <sys/socket.h>\n+\n+#include <rte_byteorder.h>\n+#include <rte_errno.h>\n+#include <rte_ether.h>\n+#include <rte_flow.h>\n+#include <rte_malloc.h>\n+\n+#include \"mlx5.h\"\n+#include \"mlx5_flow.h\"\n+#include \"mlx5_autoconf.h\"\n+\n+#ifdef HAVE_TC_ACT_VLAN\n+\n+#include <linux/tc_act/tc_vlan.h>\n+\n+#else /* HAVE_TC_ACT_VLAN */\n+\n+#define TCA_VLAN_ACT_POP 1\n+#define TCA_VLAN_ACT_PUSH 2\n+#define TCA_VLAN_ACT_MODIFY 3\n+#define TCA_VLAN_PARMS 2\n+#define TCA_VLAN_PUSH_VLAN_ID 3\n+#define TCA_VLAN_PUSH_VLAN_PROTOCOL 4\n+#define TCA_VLAN_PAD 5\n+#define TCA_VLAN_PUSH_VLAN_PRIORITY 6\n+\n+struct tc_vlan {\n+\ttc_gen;\n+\tint v_action;\n+};\n+\n+#endif /* HAVE_TC_ACT_VLAN */\n+\n+/* Normally found in linux/netlink.h. */\n+#ifndef NETLINK_CAP_ACK\n+#define NETLINK_CAP_ACK 10\n+#endif\n+\n+/* Normally found in linux/pkt_sched.h. */\n+#ifndef TC_H_MIN_INGRESS\n+#define TC_H_MIN_INGRESS 0xfff2u\n+#endif\n+\n+/* Normally found in linux/pkt_cls.h. */\n+#ifndef TCA_CLS_FLAGS_SKIP_SW\n+#define TCA_CLS_FLAGS_SKIP_SW (1 << 1)\n+#endif\n+#ifndef HAVE_TCA_FLOWER_ACT\n+#define TCA_FLOWER_ACT 3\n+#endif\n+#ifndef HAVE_TCA_FLOWER_FLAGS\n+#define TCA_FLOWER_FLAGS 22\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_ETH_TYPE\n+#define TCA_FLOWER_KEY_ETH_TYPE 8\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_ETH_DST\n+#define TCA_FLOWER_KEY_ETH_DST 4\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_ETH_DST_MASK\n+#define TCA_FLOWER_KEY_ETH_DST_MASK 5\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_ETH_SRC\n+#define TCA_FLOWER_KEY_ETH_SRC 6\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_ETH_SRC_MASK\n+#define TCA_FLOWER_KEY_ETH_SRC_MASK 7\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_IP_PROTO\n+#define TCA_FLOWER_KEY_IP_PROTO 9\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_IPV4_SRC\n+#define TCA_FLOWER_KEY_IPV4_SRC 10\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_IPV4_SRC_MASK\n+#define TCA_FLOWER_KEY_IPV4_SRC_MASK 11\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_IPV4_DST\n+#define TCA_FLOWER_KEY_IPV4_DST 12\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_IPV4_DST_MASK\n+#define TCA_FLOWER_KEY_IPV4_DST_MASK 13\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_IPV6_SRC\n+#define TCA_FLOWER_KEY_IPV6_SRC 14\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_IPV6_SRC_MASK\n+#define TCA_FLOWER_KEY_IPV6_SRC_MASK 15\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_IPV6_DST\n+#define TCA_FLOWER_KEY_IPV6_DST 16\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_IPV6_DST_MASK\n+#define TCA_FLOWER_KEY_IPV6_DST_MASK 17\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_TCP_SRC\n+#define TCA_FLOWER_KEY_TCP_SRC 18\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_TCP_SRC_MASK\n+#define TCA_FLOWER_KEY_TCP_SRC_MASK 35\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_TCP_DST\n+#define TCA_FLOWER_KEY_TCP_DST 19\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_TCP_DST_MASK\n+#define TCA_FLOWER_KEY_TCP_DST_MASK 36\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_UDP_SRC\n+#define TCA_FLOWER_KEY_UDP_SRC 20\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_UDP_SRC_MASK\n+#define TCA_FLOWER_KEY_UDP_SRC_MASK 37\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_UDP_DST\n+#define TCA_FLOWER_KEY_UDP_DST 21\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_UDP_DST_MASK\n+#define TCA_FLOWER_KEY_UDP_DST_MASK 38\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_VLAN_ID\n+#define TCA_FLOWER_KEY_VLAN_ID 23\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_VLAN_PRIO\n+#define TCA_FLOWER_KEY_VLAN_PRIO 24\n+#endif\n+#ifndef HAVE_TCA_FLOWER_KEY_VLAN_ETH_TYPE\n+#define TCA_FLOWER_KEY_VLAN_ETH_TYPE 25\n+#endif\n+\n+#ifndef IPV6_ADDR_LEN\n+#define IPV6_ADDR_LEN 16\n+#endif\n+\n+/** Empty masks for known item types. */\n+static const union {\n+\tstruct rte_flow_item_port_id port_id;\n+\tstruct rte_flow_item_eth eth;\n+\tstruct rte_flow_item_vlan vlan;\n+\tstruct rte_flow_item_ipv4 ipv4;\n+\tstruct rte_flow_item_ipv6 ipv6;\n+\tstruct rte_flow_item_tcp tcp;\n+\tstruct rte_flow_item_udp udp;\n+} flow_tcf_mask_empty;\n+\n+/** Supported masks for known item types. */\n+static const struct {\n+\tstruct rte_flow_item_port_id port_id;\n+\tstruct rte_flow_item_eth eth;\n+\tstruct rte_flow_item_vlan vlan;\n+\tstruct rte_flow_item_ipv4 ipv4;\n+\tstruct rte_flow_item_ipv6 ipv6;\n+\tstruct rte_flow_item_tcp tcp;\n+\tstruct rte_flow_item_udp udp;\n+} flow_tcf_mask_supported = {\n+\t.port_id = {\n+\t\t.id = 0xffffffff,\n+\t},\n+\t.eth = {\n+\t\t.type = RTE_BE16(0xffff),\n+\t\t.dst.addr_bytes = \"\\xff\\xff\\xff\\xff\\xff\\xff\",\n+\t\t.src.addr_bytes = \"\\xff\\xff\\xff\\xff\\xff\\xff\",\n+\t},\n+\t.vlan = {\n+\t\t/* PCP and VID only, no DEI. */\n+\t\t.tci = RTE_BE16(0xefff),\n+\t\t.inner_type = RTE_BE16(0xffff),\n+\t},\n+\t.ipv4.hdr = {\n+\t\t.next_proto_id = 0xff,\n+\t\t.src_addr = RTE_BE32(0xffffffff),\n+\t\t.dst_addr = RTE_BE32(0xffffffff),\n+\t},\n+\t.ipv6.hdr = {\n+\t\t.proto = 0xff,\n+\t\t.src_addr =\n+\t\t\t\"\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\"\n+\t\t\t\"\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\",\n+\t\t.dst_addr =\n+\t\t\t\"\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\"\n+\t\t\t\"\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\",\n+\t},\n+\t.tcp.hdr = {\n+\t\t.src_port = RTE_BE16(0xffff),\n+\t\t.dst_port = RTE_BE16(0xffff),\n+\t},\n+\t.udp.hdr = {\n+\t\t.src_port = RTE_BE16(0xffff),\n+\t\t.dst_port = RTE_BE16(0xffff),\n+\t},\n+};\n+\n+#define SZ_NLATTR_HDR MNL_ALIGN(sizeof(struct nlattr))\n+#define SZ_NLATTR_NEST SZ_NLATTR_HDR\n+#define SZ_NLATTR_DATA_OF(len) MNL_ALIGN(SZ_NLATTR_HDR + (len))\n+#define SZ_NLATTR_TYPE_OF(typ) SZ_NLATTR_DATA_OF(sizeof(typ))\n+#define SZ_NLATTR_STRZ_OF(str) SZ_NLATTR_DATA_OF(strlen(str) + 1)\n+\n+#define PTOI_TABLE_SZ_MAX(dev) (mlx5_dev_to_port_id((dev)->device, NULL, 0) + 2)\n+\n+/** DPDK port to network interface index (ifindex) conversion. */\n+struct flow_tcf_ptoi {\n+\tuint16_t port_id; /**< DPDK port ID. */\n+\tunsigned int ifindex; /**< Network interface index. */\n+};\n+\n+#define MLX5_TCF_FATE_ACTIONS (MLX5_ACTION_DROP | MLX5_ACTION_PORT_ID)\n+\n+/**\n+ * Retrieve mask for pattern item.\n+ *\n+ * This function does basic sanity checks on a pattern item in order to\n+ * return the most appropriate mask for it.\n+ *\n+ * @param[in] item\n+ *   Item specification.\n+ * @param[in] mask_default\n+ *   Default mask for pattern item as specified by the flow API.\n+ * @param[in] mask_supported\n+ *   Mask fields supported by the implementation.\n+ * @param[in] mask_empty\n+ *   Empty mask to return when there is no specification.\n+ * @param[out] error\n+ *   Perform verbose error reporting if not NULL.\n+ *\n+ * @return\n+ *   Either @p item->mask or one of the mask parameters on success, NULL\n+ *   otherwise and rte_errno is set.\n+ */\n+static const void *\n+flow_tcf_item_mask(const struct rte_flow_item *item, const void *mask_default,\n+\t\t   const void *mask_supported, const void *mask_empty,\n+\t\t   size_t mask_size, struct rte_flow_error *error)\n+{\n+\tconst uint8_t *mask;\n+\tsize_t i;\n+\n+\t/* item->last and item->mask cannot exist without item->spec. */\n+\tif (!item->spec && (item->mask || item->last)) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM, item,\n+\t\t\t\t   \"\\\"mask\\\" or \\\"last\\\" field provided without\"\n+\t\t\t\t   \" a corresponding \\\"spec\\\"\");\n+\t\treturn NULL;\n+\t}\n+\t/* No spec, no mask, no problem. */\n+\tif (!item->spec)\n+\t\treturn mask_empty;\n+\tmask = item->mask ? item->mask : mask_default;\n+\tassert(mask);\n+\t/*\n+\t * Single-pass check to make sure that:\n+\t * - Mask is supported, no bits are set outside mask_supported.\n+\t * - Both item->spec and item->last are included in mask.\n+\t */\n+\tfor (i = 0; i != mask_size; ++i) {\n+\t\tif (!mask[i])\n+\t\t\tcontinue;\n+\t\tif ((mask[i] | ((const uint8_t *)mask_supported)[i]) !=\n+\t\t    ((const uint8_t *)mask_supported)[i]) {\n+\t\t\trte_flow_error_set(error, ENOTSUP,\n+\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask,\n+\t\t\t\t\t   \"unsupported field found\"\n+\t\t\t\t\t   \" in \\\"mask\\\"\");\n+\t\t\treturn NULL;\n+\t\t}\n+\t\tif (item->last &&\n+\t\t    (((const uint8_t *)item->spec)[i] & mask[i]) !=\n+\t\t    (((const uint8_t *)item->last)[i] & mask[i])) {\n+\t\t\trte_flow_error_set(error, ENOTSUP,\n+\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM_LAST,\n+\t\t\t\t\t   item->last,\n+\t\t\t\t\t   \"range between \\\"spec\\\" and \\\"last\\\"\"\n+\t\t\t\t\t   \" not comprised in \\\"mask\\\"\");\n+\t\t\treturn NULL;\n+\t\t}\n+\t}\n+\treturn mask;\n+}\n+\n+/**\n+ * Build a conversion table between port ID and ifindex.\n+ *\n+ * @param[in] dev\n+ *   Pointer to Ethernet device.\n+ * @param[out] ptoi\n+ *   Pointer to ptoi table.\n+ * @param[in] len\n+ *   Size of ptoi table provided.\n+ *\n+ * @return\n+ *   Size of ptoi table filled.\n+ */\n+static unsigned int\n+flow_tcf_build_ptoi_table(struct rte_eth_dev *dev, struct flow_tcf_ptoi *ptoi,\n+\t\t\t  unsigned int len)\n+{\n+\tunsigned int n = mlx5_dev_to_port_id(dev->device, NULL, 0);\n+\tuint16_t port_id[n + 1];\n+\tunsigned int i;\n+\tunsigned int own = 0;\n+\n+\t/* At least one port is needed when no switch domain is present. */\n+\tif (!n) {\n+\t\tn = 1;\n+\t\tport_id[0] = dev->data->port_id;\n+\t} else {\n+\t\tn = RTE_MIN(mlx5_dev_to_port_id(dev->device, port_id, n), n);\n+\t}\n+\tif (n > len)\n+\t\treturn 0;\n+\tfor (i = 0; i != n; ++i) {\n+\t\tstruct rte_eth_dev_info dev_info;\n+\n+\t\trte_eth_dev_info_get(port_id[i], &dev_info);\n+\t\tif (port_id[i] == dev->data->port_id)\n+\t\t\town = i;\n+\t\tptoi[i].port_id = port_id[i];\n+\t\tptoi[i].ifindex = dev_info.if_index;\n+\t}\n+\t/* Ensure first entry of ptoi[] is the current device. */\n+\tif (own) {\n+\t\tptoi[n] = ptoi[0];\n+\t\tptoi[0] = ptoi[own];\n+\t\tptoi[own] = ptoi[n];\n+\t}\n+\t/* An entry with zero ifindex terminates ptoi[]. */\n+\tptoi[n].port_id = 0;\n+\tptoi[n].ifindex = 0;\n+\treturn n;\n+}\n+\n+/**\n+ * Verify the @p attr will be correctly understood by the E-switch.\n+ *\n+ * @param[in] attr\n+ *   Pointer to flow attributes\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_tcf_validate_attributes(const struct rte_flow_attr *attr,\n+\t\t\t     struct rte_flow_error *error)\n+{\n+\t/*\n+\t * Supported attributes: no groups, some priorities and ingress only.\n+\t * Don't care about transfer as it is the caller's problem.\n+\t */\n+\tif (attr->group)\n+\t\treturn rte_flow_error_set(error, ENOTSUP,\n+\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ATTR_GROUP, attr,\n+\t\t\t\t\t  \"groups are not supported\");\n+\tif (attr->priority > 0xfffe)\n+\t\treturn rte_flow_error_set(error, ENOTSUP,\n+\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,\n+\t\t\t\t\t  attr,\n+\t\t\t\t\t  \"lowest priority level is 0xfffe\");\n+\tif (!attr->ingress)\n+\t\treturn rte_flow_error_set(error, ENOTSUP,\n+\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,\n+\t\t\t\t\t  attr, \"only ingress is supported\");\n+\tif (attr->egress)\n+\t\treturn rte_flow_error_set(error, ENOTSUP,\n+\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,\n+\t\t\t\t\t  attr, \"egress is not supported\");\n+\treturn 0;\n+}\n+\n+/**\n+ * Validate flow for E-Switch.\n+ *\n+ * @param[in] priv\n+ *   Pointer to the priv 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\n+flow_tcf_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+\tunion {\n+\t\tconst struct rte_flow_item_port_id *port_id;\n+\t\tconst struct rte_flow_item_eth *eth;\n+\t\tconst struct rte_flow_item_vlan *vlan;\n+\t\tconst struct rte_flow_item_ipv4 *ipv4;\n+\t\tconst struct rte_flow_item_ipv6 *ipv6;\n+\t\tconst struct rte_flow_item_tcp *tcp;\n+\t\tconst struct rte_flow_item_udp *udp;\n+\t} spec, mask;\n+\tunion {\n+\t\tconst struct rte_flow_action_port_id *port_id;\n+\t\tconst struct rte_flow_action_of_push_vlan *of_push_vlan;\n+\t\tconst struct rte_flow_action_of_set_vlan_vid *\n+\t\t\tof_set_vlan_vid;\n+\t\tconst struct rte_flow_action_of_set_vlan_pcp *\n+\t\t\tof_set_vlan_pcp;\n+\t} conf;\n+\tuint32_t item_flags = 0;\n+\tuint32_t action_flags = 0;\n+\tuint8_t next_protocol = -1;\n+\tunsigned int tcm_ifindex = 0;\n+\tstruct flow_tcf_ptoi ptoi[PTOI_TABLE_SZ_MAX(dev)];\n+\tbool in_port_id_set;\n+\tint ret;\n+\n+\tclaim_nonzero(flow_tcf_build_ptoi_table(dev, ptoi,\n+\t\t\t\t\t\tPTOI_TABLE_SZ_MAX(dev)));\n+\tret = flow_tcf_validate_attributes(attr, error);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\tfor (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {\n+\t\tunsigned int i;\n+\n+\t\tswitch (items->type) {\n+\t\tcase RTE_FLOW_ITEM_TYPE_VOID:\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_PORT_ID:\n+\t\t\tmask.port_id = flow_tcf_item_mask\n+\t\t\t\t(items, &rte_flow_item_port_id_mask,\n+\t\t\t\t &flow_tcf_mask_supported.port_id,\n+\t\t\t\t &flow_tcf_mask_empty.port_id,\n+\t\t\t\t sizeof(flow_tcf_mask_supported.port_id),\n+\t\t\t\t error);\n+\t\t\tif (!mask.port_id)\n+\t\t\t\treturn -rte_errno;\n+\t\t\tif (mask.port_id == &flow_tcf_mask_empty.port_id) {\n+\t\t\t\tin_port_id_set = 1;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tspec.port_id = items->spec;\n+\t\t\tif (mask.port_id->id && mask.port_id->id != 0xffffffff)\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_MASK,\n+\t\t\t\t\t mask.port_id,\n+\t\t\t\t\t \"no support for partial mask on\"\n+\t\t\t\t\t \" \\\"id\\\" field\");\n+\t\t\tif (!mask.port_id->id)\n+\t\t\t\ti = 0;\n+\t\t\telse\n+\t\t\t\tfor (i = 0; ptoi[i].ifindex; ++i)\n+\t\t\t\t\tif (ptoi[i].port_id == spec.port_id->id)\n+\t\t\t\t\t\tbreak;\n+\t\t\tif (!ptoi[i].ifindex)\n+\t\t\t\treturn rte_flow_error_set\n+\t\t\t\t\t(error, ENODEV,\n+\t\t\t\t\t RTE_FLOW_ERROR_TYPE_ITEM_SPEC,\n+\t\t\t\t\t spec.port_id,\n+\t\t\t\t\t \"missing data to convert port ID to\"\n+\t\t\t\t\t \" ifindex\");\n+\t\t\tif (in_port_id_set && ptoi[i].ifindex != tcm_ifindex)\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_SPEC,\n+\t\t\t\t\t spec.port_id,\n+\t\t\t\t\t \"cannot match traffic for\"\n+\t\t\t\t\t \" several port IDs through\"\n+\t\t\t\t\t \" a single flow rule\");\n+\t\t\ttcm_ifindex = ptoi[i].ifindex;\n+\t\t\tin_port_id_set = 1;\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 |= MLX5_FLOW_LAYER_OUTER_L2;\n+\t\t\t/* TODO:\n+\t\t\t * Redundant check due to different supported mask.\n+\t\t\t * Same for the rest of items.\n+\t\t\t */\n+\t\t\tmask.eth = flow_tcf_item_mask\n+\t\t\t\t(items, &rte_flow_item_eth_mask,\n+\t\t\t\t &flow_tcf_mask_supported.eth,\n+\t\t\t\t &flow_tcf_mask_empty.eth,\n+\t\t\t\t sizeof(flow_tcf_mask_supported.eth),\n+\t\t\t\t error);\n+\t\t\tif (!mask.eth)\n+\t\t\t\treturn -rte_errno;\n+\t\t\tif (mask.eth->type && mask.eth->type !=\n+\t\t\t    RTE_BE16(0xffff))\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_MASK,\n+\t\t\t\t\t mask.eth,\n+\t\t\t\t\t \"no support for partial mask on\"\n+\t\t\t\t\t \" \\\"type\\\" field\");\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 |= MLX5_FLOW_LAYER_OUTER_VLAN;\n+\t\t\tmask.vlan = flow_tcf_item_mask\n+\t\t\t\t(items, &rte_flow_item_vlan_mask,\n+\t\t\t\t &flow_tcf_mask_supported.vlan,\n+\t\t\t\t &flow_tcf_mask_empty.vlan,\n+\t\t\t\t sizeof(flow_tcf_mask_supported.vlan),\n+\t\t\t\t error);\n+\t\t\tif (!mask.vlan)\n+\t\t\t\treturn -rte_errno;\n+\t\t\tif ((mask.vlan->tci & RTE_BE16(0xe000) &&\n+\t\t\t     (mask.vlan->tci & RTE_BE16(0xe000)) !=\n+\t\t\t      RTE_BE16(0xe000)) ||\n+\t\t\t    (mask.vlan->tci & RTE_BE16(0x0fff) &&\n+\t\t\t     (mask.vlan->tci & RTE_BE16(0x0fff)) !=\n+\t\t\t      RTE_BE16(0x0fff)) ||\n+\t\t\t    (mask.vlan->inner_type &&\n+\t\t\t     mask.vlan->inner_type != RTE_BE16(0xffff)))\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_MASK,\n+\t\t\t\t\t mask.vlan,\n+\t\t\t\t\t \"no support for partial masks on\"\n+\t\t\t\t\t \" \\\"tci\\\" (PCP and VID parts) and\"\n+\t\t\t\t\t \" \\\"inner_type\\\" fields\");\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 |= MLX5_FLOW_LAYER_OUTER_L3_IPV4;\n+\t\t\tmask.ipv4 = flow_tcf_item_mask\n+\t\t\t\t(items, &rte_flow_item_ipv4_mask,\n+\t\t\t\t &flow_tcf_mask_supported.ipv4,\n+\t\t\t\t &flow_tcf_mask_empty.ipv4,\n+\t\t\t\t sizeof(flow_tcf_mask_supported.ipv4),\n+\t\t\t\t error);\n+\t\t\tif (!mask.ipv4)\n+\t\t\t\treturn -rte_errno;\n+\t\t\tif (mask.ipv4->hdr.next_proto_id &&\n+\t\t\t    mask.ipv4->hdr.next_proto_id != 0xff)\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_MASK,\n+\t\t\t\t\t mask.ipv4,\n+\t\t\t\t\t \"no support for partial mask on\"\n+\t\t\t\t\t \" \\\"hdr.next_proto_id\\\" field\");\n+\t\t\telse if (mask.ipv4->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 |= MLX5_FLOW_LAYER_OUTER_L3_IPV6;\n+\t\t\tmask.ipv6 = flow_tcf_item_mask\n+\t\t\t\t(items, &rte_flow_item_ipv6_mask,\n+\t\t\t\t &flow_tcf_mask_supported.ipv6,\n+\t\t\t\t &flow_tcf_mask_empty.ipv6,\n+\t\t\t\t sizeof(flow_tcf_mask_supported.ipv6),\n+\t\t\t\t error);\n+\t\t\tif (!mask.ipv6)\n+\t\t\t\treturn -rte_errno;\n+\t\t\tif (mask.ipv6->hdr.proto &&\n+\t\t\t    mask.ipv6->hdr.proto != 0xff)\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_MASK,\n+\t\t\t\t\t mask.ipv6,\n+\t\t\t\t\t \"no support for partial mask on\"\n+\t\t\t\t\t \" \\\"hdr.proto\\\" field\");\n+\t\t\telse if (mask.ipv6->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, error);\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\t\t\titem_flags |= MLX5_FLOW_LAYER_OUTER_L4_UDP;\n+\t\t\tmask.udp = flow_tcf_item_mask\n+\t\t\t\t(items, &rte_flow_item_udp_mask,\n+\t\t\t\t &flow_tcf_mask_supported.udp,\n+\t\t\t\t &flow_tcf_mask_empty.udp,\n+\t\t\t\t sizeof(flow_tcf_mask_supported.udp),\n+\t\t\t\t error);\n+\t\t\tif (!mask.udp)\n+\t\t\t\treturn -rte_errno;\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 |= MLX5_FLOW_LAYER_OUTER_L4_TCP;\n+\t\t\tmask.tcp = flow_tcf_item_mask\n+\t\t\t\t(items, &rte_flow_item_tcp_mask,\n+\t\t\t\t &flow_tcf_mask_supported.tcp,\n+\t\t\t\t &flow_tcf_mask_empty.tcp,\n+\t\t\t\t sizeof(flow_tcf_mask_supported.tcp),\n+\t\t\t\t error);\n+\t\t\tif (!mask.tcp)\n+\t\t\t\treturn -rte_errno;\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\tunsigned int i;\n+\n+\t\tswitch (actions->type) {\n+\t\tcase RTE_FLOW_ACTION_TYPE_VOID:\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_PORT_ID:\n+\t\t\tif (action_flags & MLX5_TCF_FATE_ACTIONS)\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_ACTION, actions,\n+\t\t\t\t\t \"can't have multiple fate actions\");\n+\t\t\tconf.port_id = actions->conf;\n+\t\t\tif (conf.port_id->original)\n+\t\t\t\ti = 0;\n+\t\t\telse\n+\t\t\t\tfor (i = 0; ptoi[i].ifindex; ++i)\n+\t\t\t\t\tif (ptoi[i].port_id == conf.port_id->id)\n+\t\t\t\t\t\tbreak;\n+\t\t\tif (!ptoi[i].ifindex)\n+\t\t\t\treturn rte_flow_error_set\n+\t\t\t\t\t(error, ENODEV,\n+\t\t\t\t\t RTE_FLOW_ERROR_TYPE_ACTION_CONF,\n+\t\t\t\t\t conf.port_id,\n+\t\t\t\t\t \"missing data to convert port ID to\"\n+\t\t\t\t\t \" ifindex\");\n+\t\t\taction_flags |= MLX5_ACTION_PORT_ID;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_DROP:\n+\t\t\tif (action_flags & MLX5_TCF_FATE_ACTIONS)\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_ACTION, actions,\n+\t\t\t\t\t \"can't have multiple fate actions\");\n+\t\t\taction_flags |= MLX5_ACTION_DROP;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:\n+\t\t\taction_flags |= MLX5_ACTION_OF_POP_VLAN;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:\n+\t\t\taction_flags |= MLX5_ACTION_OF_PUSH_VLAN;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:\n+\t\t\taction_flags |= MLX5_ACTION_OF_SET_VLAN_VID;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:\n+\t\t\taction_flags |= MLX5_ACTION_OF_SET_VLAN_PCP;\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 maximum size of memory for flow items of Linux TC flower and\n+ * extract specified items.\n+ *\n+ * @param[in] items\n+ *   Pointer to the list of items.\n+ * @param[out] item_flags\n+ *   Pointer to the detected items.\n+ *\n+ * @return\n+ *   Maximum size of memory for items.\n+ */\n+static int\n+flow_tcf_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 flags = 0;\n+\n+\tsize += SZ_NLATTR_STRZ_OF(\"flower\") +\n+\t\tSZ_NLATTR_NEST + /* TCA_OPTIONS. */\n+\t\tSZ_NLATTR_TYPE_OF(uint32_t); /* TCA_CLS_FLAGS_SKIP_SW. */\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_PORT_ID:\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_ETH:\n+\t\t\tsize += SZ_NLATTR_TYPE_OF(uint16_t) + /* Ether type. */\n+\t\t\t\tSZ_NLATTR_DATA_OF(ETHER_ADDR_LEN) * 4;\n+\t\t\t\t/* dst/src MAC addr and mask. */\n+\t\t\tflags |= MLX5_FLOW_LAYER_OUTER_L2;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_VLAN:\n+\t\t\tsize += SZ_NLATTR_TYPE_OF(uint16_t) + /* Ether type. */\n+\t\t\t\tSZ_NLATTR_TYPE_OF(uint16_t) +\n+\t\t\t\t/* VLAN Ether type. */\n+\t\t\t\tSZ_NLATTR_TYPE_OF(uint8_t) + /* VLAN prio. */\n+\t\t\t\tSZ_NLATTR_TYPE_OF(uint16_t); /* VLAN ID. */\n+\t\t\tflags |= MLX5_FLOW_LAYER_OUTER_VLAN;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV4:\n+\t\t\tsize += SZ_NLATTR_TYPE_OF(uint16_t) + /* Ether type. */\n+\t\t\t\tSZ_NLATTR_TYPE_OF(uint8_t) + /* IP proto. */\n+\t\t\t\tSZ_NLATTR_TYPE_OF(uint32_t) * 4;\n+\t\t\t\t/* dst/src IP addr and mask. */\n+\t\t\tflags |= MLX5_FLOW_LAYER_OUTER_L3_IPV4;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV6:\n+\t\t\tsize += SZ_NLATTR_TYPE_OF(uint16_t) + /* Ether type. */\n+\t\t\t\tSZ_NLATTR_TYPE_OF(uint8_t) + /* IP proto. */\n+\t\t\t\tSZ_NLATTR_TYPE_OF(IPV6_ADDR_LEN) * 4;\n+\t\t\t\t/* dst/src IP addr and mask. */\n+\t\t\tflags |= MLX5_FLOW_LAYER_OUTER_L3_IPV6;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_UDP:\n+\t\t\tsize += SZ_NLATTR_TYPE_OF(uint8_t) + /* IP proto. */\n+\t\t\t\tSZ_NLATTR_TYPE_OF(uint16_t) * 4;\n+\t\t\t\t/* dst/src port and mask. */\n+\t\t\tflags |= MLX5_FLOW_LAYER_OUTER_L4_UDP;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_TCP:\n+\t\t\tsize += SZ_NLATTR_TYPE_OF(uint8_t) + /* IP proto. */\n+\t\t\t\tSZ_NLATTR_TYPE_OF(uint16_t) * 4;\n+\t\t\t\t/* dst/src port and mask. */\n+\t\t\tflags |= MLX5_FLOW_LAYER_OUTER_L4_TCP;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tDRV_LOG(WARNING,\n+\t\t\t\t\"unsupported item %p type %d,\"\n+\t\t\t\t\" items must be validated before flow creation\",\n+\t\t\t\t(const void *)items, items->type);\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\t*item_flags = flags;\n+\treturn size;\n+}\n+\n+/**\n+ * Calculate maximum size of memory for flow actions of Linux TC flower and\n+ * extract specified 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+ *   Maximum size of memory for actions.\n+ */\n+static int\n+flow_tcf_get_actions_and_size(const struct rte_flow_action actions[],\n+\t\t\t      uint64_t *action_flags)\n+{\n+\tint size = 0;\n+\tuint64_t flags = 0;\n+\n+\tsize += SZ_NLATTR_NEST; /* TCA_FLOWER_ACT. */\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_PORT_ID:\n+\t\t\tsize += SZ_NLATTR_NEST + /* na_act_index. */\n+\t\t\t\tSZ_NLATTR_STRZ_OF(\"mirred\") +\n+\t\t\t\tSZ_NLATTR_NEST + /* TCA_ACT_OPTIONS. */\n+\t\t\t\tSZ_NLATTR_TYPE_OF(struct tc_mirred);\n+\t\t\tflags |= MLX5_ACTION_PORT_ID;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_DROP:\n+\t\t\tsize += SZ_NLATTR_NEST + /* na_act_index. */\n+\t\t\t\tSZ_NLATTR_STRZ_OF(\"gact\") +\n+\t\t\t\tSZ_NLATTR_NEST + /* TCA_ACT_OPTIONS. */\n+\t\t\t\tSZ_NLATTR_TYPE_OF(struct tc_gact);\n+\t\t\tflags |= MLX5_ACTION_DROP;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:\n+\t\t\tflags |= MLX5_ACTION_OF_POP_VLAN;\n+\t\t\tgoto action_of_vlan;\n+\t\tcase RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:\n+\t\t\tflags |= MLX5_ACTION_OF_PUSH_VLAN;\n+\t\t\tgoto action_of_vlan;\n+\t\tcase RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:\n+\t\t\tflags |= MLX5_ACTION_OF_SET_VLAN_VID;\n+\t\t\tgoto action_of_vlan;\n+\t\tcase RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:\n+\t\t\tflags |= MLX5_ACTION_OF_SET_VLAN_PCP;\n+\t\t\tgoto action_of_vlan;\n+action_of_vlan:\n+\t\t\tsize += SZ_NLATTR_NEST + /* na_act_index. */\n+\t\t\t\tSZ_NLATTR_STRZ_OF(\"vlan\") +\n+\t\t\t\tSZ_NLATTR_NEST + /* TCA_ACT_OPTIONS. */\n+\t\t\t\tSZ_NLATTR_TYPE_OF(struct tc_vlan) +\n+\t\t\t\tSZ_NLATTR_TYPE_OF(uint16_t) +\n+\t\t\t\t/* VLAN protocol. */\n+\t\t\t\tSZ_NLATTR_TYPE_OF(uint16_t) + /* VLAN ID. */\n+\t\t\t\tSZ_NLATTR_TYPE_OF(uint8_t); /* VLAN prio. */\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tDRV_LOG(WARNING,\n+\t\t\t\t\"unsupported action %p type %d,\"\n+\t\t\t\t\" items must be validated before flow creation\",\n+\t\t\t\t(const void *)actions, actions->type);\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\t*action_flags = flags;\n+\treturn size;\n+}\n+\n+/**\n+ * Brand rtnetlink buffer with unique handle.\n+ *\n+ * This handle should be unique for a given network interface to avoid\n+ * collisions.\n+ *\n+ * @param nlh\n+ *   Pointer to Netlink message.\n+ * @param handle\n+ *   Unique 32-bit handle to use.\n+ */\n+static void\n+flow_tcf_nl_brand(struct nlmsghdr *nlh, uint32_t handle)\n+{\n+\tstruct tcmsg *tcm = mnl_nlmsg_get_payload(nlh);\n+\n+\ttcm->tcm_handle = handle;\n+\tDRV_LOG(DEBUG, \"Netlink msg %p is branded with handle %x\",\n+\t\t(void *)nlh, handle);\n+}\n+\n+/**\n+ * Prepare a flow object for Linux TC flower. It calculates the maximum size of\n+ * memory required, allocates the memory, initializes Netlink message headers\n+ * and set unique TC message handle.\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,\n+ *   otherwise NULL and rte_ernno is set.\n+ */\n+static struct mlx5_flow *\n+flow_tcf_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, uint64_t *action_flags,\n+\t\t struct rte_flow_error *error)\n+{\n+\tsize_t size = sizeof(struct mlx5_flow) +\n+\t\t      MNL_ALIGN(sizeof(struct nlmsghdr)) +\n+\t\t      MNL_ALIGN(sizeof(struct tcmsg));\n+\tstruct mlx5_flow *dev_flow;\n+\tstruct nlmsghdr *nlh;\n+\tstruct tcmsg *tcm;\n+\n+\tsize += flow_tcf_get_items_and_size(items, item_flags);\n+\tsize += flow_tcf_get_actions_and_size(actions, action_flags);\n+\tdev_flow = rte_zmalloc(__func__, size, MNL_ALIGNTO);\n+\tif (!dev_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 E-Switch flow\");\n+\t\treturn NULL;\n+\t}\n+\tnlh = mnl_nlmsg_put_header((void *)(dev_flow + 1));\n+\ttcm = mnl_nlmsg_put_extra_header(nlh, sizeof(*tcm));\n+\t*dev_flow = (struct mlx5_flow){\n+\t\t.tcf = (struct mlx5_flow_tcf){\n+\t\t\t.nlh = nlh,\n+\t\t\t.tcm = tcm,\n+\t\t},\n+\t};\n+\t/*\n+\t * Generate a reasonably unique handle based on the address of the\n+\t * target buffer.\n+\t *\n+\t * This is straightforward on 32-bit systems where the flow pointer can\n+\t * be used directly. Otherwise, its least significant part is taken\n+\t * after shifting it by the previous power of two of the pointed buffer\n+\t * size.\n+\t */\n+\tif (sizeof(dev_flow) <= 4)\n+\t\tflow_tcf_nl_brand(nlh, (uintptr_t)dev_flow);\n+\telse\n+\t\tflow_tcf_nl_brand(nlh, (uintptr_t)dev_flow >>\n+\t\t\t\t       rte_log2_u32(rte_align32prevpow2(size)));\n+\treturn dev_flow;\n+}\n+\n+/**\n+ * Translate flow for Linux TC flower and construct Netlink message.\n+ *\n+ * @param[in] priv\n+ *   Pointer to the priv structure.\n+ * @param[in, out] flow\n+ *   Pointer to the sub 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 int\n+flow_tcf_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+\tunion {\n+\t\tconst struct rte_flow_item_port_id *port_id;\n+\t\tconst struct rte_flow_item_eth *eth;\n+\t\tconst struct rte_flow_item_vlan *vlan;\n+\t\tconst struct rte_flow_item_ipv4 *ipv4;\n+\t\tconst struct rte_flow_item_ipv6 *ipv6;\n+\t\tconst struct rte_flow_item_tcp *tcp;\n+\t\tconst struct rte_flow_item_udp *udp;\n+\t} spec, mask;\n+\tunion {\n+\t\tconst struct rte_flow_action_port_id *port_id;\n+\t\tconst struct rte_flow_action_of_push_vlan *of_push_vlan;\n+\t\tconst struct rte_flow_action_of_set_vlan_vid *\n+\t\t\tof_set_vlan_vid;\n+\t\tconst struct rte_flow_action_of_set_vlan_pcp *\n+\t\t\tof_set_vlan_pcp;\n+\t} conf;\n+\tstruct flow_tcf_ptoi ptoi[PTOI_TABLE_SZ_MAX(dev)];\n+\tstruct nlmsghdr *nlh = dev_flow->tcf.nlh;\n+\tstruct tcmsg *tcm = dev_flow->tcf.tcm;\n+\tuint32_t na_act_index_cur;\n+\tbool eth_type_set = 0;\n+\tbool vlan_present = 0;\n+\tbool vlan_eth_type_set = 0;\n+\tbool ip_proto_set = 0;\n+\tstruct nlattr *na_flower;\n+\tstruct nlattr *na_flower_act;\n+\tstruct nlattr *na_vlan_id = NULL;\n+\tstruct nlattr *na_vlan_priority = NULL;\n+\n+\tclaim_nonzero(flow_tcf_build_ptoi_table(dev, ptoi,\n+\t\t\t\t\t\tPTOI_TABLE_SZ_MAX(dev)));\n+\tnlh = dev_flow->tcf.nlh;\n+\ttcm = dev_flow->tcf.tcm;\n+\t/* Prepare API must have been called beforehand. */\n+\tassert(nlh != NULL && tcm != NULL);\n+\ttcm->tcm_family = AF_UNSPEC;\n+\ttcm->tcm_ifindex = ptoi[0].ifindex;\n+\ttcm->tcm_parent = TC_H_MAKE(TC_H_INGRESS, TC_H_MIN_INGRESS);\n+\t/*\n+\t * Priority cannot be zero to prevent the kernel from picking one\n+\t * automatically.\n+\t */\n+\ttcm->tcm_info = TC_H_MAKE((attr->priority + 1) << 16,\n+\t\t\t\t  RTE_BE16(ETH_P_ALL));\n+\tmnl_attr_put_strz(nlh, TCA_KIND, \"flower\");\n+\tna_flower = mnl_attr_nest_start(nlh, TCA_OPTIONS);\n+\tmnl_attr_put_u32(nlh, TCA_FLOWER_FLAGS, TCA_CLS_FLAGS_SKIP_SW);\n+\tfor (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {\n+\t\tunsigned int i;\n+\n+\t\tswitch (items->type) {\n+\t\tcase RTE_FLOW_ITEM_TYPE_VOID:\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_PORT_ID:\n+\t\t\tmask.port_id = flow_tcf_item_mask\n+\t\t\t\t(items, &rte_flow_item_port_id_mask,\n+\t\t\t\t &flow_tcf_mask_supported.port_id,\n+\t\t\t\t &flow_tcf_mask_empty.port_id,\n+\t\t\t\t sizeof(flow_tcf_mask_supported.port_id),\n+\t\t\t\t error);\n+\t\t\tassert(mask.port_id);\n+\t\t\tif (mask.port_id == &flow_tcf_mask_empty.port_id)\n+\t\t\t\tbreak;\n+\t\t\tspec.port_id = items->spec;\n+\t\t\tif (!mask.port_id->id)\n+\t\t\t\ti = 0;\n+\t\t\telse\n+\t\t\t\tfor (i = 0; ptoi[i].ifindex; ++i)\n+\t\t\t\t\tif (ptoi[i].port_id == spec.port_id->id)\n+\t\t\t\t\t\tbreak;\n+\t\t\tassert(ptoi[i].ifindex);\n+\t\t\ttcm->tcm_ifindex = ptoi[i].ifindex;\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_ETH:\n+\t\t\tmask.eth = flow_tcf_item_mask\n+\t\t\t\t(items, &rte_flow_item_eth_mask,\n+\t\t\t\t &flow_tcf_mask_supported.eth,\n+\t\t\t\t &flow_tcf_mask_empty.eth,\n+\t\t\t\t sizeof(flow_tcf_mask_supported.eth),\n+\t\t\t\t error);\n+\t\t\tassert(mask.eth);\n+\t\t\tif (mask.eth == &flow_tcf_mask_empty.eth)\n+\t\t\t\tbreak;\n+\t\t\tspec.eth = items->spec;\n+\t\t\tif (mask.eth->type) {\n+\t\t\t\tmnl_attr_put_u16(nlh, TCA_FLOWER_KEY_ETH_TYPE,\n+\t\t\t\t\t\t spec.eth->type);\n+\t\t\t\teth_type_set = 1;\n+\t\t\t}\n+\t\t\tif (!is_zero_ether_addr(&mask.eth->dst)) {\n+\t\t\t\tmnl_attr_put(nlh, TCA_FLOWER_KEY_ETH_DST,\n+\t\t\t\t\t     ETHER_ADDR_LEN,\n+\t\t\t\t\t     spec.eth->dst.addr_bytes);\n+\t\t\t\tmnl_attr_put(nlh, TCA_FLOWER_KEY_ETH_DST_MASK,\n+\t\t\t\t\t     ETHER_ADDR_LEN,\n+\t\t\t\t\t     mask.eth->dst.addr_bytes);\n+\t\t\t}\n+\t\t\tif (!is_zero_ether_addr(&mask.eth->src)) {\n+\t\t\t\tmnl_attr_put(nlh, TCA_FLOWER_KEY_ETH_SRC,\n+\t\t\t\t\t     ETHER_ADDR_LEN,\n+\t\t\t\t\t     spec.eth->src.addr_bytes);\n+\t\t\t\tmnl_attr_put(nlh, TCA_FLOWER_KEY_ETH_SRC_MASK,\n+\t\t\t\t\t     ETHER_ADDR_LEN,\n+\t\t\t\t\t     mask.eth->src.addr_bytes);\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_VLAN:\n+\t\t\tmask.vlan = flow_tcf_item_mask\n+\t\t\t\t(items, &rte_flow_item_vlan_mask,\n+\t\t\t\t &flow_tcf_mask_supported.vlan,\n+\t\t\t\t &flow_tcf_mask_empty.vlan,\n+\t\t\t\t sizeof(flow_tcf_mask_supported.vlan),\n+\t\t\t\t error);\n+\t\t\tassert(mask.vlan);\n+\t\t\tif (!eth_type_set)\n+\t\t\t\tmnl_attr_put_u16(nlh, TCA_FLOWER_KEY_ETH_TYPE,\n+\t\t\t\t\t\t RTE_BE16(ETH_P_8021Q));\n+\t\t\teth_type_set = 1;\n+\t\t\tvlan_present = 1;\n+\t\t\tif (mask.vlan == &flow_tcf_mask_empty.vlan)\n+\t\t\t\tbreak;\n+\t\t\tspec.vlan = items->spec;\n+\t\t\tif (mask.vlan->inner_type) {\n+\t\t\t\tmnl_attr_put_u16(nlh,\n+\t\t\t\t\t\t TCA_FLOWER_KEY_VLAN_ETH_TYPE,\n+\t\t\t\t\t\t spec.vlan->inner_type);\n+\t\t\t\tvlan_eth_type_set = 1;\n+\t\t\t}\n+\t\t\tif (mask.vlan->tci & RTE_BE16(0xe000))\n+\t\t\t\tmnl_attr_put_u8(nlh, TCA_FLOWER_KEY_VLAN_PRIO,\n+\t\t\t\t\t\t(rte_be_to_cpu_16\n+\t\t\t\t\t\t (spec.vlan->tci) >> 13) & 0x7);\n+\t\t\tif (mask.vlan->tci & RTE_BE16(0x0fff))\n+\t\t\t\tmnl_attr_put_u16(nlh, TCA_FLOWER_KEY_VLAN_ID,\n+\t\t\t\t\t\t rte_be_to_cpu_16\n+\t\t\t\t\t\t (spec.vlan->tci &\n+\t\t\t\t\t\t  RTE_BE16(0x0fff)));\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV4:\n+\t\t\tmask.ipv4 = flow_tcf_item_mask\n+\t\t\t\t(items, &rte_flow_item_ipv4_mask,\n+\t\t\t\t &flow_tcf_mask_supported.ipv4,\n+\t\t\t\t &flow_tcf_mask_empty.ipv4,\n+\t\t\t\t sizeof(flow_tcf_mask_supported.ipv4),\n+\t\t\t\t error);\n+\t\t\tassert(mask.ipv4);\n+\t\t\tif (!eth_type_set || !vlan_eth_type_set)\n+\t\t\t\tmnl_attr_put_u16(nlh,\n+\t\t\t\t\t\t vlan_present ?\n+\t\t\t\t\t\t TCA_FLOWER_KEY_VLAN_ETH_TYPE :\n+\t\t\t\t\t\t TCA_FLOWER_KEY_ETH_TYPE,\n+\t\t\t\t\t\t RTE_BE16(ETH_P_IP));\n+\t\t\teth_type_set = 1;\n+\t\t\tvlan_eth_type_set = 1;\n+\t\t\tif (mask.ipv4 == &flow_tcf_mask_empty.ipv4)\n+\t\t\t\tbreak;\n+\t\t\tspec.ipv4 = items->spec;\n+\t\t\tif (mask.ipv4->hdr.next_proto_id) {\n+\t\t\t\tmnl_attr_put_u8(nlh, TCA_FLOWER_KEY_IP_PROTO,\n+\t\t\t\t\t\tspec.ipv4->hdr.next_proto_id);\n+\t\t\t\tip_proto_set = 1;\n+\t\t\t}\n+\t\t\tif (mask.ipv4->hdr.src_addr) {\n+\t\t\t\tmnl_attr_put_u32(nlh, TCA_FLOWER_KEY_IPV4_SRC,\n+\t\t\t\t\t\t spec.ipv4->hdr.src_addr);\n+\t\t\t\tmnl_attr_put_u32(nlh,\n+\t\t\t\t\t\t TCA_FLOWER_KEY_IPV4_SRC_MASK,\n+\t\t\t\t\t\t mask.ipv4->hdr.src_addr);\n+\t\t\t}\n+\t\t\tif (mask.ipv4->hdr.dst_addr) {\n+\t\t\t\tmnl_attr_put_u32(nlh, TCA_FLOWER_KEY_IPV4_DST,\n+\t\t\t\t\t\t spec.ipv4->hdr.dst_addr);\n+\t\t\t\tmnl_attr_put_u32(nlh,\n+\t\t\t\t\t\t TCA_FLOWER_KEY_IPV4_DST_MASK,\n+\t\t\t\t\t\t mask.ipv4->hdr.dst_addr);\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_IPV6:\n+\t\t\tmask.ipv6 = flow_tcf_item_mask\n+\t\t\t\t(items, &rte_flow_item_ipv6_mask,\n+\t\t\t\t &flow_tcf_mask_supported.ipv6,\n+\t\t\t\t &flow_tcf_mask_empty.ipv6,\n+\t\t\t\t sizeof(flow_tcf_mask_supported.ipv6),\n+\t\t\t\t error);\n+\t\t\tassert(mask.ipv6);\n+\t\t\tif (!eth_type_set || !vlan_eth_type_set)\n+\t\t\t\tmnl_attr_put_u16(nlh,\n+\t\t\t\t\t\t vlan_present ?\n+\t\t\t\t\t\t TCA_FLOWER_KEY_VLAN_ETH_TYPE :\n+\t\t\t\t\t\t TCA_FLOWER_KEY_ETH_TYPE,\n+\t\t\t\t\t\t RTE_BE16(ETH_P_IPV6));\n+\t\t\teth_type_set = 1;\n+\t\t\tvlan_eth_type_set = 1;\n+\t\t\tif (mask.ipv6 == &flow_tcf_mask_empty.ipv6)\n+\t\t\t\tbreak;\n+\t\t\tspec.ipv6 = items->spec;\n+\t\t\tif (mask.ipv6->hdr.proto) {\n+\t\t\t\tmnl_attr_put_u8(nlh, TCA_FLOWER_KEY_IP_PROTO,\n+\t\t\t\t\t\tspec.ipv6->hdr.proto);\n+\t\t\t\tip_proto_set = 1;\n+\t\t\t}\n+\t\t\tif (!IN6_IS_ADDR_UNSPECIFIED(mask.ipv6->hdr.src_addr)) {\n+\t\t\t\tmnl_attr_put(nlh, TCA_FLOWER_KEY_IPV6_SRC,\n+\t\t\t\t\t     sizeof(spec.ipv6->hdr.src_addr),\n+\t\t\t\t\t     spec.ipv6->hdr.src_addr);\n+\t\t\t\tmnl_attr_put(nlh, TCA_FLOWER_KEY_IPV6_SRC_MASK,\n+\t\t\t\t\t     sizeof(mask.ipv6->hdr.src_addr),\n+\t\t\t\t\t     mask.ipv6->hdr.src_addr);\n+\t\t\t}\n+\t\t\tif (!IN6_IS_ADDR_UNSPECIFIED(mask.ipv6->hdr.dst_addr)) {\n+\t\t\t\tmnl_attr_put(nlh, TCA_FLOWER_KEY_IPV6_DST,\n+\t\t\t\t\t     sizeof(spec.ipv6->hdr.dst_addr),\n+\t\t\t\t\t     spec.ipv6->hdr.dst_addr);\n+\t\t\t\tmnl_attr_put(nlh, TCA_FLOWER_KEY_IPV6_DST_MASK,\n+\t\t\t\t\t     sizeof(mask.ipv6->hdr.dst_addr),\n+\t\t\t\t\t     mask.ipv6->hdr.dst_addr);\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_UDP:\n+\t\t\tmask.udp = flow_tcf_item_mask\n+\t\t\t\t(items, &rte_flow_item_udp_mask,\n+\t\t\t\t &flow_tcf_mask_supported.udp,\n+\t\t\t\t &flow_tcf_mask_empty.udp,\n+\t\t\t\t sizeof(flow_tcf_mask_supported.udp),\n+\t\t\t\t error);\n+\t\t\tassert(mask.udp);\n+\t\t\tif (!ip_proto_set)\n+\t\t\t\tmnl_attr_put_u8(nlh, TCA_FLOWER_KEY_IP_PROTO,\n+\t\t\t\t\t\tIPPROTO_UDP);\n+\t\t\tif (mask.udp == &flow_tcf_mask_empty.udp)\n+\t\t\t\tbreak;\n+\t\t\tspec.udp = items->spec;\n+\t\t\tif (mask.udp->hdr.src_port) {\n+\t\t\t\tmnl_attr_put_u16(nlh, TCA_FLOWER_KEY_UDP_SRC,\n+\t\t\t\t\t\t spec.udp->hdr.src_port);\n+\t\t\t\tmnl_attr_put_u16(nlh,\n+\t\t\t\t\t\t TCA_FLOWER_KEY_UDP_SRC_MASK,\n+\t\t\t\t\t\t mask.udp->hdr.src_port);\n+\t\t\t}\n+\t\t\tif (mask.udp->hdr.dst_port) {\n+\t\t\t\tmnl_attr_put_u16(nlh, TCA_FLOWER_KEY_UDP_DST,\n+\t\t\t\t\t\t spec.udp->hdr.dst_port);\n+\t\t\t\tmnl_attr_put_u16(nlh,\n+\t\t\t\t\t\t TCA_FLOWER_KEY_UDP_DST_MASK,\n+\t\t\t\t\t\t mask.udp->hdr.dst_port);\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_TCP:\n+\t\t\tmask.tcp = flow_tcf_item_mask\n+\t\t\t\t(items, &rte_flow_item_tcp_mask,\n+\t\t\t\t &flow_tcf_mask_supported.tcp,\n+\t\t\t\t &flow_tcf_mask_empty.tcp,\n+\t\t\t\t sizeof(flow_tcf_mask_supported.tcp),\n+\t\t\t\t error);\n+\t\t\tassert(mask.tcp);\n+\t\t\tif (!ip_proto_set)\n+\t\t\t\tmnl_attr_put_u8(nlh, TCA_FLOWER_KEY_IP_PROTO,\n+\t\t\t\t\t\tIPPROTO_TCP);\n+\t\t\tif (mask.tcp == &flow_tcf_mask_empty.tcp)\n+\t\t\t\tbreak;\n+\t\t\tspec.tcp = items->spec;\n+\t\t\tif (mask.tcp->hdr.src_port) {\n+\t\t\t\tmnl_attr_put_u16(nlh, TCA_FLOWER_KEY_TCP_SRC,\n+\t\t\t\t\t\t spec.tcp->hdr.src_port);\n+\t\t\t\tmnl_attr_put_u16(nlh,\n+\t\t\t\t\t\t TCA_FLOWER_KEY_TCP_SRC_MASK,\n+\t\t\t\t\t\t mask.tcp->hdr.src_port);\n+\t\t\t}\n+\t\t\tif (mask.tcp->hdr.dst_port) {\n+\t\t\t\tmnl_attr_put_u16(nlh, TCA_FLOWER_KEY_TCP_DST,\n+\t\t\t\t\t\t spec.tcp->hdr.dst_port);\n+\t\t\t\tmnl_attr_put_u16(nlh,\n+\t\t\t\t\t\t TCA_FLOWER_KEY_TCP_DST_MASK,\n+\t\t\t\t\t\t mask.tcp->hdr.dst_port);\n+\t\t\t}\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+\tna_flower_act = mnl_attr_nest_start(nlh, TCA_FLOWER_ACT);\n+\tna_act_index_cur = 1;\n+\tfor (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {\n+\t\tstruct nlattr *na_act_index;\n+\t\tstruct nlattr *na_act;\n+\t\tunsigned int vlan_act;\n+\t\tunsigned int i;\n+\n+\t\tswitch (actions->type) {\n+\t\tcase RTE_FLOW_ACTION_TYPE_VOID:\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_PORT_ID:\n+\t\t\tconf.port_id = actions->conf;\n+\t\t\tif (conf.port_id->original)\n+\t\t\t\ti = 0;\n+\t\t\telse\n+\t\t\t\tfor (i = 0; ptoi[i].ifindex; ++i)\n+\t\t\t\t\tif (ptoi[i].port_id == conf.port_id->id)\n+\t\t\t\t\t\tbreak;\n+\t\t\tassert(ptoi[i].ifindex);\n+\t\t\tna_act_index =\n+\t\t\t\tmnl_attr_nest_start(nlh, na_act_index_cur++);\n+\t\t\tassert(na_act_index);\n+\t\t\tmnl_attr_put_strz(nlh, TCA_ACT_KIND, \"mirred\");\n+\t\t\tna_act = mnl_attr_nest_start(nlh, TCA_ACT_OPTIONS);\n+\t\t\tassert(na_act);\n+\t\t\tmnl_attr_put(nlh, TCA_MIRRED_PARMS,\n+\t\t\t\t     sizeof(struct tc_mirred),\n+\t\t\t\t     &(struct tc_mirred){\n+\t\t\t\t\t.action = TC_ACT_STOLEN,\n+\t\t\t\t\t.eaction = TCA_EGRESS_REDIR,\n+\t\t\t\t\t.ifindex = ptoi[i].ifindex,\n+\t\t\t\t     });\n+\t\t\tmnl_attr_nest_end(nlh, na_act);\n+\t\t\tmnl_attr_nest_end(nlh, na_act_index);\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_DROP:\n+\t\t\tna_act_index =\n+\t\t\t\tmnl_attr_nest_start(nlh, na_act_index_cur++);\n+\t\t\tassert(na_act_index);\n+\t\t\tmnl_attr_put_strz(nlh, TCA_ACT_KIND, \"gact\");\n+\t\t\tna_act = mnl_attr_nest_start(nlh, TCA_ACT_OPTIONS);\n+\t\t\tassert(na_act);\n+\t\t\tmnl_attr_put(nlh, TCA_GACT_PARMS,\n+\t\t\t\t     sizeof(struct tc_gact),\n+\t\t\t\t     &(struct tc_gact){\n+\t\t\t\t\t.action = TC_ACT_SHOT,\n+\t\t\t\t     });\n+\t\t\tmnl_attr_nest_end(nlh, na_act);\n+\t\t\tmnl_attr_nest_end(nlh, na_act_index);\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:\n+\t\t\tconf.of_push_vlan = NULL;\n+\t\t\tvlan_act = TCA_VLAN_ACT_POP;\n+\t\t\tgoto action_of_vlan;\n+\t\tcase RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:\n+\t\t\tconf.of_push_vlan = actions->conf;\n+\t\t\tvlan_act = TCA_VLAN_ACT_PUSH;\n+\t\t\tgoto action_of_vlan;\n+\t\tcase RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:\n+\t\t\tconf.of_set_vlan_vid = actions->conf;\n+\t\t\tif (na_vlan_id)\n+\t\t\t\tgoto override_na_vlan_id;\n+\t\t\tvlan_act = TCA_VLAN_ACT_MODIFY;\n+\t\t\tgoto action_of_vlan;\n+\t\tcase RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:\n+\t\t\tconf.of_set_vlan_pcp = actions->conf;\n+\t\t\tif (na_vlan_priority)\n+\t\t\t\tgoto override_na_vlan_priority;\n+\t\t\tvlan_act = TCA_VLAN_ACT_MODIFY;\n+\t\t\tgoto action_of_vlan;\n+action_of_vlan:\n+\t\t\tna_act_index =\n+\t\t\t\tmnl_attr_nest_start(nlh, na_act_index_cur++);\n+\t\t\tassert(na_act_index);\n+\t\t\tmnl_attr_put_strz(nlh, TCA_ACT_KIND, \"vlan\");\n+\t\t\tna_act = mnl_attr_nest_start(nlh, TCA_ACT_OPTIONS);\n+\t\t\tassert(na_act);\n+\t\t\tmnl_attr_put(nlh, TCA_VLAN_PARMS,\n+\t\t\t\t     sizeof(struct tc_vlan),\n+\t\t\t\t     &(struct tc_vlan){\n+\t\t\t\t\t.action = TC_ACT_PIPE,\n+\t\t\t\t\t.v_action = vlan_act,\n+\t\t\t\t     });\n+\t\t\tif (vlan_act == TCA_VLAN_ACT_POP) {\n+\t\t\t\tmnl_attr_nest_end(nlh, na_act);\n+\t\t\t\tmnl_attr_nest_end(nlh, na_act_index);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (vlan_act == TCA_VLAN_ACT_PUSH)\n+\t\t\t\tmnl_attr_put_u16(nlh,\n+\t\t\t\t\t\t TCA_VLAN_PUSH_VLAN_PROTOCOL,\n+\t\t\t\t\t\t conf.of_push_vlan->ethertype);\n+\t\t\tna_vlan_id = mnl_nlmsg_get_payload_tail(nlh);\n+\t\t\tmnl_attr_put_u16(nlh, TCA_VLAN_PAD, 0);\n+\t\t\tna_vlan_priority = mnl_nlmsg_get_payload_tail(nlh);\n+\t\t\tmnl_attr_put_u8(nlh, TCA_VLAN_PAD, 0);\n+\t\t\tmnl_attr_nest_end(nlh, na_act);\n+\t\t\tmnl_attr_nest_end(nlh, na_act_index);\n+\t\t\tif (actions->type ==\n+\t\t\t    RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID) {\n+override_na_vlan_id:\n+\t\t\t\tna_vlan_id->nla_type = TCA_VLAN_PUSH_VLAN_ID;\n+\t\t\t\t*(uint16_t *)mnl_attr_get_payload(na_vlan_id) =\n+\t\t\t\t\trte_be_to_cpu_16\n+\t\t\t\t\t(conf.of_set_vlan_vid->vlan_vid);\n+\t\t\t} else if (actions->type ==\n+\t\t\t\t   RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP) {\n+override_na_vlan_priority:\n+\t\t\t\tna_vlan_priority->nla_type =\n+\t\t\t\t\tTCA_VLAN_PUSH_VLAN_PRIORITY;\n+\t\t\t\t*(uint8_t *)mnl_attr_get_payload\n+\t\t\t\t\t(na_vlan_priority) =\n+\t\t\t\t\tconf.of_set_vlan_pcp->vlan_pcp;\n+\t\t\t}\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+\tassert(na_flower);\n+\tassert(na_flower_act);\n+\tmnl_attr_nest_end(nlh, na_flower_act);\n+\tmnl_attr_nest_end(nlh, na_flower);\n+\treturn 0;\n+}\n+\n+/**\n+ * Send Netlink message with acknowledgment.\n+ *\n+ * @param nl\n+ *   Libmnl socket to use.\n+ * @param nlh\n+ *   Message to send. This function always raises the NLM_F_ACK flag before\n+ *   sending.\n+ *\n+ * @return\n+ *   0 on success, a negative errno value otherwise and rte_errno is set.\n+ */\n+static int\n+flow_tcf_nl_ack(struct mnl_socket *nl, struct nlmsghdr *nlh)\n+{\n+\talignas(struct nlmsghdr)\n+\tuint8_t ans[mnl_nlmsg_size(sizeof(struct nlmsgerr)) +\n+\t\t    nlh->nlmsg_len - sizeof(*nlh)];\n+\tuint32_t seq = random();\n+\tint ret;\n+\n+\tnlh->nlmsg_flags |= NLM_F_ACK;\n+\tnlh->nlmsg_seq = seq;\n+\tret = mnl_socket_sendto(nl, nlh, nlh->nlmsg_len);\n+\tif (ret != -1)\n+\t\tret = mnl_socket_recvfrom(nl, ans, sizeof(ans));\n+\tif (ret != -1)\n+\t\tret = mnl_cb_run\n+\t\t\t(ans, ret, seq, mnl_socket_get_portid(nl), NULL, NULL);\n+\tif (ret > 0)\n+\t\treturn 0;\n+\trte_errno = errno;\n+\treturn -rte_errno;\n+}\n+\n+/**\n+ * Apply flow to E-Switch by sending Netlink message.\n+ *\n+ * @param[in] dev\n+ *   Pointer to Ethernet device.\n+ * @param[in, out] flow\n+ *   Pointer to the sub flow.\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\n+flow_tcf_apply(struct rte_eth_dev *dev, struct rte_flow *flow,\n+\t       struct rte_flow_error *error)\n+{\n+\tstruct priv *priv = dev->data->dev_private;\n+\tstruct mnl_socket *nl = priv->mnl_socket;\n+\tstruct mlx5_flow *dev_flow;\n+\tstruct nlmsghdr *nlh;\n+\n+\tdev_flow = LIST_FIRST(&flow->dev_flows);\n+\t/* E-Switch flow can't be expanded. */\n+\tassert(!LIST_NEXT(dev_flow, next));\n+\tnlh = dev_flow->tcf.nlh;\n+\tnlh->nlmsg_type = RTM_NEWTFILTER;\n+\tnlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;\n+\tif (!flow_tcf_nl_ack(nl, nlh))\n+\t\treturn 0;\n+\treturn rte_flow_error_set(error, rte_errno,\n+\t\t\t\t  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\t  \"netlink: failed to create TC flow rule\");\n+}\n+\n+/**\n+ * Remove flow from E-Switch by sending Netlink message.\n+ *\n+ * @param[in] dev\n+ *   Pointer to Ethernet device.\n+ * @param[in, out] flow\n+ *   Pointer to the sub flow.\n+ */\n+static void\n+flow_tcf_remove(struct rte_eth_dev *dev, struct rte_flow *flow)\n+{\n+\tstruct priv *priv = dev->data->dev_private;\n+\tstruct mnl_socket *nl = priv->mnl_socket;\n+\tstruct mlx5_flow *dev_flow;\n+\tstruct nlmsghdr *nlh;\n+\n+\tif (!flow)\n+\t\treturn;\n+\tdev_flow = LIST_FIRST(&flow->dev_flows);\n+\tif (!dev_flow)\n+\t\treturn;\n+\t/* E-Switch flow can't be expanded. */\n+\tassert(!LIST_NEXT(dev_flow, next));\n+\tnlh = dev_flow->tcf.nlh;\n+\tnlh->nlmsg_type = RTM_DELTFILTER;\n+\tnlh->nlmsg_flags = NLM_F_REQUEST;\n+\tflow_tcf_nl_ack(nl, nlh);\n+}\n+\n+/**\n+ * Remove flow from E-Switch and release resources of the device flow.\n+ *\n+ * @param[in] dev\n+ *   Pointer to Ethernet device.\n+ * @param[in, out] flow\n+ *   Pointer to the sub flow.\n+ */\n+static void\n+flow_tcf_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_tcf_remove(dev, flow);\n+\tdev_flow = LIST_FIRST(&flow->dev_flows);\n+\tif (!dev_flow)\n+\t\treturn;\n+\t/* E-Switch flow can't be expanded. */\n+\tassert(!LIST_NEXT(dev_flow, next));\n+\tLIST_REMOVE(dev_flow, next);\n+\trte_free(dev_flow);\n+}\n+\n+const struct mlx5_flow_driver_ops mlx5_flow_tcf_drv_ops = {\n+\t.validate = flow_tcf_validate,\n+\t.prepare = flow_tcf_prepare,\n+\t.translate = flow_tcf_translate,\n+\t.apply = flow_tcf_apply,\n+\t.remove = flow_tcf_remove,\n+\t.destroy = flow_tcf_destroy,\n+};\n+\n+/**\n+ * Initialize ingress qdisc of a given network interface.\n+ *\n+ * @param nl\n+ *   Libmnl socket of the @p NETLINK_ROUTE kind.\n+ * @param ifindex\n+ *   Index of network interface to initialize.\n+ * @param[out] error\n+ *   Perform verbose error reporting if not NULL.\n+ *\n+ * @return\n+ *   0 on success, a negative errno value otherwise and rte_errno is set.\n+ */\n+int\n+mlx5_flow_tcf_init(struct mnl_socket *nl, unsigned int ifindex,\n+\t\t   struct rte_flow_error *error)\n+{\n+\tstruct nlmsghdr *nlh;\n+\tstruct tcmsg *tcm;\n+\talignas(struct nlmsghdr)\n+\tuint8_t buf[mnl_nlmsg_size(sizeof(*tcm) + 128)];\n+\n+\t/* Destroy existing ingress qdisc and everything attached to it. */\n+\tnlh = mnl_nlmsg_put_header(buf);\n+\tnlh->nlmsg_type = RTM_DELQDISC;\n+\tnlh->nlmsg_flags = NLM_F_REQUEST;\n+\ttcm = mnl_nlmsg_put_extra_header(nlh, sizeof(*tcm));\n+\ttcm->tcm_family = AF_UNSPEC;\n+\ttcm->tcm_ifindex = ifindex;\n+\ttcm->tcm_handle = TC_H_MAKE(TC_H_INGRESS, 0);\n+\ttcm->tcm_parent = TC_H_INGRESS;\n+\t/* Ignore errors when qdisc is already absent. */\n+\tif (flow_tcf_nl_ack(nl, nlh) &&\n+\t    rte_errno != EINVAL && rte_errno != ENOENT)\n+\t\treturn rte_flow_error_set(error, rte_errno,\n+\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\t\t  \"netlink: failed to remove ingress\"\n+\t\t\t\t\t  \" qdisc\");\n+\t/* Create fresh ingress qdisc. */\n+\tnlh = mnl_nlmsg_put_header(buf);\n+\tnlh->nlmsg_type = RTM_NEWQDISC;\n+\tnlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;\n+\ttcm = mnl_nlmsg_put_extra_header(nlh, sizeof(*tcm));\n+\ttcm->tcm_family = AF_UNSPEC;\n+\ttcm->tcm_ifindex = ifindex;\n+\ttcm->tcm_handle = TC_H_MAKE(TC_H_INGRESS, 0);\n+\ttcm->tcm_parent = TC_H_INGRESS;\n+\tmnl_attr_put_strz_check(nlh, sizeof(buf), TCA_KIND, \"ingress\");\n+\tif (flow_tcf_nl_ack(nl, nlh))\n+\t\treturn rte_flow_error_set(error, rte_errno,\n+\t\t\t\t\t  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\t\t  \"netlink: failed to create ingress\"\n+\t\t\t\t\t  \" qdisc\");\n+\treturn 0;\n+}\n+\n+/**\n+ * Create and configure a libmnl socket for Netlink flow rules.\n+ *\n+ * @return\n+ *   A valid libmnl socket object pointer on success, NULL otherwise and\n+ *   rte_errno is set.\n+ */\n+struct mnl_socket *\n+mlx5_flow_tcf_socket_create(void)\n+{\n+\tstruct mnl_socket *nl = mnl_socket_open(NETLINK_ROUTE);\n+\n+\tif (nl) {\n+\t\tmnl_socket_setsockopt(nl, NETLINK_CAP_ACK, &(int){ 1 },\n+\t\t\t\t      sizeof(int));\n+\t\tif (!mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID))\n+\t\t\treturn nl;\n+\t}\n+\trte_errno = errno;\n+\tif (nl)\n+\t\tmnl_socket_close(nl);\n+\treturn NULL;\n+}\n+\n+/**\n+ * Destroy a libmnl socket.\n+ *\n+ * @param nl\n+ *   Libmnl socket of the @p NETLINK_ROUTE kind.\n+ */\n+void\n+mlx5_flow_tcf_socket_destroy(struct mnl_socket *nl)\n+{\n+\tmnl_socket_close(nl);\n+}\n",
    "prefixes": [
        "v2",
        "3/3"
    ]
}