[RFC PATCH v2 15/26] perf bpf: Introduce the entity and engine for userspace bpf

From: He Kuang
Date: Sun Jun 26 2016 - 07:24:11 EST


Different from bpf for kernel which is loaded into kernel and
represented by the fd handle returned, userspace bpf prgrams should be
loaded each time we run it. The field 'insns' is stored in ubpf entry
since the vm execute interface __bpf_prog_run() needs that to run the
bpf prog.

Signed-off-by: He Kuang <hekuang@xxxxxxxxxx>
Signed-off-by: Wang Nan <wangnan0@xxxxxxxxxx>
---
tools/lib/bpf/Build | 1 +
tools/lib/bpf/engine-ubpf.c | 97 +++++++++++++++++++++++++++++++++++++++++++++
tools/lib/bpf/libbpf.c | 1 +
tools/lib/bpf/libbpf.h | 6 +++
4 files changed, 105 insertions(+)
create mode 100644 tools/lib/bpf/engine-ubpf.c

diff --git a/tools/lib/bpf/Build b/tools/lib/bpf/Build
index 567dcfd..2f7e64c 100644
--- a/tools/lib/bpf/Build
+++ b/tools/lib/bpf/Build
@@ -1,2 +1,3 @@
libbpf-y := libbpf.o bpf.o
libbpf-y += engine-kbpf.o
+libbpf-$(CONFIG_UBPF) += engine-ubpf.o
diff --git a/tools/lib/bpf/engine-ubpf.c b/tools/lib/bpf/engine-ubpf.c
new file mode 100644
index 0000000..0ab3310
--- /dev/null
+++ b/tools/lib/bpf/engine-ubpf.c
@@ -0,0 +1,97 @@
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <linux/bpf.h>
+
+#include "bpf.h"
+#include "libbpf-internal.h"
+
+static int engine__init(struct bpf_program *prog)
+{
+ struct ubpf_entry *instances_entries;
+ int nr_instances = prog->instances.nr;
+
+ instances_entries = malloc(sizeof(struct ubpf_entry) * nr_instances);
+ if (!instances_entries) {
+ pr_warning("alloc memory failed for instances\n");
+ return -ENOMEM;
+ }
+
+ /* fill all entries with NULL */
+ memset(instances_entries, 0,
+ sizeof(instances_entries[0]) * nr_instances);
+
+ prog->instances.entries = instances_entries;
+
+ return 0;
+}
+
+static int engine__get_nth(struct bpf_program *prog, int n, void *ret)
+{
+ struct ubpf_entry **p_vm = (struct ubpf_entry **)ret;
+
+ if (n >= prog->instances.nr || n < 0) {
+ pr_warning("Can't get the %dth vm from program %s: only %d instances\n",
+ n, prog->section_name, prog->instances.nr);
+ return -EINVAL;
+ }
+
+ *p_vm = &((struct ubpf_entry *)prog->instances.entries)[n];
+
+ return 0;
+}
+
+static void engine__unload(struct bpf_program *prog, int index)
+{
+ struct ubpf_entry *v =
+ &((struct ubpf_entry *)prog->instances.entries)[index];
+
+ free(v->insns);
+}
+
+static int
+load_ubpf_program(struct bpf_insn *insns, int insns_cnt,
+ struct ubpf_entry *entry)
+{
+ entry->insns = malloc(insns_cnt * sizeof(struct bpf_insn));
+ if (!entry->insns) {
+ pr_warning("Failed to create ubpf entry\n");
+ return -LIBBPF_ERRNO__LOADUBPF;
+ }
+
+ memcpy(entry->insns, &insns->code, insns_cnt * sizeof(struct bpf_insn));
+
+ return 0;
+}
+
+static int engine__load(struct bpf_program *prog, struct bpf_insn *insns,
+ int insns_cnt, char *license __maybe_unused,
+ u32 kern_version __maybe_unused, int index)
+{
+ int err = 0;
+ struct ubpf_entry entry;
+
+ if (!insns || !insns_cnt) {
+ ((struct ubpf_entry **)prog->instances.entries)[index] = NULL;
+ pr_debug("Skip loading the %dth instance of program '%s'\n",
+ index, prog->section_name);
+ return err;
+ }
+
+ err = load_ubpf_program(insns, insns_cnt, &entry);
+ if (!err)
+ ((struct ubpf_entry *)prog->instances.entries)[index] = entry;
+ else
+ pr_warning("Loading the %dth instance of program '%s' failed\n",
+ index, prog->section_name);
+
+ return err;
+}
+
+struct bpf_engine uengine = {
+ .init = engine__init,
+ .load = engine__load,
+ .unload = engine__unload,
+ .get_nth = engine__get_nth,
+};
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index ddbba35..b738ef2 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -66,6 +66,7 @@ static const char *libbpf_strerror_table[NR_ERRNO] = {
[ERRCODE_OFFSET(VERIFY)] = "Kernel verifier blocks program loading",
[ERRCODE_OFFSET(PROG2BIG)] = "Program too big",
[ERRCODE_OFFSET(KVER)] = "Incorrect kernel version",
+ [ERRCODE_OFFSET(LOADUBPF)] = "Failed to load user space BPF program",
};

int libbpf_strerror(int err, char *buf, size_t size)
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 55f65de..996862f 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -26,6 +26,7 @@ enum libbpf_errno {
LIBBPF_ERRNO__VERIFY, /* Kernel verifier blocks program loading */
LIBBPF_ERRNO__PROG2BIG, /* Program too big */
LIBBPF_ERRNO__KVER, /* Incorrect kernel version */
+ LIBBPF_ERRNO__LOADUBPF, /* Failed to load user space BPF program */
__LIBBPF_ERRNO__END,
};

@@ -185,4 +186,9 @@ int bpf_map__set_priv(struct bpf_map *map, void *priv,
bpf_map_clear_priv_t clear_priv);
void *bpf_map__priv(struct bpf_map *map);

+/* The entity of ubpf program */
+struct ubpf_entry {
+ struct bpf_insn *insns;
+};
+
#endif
--
1.8.5.2