Commit cc4f864b authored by Andrii Nakryiko's avatar Andrii Nakryiko Committed by Alexei Starovoitov
Browse files

libbpf: Add support for bpf_link-based cgroup attachment



Add bpf_program__attach_cgroup(), which uses BPF_LINK_CREATE subcommand to
create an FD-based kernel bpf_link. Also add low-level bpf_link_create() API.

If expected_attach_type is not specified explicitly with
bpf_program__set_expected_attach_type(), libbpf will try to determine proper
attach type from BPF program's section definition.

Also add support for bpf_link's underlying BPF program replacement:
  - unconditional through high-level bpf_link__update_program() API;
  - cmpxchg-like with specifying expected current BPF program through
    low-level bpf_link_update() API.

Signed-off-by: default avatarAndrii Nakryiko <andriin@fb.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20200330030001.2312810-4-andriin@fb.com
parent 0c991ebc
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -112,6 +112,7 @@ enum bpf_cmd {
	BPF_MAP_UPDATE_BATCH,
	BPF_MAP_DELETE_BATCH,
	BPF_LINK_CREATE,
	BPF_LINK_UPDATE,
};

enum bpf_map_type {
@@ -577,6 +578,17 @@ union bpf_attr {
		__u32		attach_type;	/* attach type */
		__u32		flags;		/* extra flags */
	} link_create;

	struct { /* struct used by BPF_LINK_UPDATE command */
		__u32		link_fd;	/* link fd */
		/* new program fd to update link with */
		__u32		new_prog_fd;
		__u32		flags;		/* extra flags */
		/* expected link's program fd; is specified only if
		 * BPF_F_REPLACE flag is set in flags */
		__u32		old_prog_fd;
	} link_update;

} __attribute__((aligned(8)));

/* The description below is an attempt at providing documentation to eBPF
+34 −0
Original line number Diff line number Diff line
@@ -585,6 +585,40 @@ int bpf_prog_detach2(int prog_fd, int target_fd, enum bpf_attach_type type)
	return sys_bpf(BPF_PROG_DETACH, &attr, sizeof(attr));
}

int bpf_link_create(int prog_fd, int target_fd,
		    enum bpf_attach_type attach_type,
		    const struct bpf_link_create_opts *opts)
{
	union bpf_attr attr;

	if (!OPTS_VALID(opts, bpf_link_create_opts))
		return -EINVAL;

	memset(&attr, 0, sizeof(attr));
	attr.link_create.prog_fd = prog_fd;
	attr.link_create.target_fd = target_fd;
	attr.link_create.attach_type = attach_type;

	return sys_bpf(BPF_LINK_CREATE, &attr, sizeof(attr));
}

int bpf_link_update(int link_fd, int new_prog_fd,
		    const struct bpf_link_update_opts *opts)
{
	union bpf_attr attr;

	if (!OPTS_VALID(opts, bpf_link_update_opts))
		return -EINVAL;

	memset(&attr, 0, sizeof(attr));
	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);
	attr.link_update.old_prog_fd = OPTS_GET(opts, old_prog_fd, 0);

	return sys_bpf(BPF_LINK_UPDATE, &attr, sizeof(attr));
}

int bpf_prog_query(int target_fd, enum bpf_attach_type type, __u32 query_flags,
		   __u32 *attach_flags, __u32 *prog_ids, __u32 *prog_cnt)
{
+19 −0
Original line number Diff line number Diff line
@@ -168,6 +168,25 @@ LIBBPF_API int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type);
LIBBPF_API int bpf_prog_detach2(int prog_fd, int attachable_fd,
				enum bpf_attach_type type);

struct bpf_link_create_opts {
	size_t sz; /* size of this struct for forward/backward compatibility */
};
#define bpf_link_create_opts__last_field sz

LIBBPF_API int bpf_link_create(int prog_fd, int target_fd,
			       enum bpf_attach_type attach_type,
			       const struct bpf_link_create_opts *opts);

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 */
};
#define bpf_link_update_opts__last_field old_prog_fd

