Skip to content

Commit a7b0fa3

Browse files
ThinkerYzu1anakryiko
authored andcommitted
bpftool: Generated shadow variables for struct_ops maps.
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. Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Reviewed-by: Quentin Monnet <quentin@isovalent.com> Link: https://lore.kernel.org/bpf/20240229064523.2091270-4-thinker.li@gmail.com
1 parent 69e4a9d commit a7b0fa3

File tree

1 file changed

+236
-1
lines changed

1 file changed

+236
-1
lines changed

tools/bpf/bpftool/gen.c

Lines changed: 236 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,20 @@ static bool str_has_suffix(const char *str, const char *suffix)
5555
return true;
5656
}
5757

58+
static const struct btf_type *
59+
resolve_func_ptr(const struct btf *btf, __u32 id, __u32 *res_id)
60+
{
61+
const struct btf_type *t;
62+
63+
t = skip_mods_and_typedefs(btf, id, NULL);
64+
if (!btf_is_ptr(t))
65+
return NULL;
66+
67+
t = skip_mods_and_typedefs(btf, t->type, res_id);
68+
69+
return btf_is_func_proto(t) ? t : NULL;
70+
}
71+
5872
static void get_obj_name(char *name, const char *file)
5973
{
6074
char file_copy[PATH_MAX];
@@ -909,6 +923,207 @@ codegen_progs_skeleton(struct bpf_object *obj, size_t prog_cnt, bool populate_li
909923
}
910924
}
911925

