Thread (30 messages) 30 messages, 5 authors, 2019-07-01

Re: [PATCH v4 bpf-next 3/9] libbpf: add ability to attach/detach BPF program to perf event

From: Yonghong Song <hidden>
Date: 2019-07-01 23:02:43
Also in: bpf


On 7/1/19 2:57 PM, Andrii Nakryiko wrote:
On Mon, Jul 1, 2019 at 10:03 AM Yonghong Song [off-list ref] wrote:
quoted


On 6/28/19 8:49 PM, Andrii Nakryiko wrote:
quoted
bpf_program__attach_perf_event allows to attach BPF program to existing
perf event hook, providing most generic and most low-level way to attach BPF
programs. It returns struct bpf_link, which should be passed to
bpf_link__destroy to detach and free resources, associated with a link.

Signed-off-by: Andrii Nakryiko <redacted>
---
   tools/lib/bpf/libbpf.c   | 61 ++++++++++++++++++++++++++++++++++++++++
   tools/lib/bpf/libbpf.h   |  3 ++
   tools/lib/bpf/libbpf.map |  1 +
   3 files changed, 65 insertions(+)
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 455795e6f8af..98c155ec3bfa 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -32,6 +32,7 @@
   #include <linux/limits.h>
   #include <linux/perf_event.h>
   #include <linux/ring_buffer.h>
+#include <sys/ioctl.h>
   #include <sys/stat.h>
   #include <sys/types.h>
   #include <sys/vfs.h>
@@ -3958,6 +3959,66 @@ int bpf_link__destroy(struct bpf_link *link)
       return err;
   }

+struct bpf_link_fd {
+     struct bpf_link link; /* has to be at the top of struct */
+     int fd; /* hook FD */
+};
+
+static int bpf_link__destroy_perf_event(struct bpf_link *link)
+{
+     struct bpf_link_fd *l = (void *)link;
+     int err;
+
+     if (l->fd < 0)
+             return 0;
+
+     err = ioctl(l->fd, PERF_EVENT_IOC_DISABLE, 0);
+     if (err)
+             err = -errno;
+
+     close(l->fd);
+     return err;
+}
+
+struct bpf_link *bpf_program__attach_perf_event(struct bpf_program *prog,
+                                             int pfd)
+{
+     char errmsg[STRERR_BUFSIZE];
+     struct bpf_link_fd *link;
+     int prog_fd, err;
+
+     prog_fd = bpf_program__fd(prog);
+     if (prog_fd < 0) {
+             pr_warning("program '%s': can't attach before loaded\n",
+                        bpf_program__title(prog, false));
+             return ERR_PTR(-EINVAL);
+     }
should we check validity of pfd here?
If pfd < 0, we just return ERR_PTR(-EINVAL)?
I can add that. I didn't do it, because in general, you can provide fd
quoted
= 0 which is still not a valid FD for PERF_EVENT_IOC_SET_BPF and
PERF_EVENT_IOC_ENABLE, so in general we can't detect this reliably.
I just want a check for validity of input parameter which will failure 
later with dedicated error message. But the same negative pfd will
be printed in ioctl error message. I am okay with this.
quoted
This way, in bpf_link__destroy_perf_event(), we do not need to check
l->fd < 0 since it will be always nonnegative.
That check is not needed anyway, because even if pfd < 0, ioctl should
fail and return error. I'll remove that check.
quoted
quoted
+
+     link = malloc(sizeof(*link));
+     if (!link)
+             return ERR_PTR(-ENOMEM);
+     link->link.destroy = &bpf_link__destroy_perf_event;
+     link->fd = pfd;
+
+     if (ioctl(pfd, PERF_EVENT_IOC_SET_BPF, prog_fd) < 0) {
+             err = -errno;
+             free(link);
+             pr_warning("program '%s': failed to attach to pfd %d: %s\n",
+                        bpf_program__title(prog, false), pfd,
+                        libbpf_strerror_r(err, errmsg, sizeof(errmsg)));
+             return ERR_PTR(err);
+     }
+     if (ioctl(pfd, PERF_EVENT_IOC_ENABLE, 0) < 0) {
+             err = -errno;
+             free(link);
+             pr_warning("program '%s': failed to enable pfd %d: %s\n",
+                        bpf_program__title(prog, false), pfd,
+                        libbpf_strerror_r(err, errmsg, sizeof(errmsg)));
+             return ERR_PTR(err);
+     }
+     return (struct bpf_link *)link;
+}
+
   enum bpf_perf_event_ret
   bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size,
                          void **copy_mem, size_t *copy_size,
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 5082a5ebb0c2..1bf66c4a9330 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -169,6 +169,9 @@ struct bpf_link;

   LIBBPF_API int bpf_link__destroy(struct bpf_link *link);

+LIBBPF_API struct bpf_link *
+bpf_program__attach_perf_event(struct bpf_program *prog, int pfd);
+
   struct bpf_insn;

   /*
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index 3cde850fc8da..756f5aa802e9 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -169,6 +169,7 @@ LIBBPF_0.0.4 {
       global:
               bpf_link__destroy;
               bpf_object__load_xattr;
+             bpf_program__attach_perf_event;
               btf_dump__dump_type;
               btf_dump__free;
               btf_dump__new;
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help