mbox series

[RFC,0/2] Add btf__field_exists

Message ID 20220404083816.1560501-1-nborisov@suse.com (mailing list archive)
Headers show
Series Add btf__field_exists | expand

Message

Nikolay Borisov April 4, 2022, 8:38 a.m. UTC
Hello,

Here are 2 patches with which I want to probe what's the sentiments towards 2
changes:

1. Introduction of libbpf APIs similar to the bpf counterparts: bpf_core_field_exists,
bpf_core_type_exists and bpf_core_enum_value_exists. Of those I've implemented only
the first one and the reasoning behind this is in the patch itself. However, the
TLDR is that there can be cases where based on the kernel version we have to make a
decision in userspace what set of kprobes to use. There are currently no convenince
api's to do this so one has to essentially open code the checks that can be provided
by the aforementioned APIs.

2. The kernel has for_each_member macro but the libbpf library doesn't provide it,
this results in having to open code members enumeration in various places such as
in find_member_by_name/find_struct_ops_kern_types/bpf_map__init_kern_struct_ops/
parse_btf_map_def  and in the newly introduced btf__field_exists. So how about
bringing the convenience macro to libbpf?

The reason why this series is RFC is if people agree with the proposed changed
I'd be happy to extend it to add more *exists* APIs and do the conversion to
using the  for_each_member macro.

Nikolay Borisov (2):
  libbpf: Add userspace version of for_each_member macro
  libbpf: Add btf__field_exists

 tools/lib/bpf/btf.c      | 28 ++++++++++++++++++++++++++++
 tools/lib/bpf/btf.h      |  8 ++++++++
 tools/lib/bpf/libbpf.map |  1 +
 3 files changed, 37 insertions(+)

--
2.25.1

Comments

Andrii Nakryiko April 5, 2022, 11:37 p.m. UTC | #1
On Mon, Apr 4, 2022 at 1:38 AM Nikolay Borisov <nborisov@suse.com> wrote:
>
> Hello,
>
> Here are 2 patches with which I want to probe what's the sentiments towards 2
> changes:
>
> 1. Introduction of libbpf APIs similar to the bpf counterparts: bpf_core_field_exists,
> bpf_core_type_exists and bpf_core_enum_value_exists. Of those I've implemented only
> the first one and the reasoning behind this is in the patch itself. However, the
> TLDR is that there can be cases where based on the kernel version we have to make a
> decision in userspace what set of kprobes to use. There are currently no convenince
> api's to do this so one has to essentially open code the checks that can be provided
> by the aforementioned APIs.
>

The problem is that what you've implemented is not a user-space
equivalent of bpf_core_xxx() macros. CO-RE has extra logic around
___<flavor> suffixes, extra type checks, etc, etc. Helper you are
adding does a very straightforward strings check, which isn't hard to
implement and it doesn't have to be a set in stone API. So I'm a bit
hesitant to add this.

But I can share what I did in similar situations where I had to do
some CO-RE check both on BPF side and know its result in user-space. I
built a separate very simple BPF skeleton and all it did was perform
various feature checks (including those that require CO-RE) and then
returned the result through global variables. You can then trigger
such BPF feature-checking program either through bpf_prog_test_run or
through whatever other means (I actually did a simple sys_enter
program in my case). See [0] for BPF program side and [1] for
user-space activation/consumption of that.

The benefit of this approach is that there is no way BPF and
user-space sides can get "out of sync" in terms of their feature
checking. With skeleton it's also extremely simple to do all this.

  [0] https://github.com/anakryiko/retsnoop/blob/master/src/calib_feat.bpf.c
  [1] https://github.com/anakryiko/retsnoop/blob/master/src/mass_attacher.c#L483-L529


> 2. The kernel has for_each_member macro but the libbpf library doesn't provide it,
> this results in having to open code members enumeration in various places such as
> in find_member_by_name/find_struct_ops_kern_types/bpf_map__init_kern_struct_ops/
> parse_btf_map_def  and in the newly introduced btf__field_exists. So how about
> bringing the convenience macro to libbpf?

see my comment, not sure it's worth it

