mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-04-24 14:07:52 -04:00
libbpf: Create a bpf_link in bpf_map__attach_struct_ops().
bpf_map__attach_struct_ops() was creating a dummy bpf_link as a placeholder, but now it is constructing an authentic one by calling bpf_link_create() if the map has the BPF_F_LINK flag. You can flag a struct_ops map with BPF_F_LINK by calling bpf_map__set_map_flags(). Signed-off-by: Kui-Feng Lee <kuifeng@meta.com> Acked-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/r/20230323032405.3735486-5-kuifeng@meta.com Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
This commit is contained in:
parent
68b04864ca
commit
8d1608d709
1 changed files with 74 additions and 27 deletions
|
@ -116,6 +116,7 @@ static const char * const attach_type_name[] = {
|
||||||
[BPF_SK_REUSEPORT_SELECT_OR_MIGRATE] = "sk_reuseport_select_or_migrate",
|
[BPF_SK_REUSEPORT_SELECT_OR_MIGRATE] = "sk_reuseport_select_or_migrate",
|
||||||
[BPF_PERF_EVENT] = "perf_event",
|
[BPF_PERF_EVENT] = "perf_event",
|
||||||
[BPF_TRACE_KPROBE_MULTI] = "trace_kprobe_multi",
|
[BPF_TRACE_KPROBE_MULTI] = "trace_kprobe_multi",
|
||||||
|
[BPF_STRUCT_OPS] = "struct_ops",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char * const link_type_name[] = {
|
static const char * const link_type_name[] = {
|
||||||
|
@ -7686,6 +7687,37 @@ static int bpf_object__resolve_externs(struct bpf_object *obj,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bpf_map_prepare_vdata(const struct bpf_map *map)
|
||||||
|
{
|
||||||
|
struct bpf_struct_ops *st_ops;
|
||||||
|
__u32 i;
|
||||||
|
|
||||||
|
st_ops = map->st_ops;
|
||||||
|
for (i = 0; i < btf_vlen(st_ops->type); i++) {
|
||||||
|
struct bpf_program *prog = st_ops->progs[i];
|
||||||
|
void *kern_data;
|
||||||
|
int prog_fd;
|
||||||
|
|
||||||
|
if (!prog)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
prog_fd = bpf_program__fd(prog);
|
||||||
|
kern_data = st_ops->kern_vdata + st_ops->kern_func_off[i];
|
||||||
|
*(unsigned long *)kern_data = prog_fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bpf_object_prepare_struct_ops(struct bpf_object *obj)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < obj->nr_maps; i++)
|
||||||
|
if (bpf_map__is_struct_ops(&obj->maps[i]))
|
||||||
|
bpf_map_prepare_vdata(&obj->maps[i]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int bpf_object_load(struct bpf_object *obj, int extra_log_level, const char *target_btf_path)
|
static int bpf_object_load(struct bpf_object *obj, int extra_log_level, const char *target_btf_path)
|
||||||
{
|
{
|
||||||
int err, i;
|
int err, i;
|
||||||
|
@ -7711,6 +7743,7 @@ static int bpf_object_load(struct bpf_object *obj, int extra_log_level, const ch
|
||||||
err = err ? : bpf_object__relocate(obj, obj->btf_custom_path ? : target_btf_path);
|
err = err ? : bpf_object__relocate(obj, obj->btf_custom_path ? : target_btf_path);
|
||||||
err = err ? : bpf_object__load_progs(obj, extra_log_level);
|
err = err ? : bpf_object__load_progs(obj, extra_log_level);
|
||||||
err = err ? : bpf_object_init_prog_arrays(obj);
|
err = err ? : bpf_object_init_prog_arrays(obj);
|
||||||
|
err = err ? : bpf_object_prepare_struct_ops(obj);
|
||||||
|
|
||||||
if (obj->gen_loader) {
|
if (obj->gen_loader) {
|
||||||
/* reset FDs */
|
/* reset FDs */
|
||||||
|
@ -11579,22 +11612,30 @@ struct bpf_link *bpf_program__attach(const struct bpf_program *prog)
|
||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct bpf_link_struct_ops {
|
||||||
|
struct bpf_link link;
|
||||||
|
int map_fd;
|
||||||
|
};
|
||||||
|
|
||||||
static int bpf_link__detach_struct_ops(struct bpf_link *link)
|
static int bpf_link__detach_struct_ops(struct bpf_link *link)
|
||||||
{
|
{
|
||||||
|
struct bpf_link_struct_ops *st_link;
|
||||||
__u32 zero = 0;
|
__u32 zero = 0;
|
||||||
|
|
||||||
if (bpf_map_delete_elem(link->fd, &zero))
|
st_link = container_of(link, struct bpf_link_struct_ops, link);
|
||||||
return -errno;
|
|
||||||
|
|
||||||
return 0;
|
if (st_link->map_fd < 0)
|
||||||
|
/* w/o a real link */
|
||||||
|
return bpf_map_delete_elem(link->fd, &zero);
|
||||||
|
|
||||||
|
return close(link->fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct bpf_link *bpf_map__attach_struct_ops(const struct bpf_map *map)
|
struct bpf_link *bpf_map__attach_struct_ops(const struct bpf_map *map)
|
||||||
{
|
{
|
||||||
struct bpf_struct_ops *st_ops;
|
struct bpf_link_struct_ops *link;
|
||||||
struct bpf_link *link;
|
__u32 zero = 0;
|
||||||
__u32 i, zero = 0;
|
int err, fd;
|
||||||
int err;
|
|
||||||
|
|
||||||
if (!bpf_map__is_struct_ops(map) || map->fd == -1)
|
if (!bpf_map__is_struct_ops(map) || map->fd == -1)
|
||||||
return libbpf_err_ptr(-EINVAL);
|
return libbpf_err_ptr(-EINVAL);
|
||||||
|
@ -11603,31 +11644,37 @@ struct bpf_link *bpf_map__attach_struct_ops(const struct bpf_map *map)
|
||||||
if (!link)
|
if (!link)
|
||||||
return libbpf_err_ptr(-EINVAL);
|
return libbpf_err_ptr(-EINVAL);
|
||||||
|
|
||||||
st_ops = map->st_ops;
|
/* kern_vdata should be prepared during the loading phase. */
|
||||||
for (i = 0; i < btf_vlen(st_ops->type); i++) {
|
err = bpf_map_update_elem(map->fd, &zero, map->st_ops->kern_vdata, 0);
|
||||||
struct bpf_program *prog = st_ops->progs[i];
|
/* It can be EBUSY if the map has been used to create or
|
||||||
void *kern_data;
|
* update a link before. We don't allow updating the value of
|
||||||
int prog_fd;
|
* a struct_ops once it is set. That ensures that the value
|
||||||
|
* never changed. So, it is safe to skip EBUSY.
|
||||||
if (!prog)
|
*/
|
||||||
continue;
|
if (err && (!(map->def.map_flags & BPF_F_LINK) || err != -EBUSY)) {
|
||||||
|
|
||||||
prog_fd = bpf_program__fd(prog);
|
|
||||||
kern_data = st_ops->kern_vdata + st_ops->kern_func_off[i];
|
|
||||||
*(unsigned long *)kern_data = prog_fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = bpf_map_update_elem(map->fd, &zero, st_ops->kern_vdata, 0);
|
|
||||||
if (err) {
|
|
||||||
err = -errno;
|
|
||||||
free(link);
|
free(link);
|
||||||
return libbpf_err_ptr(err);
|
return libbpf_err_ptr(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
link->detach = bpf_link__detach_struct_ops;
|
link->link.detach = bpf_link__detach_struct_ops;
|
||||||
link->fd = map->fd;
|
|
||||||
|
|
||||||
return link;
|
if (!(map->def.map_flags & BPF_F_LINK)) {
|
||||||
|
/* w/o a real link */
|
||||||
|
link->link.fd = map->fd;
|
||||||
|
link->map_fd = -1;
|
||||||
|
return &link->link;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = bpf_link_create(map->fd, 0, BPF_STRUCT_OPS, NULL);
|
||||||
|
if (fd < 0) {
|
||||||
|
free(link);
|
||||||
|
return libbpf_err_ptr(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
link->link.fd = fd;
|
||||||
|
link->map_fd = map->fd;
|
||||||
|
|
||||||
|
return &link->link;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef enum bpf_perf_event_ret (*bpf_perf_event_print_t)(struct perf_event_header *hdr,
|
typedef enum bpf_perf_event_ret (*bpf_perf_event_print_t)(struct perf_event_header *hdr,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue