Re: [RFC bpf-next] libbpf: add resizable array helpers

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

 



On Sat, Sep 21, 2024 at 3:17 AM JP Kobryn <inwardvessel@xxxxxxxxx> wrote:
>
> Arrays in custom data sections can be resized via bpf_map__set_value().
> While working with these types of arrays in some sched_ext programs, there
> was some feedback that the manual operations involved could use helpers.
> The macros in the potential patch are intended to make resizing bpf arrays
> easier.
>
> To illustrate, declaring an array that will be resized looks like this:
> __u32 my_map[1] SEC(".data.my_map");
>
> Instead, using a macro to help with the declaration:
> __u32 BPF_RESIZABLE_ARRAY(data, my_map);

I don't like hiding things in a macro.
SEC() isn't great, but that's what we got and users
used to it.

> To allow access to the post-resized array in the bpf program, this helper
> can be used which maintains verifier safety:
> u32 *val = (u32 *)ARRAY_ELEM_PTR(my_map, ctx->cpu, nr_cpus);

I don't like this one either.
We have bpf_cmp_likely/unlikely that can be used
to guard array access against the limit.

> Meanwhile in the userspace program, instead of doing:
> size_t sz = bpf_map__set_value_size(skel->maps.data_my_map, sizeof(skel->data_my_map->my_map[0]) * nr_cpus);
> skel->data_my_map = bpf_map__initial_value(skel->maps.data_my_map, &sz);
>
> The resizing macro can be used:
> BPF_RESIZE_ARRAY(data, my_map, nr_cpus);

Open code of libbpf api is much more readable. Macros are not.



>
> Signed-off-by: JP Kobryn <inwardvessel@xxxxxxxxx>
> ---
>  include/uapi/linux/bpf.h    | 23 ++++++++++++++++++
>  tools/lib/bpf/bpf_helpers.h | 48 +++++++++++++++++++++++++++++++++++++
>  2 files changed, 71 insertions(+)
>
> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
> index e05b39e39c3f..92e93c9fc056 100644
> --- a/include/uapi/linux/bpf.h
> +++ b/include/uapi/linux/bpf.h
> @@ -7513,4 +7513,27 @@ struct bpf_iter_num {
>         __u64 __opaque[1];
>  } __attribute__((aligned(8)));
>
> +/*
> + * BPF_RESIZE_ARRAY - Convenience macro for resizing a BPF array
> + * @elfsec: the data section of the BPF program in which to the array exists
> + * @arr: the name of the array
> + * @n: the desired array element count
> + *
> + * For BPF arrays declared with RESIZABLE_ARRAY(), this macro performs two
> + * operations. It resizes the map which corresponds to the custom data
> + * section that contains the target array. As a side effect, the BTF info for
> + * the array is adjusted so that the array length is sized to cover the new
> + * data section size. The second operation is reassigning the skeleton pointer
> + * for that custom data section so that it points to the newly memory mapped
> + * region.
> + */
> +#define BPF_RESIZE_ARRAY(elfsec, arr, n)                                         \
> +       do {                                                                      \
> +               size_t __sz;                                                      \
> +               bpf_map__set_value_size(skel->maps.elfsec##_##arr,                \
> +                               sizeof(skel->elfsec##_##arr->arr[0]) * (n));      \
> +               skel->elfsec##_##arr =                                            \
> +                       bpf_map__initial_value(skel->maps.elfsec##_##arr, &__sz); \
> +       } while (0)
> +
>  #endif /* _UAPI__LINUX_BPF_H__ */
> diff --git a/tools/lib/bpf/bpf_helpers.h b/tools/lib/bpf/bpf_helpers.h
> index 305c62817dd3..b0d496b0f0d6 100644
> --- a/tools/lib/bpf/bpf_helpers.h
> +++ b/tools/lib/bpf/bpf_helpers.h
> @@ -420,4 +420,52 @@ extern void bpf_iter_num_destroy(struct bpf_iter_num *it) __weak __ksym;
>  )
>  #endif /* bpf_repeat */
>
> +/**
> + * RESIZABLE_ARRAY - Generates annotations for an array that may be resized
> + * @elfsec: the data section of the BPF program in which to place the array
> + * @arr: the name of the array
> + *
> + * libbpf has an API for setting map value sizes. Since data sections (i.e.
> + * bss, data, rodata) themselves are maps, a data section can be resized. If
> + * a data section has an array as its last element, the BTF info for that
> + * array will be adjusted so that length of the array is extended to meet the
> + * new length of the data section. This macro annotates an array to have an
> + * element count of one with the assumption that this array can be resized
> + * within the userspace program. It also annotates the section specifier so
> + * this array exists in a custom sub data section which can be resized
> + * independently.
> + *
> + * See BPF_RESIZE_ARRAY() for the userspace convenience macro for resizing an
> + * array declared with BPF_RESIZABLE_ARRAY().
> + */
> +#define BPF_RESIZABLE_ARRAY(elfsec, arr) arr[1] SEC("."#elfsec"."#arr)
> +
> +/*
> + * BPF_ARRAY_ELEM_PTR - Obtain the verified pointer to an array element
> + * @arr: array to index into
> + * @i: array index
> + * @n: number of elements in array
> + *
> + * Similar to MEMBER_VPTR() but is intended for use with arrays where the
> + * element count needs to be explicit.
> + * It can be used in cases where a global array is defined with an initial
> + * size but is intended to be be resized before loading the BPF program.
> + * Without this version of the macro, MEMBER_VPTR() will use the compile time
> + * size of the array to compute the max, which will result in rejection by
> + * the verifier.
> + */
> +#define BPF_ARRAY_ELEM_PTR(arr, i, n) (typeof(arr[i]) *)({       \
> +       u64 __base = (u64)arr;                                    \
> +       u64 __addr = (u64)&(arr[i]) - __base;                     \
> +       asm volatile (                                            \
> +               "if %0 <= %[max] goto +2\n"                       \
> +               "%0 = 0\n"                                        \
> +               "goto +1\n"                                       \
> +               "%0 += %1\n"                                      \
> +               : "+r"(__addr)                                    \
> +               : "r"(__base),                                    \
> +                 [max]"r"(sizeof(arr[0]) * ((n) - 1)));  \
> +       __addr;                                           \
> +})
> +
>  #endif
> --
> 2.46.0
>





[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