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.
Unified · Split
| @@ -112,6 +112,7 @@ enum bpf_cmd { · 111 unmodified lines | ||
| 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 { |
| @@ -577,6 +578,17 @@ union bpf_attr { · 459 unmodified lines | ||
| 577 | 578 | __u32 attach_type; /* attach type */ |
| 578 | 579 | __u32 flags; /* extra flags */ |
| 579 | 580 | } link_create; |
| 581 | + | |
| 582 | + struct { /* struct used by BPF_LINK_UPDATE command */ | |
| 583 | + __u32 link_fd; /* link fd */ | |
| 584 | + /* new program fd to update link with */ | |
| 585 | + __u32 new_prog_fd; | |
| 586 | + __u32 flags; /* extra flags */ | |
| 587 | + /* expected link's program fd; is specified only if | |
| 588 | + * BPF_F_REPLACE flag is set in flags */ | |
| 589 | + __u32 old_prog_fd; | |
| 590 | + } link_update; | |
| 591 | + | |
| 580 | 592 | } __attribute__((aligned(8))); |
| 581 | 593 | |
| 582 | 594 | /* 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) · 584 unmodified lines | ||
| 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 | { |
| @@ -168,6 +168,25 @@ LIBBPF_API int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type); · 167 unmodified lines | ||
| 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; |
| @@ -6978,6 +6978,12 @@ struct bpf_link { · 6977 unmodified lines | ||
| 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 |
| @@ -7533,6 +7539,46 @@ static struct bpf_link *attach_lsm(const struct bpf_sec_def *sec, · 549 unmodified lines | ||
| 7533 | 7539 | return bpf_program__attach_lsm(prog); |
| 7534 | 7540 | } |
| 7535 | 7541 | |
| 7542 | +struct bpf_link * | |
| 7543 | +bpf_program__attach_cgroup(struct bpf_program *prog, int cgroup_fd) | |
| 7544 | +{ | |
| 7545 | + const struct bpf_sec_def *sec_def; | |
| 7546 | + enum bpf_attach_type attach_type; | |
| 7547 | + char errmsg[STRERR_BUFSIZE]; | |
| 7548 | + struct bpf_link *link; | |
| 7549 | + int prog_fd, link_fd; | |
| 7550 | + | |
| 7551 | + prog_fd = bpf_program__fd(prog); | |
| 7552 | + if (prog_fd < 0) { | |
| 7553 | + pr_warn("program '%s': can't attach before loaded\n", | |
| 7554 | + bpf_program__title(prog, false)); | |
| 7555 | + return ERR_PTR(-EINVAL); | |
| 7556 | + } | |
| 7557 | + | |
| 7558 | + link = calloc(1, sizeof(*link)); | |
| 7559 | + if (!link) | |
| 7560 | + return ERR_PTR(-ENOMEM); | |
| 7561 | + link->detach = &bpf_link__detach_fd; | |
| 7562 | + | |
| 7563 | + attach_type = bpf_program__get_expected_attach_type(prog); | |
| 7564 | + if (!attach_type) { | |
| 7565 | + sec_def = find_sec_def(bpf_program__title(prog, false)); | |
| 7566 | + if (sec_def) | |
| 7567 | + attach_type = sec_def->attach_type; | |
| 7568 | + } | |
| 7569 | + link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, NULL); | |
| 7570 | + if (link_fd < 0) { | |
| 7571 | + link_fd = -errno; | |
| 7572 | + free(link); | |
| 7573 | + pr_warn("program '%s': failed to attach to cgroup: %s\n", | |
| 7574 | + bpf_program__title(prog, false), | |
| 7575 | + libbpf_strerror_r(link_fd, errmsg, sizeof(errmsg))); | |
| 7576 | + return ERR_PTR(link_fd); | |
| 7577 | + } | |
| 7578 | + link->fd = link_fd; | |
| 7579 | + return link; | |
| 7580 | +} | |
| 7581 | + | |
| 7536 | 7582 | struct bpf_link *bpf_program__attach(struct bpf_program *prog) |
| 7537 | 7583 | { |
| 7538 | 7584 | const struct bpf_sec_def *sec_def; |
| @@ -224,6 +224,8 @@ LIBBPF_API int bpf_link__fd(const struct bpf_link *link); · 223 unmodified lines | ||
| 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 | |
| @@ -245,13 +247,17 @@ bpf_program__attach_tracepoint(struct bpf_program *prog, · 15 unmodified lines | ||
| 245 | 247 | LIBBPF_API struct bpf_link * |
| 246 | 248 | bpf_program__attach_raw_tracepoint(struct bpf_program *prog, |
| 247 | 249 | const char *tp_name); |
| 248 | − | |
| 249 | 250 | LIBBPF_API struct bpf_link * |
| 250 | 251 | bpf_program__attach_trace(struct bpf_program *prog); |
| 251 | 252 | LIBBPF_API struct bpf_link * |
| 252 | 253 | bpf_program__attach_lsm(struct bpf_program *prog); |
| 254 | +LIBBPF_API struct bpf_link * | |
| 255 | +bpf_program__attach_cgroup(struct bpf_program *prog, int cgroup_fd); | |
| 256 | + | |
| 253 | 257 | struct bpf_map; |
| 258 | + | |
| 254 | 259 | LIBBPF_API struct bpf_link *bpf_map__attach_struct_ops(struct bpf_map *map); |
| 260 | + | |
| 255 | 261 | struct bpf_insn; |
| 256 | 262 | |
| 257 | 263 | /* |
| @@ -243,7 +243,11 @@ LIBBPF_0.0.8 { · 242 unmodified lines | ||
| 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; |