From patchwork Fri Aug 31 09:57:36 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adrien Mazarguil X-Patchwork-Id: 44085 Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id C4DF95323; Fri, 31 Aug 2018 11:57:55 +0200 (CEST) Received: from mail-wm0-f65.google.com (mail-wm0-f65.google.com [74.125.82.65]) by dpdk.org (Postfix) with ESMTP id 2A9A74F94 for ; Fri, 31 Aug 2018 11:57:53 +0200 (CEST) Received: by mail-wm0-f65.google.com with SMTP id 207-v6so4724416wme.5 for ; Fri, 31 Aug 2018 02:57:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=6wind-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to; bh=TL/XY9FSh42gEPQu3TfCqY700L5VIdTyt0SYhjHhF54=; b=hKFjB3qx9EcPc9TvrZK6TpiPEtMopxVmIPUQcEbIwMtzCoQHS4eMoF7uJAHMNGd+0q F8GrBKkeBKHORTA6LxwyGa0FJNSVzmfr5/tqUleVwwTL4cNiIXAdfCsVya7/ql2Qm3Hn qtmadJWWGpJnV6PNCWUgKFx4ZCPDTNCzesMPt2QbGYbQ6iqYHN/K0lqFc7EacK5fuhuo jfHy5vHg1w6RYCt3LnBn+mlMbtzF9S8JRqjlM47VlTZtyzP4KPV9COaCQ0VkK+byOdwY hlT9XCeLIYACUMVJ52hoa+MM210+mcxVDhACciYPnLi7+2wwsctJt0m77ZeURlBahfs6 UNrQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=TL/XY9FSh42gEPQu3TfCqY700L5VIdTyt0SYhjHhF54=; b=NmB1bdabuPvUhy1AgrarfNZveIZ5rE7qK5b26rGRV3OC/CS1Yg09L4ib0jzBT60CjD yUsq2kwxnlBOGvgU1Y5FbYCst3UYvn/WDSn3C12xMICuVs6ECJvKPxB/33DOKOHnNXHH 2D+HlfXlvhS3rCnMq3QTGOWeqCZIxrJoDZC6Dt6/FV6jugQX894DP9EbnjIZnb6KoJTb sJ1K6AxHd3WfgZSzVmkiFqoIo38ay/+x/U5xy+gBv+aqGipc/stRm9koO0H25c3Sv4ZR zlkha3ORxdRFdM4B8Z53476xUk/mUeVo8vLGMAtxpUxxsFvDqAG4rmSkHCVjfVilSygG uhYQ== X-Gm-Message-State: APzg51CrYzYbBYVSFhKytBwdcccYC8ugg2+oLFHzVgAScBSISilQpGTJ m6HQRyPDftrcs4O2ytGTIxQjyg== X-Google-Smtp-Source: ANB0Vda1vu/biWbWeGybReoCokGvj8nIhp/1ql1aMBwacN+STiDicH40N15+yAc3Bh/wyCvtA9zrFg== X-Received: by 2002:a1c:adcc:: with SMTP id w195-v6mr4403101wme.41.1535709472572; Fri, 31 Aug 2018 02:57:52 -0700 (PDT) Received: from 6wind.com (host.78.145.23.62.rev.coltfrance.com. [62.23.145.78]) by smtp.gmail.com with ESMTPSA id b2-v6sm3568001wmh.3.2018.08.31.02.57.51 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 31 Aug 2018 02:57:51 -0700 (PDT) Date: Fri, 31 Aug 2018 11:57:36 +0200 From: Adrien Mazarguil To: Shahaf Shuler , Yongseok Koh , Slava Ovsiienko Cc: dev@dpdk.org Message-ID: <20180831092038.23051-6-adrien.mazarguil@6wind.com> References: <20180831092038.23051-1-adrien.mazarguil@6wind.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20180831092038.23051-1-adrien.mazarguil@6wind.com> X-Mailer: git-send-email 2.11.0 Subject: [dpdk-dev] [PATCH 5/8] net/mlx5: prepare switch flow rule parser for encap offloads X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" A mere message buffer is not enough to support the additional logic required to manage flow rules with such offloads; a dedicated object (struct mlx5_nl_flow) with the ability to store additional information and adjustable target network interfaces is needed, as well as a context object for shared data (struct mlx5_nl_flow_ctx). A predictable message sequence number can now be stored in the context object as an improvement over CPU counters. Signed-off-by: Adrien Mazarguil --- drivers/net/mlx5/mlx5.c | 18 ++-- drivers/net/mlx5/mlx5.h | 22 ++-- drivers/net/mlx5/mlx5_flow.c | 10 +- drivers/net/mlx5/mlx5_nl_flow.c | 189 ++++++++++++++++++++++++----------- 4 files changed, 155 insertions(+), 84 deletions(-) diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c index 9a504a31c..c10ca4ae5 100644 --- a/drivers/net/mlx5/mlx5.c +++ b/drivers/net/mlx5/mlx5.c @@ -282,8 +282,8 @@ mlx5_dev_close(struct rte_eth_dev *dev) close(priv->nl_socket_route); if (priv->nl_socket_rdma >= 0) close(priv->nl_socket_rdma); - if (priv->mnl_socket) - mlx5_nl_flow_socket_destroy(priv->mnl_socket); + if (priv->nl_flow_ctx) + mlx5_nl_flow_ctx_destroy(priv->nl_flow_ctx); ret = mlx5_hrxq_ibv_verify(dev); if (ret) DRV_LOG(WARNING, "port %u some hash Rx queue still remain", @@ -1136,13 +1136,13 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, claim_zero(mlx5_mac_addr_add(eth_dev, &mac, 0, 0)); if (vf && config.vf_nl_en) mlx5_nl_mac_addr_sync(eth_dev); - priv->mnl_socket = mlx5_nl_flow_socket_create(); - if (!priv->mnl_socket || + priv->nl_flow_ctx = mlx5_nl_flow_ctx_create(eth_dev->device->numa_node); + if (!priv->nl_flow_ctx || !priv->ifindex || - mlx5_nl_flow_ifindex_init(priv->mnl_socket, priv->ifindex, + mlx5_nl_flow_ifindex_init(priv->nl_flow_ctx, priv->ifindex, &flow_error)) { - if (!priv->mnl_socket) { - flow_error.message = "cannot open libmnl socket"; + if (!priv->nl_flow_ctx) { + flow_error.message = "cannot create NL flow context"; } else if (!priv->ifindex) { rte_errno = ENXIO; flow_error.message = "unknown network interface index"; @@ -1204,8 +1204,8 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, close(priv->nl_socket_route); if (priv->nl_socket_rdma >= 0) close(priv->nl_socket_rdma); - if (priv->mnl_socket) - mlx5_nl_flow_socket_destroy(priv->mnl_socket); + if (priv->nl_flow_ctx) + mlx5_nl_flow_ctx_destroy(priv->nl_flow_ctx); if (own_domain_id) claim_zero(rte_eth_switch_domain_free(priv->domain_id)); rte_free(priv); diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index 287cfc643..210f4ea11 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -162,7 +162,8 @@ struct mlx5_nl_flow_ptoi { unsigned int ifindex; /**< Network interface index. */ }; -struct mnl_socket; +struct mlx5_nl_flow; +struct mlx5_nl_flow_ctx; struct priv { LIST_ENTRY(priv) mem_event_cb; /* Called by memory event callback. */ @@ -229,7 +230,7 @@ struct priv { rte_spinlock_t uar_lock[MLX5_UAR_PAGE_NUM_MAX]; /* UAR same-page access control required in 32bit implementations. */ #endif - struct mnl_socket *mnl_socket; /* Libmnl socket. */ + struct mlx5_nl_flow_ctx *nl_flow_ctx; /* Context for NL flow rules. */ }; #define PORT_ID(priv) ((priv)->dev_data->port_id) @@ -396,21 +397,24 @@ int mlx5_nl_switch_info(int nl, unsigned int ifindex, /* mlx5_nl_flow.c */ -int mlx5_nl_flow_transpose(void *buf, +int mlx5_nl_flow_transpose(struct mlx5_nl_flow *nl_flow, size_t size, const struct mlx5_nl_flow_ptoi *ptoi, const struct rte_flow_attr *attr, const struct rte_flow_item *pattern, const struct rte_flow_action *actions, struct rte_flow_error *error); -void mlx5_nl_flow_brand(void *buf, uint32_t handle); -int mlx5_nl_flow_create(struct mnl_socket *nl, void *buf, +void mlx5_nl_flow_brand(struct mlx5_nl_flow *nl_flow, uint32_t handle); +int mlx5_nl_flow_create(struct mlx5_nl_flow_ctx *ctx, + struct mlx5_nl_flow *nl_flow, struct rte_flow_error *error); -int mlx5_nl_flow_destroy(struct mnl_socket *nl, void *buf, +int mlx5_nl_flow_destroy(struct mlx5_nl_flow_ctx *ctx, + struct mlx5_nl_flow *nl_flow, struct rte_flow_error *error); -int mlx5_nl_flow_ifindex_init(struct mnl_socket *nl, unsigned int ifindex, +int mlx5_nl_flow_ifindex_init(struct mlx5_nl_flow_ctx *ctx, + unsigned int ifindex, struct rte_flow_error *error); -struct mnl_socket *mlx5_nl_flow_socket_create(void); -void mlx5_nl_flow_socket_destroy(struct mnl_socket *nl); +struct mlx5_nl_flow_ctx *mlx5_nl_flow_ctx_create(int socket); +void mlx5_nl_flow_ctx_destroy(struct mlx5_nl_flow_ctx *ctx); #endif /* RTE_PMD_MLX5_H_ */ diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index f093a5ed0..77e510dc3 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -2485,7 +2485,7 @@ mlx5_flow_merge_switch(struct rte_eth_dev *dev, ptoi[n].ifindex = 0; if (flow_size < off) flow_size = 0; - ret = mlx5_nl_flow_transpose((uint8_t *)flow + off, + ret = mlx5_nl_flow_transpose((void *)((uint8_t *)flow + off), flow_size ? flow_size - off : 0, ptoi, attr, pattern, actions, error); if (ret < 0) @@ -2885,8 +2885,8 @@ mlx5_flow_remove(struct rte_eth_dev *dev, struct rte_flow *flow) struct priv *priv = dev->data->dev_private; struct mlx5_flow_verbs *verbs; - if (flow->nl_flow && priv->mnl_socket) - mlx5_nl_flow_destroy(priv->mnl_socket, flow->nl_flow, NULL); + if (flow->nl_flow && priv->nl_flow_ctx) + mlx5_nl_flow_destroy(priv->nl_flow_ctx, flow->nl_flow, NULL); LIST_FOREACH(verbs, &flow->verbs, next) { if (verbs->flow) { claim_zero(mlx5_glue->destroy_flow(verbs->flow)); @@ -2975,8 +2975,8 @@ mlx5_flow_apply(struct rte_eth_dev *dev, struct rte_flow *flow, } } if (flow->nl_flow && - priv->mnl_socket && - mlx5_nl_flow_create(priv->mnl_socket, flow->nl_flow, error)) + priv->nl_flow_ctx && + mlx5_nl_flow_create(priv->nl_flow_ctx, flow->nl_flow, error)) goto error; return 0; error: diff --git a/drivers/net/mlx5/mlx5_nl_flow.c b/drivers/net/mlx5/mlx5_nl_flow.c index e720728b7..d20416026 100644 --- a/drivers/net/mlx5/mlx5_nl_flow.c +++ b/drivers/net/mlx5/mlx5_nl_flow.c @@ -22,10 +22,10 @@ #include #include -#include #include #include #include +#include #include "mlx5.h" #include "mlx5_autoconf.h" @@ -148,6 +148,23 @@ struct tc_vlan { #define TCA_FLOWER_KEY_VLAN_ETH_TYPE 25 #endif +/** Context object required by most functions. */ +struct mlx5_nl_flow_ctx { + int socket; /**< NUMA socket for memory allocations. */ + uint32_t seq; /**< Message sequence number for @p nl. */ + struct mnl_socket *nl; /**< @p NETLINK_ROUTE libmnl socket. */ +}; + +/** Flow rule descriptor. */ +struct mlx5_nl_flow { + uint32_t size; /**< Size of this object. */ + uint32_t applied:1; /**< Whether rule is currently applied. */ + unsigned int *ifindex_src; /**< Source interface. */ + unsigned int *ifindex_dst; /**< Destination interface. */ + alignas(struct nlmsghdr) + uint8_t msg[]; /**< Netlink message data. */ +}; + /** Parser state definitions for mlx5_nl_flow_trans[]. */ enum mlx5_nl_flow_trans { INVALID, @@ -350,10 +367,10 @@ mlx5_nl_flow_item_mask(const struct rte_flow_item *item, * Subsequent entries enable this function to resolve other DPDK port IDs * found in the flow rule. * - * @param[out] buf - * Output message buffer. May be NULL when @p size is 0. + * @param[out] nl_flow + * Output buffer. May be NULL when @p size is 0. * @param size - * Size of @p buf. Message may be truncated if not large enough. + * Size of @p nl_flow. May be truncated if not large enough. * @param[in] ptoi * DPDK port ID to network interface index translation table. This table * is terminated by an entry with a zero ifindex value. @@ -372,7 +389,7 @@ mlx5_nl_flow_item_mask(const struct rte_flow_item *item, * otherwise and rte_errno is set. */ int -mlx5_nl_flow_transpose(void *buf, +mlx5_nl_flow_transpose(struct mlx5_nl_flow *nl_flow, size_t size, const struct mlx5_nl_flow_ptoi *ptoi, const struct rte_flow_attr *attr, @@ -380,8 +397,9 @@ mlx5_nl_flow_transpose(void *buf, const struct rte_flow_action *actions, struct rte_flow_error *error) { - alignas(struct nlmsghdr) - uint8_t buf_tmp[mnl_nlmsg_size(sizeof(struct tcmsg) + 1024)]; + alignas(struct mlx5_nl_flow) + uint8_t buf_tmp[1024]; + void *buf; const struct rte_flow_item *item; const struct rte_flow_action *action; unsigned int n; @@ -398,9 +416,15 @@ mlx5_nl_flow_transpose(void *buf, const enum mlx5_nl_flow_trans *trans; const enum mlx5_nl_flow_trans *back; - if (!size) - goto error_nobufs; init: + buf = NULL; + if (size < offsetof(struct mlx5_nl_flow, msg)) + goto error_nobufs; + nl_flow->size = offsetof(struct mlx5_nl_flow, msg); + nl_flow->applied = 0; + nl_flow->ifindex_src = NULL; + nl_flow->ifindex_dst = NULL; + size -= nl_flow->size; item = pattern; action = actions; n = 0; @@ -483,15 +507,21 @@ mlx5_nl_flow_transpose(void *buf, (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, attr, "egress is not supported"); - if (size < mnl_nlmsg_size(sizeof(*tcm))) + i = RTE_ALIGN_CEIL(nl_flow->size, alignof(struct nlmsghdr)); + i -= nl_flow->size; + if (size < i + mnl_nlmsg_size(sizeof(*tcm))) goto error_nobufs; + nl_flow->size += i; + buf = (void *)((uintptr_t)nl_flow + nl_flow->size); + size -= i; nlh = mnl_nlmsg_put_header(buf); - nlh->nlmsg_type = 0; + nlh->nlmsg_type = RTM_NEWTFILTER; nlh->nlmsg_flags = 0; nlh->nlmsg_seq = 0; tcm = mnl_nlmsg_put_extra_header(nlh, sizeof(*tcm)); tcm->tcm_family = AF_UNSPEC; tcm->tcm_ifindex = ptoi[0].ifindex; + nl_flow->ifindex_src = (unsigned int *)&tcm->tcm_ifindex; /* * Let kernel pick a handle by default. A predictable handle * can be set by the caller on the resulting buffer through @@ -893,6 +923,10 @@ mlx5_nl_flow_transpose(void *buf, act = mnl_attr_nest_start_check(buf, size, TCA_ACT_OPTIONS); if (!act) goto error_nobufs; + nl_flow->ifindex_dst = + &((struct tc_mirred *) + mnl_attr_get_payload + (mnl_nlmsg_get_payload_tail(buf)))->ifindex; if (!mnl_attr_put_check(buf, size, TCA_MIRRED_PARMS, sizeof(struct tc_mirred), &(struct tc_mirred){ @@ -1014,15 +1048,18 @@ mlx5_nl_flow_transpose(void *buf, if (na_flower) mnl_attr_nest_end(buf, na_flower); nlh = buf; - return nlh->nlmsg_len; + buf = NULL; + size -= nlh->nlmsg_len; + nl_flow->size += nlh->nlmsg_len; + return nl_flow->size; } back = trans; trans = mlx5_nl_flow_trans[trans[n - 1]]; n = 0; goto trans; error_nobufs: - if (buf != buf_tmp) { - buf = buf_tmp; + if (nl_flow != (void *)buf_tmp) { + nl_flow = (void *)buf_tmp; size = sizeof(buf_tmp); goto init; } @@ -1037,14 +1074,15 @@ mlx5_nl_flow_transpose(void *buf, * This handle should be unique for a given network interface to avoid * collisions. * - * @param buf + * @param nl_flow * Flow rule buffer previously initialized by mlx5_nl_flow_transpose(). * @param handle * Unique 32-bit handle to use. */ void -mlx5_nl_flow_brand(void *buf, uint32_t handle) +mlx5_nl_flow_brand(struct mlx5_nl_flow *nl_flow, uint32_t handle) { + void *buf = nl_flow->msg; struct tcmsg *tcm = mnl_nlmsg_get_payload(buf); tcm->tcm_handle = handle; @@ -1053,8 +1091,8 @@ mlx5_nl_flow_brand(void *buf, uint32_t handle) /** * Send Netlink message with acknowledgment and process reply. * - * @param nl - * Libmnl socket to use. + * @param ctx + * Context object initialized by mlx5_nl_flow_ctx_create(). * @param nlh * Message to send. This function always raises the NLM_F_ACK flag and * sets its sequence number before sending. @@ -1067,26 +1105,26 @@ mlx5_nl_flow_brand(void *buf, uint32_t handle) * 0 on success, a negative errno value otherwise and rte_errno is set. */ static int -mlx5_nl_flow_chat(struct mnl_socket *nl, struct nlmsghdr *nlh, +mlx5_nl_flow_chat(struct mlx5_nl_flow_ctx *ctx, struct nlmsghdr *nlh, mnl_cb_t cb, void *arg) { alignas(struct nlmsghdr) uint8_t ans[MNL_SOCKET_BUFFER_SIZE]; - unsigned int portid = mnl_socket_get_portid(nl); - uint32_t seq = rte_get_tsc_cycles(); + unsigned int portid = mnl_socket_get_portid(ctx->nl); + uint32_t seq = ++ctx->seq ? ctx->seq : ++ctx->seq; int err = 0; int ret; nlh->nlmsg_flags |= NLM_F_ACK; nlh->nlmsg_seq = seq; - ret = mnl_socket_sendto(nl, nlh, nlh->nlmsg_len); + ret = mnl_socket_sendto(ctx->nl, nlh, nlh->nlmsg_len); nlh = (void *)ans; /* * The following loop postpones non-fatal errors until multipart * messages are complete. */ while (ret > 0) { - ret = mnl_socket_recvfrom(nl, ans, sizeof(ans)); + ret = mnl_socket_recvfrom(ctx->nl, ans, sizeof(ans)); if (ret == -1) { err = errno; if (err != ENOSPC) @@ -1113,9 +1151,9 @@ mlx5_nl_flow_chat(struct mnl_socket *nl, struct nlmsghdr *nlh, /** * Create a Netlink flow rule. * - * @param nl - * Libmnl socket to use. - * @param buf + * @param ctx + * Context object initialized by mlx5_nl_flow_ctx_create(). + * @param nl_flow * Flow rule buffer previously initialized by mlx5_nl_flow_transpose(). * @param[out] error * Perform verbose error reporting if not NULL. @@ -1124,15 +1162,19 @@ mlx5_nl_flow_chat(struct mnl_socket *nl, struct nlmsghdr *nlh, * 0 on success, a negative errno value otherwise and rte_errno is set. */ int -mlx5_nl_flow_create(struct mnl_socket *nl, void *buf, +mlx5_nl_flow_create(struct mlx5_nl_flow_ctx *ctx, struct mlx5_nl_flow *nl_flow, struct rte_flow_error *error) { - struct nlmsghdr *nlh = buf; + struct nlmsghdr *nlh = (void *)nl_flow->msg; + if (nl_flow->applied) + return 0; nlh->nlmsg_type = RTM_NEWTFILTER; nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; - if (!mlx5_nl_flow_chat(nl, nlh, NULL, NULL)) + if (!mlx5_nl_flow_chat(ctx, nlh, NULL, NULL)) { + nl_flow->applied = 1; return 0; + } return rte_flow_error_set (error, rte_errno, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "netlink: failed to create TC flow rule"); @@ -1141,9 +1183,12 @@ mlx5_nl_flow_create(struct mnl_socket *nl, void *buf, /** * Destroy a Netlink flow rule. * - * @param nl - * Libmnl socket to use. - * @param buf + * In case of error, no recovery is possible; caller must suppose flow rule + * was destroyed. + * + * @param ctx + * Context object initialized by mlx5_nl_flow_ctx_create(). + * @param nl_flow * Flow rule buffer previously initialized by mlx5_nl_flow_transpose(). * @param[out] error * Perform verbose error reporting if not NULL. @@ -1152,26 +1197,31 @@ mlx5_nl_flow_create(struct mnl_socket *nl, void *buf, * 0 on success, a negative errno value otherwise and rte_errno is set. */ int -mlx5_nl_flow_destroy(struct mnl_socket *nl, void *buf, +mlx5_nl_flow_destroy(struct mlx5_nl_flow_ctx *ctx, struct mlx5_nl_flow *nl_flow, struct rte_flow_error *error) { - struct nlmsghdr *nlh = buf; + struct nlmsghdr *nlh = (void *)nl_flow->msg; + int ret; + if (!nl_flow->applied) + return 0; nlh->nlmsg_type = RTM_DELTFILTER; nlh->nlmsg_flags = NLM_F_REQUEST; - if (!mlx5_nl_flow_chat(nl, nlh, NULL, NULL)) + ret = mlx5_nl_flow_chat(ctx, nlh, NULL, NULL); + nl_flow->applied = 0; + if (!ret) return 0; return rte_flow_error_set - (error, errno, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + (error, rte_errno, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "netlink: failed to destroy TC flow rule"); } /** - * Initialize ingress qdisc of a given network interface. + * Initialize ingress qdisc of network interfaces. * - * @param nl - * Libmnl socket of the @p NETLINK_ROUTE kind. - * @param ifindex + * @param ctx + * Context object initialized by mlx5_nl_flow_ctx_create(). + * @param[in] ifindex * Index of network interface to initialize. * @param[out] error * Perform verbose error reporting if not NULL. @@ -1180,7 +1230,8 @@ mlx5_nl_flow_destroy(struct mnl_socket *nl, void *buf, * 0 on success, a negative errno value otherwise and rte_errno is set. */ int -mlx5_nl_flow_ifindex_init(struct mnl_socket *nl, unsigned int ifindex, +mlx5_nl_flow_ifindex_init(struct mlx5_nl_flow_ctx *ctx, + const unsigned int ifindex, struct rte_flow_error *error) { struct nlmsghdr *nlh; @@ -1202,15 +1253,15 @@ mlx5_nl_flow_ifindex_init(struct mnl_socket *nl, unsigned int ifindex, (error, ENOBUFS, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "netlink: not enough space for message"); /* Ignore errors when qdisc is already absent. */ - if (mlx5_nl_flow_chat(nl, nlh, NULL, NULL) && - rte_errno != EINVAL && rte_errno != ENOENT) + if (mlx5_nl_flow_chat(ctx, nlh, NULL, NULL) && + rte_errno != EINVAL && rte_errno != ENOENT && rte_errno != EPERM) return rte_flow_error_set (error, rte_errno, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "netlink: failed to remove ingress qdisc"); /* Create fresh ingress qdisc. */ nlh->nlmsg_type = RTM_NEWQDISC; nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; - if (mlx5_nl_flow_chat(nl, nlh, NULL, NULL)) + if (mlx5_nl_flow_chat(ctx, nlh, NULL, NULL)) return rte_flow_error_set (error, rte_errno, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "netlink: failed to create ingress qdisc"); @@ -1218,34 +1269,50 @@ mlx5_nl_flow_ifindex_init(struct mnl_socket *nl, unsigned int ifindex, } /** - * Create and configure a libmnl socket for Netlink flow rules. + * Create NL flow rule context object. * + * @param socket + * NUMA socket for memory allocations. * @return - * A valid libmnl socket object pointer on success, NULL otherwise and - * rte_errno is set. + * A valid object on success, NULL otherwise and rte_errno is set. */ -struct mnl_socket * -mlx5_nl_flow_socket_create(void) +struct mlx5_nl_flow_ctx * +mlx5_nl_flow_ctx_create(int socket) { - struct mnl_socket *nl = mnl_socket_open(NETLINK_ROUTE); + struct mlx5_nl_flow_ctx *ctx = + rte_zmalloc_socket(__func__, sizeof(*ctx), 0, socket); - if (nl) { - mnl_socket_setsockopt(nl, NETLINK_CAP_ACK, &(int){ 1 }, - sizeof(int)); - if (!mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID)) - return nl; - } + if (!ctx) + goto error; + ctx->socket = socket; + ctx->seq = 0; + ctx->nl = mnl_socket_open(NETLINK_ROUTE); + if (!ctx->nl) + goto error; + mnl_socket_setsockopt(ctx->nl, NETLINK_CAP_ACK, &(int){ 1 }, + sizeof(int)); + if (mnl_socket_bind(ctx->nl, 0, MNL_SOCKET_AUTOPID)) + goto error; + return ctx; +error: rte_errno = errno; - if (nl) - mnl_socket_close(nl); + if (ctx) { + if (ctx->nl) + mnl_socket_close(ctx->nl); + rte_free(ctx); + } return NULL; } /** - * Destroy a libmnl socket. + * Destroy NL flow rule context object. + * + * @param ctx + * Context object initialized by mlx5_nl_flow_ctx_create(). */ void -mlx5_nl_flow_socket_destroy(struct mnl_socket *nl) +mlx5_nl_flow_ctx_destroy(struct mlx5_nl_flow_ctx *ctx) { - mnl_socket_close(nl); + mnl_socket_close(ctx->nl); + rte_free(ctx); }