Show a patch.

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

{
    "id": 44085,
    "url": "http://patches.dpdk.org/api/patches/44085/",
    "web_url": "http://patches.dpdk.org/patch/44085/",
    "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": "<20180831092038.23051-6-adrien.mazarguil@6wind.com>",
    "date": "2018-08-31T09:57:36",
    "name": "[5/8] net/mlx5: prepare switch flow rule parser for encap offloads",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "eb703045aee43375bb92f0803a6ba5d7d19f9ac5",
    "submitter": {
        "id": 165,
        "url": "http://patches.dpdk.org/api/people/165/",
        "name": "Adrien Mazarguil",
        "email": "adrien.mazarguil@6wind.com"
    },
    "delegate": null,
    "mbox": "http://patches.dpdk.org/patch/44085/mbox/",
    "series": [
        {
            "id": 1126,
            "url": "http://patches.dpdk.org/api/series/1126/",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=1126",
            "date": "2018-08-31T09:57:25",
            "name": "net/mlx5: add switch offload for VXLAN encap/decap",
            "version": 1,
            "mbox": "http://patches.dpdk.org/series/1126/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/44085/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/44085/checks/",
    "tags": {},
    "headers": {
        "X-Mailman-Version": "2.1.15",
        "In-Reply-To": "<20180831092038.23051-1-adrien.mazarguil@6wind.com>",
        "Errors-To": "dev-bounces@dpdk.org",
        "X-Mailer": "git-send-email 2.11.0",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id C4DF95323;\n\tFri, 31 Aug 2018 11:57:55 +0200 (CEST)",
            "from mail-wm0-f65.google.com (mail-wm0-f65.google.com\n\t[74.125.82.65]) by dpdk.org (Postfix) with ESMTP id 2A9A74F94\n\tfor <dev@dpdk.org>; Fri, 31 Aug 2018 11:57:53 +0200 (CEST)",
            "by mail-wm0-f65.google.com with SMTP id 207-v6so4724416wme.5\n\tfor <dev@dpdk.org>; Fri, 31 Aug 2018 02:57:53 -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\tb2-v6sm3568001wmh.3.2018.08.31.02.57.51\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);\n\tFri, 31 Aug 2018 02:57:51 -0700 (PDT)"
        ],
        "References": "<20180831092038.23051-1-adrien.mazarguil@6wind.com>",
        "X-Google-Smtp-Source": "ANB0Vda1vu/biWbWeGybReoCokGvj8nIhp/1ql1aMBwacN+STiDicH40N15+yAc3Bh/wyCvtA9zrFg==",
        "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=TL/XY9FSh42gEPQu3TfCqY700L5VIdTyt0SYhjHhF54=;\n\tb=hKFjB3qx9EcPc9TvrZK6TpiPEtMopxVmIPUQcEbIwMtzCoQHS4eMoF7uJAHMNGd+0q\n\tF8GrBKkeBKHORTA6LxwyGa0FJNSVzmfr5/tqUleVwwTL4cNiIXAdfCsVya7/ql2Qm3Hn\n\tqtmadJWWGpJnV6PNCWUgKFx4ZCPDTNCzesMPt2QbGYbQ6iqYHN/K0lqFc7EacK5fuhuo\n\tjfHy5vHg1w6RYCt3LnBn+mlMbtzF9S8JRqjlM47VlTZtyzP4KPV9COaCQ0VkK+byOdwY\n\thlT9XCeLIYACUMVJ52hoa+MM210+mcxVDhACciYPnLi7+2wwsctJt0m77ZeURlBahfs6\n\tUNrQ==",
        "MIME-Version": "1.0",
        "X-Received": "by 2002:a1c:adcc:: with SMTP id\n\tw195-v6mr4403101wme.41.1535709472572; \n\tFri, 31 Aug 2018 02:57:52 -0700 (PDT)",
        "Message-ID": "<20180831092038.23051-6-adrien.mazarguil@6wind.com>",
        "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=TL/XY9FSh42gEPQu3TfCqY700L5VIdTyt0SYhjHhF54=;\n\tb=NmB1bdabuPvUhy1AgrarfNZveIZ5rE7qK5b26rGRV3OC/CS1Yg09L4ib0jzBT60CjD\n\tyUsq2kwxnlBOGvgU1Y5FbYCst3UYvn/WDSn3C12xMICuVs6ECJvKPxB/33DOKOHnNXHH\n\t2D+HlfXlvhS3rCnMq3QTGOWeqCZIxrJoDZC6Dt6/FV6jugQX894DP9EbnjIZnb6KoJTb\n\tsJ1K6AxHd3WfgZSzVmkiFqoIo38ay/+x/U5xy+gBv+aqGipc/stRm9koO0H25c3Sv4ZR\n\tzlkha3ORxdRFdM4B8Z53476xUk/mUeVo8vLGMAtxpUxxsFvDqAG4rmSkHCVjfVilSygG\n\tuhYQ==",
        "Delivered-To": "patchwork@dpdk.org",
        "Precedence": "list",
        "From": "Adrien Mazarguil <adrien.mazarguil@6wind.com>",
        "X-Original-To": "patchwork@dpdk.org",
        "Content-Type": "text/plain; charset=us-ascii",
        "Content-Disposition": "inline",
        "Return-Path": "<dev-bounces@dpdk.org>",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "To": "Shahaf Shuler <shahafs@mellanox.com>, Yongseok Koh <yskoh@mellanox.com>, \n\tSlava Ovsiienko <viacheslavo@mellanox.com>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "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>",
        "Date": "Fri, 31 Aug 2018 11:57:36 +0200",
        "X-Gm-Message-State": "APzg51CrYzYbBYVSFhKytBwdcccYC8ugg2+oLFHzVgAScBSISilQpGTJ\n\tm6HQRyPDftrcs4O2ytGTIxQjyg==",
        "Cc": "dev@dpdk.org",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "X-BeenThere": "dev@dpdk.org",
        "Subject": "[dpdk-dev] [PATCH 5/8] net/mlx5: prepare switch flow rule parser\n\tfor encap offloads"
    },
    "content": "A mere message buffer is not enough to support the additional logic\nrequired to manage flow rules with such offloads; a dedicated object\n(struct mlx5_nl_flow) with the ability to store additional information and\nadjustable target network interfaces is needed, as well as a context\nobject for shared data (struct mlx5_nl_flow_ctx).\n\nA predictable message sequence number can now be stored in the context\nobject as an improvement over CPU counters.\n\nSigned-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>\n---\n drivers/net/mlx5/mlx5.c         |  18 ++--\n drivers/net/mlx5/mlx5.h         |  22 ++--\n drivers/net/mlx5/mlx5_flow.c    |  10 +-\n drivers/net/mlx5/mlx5_nl_flow.c | 189 ++++++++++++++++++++++++-----------\n 4 files changed, 155 insertions(+), 84 deletions(-)",
    "diff": "diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c\nindex 9a504a31c..c10ca4ae5 100644\n--- a/drivers/net/mlx5/mlx5.c\n+++ b/drivers/net/mlx5/mlx5.c\n@@ -282,8 +282,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_nl_flow_socket_destroy(priv->mnl_socket);\n+\tif (priv->nl_flow_ctx)\n+\t\tmlx5_nl_flow_ctx_destroy(priv->nl_flow_ctx);\n \tret = mlx5_hrxq_ibv_verify(dev);\n \tif (ret)\n \t\tDRV_LOG(WARNING, \"port %u some hash Rx queue still remain\",\n@@ -1136,13 +1136,13 @@ 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_nl_flow_socket_create();\n-\tif (!priv->mnl_socket ||\n+\tpriv->nl_flow_ctx = mlx5_nl_flow_ctx_create(eth_dev->device->numa_node);\n+\tif (!priv->nl_flow_ctx ||\n \t    !priv->ifindex ||\n-\t    mlx5_nl_flow_ifindex_init(priv->mnl_socket, priv->ifindex,\n+\t    mlx5_nl_flow_ifindex_init(priv->nl_flow_ctx, priv->ifindex,\n \t\t\t\t      &flow_error)) {\n-\t\tif (!priv->mnl_socket) {\n-\t\t\tflow_error.message = \"cannot open libmnl socket\";\n+\t\tif (!priv->nl_flow_ctx) {\n+\t\t\tflow_error.message = \"cannot create NL flow context\";\n \t\t} else if (!priv->ifindex) {\n \t\t\trte_errno = ENXIO;\n \t\t\tflow_error.message = \"unknown network interface index\";\n@@ -1204,8 +1204,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_nl_flow_socket_destroy(priv->mnl_socket);\n+\t\tif (priv->nl_flow_ctx)\n+\t\t\tmlx5_nl_flow_ctx_destroy(priv->nl_flow_ctx);\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.h b/drivers/net/mlx5/mlx5.h\nindex 287cfc643..210f4ea11 100644\n--- a/drivers/net/mlx5/mlx5.h\n+++ b/drivers/net/mlx5/mlx5.h\n@@ -162,7 +162,8 @@ struct mlx5_nl_flow_ptoi {\n \tunsigned int ifindex; /**< Network interface index. */\n };\n \n-struct mnl_socket;\n+struct mlx5_nl_flow;\n+struct mlx5_nl_flow_ctx;\n \n struct priv {\n \tLIST_ENTRY(priv) mem_event_cb; /* Called by memory event callback. */\n@@ -229,7 +230,7 @@ struct priv {\n \trte_spinlock_t uar_lock[MLX5_UAR_PAGE_NUM_MAX];\n \t/* UAR same-page access control required in 32bit implementations. */\n #endif\n-\tstruct mnl_socket *mnl_socket; /* Libmnl socket. */\n+\tstruct mlx5_nl_flow_ctx *nl_flow_ctx; /* Context for NL flow rules. */\n };\n \n #define PORT_ID(priv) ((priv)->dev_data->port_id)\n@@ -396,21 +397,24 @@ 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+int mlx5_nl_flow_transpose(struct mlx5_nl_flow *nl_flow,\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+void mlx5_nl_flow_brand(struct mlx5_nl_flow *nl_flow, uint32_t handle);\n+int mlx5_nl_flow_create(struct mlx5_nl_flow_ctx *ctx,\n+\t\t\tstruct mlx5_nl_flow *nl_flow,\n \t\t\tstruct rte_flow_error *error);\n-int mlx5_nl_flow_destroy(struct mnl_socket *nl, void *buf,\n+int mlx5_nl_flow_destroy(struct mlx5_nl_flow_ctx *ctx,\n+\t\t\t struct mlx5_nl_flow *nl_flow,\n \t\t\t struct rte_flow_error *error);\n-int mlx5_nl_flow_ifindex_init(struct mnl_socket *nl, unsigned int ifindex,\n+int mlx5_nl_flow_ifindex_init(struct mlx5_nl_flow_ctx *ctx,\n+\t\t\t      unsigned int ifindex,\n \t\t\t      struct rte_flow_error *error);\n-struct mnl_socket *mlx5_nl_flow_socket_create(void);\n-void mlx5_nl_flow_socket_destroy(struct mnl_socket *nl);\n+struct mlx5_nl_flow_ctx *mlx5_nl_flow_ctx_create(int socket);\n+void mlx5_nl_flow_ctx_destroy(struct mlx5_nl_flow_ctx *ctx);\n \n #endif /* RTE_PMD_MLX5_H_ */\ndiff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c\nindex f093a5ed0..77e510dc3 100644\n--- a/drivers/net/mlx5/mlx5_flow.c\n+++ b/drivers/net/mlx5/mlx5_flow.c\n@@ -2485,7 +2485,7 @@ mlx5_flow_merge_switch(struct rte_eth_dev *dev,\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+\tret = mlx5_nl_flow_transpose((void *)((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@@ -2885,8 +2885,8 @@ mlx5_flow_remove(struct rte_eth_dev *dev, struct rte_flow *flow)\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+\tif (flow->nl_flow && priv->nl_flow_ctx)\n+\t\tmlx5_nl_flow_destroy(priv->nl_flow_ctx, 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@@ -2975,8 +2975,8 @@ mlx5_flow_apply(struct rte_eth_dev *dev, struct rte_flow *flow,\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    priv->nl_flow_ctx &&\n+\t    mlx5_nl_flow_create(priv->nl_flow_ctx, flow->nl_flow, error))\n \t\tgoto error;\n \treturn 0;\n error:\ndiff --git a/drivers/net/mlx5/mlx5_nl_flow.c b/drivers/net/mlx5/mlx5_nl_flow.c\nindex e720728b7..d20416026 100644\n--- a/drivers/net/mlx5/mlx5_nl_flow.c\n+++ b/drivers/net/mlx5/mlx5_nl_flow.c\n@@ -22,10 +22,10 @@\n #include <sys/socket.h>\n \n #include <rte_byteorder.h>\n-#include <rte_cycles.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_autoconf.h\"\n@@ -148,6 +148,23 @@ struct tc_vlan {\n #define TCA_FLOWER_KEY_VLAN_ETH_TYPE 25\n #endif\n \n+/** Context object required by most functions. */\n+struct mlx5_nl_flow_ctx {\n+\tint socket; /**< NUMA socket for memory allocations. */\n+\tuint32_t seq; /**< Message sequence number for @p nl. */\n+\tstruct mnl_socket *nl; /**< @p NETLINK_ROUTE libmnl socket. */\n+};\n+\n+/** Flow rule descriptor. */\n+struct mlx5_nl_flow {\n+\tuint32_t size; /**< Size of this object. */\n+\tuint32_t applied:1; /**< Whether rule is currently applied. */\n+\tunsigned int *ifindex_src; /**< Source interface. */\n+\tunsigned int *ifindex_dst; /**< Destination interface. */\n+\talignas(struct nlmsghdr)\n+\tuint8_t msg[]; /**< Netlink message data. */\n+};\n+\n /** Parser state definitions for mlx5_nl_flow_trans[]. */\n enum mlx5_nl_flow_trans {\n \tINVALID,\n@@ -350,10 +367,10 @@ mlx5_nl_flow_item_mask(const struct rte_flow_item *item,\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[out] nl_flow\n+ *   Output 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+ *   Size of @p nl_flow. 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@@ -372,7 +389,7 @@ mlx5_nl_flow_item_mask(const struct rte_flow_item *item,\n  *   otherwise and rte_errno is set.\n  */\n int\n-mlx5_nl_flow_transpose(void *buf,\n+mlx5_nl_flow_transpose(struct mlx5_nl_flow *nl_flow,\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@@ -380,8 +397,9 @@ mlx5_nl_flow_transpose(void *buf,\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+\talignas(struct mlx5_nl_flow)\n+\tuint8_t buf_tmp[1024];\n+\tvoid *buf;\n \tconst struct rte_flow_item *item;\n \tconst struct rte_flow_action *action;\n \tunsigned int n;\n@@ -398,9 +416,15 @@ mlx5_nl_flow_transpose(void *buf,\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+\tbuf = NULL;\n+\tif (size < offsetof(struct mlx5_nl_flow, msg))\n+\t\tgoto error_nobufs;\n+\tnl_flow->size = offsetof(struct mlx5_nl_flow, msg);\n+\tnl_flow->applied = 0;\n+\tnl_flow->ifindex_src = NULL;\n+\tnl_flow->ifindex_dst = NULL;\n+\tsize -= nl_flow->size;\n \titem = pattern;\n \taction = actions;\n \tn = 0;\n@@ -483,15 +507,21 @@ mlx5_nl_flow_transpose(void *buf,\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\ti = RTE_ALIGN_CEIL(nl_flow->size, alignof(struct nlmsghdr));\n+\t\ti -= nl_flow->size;\n+\t\tif (size < i + mnl_nlmsg_size(sizeof(*tcm)))\n \t\t\tgoto error_nobufs;\n+\t\tnl_flow->size += i;\n+\t\tbuf = (void *)((uintptr_t)nl_flow + nl_flow->size);\n+\t\tsize -= i;\n \t\tnlh = mnl_nlmsg_put_header(buf);\n-\t\tnlh->nlmsg_type = 0;\n+\t\tnlh->nlmsg_type = RTM_NEWTFILTER;\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\tnl_flow->ifindex_src = (unsigned int *)&tcm->tcm_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@@ -893,6 +923,10 @@ mlx5_nl_flow_transpose(void *buf,\n \t\tact = mnl_attr_nest_start_check(buf, size, TCA_ACT_OPTIONS);\n \t\tif (!act)\n \t\t\tgoto error_nobufs;\n+\t\tnl_flow->ifindex_dst =\n+\t\t\t&((struct tc_mirred *)\n+\t\t\t  mnl_attr_get_payload\n+\t\t\t  (mnl_nlmsg_get_payload_tail(buf)))->ifindex;\n \t\tif (!mnl_attr_put_check(buf, size, TCA_MIRRED_PARMS,\n \t\t\t\t\tsizeof(struct tc_mirred),\n \t\t\t\t\t&(struct tc_mirred){\n@@ -1014,15 +1048,18 @@ mlx5_nl_flow_transpose(void *buf,\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\tbuf = NULL;\n+\t\tsize -= nlh->nlmsg_len;\n+\t\tnl_flow->size += nlh->nlmsg_len;\n+\t\treturn nl_flow->size;\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+\tif (nl_flow != (void *)buf_tmp) {\n+\t\tnl_flow = (void *)buf_tmp;\n \t\tsize = sizeof(buf_tmp);\n \t\tgoto init;\n \t}\n@@ -1037,14 +1074,15 @@ mlx5_nl_flow_transpose(void *buf,\n  * This handle should be unique for a given network interface to avoid\n  * collisions.\n  *\n- * @param buf\n+ * @param nl_flow\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+mlx5_nl_flow_brand(struct mlx5_nl_flow *nl_flow, uint32_t handle)\n {\n+\tvoid *buf = nl_flow->msg;\n \tstruct tcmsg *tcm = mnl_nlmsg_get_payload(buf);\n \n \ttcm->tcm_handle = handle;\n@@ -1053,8 +1091,8 @@ mlx5_nl_flow_brand(void *buf, uint32_t handle)\n /**\n  * Send Netlink message with acknowledgment and process reply.\n  *\n- * @param nl\n- *   Libmnl socket to use.\n+ * @param ctx\n+ *   Context object initialized by mlx5_nl_flow_ctx_create().\n  * @param nlh\n  *   Message to send. This function always raises the NLM_F_ACK flag and\n  *   sets its sequence number before sending.\n@@ -1067,26 +1105,26 @@ mlx5_nl_flow_brand(void *buf, uint32_t handle)\n  *   0 on success, a negative errno value otherwise and rte_errno is set.\n  */\n static int\n-mlx5_nl_flow_chat(struct mnl_socket *nl, struct nlmsghdr *nlh,\n+mlx5_nl_flow_chat(struct mlx5_nl_flow_ctx *ctx, struct nlmsghdr *nlh,\n \t\t  mnl_cb_t cb, void *arg)\n {\n \talignas(struct nlmsghdr)\n \tuint8_t ans[MNL_SOCKET_BUFFER_SIZE];\n-\tunsigned int portid = mnl_socket_get_portid(nl);\n-\tuint32_t seq = rte_get_tsc_cycles();\n+\tunsigned int portid = mnl_socket_get_portid(ctx->nl);\n+\tuint32_t seq = ++ctx->seq ? ctx->seq : ++ctx->seq;\n \tint err = 0;\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+\tret = mnl_socket_sendto(ctx->nl, nlh, nlh->nlmsg_len);\n \tnlh = (void *)ans;\n \t/*\n \t * The following loop postpones non-fatal errors until multipart\n \t * messages are complete.\n \t */\n \twhile (ret > 0) {\n-\t\tret = mnl_socket_recvfrom(nl, ans, sizeof(ans));\n+\t\tret = mnl_socket_recvfrom(ctx->nl, ans, sizeof(ans));\n \t\tif (ret == -1) {\n \t\t\terr = errno;\n \t\t\tif (err != ENOSPC)\n@@ -1113,9 +1151,9 @@ mlx5_nl_flow_chat(struct mnl_socket *nl, struct nlmsghdr *nlh,\n /**\n  * Create a Netlink flow rule.\n  *\n- * @param nl\n- *   Libmnl socket to use.\n- * @param buf\n+ * @param ctx\n+ *   Context object initialized by mlx5_nl_flow_ctx_create().\n+ * @param nl_flow\n  *   Flow rule buffer previously initialized by mlx5_nl_flow_transpose().\n  * @param[out] error\n  *   Perform verbose error reporting if not NULL.\n@@ -1124,15 +1162,19 @@ mlx5_nl_flow_chat(struct mnl_socket *nl, struct nlmsghdr *nlh,\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+mlx5_nl_flow_create(struct mlx5_nl_flow_ctx *ctx, struct mlx5_nl_flow *nl_flow,\n \t\t    struct rte_flow_error *error)\n {\n-\tstruct nlmsghdr *nlh = buf;\n+\tstruct nlmsghdr *nlh = (void *)nl_flow->msg;\n \n+\tif (nl_flow->applied)\n+\t\treturn 0;\n \tnlh->nlmsg_type = RTM_NEWTFILTER;\n \tnlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;\n-\tif (!mlx5_nl_flow_chat(nl, nlh, NULL, NULL))\n+\tif (!mlx5_nl_flow_chat(ctx, nlh, NULL, NULL)) {\n+\t\tnl_flow->applied = 1;\n \t\treturn 0;\n+\t}\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@@ -1141,9 +1183,12 @@ mlx5_nl_flow_create(struct mnl_socket *nl, void *buf,\n /**\n  * Destroy a Netlink flow rule.\n  *\n- * @param nl\n- *   Libmnl socket to use.\n- * @param buf\n+ * In case of error, no recovery is possible; caller must suppose flow rule\n+ * was destroyed.\n+ *\n+ * @param ctx\n+ *   Context object initialized by mlx5_nl_flow_ctx_create().\n+ * @param nl_flow\n  *   Flow rule buffer previously initialized by mlx5_nl_flow_transpose().\n  * @param[out] error\n  *   Perform verbose error reporting if not NULL.\n@@ -1152,26 +1197,31 @@ mlx5_nl_flow_create(struct mnl_socket *nl, void *buf,\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+mlx5_nl_flow_destroy(struct mlx5_nl_flow_ctx *ctx, struct mlx5_nl_flow *nl_flow,\n \t\t     struct rte_flow_error *error)\n {\n-\tstruct nlmsghdr *nlh = buf;\n+\tstruct nlmsghdr *nlh = (void *)nl_flow->msg;\n+\tint ret;\n \n+\tif (!nl_flow->applied)\n+\t\treturn 0;\n \tnlh->nlmsg_type = RTM_DELTFILTER;\n \tnlh->nlmsg_flags = NLM_F_REQUEST;\n-\tif (!mlx5_nl_flow_chat(nl, nlh, NULL, NULL))\n+\tret = mlx5_nl_flow_chat(ctx, nlh, NULL, NULL);\n+\tnl_flow->applied = 0;\n+\tif (!ret)\n \t\treturn 0;\n \treturn rte_flow_error_set\n-\t\t(error, errno, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t(error, rte_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+ * Initialize ingress qdisc of network interfaces.\n  *\n- * @param nl\n- *   Libmnl socket of the @p NETLINK_ROUTE kind.\n- * @param ifindex\n+ * @param ctx\n+ *   Context object initialized by mlx5_nl_flow_ctx_create().\n+ * @param[in] ifindex\n  *   Index of network interface to initialize.\n  * @param[out] error\n  *   Perform verbose error reporting if not NULL.\n@@ -1180,7 +1230,8 @@ mlx5_nl_flow_destroy(struct mnl_socket *nl, void *buf,\n  *   0 on success, a negative errno value otherwise and rte_errno is set.\n  */\n int\n-mlx5_nl_flow_ifindex_init(struct mnl_socket *nl, unsigned int ifindex,\n+mlx5_nl_flow_ifindex_init(struct mlx5_nl_flow_ctx *ctx,\n+\t\t\t  const unsigned int ifindex,\n \t\t\t  struct rte_flow_error *error)\n {\n \tstruct nlmsghdr *nlh;\n@@ -1202,15 +1253,15 @@ mlx5_nl_flow_ifindex_init(struct mnl_socket *nl, unsigned int ifindex,\n \t\t\t(error, ENOBUFS, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,\n \t\t\t NULL, \"netlink: not enough space for message\");\n \t/* Ignore errors when qdisc is already absent. */\n-\tif (mlx5_nl_flow_chat(nl, nlh, NULL, NULL) &&\n-\t    rte_errno != EINVAL && rte_errno != ENOENT)\n+\tif (mlx5_nl_flow_chat(ctx, nlh, NULL, NULL) &&\n+\t    rte_errno != EINVAL && rte_errno != ENOENT && rte_errno != EPERM)\n \t\treturn rte_flow_error_set\n \t\t\t(error, rte_errno, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,\n \t\t\t NULL, \"netlink: failed to remove ingress qdisc\");\n \t/* Create fresh ingress qdisc. */\n \tnlh->nlmsg_type = RTM_NEWQDISC;\n \tnlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;\n-\tif (mlx5_nl_flow_chat(nl, nlh, NULL, NULL))\n+\tif (mlx5_nl_flow_chat(ctx, nlh, NULL, NULL))\n \t\treturn rte_flow_error_set\n \t\t\t(error, rte_errno, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,\n \t\t\t NULL, \"netlink: failed to create ingress qdisc\");\n@@ -1218,34 +1269,50 @@ mlx5_nl_flow_ifindex_init(struct mnl_socket *nl, unsigned int ifindex,\n }\n \n /**\n- * Create and configure a libmnl socket for Netlink flow rules.\n+ * Create NL flow rule context object.\n  *\n+ * @param socket\n+ *   NUMA socket for memory allocations.\n  * @return\n- *   A valid libmnl socket object pointer on success, NULL otherwise and\n- *   rte_errno is set.\n+ *   A valid object on success, NULL otherwise and rte_errno is set.\n  */\n-struct mnl_socket *\n-mlx5_nl_flow_socket_create(void)\n+struct mlx5_nl_flow_ctx *\n+mlx5_nl_flow_ctx_create(int socket)\n {\n-\tstruct mnl_socket *nl = mnl_socket_open(NETLINK_ROUTE);\n+\tstruct mlx5_nl_flow_ctx *ctx =\n+\t\trte_zmalloc_socket(__func__, sizeof(*ctx), 0, socket);\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+\tif (!ctx)\n+\t\tgoto error;\n+\tctx->socket = socket;\n+\tctx->seq = 0;\n+\tctx->nl = mnl_socket_open(NETLINK_ROUTE);\n+\tif (!ctx->nl)\n+\t\tgoto error;\n+\tmnl_socket_setsockopt(ctx->nl, NETLINK_CAP_ACK, &(int){ 1 },\n+\t\t\t      sizeof(int));\n+\tif (mnl_socket_bind(ctx->nl, 0, MNL_SOCKET_AUTOPID))\n+\t\tgoto error;\n+\treturn ctx;\n+error:\n \trte_errno = errno;\n-\tif (nl)\n-\t\tmnl_socket_close(nl);\n+\tif (ctx) {\n+\t\tif (ctx->nl)\n+\t\t\tmnl_socket_close(ctx->nl);\n+\t\trte_free(ctx);\n+\t}\n \treturn NULL;\n }\n \n /**\n- * Destroy a libmnl socket.\n+ * Destroy NL flow rule context object.\n+ *\n+ * @param ctx\n+ *   Context object initialized by mlx5_nl_flow_ctx_create().\n  */\n void\n-mlx5_nl_flow_socket_destroy(struct mnl_socket *nl)\n+mlx5_nl_flow_ctx_destroy(struct mlx5_nl_flow_ctx *ctx)\n {\n-\tmnl_socket_close(nl);\n+\tmnl_socket_close(ctx->nl);\n+\trte_free(ctx);\n }\n",
    "prefixes": [
        "5/8"
    ]
}