get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 41723,
    "url": "http://patches.dpdk.org/api/patches/41723/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20180627173355.4718-3-adrien.mazarguil@6wind.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20180627173355.4718-3-adrien.mazarguil@6wind.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20180627173355.4718-3-adrien.mazarguil@6wind.com",
    "date": "2018-06-27T18:08:12",
    "name": "[2/6] net/mlx5: add framework for switch flow rules",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "ef8623b99800534cd928027b56bd1dc288e7bf85",
    "submitter": {
        "id": 165,
        "url": "http://patches.dpdk.org/api/people/165/?format=api",
        "name": "Adrien Mazarguil",
        "email": "adrien.mazarguil@6wind.com"
    },
    "delegate": null,
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20180627173355.4718-3-adrien.mazarguil@6wind.com/mbox/",
    "series": [
        {
            "id": 273,
            "url": "http://patches.dpdk.org/api/series/273/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=273",
            "date": "2018-06-27T18:08:08",
            "name": "net/mlx5: add support for switch flow rules",
            "version": 1,
            "mbox": "http://patches.dpdk.org/series/273/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/41723/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/41723/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id ED34C1C393;\n\tWed, 27 Jun 2018 20:08:31 +0200 (CEST)",
            "from mail-wm0-f67.google.com (mail-wm0-f67.google.com\n\t[74.125.82.67]) by dpdk.org (Postfix) with ESMTP id CA2B41C389\n\tfor <dev@dpdk.org>; Wed, 27 Jun 2018 20:08:29 +0200 (CEST)",
            "by mail-wm0-f67.google.com with SMTP id 69-v6so6411282wmf.3\n\tfor <dev@dpdk.org>; Wed, 27 Jun 2018 11:08:29 -0700 (PDT)",
            "from 6wind.com (host.78.145.23.62.rev.coltfrance.com.\n\t[62.23.145.78]) by smtp.gmail.com with ESMTPSA id\n\t132-v6sm8584514wmr.33.2018.06.27.11.08.28\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);\n\tWed, 27 Jun 2018 11:08:28 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=6wind-com.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:in-reply-to;\n\tbh=U1E2+DC2LJ/BRtPJepqcUF6KWkj9ynxLOWeVoySyUcI=;\n\tb=O2bYwX49+zlyk4Uvd/ZmxkfiSTu7/40DAQO6Vp2eGASyjSvVi8APfWbmj5Sqx2Befc\n\tZryEXttIN12kFCc1Vs9emCAMhV3KNXZaFC3oSYzP+vbPcjVQMjLtOtJ3QUEgGAZU4uxX\n\tiNJbSoOxFYPtEExwNjLMfaHACadgCZNPkZCyfMLSC+vsDbhTDJWpvj+2NWEGhZJaHoal\n\thU6EI0eCGIwXjntrtJwVhKQuBq6DcXuzE/AlaeRA/IG0qQLxMhchAgAH433DBFxD+91W\n\trreoVjMK5tLFjrE0ED/NgHFsYaff3xoW0LkESeFbxI5i7b6y5Ox4BataPlvYYSd8Th0a\n\tjQyg==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:in-reply-to;\n\tbh=U1E2+DC2LJ/BRtPJepqcUF6KWkj9ynxLOWeVoySyUcI=;\n\tb=bPEE7b8iYhuy73D083UCSlr3/quSK3ldACkQLbD7EcLw+W57aFh2sapR8KajQDNrQA\n\tzskzBgnLGXUBX6ahycEB/O5O0mBhpO+boCsnQZawbTX2skLsE23OHrDHnviTpBsPxDqH\n\tS8Fs8uKGJ139HCJfKbYOkcszOGsiZubEky5npTxspvFo/nWjkbi+vcXTp0NTUd3wjq3M\n\tn+olQsnfoB1Op1iNt4I4UxI+o15j8OhzRj4luBOVMkacMKADzS7Oe7Lj/tHxHeXuRtLw\n\t95tr/g/D3muCo8UHGkbu/NbuZ2u/rCZr+MsOxX22Ogk5A8vB3n5cXAW6qC3i1kudR3wc\n\tXeYQ==",
        "X-Gm-Message-State": "APt69E0dkuU8LbxM52rcktRldR2tR/y2F15VdpYSTXV3J84nOyh2Q6ZH\n\t8X/4yEMfzcskDcVomlPa6F/VSw==",
        "X-Google-Smtp-Source": "AAOMgpdhT+0jIuQpVRvAxEAqK6e4X3o2jQYKMuoE+5/iDGAQGooXmt9LPkYYXtvo02MsUv7blXJIIg==",
        "X-Received": "by 2002:a1c:928c:: with SMTP id\n\tu134-v6mr5665915wmd.106.1530122909288; \n\tWed, 27 Jun 2018 11:08:29 -0700 (PDT)",
        "Date": "Wed, 27 Jun 2018 20:08:12 +0200",
        "From": "Adrien Mazarguil <adrien.mazarguil@6wind.com>",
        "To": "Shahaf Shuler <shahafs@mellanox.com>",
        "Cc": "Nelio Laranjeiro <nelio.laranjeiro@6wind.com>,\n\tYongseok Koh <yskoh@mellanox.com>, dev@dpdk.org",
        "Message-ID": "<20180627173355.4718-3-adrien.mazarguil@6wind.com>",
        "References": "<20180627173355.4718-1-adrien.mazarguil@6wind.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=us-ascii",
        "Content-Disposition": "inline",
        "In-Reply-To": "<20180627173355.4718-1-adrien.mazarguil@6wind.com>",
        "X-Mailer": "git-send-email 2.11.0",
        "Subject": "[dpdk-dev] [PATCH 2/6] net/mlx5: add framework for switch flow rules",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Because mlx5 switch flow rules are configured through Netlink (TC\ninterface) and have little in common with Verbs, this patch adds a separate\nparser function to handle them.\n\n- mlx5_nl_flow_transpose() converts a rte_flow rule to its TC equivalent\n  and stores the result in a buffer.\n\n- mlx5_nl_flow_brand() gives a unique handle to a flow rule buffer.\n\n- mlx5_nl_flow_create() instantiates a flow rule on the device based on\n  such a buffer.\n\n- mlx5_nl_flow_destroy() performs the reverse operation.\n\nThese functions are called by the existing implementation when encountering\nflow rules which must be offloaded to the switch (currently relying on the\ntransfer attribute).\n\nSigned-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>\nSigned-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>\n---\n drivers/net/mlx5/mlx5.h         |  18 +++\n drivers/net/mlx5/mlx5_flow.c    | 113 ++++++++++++++\n drivers/net/mlx5/mlx5_nl_flow.c | 295 +++++++++++++++++++++++++++++++++++\n 3 files changed, 426 insertions(+)",
    "diff": "diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h\nindex 390249adb..aa16057d6 100644\n--- a/drivers/net/mlx5/mlx5.h\n+++ b/drivers/net/mlx5/mlx5.h\n@@ -148,6 +148,12 @@ struct mlx5_drop {\n \tstruct mlx5_rxq_ibv *rxq; /* Verbs Rx queue. */\n };\n \n+/** DPDK port to network interface index (ifindex) conversion. */\n+struct mlx5_nl_flow_ptoi {\n+\tuint16_t port_id; /**< DPDK port ID. */\n+\tunsigned int ifindex; /**< Network interface index. */\n+};\n+\n struct mnl_socket;\n \n struct priv {\n@@ -374,6 +380,18 @@ int mlx5_nl_allmulti(struct rte_eth_dev *dev, int enable);\n \n /* mlx5_nl_flow.c */\n \n+int mlx5_nl_flow_transpose(void *buf,\n+\t\t\t   size_t size,\n+\t\t\t   const struct mlx5_nl_flow_ptoi *ptoi,\n+\t\t\t   const struct rte_flow_attr *attr,\n+\t\t\t   const struct rte_flow_item *pattern,\n+\t\t\t   const struct rte_flow_action *actions,\n+\t\t\t   struct rte_flow_error *error);\n+void mlx5_nl_flow_brand(void *buf, uint32_t handle);\n+int mlx5_nl_flow_create(struct mnl_socket *nl, void *buf,\n+\t\t\tstruct rte_flow_error *error);\n+int mlx5_nl_flow_destroy(struct mnl_socket *nl, void *buf,\n+\t\t\t struct rte_flow_error *error);\n int mlx5_nl_flow_init(struct mnl_socket *nl, unsigned int ifindex,\n \t\t      struct rte_flow_error *error);\n struct mnl_socket *mlx5_nl_flow_socket_create(void);\ndiff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c\nindex 9241855be..93b245991 100644\n--- a/drivers/net/mlx5/mlx5_flow.c\n+++ b/drivers/net/mlx5/mlx5_flow.c\n@@ -4,6 +4,7 @@\n  */\n \n #include <sys/queue.h>\n+#include <stdalign.h>\n #include <stdint.h>\n #include <string.h>\n \n@@ -271,6 +272,7 @@ struct rte_flow {\n \t/**< Store tunnel packet type data to store in Rx queue. */\n \tuint8_t key[40]; /**< RSS hash key. */\n \tuint16_t (*queue)[]; /**< Destination queues to redirect traffic to. */\n+\tvoid *nl_flow; /**< Netlink flow buffer if relevant. */\n };\n \n static const struct rte_flow_ops mlx5_flow_ops = {\n@@ -2403,6 +2405,106 @@ mlx5_flow_actions(struct rte_eth_dev *dev,\n }\n \n /**\n+ * Validate flow rule and fill flow structure accordingly.\n+ *\n+ * @param dev\n+ *   Pointer to Ethernet device.\n+ * @param[out] flow\n+ *   Pointer to flow structure.\n+ * @param flow_size\n+ *   Size of allocated space for @p flow.\n+ * @param[in] attr\n+ *   Flow rule attributes.\n+ * @param[in] pattern\n+ *   Pattern specification (list terminated by the END pattern item).\n+ * @param[in] actions\n+ *   Associated actions (list terminated by the END action).\n+ * @param[out] error\n+ *   Perform verbose error reporting if not NULL.\n+ *\n+ * @return\n+ *   A positive value representing the size of the flow object in bytes\n+ *   regardless of @p flow_size on success, a negative errno value otherwise\n+ *   and rte_errno is set.\n+ */\n+static int\n+mlx5_flow_merge_switch(struct rte_eth_dev *dev,\n+\t\t       struct rte_flow *flow,\n+\t\t       size_t flow_size,\n+\t\t       const struct rte_flow_attr *attr,\n+\t\t       const struct rte_flow_item pattern[],\n+\t\t       const struct rte_flow_action actions[],\n+\t\t       struct rte_flow_error *error)\n+{\n+\tstruct priv *priv = dev->data->dev_private;\n+\tunsigned int n = mlx5_domain_to_port_id(priv->domain_id, NULL, 0);\n+\tuint16_t port_list[!n + n];\n+\tstruct mlx5_nl_flow_ptoi ptoi[!n + n + 1];\n+\tsize_t off = RTE_ALIGN_CEIL(sizeof(*flow), alignof(max_align_t));\n+\tunsigned int i;\n+\tunsigned int own = 0;\n+\tint ret;\n+\n+\t/* At least one port is needed when no switch domain is present. */\n+\tif (!n) {\n+\t\tn = 1;\n+\t\tport_list[0] = dev->data->port_id;\n+\t} else {\n+\t\tn = mlx5_domain_to_port_id(priv->domain_id, port_list, n);\n+\t\tif (n > RTE_DIM(port_list))\n+\t\t\tn = RTE_DIM(port_list);\n+\t}\n+\tfor (i = 0; i != n; ++i) {\n+\t\tstruct rte_eth_dev_info dev_info;\n+\n+\t\trte_eth_dev_info_get(port_list[i], &dev_info);\n+\t\tif (port_list[i] == dev->data->port_id)\n+\t\t\town = i;\n+\t\tptoi[i].port_id = port_list[i];\n+\t\tptoi[i].ifindex = dev_info.if_index;\n+\t}\n+\t/* Ensure first entry of ptoi[] is the current device. */\n+\tif (own) {\n+\t\tptoi[n] = ptoi[0];\n+\t\tptoi[0] = ptoi[own];\n+\t\tptoi[own] = ptoi[n];\n+\t}\n+\t/* An entry with zero ifindex terminates ptoi[]. */\n+\tptoi[n].port_id = 0;\n+\tptoi[n].ifindex = 0;\n+\tif (flow_size < off)\n+\t\tflow_size = 0;\n+\tret = mlx5_nl_flow_transpose((uint8_t *)flow + off,\n+\t\t\t\t     flow_size ? flow_size - off : 0,\n+\t\t\t\t     ptoi, attr, pattern, actions, error);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\tif (flow_size) {\n+\t\t*flow = (struct rte_flow){\n+\t\t\t.attributes = *attr,\n+\t\t\t.nl_flow = (uint8_t *)flow + off,\n+\t\t};\n+\t\t/*\n+\t\t * Generate a reasonably unique handle based on the address\n+\t\t * of the target buffer.\n+\t\t *\n+\t\t * This is straightforward on 32-bit systems where the flow\n+\t\t * pointer can be used directly. Otherwise, its least\n+\t\t * significant part is taken after shifting it by the\n+\t\t * previous power of two of the pointed buffer size.\n+\t\t */\n+\t\tif (sizeof(flow) <= 4)\n+\t\t\tmlx5_nl_flow_brand(flow->nl_flow, (uintptr_t)flow);\n+\t\telse\n+\t\t\tmlx5_nl_flow_brand\n+\t\t\t\t(flow->nl_flow,\n+\t\t\t\t (uintptr_t)flow >>\n+\t\t\t\t rte_log2_u32(rte_align32prevpow2(flow_size)));\n+\t}\n+\treturn off + ret;\n+}\n+\n+/**\n  * Validate the rule and return a flow structure filled accordingly.\n  *\n  * @param dev\n@@ -2439,6 +2541,9 @@ mlx5_flow_merge(struct rte_eth_dev *dev, struct rte_flow *flow,\n \tint ret;\n \tuint32_t i;\n \n+\tif (attr->transfer)\n+\t\treturn mlx5_flow_merge_switch(dev, flow, flow_size,\n+\t\t\t\t\t      attr, items, actions, error);\n \tif (!remain)\n \t\tflow = &local_flow;\n \tret = mlx5_flow_attributes(dev, attr, flow, error);\n@@ -2554,8 +2659,11 @@ mlx5_flow_validate(struct rte_eth_dev *dev,\n static void\n mlx5_flow_fate_remove(struct rte_eth_dev *dev, struct rte_flow *flow)\n {\n+\tstruct priv *priv = dev->data->dev_private;\n \tstruct mlx5_flow_verbs *verbs;\n \n+\tif (flow->nl_flow && priv->mnl_socket)\n+\t\tmlx5_nl_flow_destroy(priv->mnl_socket, flow->nl_flow, NULL);\n \tLIST_FOREACH(verbs, &flow->verbs, next) {\n \t\tif (verbs->flow) {\n \t\t\tclaim_zero(mlx5_glue->destroy_flow(verbs->flow));\n@@ -2592,6 +2700,7 @@ static int\n mlx5_flow_fate_apply(struct rte_eth_dev *dev, struct rte_flow *flow,\n \t\t     struct rte_flow_error *error)\n {\n+\tstruct priv *priv = dev->data->dev_private;\n \tstruct mlx5_flow_verbs *verbs;\n \tint err;\n \n@@ -2640,6 +2749,10 @@ mlx5_flow_fate_apply(struct rte_eth_dev *dev, struct rte_flow *flow,\n \t\t\tgoto error;\n \t\t}\n \t}\n+\tif (flow->nl_flow &&\n+\t    priv->mnl_socket &&\n+\t    mlx5_nl_flow_create(priv->mnl_socket, flow->nl_flow, error))\n+\t\tgoto error;\n \treturn 0;\n error:\n \terr = rte_errno; /* Save rte_errno before cleanup. */\ndiff --git a/drivers/net/mlx5/mlx5_nl_flow.c b/drivers/net/mlx5/mlx5_nl_flow.c\nindex 7a8683b03..1fc62fb0a 100644\n--- a/drivers/net/mlx5/mlx5_nl_flow.c\n+++ b/drivers/net/mlx5/mlx5_nl_flow.c\n@@ -5,7 +5,9 @@\n \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 <stdalign.h>\n@@ -14,11 +16,248 @@\n #include <stdlib.h>\n #include <sys/socket.h>\n \n+#include <rte_byteorder.h>\n #include <rte_errno.h>\n #include <rte_flow.h>\n \n #include \"mlx5.h\"\n \n+/** Parser state definitions for mlx5_nl_flow_trans[]. */\n+enum mlx5_nl_flow_trans {\n+\tINVALID,\n+\tBACK,\n+\tATTR,\n+\tPATTERN,\n+\tITEM_VOID,\n+\tACTIONS,\n+\tACTION_VOID,\n+\tEND,\n+};\n+\n+#define TRANS(...) (const enum mlx5_nl_flow_trans []){ __VA_ARGS__, INVALID, }\n+\n+#define PATTERN_COMMON \\\n+\tITEM_VOID, ACTIONS\n+#define ACTIONS_COMMON \\\n+\tACTION_VOID, END\n+\n+/** Parser state transitions used by mlx5_nl_flow_transpose(). */\n+static const enum mlx5_nl_flow_trans *const mlx5_nl_flow_trans[] = {\n+\t[INVALID] = NULL,\n+\t[BACK] = NULL,\n+\t[ATTR] = TRANS(PATTERN),\n+\t[PATTERN] = TRANS(PATTERN_COMMON),\n+\t[ITEM_VOID] = TRANS(BACK),\n+\t[ACTIONS] = TRANS(ACTIONS_COMMON),\n+\t[ACTION_VOID] = TRANS(BACK),\n+\t[END] = NULL,\n+};\n+\n+/**\n+ * Transpose flow rule description to rtnetlink message.\n+ *\n+ * This function transposes a flow rule description to a traffic control\n+ * (TC) filter creation message ready to be sent over Netlink.\n+ *\n+ * Target interface is specified as the first entry of the @p ptoi table.\n+ * Subsequent entries enable this function to resolve other DPDK port IDs\n+ * found in the flow rule.\n+ *\n+ * @param[out] buf\n+ *   Output message buffer. May be NULL when @p size is 0.\n+ * @param size\n+ *   Size of @p buf. Message may be truncated if not large enough.\n+ * @param[in] ptoi\n+ *   DPDK port ID to network interface index translation table. This table\n+ *   is terminated by an entry with a zero ifindex value.\n+ * @param[in] attr\n+ *   Flow rule attributes.\n+ * @param[in] pattern\n+ *   Pattern specification.\n+ * @param[in] actions\n+ *   Associated actions.\n+ * @param[out] error\n+ *   Perform verbose error reporting if not NULL.\n+ *\n+ * @return\n+ *   A positive value representing the exact size of the message in bytes\n+ *   regardless of the @p size parameter on success, a negative errno value\n+ *   otherwise and rte_errno is set.\n+ */\n+int\n+mlx5_nl_flow_transpose(void *buf,\n+\t\t       size_t size,\n+\t\t       const struct mlx5_nl_flow_ptoi *ptoi,\n+\t\t       const struct rte_flow_attr *attr,\n+\t\t       const struct rte_flow_item *pattern,\n+\t\t       const struct rte_flow_action *actions,\n+\t\t       struct rte_flow_error *error)\n+{\n+\talignas(struct nlmsghdr)\n+\tuint8_t buf_tmp[MNL_SOCKET_BUFFER_SIZE];\n+\tconst struct rte_flow_item *item;\n+\tconst struct rte_flow_action *action;\n+\tunsigned int n;\n+\tstruct nlattr *na_flower;\n+\tstruct nlattr *na_flower_act;\n+\tconst enum mlx5_nl_flow_trans *trans;\n+\tconst enum mlx5_nl_flow_trans *back;\n+\n+\tif (!size)\n+\t\tgoto error_nobufs;\n+init:\n+\titem = pattern;\n+\taction = actions;\n+\tn = 0;\n+\tna_flower = NULL;\n+\tna_flower_act = NULL;\n+\ttrans = TRANS(ATTR);\n+\tback = trans;\n+trans:\n+\tswitch (trans[n++]) {\n+\t\tstruct nlmsghdr *nlh;\n+\t\tstruct tcmsg *tcm;\n+\n+\tcase INVALID:\n+\t\tif (item->type)\n+\t\t\treturn rte_flow_error_set\n+\t\t\t\t(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t item, \"unsupported pattern item combination\");\n+\t\telse if (action->type)\n+\t\t\treturn rte_flow_error_set\n+\t\t\t\t(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t action, \"unsupported action combination\");\n+\t\treturn rte_flow_error_set\n+\t\t\t(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t \"flow rule lacks some kind of fate action\");\n+\tcase BACK:\n+\t\ttrans = back;\n+\t\tn = 0;\n+\t\tgoto trans;\n+\tcase ATTR:\n+\t\t/*\n+\t\t * Supported attributes: no groups, some priorities and\n+\t\t * ingress only. Don't care about transfer as it is the\n+\t\t * caller's problem.\n+\t\t */\n+\t\tif (attr->group)\n+\t\t\treturn rte_flow_error_set\n+\t\t\t\t(error, ENOTSUP,\n+\t\t\t\t RTE_FLOW_ERROR_TYPE_ATTR_GROUP,\n+\t\t\t\t attr, \"groups are not supported\");\n+\t\tif (attr->priority > 0xfffe)\n+\t\t\treturn rte_flow_error_set\n+\t\t\t\t(error, ENOTSUP,\n+\t\t\t\t RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,\n+\t\t\t\t attr, \"lowest priority level is 0xfffe\");\n+\t\tif (!attr->ingress)\n+\t\t\treturn rte_flow_error_set\n+\t\t\t\t(error, ENOTSUP,\n+\t\t\t\t RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,\n+\t\t\t\t attr, \"only ingress is supported\");\n+\t\tif (attr->egress)\n+\t\t\treturn rte_flow_error_set\n+\t\t\t\t(error, ENOTSUP,\n+\t\t\t\t RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,\n+\t\t\t\t attr, \"egress is not supported\");\n+\t\tif (size < mnl_nlmsg_size(sizeof(*tcm)))\n+\t\t\tgoto error_nobufs;\n+\t\tnlh = mnl_nlmsg_put_header(buf);\n+\t\tnlh->nlmsg_type = 0;\n+\t\tnlh->nlmsg_flags = 0;\n+\t\tnlh->nlmsg_seq = 0;\n+\t\ttcm = mnl_nlmsg_put_extra_header(nlh, sizeof(*tcm));\n+\t\ttcm->tcm_family = AF_UNSPEC;\n+\t\ttcm->tcm_ifindex = ptoi[0].ifindex;\n+\t\t/*\n+\t\t * Let kernel pick a handle by default. A predictable handle\n+\t\t * can be set by the caller on the resulting buffer through\n+\t\t * mlx5_nl_flow_brand().\n+\t\t */\n+\t\ttcm->tcm_handle = 0;\n+\t\ttcm->tcm_parent = TC_H_MAKE(TC_H_INGRESS, TC_H_MIN_INGRESS);\n+\t\t/*\n+\t\t * Priority cannot be zero to prevent the kernel from\n+\t\t * picking one automatically.\n+\t\t */\n+\t\ttcm->tcm_info = TC_H_MAKE((attr->priority + 1) << 16,\n+\t\t\t\t\t  RTE_BE16(ETH_P_ALL));\n+\t\tbreak;\n+\tcase PATTERN:\n+\t\tif (!mnl_attr_put_strz_check(buf, size, TCA_KIND, \"flower\"))\n+\t\t\tgoto error_nobufs;\n+\t\tna_flower = mnl_attr_nest_start_check(buf, size, TCA_OPTIONS);\n+\t\tif (!na_flower)\n+\t\t\tgoto error_nobufs;\n+\t\tif (!mnl_attr_put_u32_check(buf, size, TCA_FLOWER_FLAGS,\n+\t\t\t\t\t    TCA_CLS_FLAGS_SKIP_SW))\n+\t\t\tgoto error_nobufs;\n+\t\tbreak;\n+\tcase ITEM_VOID:\n+\t\tif (item->type != RTE_FLOW_ITEM_TYPE_VOID)\n+\t\t\tgoto trans;\n+\t\t++item;\n+\t\tbreak;\n+\tcase ACTIONS:\n+\t\tif (item->type != RTE_FLOW_ITEM_TYPE_END)\n+\t\t\tgoto trans;\n+\t\tassert(na_flower);\n+\t\tassert(!na_flower_act);\n+\t\tna_flower_act =\n+\t\t\tmnl_attr_nest_start_check(buf, size, TCA_FLOWER_ACT);\n+\t\tif (!na_flower_act)\n+\t\t\tgoto error_nobufs;\n+\t\tbreak;\n+\tcase ACTION_VOID:\n+\t\tif (action->type != RTE_FLOW_ACTION_TYPE_VOID)\n+\t\t\tgoto trans;\n+\t\t++action;\n+\t\tbreak;\n+\tcase END:\n+\t\tif (item->type != RTE_FLOW_ITEM_TYPE_END ||\n+\t\t    action->type != RTE_FLOW_ACTION_TYPE_END)\n+\t\t\tgoto trans;\n+\t\tif (na_flower_act)\n+\t\t\tmnl_attr_nest_end(buf, na_flower_act);\n+\t\tif (na_flower)\n+\t\t\tmnl_attr_nest_end(buf, na_flower);\n+\t\tnlh = buf;\n+\t\treturn nlh->nlmsg_len;\n+\t}\n+\tback = trans;\n+\ttrans = mlx5_nl_flow_trans[trans[n - 1]];\n+\tn = 0;\n+\tgoto trans;\n+error_nobufs:\n+\tif (buf != buf_tmp) {\n+\t\tbuf = buf_tmp;\n+\t\tsize = sizeof(buf_tmp);\n+\t\tgoto init;\n+\t}\n+\treturn rte_flow_error_set\n+\t\t(error, ENOBUFS, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t \"generated TC message is too large\");\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 buf\n+ *   Flow rule buffer previously initialized by mlx5_nl_flow_transpose().\n+ * @param handle\n+ *   Unique 32-bit handle to use.\n+ */\n+void\n+mlx5_nl_flow_brand(void *buf, uint32_t handle)\n+{\n+\tstruct tcmsg *tcm = mnl_nlmsg_get_payload(buf);\n+\n+\ttcm->tcm_handle = handle;\n+}\n+\n /**\n  * Send Netlink message with acknowledgment.\n  *\n@@ -54,6 +293,62 @@ mlx5_nl_flow_nl_ack(struct mnl_socket *nl, struct nlmsghdr *nlh)\n }\n \n /**\n+ * Create a Netlink flow rule.\n+ *\n+ * @param nl\n+ *   Libmnl socket to use.\n+ * @param buf\n+ *   Flow rule buffer previously initialized by mlx5_nl_flow_transpose().\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_nl_flow_create(struct mnl_socket *nl, void *buf,\n+\t\t    struct rte_flow_error *error)\n+{\n+\tstruct nlmsghdr *nlh = buf;\n+\n+\tnlh->nlmsg_type = RTM_NEWTFILTER;\n+\tnlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;\n+\tif (!mlx5_nl_flow_nl_ack(nl, nlh))\n+\t\treturn 0;\n+\treturn rte_flow_error_set\n+\t\t(error, rte_errno, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t \"netlink: failed to create TC flow rule\");\n+}\n+\n+/**\n+ * Destroy a Netlink flow rule.\n+ *\n+ * @param nl\n+ *   Libmnl socket to use.\n+ * @param buf\n+ *   Flow rule buffer previously initialized by mlx5_nl_flow_transpose().\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_nl_flow_destroy(struct mnl_socket *nl, void *buf,\n+\t\t     struct rte_flow_error *error)\n+{\n+\tstruct nlmsghdr *nlh = buf;\n+\n+\tnlh->nlmsg_type = RTM_DELTFILTER;\n+\tnlh->nlmsg_flags = NLM_F_REQUEST;\n+\tif (!mlx5_nl_flow_nl_ack(nl, nlh))\n+\t\treturn 0;\n+\treturn rte_flow_error_set\n+\t\t(error, errno, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t \"netlink: failed to destroy TC flow rule\");\n+}\n+\n+/**\n  * Initialize ingress qdisc of a given network interface.\n  *\n  * @param nl\n",
    "prefixes": [
        "2/6"
    ]
}