926+
static int walk_st_ops_shadow_vars(struct btf *btf, const char *ident,
927+
const struct btf_type *map_type, __u32 map_type_id)
928+
{
929+
LIBBPF_OPTS(btf_dump_emit_type_decl_opts, opts, .indent_level = 3);
930+
const struct btf_type *member_type;
931+
__u32 offset, next_offset = 0;
932+
const struct btf_member *m;
933+
struct btf_dump *d = NULL;
934+
const char *member_name;
935+
__u32 member_type_id;
936+
int i, err = 0, n;
937+
int size;
938+
939+
d = btf_dump__new(btf, codegen_btf_dump_printf, NULL, NULL);
940+
if (!d)
941+
return -errno;
942+
943+
n = btf_vlen(map_type);
944+
for (i = 0, m = btf_members(map_type); i < n; i++, m++) {
945+
member_type = skip_mods_and_typedefs(btf, m->type, &member_type_id);
946+
member_name = btf__name_by_offset(btf, m->name_off);
947+
948+
offset = m->offset / 8;
949+
if (next_offset < offset)
950+
printf("\t\t\tchar __padding_%d[%d];\n", i, offset - next_offset);
951+
952+
switch (btf_kind(member_type)) {
953+
case BTF_KIND_INT:
954+
case BTF_KIND_FLOAT:
955+
case BTF_KIND_ENUM:
956+
case BTF_KIND_ENUM64:
957+
/* scalar type */
958+
printf("\t\t\t");
959+
opts.field_name = member_name;
960+
err = btf_dump__emit_type_decl(d, member_type_id, &opts);
961+
if (err) {
962+
p_err("Failed to emit type declaration for %s: %d", member_name, err);
963+
goto out;
964+
}
965+
printf(";\n");
966+
967+
size = btf__resolve_size(btf, member_type_id);
968+
if (size < 0) {
969+
p_err("Failed to resolve size of %s: %d\n", member_name, size);
970+
err = size;
971+
goto out;
972+
}
973+
974+
next_offset = offset + size;
975+
break;
976+
977+
case BTF_KIND_PTR:
978+
if (resolve_func_ptr(btf, m->type, NULL)) {
979+
/* Function pointer */
980+
printf("\t\t\tstruct bpf_program *%s;\n", member_name);
981+
982+
next_offset = offset + sizeof(void *);
983+
break;
984+
}
985+
/* All pointer types are unsupported except for
986+
* function pointers.
987+
*/
988+
fallthrough;
989+
990+
default:
991+
/* Unsupported types
992+
*
993+
* Types other than scalar types and function
994+
* pointers are currently not supported in order to
995+
* prevent conflicts in the generated code caused
996+
* by multiple definitions. For instance, if the
997+
* struct type FOO is used in a struct_ops map,
998+
* bpftool has to generate definitions for FOO,
999+
* which may result in conflicts if FOO is defined
1000+
* in different skeleton files.
1001+
*/
1002+
size = btf__resolve_size(btf, member_type_id);
1003+
if (size < 0) {
1004+
p_err("Failed to resolve size of %s: %d\n", member_name, size);
1005+
err = size;
1006+
goto out;
1007+
}
1008+
printf("\t\t\tchar __unsupported_%d[%d];\n", i, size);
1009+
1010+
next_offset = offset + size;
1011+
break;
1012+
}
1013+
}
1014+
1015+
/* Cannot fail since it must be a struct type */
1016+
size = btf__resolve_size(btf, map_type_id);
1017+
if (next_offset < (__u32)size)
1018+
printf("\t\t\tchar __padding_end[%d];\n", size - next_offset);
1019+
1020+
out:
1021+
btf_dump__free(d);
1022+
1023+
return err;
1024+
}
1025+
1026+
/* Generate the pointer of the shadow type for a struct_ops map.
1027+
*
1028+
* This function adds a pointer of the shadow type for a struct_ops map.
1029+
* The members of a struct_ops map can be exported through a pointer to a
1030+
* shadow type. The user can access these members through the pointer.
1031+
*
1032+
* A shadow type includes not all members, only members of some types.
1033+
* They are scalar types and function pointers. The function pointers are
1034+
* translated to the pointer of the struct bpf_program. The scalar types
1035+
* are translated to the original type without any modifiers.
1036+
*
1037+
* Unsupported types will be translated to a char array to occupy the same
1038+
* space as the original field, being renamed as __unsupported_*. The user
1039+
* should treat these fields as opaque data.
1040+
*/
1041+
static int gen_st_ops_shadow_type(const char *obj_name, struct btf *btf, const char *ident,
1042+
const struct bpf_map *map)
1043+
{
1044+
const struct btf_type *map_type;
1045+
const char *type_name;
1046+
__u32 map_type_id;
1047+
int err;
1048+
1049+
map_type_id = bpf_map__btf_value_type_id(map);
1050+
if (map_type_id == 0)
1051+
return -EINVAL;
1052+
map_type = btf__type_by_id(btf, map_type_id);
1053+
if (!map_type)
1054+
return -EINVAL;
1055+
1056+
type_name = btf__name_by_offset(btf, map_type->name_off);
1057+
1058+
printf("\t\tstruct %s__%s__%s {\n", obj_name, ident, type_name);
1059+
1060+
err = walk_st_ops_shadow_vars(btf, ident, map_type, map_type_id);
1061+
if (err)
1062+
return err;
1063+
1064+
printf("\t\t} *%s;\n", ident);
1065+
1066+
return 0;
1067+
}
1068+
1069+
static int gen_st_ops_shadow(const char *obj_name, struct btf *btf, struct bpf_object *obj)
1070+
{
1071+
int err, st_ops_cnt = 0;
1072+
struct bpf_map *map;
1073+
char ident[256];
1074+
1075+
if (!btf)
1076+
return 0;
1077+
1078+
/* Generate the pointers to shadow types of
1079+
* struct_ops maps.
1080+
*/
1081+
bpf_object__for_each_map(map, obj) {
1082+
if (bpf_map__type(map) != BPF_MAP_TYPE_STRUCT_OPS)
1083+
continue;
1084+
if (!get_map_ident(map, ident, sizeof(ident)))
1085+
continue;
1086+
1087+
if (st_ops_cnt == 0) /* first struct_ops map */
1088+
printf("\tstruct {\n");
1089+
st_ops_cnt++;
1090+
1091+
err = gen_st_ops_shadow_type(obj_name, btf, ident, map);
1092+
if (err)
1093+
return err;
1094+
}
1095+
1096+
if (st_ops_cnt)
1097+
printf("\t} struct_ops;\n");
1098+
1099+
return 0;
1100+
}
1101+
1102+
/* Generate the code to initialize the pointers of shadow types. */
1103+
static void gen_st_ops_shadow_init(struct btf *btf, struct bpf_object *obj)
1104+
{
1105+
struct bpf_map *map;
1106+
char ident[256];
1107+
1108+
if (!btf)
1109+
return;
1110+
1111+
/* Initialize the pointers to_ops shadow types of
1112+
* struct_ops maps.
1113+
*/
1114+
bpf_object__for_each_map(map, obj) {
1115+
if (bpf_map__type(map) != BPF_MAP_TYPE_STRUCT_OPS)
1116+
continue;
1117+
if (!get_map_ident(map, ident, sizeof(ident)))
1118+
continue;
1119+
codegen("\
1120+
\n\
1121+
obj->struct_ops.%1$s = bpf_map__initial_value(obj->maps.%1$s, NULL);\n\
1122+
\n\
1123+
", ident);
1124+
}
1125+
}
1126+
9121127
static int do_skeleton(int argc, char **argv)
9131128
{
9141129
char header_guard[MAX_OBJ_NAME_LEN + sizeof("__SKEL_H__")];
@@ -1052,6 +1267,11 @@ static int do_skeleton(int argc, char **argv)
10521267
printf("\t} maps;\n");
10531268
}
10541269

1270+
btf = bpf_object__btf(obj);
1271+
err = gen_st_ops_shadow(obj_name, btf, obj);
1272+
if (err)
1273+
goto out;
1274+
10551275
if (prog_cnt) {
10561276
printf("\tstruct {\n");
10571277
bpf_object__for_each_program(prog, obj) {
@@ -1075,7 +1295,6 @@ static int do_skeleton(int argc, char **argv)
10751295
printf("\t} links;\n");
10761296
}
10771297

1078-
btf = bpf_object__btf(obj);
10791298
if (btf) {
10801299
err = codegen_datasecs(obj, obj_name);
10811300
if (err)
@@ -1133,6 +1352,12 @@ static int do_skeleton(int argc, char **argv)
11331352
if (err) \n\
11341353
goto err_out; \n\
11351354
\n\
1355+
", obj_name);
1356+
1357+
gen_st_ops_shadow_init(btf, obj);
1358+
1359+
codegen("\
1360+
\n\
11361361
return obj; \n\
11371362
err_out: \n\
11381363
%1$s__destroy(obj); \n\
@@ -1442,6 +1667,10 @@ static int do_subskeleton(int argc, char **argv)
14421667
printf("\t} maps;\n");
14431668
}
14441669

1670+
err = gen_st_ops_shadow(obj_name, btf, obj);
1671+
if (err)
1672+
goto out;
1673+
14451674
if (prog_cnt) {
14461675
printf("\tstruct {\n");
14471676
bpf_object__for_each_program(prog, obj) {
@@ -1553,6 +1782,12 @@ static int do_subskeleton(int argc, char **argv)
15531782
if (err) \n\
15541783
goto err; \n\
15551784
\n\
1785+
");
1786+
1787+
gen_st_ops_shadow_init(btf, obj);
1788+
1789+
codegen("\
1790+
\n\
15561791
return obj; \n\
15571792
err: \n\
15581793
%1$s__destroy(obj); \n\

0 commit comments

Comments
 (0)