Skip to content

Commit 69e4a9d

Browse files
ThinkerYzu1anakryiko
authored andcommitted
libbpf: Convert st_ops->data to shadow type.
Convert st_ops->data to the shadow type of the struct_ops map. The shadow type of a struct_ops type is a variant of the original struct type providing a way to access/change the values in the maps of the struct_ops type. bpf_map__initial_value() will return st_ops->data for struct_ops types. The skeleton is going to use it as the pointer to the shadow type of the original struct type. One of the main differences between the original struct type and the shadow type is that all function pointers of the shadow type are converted to pointers of struct bpf_program. Users can replace these bpf_program pointers with other BPF programs. The st_ops->progs[] will be updated before updating the value of a map to reflect the changes made by users. Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/bpf/20240229064523.2091270-3-thinker.li@gmail.com
1 parent 3644d28 commit 69e4a9d

File tree

1 file changed

+38
-2
lines changed

1 file changed

+38
-2
lines changed

tools/lib/bpf/libbpf.c

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,6 +1014,19 @@ static bool bpf_map__is_struct_ops(const struct bpf_map *map)
10141014
return map->def.type == BPF_MAP_TYPE_STRUCT_OPS;
10151015
}
10161016

1017+
static bool is_valid_st_ops_program(struct bpf_object *obj,
1018+
const struct bpf_program *prog)
1019+
{
1020+
int i;
1021+
1022+
for (i = 0; i < obj->nr_programs; i++) {
1023+
if (&obj->programs[i] == prog)
1024+
return prog->type == BPF_PROG_TYPE_STRUCT_OPS;
1025+
}
1026+
1027+
return false;
1028+
}
1029+
10171030
/* Init the map's fields that depend on kern_btf */
10181031
static int bpf_map__init_kern_struct_ops(struct bpf_map *map)
10191032
{
@@ -1102,9 +1115,16 @@ static int bpf_map__init_kern_struct_ops(struct bpf_map *map)
11021115
if (btf_is_ptr(mtype)) {
11031116
struct bpf_program *prog;
11041117

1105-
prog = st_ops->progs[i];
1118+
/* Update the value from the shadow type */
1119+
prog = *(void **)mdata;
1120+
st_ops->progs[i] = prog;
11061121
if (!prog)
11071122
continue;
1123+
if (!is_valid_st_ops_program(obj, prog)) {
1124+
pr_warn("struct_ops init_kern %s: member %s is not a struct_ops program\n",
1125+
map->name, mname);
1126+
return -ENOTSUP;
1127+
}
11081128

11091129
kern_mtype = skip_mods_and_typedefs(kern_btf,
11101130
kern_mtype->type,
@@ -9310,7 +9330,9 @@ static struct bpf_map *find_struct_ops_map_by_offset(struct bpf_object *obj,
93109330
return NULL;
93119331
}
93129332

9313-
/* Collect the reloc from ELF and populate the st_ops->progs[] */
9333+
/* Collect the reloc from ELF, populate the st_ops->progs[], and update
9334+
* st_ops->data for shadow type.
9335+
*/
93149336
static int bpf_object__collect_st_ops_relos(struct bpf_object *obj,
93159337
Elf64_Shdr *shdr, Elf_Data *data)
93169338
{
@@ -9424,6 +9446,14 @@ static int bpf_object__collect_st_ops_relos(struct bpf_object *obj,
94249446
}
94259447

94269448
st_ops->progs[member_idx] = prog;
9449+
9450+
/* st_ops->data will be exposed to users, being returned by
9451+
* bpf_map__initial_value() as a pointer to the shadow
9452+
* type. All function pointers in the original struct type
9453+
* should be converted to a pointer to struct bpf_program
9454+
* in the shadow type.
9455+
*/
9456+
*((struct bpf_program **)(st_ops->data + moff)) = prog;
94279457
}
94289458

94299459
return 0;
@@ -9882,6 +9912,12 @@ int bpf_map__set_initial_value(struct bpf_map *map,
98829912

98839913
void *bpf_map__initial_value(struct bpf_map *map, size_t *psize)
98849914
{
9915+
if (bpf_map__is_struct_ops(map)) {
9916+
if (psize)
9917+
*psize = map->def.value_size;
9918+
return map->st_ops->data;
9919+
}
9920+
98859921
if (!map->mmaped)
98869922
return NULL;
98879923
*psize = map->def.value_size;

0 commit comments

Comments
 (0)