libbpf: Add bpf_cookie to perf_event, kprobe, uprobe, and tp attach APIs
authorAndrii Nakryiko <andrii@kernel.org>
Sun, 15 Aug 2021 07:06:04 +0000 (00:06 -0700)
committerDaniel Borkmann <daniel@iogearbox.net>
Mon, 16 Aug 2021 22:45:08 +0000 (00:45 +0200)
Wire through bpf_cookie for all attach APIs that use perf_event_open under the
hood:
  - for kprobes, extend existing bpf_kprobe_opts with bpf_cookie field;
  - for perf_event, uprobe, and tracepoint APIs, add their _opts variants and
    pass bpf_cookie through opts.

For kernel that don't support BPF_LINK_CREATE for perf_events, and thus
bpf_cookie is not supported either, return error and log warning for user.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20210815070609.987780-12-andrii@kernel.org
tools/lib/bpf/libbpf.c
tools/lib/bpf/libbpf.h
tools/lib/bpf/libbpf.map

index 5dc15f5b4b78b9582acbf03e56914b76769308b6..62ce878cb8e0e62b8ae90a3b1928b3b7602dfdb1 100644 (file)
@@ -9014,12 +9014,16 @@ static void bpf_link_perf_dealloc(struct bpf_link *link)
        free(perf_link);
 }
 
