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

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.com


Signed-off-by: default avatarMartin KaFai Lau <martin.lau@kernel.org>
parent aef56f2e
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -794,11 +794,17 @@ int bpf_link_update(int link_fd, int new_prog_fd,
	if (!OPTS_VALID(opts, bpf_link_update_opts))
		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);
	attr.link_update.link_fd = link_fd;
	attr.link_update.new_prog_fd = new_prog_fd;
	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);
	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);
	return libbpf_err_errno(ret);
+2 −1
Original line number Diff line number Diff line
@@ -336,8 +336,9 @@ struct bpf_link_update_opts {
	size_t sz; /* size of this struct for forward/backward compatibility */
	__u32 flags;	   /* extra flags */
	__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,
			       const struct bpf_link_update_opts *opts);
+35 −0
Original line number Diff line number Diff line
@@ -11677,6 +11677,41 @@ struct bpf_link *bpf_map__attach_struct_ops(const struct bpf_map *map)
	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,
							  void *private_data);

+1 −0
Original line number Diff line number Diff line
@@ -719,6 +719,7 @@ bpf_program__attach_freplace(const struct bpf_program *prog,
struct bpf_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 {
	size_t sz; /* size of this struct for forward/backward compatibility */
+1 −0
Original line number Diff line number Diff line
@@ -386,6 +386,7 @@ LIBBPF_1.1.0 {
LIBBPF_1.2.0 {
	global:
		bpf_btf_get_info_by_fd;
		bpf_link__update_map;
		bpf_link_get_info_by_fd;
		bpf_map_get_info_by_fd;
		bpf_prog_get_info_by_fd;