>
> The reason why this series is RFC is if people agree with the proposed changed
> I'd be happy to extend it to add more *exists* APIs and do the conversion to
> using the  for_each_member macro.
>
> Nikolay Borisov (2):
>   libbpf: Add userspace version of for_each_member macro
>   libbpf: Add btf__field_exists
>
>  tools/lib/bpf/btf.c      | 28 ++++++++++++++++++++++++++++
>  tools/lib/bpf/btf.h      |  8 ++++++++
>  tools/lib/bpf/libbpf.map |  1 +
>  3 files changed, 37 insertions(+)
>
> --
> 2.25.1
>
Nikolay Borisov April 6, 2022, 6:41 a.m. UTC | #2
On 6.04.22 г. 2:37 ч., Andrii Nakryiko wrote:
> The problem is that what you've implemented is not a user-space
> equivalent of bpf_core_xxx() macros. CO-RE has extra logic around
> ___<flavor> suffixes, extra type checks, etc, etc. Helper you are
> adding does a very straightforward strings check, which isn't hard to
> implement and it doesn't have to be a set in stone API. So I'm a bit
> hesitant to add this.
> 
> But I can share what I did in similar situations where I had to do
> some CO-RE check both on BPF side and know its result in user-space. I
> built a separate very simple BPF skeleton and all it did was perform
> various feature checks (including those that require CO-RE) and then
> returned the result through global variables. You can then trigger
> such BPF feature-checking program either through bpf_prog_test_run or
> through whatever other means (I actually did a simple sys_enter
> program in my case). See [0] for BPF program side and [1] for
> user-space activation/consumption of that.
> 
> The benefit of this approach is that there is no way BPF and
> user-space sides can get "out of sync" in terms of their feature
> checking. With skeleton it's also extremely simple to do all this.
> 
>    [0]https://github.com/anakryiko/retsnoop/blob/master/src/calib_feat.bpf.c
>    [1]https://github.com/anakryiko/retsnoop/blob/master/src/mass_attacher.c#L483-L529
> 


That's indeed neat, however what is the minimum kernel version required 
to have global variables work ? AFAIU one requirement is to use a 
recent-enough libbpf which supports the skeleton functionality which is 
fine, userspace components can be updated somewhat easily than target 
kernels.
Andrii Nakryiko April 6, 2022, 5:14 p.m. UTC | #3
On Tue, Apr 5, 2022 at 11:41 PM Nikolay Borisov <nborisov@suse.com> wrote:
>
>
>
> On 6.04.22 г. 2:37 ч., Andrii Nakryiko wrote:
> > The problem is that what you've implemented is not a user-space
> > equivalent of bpf_core_xxx() macros. CO-RE has extra logic around
> > ___<flavor> suffixes, extra type checks, etc, etc. Helper you are
> > adding does a very straightforward strings check, which isn't hard to
> > implement and it doesn't have to be a set in stone API. So I'm a bit
> > hesitant to add this.
> >
> > But I can share what I did in similar situations where I had to do
> > some CO-RE check both on BPF side and know its result in user-space. I
> > built a separate very simple BPF skeleton and all it did was perform
> > various feature checks (including those that require CO-RE) and then
> > returned the result through global variables. You can then trigger
> > such BPF feature-checking program either through bpf_prog_test_run or
> > through whatever other means (I actually did a simple sys_enter
> > program in my case). See [0] for BPF program side and [1] for
> > user-space activation/consumption of that.
> >
> > The benefit of this approach is that there is no way BPF and
> > user-space sides can get "out of sync" in terms of their feature
> > checking. With skeleton it's also extremely simple to do all this.
> >
> >    [0]https://github.com/anakryiko/retsnoop/blob/master/src/calib_feat.bpf.c
> >    [1]https://github.com/anakryiko/retsnoop/blob/master/src/mass_attacher.c#L483-L529
> >
>
>
> That's indeed neat, however what is the minimum kernel version required
> to have global variables work ? AFAIU one requirement is to use a
> recent-enough libbpf which supports the skeleton functionality which is
> fine, userspace components can be updated somewhat easily than target
> kernels.

You need Linux 5.5 for global variables mapping into user-space (added
in [0]). But you don't need to use global variables to pass
information back to user-space. You can just do a trivial
BPF_MAP_TYPE_ARRAY for this. It's a bit more verbose to work with from
BPF and user-space side, but effectively is the same for this case.
Then you basically have no extra Linux version constraints just
because of this feature probing. Only the need to have vmlinux BTF.

  [0] fc9702273e2e ("bpf: Add mmap() support for BPF_MAP_TYPE_ARRAY")