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

libbpf: Add bpf_link pinning/unpinning

With bpf_link abstraction supported by kernel explicitly, add
pinning/unpinning API for links. Also allow to create (open) bpf_link from BPF
FS file.

This API allows to have an "ephemeral" FD-based BPF links (like raw tracepoint
or fexit/freplace attachments) surviving user process exit, by pinning them in
a BPF FS, which is an important use case for long-running BPF programs.

As part of this, expose underlying FD for bpf_link. While legacy bpf_link's
might not have a FD associated with them (which will be expressed as
a bpf_link with fd=-1), kernel's abstraction is based around FD-based usage,
so match it closely. This, subsequently, allows to have a generic
pinning/unpinning API for generalized bpf_link. For some types of bpf_links
kernel might not support pinning, in which case bpf_link__pin() will return
error.

With FD being part of generic bpf_link, also get rid of bpf_link_fd in favor
of using vanialla bpf_link.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20200303043159.323675-3-andriin@fb.com

authored by

Andrii Nakryiko and committed by
Alexei Starovoitov
c016b68e 70ed506c

+114 -27
+104 -27
tools/lib/bpf/libbpf.c
··· 6931 6931 struct bpf_link { 6932 6932 int (*detach)(struct bpf_link *link); 6933 6933 int (*destroy)(struct bpf_link *link); 6934 + char *pin_path; /* NULL, if not pinned */ 6935 + int fd; /* hook FD, -1 if not applicable */ 6934 6936 bool disconnected; 6935 6937 }; 6936 6938 ··· 6962 6960 err = link->detach(link); 6963 6961 if (link->destroy) 6964 6962 link->destroy(link); 6963 + if (link->pin_path) 6964 + free(link->pin_path); 6965 6965 free(link); 6966 6966 6967 6967 return err; 6968 6968 } 6969 6969 6970 - struct bpf_link_fd { 6971 - struct bpf_link link; /* has to be at the top of struct */ 6972 - int fd; /* hook FD */ 6973 - }; 6970 + int bpf_link__fd(const struct bpf_link *link) 6971 + { 6972 + return link->fd; 6973 + } 6974 + 6975 + const char *bpf_link__pin_path(const struct bpf_link *link) 6976 + { 6977 + return link->pin_path; 6978 + } 6979 + 6980 + static int bpf_link__detach_fd(struct bpf_link *link) 6981 + { 6982 + return close(link->fd); 6983 + } 6984 + 6985 + struct bpf_link *bpf_link__open(const char *path) 6986 + { 6987 + struct bpf_link *link; 6988 + int fd; 6989 + 6990 + fd = bpf_obj_get(path); 6991 + if (fd < 0) { 6992 + fd = -errno; 6993 + pr_warn("failed to open link at %s: %d\n", path, fd); 6994 + return ERR_PTR(fd); 6995 + } 6996 + 6997 + link = calloc(1, sizeof(*link)); 6998 + if (!link) { 6999 + close(fd); 7000 + return ERR_PTR(-ENOMEM); 7001 + } 7002 + link->detach = &bpf_link__detach_fd; 7003 + link->fd = fd; 7004 + 7005 + link->pin_path = strdup(path); 7006 + if (!link->pin_path) { 7007 + bpf_link__destroy(link); 7008 + return ERR_PTR(-ENOMEM); 7009 + } 7010 + 7011 + return link; 7012 + } 7013 + 7014 + int bpf_link__pin(struct bpf_link *link, const char *path) 7015 + { 7016 + int err; 7017 + 7018 + if (link->pin_path) 7019 + return -EBUSY; 7020 + err = make_parent_dir(path); 7021 + if (err) 7022 + return err; 7023 + err = check_path(path); 7024 + if (err) 7025 + return err; 7026 + 7027 + link->pin_path = strdup(path); 7028 + if (!link->pin_path) 7029 + return -ENOMEM; 7030 + 7031 + if (bpf_obj_pin(link->fd, link->pin_path)) { 7032 + err = -errno; 7033 + zfree(&link->pin_path); 7034 + return err; 7035 + } 7036 + 7037 + pr_debug("link fd=%d: pinned at %s\n", link->fd, link->pin_path); 7038 + return 0; 7039 + } 7040 + 7041 + int bpf_link__unpin(struct bpf_link *link) 7042 + { 7043 + int err; 7044 + 7045 + if (!link->pin_path) 7046 + return -EINVAL; 7047 + 7048 + err = unlink(link->pin_path); 7049 + if (err != 0) 7050 + return -errno; 7051 + 7052 + pr_debug("link fd=%d: unpinned from %s\n", link->fd, link->pin_path); 7053 + zfree(&link->pin_path); 7054 + return 0; 7055 + } 6974 7056 6975 7057 static int bpf_link__detach_perf_event(struct bpf_link *link) 6976 7058 { 6977 - struct bpf_link_fd *l = (void *)link; 6978 7059 int err; 6979 7060 6980 - err = ioctl(l->fd, PERF_EVENT_IOC_DISABLE, 0); 7061 + err = ioctl(link->fd, PERF_EVENT_IOC_DISABLE, 0); 6981 7062 if (err) 6982 7063 err = -errno; 6983 7064 6984 - close(l->fd); 7065 + close(link->fd); 6985 7066 return err; 6986 7067 } 6987 7068 ··· 7072 6987 int pfd) 7073 6988 { 7074 6989 char errmsg[STRERR_BUFSIZE]; 7075 - struct bpf_link_fd *link; 6990 + struct bpf_link *link; 7076 6991 int prog_fd, err; 7077 6992 7078 6993 if (pfd < 0) { ··· 7090 7005 link = calloc(1, sizeof(*link)); 7091 7006 if (!link) 7092 7007 return ERR_PTR(-ENOMEM); 7093 - link->link.detach = &bpf_link__detach_perf_event; 7008 + link->detach = &bpf_link__detach_perf_event; 7094 7009 link->fd = pfd; 7095 7010 7096 7011 if (ioctl(pfd, PERF_EVENT_IOC_SET_BPF, prog_fd) < 0) { ··· 7109 7024 libbpf_strerror_r(err, errmsg, sizeof(errmsg))); 7110 7025 return ERR_PTR(err); 7111 7026 } 7112 - return (struct bpf_link *)link; 7027 + return link; 7113 7028 } 7114 7029 7115 7030 /* ··· 7397 7312 return link; 7398 7313 } 7399 7314 7400 - static int bpf_link__detach_fd(struct bpf_link *link) 7401 - { 7402 - struct bpf_link_fd *l = (void *)link; 7403 - 7404 - return close(l->fd); 7405 - } 7406 - 7407 7315 struct bpf_link *bpf_program__attach_raw_tracepoint(struct bpf_program *prog, 7408 7316 const char *tp_name) 7409 7317 { 7410 7318 char errmsg[STRERR_BUFSIZE]; 7411 - struct bpf_link_fd *link; 7319 + struct bpf_link *link; 7412 7320 int prog_fd, pfd; 7413 7321 7414 7322 prog_fd = bpf_program__fd(prog); ··· 7414 7336 link = calloc(1, sizeof(*link)); 7415 7337 if (!link) 7416 7338 return ERR_PTR(-ENOMEM); 7417 - link->link.detach = &bpf_link__detach_fd; 7339 + link->detach = &bpf_link__detach_fd; 7418 7340 7419 7341 pfd = bpf_raw_tracepoint_open(tp_name, prog_fd); 7420 7342 if (pfd < 0) { ··· 7426 7348 return ERR_PTR(pfd); 7427 7349 } 7428 7350 link->fd = pfd; 7429 - return (struct bpf_link *)link; 7351 + return link; 7430 7352 } 7431 7353 7432 7354 static struct bpf_link *attach_raw_tp(const struct bpf_sec_def *sec, ··· 7440 7362 struct bpf_link *bpf_program__attach_trace(struct bpf_program *prog) 7441 7363 { 7442 7364 char errmsg[STRERR_BUFSIZE]; 7443 - struct bpf_link_fd *link; 7365 + struct bpf_link *link; 7444 7366 int prog_fd, pfd; 7445 7367 7446 7368 prog_fd = bpf_program__fd(prog); ··· 7453 7375 link = calloc(1, sizeof(*link)); 7454 7376 if (!link) 7455 7377 return ERR_PTR(-ENOMEM); 7456 - link->link.detach = &bpf_link__detach_fd; 7378 + link->detach = &bpf_link__detach_fd; 7457 7379 7458 7380 pfd = bpf_raw_tracepoint_open(NULL, prog_fd); 7459 7381 if (pfd < 0) { ··· 7487 7409 7488 7410 static int bpf_link__detach_struct_ops(struct bpf_link *link) 7489 7411 { 7490 - struct bpf_link_fd *l = (void *)link; 7491 7412 __u32 zero = 0; 7492 7413 7493 - if (bpf_map_delete_elem(l->fd, &zero)) 7414 + if (bpf_map_delete_elem(link->fd, &zero)) 7494 7415 return -errno; 7495 7416 7496 7417 return 0; ··· 7498 7421 struct bpf_link *bpf_map__attach_struct_ops(struct bpf_map *map) 7499 7422 { 7500 7423 struct bpf_struct_ops *st_ops; 7501 - struct bpf_link_fd *link; 7424 + struct bpf_link *link; 7502 7425 __u32 i, zero = 0; 7503 7426 int err; 7504 7427 ··· 7530 7453 return ERR_PTR(err); 7531 7454 } 7532 7455 7533 - link->link.detach = bpf_link__detach_struct_ops; 7456 + link->detach = bpf_link__detach_struct_ops; 7534 7457 link->fd = map->fd; 7535 7458 7536 - return (struct bpf_link *)link; 7459 + return link; 7537 7460 } 7538 7461 7539 7462 enum bpf_perf_event_ret
+5
tools/lib/bpf/libbpf.h
··· 219 219 220 220 struct bpf_link; 221 221 222 + LIBBPF_API struct bpf_link *bpf_link__open(const char *path); 223 + LIBBPF_API int bpf_link__fd(const struct bpf_link *link); 224 + LIBBPF_API const char *bpf_link__pin_path(const struct bpf_link *link); 225 + LIBBPF_API int bpf_link__pin(struct bpf_link *link, const char *path); 226 + LIBBPF_API int bpf_link__unpin(struct bpf_link *link); 222 227 LIBBPF_API void bpf_link__disconnect(struct bpf_link *link); 223 228 LIBBPF_API int bpf_link__destroy(struct bpf_link *link); 224 229
+5
tools/lib/bpf/libbpf.map
··· 238 238 239 239 LIBBPF_0.0.8 { 240 240 global: 241 + bpf_link__fd; 242 + bpf_link__open; 243 + bpf_link__pin; 244 + bpf_link__pin_path; 245 + bpf_link__unpin; 241 246 bpf_program__set_attach_target; 242 247 } LIBBPF_0.0.7;