[PATCH bpf-next v8 3/5] libbpf: Add libbpf_probe_bpf_kfunc API

Tao Chen posted 5 patches 9 months, 3 weeks ago
[PATCH bpf-next v8 3/5] libbpf: Add libbpf_probe_bpf_kfunc API
Posted by Tao Chen 9 months, 3 weeks ago
Similarly to libbpf_probe_bpf_helper, the libbpf_probe_bpf_kfunc
used to test the availability of the different eBPF kfuncs on the
current system.

Cc: Tao Chen <dylane.chen@didiglobal.com>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Reviewed-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Tao Chen <chen.dylane@linux.dev>
---
 tools/lib/bpf/libbpf.h        | 19 ++++++++++++-
 tools/lib/bpf/libbpf.map      |  1 +
 tools/lib/bpf/libbpf_probes.c | 51 +++++++++++++++++++++++++++++++++++
 3 files changed, 70 insertions(+), 1 deletion(-)

diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 3020ee45303a..c79b4475b956 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -1680,7 +1680,24 @@ LIBBPF_API int libbpf_probe_bpf_map_type(enum bpf_map_type map_type, const void
  */
 LIBBPF_API int libbpf_probe_bpf_helper(enum bpf_prog_type prog_type,
 				       enum bpf_func_id helper_id, const void *opts);
-
+/**
+ * @brief **libbpf_probe_bpf_kfunc()** detects if host kernel supports the
+ * use of a given BPF kfunc from specified BPF program type.
+ * @param prog_type BPF program type used to check the support of BPF kfunc
+ * @param kfunc_id The btf ID of BPF kfunc to check support for
+ * @param btf_fd The module BTF FD, if kfunc is defined in kernel module,
+ * btf_fd is used to point to module's BTF, which is >= 0, and < 0 means kfunc
+ * defined in vmlinux.
+ * @param opts reserved for future extensibility, should be NULL
+ * @return 1, if given combination of program type and kfunc is supported; 0,
+ * if the combination is not supported; negative error code if feature
+ * detection for provided input arguments failed or can't be performed
+ *
+ * Make sure the process has required set of CAP_* permissions (or runs as
+ * root) when performing feature checking.
+ */
+LIBBPF_API int libbpf_probe_bpf_kfunc(enum bpf_prog_type prog_type,
+				      int kfunc_id, int btf_fd, const void *opts);
 /**
  * @brief **libbpf_num_possible_cpus()** is a helper function to get the
  * number of possible CPUs that the host kernel supports and expects.
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index b5a838de6f47..3bbfe13aeb6a 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -438,4 +438,5 @@ LIBBPF_1.6.0 {
 		bpf_linker__new_fd;
 		btf__add_decl_attr;
 		btf__add_type_attr;
+		libbpf_probe_bpf_kfunc;
 } LIBBPF_1.5.0;
diff --git a/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c
index de2b1205b436..8efebc18a215 100644
--- a/tools/lib/bpf/libbpf_probes.c
+++ b/tools/lib/bpf/libbpf_probes.c
@@ -431,6 +431,57 @@ static bool can_probe_prog_type(enum bpf_prog_type prog_type)
 	return true;
 }
 
+int libbpf_probe_bpf_kfunc(enum bpf_prog_type prog_type, int kfunc_id, int btf_fd,
+			   const void *opts)
+{
+	struct bpf_insn insns[] = {
+		BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, BPF_PSEUDO_KFUNC_CALL, 1, kfunc_id),
+		BPF_EXIT_INSN(),
+	};
+	const size_t insn_cnt = ARRAY_SIZE(insns);
+	char buf[4096];
+	int fd_array[2] = {-1};
+	int ret;
+
+	if (opts)
+		return libbpf_err(-EINVAL);
+
+	if (!can_probe_prog_type(prog_type))
+		return libbpf_err(-EOPNOTSUPP);
+
+	if (btf_fd >= 0)
+		fd_array[1] = btf_fd;
+	else
+		/* insn.off = 0, means vmlinux btf */
+		insns[0].off = 0;
+
+	buf[0] = '\0';
+	ret = probe_prog_load(prog_type, insns, insn_cnt, btf_fd >= 0 ? fd_array : NULL,
+			      buf, sizeof(buf));
+	if (ret < 0)
+		return libbpf_err(ret);
+
+	if (ret > 0)
+		return 1; /* assume supported */
+
+	/* If BPF verifier recognizes BPF kfunc but it's not supported for
+	 * given BPF program type, it will emit "calling kernel function
+	 * <name> is not allowed". If the kfunc id is invalid,
+	 * it will emit "kernel btf_id <id> is not a function". If BTF fd
+	 * invalid in module BTF, it will emit "invalid module BTF fd specified" or
+	 * "negative offset disallowed for kernel module function call". If
+	 * kfunc prog not dev buound, it will emit "metadata kfuncs require
+	 * device-bound program".
+	 */
+	if (strstr(buf, "not allowed") || strstr(buf, "not a function") ||
+	   strstr(buf, "invalid module BTF fd") ||
+	   strstr(buf, "negative offset disallowed") ||
+	   strstr(buf, "device-bound program"))
+		return 0;
+
+	return 1;
+}
+
 int libbpf_probe_bpf_helper(enum bpf_prog_type prog_type, enum bpf_func_id helper_id,
 			    const void *opts)
 {
-- 
2.43.0
Re: [PATCH bpf-next v8 3/5] libbpf: Add libbpf_probe_bpf_kfunc API
Posted by Andrii Nakryiko 9 months, 3 weeks ago
On Mon, Feb 24, 2025 at 9:02 AM Tao Chen <chen.dylane@linux.dev> wrote:
>
> Similarly to libbpf_probe_bpf_helper, the libbpf_probe_bpf_kfunc
> used to test the availability of the different eBPF kfuncs on the
> current system.
>
> Cc: Tao Chen <dylane.chen@didiglobal.com>
> Reviewed-by: Jiri Olsa <jolsa@kernel.org>
> Reviewed-by: Eduard Zingerman <eddyz87@gmail.com>
> Signed-off-by: Tao Chen <chen.dylane@linux.dev>
> ---
>  tools/lib/bpf/libbpf.h        | 19 ++++++++++++-
>  tools/lib/bpf/libbpf.map      |  1 +
>  tools/lib/bpf/libbpf_probes.c | 51 +++++++++++++++++++++++++++++++++++
>  3 files changed, 70 insertions(+), 1 deletion(-)
>

[...]

> +       buf[0] = '\0';
> +       ret = probe_prog_load(prog_type, insns, insn_cnt, btf_fd >= 0 ? fd_array : NULL,
> +                             buf, sizeof(buf));
> +       if (ret < 0)
> +               return libbpf_err(ret);
> +
> +       if (ret > 0)
> +               return 1; /* assume supported */
> +
> +       /* If BPF verifier recognizes BPF kfunc but it's not supported for
> +        * given BPF program type, it will emit "calling kernel function
> +        * <name> is not allowed". If the kfunc id is invalid,
> +        * it will emit "kernel btf_id <id> is not a function". If BTF fd
> +        * invalid in module BTF, it will emit "invalid module BTF fd specified" or
> +        * "negative offset disallowed for kernel module function call". If
> +        * kfunc prog not dev buound, it will emit "metadata kfuncs require
> +        * device-bound program".
> +        */
> +       if (strstr(buf, "not allowed") || strstr(buf, "not a function") ||
> +          strstr(buf, "invalid module BTF fd") ||

why is invalid module BTF FD not an error (negative return)?

> +          strstr(buf, "negative offset disallowed") ||
> +          strstr(buf, "device-bound program"))
> +               return 0;
> +
> +       return 1;
> +}
> +
>  int libbpf_probe_bpf_helper(enum bpf_prog_type prog_type, enum bpf_func_id helper_id,
>                             const void *opts)
>  {
> --
> 2.43.0
>
Re: [PATCH bpf-next v8 3/5] libbpf: Add libbpf_probe_bpf_kfunc API
Posted by Tao Chen 9 months, 3 weeks ago
在 2025/2/25 09:15, Andrii Nakryiko 写道:
> On Mon, Feb 24, 2025 at 9:02 AM Tao Chen <chen.dylane@linux.dev> wrote:
>>
>> Similarly to libbpf_probe_bpf_helper, the libbpf_probe_bpf_kfunc
>> used to test the availability of the different eBPF kfuncs on the
>> current system.
>>
>> Cc: Tao Chen <dylane.chen@didiglobal.com>
>> Reviewed-by: Jiri Olsa <jolsa@kernel.org>
>> Reviewed-by: Eduard Zingerman <eddyz87@gmail.com>
>> Signed-off-by: Tao Chen <chen.dylane@linux.dev>
>> ---
>>   tools/lib/bpf/libbpf.h        | 19 ++++++++++++-
>>   tools/lib/bpf/libbpf.map      |  1 +
>>   tools/lib/bpf/libbpf_probes.c | 51 +++++++++++++++++++++++++++++++++++
>>   3 files changed, 70 insertions(+), 1 deletion(-)
>>
> 
> [...]
> 
>> +       buf[0] = '\0';
>> +       ret = probe_prog_load(prog_type, insns, insn_cnt, btf_fd >= 0 ? fd_array : NULL,
>> +                             buf, sizeof(buf));
>> +       if (ret < 0)
>> +               return libbpf_err(ret);
>> +
>> +       if (ret > 0)
>> +               return 1; /* assume supported */
>> +
>> +       /* If BPF verifier recognizes BPF kfunc but it's not supported for
>> +        * given BPF program type, it will emit "calling kernel function
>> +        * <name> is not allowed". If the kfunc id is invalid,
>> +        * it will emit "kernel btf_id <id> is not a function". If BTF fd
>> +        * invalid in module BTF, it will emit "invalid module BTF fd specified" or
>> +        * "negative offset disallowed for kernel module function call". If
>> +        * kfunc prog not dev buound, it will emit "metadata kfuncs require
>> +        * device-bound program".
>> +        */
>> +       if (strstr(buf, "not allowed") || strstr(buf, "not a function") ||
>> +          strstr(buf, "invalid module BTF fd") ||
> 
> why is invalid module BTF FD not an error (negative return)?
> 
>> +          strstr(buf, "negative offset disallowed") ||
>> +          strstr(buf, "device-bound program"))
>> +               return 0;
>> +
>> +       return 1;
>> +}
>> +
>>   int libbpf_probe_bpf_helper(enum bpf_prog_type prog_type, enum bpf_func_id helper_id,
>>                              const void *opts)
>>   {
>> --
>> 2.43.0
>>

In probe_prog_load, err will be checked and converted into either 0 or 1.

-- 
Best Regards
Tao Chen
Re: [PATCH bpf-next v8 3/5] libbpf: Add libbpf_probe_bpf_kfunc API
Posted by Andrii Nakryiko 9 months, 3 weeks ago
On Mon, Feb 24, 2025 at 9:47 PM Tao Chen <chen.dylane@linux.dev> wrote:
>
> 在 2025/2/25 09:15, Andrii Nakryiko 写道:
> > On Mon, Feb 24, 2025 at 9:02 AM Tao Chen <chen.dylane@linux.dev> wrote:
> >>
> >> Similarly to libbpf_probe_bpf_helper, the libbpf_probe_bpf_kfunc
> >> used to test the availability of the different eBPF kfuncs on the
> >> current system.
> >>
> >> Cc: Tao Chen <dylane.chen@didiglobal.com>
> >> Reviewed-by: Jiri Olsa <jolsa@kernel.org>
> >> Reviewed-by: Eduard Zingerman <eddyz87@gmail.com>
> >> Signed-off-by: Tao Chen <chen.dylane@linux.dev>
> >> ---
> >>   tools/lib/bpf/libbpf.h        | 19 ++++++++++++-
> >>   tools/lib/bpf/libbpf.map      |  1 +
> >>   tools/lib/bpf/libbpf_probes.c | 51 +++++++++++++++++++++++++++++++++++
> >>   3 files changed, 70 insertions(+), 1 deletion(-)
> >>
> >
> > [...]
> >
> >> +       buf[0] = '\0';
> >> +       ret = probe_prog_load(prog_type, insns, insn_cnt, btf_fd >= 0 ? fd_array : NULL,
> >> +                             buf, sizeof(buf));
> >> +       if (ret < 0)
> >> +               return libbpf_err(ret);
> >> +
> >> +       if (ret > 0)
> >> +               return 1; /* assume supported */
> >> +
> >> +       /* If BPF verifier recognizes BPF kfunc but it's not supported for
> >> +        * given BPF program type, it will emit "calling kernel function
> >> +        * <name> is not allowed". If the kfunc id is invalid,
> >> +        * it will emit "kernel btf_id <id> is not a function". If BTF fd
> >> +        * invalid in module BTF, it will emit "invalid module BTF fd specified" or
> >> +        * "negative offset disallowed for kernel module function call". If
> >> +        * kfunc prog not dev buound, it will emit "metadata kfuncs require
> >> +        * device-bound program".
> >> +        */
> >> +       if (strstr(buf, "not allowed") || strstr(buf, "not a function") ||
> >> +          strstr(buf, "invalid module BTF fd") ||
> >
> > why is invalid module BTF FD not an error (negative return)?
> >
> >> +          strstr(buf, "negative offset disallowed") ||
> >> +          strstr(buf, "device-bound program"))
> >> +               return 0;
> >> +
> >> +       return 1;
> >> +}
> >> +
> >>   int libbpf_probe_bpf_helper(enum bpf_prog_type prog_type, enum bpf_func_id helper_id,
> >>                              const void *opts)
> >>   {
> >> --
> >> 2.43.0
> >>
>
> In probe_prog_load, err will be checked and converted into either 0 or 1.

I guess what I was getting at is that providing invalid module BTF FD
is not a "not supported" case, it's an error case (and so should
result in negative return)

>
> --
> Best Regards
> Tao Chen