Re: [PATCH bpf] libbpf: fix reuse of pinned map on older kernel

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Jul 8, 2021 at 4:43 AM Martynas Pumputis <m@xxxxxxxxx> wrote:
>
>
>
> On 7/8/21 12:58 AM, Andrii Nakryiko wrote:
> > On Tue, Jul 6, 2021 at 10:24 AM Martynas Pumputis <m@xxxxxxxxx> wrote:
> >>
> >> When loading a BPF program with a pinned map, the loader checks whether
> >> the pinned map can be reused, i.e. their properties match. To derive
> >> such of the pinned map, the loader invokes BPF_OBJ_GET_INFO_BY_FD and
> >> then does the comparison.
> >>
> >> Unfortunately, on < 4.12 kernels the BPF_OBJ_GET_INFO_BY_FD is not
> >> available, so loading the program fails with the following error:
> >>
> >>          libbpf: failed to get map info for map FD 5: Invalid argument
> >>          libbpf: couldn't reuse pinned map at
> >>                  '/sys/fs/bpf/tc/globals/cilium_call_policy': parameter
> >>                  mismatch"
> >>          libbpf: map 'cilium_call_policy': error reusing pinned map
> >>          libbpf: map 'cilium_call_policy': failed to create:
> >>                  Invalid argument(-22)
> >>          libbpf: failed to load object 'bpf_overlay.o'
> >>
> >> To fix this, probe the kernel for BPF_OBJ_GET_INFO_BY_FD support. If it
> >> doesn't support, then fallback to derivation of the map properties via
> >> /proc/$PID/fdinfo/$MAP_FD.
> >>
> >> Signed-off-by: Martynas Pumputis <m@xxxxxxxxx>
> >> ---
> >>   tools/lib/bpf/libbpf.c | 103 +++++++++++++++++++++++++++++++++++++++++++++------
> >>   1 file changed, 92 insertions(+), 11 deletions(-)
> >>
> >
> > [...]
> >
> >> @@ -4406,10 +4478,19 @@ static bool map_is_reuse_compat(const struct bpf_map *map, int map_fd)
> >>
> >>          map_info_len = sizeof(map_info);
> >>
> >> -       if (bpf_obj_get_info_by_fd(map_fd, &map_info, &map_info_len)) {
> >> -               pr_warn("failed to get map info for map FD %d: %s\n",
> >> -                       map_fd, libbpf_strerror_r(errno, msg, sizeof(msg)));
> >> -               return false;
> >> +       if (kernel_supports(obj, FEAT_OBJ_GET_INFO_BY_FD)) {
> >
> > why not just try bpf_obj_get_info_by_fd() first, and if it fails
> > always fallback to bpf_get_map_info_from_fdinfo(). No need to do
> > feature detection. This will cut down on the amount of code without
> > any regression in behavior. More so, it will actually now be
> > consistent and good behavior in case of bpf_map__reuse_fd() where we
> > don't have obj. WDYT?
>
> I was thinking about it, but then decided to use the kernel probing
> instead. The reasoning was the following:
>
> 1) For programs with many pinned maps we would issue many failing
> BPF_OBJ_GET_INFO_BY_FD calls (instead of a single one) which might
> hinder the performance.

you can't have so many maps per BPF program to really notice
performance drop for doing an almost no-op bpf() syscall, so I find
this a weak argument

> 2) A canonical way in libbpf to detect features is via kernel_supports()
> and friends, so I didn't want to diverge there.

There are places where we just gracefully handle missing features.
E.g., when loading map with BTF and it fails, we'll retry without BTF.
Or in __perf_buffer__new we allow BPF_OBJ_GET_INFO_BY_FD to fail.

I'd start with a simple fallback and do explicit feature detection
later if it turns out to be problematic.

>
> Re bpf_map__reuse_fd(), if we are OK to break the API before libbpf
> v1.0, then we could extend bpf_map__reuse_fd() to accept the obj.
> However, this would break some consumers of the lib, e.g., iproute2 [1].

No, we are not ok to just arbitrarily break API. And especially that
passing obj to bpf_map API seems weird. We could solve this problem by
remembering the bpf_object pointer inside struct bpf_map, just like we
do for struct bpf_program, but again, I'm not sure it's worth it in
this case. But strategy doesn't help perf_buffer__new() case.

>
> Anyway, if you think that we can ignore 1) and 2), then I'm happy to
> change. Also, I'm going to submit to bpf-next.

I'd like bpf_map__reuse_fd() to have consistent behavior. And avoid
extra code if possible, so let's try a simple fallback for now?

>
> [1]:
> https://github.com/shemminger/iproute2/blob/v5.11.0/lib/bpf_libbpf.c#L98
>
> >
> >
> >> +               if (bpf_obj_get_info_by_fd(map_fd, &map_info, &map_info_len)) {
> >> +                       pr_warn("failed to get map info for map FD %d: %s\n",
> >> +                               map_fd,
> >> +                               libbpf_strerror_r(errno, msg, sizeof(msg)));
> >> +                       return false;
> >> +               }
> >
> > [...]
> >



[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux