[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250422-afabre-traits-010-rfc2-v2-17-92bcc6b146c9@arthurfabre.com>
Date: Tue, 22 Apr 2025 15:23:46 +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 17/17] trait: Allow socket filters to
access traits
Add kfuncs to allow socket filter programs access to traits in an skb.
To ensure every skb can modify traits independently, copy on write if
multiple skbs are using the same traits.
To allow new traits to be set (which requires more memory), try to use
up more of the headroom of the skb if we run out of space setting.
Signed-off-by: Arthur Fabre <arthur@...hurfabre.com>
---
include/linux/skbuff.h | 9 ++++
net/core/skbuff.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 121 insertions(+)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index ae569b1b1af83b586e1be6c69439ef74bac38cf3..e573889cf1256e7aff84b488af875a13f558cb01 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -4874,9 +4874,11 @@ void *__skb_ext_set(struct sk_buff *skb, enum skb_ext_id id,
struct skb_ext *ext);
void *skb_ext_add(struct sk_buff *skb, enum skb_ext_id id);
void *skb_ext_from_headroom(struct sk_buff *skb, enum skb_ext_id id, int head_offset, int size);
+bool skb_ext_grow_headroom(const struct sk_buff *skb, int add);
void __skb_ext_del(struct sk_buff *skb, enum skb_ext_id id);
void __skb_ext_put(struct skb_ext *ext);
int __skb_ext_total_size(const struct skb_ext *ext);
+int skb_ext_size(const struct sk_buff *skb, enum skb_ext_id id);
static inline void skb_ext_put(struct sk_buff *skb)
{
@@ -4960,6 +4962,13 @@ static inline void *skb_traits(const struct sk_buff *skb)
#endif
}
+int skb_trait_set(struct sk_buff *skb, u64 key,
+ const void *val, u64 val__sz, u64 flags);
+int skb_trait_is_set(const struct sk_buff *skb, u64 key);
+int skb_trait_get(const struct sk_buff *skb, u64 key,
+ void *val, u64 val__sz);
+int skb_trait_del(const struct sk_buff *skb, u64 key);
+
static inline void nf_reset_ct(struct sk_buff *skb)
{
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 9f27caba82af0be7897b68b5fad087f3e9c62955..27e163b83b12ffac973e1e098f035b807e1f4232 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -7148,6 +7148,19 @@ void *skb_ext_from_headroom(struct sk_buff *skb, enum skb_ext_id id, int head_of
return __skb_ext_set_active(skb, new, id);
}
+bool skb_ext_grow_headroom(const struct sk_buff *skb, int add)
+{
+ if (!skb->active_extensions)
+ return false;
+ if (skb->extensions->mode != SKB_EXT_HEADROOM)
+ return false;
+ if (skb_headroom(skb) < add)
+ return false;
+
+ skb->extensions->chunks += SKB_EXT_CHUNKS(add);
+ return true;
+}
+
#ifdef CONFIG_XFRM
static void skb_ext_put_sp(struct sec_path *sp)
{
@@ -7215,8 +7228,107 @@ int __skb_ext_total_size(const struct skb_ext *ext)
{
return SKB_EXT_CHUNKS_BYTES(ext->chunks);
}
+
+int skb_ext_size(const struct sk_buff *skb, enum skb_ext_id id)
+{
+ if (!skb_ext_exist(skb, id))
+ return 0;
+
+ switch (skb->extensions->mode) {
+ case SKB_EXT_ALLOC:
+ return skb_ext_type_len[id];
+ case SKB_EXT_HEADROOM:
+ return SKB_EXT_CHUNKS_BYTES(skb->extensions->chunks - skb->extensions->offset[id]);
+ }
+}
#endif /* CONFIG_SKB_EXTENSIONS */
+__bpf_kfunc_start_defs();
+
+__bpf_kfunc int skb_trait_set(struct sk_buff *skb, u64 key,
+ const void *val, u64 val__sz, u64 flags)
+{
+#ifndef CONFIG_SKB_EXTENSIONS
+ return -EOPNOTSUPP;
+#else
+ int err;
+ void *traits = skb_traits(skb);
+
+ if (!traits)
+ return -EOPNOTSUPP;
+
+ /* Traits are shared, get our own copy before modifying */
+ if (refcount_read(&skb->extensions->refcnt) > 1) {
+ traits = skb_ext_add(skb, SKB_EXT_TRAITS);
+ if (!traits)
+ return -ENOMEM;
+ }
+
+ err = trait_set(traits, traits + skb_ext_size(skb, SKB_EXT_TRAITS),
+ key, val, val__sz, flags);
+ if (err == -ENOSPC && skb->extensions->mode == SKB_EXT_HEADROOM) {
+ /* Take more headroom if available */
+ if (!skb_ext_grow_headroom(skb, val__sz))
+ return err;
+
+ err = trait_set(traits, traits + skb_ext_size(skb, SKB_EXT_TRAITS),
+ key, val, val__sz, flags);
+ }
+ return err;
+#endif /* CONFIG_SKB_EXTENSIONS */
+}
+
+__bpf_kfunc int skb_trait_is_set(const struct sk_buff *skb, u64 key)
+{
+ void *traits = skb_traits(skb);
+
+ if (!traits)
+ return -EOPNOTSUPP;
+
+ return trait_is_set(traits, key);
+}
+
+__bpf_kfunc int skb_trait_get(const struct sk_buff *skb, u64 key,
+ void *val, u64 val__sz)
+{
+ void *traits = skb_traits(skb);
+
+ if (!traits)
+ return -EOPNOTSUPP;
+
+ return trait_get(traits, key, val, val__sz);
+}
+
+__bpf_kfunc int skb_trait_del(const struct sk_buff *skb, u64 key)
+{
+ void *traits = skb_traits(skb);
+
+ if (!traits)
+ return -EOPNOTSUPP;
+
+ return trait_del(traits, key);
+}
+
+__bpf_kfunc_end_defs();
+
+BTF_KFUNCS_START(bpf_skb_traits)
+BTF_ID_FLAGS(func, skb_trait_set)
+BTF_ID_FLAGS(func, skb_trait_is_set)
+BTF_ID_FLAGS(func, skb_trait_get)
+BTF_ID_FLAGS(func, skb_trait_del)
+BTF_KFUNCS_END(bpf_skb_traits)
+
+static const struct btf_kfunc_id_set bpf_traits_kfunc_set = {
+ .owner = THIS_MODULE,
+ .set = &bpf_skb_traits,
+};
+
+static int init_subsystem(void)
+{
+ return register_btf_kfunc_id_set(BPF_PROG_TYPE_SOCKET_FILTER, &bpf_traits_kfunc_set);
+}
+late_initcall(init_subsystem);
+
static void kfree_skb_napi_cache(struct sk_buff *skb)
{
/* if SKB is a clone, don't handle this case */
--
2.43.0
Powered by blists - more mailing lists