LIBBPF_API int bpf_link_update(int link_fd, int new_prog_fd,
			       const struct bpf_link_update_opts *opts);

struct bpf_prog_test_run_attr {
	int prog_fd;
	int repeat;
+46 −0
Original line number Diff line number Diff line
@@ -6978,6 +6978,12 @@ struct bpf_link {
	bool disconnected;
};

/* Replace link's underlying BPF program with the new one */
int bpf_link__update_program(struct bpf_link *link, struct bpf_program *prog)
{
	return bpf_link_update(bpf_link__fd(link), bpf_program__fd(prog), NULL);
}

/* Release "ownership" of underlying BPF resource (typically, BPF program
 * attached to some BPF hook, e.g., tracepoint, kprobe, etc). Disconnected
 * link, when destructed through bpf_link__destroy() call won't attempt to
@@ -7533,6 +7539,46 @@ static struct bpf_link *attach_lsm(const struct bpf_sec_def *sec,
	return bpf_program__attach_lsm(prog);
}

struct bpf_link *
bpf_program__attach_cgroup(struct bpf_program *prog, int cgroup_fd)
{
	const struct bpf_sec_def *sec_def;
	enum bpf_attach_type attach_type;
	char errmsg[STRERR_BUFSIZE];
	struct bpf_link *link;
	int prog_fd, link_fd;

	prog_fd = bpf_program__fd(prog);
	if (prog_fd < 0) {
		pr_warn("program '%s': can't attach before loaded\n",
			bpf_program__title(prog, false));
		return ERR_PTR(-EINVAL);
	}

	link = calloc(1, sizeof(*link));
	if (!link)
		return ERR_PTR(-ENOMEM);
	link->detach = &bpf_link__detach_fd;

	attach_type = bpf_program__get_expected_attach_type(prog);
	if (!attach_type) {
		sec_def = find_sec_def(bpf_program__title(prog, false));
		if (sec_def)
			attach_type = sec_def->attach_type;
	}
	link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, NULL);
	if (link_fd < 0) {
		link_fd = -errno;
		free(link);
		pr_warn("program '%s': failed to attach to cgroup: %s\n",
			bpf_program__title(prog, false),
			libbpf_strerror_r(link_fd, errmsg, sizeof(errmsg)));
		return ERR_PTR(link_fd);
	}
	link->fd = link_fd;
	return link;
}

struct bpf_link *bpf_program__attach(struct bpf_program *prog)
{
	const struct bpf_sec_def *sec_def;
+7 −1
Original line number Diff line number Diff line
@@ -224,6 +224,8 @@ LIBBPF_API int bpf_link__fd(const struct bpf_link *link);
LIBBPF_API const char *bpf_link__pin_path(const struct bpf_link *link);
LIBBPF_API int bpf_link__pin(struct bpf_link *link, const char *path);
LIBBPF_API int bpf_link__unpin(struct bpf_link *link);
LIBBPF_API int bpf_link__update_program(struct bpf_link *link,
					struct bpf_program *prog);
LIBBPF_API void bpf_link__disconnect(struct bpf_link *link);
LIBBPF_API int bpf_link__destroy(struct bpf_link *link);

@@ -245,13 +247,17 @@ bpf_program__attach_tracepoint(struct bpf_program *prog,
LIBBPF_API struct bpf_link *
bpf_program__attach_raw_tracepoint(struct bpf_program *prog,
				   const char *tp_name);

LIBBPF_API struct bpf_link *
bpf_program__attach_trace(struct bpf_program *prog);
LIBBPF_API struct bpf_link *
bpf_program__attach_lsm(struct bpf_program *prog);
LIBBPF_API struct bpf_link *
bpf_program__attach_cgroup(struct bpf_program *prog, int cgroup_fd);

struct bpf_map;

LIBBPF_API struct bpf_link *bpf_map__attach_struct_ops(struct bpf_map *map);

struct bpf_insn;

/*
Loading