Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

authored by

Andrii Nakryiko and committed by
Alexei Starovoitov
cc4f864b 0c991ebc

+122 -1
+12
tools/include/uapi/linux/bpf.h
··· 112 112 BPF_MAP_UPDATE_BATCH, 113 113 BPF_MAP_DELETE_BATCH, 114 114 BPF_LINK_CREATE, 115 + BPF_LINK_UPDATE, 115 116 }; 116 117 117 118 enum bpf_map_type { ··· 578 577 __u32 attach_type; /* attach type */ 579 578 __u32 flags; /* extra flags */ 580 579 } link_create; 580 + 581 + struct { /* struct used by BPF_LINK_UPDATE command */ 582 + __u32 link_fd; /* link fd */ 583 + /* new program fd to update link with */ 584 + __u32 new_prog_fd; 585 + __u32 flags; /* extra flags */ 586 + /* expected link's program fd; is specified only if 587 + * BPF_F_REPLACE flag is set in flags */ 588 + __u32 old_prog_fd; 589 + } link_update; 590 + 581 591 } __attribute__((aligned(8))); 582 592 583 593 /* The description below is an attempt at providing documentation to eBPF
+34
tools/lib/bpf/bpf.c
··· 585 585 return sys_bpf(BPF_PROG_DETACH, &attr, sizeof(attr)); 586 586 } 587 587 588 + int bpf_link_create(int prog_fd, int target_fd, 589 + enum bpf_attach_type attach_type, 590 + const struct bpf_link_create_opts *opts) 591 + { 592 + union bpf_attr attr; 593 + 594 + if (!OPTS_VALID(opts, bpf_link_create_opts)) 595 + return -EINVAL; 596 + 597 + memset(&attr, 0, sizeof(attr)); 598 + attr.link_create.prog_fd = prog_fd; 599 + attr.link_create.target_fd = target_fd; 600 + attr.link_create.attach_type = attach_type; 601 + 602 + return sys_bpf(BPF_LINK_CREATE, &attr, sizeof(attr)); 603 + } 604 + 605 + int bpf_link_update(int link_fd, int new_prog_fd, 606 + const struct bpf_link_update_opts *opts) 607 + { 608 + union bpf_attr attr; 609 + 610 + if (!OPTS_VALID(opts, bpf_link_update_opts)) 611 + return -EINVAL; 612 + 613 + memset(&attr, 0, sizeof(attr)); 614 + attr.link_update.link_fd = link_fd; 615 + attr.link_update.new_prog_fd = new_prog_fd; 616 + attr.link_update.flags = OPTS_GET(opts, flags, 0); 617 + attr.link_update.old_prog_fd = OPTS_GET(opts, old_prog_fd, 0); 618 + 619 + return sys_bpf(BPF_LINK_UPDATE, &attr, sizeof(attr)); 620 + } 621 + 588 622 int bpf_prog_query(int target_fd, enum bpf_attach_type type, __u32 query_flags, 589 623 __u32 *attach_flags, __u32 *prog_ids, __u32 *prog_cnt) 590 624 {
+19
tools/lib/bpf/bpf.h
··· 168 168 LIBBPF_API int bpf_prog_detach2(int prog_fd, int attachable_fd, 169 169 enum bpf_attach_type type); 170 170 171 + struct bpf_link_create_opts { 172 + size_t sz; /* size of this struct for forward/backward compatibility */ 173 + }; 174 + #define bpf_link_create_opts__last_field sz 175 + 176 + LIBBPF_API int bpf_link_create(int prog_fd, int target_fd, 177 + enum bpf_attach_type attach_type, 178 + const struct bpf_link_create_opts *opts); 179 + 180 + struct bpf_link_update_opts { 181 + size_t sz; /* size of this struct for forward/backward compatibility */ 182 + __u32 flags; /* extra flags */ 183 + __u32 old_prog_fd; /* expected old program FD */ 184 + }; 185 + #define bpf_link_update_opts__last_field old_prog_fd 186 + 187 + LIBBPF_API int bpf_link_update(int link_fd, int new_prog_fd, 188 + const struct bpf_link_update_opts *opts); 189 + 171 190 struct bpf_prog_test_run_attr { 172 191 int prog_fd; 173 192 int repeat;
+46
tools/lib/bpf/libbpf.c
··· 6978 6978 bool disconnected; 6979 6979 }; 6980 6980 6981 + /* Replace link's underlying BPF program with the new one */ 6982 + int bpf_link__update_program(struct bpf_link *link, struct bpf_program *prog) 6983 + { 6984 + return bpf_link_update(bpf_link__fd(link), bpf_program__fd(prog), NULL); 6985 + } 6986 + 6981 6987 /* Release "ownership" of underlying BPF resource (typically, BPF program 6982 6988 * attached to some BPF hook, e.g., tracepoint, kprobe, etc). Disconnected 6983 6989 * link, when destructed through bpf_link__destroy() call won't attempt to ··· 7537 7531 struct bpf_program *prog) 7538 7532 { 7539 7533 return bpf_program__attach_lsm(prog); 7534 + } 7535 + 7536 + struct bpf_link * 7537 + bpf_program__attach_cgroup(struct bpf_program *prog, int cgroup_fd) 7538 + { 7539 + const struct bpf_sec_def *sec_def; 7540 + enum bpf_attach_type attach_type; 7541 + char errmsg[STRERR_BUFSIZE]; 7542 + struct bpf_link *link; 7543 + int prog_fd, link_fd; 7544 + 7545 + prog_fd = bpf_program__fd(prog); 7546 + if (prog_fd < 0) { 7547 + pr_warn("program '%s': can't attach before loaded\n", 7548 + bpf_program__title(prog, false)); 7549 + return ERR_PTR(-EINVAL); 7550 + } 7551 + 7552 + link = calloc(1, sizeof(*link)); 7553 + if (!link) 7554 + return ERR_PTR(-ENOMEM); 7555 + link->detach = &bpf_link__detach_fd; 7556 + 7557 + attach_type = bpf_program__get_expected_attach_type(prog); 7558 + if (!attach_type) { 7559 + sec_def = find_sec_def(bpf_program__title(prog, false)); 7560 + if (sec_def) 7561 + attach_type = sec_def->attach_type; 7562 + } 7563 + link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, NULL); 7564 + if (link_fd < 0) { 7565 + link_fd = -errno; 7566 + free(link); 7567 + pr_warn("program '%s': failed to attach to cgroup: %s\n", 7568 + bpf_program__title(prog, false), 7569 + libbpf_strerror_r(link_fd, errmsg, sizeof(errmsg))); 7570 + return ERR_PTR(link_fd); 7571 + } 7572 + link->fd = link_fd; 7573 + return link; 7540 7574 } 7541 7575 7542 7576 struct bpf_link *bpf_program__attach(struct bpf_program *prog)
+7 -1
tools/lib/bpf/libbpf.h
··· 224 224 LIBBPF_API const char *bpf_link__pin_path(const struct bpf_link *link); 225 225 LIBBPF_API int bpf_link__pin(struct bpf_link *link, const char *path); 226 226 LIBBPF_API int bpf_link__unpin(struct bpf_link *link); 227 + LIBBPF_API int bpf_link__update_program(struct bpf_link *link, 228 + struct bpf_program *prog); 227 229 LIBBPF_API void bpf_link__disconnect(struct bpf_link *link); 228 230 LIBBPF_API int bpf_link__destroy(struct bpf_link *link); 229 231 ··· 247 245 LIBBPF_API struct bpf_link * 248 246 bpf_program__attach_raw_tracepoint(struct bpf_program *prog, 249 247 const char *tp_name); 250 - 251 248 LIBBPF_API struct bpf_link * 252 249 bpf_program__attach_trace(struct bpf_program *prog); 253 250 LIBBPF_API struct bpf_link * 254 251 bpf_program__attach_lsm(struct bpf_program *prog); 252 + LIBBPF_API struct bpf_link * 253 + bpf_program__attach_cgroup(struct bpf_program *prog, int cgroup_fd); 254 + 255 255 struct bpf_map; 256 + 256 257 LIBBPF_API struct bpf_link *bpf_map__attach_struct_ops(struct bpf_map *map); 258 + 257 259 struct bpf_insn; 258 260 259 261 /*
+4
tools/lib/bpf/libbpf.map
··· 243 243 bpf_link__pin; 244 244 bpf_link__pin_path; 245 245 bpf_link__unpin; 246 + bpf_link__update_program; 247 + bpf_link_create; 248 + bpf_link_update; 246 249 bpf_map__set_initial_value; 250 + bpf_program__attach_cgroup; 247 251 bpf_program__attach_lsm; 248 252 bpf_program__is_lsm; 249 253 bpf_program__set_attach_target;