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: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20200330030001.2312810-4-andriin@fb.com
			
			
This commit is contained in:
		
							parent
							
								
									0c991ebc8c
								
							
						
					
					
						commit
						cc4f864bb1
					
				| @ -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
 | ||||
|  | ||||
| @ -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) | ||||
| { | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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; | ||||
| 
 | ||||
| /*
 | ||||
|  | ||||
| @ -243,7 +243,11 @@ LIBBPF_0.0.8 { | ||||
| 		bpf_link__pin; | ||||
| 		bpf_link__pin_path; | ||||
| 		bpf_link__unpin; | ||||
| 		bpf_link__update_program; | ||||
| 		bpf_link_create; | ||||
| 		bpf_link_update; | ||||
| 		bpf_map__set_initial_value; | ||||
| 		bpf_program__attach_cgroup; | ||||
| 		bpf_program__attach_lsm; | ||||
| 		bpf_program__is_lsm; | ||||
| 		bpf_program__set_attach_target; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user