On Wed, Feb 28, 2024 at 10:45 PM Kui-Feng Lee <thinker.li@xxxxxxxxx> wrote: > > Declares and defines a pointer of the shadow type for each struct_ops map. > > The code generator will create an anonymous struct type as the shadow type > for each struct_ops map. The shadow type is translated from the original > struct type of the map. The user of the skeleton use pointers of them to > access the values of struct_ops maps. > > However, shadow types only supports certain types of fields, including > scalar types and function pointers. Any fields of unsupported types are > translated into an array of characters to occupy the space of the original > field. Function pointers are translated into pointers of the struct > bpf_program. Additionally, padding fields are generated to occupy the space > between two consecutive fields. > > The pointers of shadow types of struct_osp maps are initialized when > *__open_opts() in skeletons are called. For a map called FOO, the user can > access it through the pointer at skel->struct_ops.FOO. > > Reviewed-by: Quentin Monnet <quentin@xxxxxxxxxxxxx> > Signed-off-by: Kui-Feng Lee <thinker.li@xxxxxxxxx> > --- > tools/bpf/bpftool/gen.c | 237 +++++++++++++++++++++++++++++++++++++++- > 1 file changed, 236 insertions(+), 1 deletion(-) > [...] > +/* Generate the pointer of the shadow type for a struct_ops map. > + * > + * This function adds a pointer of the shadow type for a struct_ops map. > + * The members of a struct_ops map can be exported through a pointer to a > + * shadow type. The user can access these members through the pointer. > + * > + * A shadow type includes not all members, only members of some types. > + * They are scalar types and function pointers. The function pointers are > + * translated to the pointer of the struct bpf_program. The scalar types > + * are translated to the original type without any modifiers. > + * > + * Unsupported types will be translated to a char array to occupy the same > + * space as the original field, being renamed as __unsupported_*. The user > + * should treat these fields as opaque data. > + */ > +static int gen_st_ops_shadow_type(const char *obj_name, struct btf *btf, const char *ident, > + const struct bpf_map *map) > +{ > + const struct btf_type *map_type; > + const char *type_name; > + __u32 map_type_id; > + int err; > + > + map_type_id = bpf_map__btf_value_type_id(map); > + if (map_type_id == 0) > + return -EINVAL; > + map_type = btf__type_by_id(btf, map_type_id); > + if (!map_type) > + return -EINVAL; > + > + type_name = btf__name_by_offset(btf, map_type->name_off); > + > + printf("\t\tstruct %s_%s_%s {\n", obj_name, ident, type_name); it should be %s__%s__%s, I fixed it up > + > + err = walk_st_ops_shadow_vars(btf, ident, map_type, map_type_id); > + if (err) > + return err; > + > + printf("\t\t} *%s;\n", ident); > + > + return 0; > +} > + > +static int gen_st_ops_shadow(const char *obj_name, struct btf *btf, struct bpf_object *obj) > +{ > + int err, st_ops_cnt = 0; > + struct bpf_map *map; > + char ident[256]; > + > + if (!btf) > + return 0; > + > + /* Generate the pointers to shadow types of > + * struct_ops maps. > + */ > + bpf_object__for_each_map(map, obj) { > + if (bpf_map__type(map) != BPF_MAP_TYPE_STRUCT_OPS) > + continue; > + if (!get_map_ident(map, ident, sizeof(ident))) > + continue; > + > + if (!st_ops_cnt++) goodness, too much operator precedence knowledge assumed, I simplified this to what I can follow myself: if (st_ops_cnt == 0) printf(...); st_ops_cnt++; I don't think saving one line of code is worth it. > + printf("\tstruct {\n"); > + > + err = gen_st_ops_shadow_type(obj_name, btf, ident, map); > + if (err) > + return err; > + } > + > + if (st_ops_cnt) > + printf("\t} struct_ops;\n"); > + > + return 0; > +} > + [...]