diff mbox series

[bpf-next,3/8] libbpf: further decouple feature checking logic from bpf_object

Message ID 20231207185443.2297160-4-andrii@kernel.org (mailing list archive)
State New, archived
Headers show
Series BPF token support in libbpf's BPF object | expand

Commit Message

Andrii Nakryiko Dec. 7, 2023, 6:54 p.m. UTC
Add feat_supported() helper that accepts feature cache instead of
bpf_object. This allows low-level code in bpf.c to not know or care
about higher-level concept of bpf_object, yet it will be able to utilize
custom feature checking in cases where BPF token might influence the
outcome.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
---
 tools/lib/bpf/bpf.c             |  6 +++---
 tools/lib/bpf/libbpf.c          | 23 ++++++++++++++++-------
 tools/lib/bpf/libbpf_internal.h |  5 ++++-
 3 files changed, 23 insertions(+), 11 deletions(-)

Comments

Eduard Zingerman Dec. 10, 2023, 3:31 p.m. UTC | #1
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index a6b8d6f70918..af5e777efcbd 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -637,6 +637,7 @@ struct elf_state {
>  };
>  
>  struct usdt_manager;
> +struct kern_feature_cache;

Nit: this forward declaration is not necessary.
Andrii Nakryiko Dec. 11, 2023, 6:20 p.m. UTC | #2
On Sun, Dec 10, 2023 at 7:31 AM Eduard Zingerman <eddyz87@gmail.com> wrote:
>
> > diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> > index a6b8d6f70918..af5e777efcbd 100644
> > --- a/tools/lib/bpf/libbpf.c
> > +++ b/tools/lib/bpf/libbpf.c
> > @@ -637,6 +637,7 @@ struct elf_state {
> >  };
> >
> >  struct usdt_manager;
> > +struct kern_feature_cache;
>
> Nit: this forward declaration is not necessary.
>
>

true, we have it in libbpf_internal.h now, will drop
John Fastabend Dec. 11, 2023, 9:41 p.m. UTC | #3
Andrii Nakryiko wrote:
> Add feat_supported() helper that accepts feature cache instead of
> bpf_object. This allows low-level code in bpf.c to not know or care
> about higher-level concept of bpf_object, yet it will be able to utilize
> custom feature checking in cases where BPF token might influence the
> outcome.
> 
> Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
> ---

...

> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index a6b8d6f70918..af5e777efcbd 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -637,6 +637,7 @@ struct elf_state {
>  };
>  
>  struct usdt_manager;
> +struct kern_feature_cache;
>  
>  struct bpf_object {
>  	char name[BPF_OBJ_NAME_LEN];
> @@ -5063,17 +5064,14 @@ static struct kern_feature_desc {
>  	},
>  };
>  
> -bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id)
> +bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id)
>  {
>  	struct kern_feature_desc *feat = &feature_probes[feat_id];
> -	struct kern_feature_cache *cache = &feature_cache;
>  	int ret;
>  
> -	if (obj && obj->gen_loader)
> -		/* To generate loader program assume the latest kernel
> -		 * to avoid doing extra prog_load, map_create syscalls.
> -		 */
> -		return true;
> +	/* assume global feature cache, unless custom one is provided */
> +	if (!cache)
> +		cache = &feature_cache;

Why expose a custom cache at all? Where would that be used? I guess we are
looking at libbpf_internal APIs so maybe not a big deal.

>  
>  	if (READ_ONCE(cache->res[feat_id]) == FEAT_UNKNOWN) {
>  		ret = feat->probe();
> @@ -5090,6 +5088,17 @@ bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id)
>  	return READ_ONCE(cache->res[feat_id]) == FEAT_SUPPORTED;
>  }

Acked-by: John Fastabend <john.fastabend@gmail.com>
Andrii Nakryiko Dec. 11, 2023, 10:50 p.m. UTC | #4
On Mon, Dec 11, 2023 at 1:41 PM John Fastabend <john.fastabend@gmail.com> wrote:
>
> Andrii Nakryiko wrote:
> > Add feat_supported() helper that accepts feature cache instead of
> > bpf_object. This allows low-level code in bpf.c to not know or care
> > about higher-level concept of bpf_object, yet it will be able to utilize
> > custom feature checking in cases where BPF token might influence the
> > outcome.
> >
> > Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
> > ---
>
> ...
>
> > diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> > index a6b8d6f70918..af5e777efcbd 100644
> > --- a/tools/lib/bpf/libbpf.c
> > +++ b/tools/lib/bpf/libbpf.c
> > @@ -637,6 +637,7 @@ struct elf_state {
> >  };
> >
> >  struct usdt_manager;
> > +struct kern_feature_cache;
> >
> >  struct bpf_object {
> >       char name[BPF_OBJ_NAME_LEN];
> > @@ -5063,17 +5064,14 @@ static struct kern_feature_desc {
> >       },
> >  };
> >
> > -bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id)
> > +bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id)
> >  {
> >       struct kern_feature_desc *feat = &feature_probes[feat_id];
> > -     struct kern_feature_cache *cache = &feature_cache;
> >       int ret;
> >
> > -     if (obj && obj->gen_loader)
> > -             /* To generate loader program assume the latest kernel
> > -              * to avoid doing extra prog_load, map_create syscalls.
> > -              */
> > -             return true;
> > +     /* assume global feature cache, unless custom one is provided */
> > +     if (!cache)
> > +             cache = &feature_cache;
>
> Why expose a custom cache at all? Where would that be used? I guess we are
> looking at libbpf_internal APIs so maybe not a big deal.

bpf_object with token_fd set will have to use a separate non-global
feature cache. Couple that with me moving this code into a separate
features.c file in one of the next patches, we need to have some
internal interface to make this happen.

Also, bpf.c is also using feature detectors, but today they all use
unprivileged program types, so I didn't add custom feature_cache there
just yet. But if in the future we have more complicated feature
detectors that will rely on privileged programs/maps, we'd need to
pass custom feature_cache from bpf.c as well.

>
> >
> >       if (READ_ONCE(cache->res[feat_id]) == FEAT_UNKNOWN) {
> >               ret = feat->probe();
> > @@ -5090,6 +5088,17 @@ bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id)
> >       return READ_ONCE(cache->res[feat_id]) == FEAT_SUPPORTED;
> >  }
>
> Acked-by: John Fastabend <john.fastabend@gmail.com>
diff mbox series

Patch

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index f4e1da3c6d5f..120855ac6859 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -146,7 +146,7 @@  int bump_rlimit_memlock(void)
 	struct rlimit rlim;
 
 	/* if kernel supports memcg-based accounting, skip bumping RLIMIT_MEMLOCK */
-	if (memlock_bumped || kernel_supports(NULL, FEAT_MEMCG_ACCOUNT))
+	if (memlock_bumped || feat_supported(NULL, FEAT_MEMCG_ACCOUNT))
 		return 0;
 
 	memlock_bumped = true;
@@ -181,7 +181,7 @@  int bpf_map_create(enum bpf_map_type map_type,
 		return libbpf_err(-EINVAL);
 
 	attr.map_type = map_type;
-	if (map_name && kernel_supports(NULL, FEAT_PROG_NAME))
+	if (map_name && feat_supported(NULL, FEAT_PROG_NAME))
 		libbpf_strlcpy(attr.map_name, map_name, sizeof(attr.map_name));
 	attr.key_size = key_size;
 	attr.value_size = value_size;
@@ -265,7 +265,7 @@  int bpf_prog_load(enum bpf_prog_type prog_type,
 	attr.kern_version = OPTS_GET(opts, kern_version, 0);
 	attr.prog_token_fd = OPTS_GET(opts, token_fd, 0);
 
-	if (prog_name && kernel_supports(NULL, FEAT_PROG_NAME))
+	if (prog_name && feat_supported(NULL, FEAT_PROG_NAME))
 		libbpf_strlcpy(attr.prog_name, prog_name, sizeof(attr.prog_name));
 	attr.license = ptr_to_u64(license);
 
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index a6b8d6f70918..af5e777efcbd 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -637,6 +637,7 @@  struct elf_state {
 };
 
 struct usdt_manager;
+struct kern_feature_cache;
 
 struct bpf_object {
 	char name[BPF_OBJ_NAME_LEN];
@@ -5063,17 +5064,14 @@  static struct kern_feature_desc {
 	},
 };
 
-bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id)
+bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id)
 {
 	struct kern_feature_desc *feat = &feature_probes[feat_id];
-	struct kern_feature_cache *cache = &feature_cache;
 	int ret;
 
-	if (obj && obj->gen_loader)
-		/* To generate loader program assume the latest kernel
-		 * to avoid doing extra prog_load, map_create syscalls.
-		 */
-		return true;
+	/* assume global feature cache, unless custom one is provided */
+	if (!cache)
+		cache = &feature_cache;
 
 	if (READ_ONCE(cache->res[feat_id]) == FEAT_UNKNOWN) {
 		ret = feat->probe();
@@ -5090,6 +5088,17 @@  bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id)
 	return READ_ONCE(cache->res[feat_id]) == FEAT_SUPPORTED;
 }
 
+bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id)
+{
+	if (obj && obj->gen_loader)
+		/* To generate loader program assume the latest kernel
+		 * to avoid doing extra prog_load, map_create syscalls.
+		 */
+		return true;
+
+	return feat_supported(NULL, feat_id);
+}
+
 static bool map_is_reuse_compat(const struct bpf_map *map, int map_fd)
 {
 	struct bpf_map_info map_info;
diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h
index b5d334754e5d..754a432335e4 100644
--- a/tools/lib/bpf/libbpf_internal.h
+++ b/tools/lib/bpf/libbpf_internal.h
@@ -360,8 +360,11 @@  enum kern_feature_id {
 	__FEAT_CNT,
 };
 
-int probe_memcg_account(void);
+struct kern_feature_cache;
+bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id);
 bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id);
+
+int probe_memcg_account(void);
 int bump_rlimit_memlock(void);
 
 int parse_cpu_mask_str(const char *s, bool **mask, int *mask_sz);