Commit 912dd4b0 authored by Kui-Feng Lee's avatar Kui-Feng Lee Committed by Martin KaFai Lau

libbpf: Update a bpf_link with another struct_ops.

Introduce bpf_link__update_map(), which allows to atomically update
underlying struct_ops implementation for given struct_ops BPF link.

Also add old_map_fd to struct bpf_link_update_opts to handle
BPF_F_REPLACE feature.
Signed-off-by: default avatarKui-Feng Lee <kuifeng@meta.com>
Link: https://lore.kernel.org/r/20230323032405.3735486-7-kuifeng@meta.comSigned-off-by: default avatarMartin KaFai Lau <martin.lau@kernel.org>
parent aef56f2e
...@@ -794,11 +794,17 @@ int bpf_link_update(int link_fd, int new_prog_fd, ...@@ -794,11 +794,17 @@ int bpf_link_update(int link_fd, int new_prog_fd,
if (!OPTS_VALID(opts, bpf_link_update_opts)) if (!OPTS_VALID(opts, bpf_link_update_opts))
return libbpf_err(-EINVAL); return libbpf_err(-EINVAL);
if (OPTS_GET(opts, old_prog_fd, 0) && OPTS_GET(opts, old_map_fd, 0))
return libbpf_err(-EINVAL);
memset(&attr, 0, attr_sz); memset(&attr, 0, attr_sz);
attr.link_update.link_fd = link_fd; attr.link_update.link_fd = link_fd;
attr.link_update.new_prog_fd = new_prog_fd; attr.link_update.new_prog_fd = new_prog_fd;
attr.link_update.flags = OPTS_GET(opts, flags, 0); attr.link_update.flags = OPTS_GET(opts, flags, 0);
if (OPTS_GET(opts, old_prog_fd, 0))
attr.link_update.old_prog_fd = OPTS_GET(opts, old_prog_fd, 0); attr.link_update.old_prog_fd = OPTS_GET(opts, old_prog_fd, 0);
else if (OPTS_GET(opts, old_map_fd, 0))
attr.link_update.old_map_fd = OPTS_GET(opts, old_map_fd, 0);
ret = sys_bpf(BPF_LINK_UPDATE, &attr, attr_sz); ret = sys_bpf(BPF_LINK_UPDATE, &attr, attr_sz);
return libbpf_err_errno(ret); return libbpf_err_errno(ret);
......
...@@ -336,8 +336,9 @@ struct bpf_link_update_opts { ...@@ -336,8 +336,9 @@ struct bpf_link_update_opts {
size_t sz; /* size of this struct for forward/backward compatibility */ size_t sz; /* size of this struct for forward/backward compatibility */
__u32 flags; /* extra flags */ __u32 flags; /* extra flags */
__u32 old_prog_fd; /* expected old program FD */ __u32 old_prog_fd; /* expected old program FD */
__u32 old_map_fd; /* expected old map FD */
}; };
#define bpf_link_update_opts__last_field old_prog_fd #define bpf_link_update_opts__last_field old_map_fd
LIBBPF_API int bpf_link_update(int link_fd, int new_prog_fd, LIBBPF_API int bpf_link_update(int link_fd, int new_prog_fd,
const struct bpf_link_update_opts *opts); const struct bpf_link_update_opts *opts);
......
...@@ -11677,6 +11677,41 @@ struct bpf_link *bpf_map__attach_struct_ops(const struct bpf_map *map) ...@@ -11677,6 +11677,41 @@ struct bpf_link *bpf_map__attach_struct_ops(const struct bpf_map *map)
return &link->link; return &link->link;
} }
/*
* Swap the back struct_ops of a link with a new struct_ops map.
*/
int bpf_link__update_map(struct bpf_link *link, const struct bpf_map *map)
{
struct bpf_link_struct_ops *st_ops_link;
__u32 zero = 0;
int err;
if (!bpf_map__is_struct_ops(map) || map->fd < 0)
return -EINVAL;
st_ops_link = container_of(link, struct bpf_link_struct_ops, link);
/* Ensure the type of a link is correct */
if (st_ops_link->map_fd < 0)
return -EINVAL;
err = bpf_map_update_elem(map->fd, &zero, map->st_ops->kern_vdata, 0);
/* It can be EBUSY if the map has been used to create or
* update a link before. We don't allow updating the value of
* a struct_ops once it is set. That ensures that the value
* never changed. So, it is safe to skip EBUSY.
*/
if (err && err != -EBUSY)
return err;
err = bpf_link_update(link->fd, map->fd, NULL);
if (err < 0)
return err;
st_ops_link->map_fd = map->fd;
return 0;
}
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,
void *private_data); void *private_data);
......
...@@ -719,6 +719,7 @@ bpf_program__attach_freplace(const struct bpf_program *prog, ...@@ -719,6 +719,7 @@ bpf_program__attach_freplace(const struct bpf_program *prog,
struct bpf_map; struct bpf_map;
LIBBPF_API struct bpf_link *bpf_map__attach_struct_ops(const struct bpf_map *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);
struct bpf_iter_attach_opts { struct bpf_iter_attach_opts {
size_t sz; /* size of this struct for forward/backward compatibility */ size_t sz; /* size of this struct for forward/backward compatibility */
......
...@@ -386,6 +386,7 @@ LIBBPF_1.1.0 { ...@@ -386,6 +386,7 @@ LIBBPF_1.1.0 {
LIBBPF_1.2.0 { LIBBPF_1.2.0 {
global: global:
bpf_btf_get_info_by_fd; bpf_btf_get_info_by_fd;
bpf_link__update_map;
bpf_link_get_info_by_fd; bpf_link_get_info_by_fd;
bpf_map_get_info_by_fd; bpf_map_get_info_by_fd;
bpf_prog_get_info_by_fd; bpf_prog_get_info_by_fd;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment