[DTrace-devel] [PATCH] Associate BPF programs with probes (as perf events)

Kris Van Hees kris.van.hees at oracle.com
Wed Mar 4 07:49:01 PST 2020


Once a BPF program has been loaded successfully (i.e. the verifier has
accepted it), it needs to be associated (attached) to one or more
probes.  Each probe represents a perf event (identified by a unique
numeric id), and that event must be created by means of the
perf_event_open() system call.  The result (if successful) will be a
file descriptor that refers to the perf event for the probe.  This fd
can be used to attach the BPF program (identified by a file descriptor)
to the perf event.

Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
 libdtrace/dt_bpf.c   | 54 ++++++++++++++++++++++++++++++++++++++++++--
 libdtrace/dt_probe.c |  1 +
 libdtrace/dt_probe.h |  1 +
 3 files changed, 54 insertions(+), 2 deletions(-)

diff --git a/libdtrace/dt_bpf.c b/libdtrace/dt_bpf.c
index 5d8560be..ae742148 100644
--- a/libdtrace/dt_bpf.c
+++ b/libdtrace/dt_bpf.c
@@ -8,6 +8,9 @@
 #include <assert.h>
 #include <errno.h>
 #include <string.h>
+#include <linux/perf_event.h>
+#include <sys/ioctl.h>
+#include <sys/syscall.h>
 #include <dtrace.h>
 #include <dt_impl.h>
 #include <dt_probe.h>
@@ -19,6 +22,17 @@ static bool dt_gmap_done = 0;
 
 #define BPF_CG_LICENSE	"GPL";
 
+static inline int perf_event_open(struct perf_event_attr *attr, pid_t pid,
+				  int cpu, int group_fd, unsigned long flags)
+{
+	return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
+}
+
+extern inline int bpf(enum bpf_cmd cmd, union bpf_attr *attr)
+{
+	return syscall(__NR_bpf, cmd, attr, sizeof(union bpf_attr));
+}
+
 static int
 create_gmap(dtrace_hdl_t *dtp, const char *name, enum bpf_map_type type,
 	    int ksz, int vsz, int size)
@@ -215,6 +229,39 @@ dt_bpf_load_prog(dtrace_hdl_t *dtp, const dt_probe_t *prp,
 	return rc;
 }
 
+/*
+ * Attach a BPF program to a probe.
+ */
+int
+dt_bpf_attach(dtrace_hdl_t *dtp, dt_probe_t *prp, int bpf_fd)
+{
+	/*
+	 * If we have not yet created a perf event for this probe, do that now
+	 * and cache the file descriptor so we only need to do this once.
+	 */
+	if (prp->event_fd == -1) {
+		int			fd;
+		struct perf_event_attr	attr = { 0, };
+
+		attr.type = PERF_TYPE_TRACEPOINT;
+		attr.sample_type = PERF_SAMPLE_RAW;
+		attr.sample_period = 1;
+		attr.wakeup_events = 1;
+		attr.config = prp->event_id;
+
+		fd = perf_event_open(&attr, -1, 0, -1, 0);
+		if (fd < 0)
+			return -errno;
+
+		prp->event_fd = fd;
+	}
+
+	if (ioctl(prp->event_fd, PERF_EVENT_IOC_SET_BPF, bpf_fd) < 0)
+		return -errno;
+
+	return 0;
+}
+
 int
 dt_bpf_stmt(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp,
 	    void *data)
@@ -223,7 +270,7 @@ dt_bpf_stmt(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp,
 	dtrace_actdesc_t	*ap = sdp->dtsd_action;
 	dtrace_probeinfo_t	pip;
 	dt_probe_t		*prp;
-	int			rc;
+	int			fd, rc;
 	int			*cnt = data;
 
 	memset(&pip, 0, sizeof(pip));
@@ -238,8 +285,11 @@ dt_bpf_stmt(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp,
 	 * list.
 	 */
 	assert(ap == sdp->dtsd_action_last);
-	rc = dt_bpf_load_prog(dtp, prp, ap->dtad_difo);
+	fd = dt_bpf_load_prog(dtp, prp, ap->dtad_difo);
+	if (fd < 0)
+		return fd;
 
+	rc = dt_bpf_attach(dtp, prp, fd);
 	if (rc < 0)
 		return rc;
 
diff --git a/libdtrace/dt_probe.c b/libdtrace/dt_probe.c
index 5918460f..2652be2b 100644
--- a/libdtrace/dt_probe.c
+++ b/libdtrace/dt_probe.c
@@ -692,6 +692,7 @@ dt_probe_insert(dtrace_hdl_t *dtp, dt_provider_t *prov, const char *prv,
 	prp->desc = desc;
 	prp->prov = prov;
 	prp->event_id = -1;
+	prp->event_fd = -1;
 
 	dt_htab_insert(dtp->dt_byprv, prp);
 	dt_htab_insert(dtp->dt_bymod, prp);
diff --git a/libdtrace/dt_probe.h b/libdtrace/dt_probe.h
index a38c1b3a..a0e4133e 100644
--- a/libdtrace/dt_probe.h
+++ b/libdtrace/dt_probe.h
@@ -39,6 +39,7 @@ typedef struct dt_probe {
 	struct dt_hentry he_prb;	/* probe name htab link */
 	struct dt_hentry he_fqn;	/* fully qualified name htab link */
 	int event_id;			/* tracing event id */
+	int event_fd;			/* perf event file descriptor */
 	dt_ident_t *pr_ident;		/* pointer to probe identifier */
 	const char *pr_name;		/* pointer to name component */
 	dt_node_t *nargs;		/* native argument list */
-- 
2.25.0




More information about the DTrace-devel mailing list