-struct bpf_link *bpf_program__attach_perf_event(struct bpf_program *prog, int pfd)
+struct bpf_link *bpf_program__attach_perf_event_opts(struct bpf_program *prog, int pfd,
+                                                    const struct bpf_perf_event_opts *opts)
 {
        char errmsg[STRERR_BUFSIZE];
        struct bpf_link_perf *link;
        int prog_fd, link_fd = -1, err;
 
+       if (!OPTS_VALID(opts, bpf_perf_event_opts))
+               return libbpf_err_ptr(-EINVAL);
+
        if (pfd < 0) {
                pr_warn("prog '%s': invalid perf event FD %d\n",
                        prog->name, pfd);
@@ -9040,7 +9044,10 @@ struct bpf_link *bpf_program__attach_perf_event(struct bpf_program *prog, int pf
        link->perf_event_fd = pfd;
 
        if (kernel_supports(prog->obj, FEAT_PERF_LINK)) {
-               link_fd = bpf_link_create(prog_fd, pfd, BPF_PERF_EVENT, NULL);
+               DECLARE_LIBBPF_OPTS(bpf_link_create_opts, link_opts,
+                       .perf_event.bpf_cookie = OPTS_GET(opts, bpf_cookie, 0));
+
+               link_fd = bpf_link_create(prog_fd, pfd, BPF_PERF_EVENT, &link_opts);
                if (link_fd < 0) {
                        err = -errno;
                        pr_warn("prog '%s': failed to create BPF link for perf_event FD %d: %d (%s)\n",
@@ -9050,6 +9057,12 @@ struct bpf_link *bpf_program__attach_perf_event(struct bpf_program *prog, int pf
                }
                link->link.fd = link_fd;
        } else {
+               if (OPTS_GET(opts, bpf_cookie, 0)) {
+                       pr_warn("prog '%s': user context value is not supported\n", prog->name);
+                       err = -EOPNOTSUPP;
+                       goto err_out;
+               }
+
                if (ioctl(pfd, PERF_EVENT_IOC_SET_BPF, prog_fd) < 0) {
                        err = -errno;
                        pr_warn("prog '%s': failed to attach to perf_event FD %d: %s\n",
@@ -9076,6 +9089,11 @@ err_out:
        return libbpf_err_ptr(err);
 }
 
+struct bpf_link *bpf_program__attach_perf_event(struct bpf_program *prog, int pfd)
+{
+       return bpf_program__attach_perf_event_opts(prog, pfd, NULL);
+}
+
 /*
  * this function is expected to parse integer in the range of [0, 2^31-1] from
  * given file using scanf format string fmt. If actual parsed value is
@@ -9184,8 +9202,9 @@ static int perf_event_open_probe(bool uprobe, bool retprobe, const char *name,
 struct bpf_link *
 bpf_program__attach_kprobe_opts(struct bpf_program *prog,
                                const char *func_name,
-                               struct bpf_kprobe_opts *opts)
+                               const struct bpf_kprobe_opts *opts)
 {
+       DECLARE_LIBBPF_OPTS(bpf_perf_event_opts, pe_opts);
        char errmsg[STRERR_BUFSIZE];
        struct bpf_link *link;
        unsigned long offset;
@@ -9197,6 +9216,7 @@ bpf_program__attach_kprobe_opts(struct bpf_program *prog,
 
        retprobe = OPTS_GET(opts, retprobe, false);
        offset = OPTS_GET(opts, offset, 0);
+       pe_opts.bpf_cookie = OPTS_GET(opts, bpf_cookie, 0);
 
        pfd = perf_event_open_probe(false /* uprobe */, retprobe, func_name,
                                    offset, -1 /* pid */);
@@ -9206,7 +9226,7 @@ bpf_program__attach_kprobe_opts(struct bpf_program *prog,
                        libbpf_strerror_r(pfd, errmsg, sizeof(errmsg)));
                return libbpf_err_ptr(pfd);
        }
-       link = bpf_program__attach_perf_event(prog, pfd);
+       link = bpf_program__attach_perf_event_opts(prog, pfd, &pe_opts);
        err = libbpf_get_error(link);
        if (err) {
                close(pfd);
@@ -9261,14 +9281,22 @@ static struct bpf_link *attach_kprobe(const struct bpf_sec_def *sec,
        return link;
 }
 
-struct bpf_link *bpf_program__attach_uprobe(struct bpf_program *prog,
-                                           bool retprobe, pid_t pid,
-                                           const char *binary_path,
-                                           size_t func_offset)
+LIBBPF_API struct bpf_link *
+bpf_program__attach_uprobe_opts(struct bpf_program *prog, pid_t pid,
+                               const char *binary_path, size_t func_offset,
+                               const struct bpf_uprobe_opts *opts)
 {
+       DECLARE_LIBBPF_OPTS(bpf_perf_event_opts, pe_opts);
        char errmsg[STRERR_BUFSIZE];
        struct bpf_link *link;
        int pfd, err;
+       bool retprobe;
+
+       if (!OPTS_VALID(opts, bpf_uprobe_opts))
+               return libbpf_err_ptr(-EINVAL);
+
+       retprobe = OPTS_GET(opts, retprobe, false);
+       pe_opts.bpf_cookie = OPTS_GET(opts, bpf_cookie, 0);
 
        pfd = perf_event_open_probe(true /* uprobe */, retprobe,
                                    binary_path, func_offset, pid);
@@ -9279,7 +9307,7 @@ struct bpf_link *bpf_program__attach_uprobe(struct bpf_program *prog,
                        libbpf_strerror_r(pfd, errmsg, sizeof(errmsg)));
                return libbpf_err_ptr(pfd);
        }
-       link = bpf_program__attach_perf_event(prog, pfd);
+       link = bpf_program__attach_perf_event_opts(prog, pfd, &pe_opts);
        err = libbpf_get_error(link);
        if (err) {
                close(pfd);
@@ -9292,6 +9320,16 @@ struct bpf_link *bpf_program__attach_uprobe(struct bpf_program *prog,
        return link;
 }
 
+struct bpf_link *bpf_program__attach_uprobe(struct bpf_program *prog,
+                                           bool retprobe, pid_t pid,
+                                           const char *binary_path,
+                                           size_t func_offset)
+{
+       DECLARE_LIBBPF_OPTS(bpf_uprobe_opts, opts, .retprobe = retprobe);
+
+       return bpf_program__attach_uprobe_opts(prog, pid, binary_path, func_offset, &opts);
+}
+
 static int determine_tracepoint_id(const char *tp_category,
                                   const char *tp_name)
 {
@@ -9342,14 +9380,21 @@ static int perf_event_open_tracepoint(const char *tp_category,
        return pfd;
 }
 
-struct bpf_link *bpf_program__attach_tracepoint(struct bpf_program *prog,
-                                               const char *tp_category,
-                                               const char *tp_name)
+struct bpf_link *bpf_program__attach_tracepoint_opts(struct bpf_program *prog,
+                                                    const char *tp_category,
+                                                    const char *tp_name,
+                                                    const struct bpf_tracepoint_opts *opts)
 {
+       DECLARE_LIBBPF_OPTS(bpf_perf_event_opts, pe_opts);
        char errmsg[STRERR_BUFSIZE];
        struct bpf_link *link;
        int pfd, err;
 
+       if (!OPTS_VALID(opts, bpf_tracepoint_opts))
+               return libbpf_err_ptr(-EINVAL);
+
+       pe_opts.bpf_cookie = OPTS_GET(opts, bpf_cookie, 0);
+
        pfd = perf_event_open_tracepoint(tp_category, tp_name);
        if (pfd < 0) {
                pr_warn("prog '%s': failed to create tracepoint '%s/%s' perf event: %s\n",
@@ -9357,7 +9402,7 @@ struct bpf_link *bpf_program__attach_tracepoint(struct bpf_program *prog,
                        libbpf_strerror_r(pfd, errmsg, sizeof(errmsg)));
                return libbpf_err_ptr(pfd);
        }
-       link = bpf_program__attach_perf_event(prog, pfd);
+       link = bpf_program__attach_perf_event_opts(prog, pfd, &pe_opts);
        err = libbpf_get_error(link);
        if (err) {
                close(pfd);
@@ -9369,6 +9414,13 @@ struct bpf_link *bpf_program__attach_tracepoint(struct bpf_program *prog,
        return link;
 }
 
+struct bpf_link *bpf_program__attach_tracepoint(struct bpf_program *prog,
+                                               const char *tp_category,
+                                               const char *tp_name)
+{
+       return bpf_program__attach_tracepoint_opts(prog, tp_category, tp_name, NULL);
+}
+
 static struct bpf_link *attach_tp(const struct bpf_sec_def *sec,
                                  struct bpf_program *prog)
 {
index 1271d99bb7aa1dcf83008e2350fa0904d7c757b6..1f4a67285365dd78c6c7ca0677ecde7b4993f938 100644 (file)
@@ -104,17 +104,6 @@ struct bpf_object_open_opts {
 };
 #define bpf_object_open_opts__last_field btf_custom_path
 
-struct bpf_kprobe_opts {
-       /* size of this struct, for forward/backward compatiblity */
-       size_t sz;
-       /* function's offset to install kprobe to */
-       unsigned long offset;
-       /* kprobe is return probe */
-       bool retprobe;
-       size_t :0;
-};
-#define bpf_kprobe_opts__last_field retprobe
-
 LIBBPF_API struct bpf_object *bpf_object__open(const char *path);
 LIBBPF_API struct bpf_object *
 bpf_object__open_file(const char *path, const struct bpf_object_open_opts *opts);
@@ -255,24 +244,82 @@ LIBBPF_API int bpf_link__destroy(struct bpf_link *link);
 
 LIBBPF_API struct bpf_link *
 bpf_program__attach(struct bpf_program *prog);
+
+struct bpf_perf_event_opts {
+       /* size of this struct, for forward/backward compatiblity */
+       size_t sz;
+       /* custom user-provided value fetchable through bpf_get_attach_cookie() */
+       __u64 bpf_cookie;
+};
+#define bpf_perf_event_opts__last_field bpf_cookie
+
 LIBBPF_API struct bpf_link *
 bpf_program__attach_perf_event(struct bpf_program *prog, int pfd);
+
+LIBBPF_API struct bpf_link *
+bpf_program__attach_perf_event_opts(struct bpf_program *prog, int pfd,
+                                   const struct bpf_perf_event_opts *opts);
+
+struct bpf_kprobe_opts {
+       /* size of this struct, for forward/backward compatiblity */
+       size_t sz;
+       /* custom user-provided value fetchable through bpf_get_attach_cookie() */
+       __u64 bpf_cookie;
+       /* function's offset to install kprobe to */
+       unsigned long offset;
+       /* kprobe is return probe */
+       bool retprobe;
+       size_t :0;
+};
+#define bpf_kprobe_opts__last_field retprobe
+
 LIBBPF_API struct bpf_link *
 bpf_program__attach_kprobe(struct bpf_program *prog, bool retprobe,
                           const char *func_name);
 LIBBPF_API struct bpf_link *
 bpf_program__attach_kprobe_opts(struct bpf_program *prog,
                                 const char *func_name,
-                                struct bpf_kprobe_opts *opts);
+                                const struct bpf_kprobe_opts *opts);
+
+struct bpf_uprobe_opts {
+       /* size of this struct, for forward/backward compatiblity */
+       size_t sz;
+       /* custom user-provided value fetchable through bpf_get_attach_cookie() */
+       __u64 bpf_cookie;
+       /* uprobe is return probe, invoked at function return time */
+       bool retprobe;
+       size_t :0;
+};
+#define bpf_uprobe_opts__last_field retprobe
+
 LIBBPF_API struct bpf_link *
 bpf_program__attach_uprobe(struct bpf_program *prog, bool retprobe,
                           pid_t pid, const char *binary_path,
                           size_t func_offset);
+LIBBPF_API struct bpf_link *
+bpf_program__attach_uprobe_opts(struct bpf_program *prog, pid_t pid,
+                               const char *binary_path, size_t func_offset,
+                               const struct bpf_uprobe_opts *opts);
+
+struct bpf_tracepoint_opts {
+       /* size of this struct, for forward/backward compatiblity */
+       size_t sz;
+       /* custom user-provided value fetchable through bpf_get_attach_cookie() */
+       __u64 bpf_cookie;
+};
+#define bpf_tracepoint_opts__last_field bpf_cookie
+
 LIBBPF_API struct bpf_link *
 bpf_program__attach_tracepoint(struct bpf_program *prog,
                               const char *tp_category,
                               const char *tp_name);
 LIBBPF_API struct bpf_link *
+bpf_program__attach_tracepoint_opts(struct bpf_program *prog,
+                                   const char *tp_category,
+                                   const char *tp_name,
+                                   const struct bpf_tracepoint_opts *opts);
+
+LIBBPF_API struct bpf_link *
 bpf_program__attach_raw_tracepoint(struct bpf_program *prog,
                                   const char *tp_name);
 LIBBPF_API struct bpf_link *
index 58e0fb2c482f9eaf6c705f1f923d92aeed8fa021..bbc53bb25f68f03550d0c747aa161a187b1aee57 100644 (file)
@@ -374,6 +374,9 @@ LIBBPF_0.5.0 {
                bpf_map__pin_path;
                bpf_map_lookup_and_delete_elem_flags;
                bpf_program__attach_kprobe_opts;
+               bpf_program__attach_perf_event_opts;
+               bpf_program__attach_tracepoint_opts;
+               bpf_program__attach_uprobe_opts;
                bpf_object__gen_loader;
                btf__load_from_kernel_by_id;
                btf__load_from_kernel_by_id_split;