From patchwork Mon Dec 19 15:41:30 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 13076723 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2D488C10F1B for ; Mon, 19 Dec 2022 15:42:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232336AbiLSPm1 (ORCPT ); Mon, 19 Dec 2022 10:42:27 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58004 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232283AbiLSPmZ (ORCPT ); Mon, 19 Dec 2022 10:42:25 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E58C712083; Mon, 19 Dec 2022 07:42:24 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 822D661019; Mon, 19 Dec 2022 15:42:24 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6B584C433D2; Mon, 19 Dec 2022 15:42:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1671464544; bh=Mko/GoxpYbPQ1yT5G9uVYi0KpQ+vihSNa+XLZtA91z0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=DWak3xIi05AKzNtr1WWLLzc+peZ8xZpm6TTgUPSynIjojSoqR750nA616UErlxrMB 29TTfEliPDLOb7UCT3DByW05KD308TRJKkoEPjTDIn5ZQFVYBNO7H/ldmle9XprNN9 YXNt6Qg4iIfJYRUTNdMEug0O29qAdHhhWjOs/c8sWrw/3uSyWcpvrWI17b8RW7BGP7 +nKefQxLm27DzZ+6CP6oV37Oim4bgzJYXAmDSHisW9EyKbhDkgqF7SYlMnKJGyWmd7 x0kmPXr6uNH1swEFCcqK0Ghvw+EojYHQcDJPu/sCuLGetZ+Mrv9hbGByNzFVHFMgNP sEZ+khaXZzPaQ== From: Lorenzo Bianconi To: bpf@vger.kernel.org Cc: netdev@vger.kernel.org, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, davem@davemloft.net, kuba@kernel.org, hawk@kernel.org, pabeni@redhat.com, edumazet@google.com, toke@redhat.com, memxor@gmail.com, alardam@gmail.com, saeedm@nvidia.com, anthony.l.nguyen@intel.com, gospo@broadcom.com, vladimir.oltean@nxp.com, nbd@nbd.name, john@phrozen.org, leon@kernel.org, simon.horman@corigine.com, aelior@marvell.com, christophe.jaillet@wanadoo.fr, ecree.xilinx@gmail.com, grygorii.strashko@ti.com, mst@redhat.com, bjorn@kernel.org, magnus.karlsson@intel.com, maciej.fijalkowski@intel.com, intel-wired-lan@lists.osuosl.org, lorenzo.bianconi@redhat.com Subject: [RFC bpf-next 1/8] tools: uapi: align if_link.h Date: Mon, 19 Dec 2022 16:41:30 +0100 Message-Id: X-Mailer: git-send-email 2.38.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC Align IFLA enum definitions in tools/include/uapi/linux/if_link.h to include/uapi/linux/if_link.h after the following commits: - '7e6e1b57162e ("rtnetlink: advertise allmulti counter")' - 'dca56c3038c3 ("net: expose devlink port over rtnetlink")' Signed-off-by: Lorenzo Bianconi --- tools/include/uapi/linux/if_link.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index 901d98b865a1..82fe18f26db5 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h @@ -350,6 +350,9 @@ enum { IFLA_GRO_MAX_SIZE, IFLA_TSO_MAX_SIZE, IFLA_TSO_MAX_SEGS, + IFLA_ALLMULTI, /* Allmulti count: > 0 means acts ALLMULTI */ + + IFLA_DEVLINK_PORT, __IFLA_MAX }; From patchwork Mon Dec 19 15:41:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 13076724 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6B2F9C10F1B for ; Mon, 19 Dec 2022 15:42:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232339AbiLSPmj (ORCPT ); Mon, 19 Dec 2022 10:42:39 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58060 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232351AbiLSPmc (ORCPT ); Mon, 19 Dec 2022 10:42:32 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C7AD59FCD; Mon, 19 Dec 2022 07:42:30 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 51EDEB80EA5; Mon, 19 Dec 2022 15:42:29 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6F9C3C433F0; Mon, 19 Dec 2022 15:42:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1671464548; bh=HiyPU/bfnqzxVK+tGHAHOccIB19x9zT4NEILwz8Mm0c=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mtAQH1tpWzxjn5x3fW7rmUaPBWthk+TQwtiPxQeHoMy8pTzQTLPN3REc/E9BBg31g ec3fA499dEoRHS9bEpWfjsYfRDBJt55G6KDbulSpFl4FTXJ+FsWYpQNTua+ut8E4P6 2Mg+/FmfAcqXKdp/e7zVoaM3fT2ZIw8ZonP2Pt8W7PQRm1GHq5F1wRVf6QyU1sgfel I+4Q58xuya30feiID4IqQkXKjEQoZVxxpq64BNgs+Mw+VycKPhfXeU2w/dFOIJ/eU/ rVNp0fHY3/PpvcqfDI8ReVtpjmGTg0c8kaRGd1bS9+5lAuEOovO++ame/kj6a2vcDB POOA0Q19EiXkA== From: Lorenzo Bianconi To: bpf@vger.kernel.org Cc: netdev@vger.kernel.org, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, davem@davemloft.net, kuba@kernel.org, hawk@kernel.org, pabeni@redhat.com, edumazet@google.com, toke@redhat.com, memxor@gmail.com, alardam@gmail.com, saeedm@nvidia.com, anthony.l.nguyen@intel.com, gospo@broadcom.com, vladimir.oltean@nxp.com, nbd@nbd.name, john@phrozen.org, leon@kernel.org, simon.horman@corigine.com, aelior@marvell.com, christophe.jaillet@wanadoo.fr, ecree.xilinx@gmail.com, grygorii.strashko@ti.com, mst@redhat.com, bjorn@kernel.org, magnus.karlsson@intel.com, maciej.fijalkowski@intel.com, intel-wired-lan@lists.osuosl.org, lorenzo.bianconi@redhat.com Subject: [RFC bpf-next 2/8] net: introduce XDP features flag Date: Mon, 19 Dec 2022 16:41:31 +0100 Message-Id: <43c340d440d8a87396198b301c5ffbf5ab56f304.1671462950.git.lorenzo@kernel.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC From: Marek Majtyka Implement support for checking what kind of XDP features a netdev supports. Previously, there was no way to do this other than to try to create an AF_XDP socket on the interface or load an XDP program and see if it worked. This commit changes this by adding a new variable which describes all xdp supported functions on pretty detailed level: - aborted - drop - pass - tx - redirect - sock_zerocopy - hw_offload - redirect_target - tx_lock - frag_rx - frag_target Zerocopy mode requires that redirect XDP operation is implemented in a driver and the driver supports also zero copy mode. Full mode requires that all XDP operation are implemented in the driver. Basic mode is just full mode without redirect operation. Frag target requires redirect_target one is supported by the driver. Initially, these new flags are disabled for all drivers by default. Co-developed-by: Kumar Kartikeya Dwivedi Signed-off-by: Kumar Kartikeya Dwivedi Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Marek Majtyka --- .../networking/netdev-xdp-features.rst | 60 +++++++++++++++++ include/linux/netdevice.h | 2 + include/linux/xdp_features.h | 64 +++++++++++++++++++ include/uapi/linux/if_link.h | 7 ++ include/uapi/linux/xdp_features.h | 34 ++++++++++ net/core/rtnetlink.c | 34 ++++++++++ tools/include/uapi/linux/if_link.h | 7 ++ tools/include/uapi/linux/xdp_features.h | 34 ++++++++++ 8 files changed, 242 insertions(+) create mode 100644 Documentation/networking/netdev-xdp-features.rst create mode 100644 include/linux/xdp_features.h create mode 100644 include/uapi/linux/xdp_features.h create mode 100644 tools/include/uapi/linux/xdp_features.h diff --git a/Documentation/networking/netdev-xdp-features.rst b/Documentation/networking/netdev-xdp-features.rst new file mode 100644 index 000000000000..1dc803fe72dd --- /dev/null +++ b/Documentation/networking/netdev-xdp-features.rst @@ -0,0 +1,60 @@ +.. SPDX-License-Identifier: GPL-2.0 + +===================== +Netdev XDP features +===================== + + * XDP FEATURES FLAGS + +Following netdev xdp features flags can be retrieved over route netlink +interface (compact form) - the same way as netdev feature flags. +These features flags are read only and cannot be change at runtime. + +* XDP_ABORTED + +This feature informs if netdev supports xdp aborted action. + +* XDP_DROP + +This feature informs if netdev supports xdp drop action. + +* XDP_PASS + +This feature informs if netdev supports xdp pass action. + +* XDP_TX + +This feature informs if netdev supports xdp tx action. + +* XDP_REDIRECT + +This feature informs if netdev supports xdp redirect action. +It assumes the all beforehand mentioned flags are enabled. + +* XDP_SOCK_ZEROCOPY + +This feature informs if netdev driver supports xdp zero copy. +It assumes the all beforehand mentioned flags are enabled. + +* XDP_HW_OFFLOAD + +This feature informs if netdev driver supports xdp hw oflloading. + +* XDP_TX_LOCK + +This feature informs if netdev ndo_xdp_xmit function requires locking. + +* XDP_REDIRECT_TARGET + +This feature informs if netdev implements ndo_xdp_xmit callback. + +* XDP_FRAG_RX + +This feature informs if netdev implements non-linear xdp buff support in +the driver napi callback. + +* XDP_FRAG_TARGET + +This feature informs if netdev implements non-linear xdp buff support in +ndo_xdp_xmit callback. XDP_FRAG_TARGET requires XDP_REDIRECT_TARGET is properly +supported. diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index aad12a179e54..ae5a8564383b 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -43,6 +43,7 @@ #include #include +#include #include #include #include @@ -2362,6 +2363,7 @@ struct net_device { struct rtnl_hw_stats64 *offload_xstats_l3; struct devlink_port *devlink_port; + xdp_features_t xdp_features; }; #define to_net_dev(d) container_of(d, struct net_device, dev) diff --git a/include/linux/xdp_features.h b/include/linux/xdp_features.h new file mode 100644 index 000000000000..4e72a86ef329 --- /dev/null +++ b/include/linux/xdp_features.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Network device xdp features. + */ +#ifndef _LINUX_XDP_FEATURES_H +#define _LINUX_XDP_FEATURES_H + +#include +#include +#include +#include + +typedef u32 xdp_features_t; + +#define __XDP_F_BIT(bit) ((xdp_features_t)1 << (bit)) +#define __XDP_F(name) __XDP_F_BIT(XDP_F_##name##_BIT) + +#define XDP_F_ABORTED __XDP_F(ABORTED) +#define XDP_F_DROP __XDP_F(DROP) +#define XDP_F_PASS __XDP_F(PASS) +#define XDP_F_TX __XDP_F(TX) +#define XDP_F_REDIRECT __XDP_F(REDIRECT) +#define XDP_F_REDIRECT_TARGET __XDP_F(REDIRECT_TARGET) +#define XDP_F_SOCK_ZEROCOPY __XDP_F(SOCK_ZEROCOPY) +#define XDP_F_HW_OFFLOAD __XDP_F(HW_OFFLOAD) +#define XDP_F_TX_LOCK __XDP_F(TX_LOCK) +#define XDP_F_FRAG_RX __XDP_F(FRAG_RX) +#define XDP_F_FRAG_TARGET __XDP_F(FRAG_TARGET) + +#define XDP_F_BASIC (XDP_F_ABORTED | XDP_F_DROP | \ + XDP_F_PASS | XDP_F_TX) + +#define XDP_F_FULL (XDP_F_BASIC | XDP_F_REDIRECT) + +#define XDP_F_FULL_ZC (XDP_F_FULL | XDP_F_SOCK_ZEROCOPY) + +#define XDP_FEATURES_ABORTED_STR "xdp-aborted" +#define XDP_FEATURES_DROP_STR "xdp-drop" +#define XDP_FEATURES_PASS_STR "xdp-pass" +#define XDP_FEATURES_TX_STR "xdp-tx" +#define XDP_FEATURES_REDIRECT_STR "xdp-redirect" +#define XDP_FEATURES_REDIRECT_TARGET_STR "xdp-redirect-target" +#define XDP_FEATURES_SOCK_ZEROCOPY_STR "xdp-sock-zerocopy" +#define XDP_FEATURES_HW_OFFLOAD_STR "xdp-hw-offload" +#define XDP_FEATURES_TX_LOCK_STR "xdp-tx-lock" +#define XDP_FEATURES_FRAG_RX_STR "xdp-frag-rx" +#define XDP_FEATURES_FRAG_TARGET_STR "xdp-frag-target" + +#define DECLARE_XDP_FEATURES_TABLE(name, length) \ + const char name[][length] = { \ + [XDP_F_ABORTED_BIT] = XDP_FEATURES_ABORTED_STR, \ + [XDP_F_DROP_BIT] = XDP_FEATURES_DROP_STR, \ + [XDP_F_PASS_BIT] = XDP_FEATURES_PASS_STR, \ + [XDP_F_TX_BIT] = XDP_FEATURES_TX_STR, \ + [XDP_F_REDIRECT_BIT] = XDP_FEATURES_REDIRECT_STR, \ + [XDP_F_REDIRECT_TARGET_BIT] = XDP_FEATURES_REDIRECT_TARGET_STR, \ + [XDP_F_SOCK_ZEROCOPY_BIT] = XDP_FEATURES_SOCK_ZEROCOPY_STR, \ + [XDP_F_HW_OFFLOAD_BIT] = XDP_FEATURES_HW_OFFLOAD_STR, \ + [XDP_F_TX_LOCK_BIT] = XDP_FEATURES_TX_LOCK_STR, \ + [XDP_F_FRAG_RX_BIT] = XDP_FEATURES_FRAG_RX_STR, \ + [XDP_F_FRAG_TARGET_BIT] = XDP_FEATURES_FRAG_TARGET_STR, \ + } + +#endif /* _LINUX_XDP_FEATURES_H */ diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 1021a7e47a86..971c658ceaea 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -374,6 +374,8 @@ enum { IFLA_DEVLINK_PORT, + IFLA_XDP_FEATURES, + __IFLA_MAX }; @@ -1318,6 +1320,11 @@ enum { #define IFLA_XDP_MAX (__IFLA_XDP_MAX - 1) +enum { + IFLA_XDP_FEATURES_WORD_UNSPEC = 0, + IFLA_XDP_FEATURES_BITS_WORD, +}; + enum { IFLA_EVENT_NONE, IFLA_EVENT_REBOOT, /* internal reset / reboot */ diff --git a/include/uapi/linux/xdp_features.h b/include/uapi/linux/xdp_features.h new file mode 100644 index 000000000000..48eb42069bcd --- /dev/null +++ b/include/uapi/linux/xdp_features.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (c) 2020 Intel + */ + +#ifndef __UAPI_LINUX_XDP_FEATURES__ +#define __UAPI_LINUX_XDP_FEATURES__ + +enum { + XDP_F_ABORTED_BIT, + XDP_F_DROP_BIT, + XDP_F_PASS_BIT, + XDP_F_TX_BIT, + XDP_F_REDIRECT_BIT, + XDP_F_REDIRECT_TARGET_BIT, + XDP_F_SOCK_ZEROCOPY_BIT, + XDP_F_HW_OFFLOAD_BIT, + XDP_F_TX_LOCK_BIT, + XDP_F_FRAG_RX_BIT, + XDP_F_FRAG_TARGET_BIT, + /* + * Add your fresh new property above and remember to update + * documentation. + */ + XDP_FEATURES_COUNT, +}; + +#define XDP_FEATURES_WORDS ((XDP_FEATURES_COUNT + 32 - 1) / 32) +#define XDP_FEATURES_WORD(blocks, index) ((blocks)[(index) / 32U]) +#define XDP_FEATURES_FIELD_FLAG(index) (1U << (index) % 32U) +#define XDP_FEATURES_BIT_IS_SET(blocks, index) \ + (XDP_FEATURES_WORD(blocks, index) & XDP_FEATURES_FIELD_FLAG(index)) + +#endif /* __UAPI_LINUX_XDP_FEATURES__ */ diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 64289bc98887..1c299746b614 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1016,6 +1016,14 @@ static size_t rtnl_xdp_size(void) return xdp_size; } +static size_t rtnl_xdp_features_size(void) +{ + size_t xdp_size = nla_total_size(0) + /* nest IFLA_XDP_FEATURES */ + XDP_FEATURES_WORDS * nla_total_size(4); + + return xdp_size; +} + static size_t rtnl_prop_list_size(const struct net_device *dev) { struct netdev_name_node *name_node; @@ -1103,6 +1111,7 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev, + rtnl_prop_list_size(dev) + nla_total_size(MAX_ADDR_LEN) /* IFLA_PERM_ADDRESS */ + rtnl_devlink_port_size(dev) + + rtnl_xdp_features_size() /* IFLA_XDP_FEATURES */ + 0; } @@ -1546,6 +1555,27 @@ static int rtnl_xdp_fill(struct sk_buff *skb, struct net_device *dev) return err; } +static int rtnl_xdp_features_fill(struct sk_buff *skb, struct net_device *dev) +{ + struct nlattr *attr; + + attr = nla_nest_start_noflag(skb, IFLA_XDP_FEATURES); + if (!attr) + return -EMSGSIZE; + + BUILD_BUG_ON(XDP_FEATURES_WORDS != 1); + if (nla_put_u32(skb, IFLA_XDP_FEATURES_BITS_WORD, dev->xdp_features)) + goto err_cancel; + + nla_nest_end(skb, attr); + + return 0; + +err_cancel: + nla_nest_cancel(skb, attr); + return -EMSGSIZE; +} + static u32 rtnl_get_event(unsigned long event) { u32 rtnl_event_type = IFLA_EVENT_NONE; @@ -1904,6 +1934,9 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, if (rtnl_fill_devlink_port(skb, dev)) goto nla_put_failure; + if (rtnl_xdp_features_fill(skb, dev)) + goto nla_put_failure; + nlmsg_end(skb, nlh); return 0; @@ -1968,6 +2001,7 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = { [IFLA_TSO_MAX_SIZE] = { .type = NLA_REJECT }, [IFLA_TSO_MAX_SEGS] = { .type = NLA_REJECT }, [IFLA_ALLMULTI] = { .type = NLA_REJECT }, + [IFLA_XDP_FEATURES] = { .type = NLA_NESTED }, }; static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index 82fe18f26db5..994228e9909a 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h @@ -354,6 +354,8 @@ enum { IFLA_DEVLINK_PORT, + IFLA_XDP_FEATURES, + __IFLA_MAX }; @@ -1222,6 +1224,11 @@ enum { #define IFLA_XDP_MAX (__IFLA_XDP_MAX - 1) +enum { + IFLA_XDP_FEATURES_WORD_UNSPEC = 0, + IFLA_XDP_FEATURES_BITS_WORD, +}; + enum { IFLA_EVENT_NONE, IFLA_EVENT_REBOOT, /* internal reset / reboot */ diff --git a/tools/include/uapi/linux/xdp_features.h b/tools/include/uapi/linux/xdp_features.h new file mode 100644 index 000000000000..48eb42069bcd --- /dev/null +++ b/tools/include/uapi/linux/xdp_features.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (c) 2020 Intel + */ + +#ifndef __UAPI_LINUX_XDP_FEATURES__ +#define __UAPI_LINUX_XDP_FEATURES__ + +enum { + XDP_F_ABORTED_BIT, + XDP_F_DROP_BIT, + XDP_F_PASS_BIT, + XDP_F_TX_BIT, + XDP_F_REDIRECT_BIT, + XDP_F_REDIRECT_TARGET_BIT, + XDP_F_SOCK_ZEROCOPY_BIT, + XDP_F_HW_OFFLOAD_BIT, + XDP_F_TX_LOCK_BIT, + XDP_F_FRAG_RX_BIT, + XDP_F_FRAG_TARGET_BIT, + /* + * Add your fresh new property above and remember to update + * documentation. + */ + XDP_FEATURES_COUNT, +}; + +#define XDP_FEATURES_WORDS ((XDP_FEATURES_COUNT + 32 - 1) / 32) +#define XDP_FEATURES_WORD(blocks, index) ((blocks)[(index) / 32U]) +#define XDP_FEATURES_FIELD_FLAG(index) (1U << (index) % 32U) +#define XDP_FEATURES_BIT_IS_SET(blocks, index) \ + (XDP_FEATURES_WORD(blocks, index) & XDP_FEATURES_FIELD_FLAG(index)) + +#endif /* __UAPI_LINUX_XDP_FEATURES__ */ From patchwork Mon Dec 19 15:41:32 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 13076726 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1264BC4332F for ; Mon, 19 Dec 2022 15:42:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232380AbiLSPmm (ORCPT ); Mon, 19 Dec 2022 10:42:42 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58032 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232360AbiLSPmh (ORCPT ); Mon, 19 Dec 2022 10:42:37 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9B0B8120B0; Mon, 19 Dec 2022 07:42:34 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 29DB1B80EA4; Mon, 19 Dec 2022 15:42:33 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 30E08C433F0; Mon, 19 Dec 2022 15:42:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1671464551; bh=sLaV3PORdHQIelCzXuJI8Bq0/5k16dDGcnYvMnrp1xQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JjWGl09KIrnRFqsxJUJNmhu6SOj6GWQwvrniX8nXWAiaTCdy1l5Iu/7d0QGx8NW6F xUZ5qlwDKHv4xuFKOm2TFq5hNeoostCM2LIxUAAY/XKHBl7AWE2KbXJNlAv5BfDKDA p8zSkCDxLQOVq0VCb/71xSkiFhrCFXcuSIJLcZ5WDho1OhgrCHh2SwiGagiTIRnwh+ JkcPNf6oRNi3XboPaEnQ3bWltdejy90eYoG+hJ6+1WKpaNu3VccTAO2QRRyhsdO5t7 NxqSCWTfTJgQb6cruoaWfdAlb0XE4fbVW9WWS05P0jXoTPG2AtRrdO225nMg9XKVKL ZRat7qK7kHXGg== From: Lorenzo Bianconi To: bpf@vger.kernel.org Cc: netdev@vger.kernel.org, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, davem@davemloft.net, kuba@kernel.org, hawk@kernel.org, pabeni@redhat.com, edumazet@google.com, toke@redhat.com, memxor@gmail.com, alardam@gmail.com, saeedm@nvidia.com, anthony.l.nguyen@intel.com, gospo@broadcom.com, vladimir.oltean@nxp.com, nbd@nbd.name, john@phrozen.org, leon@kernel.org, simon.horman@corigine.com, aelior@marvell.com, christophe.jaillet@wanadoo.fr, ecree.xilinx@gmail.com, grygorii.strashko@ti.com, mst@redhat.com, bjorn@kernel.org, magnus.karlsson@intel.com, maciej.fijalkowski@intel.com, intel-wired-lan@lists.osuosl.org, lorenzo.bianconi@redhat.com Subject: [RFC bpf-next 3/8] drivers: net: turn on XDP features Date: Mon, 19 Dec 2022 16:41:32 +0100 Message-Id: <43a674257d9950e5867aff3dbd6df9a4d9b43c75.1671462950.git.lorenzo@kernel.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC From: Marek Majtyka A summary of the flags being set for various drivers is given below. Note that XDP_F_REDIRECT_TARGET and XDP_F_FRAG_TARGET are features that can be turned off and on at runtime. This means that these flags may be set and unset under RTNL lock protection by the driver. Hence, READ_ONCE must be used by code loading the flag value. Also, these flags are not used for synchronization against the availability of XDP resources on a device. It is merely a hint, and hence the read may race with the actual teardown of XDP resources on the device. This may change in the future, e.g. operations taking a reference on the XDP resources of the driver, and in turn inhibiting turning off this flag. However, for now, it can only be used as a hint to check whether device supports becoming a redirection target. Turn 'hw-offload' feature flag on for: - netronome (nfp) - netdevsim. Turn 'native' and 'zerocopy' features flags on for: - intel (i40e, ice, ixgbe, igc) - mellanox (mlx5). - stmmac Turn 'native' features flags on for: - amazon (ena) - broadcom (bnxt) - freescale (dpaa, dpaa2, enetc) - funeth - intel (igb) - marvell (mvneta, mvpp2, octeontx2) - mellanox (mlx4) - qlogic (qede) - sfc - socionext (netsec) - ti (cpsw) - tap - veth - xen - virtio_net. Turn 'basic' (tx, pass, aborted and drop) features flags on for: - netronome (nfp) - cavium (thunder) - hyperv. Turn 'tx_lock' feature flag on for: - aquantia - freescale (dpaa2) - intel (igb) - marvell (mvneta, mvpp2) - microsoft (mana) - mediatek - qlogic (qede) - socionext (netsec) - ti (cpsw) - tap - veth - xen Turn 'redirect_target' feature flag on for: - amanzon (ena) - broadcom (bnxt) - freescale (dpaa, dpaa2) - intel (i40e, ice, igb, ixgbe) - ti (cpsw) - marvell (mvneta, mvpp2) - sfc - socionext (netsec) - qlogic (qede) - mellanox (mlx5) - tap - veth - virtio_net - xen Co-developed-by: Kumar Kartikeya Dwivedi Signed-off-by: Kumar Kartikeya Dwivedi Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Marek Majtyka --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 5 +++ .../net/ethernet/aquantia/atlantic/aq_nic.c | 3 ++ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 + drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 2 + .../net/ethernet/cavium/thunder/nicvf_main.c | 2 + .../net/ethernet/freescale/dpaa/dpaa_eth.c | 2 + .../net/ethernet/freescale/dpaa2/dpaa2-eth.c | 1 + .../net/ethernet/freescale/enetc/enetc_pf.c | 3 ++ .../ethernet/fungible/funeth/funeth_main.c | 6 +++ drivers/net/ethernet/intel/i40e/i40e_main.c | 9 ++++- drivers/net/ethernet/intel/ice/ice_main.c | 5 +++ drivers/net/ethernet/intel/igb/igb_main.c | 9 ++++- drivers/net/ethernet/intel/igc/igc_main.c | 2 + drivers/net/ethernet/intel/igc/igc_xdp.c | 5 +++ drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 5 +++ .../net/ethernet/intel/ixgbevf/ixgbevf_main.c | 1 + drivers/net/ethernet/marvell/mvneta.c | 3 ++ .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 3 ++ .../ethernet/marvell/octeontx2/nic/otx2_pf.c | 9 ++++- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 5 +++ .../net/ethernet/mellanox/mlx4/en_netdev.c | 2 + .../net/ethernet/mellanox/mlx5/core/en_main.c | 9 +++++ drivers/net/ethernet/microsoft/mana/mana_en.c | 2 + .../ethernet/netronome/nfp/nfp_net_common.c | 3 ++ drivers/net/ethernet/qlogic/qede/qede_main.c | 2 + drivers/net/ethernet/sfc/efx.c | 2 + drivers/net/ethernet/sfc/siena/efx.c | 2 + drivers/net/ethernet/socionext/netsec.c | 2 + .../net/ethernet/stmicro/stmmac/stmmac_main.c | 1 + drivers/net/ethernet/ti/cpsw.c | 2 + drivers/net/ethernet/ti/cpsw_new.c | 2 + drivers/net/hyperv/netvsc_drv.c | 2 + drivers/net/netdevsim/netdev.c | 1 + drivers/net/tun.c | 3 ++ drivers/net/veth.c | 4 ++ drivers/net/virtio_net.c | 5 +++ drivers/net/xen-netfront.c | 1 + include/net/xdp.h | 39 +++++++++++++++++++ 38 files changed, 161 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index a95529a69cbb..679d75b69870 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -589,7 +589,10 @@ static int ena_xdp_set(struct net_device *netdev, struct netdev_bpf *bpf) if (rc) return rc; } + __xdp_features_set_redirect_target(&netdev->xdp_features, + XDP_F_REDIRECT_TARGET); } else if (old_bpf_prog) { + xdp_features_clear_redirect_target(&netdev->xdp_features); rc = ena_destroy_and_free_all_xdp_queues(adapter); if (rc) return rc; @@ -4066,6 +4069,8 @@ static void ena_set_conf_feat_params(struct ena_adapter *adapter, /* Set offload features */ ena_set_dev_offloads(feat, netdev); + netdev->xdp_features = XDP_F_FULL | XDP_F_TX_LOCK; + adapter->max_mtu = feat->dev_attr.max_mtu; netdev->max_mtu = adapter->max_mtu; netdev->min_mtu = ENA_MIN_MTU; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index 06508eebb585..db4cf1c977d7 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -384,6 +384,9 @@ void aq_nic_ndev_init(struct aq_nic_s *self) self->ndev->mtu = aq_nic_cfg->mtu - ETH_HLEN; self->ndev->max_mtu = aq_hw_caps->mtu - ETH_FCS_LEN - ETH_HLEN; + self->ndev->xdp_features = XDP_F_FULL | XDP_F_TX_LOCK | + XDP_F_REDIRECT_TARGET | XDP_F_FRAG_RX | + XDP_F_FRAG_TARGET; } void aq_nic_set_tx_ring(struct aq_nic_s *self, unsigned int idx, diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 4c7d07c684c4..2c02833b5bdf 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -13681,6 +13681,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) netif_set_tso_max_size(dev, GSO_MAX_SIZE); + dev->xdp_features = XDP_F_FULL | XDP_F_FRAG_RX; + #ifdef CONFIG_BNXT_SRIOV init_waitqueue_head(&bp->sriov_cfg_wait); #endif diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c index c3065ec0a479..3c1b1ee7a37b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c @@ -424,9 +424,11 @@ static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog) if (prog) { bnxt_set_rx_skb_mode(bp, true); + xdp_features_set_redirect_target(&dev->xdp_features); } else { int rx, tx; + xdp_features_clear_redirect_target(&dev->xdp_features); bnxt_set_rx_skb_mode(bp, false); bnxt_get_max_rings(bp, &rx, &tx, true); if (rx > 1) { diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index f2f95493ec89..067bdd20aec8 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c @@ -2218,6 +2218,8 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->netdev_ops = &nicvf_netdev_ops; netdev->watchdog_timeo = NICVF_TX_TIMEOUT; + netdev->xdp_features = XDP_F_BASIC; + /* MTU range: 64 - 9200 */ netdev->min_mtu = NIC_HW_MIN_FRS; netdev->max_mtu = NIC_HW_MAX_FRS; diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index 3f8032947d86..24faa37a9a04 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -244,6 +244,8 @@ static int dpaa_netdev_init(struct net_device *net_dev, net_dev->features |= net_dev->hw_features; net_dev->vlan_features = net_dev->features; + net_dev->xdp_features = XDP_F_FULL | XDP_F_REDIRECT_TARGET; + if (is_valid_ether_addr(mac_addr)) { memcpy(net_dev->perm_addr, mac_addr, net_dev->addr_len); eth_hw_addr_set(net_dev, mac_addr); diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index 0c35abb7d065..99eb7bbb8ca1 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -4593,6 +4593,7 @@ static int dpaa2_eth_netdev_init(struct net_device *net_dev) NETIF_F_LLTX | NETIF_F_HW_TC | NETIF_F_TSO; net_dev->gso_max_segs = DPAA2_ETH_ENQUEUE_MAX_FDS; net_dev->hw_features = net_dev->features; + net_dev->xdp_features = XDP_F_FULL_ZC | XDP_F_TX_LOCK | XDP_F_REDIRECT_TARGET; if (priv->dpni_attrs.vlan_filter_entries) net_dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c index 9f6c4f5c0a6c..e83062e780e5 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c @@ -825,6 +825,9 @@ static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev, ndev->hw_features |= NETIF_F_RXHASH; ndev->priv_flags |= IFF_UNICAST_FLT; + ndev->xdp_features = XDP_F_FULL | XDP_F_TX_LOCK | + XDP_F_REDIRECT_TARGET | XDP_F_FRAG_RX | + XDP_F_FRAG_TARGET; if (si->hw_features & ENETC_SI_F_PSFP && !enetc_psfp_enable(priv)) { priv->active_offloads |= ENETC_F_QCI; diff --git a/drivers/net/ethernet/fungible/funeth/funeth_main.c b/drivers/net/ethernet/fungible/funeth/funeth_main.c index b4cce30e526a..1ba7e51cce8d 100644 --- a/drivers/net/ethernet/fungible/funeth/funeth_main.c +++ b/drivers/net/ethernet/fungible/funeth/funeth_main.c @@ -1160,6 +1160,11 @@ static int fun_xdp_setup(struct net_device *dev, struct netdev_bpf *xdp) WRITE_ONCE(rxqs[i]->xdp_prog, prog); } + if (prog) + xdp_features_set_redirect_target(&dev->xdp_features); + else + xdp_features_clear_redirect_target(&dev->xdp_features); + dev->max_mtu = prog ? XDP_MAX_MTU : FUN_MAX_MTU; old_prog = xchg(&fp->xdp_prog, prog); if (old_prog) @@ -1765,6 +1770,7 @@ static int fun_create_netdev(struct fun_ethdev *ed, unsigned int portid) netdev->vlan_features = netdev->features & VLAN_FEAT; netdev->mpls_features = netdev->vlan_features; netdev->hw_enc_features = netdev->hw_features; + netdev->xdp_features = XDP_F_FULL; netdev->min_mtu = ETH_MIN_MTU; netdev->max_mtu = FUN_MAX_MTU; diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 94feea3b2599..e71a53677f06 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -13339,9 +13339,11 @@ static int i40e_xdp_setup(struct i40e_vsi *vsi, struct bpf_prog *prog, old_prog = xchg(&vsi->xdp_prog, prog); if (need_reset) { - if (!prog) + if (!prog) { + xdp_features_clear_redirect_target(&vsi->netdev->xdp_features); /* Wait until ndo_xsk_wakeup completes. */ synchronize_rcu(); + } i40e_reset_and_rebuild(pf, true, true); } @@ -13362,11 +13364,13 @@ static int i40e_xdp_setup(struct i40e_vsi *vsi, struct bpf_prog *prog, /* Kick start the NAPI context if there is an AF_XDP socket open * on that queue id. This so that receiving will start. */ - if (need_reset && prog) + if (need_reset && prog) { for (i = 0; i < vsi->num_queue_pairs; i++) if (vsi->xdp_rings[i]->xsk_pool) (void)i40e_xsk_wakeup(vsi->netdev, i, XDP_WAKEUP_RX); + xdp_features_set_redirect_target(&vsi->netdev->xdp_features); + } return 0; } @@ -13783,6 +13787,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) netdev->hw_enc_features |= NETIF_F_TSO_MANGLEID; netdev->features &= ~NETIF_F_HW_TC; + netdev->xdp_features = XDP_F_FULL_ZC; if (vsi->type == I40E_VSI_MAIN) { SET_NETDEV_DEV(netdev, &pf->pdev->dev); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index a9a7f8b52140..07f1d0fd0571 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -22,6 +22,7 @@ #include "ice_eswitch.h" #include "ice_tc_lib.h" #include "ice_vsi_vlan_ops.h" +#include #define DRV_SUMMARY "Intel(R) Ethernet Connection E800 Series Linux Driver" static const char ice_driver_string[] = DRV_SUMMARY; @@ -2899,11 +2900,14 @@ ice_xdp_setup_prog(struct ice_vsi *vsi, struct bpf_prog *prog, if (xdp_ring_err) NL_SET_ERR_MSG_MOD(extack, "Setting up XDP Tx resources failed"); } + __xdp_features_set_redirect_target(&vsi->netdev->xdp_features, + XDP_F_REDIRECT_TARGET); /* reallocate Rx queues that are used for zero-copy */ xdp_ring_err = ice_realloc_zc_buf(vsi, true); if (xdp_ring_err) NL_SET_ERR_MSG_MOD(extack, "Setting up XDP Rx resources failed"); } else if (ice_is_xdp_ena_vsi(vsi) && !prog) { + xdp_features_clear_redirect_target(&vsi->netdev->xdp_features); xdp_ring_err = ice_destroy_xdp_rings(vsi); if (xdp_ring_err) NL_SET_ERR_MSG_MOD(extack, "Freeing XDP Tx resources failed"); @@ -3446,6 +3450,7 @@ static int ice_cfg_netdev(struct ice_vsi *vsi) np->vsi = vsi; ice_set_netdev_features(netdev); + netdev->xdp_features = XDP_F_FULL_ZC; ice_set_ops(netdev); diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 97290fc0fddd..2834b6e9f604 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -2871,8 +2871,14 @@ static int igb_xdp_setup(struct net_device *dev, struct netdev_bpf *bpf) bpf_prog_put(old_prog); /* bpf is just replaced, RXQ and MTU are already setup */ - if (!need_reset) + if (!need_reset) { return 0; + } else { + if (prog) + xdp_features_set_redirect_target(&dev->xdp_features); + else + xdp_features_clear_redirect_target(&dev->xdp_features); + } if (running) igb_open(dev); @@ -3317,6 +3323,7 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->priv_flags |= IFF_SUPP_NOFCS; netdev->priv_flags |= IFF_UNICAST_FLT; + netdev->xdp_features = XDP_F_FULL | XDP_F_TX_LOCK; /* MTU range: 68 - 9216 */ netdev->min_mtu = ETH_MIN_MTU; diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 1586e1e435c6..64917a272cf4 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -6379,6 +6379,8 @@ static int igc_probe(struct pci_dev *pdev, netdev->mpls_features |= NETIF_F_HW_CSUM; netdev->hw_enc_features |= netdev->vlan_features; + netdev->xdp_features = XDP_F_FULL_ZC; + /* MTU range: 68 - 9216 */ netdev->min_mtu = ETH_MIN_MTU; netdev->max_mtu = MAX_STD_JUMBO_FRAME_SIZE; diff --git a/drivers/net/ethernet/intel/igc/igc_xdp.c b/drivers/net/ethernet/intel/igc/igc_xdp.c index aeeb34e64610..570170a29e3a 100644 --- a/drivers/net/ethernet/intel/igc/igc_xdp.c +++ b/drivers/net/ethernet/intel/igc/igc_xdp.c @@ -29,6 +29,11 @@ int igc_xdp_set_prog(struct igc_adapter *adapter, struct bpf_prog *prog, if (old_prog) bpf_prog_put(old_prog); + if (prog) + xdp_features_set_redirect_target(&dev->xdp_features); + else + xdp_features_clear_redirect_target(&dev->xdp_features); + if (if_running) igc_open(dev); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index ab8370c413f3..4550b80f4ebd 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -10301,6 +10301,8 @@ static int ixgbe_xdp_setup(struct net_device *dev, struct bpf_prog *prog) rcu_assign_pointer(adapter->xdp_prog, old_prog); return -EINVAL; } + if (!prog) + xdp_features_clear_redirect_target(&dev->xdp_features); } else { for (i = 0; i < adapter->num_rx_queues; i++) (void)xchg(&adapter->rx_ring[i]->xdp_prog, @@ -10320,6 +10322,7 @@ static int ixgbe_xdp_setup(struct net_device *dev, struct bpf_prog *prog) if (adapter->xdp_ring[i]->xsk_pool) (void)ixgbe_xsk_wakeup(adapter->netdev, i, XDP_WAKEUP_RX); + xdp_features_set_redirect_target(&dev->xdp_features); } return 0; @@ -11017,6 +11020,8 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->priv_flags |= IFF_UNICAST_FLT; netdev->priv_flags |= IFF_SUPP_NOFCS; + netdev->xdp_features = XDP_F_FULL_ZC; + /* MTU range: 68 - 9710 */ netdev->min_mtu = ETH_MIN_MTU; netdev->max_mtu = IXGBE_MAX_JUMBO_FRAME_SIZE - (ETH_HLEN + ETH_FCS_LEN); diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index ea0a230c1153..8bc32ab2c2dd 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -4634,6 +4634,7 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) NETIF_F_HW_VLAN_CTAG_TX; netdev->priv_flags |= IFF_UNICAST_FLT; + netdev->xdp_features = XDP_F_BASIC; /* MTU range: 68 - 1504 or 9710 */ netdev->min_mtu = ETH_MIN_MTU; diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index f8925cac61e4..e3928a534308 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -5612,6 +5612,9 @@ static int mvneta_probe(struct platform_device *pdev) NETIF_F_TSO | NETIF_F_RXCSUM; dev->hw_features |= dev->features; dev->vlan_features |= dev->features; + dev->xdp_features = XDP_F_FULL | XDP_F_TX_LOCK | + XDP_F_REDIRECT_TARGET | XDP_F_FRAG_RX | + XDP_F_FRAG_TARGET; dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; netif_set_tso_max_segs(dev, MVNETA_MAX_TSO_SEGS); diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index 4da45c5abba5..6bfe28aafb4f 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -6866,6 +6866,9 @@ static int mvpp2_port_probe(struct platform_device *pdev, dev->vlan_features |= features; netif_set_tso_max_segs(dev, MVPP2_MAX_TSO_SEGS); + + dev->xdp_features = XDP_F_FULL | XDP_F_TX_LOCK | XDP_F_REDIRECT_TARGET; + dev->priv_flags |= IFF_UNICAST_FLT; /* MTU range: 68 - 9704 */ diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c index c1ea60bc2630..3c7fc7bf8339 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c @@ -2512,10 +2512,14 @@ static int otx2_xdp_setup(struct otx2_nic *pf, struct bpf_prog *prog) /* Network stack and XDP shared same rx queues. * Use separate tx queues for XDP and network stack. */ - if (pf->xdp_prog) + if (pf->xdp_prog) { pf->hw.xdp_queues = pf->hw.rx_queues; - else + __xdp_features_set_redirect_target(&dev->xdp_features, + XDP_F_REDIRECT_TARGET); + } else { pf->hw.xdp_queues = 0; + xdp_features_clear_redirect_target(&dev->xdp_features); + } pf->hw.tot_tx_queues += pf->hw.xdp_queues; @@ -2878,6 +2882,7 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id) netdev->watchdog_timeo = OTX2_TX_TIMEOUT; netdev->netdev_ops = &otx2_netdev_ops; + netdev->xdp_features = XDP_F_FULL; netdev->min_mtu = OTX2_MIN_MTU; netdev->max_mtu = otx2_get_max_mtu(pf); diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index e3de9a53b2d9..17831770b494 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -4186,6 +4186,11 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) register_netdevice_notifier(&mac->device_notifier); } + if (mtk_page_pool_enabled(eth)) + eth->netdev[id]->xdp_features = XDP_F_FULL | XDP_F_TX_LOCK | + XDP_F_REDIRECT_TARGET | + XDP_F_FRAG_TARGET; + return 0; free_netdev: diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 8800d3f1f55c..3c7b011de300 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -3410,6 +3410,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, priv->rss_hash_fn = ETH_RSS_HASH_TOP; } + dev->xdp_features = XDP_F_FULL; + /* MTU range: 68 - hw-specific max */ dev->min_mtu = ETH_MIN_MTU; dev->max_mtu = priv->max_mtu; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 8d36e2de53a9..2a406dddae84 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -4776,6 +4776,13 @@ static int mlx5e_xdp_set(struct net_device *netdev, struct bpf_prog *prog) if (old_prog) bpf_prog_put(old_prog); + if (reset) { + if (prog) + xdp_features_set_redirect_target(&netdev->xdp_features); + else + xdp_features_clear_redirect_target(&netdev->xdp_features); + } + if (!test_bit(MLX5E_STATE_OPENED, &priv->state) || reset) goto unlock; @@ -5170,6 +5177,8 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev) netdev->features |= NETIF_F_HIGHDMA; netdev->features |= NETIF_F_HW_VLAN_STAG_FILTER; + netdev->xdp_features = XDP_F_FULL_ZC | XDP_F_FRAG_RX; + netdev->priv_flags |= IFF_UNICAST_FLT; netif_set_tso_max_size(netdev, GSO_MAX_SIZE); diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c index 2f6a048dee90..61955359931b 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_en.c +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c @@ -2160,6 +2160,8 @@ static int mana_probe_port(struct mana_context *ac, int port_idx, ndev->hw_features |= NETIF_F_RXHASH; ndev->features = ndev->hw_features; ndev->vlan_features = 0; + ndev->xdp_features = XDP_F_FULL | XDP_F_TX_LOCK | + XDP_F_REDIRECT_TARGET; err = register_netdev(ndev); if (err) { diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 2314cf55e821..f704b4ad5702 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -2482,10 +2482,13 @@ static void nfp_net_netdev_init(struct nfp_net *nn) netdev->features &= ~NETIF_F_HW_VLAN_STAG_RX; nn->dp.ctrl &= ~NFP_NET_CFG_CTRL_RXQINQ; + nn->dp.netdev->xdp_features = XDP_F_BASIC | XDP_F_HW_OFFLOAD; + /* Finalise the netdev setup */ switch (nn->dp.ops->version) { case NFP_NFD_VER_NFD3: netdev->netdev_ops = &nfp_nfd3_netdev_ops; + nn->dp.netdev->xdp_features |= XDP_F_SOCK_ZEROCOPY; break; case NFP_NFD_VER_NFDK: netdev->netdev_ops = &nfp_nfdk_netdev_ops; diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index 953f304b8588..f090ce57befd 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -892,6 +892,8 @@ static void qede_init_ndev(struct qede_dev *edev) ndev->hw_features = hw_features; + ndev->xdp_features = XDP_F_FULL | XDP_F_TX_LOCK | XDP_F_REDIRECT_TARGET; + /* MTU range: 46 - 9600 */ ndev->min_mtu = ETH_ZLEN - ETH_HLEN; ndev->max_mtu = QEDE_MAX_JUMBO_PACKET_SIZE; diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 0556542d7a6b..bc624c2ea016 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -1078,6 +1078,8 @@ static int efx_pci_probe(struct pci_dev *pci_dev, pci_info(pci_dev, "Solarflare NIC detected\n"); + efx->net_dev->xdp_features = XDP_F_FULL | XDP_F_REDIRECT_TARGET; + if (!efx->type->is_vf) efx_probe_vpd_strings(efx); diff --git a/drivers/net/ethernet/sfc/siena/efx.c b/drivers/net/ethernet/sfc/siena/efx.c index 60e5b7c8ccf9..0872e075ea3a 100644 --- a/drivers/net/ethernet/sfc/siena/efx.c +++ b/drivers/net/ethernet/sfc/siena/efx.c @@ -1048,6 +1048,8 @@ static int efx_pci_probe(struct pci_dev *pci_dev, pci_info(pci_dev, "Solarflare NIC detected\n"); + efx->net_dev->xdp_features = XDP_F_FULL | XDP_F_REDIRECT_TARGET; + if (!efx->type->is_vf) efx_probe_vpd_strings(efx); diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c index 9b46579b5a10..e4586c49f5b8 100644 --- a/drivers/net/ethernet/socionext/netsec.c +++ b/drivers/net/ethernet/socionext/netsec.c @@ -2104,6 +2104,8 @@ static int netsec_probe(struct platform_device *pdev) NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; ndev->hw_features = ndev->features; + ndev->xdp_features = XDP_F_FULL | XDP_F_TX_LOCK | XDP_F_REDIRECT_TARGET; + priv->rx_cksum_offload_flag = true; ret = netsec_register_mdio(priv, phy_addr); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index ec64b65dee34..4b759cb1a9ff 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -7144,6 +7144,7 @@ int stmmac_dvr_probe(struct device *device, ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM; + ndev->xdp_features = XDP_F_FULL | XDP_F_TX_LOCK | XDP_F_REDIRECT_TARGET; ret = stmmac_tc_init(priv, priv); if (!ret) { diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 13c9c2d6b79b..6e76345a0d46 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -1458,6 +1458,7 @@ static int cpsw_probe_dual_emac(struct cpsw_priv *priv) priv_sl2->emac_port = 1; cpsw->slaves[1].ndev = ndev; ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_CTAG_RX; + ndev->xdp_features = XDP_F_FULL | XDP_F_TX_LOCK | XDP_F_REDIRECT_TARGET; ndev->netdev_ops = &cpsw_netdev_ops; ndev->ethtool_ops = &cpsw_ethtool_ops; @@ -1635,6 +1636,7 @@ static int cpsw_probe(struct platform_device *pdev) cpsw->slaves[0].ndev = ndev; ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_CTAG_RX; + ndev->xdp_features = XDP_F_FULL | XDP_F_TX_LOCK | XDP_F_REDIRECT_TARGET; ndev->netdev_ops = &cpsw_netdev_ops; ndev->ethtool_ops = &cpsw_ethtool_ops; diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c index 83596ec0c7cb..a8a20840a05a 100644 --- a/drivers/net/ethernet/ti/cpsw_new.c +++ b/drivers/net/ethernet/ti/cpsw_new.c @@ -1405,6 +1405,8 @@ static int cpsw_create_ports(struct cpsw_common *cpsw) ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_NETNS_LOCAL | NETIF_F_HW_TC; + ndev->xdp_features = XDP_F_FULL | XDP_F_TX_LOCK | XDP_F_REDIRECT_TARGET; + ndev->netdev_ops = &cpsw_netdev_ops; ndev->ethtool_ops = &cpsw_ethtool_ops; SET_NETDEV_DEV(ndev, dev); diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index f9b219e6cd58..4bb09de440b2 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -2559,6 +2559,8 @@ static int netvsc_probe(struct hv_device *dev, netdev_lockdep_set_classes(net); + net->xdp_features = XDP_F_FULL; + /* MTU range: 68 - 1500 or 65521 */ net->min_mtu = NETVSC_MTU_MIN; if (nvdev->nvsp_version >= NVSP_PROTOCOL_VERSION_2) diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c index 6db6a75ff9b9..20962dd54bac 100644 --- a/drivers/net/netdevsim/netdev.c +++ b/drivers/net/netdevsim/netdev.c @@ -286,6 +286,7 @@ static void nsim_setup(struct net_device *dev) NETIF_F_TSO; dev->hw_features |= NETIF_F_HW_TC; dev->max_mtu = ETH_MAX_MTU; + dev->xdp_features = XDP_F_HW_OFFLOAD; } static int nsim_init_netdevsim(struct netdevsim *ns) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index a7d17c680f4a..b35210a6371b 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1401,6 +1401,9 @@ static void tun_net_initialize(struct net_device *dev) eth_hw_addr_random(dev); + /* Currently tun does not support XDP, only tap does. */ + dev->xdp_features = XDP_F_FULL | XDP_F_TX_LOCK | XDP_F_REDIRECT_TARGET; + break; } diff --git a/drivers/net/veth.c b/drivers/net/veth.c index ac7c0653695f..e2518ed81dc5 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -1648,6 +1648,10 @@ static void veth_setup(struct net_device *dev) dev->hw_enc_features = VETH_FEATURES; dev->mpls_features = NETIF_F_HW_CSUM | NETIF_F_GSO_SOFTWARE; netif_set_tso_max_size(dev, GSO_MAX_SIZE); + + dev->xdp_features = XDP_F_FULL | XDP_F_TX_LOCK | + XDP_F_REDIRECT_TARGET | XDP_F_FRAG_RX | + XDP_F_FRAG_TARGET; } /* diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 7723b2a49d8e..bbd0e306c098 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -3155,7 +3155,11 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog, if (i == 0 && !old_prog) virtnet_clear_guest_offloads(vi); } + if (!old_prog) + __xdp_features_set_redirect_target(&dev->xdp_features, + XDP_F_REDIRECT_TARGET); } else { + xdp_features_clear_redirect_target(&dev->xdp_features); vi->xdp_enabled = false; } @@ -3785,6 +3789,7 @@ static int virtnet_probe(struct virtio_device *vdev) dev->hw_features |= NETIF_F_GRO_HW; dev->vlan_features = dev->features; + dev->xdp_features = XDP_F_FULL; /* MTU range: 68 - 65535 */ dev->min_mtu = MIN_MTU; diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 14aec417fa06..65820489bb9a 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1741,6 +1741,7 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev) * negotiate with the backend regarding supported features. */ netdev->features |= netdev->hw_features; + netdev->xdp_features = XDP_F_FULL | XDP_F_TX_LOCK | XDP_F_REDIRECT_TARGET; netdev->ethtool_ops = &xennet_ethtool_ops; netdev->min_mtu = ETH_MIN_MTU; diff --git a/include/net/xdp.h b/include/net/xdp.h index 55dbc68bfffc..68b322735b5c 100644 --- a/include/net/xdp.h +++ b/include/net/xdp.h @@ -7,6 +7,7 @@ #define __LINUX_NET_XDP_H__ #include /* skb_shared_info */ +#include /** * DOC: XDP RX-queue information @@ -407,6 +408,44 @@ struct netdev_bpf; void xdp_attachment_setup(struct xdp_attachment_info *info, struct netdev_bpf *bpf); +#if defined(CONFIG_NET) && defined(CONFIG_BPF_SYSCALL) + +static inline void +__xdp_features_set_redirect_target(xdp_features_t *xdp_features, u32 flags) +{ + flags &= (XDP_F_REDIRECT_TARGET | XDP_F_FRAG_TARGET); + WRITE_ONCE(*xdp_features, *xdp_features | flags); +} + +static inline void +xdp_features_clear_redirect_target(xdp_features_t *xdp_features) +{ + WRITE_ONCE(*xdp_features, + *xdp_features & ~(XDP_F_REDIRECT_TARGET | XDP_F_FRAG_TARGET)); +} + +#else + +static inline void +__xdp_features_set_redirect_target(xdp_features_t *xdp_features, u32 flags) +{ +} + +static inline void +xdp_features_clear_redirect_target(xdp_features_t *xdp_features) +{ +} + +#endif + +static inline void +xdp_features_set_redirect_target(xdp_features_t *xdp_features) +{ + __xdp_features_set_redirect_target(xdp_features, + XDP_F_REDIRECT_TARGET | + XDP_F_FRAG_TARGET); +} + #define DEV_MAP_BULK_SIZE XDP_BULK_QUEUE_SIZE #endif /* __LINUX_NET_XDP_H__ */ From patchwork Mon Dec 19 15:41:33 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 13076725 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A42C2C3DA71 for ; Mon, 19 Dec 2022 15:42:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232387AbiLSPmn (ORCPT ); Mon, 19 Dec 2022 10:42:43 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58036 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232058AbiLSPmi (ORCPT ); Mon, 19 Dec 2022 10:42:38 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2385825FE; Mon, 19 Dec 2022 07:42:38 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id DB2A7B80EA6; Mon, 19 Dec 2022 15:42:36 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 244DDC43392; Mon, 19 Dec 2022 15:42:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1671464555; bh=AFHGA4/VUtLtWks3taPMr6hCqmlIuVlvJjAohqShmBc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kv95OSOUNhxRPvuXoUI8nLwdmB4hfbglAEdpHGx2N2itWrIz1p2QrRi6yVFE5nJTz SJt5DNlrhMoPvPdzdbm9Z4zARUxcVOZmDMR4U2RY5io9H0ARlUbcp7YVo6HLHSVlXQ /U7Z1/qvuDogfjLzxLzNEIoHh4t/KpJqk7m4R99mwA8wWdsE8MiDKto5M6CykOobx1 /5mbOqLmbwz2OElf55twBEhtMOb0qQPJFXd850tqPRugmf9M1bw5CwV9qDxP/X/RC1 2oNFRLOpvBrSCC0VTdLD6558JMcLQUahqm+XDdKOG3/cPO4/5rfzj3ndHC9rjuL2XB r4LY71/02A8SA== From: Lorenzo Bianconi To: bpf@vger.kernel.org Cc: netdev@vger.kernel.org, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, davem@davemloft.net, kuba@kernel.org, hawk@kernel.org, pabeni@redhat.com, edumazet@google.com, toke@redhat.com, memxor@gmail.com, alardam@gmail.com, saeedm@nvidia.com, anthony.l.nguyen@intel.com, gospo@broadcom.com, vladimir.oltean@nxp.com, nbd@nbd.name, john@phrozen.org, leon@kernel.org, simon.horman@corigine.com, aelior@marvell.com, christophe.jaillet@wanadoo.fr, ecree.xilinx@gmail.com, grygorii.strashko@ti.com, mst@redhat.com, bjorn@kernel.org, magnus.karlsson@intel.com, maciej.fijalkowski@intel.com, intel-wired-lan@lists.osuosl.org, lorenzo.bianconi@redhat.com Subject: [RFC bpf-next 4/8] xsk: add usage of XDP features flags Date: Mon, 19 Dec 2022 16:41:33 +0100 Message-Id: X-Mailer: git-send-email 2.38.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC From: Marek Majtyka Change necessary condition check for XSK from ndo functions to xdp features flags. Signed-off-by: Marek Majtyka Signed-off-by: Lorenzo Bianconi --- net/xdp/xsk_buff_pool.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/xdp/xsk_buff_pool.c b/net/xdp/xsk_buff_pool.c index ed6c71826d31..7afd12dd69cc 100644 --- a/net/xdp/xsk_buff_pool.c +++ b/net/xdp/xsk_buff_pool.c @@ -178,8 +178,7 @@ int xp_assign_dev(struct xsk_buff_pool *pool, /* For copy-mode, we are done. */ return 0; - if (!netdev->netdev_ops->ndo_bpf || - !netdev->netdev_ops->ndo_xsk_wakeup) { + if ((netdev->xdp_features & XDP_F_FULL_ZC) != XDP_F_FULL_ZC) { err = -EOPNOTSUPP; goto err_unreg_pool; } From patchwork Mon Dec 19 15:41:34 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 13076727 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 414E9C4332F for ; Mon, 19 Dec 2022 15:42:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232388AbiLSPmp (ORCPT ); Mon, 19 Dec 2022 10:42:45 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58058 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232363AbiLSPml (ORCPT ); Mon, 19 Dec 2022 10:42:41 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7C30412083; Mon, 19 Dec 2022 07:42:40 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 17BFD6101A; Mon, 19 Dec 2022 15:42:40 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0148FC433EF; Mon, 19 Dec 2022 15:42:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1671464559; bh=/GvW1CBUtaSQShWzPvNHf0BP6LO6rDP67Uq5eKJRcw8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=aD8H3WWbpD36LwAUsVy8GUnEZXJd70+H5AiURKCFAenW8xRZ50lmvGSCQKOWP7Y1R FN34kYUYYVXuiVThLcwt/tAvCTlGewF0XFFxCo+bbae3KOla4+YOulDcvu+ZwE/0d2 VRlGyRamtEugVoWy7gvEPKnuDyFM9x97aN94CNC4B0brWP8I6aHDYirIO6IZZBD80d KgFWZGCLDCo3eazn/q9cUN4ZBczB8iCHxBrfOoSyiDffL5qZcOFRSbPpFmmtXmgo6U Zn1SxS0TIuPVUYpwDmZdtgPx5c3WbbcauXtjV/Xi+TtmUQtNekfy5AX+XQKKfQVGmA n1f3BmhrF0S1w== From: Lorenzo Bianconi To: bpf@vger.kernel.org Cc: netdev@vger.kernel.org, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, davem@davemloft.net, kuba@kernel.org, hawk@kernel.org, pabeni@redhat.com, edumazet@google.com, toke@redhat.com, memxor@gmail.com, alardam@gmail.com, saeedm@nvidia.com, anthony.l.nguyen@intel.com, gospo@broadcom.com, vladimir.oltean@nxp.com, nbd@nbd.name, john@phrozen.org, leon@kernel.org, simon.horman@corigine.com, aelior@marvell.com, christophe.jaillet@wanadoo.fr, ecree.xilinx@gmail.com, grygorii.strashko@ti.com, mst@redhat.com, bjorn@kernel.org, magnus.karlsson@intel.com, maciej.fijalkowski@intel.com, intel-wired-lan@lists.osuosl.org, lorenzo.bianconi@redhat.com Subject: [RFC bpf-next 5/8] xsk: add check for full support of XDP in bind Date: Mon, 19 Dec 2022 16:41:34 +0100 Message-Id: <8522db2faf32eb9e37862cd5bd6ba98bec3fa2d8.1671462951.git.lorenzo@kernel.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC From: Marek Majtyka Add check for full support of XDP in AF_XDP socket bind. To be able to use an AF_XDP socket with zero-copy, there needs to be support for both XDP_REDIRECT in the driver (XDP native mode) and the driver needs to support zero-copy. The problem is that there are drivers out there that only support XDP partially, so it is possible to successfully load the XDP program in native mode, but it will still not be able to support zero-copy as it does not have XDP_REDIRECT support. We can now alleviate this problem by using the new XDP netdev capability that signifies if full XDP support is indeed present. This check can be triggered by a new bind flag called XDP_CHECK_NATIVE_MODE. To simplify usage, this check is triggered automatically from inside libbpf library via turning on the new XDP_CHECK_NATIVE_MODE flag if and only if the driver mode is selected for the socket. As a result, the xsk_bind function decides if the native mode for a given interface makes sense or not using xdp netdev feature flags. Eventually the xsk socket is bound or an error is returned. Apart from this change and to catch all invalid inputs in a single place, an additional check is set to forbid skb mode and zero copy settings at the same time as that combination makes no sense. Signed-off-by: Marek Majtyka Signed-off-by: Lorenzo Bianconi --- include/uapi/linux/if_xdp.h | 1 + net/xdp/xsk.c | 4 ++-- net/xdp/xsk_buff_pool.c | 17 ++++++++++++++++- tools/include/uapi/linux/if_xdp.h | 1 + tools/testing/selftests/bpf/xsk.c | 3 +++ 5 files changed, 23 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/if_xdp.h b/include/uapi/linux/if_xdp.h index a78a8096f4ce..8f47754dacce 100644 --- a/include/uapi/linux/if_xdp.h +++ b/include/uapi/linux/if_xdp.h @@ -25,6 +25,7 @@ * application. */ #define XDP_USE_NEED_WAKEUP (1 << 3) +#define XDP_CHECK_NATIVE_MODE (1 << 4) /* Flags for xsk_umem_config flags */ #define XDP_UMEM_UNALIGNED_CHUNK_FLAG (1 << 0) diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c index 9f0561b67c12..76e9a9e99559 100644 --- a/net/xdp/xsk.c +++ b/net/xdp/xsk.c @@ -889,7 +889,7 @@ static int xsk_bind(struct socket *sock, struct sockaddr *addr, int addr_len) flags = sxdp->sxdp_flags; if (flags & ~(XDP_SHARED_UMEM | XDP_COPY | XDP_ZEROCOPY | - XDP_USE_NEED_WAKEUP)) + XDP_USE_NEED_WAKEUP | XDP_CHECK_NATIVE_MODE)) return -EINVAL; rtnl_lock(); @@ -917,7 +917,7 @@ static int xsk_bind(struct socket *sock, struct sockaddr *addr, int addr_len) struct socket *sock; if ((flags & XDP_COPY) || (flags & XDP_ZEROCOPY) || - (flags & XDP_USE_NEED_WAKEUP)) { + (flags & XDP_USE_NEED_WAKEUP) || (flags & XDP_CHECK_NATIVE_MODE)) { /* Cannot specify flags for shared sockets. */ err = -EINVAL; goto out_unlock; diff --git a/net/xdp/xsk_buff_pool.c b/net/xdp/xsk_buff_pool.c index 7afd12dd69cc..02f569893c02 100644 --- a/net/xdp/xsk_buff_pool.c +++ b/net/xdp/xsk_buff_pool.c @@ -143,7 +143,7 @@ static void xp_disable_drv_zc(struct xsk_buff_pool *pool) int xp_assign_dev(struct xsk_buff_pool *pool, struct net_device *netdev, u16 queue_id, u16 flags) { - bool force_zc, force_copy; + bool force_zc, force_copy, force_check; struct netdev_bpf bpf; int err = 0; @@ -151,10 +151,24 @@ int xp_assign_dev(struct xsk_buff_pool *pool, force_zc = flags & XDP_ZEROCOPY; force_copy = flags & XDP_COPY; + force_check = flags & XDP_CHECK_NATIVE_MODE; + if (force_zc && force_copy) return -EINVAL; + if (!(flags & XDP_SHARED_UMEM)) { + if (force_check) { + /* forbid driver mode without full XDP support */ + if (!(XDP_F_REDIRECT & netdev->xdp_features)) + return -EOPNOTSUPP; + } else { + /* forbid skb mode and zero copy */ + if (force_zc) + return -EINVAL; + } + } + if (xsk_get_pool_from_qid(netdev, queue_id)) return -EBUSY; @@ -222,6 +236,7 @@ int xp_assign_dev_shared(struct xsk_buff_pool *pool, struct xdp_sock *umem_xs, return -EINVAL; flags = umem->zc ? XDP_ZEROCOPY : XDP_COPY; + flags |= XDP_SHARED_UMEM; if (umem_xs->pool->uses_need_wakeup) flags |= XDP_USE_NEED_WAKEUP; diff --git a/tools/include/uapi/linux/if_xdp.h b/tools/include/uapi/linux/if_xdp.h index a78a8096f4ce..8f47754dacce 100644 --- a/tools/include/uapi/linux/if_xdp.h +++ b/tools/include/uapi/linux/if_xdp.h @@ -25,6 +25,7 @@ * application. */ #define XDP_USE_NEED_WAKEUP (1 << 3) +#define XDP_CHECK_NATIVE_MODE (1 << 4) /* Flags for xsk_umem_config flags */ #define XDP_UMEM_UNALIGNED_CHUNK_FLAG (1 << 0) diff --git a/tools/testing/selftests/bpf/xsk.c b/tools/testing/selftests/bpf/xsk.c index 39d349509ba4..d6b9349000d2 100644 --- a/tools/testing/selftests/bpf/xsk.c +++ b/tools/testing/selftests/bpf/xsk.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -1130,6 +1131,8 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr, sxdp.sxdp_shared_umem_fd = umem->fd; } else { sxdp.sxdp_flags = xsk->config.bind_flags; + if (xsk->config.xdp_flags & XDP_FLAGS_DRV_MODE) + sxdp.sxdp_flags |= XDP_CHECK_NATIVE_MODE; } err = bind(xsk->fd, (struct sockaddr *)&sxdp, sizeof(sxdp)); From patchwork Mon Dec 19 15:41:35 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 13076728 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C39ECC4167B for ; Mon, 19 Dec 2022 15:43:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232064AbiLSPnO (ORCPT ); Mon, 19 Dec 2022 10:43:14 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58158 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232394AbiLSPmr (ORCPT ); Mon, 19 Dec 2022 10:42:47 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D4DDC120BC; Mon, 19 Dec 2022 07:42:45 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 9560EB80EA3; Mon, 19 Dec 2022 15:42:44 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id B59EDC43398; Mon, 19 Dec 2022 15:42:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1671464563; bh=uzUgGEhWKxfTXIAicGnMskAOI5jXVPYSOrd9yyXt3LQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=OW7jKiqJrZsTqb50XmGmAj4/Q7hZKNtmhdVMeHek65EccBzLp6s019XAF3Bc8XbB8 3yTPd0SrsrvaNbdctyz633/Iw926tvZXITTl1+Zzh4/STfasaUDgWkPOkLO/zsls7c hXv4A2xUOlKzSIJ4VgJFDQCNeAoU7endWt2mjKbZ9uISXFBLOkIM8n1ITklLW1wPTs G2py07m81MonY9VVVRbRjyvz+hTaDUxNIlB1DzZL+CKxS4owra3XCvdJWbmGfXujaK iBQrliNzJ0TnK0a589D1mt5XP+fl+1kuZy+Mfahov5fSW06WmM5Y+g+MoX71iGB7Qs n+eZbRgVhjYww== From: Lorenzo Bianconi To: bpf@vger.kernel.org Cc: netdev@vger.kernel.org, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, davem@davemloft.net, kuba@kernel.org, hawk@kernel.org, pabeni@redhat.com, edumazet@google.com, toke@redhat.com, memxor@gmail.com, alardam@gmail.com, saeedm@nvidia.com, anthony.l.nguyen@intel.com, gospo@broadcom.com, vladimir.oltean@nxp.com, nbd@nbd.name, john@phrozen.org, leon@kernel.org, simon.horman@corigine.com, aelior@marvell.com, christophe.jaillet@wanadoo.fr, ecree.xilinx@gmail.com, grygorii.strashko@ti.com, mst@redhat.com, bjorn@kernel.org, magnus.karlsson@intel.com, maciej.fijalkowski@intel.com, intel-wired-lan@lists.osuosl.org, lorenzo.bianconi@redhat.com Subject: [RFC bpf-next 6/8] libbpf: add API to get XDP/XSK supported features Date: Mon, 19 Dec 2022 16:41:35 +0100 Message-Id: <6cce9b15a57345402bb94366434a5ac5609583b8.1671462951.git.lorenzo@kernel.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC From: Kumar Kartikeya Dwivedi Add functions to get XDP/XSK supported function of netdev over route netlink interface. These functions provide functionalities that are going to be used in upcoming change. The newly added bpf_xdp_query_features takes a fflags_cnt parameter, which denotes the number of elements in the output fflags array. This must be at least 1 and maybe greater than XDP_FEATURES_WORDS. The function only writes to words which is min of fflags_cnt and XDP_FEATURES_WORDS. Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Co-developed-by: Marek Majtyka Signed-off-by: Marek Majtyka Signed-off-by: Kumar Kartikeya Dwivedi --- tools/lib/bpf/libbpf.h | 1 + tools/lib/bpf/libbpf.map | 1 + tools/lib/bpf/netlink.c | 62 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index eee883f007f9..9d102eb5007e 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -967,6 +967,7 @@ LIBBPF_API int bpf_xdp_detach(int ifindex, __u32 flags, const struct bpf_xdp_attach_opts *opts); LIBBPF_API int bpf_xdp_query(int ifindex, int flags, struct bpf_xdp_query_opts *opts); LIBBPF_API int bpf_xdp_query_id(int ifindex, int flags, __u32 *prog_id); +LIBBPF_API int bpf_xdp_query_features(int ifindex, __u32 *fflags, __u32 *fflags_cnt); /* TC related API */ enum bpf_tc_attach_point { diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index 71bf5691a689..9c2abb58fa4b 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -362,6 +362,7 @@ LIBBPF_1.0.0 { bpf_program__set_autoattach; btf__add_enum64; btf__add_enum64_value; + bpf_xdp_query_features; libbpf_bpf_attach_type_str; libbpf_bpf_link_type_str; libbpf_bpf_map_type_str; diff --git a/tools/lib/bpf/netlink.c b/tools/lib/bpf/netlink.c index 35104580870c..6fd424cde58b 100644 --- a/tools/lib/bpf/netlink.c +++ b/tools/lib/bpf/netlink.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,12 @@ struct xdp_id_md { struct xdp_link_info info; }; +struct xdp_features_md { + int ifindex; + __u32 *flags; + __u32 *flags_cnt; +}; + static int libbpf_netlink_open(__u32 *nl_pid) { struct sockaddr_nl sa; @@ -357,6 +364,39 @@ static int get_xdp_info(void *cookie, void *msg, struct nlattr **tb) return 0; } +static int bpf_get_xdp_features(void *cookie, void *msg, struct nlattr **tb) +{ + struct nlattr *xdp_tb[IFLA_XDP_FEATURES_BITS_WORD + 1]; + struct xdp_features_md *md = cookie; + struct ifinfomsg *ifinfo = msg; + int ret, i, words; + + if (md->ifindex && md->ifindex != ifinfo->ifi_index) + return 0; + + if (!tb[IFLA_XDP_FEATURES]) + return 0; + + words = min(XDP_FEATURES_WORDS, *md->flags_cnt); + for (i = 0; i < words; ++i) + md->flags[i] = 0; + + ret = libbpf_nla_parse_nested(xdp_tb, XDP_FEATURES_WORDS, + tb[IFLA_XDP_FEATURES], NULL); + if (ret) + return ret; + + *md->flags_cnt = words; + for (i = 0; i < words; ++i) { + if (!xdp_tb[IFLA_XDP_FEATURES_BITS_WORD]) + continue; + + md->flags[i] = libbpf_nla_getattr_u32(xdp_tb[IFLA_XDP_FEATURES_BITS_WORD]); + } + + return 0; +} + int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) { struct libbpf_nla_req req = { @@ -421,6 +461,28 @@ int bpf_xdp_query_id(int ifindex, int flags, __u32 *prog_id) return 0; } +int bpf_xdp_query_features(int ifindex, __u32 *xdp_fflags, __u32 *fflags_cnt) +{ + struct libbpf_nla_req req = { + .nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), + .nh.nlmsg_type = RTM_GETLINK, + .nh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, + .ifinfo.ifi_family = AF_PACKET, + }; + struct xdp_features_md md = {}; + int ret; + + if (!xdp_fflags || !fflags_cnt) + return -EINVAL; + + md.ifindex = ifindex; + md.flags = xdp_fflags; + md.flags_cnt = fflags_cnt; + + ret = libbpf_netlink_send_recv(&req, __dump_link_nlmsg, + bpf_get_xdp_features, &md); + return libbpf_err(ret); +} typedef int (*qdisc_config_t)(struct libbpf_nla_req *req); From patchwork Mon Dec 19 15:41:36 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 13076729 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3706BC4332F for ; Mon, 19 Dec 2022 15:43:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232491AbiLSPn1 (ORCPT ); Mon, 19 Dec 2022 10:43:27 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58214 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232421AbiLSPmu (ORCPT ); Mon, 19 Dec 2022 10:42:50 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A058D12609; Mon, 19 Dec 2022 07:42:49 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 51F55B80EAA; Mon, 19 Dec 2022 15:42:48 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7428AC433D2; Mon, 19 Dec 2022 15:42:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1671464567; bh=y6oFJlBwi66+CEvrDKGUOKWKRpfOH8XKz8B1jxaGaqY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=lmmZLsTdqfy3in8F57kJGpkgb6fKCWhl1Gm5TJd/UWO75WV1nESrT7kYmfy4ifIjz JNAVcKolh4Nf/xSRyNtpwWRh4umfkRZYP17Edy0ryOfs5jMN9n8gLyTQZ5tJQThaab 6AankrXmqLI7pj9Duee4FUwkB8bIR5FaNIY4uV7jkVjpLi7iPuRW2hbJi/7yp7yam4 Ra/SKbduTekM6OkBRUo/+We5r0dbNemFce34BvyyUC36Lpd3hX2O+biQvWm116wHVD okKrQOgFHSl287KylITnq6BdevK2j7l1hAUeppzuBiDnUST8bdY+G0MXfTjIIu2GPs +NoaU0i0D4zPw== From: Lorenzo Bianconi To: bpf@vger.kernel.org Cc: netdev@vger.kernel.org, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, davem@davemloft.net, kuba@kernel.org, hawk@kernel.org, pabeni@redhat.com, edumazet@google.com, toke@redhat.com, memxor@gmail.com, alardam@gmail.com, saeedm@nvidia.com, anthony.l.nguyen@intel.com, gospo@broadcom.com, vladimir.oltean@nxp.com, nbd@nbd.name, john@phrozen.org, leon@kernel.org, simon.horman@corigine.com, aelior@marvell.com, christophe.jaillet@wanadoo.fr, ecree.xilinx@gmail.com, grygorii.strashko@ti.com, mst@redhat.com, bjorn@kernel.org, magnus.karlsson@intel.com, maciej.fijalkowski@intel.com, intel-wired-lan@lists.osuosl.org, lorenzo.bianconi@redhat.com Subject: [RFC bpf-next 7/8] bpf: devmap: check XDP features in bpf_map_update_elem and __xdp_enqueue Date: Mon, 19 Dec 2022 16:41:36 +0100 Message-Id: <9e15c15f2ee134f628fc286e123ec85e40617b35.1671462951.git.lorenzo@kernel.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC When we update devmap element, the net_device whose ifindex is specified in map value must support ndo_xdp_xmit callback, which is indicated by the presence of XDP_F_REDIRECT_TARGET feature. Let's check for this feature and return an error if device cannot be used as a redirect target. Moreover check the device support xdp non-linear frame in __xdp_enqueue and is_valid_dst routines. This patch allows to perfrom XDP_REDIRECT on non-linear xdp buffers. Co-developed-by: Kumar Kartikeya Dwivedi Signed-off-by: Kumar Kartikeya Dwivedi Signed-off-by: Lorenzo Bianconi --- kernel/bpf/devmap.c | 25 +++++++++++++++++++++---- net/core/filter.c | 13 +++++-------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c index d01e4c55b376..16199eb5c7a6 100644 --- a/kernel/bpf/devmap.c +++ b/kernel/bpf/devmap.c @@ -474,7 +474,11 @@ static inline int __xdp_enqueue(struct net_device *dev, struct xdp_frame *xdpf, { int err; - if (!dev->netdev_ops->ndo_xdp_xmit) + if (!(dev->xdp_features & XDP_F_REDIRECT_TARGET)) + return -EOPNOTSUPP; + + if (unlikely(!(dev->xdp_features & XDP_F_FRAG_TARGET) && + xdp_frame_has_frags(xdpf))) return -EOPNOTSUPP; err = xdp_ok_fwd_dev(dev, xdp_get_frame_len(xdpf)); @@ -532,8 +536,14 @@ int dev_map_enqueue(struct bpf_dtab_netdev *dst, struct xdp_frame *xdpf, static bool is_valid_dst(struct bpf_dtab_netdev *obj, struct xdp_frame *xdpf) { - if (!obj || - !obj->dev->netdev_ops->ndo_xdp_xmit) + if (!obj) + return false; + + if (!(obj->dev->xdp_features & XDP_F_REDIRECT_TARGET)) + return false; + + if (unlikely(!(obj->dev->xdp_features & XDP_F_FRAG_TARGET) && + xdp_frame_has_frags(xdpf))) return false; if (xdp_ok_fwd_dev(obj->dev, xdp_get_frame_len(xdpf))) @@ -843,6 +853,7 @@ static struct bpf_dtab_netdev *__dev_map_alloc_node(struct net *net, { struct bpf_prog *prog = NULL; struct bpf_dtab_netdev *dev; + int ret = -EINVAL; dev = bpf_map_kmalloc_node(&dtab->map, sizeof(*dev), GFP_NOWAIT | __GFP_NOWARN, @@ -854,6 +865,12 @@ static struct bpf_dtab_netdev *__dev_map_alloc_node(struct net *net, if (!dev->dev) goto err_out; + /* Check if net_device can be used as a redirect target */ + if (!(READ_ONCE(dev->dev->xdp_features) & XDP_F_REDIRECT_TARGET)) { + ret = -EOPNOTSUPP; + goto err_put_dev; + } + if (val->bpf_prog.fd > 0) { prog = bpf_prog_get_type_dev(val->bpf_prog.fd, BPF_PROG_TYPE_XDP, false); @@ -882,7 +899,7 @@ static struct bpf_dtab_netdev *__dev_map_alloc_node(struct net *net, dev_put(dev->dev); err_out: kfree(dev); - return ERR_PTR(-EINVAL); + return ERR_PTR(ret); } static int __dev_map_update_elem(struct net *net, struct bpf_map *map, diff --git a/net/core/filter.c b/net/core/filter.c index 929358677183..c2bd1935b55a 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -4282,16 +4282,13 @@ int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp, struct bpf_redirect_info *ri = this_cpu_ptr(&bpf_redirect_info); enum bpf_map_type map_type = ri->map_type; - /* XDP_REDIRECT is not fully supported yet for xdp frags since - * not all XDP capable drivers can map non-linear xdp_frame in - * ndo_xdp_xmit. - */ - if (unlikely(xdp_buff_has_frags(xdp) && - map_type != BPF_MAP_TYPE_CPUMAP)) - return -EOPNOTSUPP; + if (map_type == BPF_MAP_TYPE_XSKMAP) { + /* XDP_REDIRECT is not supported AF_XDP yet. */ + if (unlikely(xdp_buff_has_frags(xdp))) + return -EOPNOTSUPP; - if (map_type == BPF_MAP_TYPE_XSKMAP) return __xdp_do_redirect_xsk(ri, dev, xdp, xdp_prog); + } return __xdp_do_redirect_frame(ri, dev, xdp_convert_buff_to_frame(xdp), xdp_prog); From patchwork Mon Dec 19 15:41:37 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 13076730 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8390EC4332F for ; Mon, 19 Dec 2022 15:43:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232527AbiLSPnh (ORCPT ); Mon, 19 Dec 2022 10:43:37 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58058 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232135AbiLSPnK (ORCPT ); Mon, 19 Dec 2022 10:43:10 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2B4BC12630; Mon, 19 Dec 2022 07:42:52 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 8FA8F6102F; Mon, 19 Dec 2022 15:42:51 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 43247C433EF; Mon, 19 Dec 2022 15:42:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1671464571; bh=m3H+RKHqgvTIfSuFUP9wRf0/5Mxu+/ip+APt54T/WV0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=sHZlCnS9YDgDtfuhaLaQPsE+WvcHinf4sgnawryBXRuzrra6e5uXC0PdULQjR25el gEFqqnwzg61BBgscWIbKxTlw0fAhhl3PqjxKD32qWr+cFKFvwqc7iH+SOftIIyW0OH iH2mJHLbtjlGROyvJlC/F071tXSWbX+bPp90SqQhH4llx00nZVcu0OLsWj0/h6edeS DmAjt4jKq9oT/pJQ808PEgXLRCtK5DFlukDBQuWJKuh1VTrpn4/ky414x6LDqJuZQZ rv8gKggr2HvDxl5gAoGTZdYNBf6FUdDsfBMHXTNGVNzSbkMJFTmY9dEjtfD7o4OOvr AcDAzGcJDfL6g== From: Lorenzo Bianconi To: bpf@vger.kernel.org Cc: netdev@vger.kernel.org, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, davem@davemloft.net, kuba@kernel.org, hawk@kernel.org, pabeni@redhat.com, edumazet@google.com, toke@redhat.com, memxor@gmail.com, alardam@gmail.com, saeedm@nvidia.com, anthony.l.nguyen@intel.com, gospo@broadcom.com, vladimir.oltean@nxp.com, nbd@nbd.name, john@phrozen.org, leon@kernel.org, simon.horman@corigine.com, aelior@marvell.com, christophe.jaillet@wanadoo.fr, ecree.xilinx@gmail.com, grygorii.strashko@ti.com, mst@redhat.com, bjorn@kernel.org, magnus.karlsson@intel.com, maciej.fijalkowski@intel.com, intel-wired-lan@lists.osuosl.org, lorenzo.bianconi@redhat.com Subject: [RFC bpf-next 8/8] selftests/bpf: introduce XDP compliance test tool Date: Mon, 19 Dec 2022 16:41:37 +0100 Message-Id: <9ce76ae541e267ba5cce9658c0f712b93977b407.1671462951.git.lorenzo@kernel.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC Introduce xdp_features tool in order to test XDP features supported by the NIC and match them against advertised ones. In order to test supported/advertised XDP features, xdp_features must run on the Device Under Test (DUT) and on a Tester device. xdp_features opens a control TCP channel between DUT and Tester devices to send control commands from Tester to the DUT and a UDP data channel where the Tester sends UDP 'echo' packets and the DUT is expected to reply back with the same packet. DUT installs multiple XDP programs on the NIC to test XDP capabilities and reports back to the Tester some XDP stats. Currently xdp_features supports the following XDP features: - XDP_DROP - XDP_PASS - XDP_TX - XDP_REDIRECT - XDP_REDIRECT_TARGET Co-developed-by: Kumar Kartikeya Dwivedi Signed-off-by: Kumar Kartikeya Dwivedi Signed-off-by: Lorenzo Bianconi --- tools/testing/selftests/bpf/Makefile | 5 +- .../selftests/bpf/progs/test_xdp_features.c | 235 ++++++ .../selftests/bpf/test_xdp_features.sh | 99 +++ tools/testing/selftests/bpf/xdp_features.c | 745 ++++++++++++++++++ 4 files changed, 1082 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/bpf/progs/test_xdp_features.c create mode 100755 tools/testing/selftests/bpf/test_xdp_features.sh create mode 100644 tools/testing/selftests/bpf/xdp_features.c diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index c22c43bbee19..c485739dd452 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -73,7 +73,8 @@ TEST_PROGS := test_kmod.sh \ test_bpftool.sh \ test_bpftool_metadata.sh \ test_doc_build.sh \ - test_xsk.sh + test_xsk.sh \ + test_xdp_features.sh TEST_PROGS_EXTENDED := with_addr.sh \ with_tunnels.sh ima_setup.sh verify_sig_setup.sh \ @@ -83,7 +84,7 @@ TEST_PROGS_EXTENDED := with_addr.sh \ TEST_GEN_PROGS_EXTENDED = test_sock_addr test_skb_cgroup_id_user \ flow_dissector_load test_flow_dissector test_tcp_check_syncookie_user \ test_lirc_mode2_user xdping test_cpp runqslower bench bpf_testmod.ko \ - xskxceiver xdp_redirect_multi xdp_synproxy veristat + xskxceiver xdp_redirect_multi xdp_synproxy veristat xdp_features TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read $(OUTPUT)/sign-file TEST_GEN_FILES += liburandom_read.so diff --git a/tools/testing/selftests/bpf/progs/test_xdp_features.c b/tools/testing/selftests/bpf/progs/test_xdp_features.c new file mode 100644 index 000000000000..6542364693c9 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_xdp_features.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct xdp_cpumap_stats { + unsigned int redirect; + unsigned int pass; + unsigned int drop; +}; + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, __u32); + __type(value, __u32); + __uint(max_entries, 1); +} stats SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, __u32); + __type(value, __u32); + __uint(max_entries, 1); +} dut_stats SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_CPUMAP); + __uint(key_size, sizeof(__u32)); + __uint(value_size, sizeof(struct bpf_cpumap_val)); + __uint(max_entries, 1); +} cpu_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP); + __uint(key_size, sizeof(__u32)); + __uint(value_size, sizeof(struct bpf_devmap_val)); + __uint(max_entries, 1); +} dev_map SEC(".maps"); + +const volatile __u32 expected_feature = XDP_FEATURES_FIELD_FLAG(XDP_F_PASS_BIT); +const volatile __be32 tester_ip; +const volatile __be32 dut_ip; + +#define ECHO_PORT 12346 + +/* test commands */ +enum test_commands { + CMD_STOP, /* CMD */ + CMD_START, /* CMD + xdp feature */ + CMD_ECHO, /* CMD */ + CMD_ACK, /* CMD + data */ + CMD_GET_XDP_CAP, /* CMD */ + CMD_GET_STATS, /* CMD */ +}; + +struct tlv_hdr { + __be16 type; + __be16 len; + __be32 data[]; +}; + +static __always_inline int xdp_process_echo_packet(struct xdp_md *xdp, bool dut) +{ + void *data_end = (void *)(long)xdp->data_end; + __be32 saddr = dut ? tester_ip : dut_ip; + __be32 daddr = dut ? dut_ip : tester_ip; + void *data = (void *)(long)xdp->data; + struct ethhdr *eh = data; + struct tlv_hdr *tlv; + struct udphdr *uh; + struct iphdr *ih; + __be16 port; + __u8 *cmd; + + if (eh + 1 > (struct ethhdr *)data_end) + return -EINVAL; + + if (eh->h_proto != bpf_htons(ETH_P_IP)) + return -EINVAL; + + ih = (struct iphdr *)(eh + 1); + if (ih + 1 > (struct iphdr *)data_end) + return -EINVAL; + + if (saddr != ih->saddr) + return -EINVAL; + + if (daddr != ih->daddr) + return -EINVAL; + + if (ih->protocol != IPPROTO_UDP) + return -EINVAL; + + uh = (struct udphdr *)(ih + 1); + if (uh + 1 > (struct udphdr *)data_end) + return -EINVAL; + + port = dut ? uh->dest : uh->source; + if (port != bpf_htons(ECHO_PORT)) + return -EINVAL; + + tlv = (struct tlv_hdr *)(uh + 1); + if (tlv + 1 > data_end) + return -EINVAL; + + return bpf_htons(tlv->type) == CMD_ECHO ? 0 : -EINVAL; +} + +SEC("xdp") +int xdp_tester(struct xdp_md *xdp) +{ + __u32 *val, key = 0; + + switch (expected_feature) { + case XDP_FEATURES_FIELD_FLAG(XDP_F_REDIRECT_TARGET_BIT): + case XDP_FEATURES_FIELD_FLAG(XDP_F_TX_BIT): + if (xdp_process_echo_packet(xdp, true)) + goto out; + break; + case XDP_FEATURES_FIELD_FLAG(XDP_F_DROP_BIT): + case XDP_FEATURES_FIELD_FLAG(XDP_F_PASS_BIT): + case XDP_FEATURES_FIELD_FLAG(XDP_F_REDIRECT_BIT): + if (xdp_process_echo_packet(xdp, false)) + goto out; + break; + default: + goto out; + } + + val = bpf_map_lookup_elem(&stats, &key); + if (val) + __sync_add_and_fetch(val, 1); + +out: + return XDP_PASS; +} + +SEC("xdp") +int xdp_do_pass(struct xdp_md *xdp) +{ + __u32 *val, key = 0; + + val = bpf_map_lookup_elem(&dut_stats, &key); + if (val) + __sync_add_and_fetch(val, 1); + + return XDP_PASS; +} + +SEC("xdp") +int xdp_do_drop(struct xdp_md *xdp) +{ + __u32 *val, key = 0; + + if (xdp_process_echo_packet(xdp, true)) + return XDP_PASS; + + val = bpf_map_lookup_elem(&dut_stats, &key); + if (val) + __sync_add_and_fetch(val, 1); + + return XDP_DROP; +} + +SEC("xdp") +int xdp_do_tx(struct xdp_md *xdp) +{ + void *data = (void *)(long)xdp->data; + struct ethhdr *eh = data; + __u8 tmp_mac[ETH_ALEN]; + __u32 *val, key = 0; + + if (xdp_process_echo_packet(xdp, true)) + return XDP_PASS; + + __builtin_memcpy(tmp_mac, eh->h_source, ETH_ALEN); + __builtin_memcpy(eh->h_source, eh->h_dest, ETH_ALEN); + __builtin_memcpy(eh->h_dest, tmp_mac, ETH_ALEN); + + val = bpf_map_lookup_elem(&dut_stats, &key); + if (val) + __sync_add_and_fetch(val, 1); + + return XDP_TX; +} + +SEC("xdp") +int xdp_do_redirect(struct xdp_md *xdp) +{ + if (xdp_process_echo_packet(xdp, true)) + return XDP_PASS; + + return bpf_redirect_map(&cpu_map, 0, 0); +} + +SEC("tp_btf/xdp_cpumap_kthread") +int BPF_PROG(tp_xdp_cpumap_kthread, int map_id, unsigned int processed, + unsigned int drops, int sched, struct xdp_cpumap_stats *xdp_stats) +{ + __u32 *val, key = 0; + + val = bpf_map_lookup_elem(&dut_stats, &key); + if (val) + __sync_add_and_fetch(val, 1); + + return 0; +} + +SEC("xdp/cpumap") +int xdp_do_redirect_cpumap(struct xdp_md *xdp) +{ + void *data = (void *)(long)xdp->data; + struct ethhdr *eh = data; + __u8 tmp_mac[ETH_ALEN]; + + if (xdp_process_echo_packet(xdp, true)) + return XDP_PASS; + + __builtin_memcpy(tmp_mac, eh->h_source, ETH_ALEN); + __builtin_memcpy(eh->h_source, eh->h_dest, ETH_ALEN); + __builtin_memcpy(eh->h_dest, tmp_mac, ETH_ALEN); + + return bpf_redirect_map(&dev_map, 0, 0); +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_xdp_features.sh b/tools/testing/selftests/bpf/test_xdp_features.sh new file mode 100755 index 000000000000..2f6e9c879432 --- /dev/null +++ b/tools/testing/selftests/bpf/test_xdp_features.sh @@ -0,0 +1,99 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# Create 2 namespaces with two veth peers, and +# check reported and detected XDP capabilities +# +# NS0(v00) NS1(v11) +# | | +# | | +# (v01, id:111) ------ (v10,id:222) + +readonly NS0="ns1-$(mktemp -u XXXXXX)" +readonly NS1="ns2-$(mktemp -u XXXXXX)" +ret=1 + +setup() { + { + ip netns add ${NS0} + ip netns add ${NS1} + + ip link add v01 index 111 type veth peer name v00 netns ${NS0} + ip link add v10 index 222 type veth peer name v11 netns ${NS1} + + ip link set v01 up + ip addr add 10.10.0.1/24 dev v01 + ip link set v01 address 00:11:22:33:44:55 + ip -n ${NS0} link set dev v00 up + ip -n ${NS0} addr add 10.10.0.11/24 dev v00 + ip -n ${NS0} route add default via 10.10.0.1 + ip -n ${NS0} link set v00 address 00:12:22:33:44:55 + + ip link set v10 up + ip addr add 10.10.1.1/24 dev v10 + ip link set v10 address 00:13:22:33:44:55 + ip -n ${NS1} link set dev v11 up + ip -n ${NS1} addr add 10.10.1.11/24 dev v11 + ip -n ${NS1} route add default via 10.10.1.1 + ip -n ${NS1} link set v11 address 00:14:22:33:44:55 + + sysctl -w net.ipv4.ip_forward=1 + # Enable XDP mode + ethtool -K v01 gro on + ethtool -K v01 tx-checksumming off + ip netns exec ${NS0} ethtool -K v00 gro on + ip netns exec ${NS0} ethtool -K v00 tx-checksumming off + ethtool -K v10 gro on + ethtool -K v10 tx-checksumming off + ip netns exec ${NS1} ethtool -K v11 gro on + ip netns exec ${NS1} ethtool -K v11 tx-checksumming off + } > /dev/null 2>&1 +} + +cleanup() { + ip link del v01 2> /dev/null + ip link del v10 2> /dev/null + ip netns del ${NS0} 2> /dev/null + ip netns del ${NS1} 2> /dev/null + [ "$(pidof xdp_features)" = "" ] || kill $(pidof xdp_features) 2> /dev/null +} + +test_xdp_features() { + setup + + ## XDP_PASS + ip netns exec ${NS1} ./xdp_features -f XDP_PASS -D 10.10.1.11 -T 10.10.0.11 v11 & + ip netns exec ${NS0} ./xdp_features -t -f XDP_PASS -D 10.10.1.11 -C 10.10.1.11 -T 10.10.0.11 v00 + + [ $? -ne 0 ] && exit + + # XDP_DROP + ip netns exec ${NS1} ./xdp_features -f XDP_DROP -D 10.10.1.11 -T 10.10.0.11 v11 & + ip netns exec ${NS0} ./xdp_features -t -f XDP_DROP -D 10.10.1.11 -C 10.10.1.11 -T 10.10.0.11 v00 + + [ $? -ne 0 ] && exit + + ## XDP_TX + ./xdp_features -f XDP_TX -D 10.10.0.1 -T 10.10.0.11 v01 & + ip netns exec ${NS0} ./xdp_features -t -f XDP_TX -D 10.10.0.1 -C 10.10.0.1 -T 10.10.0.11 v00 + + ## XDP_REDIRECT + ip netns exec ${NS1} ./xdp_features -f XDP_REDIRECT -D 10.10.1.11 -T 10.10.0.11 v11 & + ip netns exec ${NS0} ./xdp_features -t -f XDP_REDIRECT -D 10.10.1.11 -C 10.10.1.11 -T 10.10.0.11 v00 + + [ $? -ne 0 ] && exit + + ## XDP_REDIRECT_TARGET + ./xdp_features -f XDP_REDIRECT_TARGET -D 10.10.0.1 -T 10.10.0.11 v01 & + ip netns exec ${NS0} ./xdp_features -t -f XDP_REDIRECT_TARGET -D 10.10.0.1 -C 10.10.0.1 -T 10.10.0.11 v00 + + ret=$? + cleanup +} + +set -e +trap cleanup 2 3 6 9 + +test_xdp_features + +exit $ret diff --git a/tools/testing/selftests/bpf/xdp_features.c b/tools/testing/selftests/bpf/xdp_features.c new file mode 100644 index 000000000000..8345a160308f --- /dev/null +++ b/tools/testing/selftests/bpf/xdp_features.c @@ -0,0 +1,745 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_xdp_features.skel.h" + +#define RED(str) "\033[0;31m" str "\033[0m" +#define GREEN(str) "\033[0;32m" str "\033[0m" +#define YELLOW(str) "\033[0;33m" str "\033[0m" + +static struct env { + bool verbosity; + int ifindex; + unsigned int feature; + bool tester; + in_addr_t dut_ctrl_ip; + in_addr_t dut_ip; + in_addr_t tester_ip; +} env; + +#define DUT_CTRL_PORT 12345 +#define DUT_ECHO_PORT 12346 + +/* test commands */ +enum test_commands { + CMD_STOP, /* CMD */ + CMD_START, /* CMD + xdp feature */ + CMD_ECHO, /* CMD */ + CMD_ACK, /* CMD + data */ + CMD_GET_XDP_CAP, /* CMD */ + CMD_GET_STATS, /* CMD */ +}; + +struct tlv_hdr { + __be16 type; + __be16 len; + __be32 data[]; +}; + +#define BUFSIZE 128 + +static int libbpf_print_fn(enum libbpf_print_level level, + const char *format, va_list args) +{ + if (level == LIBBPF_DEBUG && !env.verbosity) + return 0; + return vfprintf(stderr, format, args); +} + +static volatile bool exiting; + +static void sig_handler(int sig) +{ + exiting = true; +} + +const char *argp_program_version = "xdp-features 0.0"; +const char argp_program_doc[] = +"XDP features detecion application.\n" +"\n" +"XDP features application checks the XDP advertised features match detected ones.\n" +"\n" +"USAGE: ./xdp-features [-vt] [-f ] [-D ] [-T ] [-C ] \n" +"\n" +"XDP features\n:" +"- XDP_PASS\n" +"- XDP_DROP\n" +"- XDP_ABORTED\n" +"- XDP_REDIRECT\n" +"- XDP_REDIRECT_TARGET\n" +"- XDP_TX\n"; + +static const struct argp_option opts[] = { + { "verbose", 'v', NULL, 0, "Verbose debug output" }, + { "tester", 't', NULL, 0, "Tester mode" }, + { "feature", 'f', "XDP-FEATURE", 0, "XDP feature to test" }, + { "dut_data_ip", 'D', "DUT-DATA-IP", 0, "DUT IP data channel" }, + { "dut_ctrl_ip", 'C', "DUT-CTRL-IP", 0, "DUT IP control channel" }, + { "tester_data_ip", 'T', "TESTER-DATA-IP", 0, "Tester IP data channel" }, + {}, +}; + +static int get_xdp_feature(const char *arg) +{ + if (!strcmp(arg, "XDP_PASS")) + return XDP_FEATURES_FIELD_FLAG(XDP_F_PASS_BIT); + else if (!strcmp(arg, "XDP_DROP")) + return XDP_FEATURES_FIELD_FLAG(XDP_F_DROP_BIT); + else if (!strcmp(arg, "XDP_ABORTED")) + return XDP_FEATURES_FIELD_FLAG(XDP_F_ABORTED_BIT); + else if (!strcmp(arg, "XDP_REDIRECT")) + return XDP_FEATURES_FIELD_FLAG(XDP_F_REDIRECT_BIT); + else if (!strcmp(arg, "XDP_REDIRECT_TARGET")) + return XDP_FEATURES_FIELD_FLAG(XDP_F_REDIRECT_TARGET_BIT); + else if (!strcmp(arg, "XDP_TX")) + return XDP_FEATURES_FIELD_FLAG(XDP_F_TX_BIT); + + return -EINVAL; +} + +static char *get_xdp_feature_str(int feature) +{ + switch (feature) { + case XDP_FEATURES_FIELD_FLAG(XDP_F_PASS_BIT): + return YELLOW("XDP_PASS"); + case XDP_FEATURES_FIELD_FLAG(XDP_F_DROP_BIT): + return YELLOW("XDP_DROP"); + case XDP_FEATURES_FIELD_FLAG(XDP_F_ABORTED_BIT): + return YELLOW("XDP_ABORTED"); + case XDP_FEATURES_FIELD_FLAG(XDP_F_TX_BIT): + return YELLOW("XDP_TX"); + case XDP_FEATURES_FIELD_FLAG(XDP_F_REDIRECT_BIT): + return YELLOW("XDP_REDIRECT"); + case XDP_FEATURES_FIELD_FLAG(XDP_F_REDIRECT_TARGET_BIT): + return YELLOW("XDP_REDIRECT_TARGET"); + default: + return ""; + } +} + +static error_t parse_arg(int key, char *arg, struct argp_state *state) +{ + switch (key) { + case 'v': + env.verbosity = true; + break; + case 't': + env.tester = true; + break; + case 'f': + env.feature = get_xdp_feature(arg); + if (env.feature < 0) { + fprintf(stderr, "Invalid xdp feature: %s\n", arg); + argp_usage(state); + return ARGP_ERR_UNKNOWN; + } + break; + case 'D': + env.dut_ip = inet_addr(arg); + if (env.dut_ip < 0) + return ARGP_ERR_UNKNOWN; + break; + case 'C': + env.dut_ctrl_ip = inet_addr(arg); + if (env.dut_ctrl_ip < 0) + return ARGP_ERR_UNKNOWN; + break; + case 'T': + env.tester_ip = inet_addr(arg); + if (env.tester_ip < 0) + return ARGP_ERR_UNKNOWN; + break; + case ARGP_KEY_ARG: + errno = 0; + if (strlen(arg) >= IF_NAMESIZE) { + fprintf(stderr, "Invalid device name: %s\n", arg); + argp_usage(state); + return ARGP_ERR_UNKNOWN; + } + + env.ifindex = if_nametoindex(arg); + if (!env.ifindex) + env.ifindex = strtoul(arg, NULL, 0); + if (!env.ifindex) { + fprintf(stderr, + "Bad interface index or name (%d): %s\n", + errno, strerror(errno)); + argp_usage(state); + return ARGP_ERR_UNKNOWN; + } + break; + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + +static const struct argp argp = { + .options = opts, + .parser = parse_arg, + .doc = argp_program_doc, +}; + +static void set_env_defaul(void) +{ + env.feature = XDP_FEATURES_FIELD_FLAG(XDP_F_PASS_BIT); + env.ifindex = -ENODEV; + env.dut_ctrl_ip = inet_addr("127.0.0.1"); + env.dut_ip = inet_addr("127.0.0.1"); + env.tester_ip = inet_addr("127.0.0.1"); +} + +static void *dut_echo_thread(void *arg) +{ + unsigned char buf[sizeof(struct tlv_hdr)]; + int sockfd = *(int *)arg; + + while (!exiting) { + unsigned int len = sizeof(struct sockaddr_in); + struct sockaddr_in addr; + struct tlv_hdr *tlv = (struct tlv_hdr *)buf; + size_t n; + + n = recvfrom(sockfd, buf, sizeof(buf), MSG_WAITALL, + (struct sockaddr *)&addr, &len); + if (n != ntohs(tlv->len)) + continue; + + if (ntohs(tlv->type) != CMD_ECHO) + continue; + + sendto(sockfd, buf, sizeof(buf), MSG_NOSIGNAL | MSG_CONFIRM, + (struct sockaddr *)&addr, sizeof(addr)); + } + + pthread_exit((void *)0); + close(sockfd); + + return NULL; +} + +static int dut_run_echo_thread(pthread_t *t, int *echo_sockfd) +{ + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = htonl(INADDR_ANY), + .sin_port = htons(DUT_ECHO_PORT), + }; + int err, sockfd, optval = 1; + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) { + fprintf(stderr, "Failed to create echo socket\n"); + return -errno; + } + + err = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, + sizeof(optval)); + if (err < 0) { + fprintf(stderr, "Failed sockopt on echo socket\n"); + return -errno; + } + + err = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + if (err) { + fprintf(stderr, "Failed to bind echo socket\n"); + return -errno; + } + + /* start echo channel */ + *echo_sockfd = sockfd; + err = pthread_create(t, NULL, dut_echo_thread, echo_sockfd); + if (err) { + fprintf(stderr, "Failed creating dut_echo thread: %s\n", + strerror(-err)); + close(sockfd); + return -EINVAL; + } + + return 0; +} + +static int dut_attach_xdp_prog(struct test_xdp_features *skel, int feature, + int flags) +{ + struct bpf_program *prog; + unsigned int key = 0; + int err, fd = 0; + + switch (feature) { + case XDP_FEATURES_FIELD_FLAG(XDP_F_TX_BIT): + prog = skel->progs.xdp_do_tx; + break; + case XDP_FEATURES_FIELD_FLAG(XDP_F_DROP_BIT): + case XDP_FEATURES_FIELD_FLAG(XDP_F_ABORTED_BIT): + prog = skel->progs.xdp_do_drop; + break; + case XDP_FEATURES_FIELD_FLAG(XDP_F_PASS_BIT): + prog = skel->progs.xdp_do_pass; + break; + case XDP_FEATURES_FIELD_FLAG(XDP_F_REDIRECT_TARGET_BIT): { + struct bpf_devmap_val entry = { + .ifindex = env.ifindex, + }; + + err = bpf_map__update_elem(skel->maps.dev_map, + &key, sizeof(key), + &entry, sizeof(entry), 0); + if (err < 0) + return err; + + fd = bpf_program__fd(skel->progs.xdp_do_redirect_cpumap); + } + case XDP_FEATURES_FIELD_FLAG(XDP_F_REDIRECT_BIT): { + struct bpf_cpumap_val entry = { + .qsize = 2048, + .bpf_prog.fd = fd, + }; + + err = bpf_map__update_elem(skel->maps.cpu_map, + &key, sizeof(key), + &entry, sizeof(entry), 0); + if (err < 0) + return err; + + prog = skel->progs.xdp_do_redirect; + break; + } + default: + return -EINVAL; + } + + err = bpf_xdp_attach(env.ifindex, bpf_program__fd(prog), flags, NULL); + if (err) + fprintf(stderr, + "Failed to attach XDP program to ifindex %d\n", + env.ifindex); + return err; +} + +static int __recv_msg(int sockfd, void *buf, size_t bufsize, + unsigned int *val, unsigned int val_size) +{ + struct tlv_hdr *tlv = (struct tlv_hdr *)buf; + int len, n = sizeof(*tlv), i = 0; + + len = recv(sockfd, buf, bufsize, 0); + if (len != ntohs(tlv->len)) + return -EINVAL; + + while (n < len && i < val_size) { + val[i] = ntohl(tlv->data[i]); + n += sizeof(tlv->data[0]); + i++; + } + + return i; +} + +static int recv_msg(int sockfd, void *buf, size_t bufsize) +{ + return __recv_msg(sockfd, buf, bufsize, NULL, 0); +} + +static int dut_run(struct test_xdp_features *skel) +{ + int flags = XDP_FLAGS_UPDATE_IF_NOEXIST | XDP_FLAGS_DRV_MODE; + int state, err, sockfd, ctrl_sockfd, echo_sockfd, optval = 1; + struct sockaddr_in ctrl_addr, addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = htonl(INADDR_ANY), + .sin_port = htons(DUT_CTRL_PORT), + }; + unsigned int len = sizeof(ctrl_addr); + pthread_t dut_thread; + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + fprintf(stderr, "Failed to create DUT socket\n"); + return -errno; + } + + err = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, + sizeof(optval)); + if (err < 0) { + fprintf(stderr, "Failed sockopt on DUT socket\n"); + return -errno; + } + + err = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + if (err < 0) { + fprintf(stderr, "Failed to bind DUT socket\n"); + return -errno; + } + + err = listen(sockfd, 5); + if (err) { + fprintf(stderr, "Failed to listen DUT socket\n"); + return -errno; + } + + ctrl_sockfd = accept(sockfd, (struct sockaddr *)&ctrl_addr, &len); + if (ctrl_sockfd < 0) { + fprintf(stderr, "Failed to accept connection on DUT socket\n"); + close(sockfd); + return -errno; + } + + /* CTRL loop */ + while (!exiting) { + unsigned char buf[BUFSIZE] = {}; + struct tlv_hdr *tlv = (struct tlv_hdr *)buf; + + err = recv_msg(ctrl_sockfd, buf, BUFSIZE); + if (err) + continue; + + switch (ntohs(tlv->type)) { + case CMD_START: { + if (state == CMD_START) + continue; + + state = CMD_START; + /* Load the XDP program on the DUT */ + err = dut_attach_xdp_prog(skel, ntohl(tlv->data[0]), flags); + if (err) + goto out; + + err = dut_run_echo_thread(&dut_thread, &echo_sockfd); + if (err < 0) + goto out; + + tlv->type = htons(CMD_ACK); + tlv->len = htons(sizeof(*tlv)); + err = send(ctrl_sockfd, buf, sizeof(*tlv), 0); + if (err < 0) + goto end_thread; + break; + } + case CMD_STOP: + if (state != CMD_START) + break; + + state = CMD_STOP; + + exiting = true; + bpf_xdp_detach(env.ifindex, flags, NULL); + + tlv->type = htons(CMD_ACK); + tlv->len = htons(sizeof(*tlv)); + err = send(ctrl_sockfd, buf, sizeof(*tlv), 0); + goto end_thread; + case CMD_GET_XDP_CAP: { + unsigned int xdp_cap[XDP_FEATURES_WORDS] = {}; + unsigned int xdp_cap_size = ARRAY_SIZE(xdp_cap); + size_t n; + int i; + + err = bpf_xdp_query_features(env.ifindex, xdp_cap, + &xdp_cap_size); + if (err < 0) { + fprintf(stderr, + "Failed to query XDP cap for ifindex %d\n", + env.ifindex); + goto end_thread; + } + + tlv->type = htons(CMD_ACK); + n = sizeof(*tlv) + xdp_cap_size * sizeof(xdp_cap[0]); + tlv->len = htons(n); + for (i = 0; i < xdp_cap_size; i++) + tlv->data[i] = htonl(xdp_cap[i]); + + err = send(ctrl_sockfd, buf, n, 0); + if (err < 0) + goto end_thread; + break; + } + case CMD_GET_STATS: { + unsigned int key = 0, val; + size_t n; + + err = bpf_map__lookup_elem(skel->maps.dut_stats, + &key, sizeof(key), + &val, sizeof(val), 0); + if (err) { + fprintf(stderr, "bpf_map_lookup_elem failed\n"); + goto end_thread; + } + + tlv->type = htons(CMD_ACK); + n = sizeof(*tlv) + sizeof(val); + tlv->len = htons(n); + tlv->data[0] = htonl(val); + + err = send(ctrl_sockfd, buf, n, 0); + if (err < 0) + goto end_thread; + break; + } + default: + break; + } + } + +end_thread: + pthread_join(dut_thread, NULL); +out: + bpf_xdp_detach(env.ifindex, flags, NULL); + close(ctrl_sockfd); + close(sockfd); + + return err; +} + +static bool tester_collect_advertised_cap(unsigned int cap) +{ + return cap & env.feature; +} + +static bool tester_collect_detected_cap(struct test_xdp_features *skel, + unsigned int dut_stats) +{ + unsigned int err, key = 0, val; + + if (!dut_stats) + return false; + + err = bpf_map__lookup_elem(skel->maps.stats, &key, sizeof(key), + &val, sizeof(val), 0); + if (err) { + fprintf(stderr, "bpf_map_lookup_elem failed\n"); + return false; + } + + switch (env.feature) { + case XDP_FEATURES_FIELD_FLAG(XDP_F_PASS_BIT): + case XDP_FEATURES_FIELD_FLAG(XDP_F_TX_BIT): + case XDP_FEATURES_FIELD_FLAG(XDP_F_REDIRECT_BIT): + case XDP_FEATURES_FIELD_FLAG(XDP_F_REDIRECT_TARGET_BIT): + return val > 0; + case XDP_FEATURES_FIELD_FLAG(XDP_F_DROP_BIT): + case XDP_FEATURES_FIELD_FLAG(XDP_F_ABORTED_BIT): + return val == 0; + default: + return false; + } +} + +static int __send_and_recv_msg(int sockfd, enum test_commands cmd, + unsigned int *val, unsigned int val_size) +{ + unsigned char buf[BUFSIZE] = {}; + struct tlv_hdr *tlv = (struct tlv_hdr *)buf; + int n = sizeof(*tlv), err; + + tlv->type = htons(cmd); + switch (cmd) { + case CMD_START: + tlv->data[0] = htonl(env.feature); + n += sizeof(*val); + break; + default: + break; + } + tlv->len = htons(n); + + err = send(sockfd, buf, n, 0); + if (err < 0) + return err; + + err = __recv_msg(sockfd, buf, BUFSIZE, val, val_size); + if (err < 0) + return err; + + return ntohs(tlv->type) == CMD_ACK ? 0 : -EINVAL; +} + +static int send_and_recv_msg(int sockfd, enum test_commands cmd) +{ + return __send_and_recv_msg(sockfd, cmd, NULL, 0); +} + +static int send_echo_msg(void) +{ + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = env.dut_ip, + .sin_port = htons(DUT_ECHO_PORT), + }; + unsigned char buf[sizeof(struct tlv_hdr)]; + struct tlv_hdr *tlv = (struct tlv_hdr *)buf; + int sockfd, n; + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) { + fprintf(stderr, "Failed to create echo socket\n"); + return -errno; + } + + tlv->type = htons(CMD_ECHO); + tlv->len = htons(sizeof(*tlv)); + + n = sendto(sockfd, buf, sizeof(*tlv), MSG_NOSIGNAL | MSG_CONFIRM, + (struct sockaddr *)&addr, sizeof(addr)); + close(sockfd); + + return n == ntohs(tlv->len) ? 0 : -EINVAL; +} + +static int tester_run(struct test_xdp_features *skel) +{ + int flags = XDP_FLAGS_UPDATE_IF_NOEXIST | XDP_FLAGS_DRV_MODE; + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = env.dut_ctrl_ip, + .sin_port = htons(DUT_CTRL_PORT), + }; + bool advertised_cap; + int i, err, sockfd; + bool detected_cap; + unsigned int val[1]; + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + fprintf(stderr, "Failed to create tester socket\n"); + return -errno; + } + + for (i = 0; i < 10; i++) { + /* connect ctrl channel */ + if (!connect(sockfd, (struct sockaddr *)&addr, sizeof(addr))) + break; + sleep(1); + } + + if (i == 10) { + fprintf(stderr, "Failed to connect to the DUT\n"); + return -ETIMEDOUT; + } + + err = __send_and_recv_msg(sockfd, CMD_GET_XDP_CAP, val, ARRAY_SIZE(val)); + if (err < 0) { + close(sockfd); + return err; + } + + advertised_cap = tester_collect_advertised_cap(val[0]); + + err = bpf_xdp_attach(env.ifindex, + bpf_program__fd(skel->progs.xdp_tester), + flags, NULL); + if (err) { + fprintf(stderr, "Failed to attach XDP program to ifindex %d\n", + env.ifindex); + goto out; + } + + err = send_and_recv_msg(sockfd, CMD_START); + if (err) + goto out; + + for (i = 0; i < 10 && !exiting; i++) { + err = send_echo_msg(); + if (err < 0) + goto out; + + sleep(1); + } + + err = __send_and_recv_msg(sockfd, CMD_GET_STATS, val, ARRAY_SIZE(val)); + if (err) + goto out; + + /* stop the test */ + err = send_and_recv_msg(sockfd, CMD_STOP); + /* send a new echo message to wake echo thread of the dut */ + send_echo_msg(); + + detected_cap = tester_collect_detected_cap(skel, val[0]); + + fprintf(stdout, "Feature %s: [%s][%s]\n", get_xdp_feature_str(env.feature), + detected_cap ? GREEN("DETECTED") : RED("NOT DETECTED"), + advertised_cap ? GREEN("ADVERTISED") : RED("NOT ADVERTISED")); +out: + bpf_xdp_detach(env.ifindex, flags, NULL); + close(sockfd); + return err < 0 ? err : 0; +} + +int main(int argc, char **argv) +{ + struct test_xdp_features *skel; + int err; + + libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + + signal(SIGINT, sig_handler); + signal(SIGTERM, sig_handler); + + set_env_defaul(); + + /* Parse command line arguments */ + err = argp_parse(&argp, argc, argv, 0, NULL, NULL); + if (err) + return err; + + if (env.ifindex < 0) { + fprintf(stderr, "Invalid ifindex\n"); + return -ENODEV; + } + + /* Load and verify BPF application */ + skel = test_xdp_features__open(); + if (!skel) { + fprintf(stderr, "Failed to open and load BPF skeleton\n"); + return -EINVAL; + } + + skel->rodata->expected_feature = env.feature; + skel->rodata->dut_ip = env.dut_ip; + skel->rodata->tester_ip = env.tester_ip; + + /* Load & verify BPF programs */ + err = test_xdp_features__load(skel); + if (err) { + fprintf(stderr, "Failed to load and verify BPF skeleton\n"); + goto cleanup; + } + + err = test_xdp_features__attach(skel); + if (err) { + fprintf(stderr, "Failed to attach BPF skeleton\n"); + goto cleanup; + } + + if (env.tester) { + /* Tester */ + fprintf(stdout, "Starting tester on device %d\n", env.ifindex); + err = tester_run(skel); + } else { + /* DUT */ + fprintf(stdout, "Starting DUT on device %d\n", env.ifindex); + err = dut_run(skel); + } + +cleanup: + test_xdp_features__destroy(skel); + + return err < 0 ? -err : 0; +}