From: Kui-Feng Lee <sinquersw@gmail.com>
To: Andrii Nakryiko <andrii.nakryiko@gmail.com>, thinker.li@gmail.com
Cc: bpf@vger.kernel.org, ast@kernel.org, martin.lau@linux.dev,
song@kernel.org, kernel-team@meta.com, andrii@kernel.org,
kuifeng@meta.com
Subject: Re: [RFC bpf-next v2 1/3] libbpf: Create a shadow copy for each struct_ops map if necessary.
Date: Thu, 15 Feb 2024 18:35:24 -0800 [thread overview]
Message-ID: <da6aeb49-3d01-4729-8f01-8770ba69019f@gmail.com> (raw)
In-Reply-To: <CAEf4BzZBP=aV4j38+hqVgXoKa+DAZu5F-yeDVge+sLi5OBuRGw@mail.gmail.com>
On 2/15/24 15:55, Andrii Nakryiko wrote:
> On Tue, Feb 13, 2024 at 6:08 PM <thinker.li@gmail.com> wrote:
>>
>> From: Kui-Feng Lee <thinker.li@gmail.com>
>>
>> If the user has passed a shadow info for a struct_ops map along with struct
>> bpf_object_open_opts, a shadow copy will be created for the map and
>> returned from bpf_map__initial_value().
>>
>> The user can read and write shadow variables through the shadow copy, which
>> is placed in the struct pointed by skel->struct_ops.FOO, where FOO is the
>> map name.
>>
>> The value of a shadow variable will be used to update the value of the map
>> when loading the map to the kernel.
>>
>> Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com>
>> ---
>> tools/lib/bpf/libbpf.c | 195 ++++++++++++++++++++++++++++++--
>> tools/lib/bpf/libbpf.h | 34 +++++-
>> tools/lib/bpf/libbpf.map | 1 +
>> tools/lib/bpf/libbpf_internal.h | 1 +
>> 4 files changed, 220 insertions(+), 11 deletions(-)
>>
>> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
>> index 01f407591a92..ce9c4cdb2dc5 100644
>> --- a/tools/lib/bpf/libbpf.c
>> +++ b/tools/lib/bpf/libbpf.c
>> @@ -487,6 +487,14 @@ struct bpf_struct_ops {
>> * from "data".
>> */
>> void *kern_vdata;
>> + /* Description of the layout that a shadow copy should look like.
>> + */
>> + const struct bpf_struct_ops_map_info *shadow_info;
>> + /* A shadow copy of the struct_ops data created according to the
>> + * layout described by shadow_info.
>> + */
>> + void *shadow_data;
>> + __u32 shadow_data_size;
>
> what I mentioned on cover letter, just a few lines above, before
> kern_vdata we have just `void *data` which initially contains whatever
> was set in ELF. Just expose that through bpf_map__initial_value() and
> teach bpftool to generate section with variables for that memory and
> that should be all we need, no?
I am not sure if read your question correctly.
Padding & alignments can vary in different platforms. BPF and
user space programs are supposed to be in different platforms.
So, I can not expect that the same struct has the same layout in
BPF/x86/and ARM, right?
>
>> __u32 type_id;
>> };
>>
>> @@ -1027,7 +1035,7 @@ static int bpf_map__init_kern_struct_ops(struct bpf_map *map)
>> struct module_btf *mod_btf;
>> void *data, *kern_data;
>> const char *tname;
>> - int err;
>> + int err, j;
>>
>> st_ops = map->st_ops;
>> type = st_ops->type;
>
> [...]
>
>> void *bpf_map__initial_value(struct bpf_map *map, size_t *psize)
>> {
>> + if (bpf_map__is_struct_ops(map)) {
>> + if (psize)
>> + *psize = map->st_ops->shadow_data_size;
>> + return map->st_ops->shadow_data;
>> + }
>> +
>> if (!map->mmaped)
>> return NULL;
>> *psize = map->def.value_size;
>> @@ -13462,3 +13632,8 @@ void bpf_object__destroy_skeleton(struct bpf_object_skeleton *s)
>> free(s->progs);
>> free(s);
>> }
>> +
>> +__u32 bpf_map__struct_ops_type(const struct bpf_map *map)
>> +{
>> + return map->st_ops->type_id;
>> +}
>
> we can expose this st_ops->type_id as map->def.value_type_id so that
> existing bpf_map__btf_value_type_id() API can be used, no need to add
> more struct_ops-specific APIs
OK!
>
>> diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
>> index 5723cbbfcc41..b435cafefe7a 100644
>> --- a/tools/lib/bpf/libbpf.h
>> +++ b/tools/lib/bpf/libbpf.h
>> @@ -109,6 +109,27 @@ LIBBPF_API libbpf_print_fn_t libbpf_set_print(libbpf_print_fn_t fn);
>> /* Hide internal to user */
>> struct bpf_object;
>>
>> +/* Description of a member in the struct_ops type for a map. */
>> +struct bpf_struct_ops_member_info {
>> + const char *name;
>> + __u32 offset;
>> + __u32 size;
>> +};
>> +
>> +/* Description of the layout of a shadow copy for a struct_ops map. */
>> +struct bpf_struct_ops_map_info {
>> + /* The name of the struct_ops map */
>> + const char *name;
>> + const struct bpf_struct_ops_member_info *members;
>> + __u32 cnt;
>> + __u32 data_size;
>> +};
>> +
>> +struct bpf_struct_ops_shadow_info {
>> + const struct bpf_struct_ops_map_info *maps;
>> + __u32 cnt;
>> +};
>> +
>> struct bpf_object_open_opts {
>> /* size of this struct, for forward/backward compatibility */
>> size_t sz;
>> @@ -197,9 +218,18 @@ struct bpf_object_open_opts {
>> */
>> const char *bpf_token_path;
>>
>> + /* A list of shadow info for every struct_ops map. A shadow info
>> + * provides the information used by libbpf to map the offsets of
>> + * struct members of a struct_ops type from BTF to the offsets of
>> + * the corresponding members in the shadow copy in the user
>> + * space. It ensures that the shadow copy provided by the libbpf
>> + * can be accessed by the user space program correctly.
>> + */
>> + const struct bpf_struct_ops_shadow_info *struct_ops_shadow;
>> +
>
> I still don't follow. bpftool will generate memory-layout compatible
> structure for user-space, they can just work directly with that
> memory. We shouldn't need all this extra info structs.
>
> Libbpf can just check that fields that are supposed to be BPF prog
> references are correct `struct bpf_program *` pointers.
Check the explanation above.
>
>> size_t :0;
>> };
>> -#define bpf_object_open_opts__last_field bpf_token_path
>> +#define bpf_object_open_opts__last_field struct_ops_shadow
>>
>> /**
>> * @brief **bpf_object__open()** creates a bpf_object by opening
>> @@ -839,6 +869,8 @@ struct bpf_map;
>> LIBBPF_API struct bpf_link *bpf_map__attach_struct_ops(const struct bpf_map *map);
>> LIBBPF_API int bpf_link__update_map(struct bpf_link *link, const struct bpf_map *map);
>>
>> +LIBBPF_API __u32 bpf_map__struct_ops_type(const struct bpf_map *map);
>> +
>> struct bpf_iter_attach_opts {
>> size_t sz; /* size of this struct for forward/backward compatibility */
>> union bpf_iter_link_info *link_info;
>> diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
>> index 86804fd90dd1..e0efc85114df 100644
>> --- a/tools/lib/bpf/libbpf.map
>> +++ b/tools/lib/bpf/libbpf.map
>> @@ -413,4 +413,5 @@ LIBBPF_1.4.0 {
>> bpf_token_create;
>> btf__new_split;
>> btf_ext__raw_data;
>> + bpf_map__struct_ops_type;
>> } LIBBPF_1.3.0;
>> diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h
>> index ad936ac5e639..aec6d57fe5d1 100644
>> --- a/tools/lib/bpf/libbpf_internal.h
>> +++ b/tools/lib/bpf/libbpf_internal.h
>> @@ -234,6 +234,7 @@ struct btf_type;
>> struct btf_type *btf_type_by_id(const struct btf *btf, __u32 type_id);
>> const char *btf_kind_str(const struct btf_type *t);
>> const struct btf_type *skip_mods_and_typedefs(const struct btf *btf, __u32 id, __u32 *res_id);
>> +const struct btf_type *resolve_func_ptr(const struct btf *btf, __u32 id, __u32 *res_id);
>>
>> static inline enum btf_func_linkage btf_func_linkage(const struct btf_type *t)
>> {
>> --
>> 2.34.1
>>
next prev parent reply other threads:[~2024-02-16 2:35 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-02-14 2:08 [RFC bpf-next v2 0/3] Create shadow variables for struct_ops in skeletons thinker.li
2024-02-14 2:08 ` [RFC bpf-next v2 1/3] libbpf: Create a shadow copy for each struct_ops map if necessary thinker.li
2024-02-15 23:55 ` Andrii Nakryiko
2024-02-16 2:35 ` Kui-Feng Lee [this message]
2024-02-16 16:52 ` Andrii Nakryiko
2024-02-16 17:12 ` Kui-Feng Lee
2024-02-14 2:08 ` [RFC bpf-next v2 2/3] bpftool: generated shadow variables for struct_ops maps thinker.li
2024-02-14 2:08 ` [RFC bpf-next v2 3/3] selftests/bpf: Test if shadow variables work thinker.li
2024-02-15 23:50 ` [RFC bpf-next v2 0/3] Create shadow variables for struct_ops in skeletons Andrii Nakryiko
2024-02-16 2:40 ` Kui-Feng Lee
2024-02-16 16:54 ` Andrii Nakryiko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=da6aeb49-3d01-4729-8f01-8770ba69019f@gmail.com \
--to=sinquersw@gmail.com \
--cc=andrii.nakryiko@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=kernel-team@meta.com \
--cc=kuifeng@meta.com \
--cc=martin.lau@linux.dev \
--cc=song@kernel.org \
--cc=thinker.li@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox