[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250422-afabre-traits-010-rfc2-v2-3-92bcc6b146c9@arthurfabre.com>
Date: Tue, 22 Apr 2025 15:23:32 +0200
From: Arthur Fabre <arthur@...hurfabre.com>
To: netdev@...r.kernel.org, bpf@...r.kernel.org
Cc: jakub@...udflare.com, hawk@...nel.org, yan@...udflare.com,
jbrandeburg@...udflare.com, thoiland@...hat.com, lbiancon@...hat.com,
ast@...nel.org, kuba@...nel.org, edumazet@...gle.com,
Arthur Fabre <arthur@...hurfabre.com>
Subject: [PATCH RFC bpf-next v2 03/17] trait: XDP support
Store the trait KV store in the xdp_buff headroom, right after the
xdp_frame.
Storing it at the front of the headroom makes it easy to add encap
headers / adjust_head(): we don't need to copy the traits out of the way
first.
But, in case we want to change this in the future, disallow traits from
being used at the same time as metadata.
Support for traits is gated on support for metadata: to propagate the
traits to the skb layer, drivers will have to explicitly signal support
like the existing skb_metadata_set() call.
This assumes there is enough headroom to store the traits header. That
avoids having to check in the hot-path, where all we could do anyways is
BUG_ON().
Signed-off-by: Arthur Fabre <arthur@...hurfabre.com>
---
include/net/xdp.h | 25 ++++++++++++++++++++-
net/core/filter.c | 7 ++++--
net/core/xdp.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 95 insertions(+), 3 deletions(-)
diff --git a/include/net/xdp.h b/include/net/xdp.h
index 16c36813cbf8631ea170d2698f1d3408286129a2..0da1e87afdebfd4323d1944de65a6d63438209bf 100644
--- a/include/net/xdp.h
+++ b/include/net/xdp.h
@@ -10,6 +10,7 @@
#include <linux/filter.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h> /* skb_shared_info */
+#include <net/trait.h>
#include <net/page_pool/types.h>
@@ -79,6 +80,7 @@ enum xdp_buff_flags {
XDP_FLAGS_META_SUPPORTED = BIT(2), /* metadata in headroom supported
* by driver
*/
+ XDP_FLAGS_TRAITS_SUPPORTED = BIT(3), /* traits in headroom supported */
};
struct xdp_buff {
@@ -118,6 +120,13 @@ static __always_inline void xdp_buff_set_frag_pfmemalloc(struct xdp_buff *xdp)
xdp->flags |= XDP_FLAGS_FRAGS_PF_MEMALLOC;
}
+#define _XDP_FRAME_SIZE (40)
+
+static __always_inline void *xdp_buff_traits(const struct xdp_buff *xdp)
+{
+ return xdp->data_hard_start + _XDP_FRAME_SIZE;
+}
+
static __always_inline void
xdp_init_buff(struct xdp_buff *xdp, u32 frame_sz, struct xdp_rxq_info *rxq)
{
@@ -137,8 +146,15 @@ xdp_prepare_buff(struct xdp_buff *xdp, unsigned char *hard_start,
xdp->data_end = data + data_len;
xdp->data_meta = data;
- if (meta_valid)
+ if (meta_valid) {
xdp->flags |= XDP_FLAGS_META_SUPPORTED;
+
+ xdp->flags |= XDP_FLAGS_TRAITS_SUPPORTED;
+ /* We assume drivers reserve enough headroom to store xdp_frame
+ * and the traits header.
+ */
+ traits_init(xdp_buff_traits(xdp), xdp->data_meta);
+ }
}
/* Reserve memory area at end-of data area.
@@ -273,6 +289,8 @@ struct xdp_frame {
u32 flags; /* supported values defined in xdp_buff_flags */
};
+static_assert(sizeof(struct xdp_frame) == _XDP_FRAME_SIZE);
+
static __always_inline bool xdp_frame_has_frags(const struct xdp_frame *frame)
{
return !!(frame->flags & XDP_FLAGS_HAS_FRAGS);
@@ -522,6 +540,11 @@ static inline bool xdp_metalen_invalid(unsigned long metalen)
return !IS_ALIGNED(metalen, sizeof(u32)) || metalen > meta_max;
}
+static __always_inline void *xdp_data_hard_start(const struct xdp_buff *xdp)
+{
+ return xdp_buff_traits(xdp) + traits_size(xdp_buff_traits(xdp));
+}
+
struct xdp_attachment_info {
struct bpf_prog *prog;
u32 flags;
diff --git a/net/core/filter.c b/net/core/filter.c
index f9b3358e274fa4b85e39509b04192c282ba2009c..909962b5d89b8f45c8963f9074e02c7cc5f1c393 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -85,6 +85,7 @@
#include <linux/un.h>
#include <net/xdp_sock_drv.h>
#include <net/inet_dscp.h>
+#include <net/trait.h>
#include "dev.h"
@@ -3942,9 +3943,8 @@ static unsigned long xdp_get_metalen(const struct xdp_buff *xdp)
BPF_CALL_2(bpf_xdp_adjust_head, struct xdp_buff *, xdp, int, offset)
{
- void *xdp_frame_end = xdp->data_hard_start + sizeof(struct xdp_frame);
unsigned long metalen = xdp_get_metalen(xdp);
- void *data_start = xdp_frame_end + metalen;
+ void *data_start = xdp_data_hard_start(xdp) + metalen;
void *data = xdp->data + offset;
if (unlikely(data < data_start ||
@@ -4247,6 +4247,9 @@ BPF_CALL_2(bpf_xdp_adjust_meta, struct xdp_buff *, xdp, int, offset)
if (unlikely(xdp_metalen_invalid(metalen)))
return -EACCES;
+ /* Traits and meta can't be used together */
+ xdp->flags &= ~XDP_FLAGS_TRAITS_SUPPORTED;
+
xdp->data_meta = meta;
return 0;
diff --git a/net/core/xdp.c b/net/core/xdp.c
index 4ee9ff9dbd0e810425e00c1e8bcc0d7088ddaad4..9b7124d52f377cf800664b3433c047f27956933e 100644
--- a/net/core/xdp.c
+++ b/net/core/xdp.c
@@ -1021,3 +1021,69 @@ void xdp_features_clear_redirect_target(struct net_device *dev)
xdp_set_features_flag(dev, val);
}
EXPORT_SYMBOL_GPL(xdp_features_clear_redirect_target);
+
+__bpf_kfunc_start_defs();
+
+__bpf_kfunc int bpf_xdp_trait_set(struct xdp_buff *xdp, u64 key,
+ const void *val, u64 val__sz, u64 flags)
+{
+ if (!(xdp->flags & XDP_FLAGS_TRAITS_SUPPORTED))
+ return -EOPNOTSUPP;
+ /* Traits and meta can't be used together */
+ xdp->flags &= ~XDP_FLAGS_META_SUPPORTED;
+
+ return trait_set(xdp_buff_traits(xdp), xdp->data, key,
+ val, val__sz, flags);
+}
+
+__bpf_kfunc int bpf_xdp_trait_is_set(struct xdp_buff *xdp, u64 key)
+{
+ if (!(xdp->flags & XDP_FLAGS_TRAITS_SUPPORTED))
+ return -EOPNOTSUPP;
+ /* Traits and meta can't be used together */
+ xdp->flags &= ~XDP_FLAGS_META_SUPPORTED;
+
+ return trait_is_set(xdp_buff_traits(xdp), key);
+}
+
+__bpf_kfunc int bpf_xdp_trait_get(struct xdp_buff *xdp, u64 key,
+ void *val, u64 val__sz)
+{
+ if (!(xdp->flags & XDP_FLAGS_TRAITS_SUPPORTED))
+ return -EOPNOTSUPP;
+ /* Traits and meta can't be used together */
+ xdp->flags &= ~XDP_FLAGS_META_SUPPORTED;
+
+ return trait_get(xdp_buff_traits(xdp), key, val, val__sz);
+}
+
+__bpf_kfunc int bpf_xdp_trait_del(struct xdp_buff *xdp, u64 key)
+{
+ if (!(xdp->flags & XDP_FLAGS_TRAITS_SUPPORTED))
+ return -EOPNOTSUPP;
+ /* Traits and meta can't be used together */
+ xdp->flags &= ~XDP_FLAGS_META_SUPPORTED;
+
+ return trait_del(xdp_buff_traits(xdp), key);
+}
+
+__bpf_kfunc_end_defs();
+
+BTF_KFUNCS_START(xdp_trait)
+BTF_ID_FLAGS(func, bpf_xdp_trait_set)
+BTF_ID_FLAGS(func, bpf_xdp_trait_is_set)
+BTF_ID_FLAGS(func, bpf_xdp_trait_get)
+BTF_ID_FLAGS(func, bpf_xdp_trait_del)
+BTF_KFUNCS_END(xdp_trait)
+
+static const struct btf_kfunc_id_set xdp_trait_kfunc_set = {
+ .owner = THIS_MODULE,
+ .set = &xdp_trait,
+};
+
+static int xdp_trait_init(void)
+{
+ return register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP,
+ &xdp_trait_kfunc_set);
+}
+late_initcall(xdp_trait_init);
--
2.43.0
Powered by blists - more mailing lists