get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 43007,
    "url": "http://patches.dpdk.org/api/patches/43007/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20180713092910.26276-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": "<20180713092910.26276-3-adrien.mazarguil@6wind.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20180713092910.26276-3-adrien.mazarguil@6wind.com",
    "date": "2018-07-13T09:40:39",
    "name": "[v2,2/6] net/mlx5: add framework for switch flow rules",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "14d686a432af406ece69441811c61b41409b4724",
    "submitter": {
        "id": 165,
        "url": "http://patches.dpdk.org/api/people/165/?format=api",
        "name": "Adrien Mazarguil",
        "email": "adrien.mazarguil@6wind.com"
    },
    "delegate": {
        "id": 6624,
        "url": "http://patches.dpdk.org/api/users/6624/?format=api",
        "username": "shahafs",
        "first_name": "Shahaf",
        "last_name": "Shuler",
        "email": "shahafs@mellanox.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20180713092910.26276-3-adrien.mazarguil@6wind.com/mbox/",
    "series": [
        {
            "id": 558,
            "url": "http://patches.dpdk.org/api/series/558/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=558",
            "date": "2018-07-13T09:40:35",
            "name": "net/mlx5: add support for switch flow rules",
            "version": 2,
            "mbox": "http://patches.dpdk.org/series/558/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/43007/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/43007/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 C30916CC3;\n\tFri, 13 Jul 2018 11:40:59 +0200 (CEST)",
            "from mail-wr1-f68.google.com (mail-wr1-f68.google.com\n\t[209.85.221.68]) by dpdk.org (Postfix) with ESMTP id DC50B56A1\n\tfor <dev@dpdk.org>; Fri, 13 Jul 2018 11:40:56 +0200 (CEST)",
            "by mail-wr1-f68.google.com with SMTP id h9-v6so24473168wro.3\n\tfor <dev@dpdk.org>; Fri, 13 Jul 2018 02:40:56 -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\th5-v6sm15051127wrr.19.2018.07.13.02.40.55\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);\n\tFri, 13 Jul 2018 02:40:55 -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=VEAEpZk4lO+Va1c+n+6wlkyY73J5rH1Bi0fyDVEQxMc=;\n\tb=SLtB1Fte+5EF1n0ZuziX/FRm5fanhyRYSxAH5GN8XEZ+TlUGhaY1fHNfWS7/WzRP/M\n\tD1dHW1bDwwerGP0JdRx77Q1BMjLiZSdR+7nTnlZRO7U/cdgei8b8WylNEtVpU3pZQzmn\n\tLHXebH0Ez+/onGQpGTmOO9iO0PwnnpGK5YxMqshWOw/e8zwDZGMAj1pi9Zv/qzcw/97e\n\t1chhQNX76vNCsakyRaFePR4qFgtg0+dN1TvvciRKabUAo/ORX1R0TsY33vgyOFZHFktd\n\tFEM/QErYTuKPcUXCXUth2YyxU2Z0wxEacs5JK0pO0j6H2Os8spqqo5HLO3qStEzWJUmL\n\t/WuQ==",
        "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=VEAEpZk4lO+Va1c+n+6wlkyY73J5rH1Bi0fyDVEQxMc=;\n\tb=WzL26L/giTNkyPd6MFdY+ozdyOQ6Q1uhAhdSb+vJaICipoOEPmhxqM/g6BL/J9aJOL\n\tYgF6OmXY4n4w/0fT2r3Y9W3VSonc44+KDDWRtKMyNSJbRvDdaYYLsGxqsxmOQ4xxq1e3\n\tyJ5rN5o4c3tvJTBlOfVcm6IHd2ZS5UrTOnC9H7FUGm0wtJ/46FuhC5MryEb361t3CZqw\n\tQwCvRKHsDdiw/ZJb5BWTeMlPG+I0BAvuGpPTTdoMoTIby3/xCEwLIa33hUUbcl8fKjFO\n\tH1YYMTK30OJkxinlID5xXMb4UOpzJkkNrakuOYrIn/cV7SbR26+AW4L/DG6tedxAaTYV\n\t72iA==",
        "X-Gm-Message-State": "AOUpUlGard+xM3I7e1ZTdYfAeM0DBM9KDYZKTsjNGviamTI8d753tlfj\n\tIgWKpilxWeheXhIY2n6xKejSP1mU",
        "X-Google-Smtp-Source": "AAOMgpcHrsb0zE0m1YnISK3lc3VaERz4KUJiinMeAedgRew73gPaD+0BYDkKQR6YwQb5slcGiJrwUA==",
        "X-Received": "by 2002:adf:b851:: with SMTP id\n\tu17-v6mr4625308wrf.73.1531474856477; \n\tFri, 13 Jul 2018 02:40:56 -0700 (PDT)",
        "Date": "Fri, 13 Jul 2018 11:40:39 +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": "<20180713092910.26276-3-adrien.mazarguil@6wind.com>",
        "References": "<20180627173355.4718-1-adrien.mazarguil@6wind.com>\n\t<20180713092910.26276-1-adrien.mazarguil@6wind.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=us-ascii",
        "Content-Disposition": "inline",
        "In-Reply-To": "<20180713092910.26276-1-adrien.mazarguil@6wind.com>",
        "X-Mailer": "git-send-email 2.11.0",
        "Subject": "[dpdk-dev] [PATCH v2 2/6] net/mlx5: add framework for switch flow\n\trules",
        "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>\nAcked-by: Yongseok Koh <yskoh@mellanox.com>\n--\nv2 changes:\n\n- Replaced mlx5_domain_to_port_id() with mlx5_dev_to_port_id().\n- Added definitions for NETLINK_CAP_ACK, TC_H_MIN_INGRESS,\n  TCA_CLS_FLAGS_SKIP_SW, TCA_FLOWER_ACT and TCA_FLOWER_FLAGS in case they\n  are missing from the host system (e.g. RHEL 7.2).\n- Modified the size of buf_tmp[] in mlx5_nl_flow_transpose() as\n  MNL_SOCKET_BUFFER_SIZE was insane. 1 kiB of message payload is plenty\n  enough for the time being.\n---\n drivers/net/mlx5/Makefile       |  10 ++\n drivers/net/mlx5/mlx5.h         |  18 ++\n drivers/net/mlx5/mlx5_flow.c    | 111 +++++++++++++\n drivers/net/mlx5/mlx5_nl_flow.c | 311 +++++++++++++++++++++++++++++++++++\n 4 files changed, 450 insertions(+)",
    "diff": "diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile\nindex 8d3cb219b..1ccfbb594 100644\n--- a/drivers/net/mlx5/Makefile\n+++ b/drivers/net/mlx5/Makefile\n@@ -199,6 +199,16 @@ mlx5_autoconf.h.new: $(RTE_SDK)/buildtools/auto-config-h.sh\n \t\tlinux/if_link.h \\\n \t\tenum IFLA_PHYS_PORT_NAME \\\n \t\t$(AUTOCONF_OUTPUT)\n+\t$Q sh -- '$<' '$@' \\\n+\t\tHAVE_TCA_FLOWER_ACT \\\n+\t\tlinux/pkt_cls.h \\\n+\t\tenum TCA_FLOWER_ACT \\\n+\t\t$(AUTOCONF_OUTPUT)\n+\t$Q sh -- '$<' '$@' \\\n+\t\tHAVE_TCA_FLOWER_FLAGS \\\n+\t\tlinux/pkt_cls.h \\\n+\t\tenum TCA_FLOWER_FLAGS \\\n+\t\t$(AUTOCONF_OUTPUT)\n \n # Create mlx5_autoconf.h or update it in case it differs from the new one.\n \ndiff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h\nindex 98b6ec07d..5bad1b32b 100644\n--- a/drivers/net/mlx5/mlx5.h\n+++ b/drivers/net/mlx5/mlx5.h\n@@ -156,6 +156,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@@ -385,6 +391,18 @@ int mlx5_nl_switch_info(int nl, unsigned int ifindex,\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 89bfc670f..890bf7d72 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@@ -280,6 +281,7 @@ struct rte_flow {\n \tstruct rte_flow_action_rss rss;/**< RSS context. */\n \tuint8_t key[MLX5_RSS_HASH_KEY_LEN]; /**< RSS hash key. */\n \tuint16_t (*queue)[]; /**< Destination queues to redirect traffic to. */\n+\tvoid *nl_flow; /**< Netlink flow buffer if relevant. */\n };\n \n static const struct rte_flow_ops mlx5_flow_ops = {\n@@ -2365,6 +2367,103 @@ 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+\tunsigned int n = mlx5_dev_to_port_id(dev->device, NULL, 0);\n+\tuint16_t port_id[!n + n];\n+\tstruct mlx5_nl_flow_ptoi ptoi[!n + n + 1];\n+\tsize_t off = RTE_ALIGN_CEIL(sizeof(*flow), alignof(max_align_t));\n+\tunsigned int i;\n+\tunsigned int own = 0;\n+\tint ret;\n+\n+\t/* At least one port is needed when no switch domain is present. */\n+\tif (!n) {\n+\t\tn = 1;\n+\t\tport_id[0] = dev->data->port_id;\n+\t} else {\n+\t\tn = RTE_MIN(mlx5_dev_to_port_id(dev->device, port_id, n), n);\n+\t}\n+\tfor (i = 0; i != n; ++i) {\n+\t\tstruct rte_eth_dev_info dev_info;\n+\n+\t\trte_eth_dev_info_get(port_id[i], &dev_info);\n+\t\tif (port_id[i] == dev->data->port_id)\n+\t\t\town = i;\n+\t\tptoi[i].port_id = port_id[i];\n+\t\tptoi[i].ifindex = dev_info.if_index;\n+\t}\n+\t/* Ensure first entry of ptoi[] is the current device. */\n+\tif (own) {\n+\t\tptoi[n] = ptoi[0];\n+\t\tptoi[0] = ptoi[own];\n+\t\tptoi[own] = ptoi[n];\n+\t}\n+\t/* An entry with zero ifindex terminates ptoi[]. */\n+\tptoi[n].port_id = 0;\n+\tptoi[n].ifindex = 0;\n+\tif (flow_size < off)\n+\t\tflow_size = 0;\n+\tret = mlx5_nl_flow_transpose((uint8_t *)flow + off,\n+\t\t\t\t     flow_size ? flow_size - off : 0,\n+\t\t\t\t     ptoi, attr, pattern, actions, error);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\tif (flow_size) {\n+\t\t*flow = (struct rte_flow){\n+\t\t\t.attributes = *attr,\n+\t\t\t.nl_flow = (uint8_t *)flow + off,\n+\t\t};\n+\t\t/*\n+\t\t * Generate a reasonably unique handle based on the address\n+\t\t * of the target buffer.\n+\t\t *\n+\t\t * This is straightforward on 32-bit systems where the flow\n+\t\t * pointer can be used directly. Otherwise, its least\n+\t\t * significant part is taken after shifting it by the\n+\t\t * previous power of two of the pointed buffer size.\n+\t\t */\n+\t\tif (sizeof(flow) <= 4)\n+\t\t\tmlx5_nl_flow_brand(flow->nl_flow, (uintptr_t)flow);\n+\t\telse\n+\t\t\tmlx5_nl_flow_brand\n+\t\t\t\t(flow->nl_flow,\n+\t\t\t\t (uintptr_t)flow >>\n+\t\t\t\t rte_log2_u32(rte_align32prevpow2(flow_size)));\n+\t}\n+\treturn off + ret;\n+}\n+\n+/**\n  * Convert the @p attributes, @p pattern, @p action, into an flow for the NIC\n  * after ensuring the NIC will understand and process it correctly.\n  * The conversion is only performed item/action per item/action, each of\n@@ -2418,6 +2517,10 @@ mlx5_flow_merge(struct rte_eth_dev *dev, struct rte_flow *flow,\n \tint ret;\n \tuint32_t i;\n \n+\tif (attributes->transfer)\n+\t\treturn mlx5_flow_merge_switch(dev, flow, flow_size,\n+\t\t\t\t\t      attributes, pattern,\n+\t\t\t\t\t      actions, error);\n \tif (size > flow_size)\n \t\tflow = &local_flow;\n \tret = mlx5_flow_attributes(dev, attributes, flow, error);\n@@ -2708,8 +2811,11 @@ mlx5_flow_validate(struct rte_eth_dev *dev,\n static void\n mlx5_flow_remove(struct rte_eth_dev *dev, struct rte_flow *flow)\n {\n+\tstruct priv *priv = dev->data->dev_private;\n \tstruct mlx5_flow_verbs *verbs;\n \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@@ -2746,6 +2852,7 @@ static int\n mlx5_flow_apply(struct rte_eth_dev *dev, struct rte_flow *flow,\n \t\tstruct rte_flow_error *error)\n {\n+\tstruct priv *priv = dev->data->dev_private;\n \tstruct mlx5_flow_verbs *verbs;\n \tint err;\n \n@@ -2794,6 +2901,10 @@ mlx5_flow_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 60a4493e5..a9a5bac49 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,6 +16,7 @@\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@@ -24,6 +27,258 @@\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+\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_nlmsg_size(sizeof(struct tcmsg) + 1024)];\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@@ -60,6 +315,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": [
        "v2",
        "2/6"
    ]
}