[RFC PATCH v2 13/26] perf bpf: Add abstraction for bpf program methods

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


Supporting different bpf program types loaded into kernel and
userspace, this patch abstracts the operations to related to bpf
program into bpf_engine. The methods set for bpf loaded into kernel
are included in engine-kbpf.c, which is used as the default value.

Signed-off-by: He Kuang <hekuang@xxxxxxxxxx>
Signed-off-by: Wang Nan <wangnan0@xxxxxxxxxx>
---
tools/lib/bpf/Build | 1 +
tools/lib/bpf/engine-kbpf.c | 131 ++++++++++++++++++++++++++++++++++++++++
tools/lib/bpf/libbpf-internal.h | 11 ++++
tools/lib/bpf/libbpf.c | 115 ++++-------------------------------
4 files changed, 156 insertions(+), 102 deletions(-)
create mode 100644 tools/lib/bpf/engine-kbpf.c

diff --git a/tools/lib/bpf/Build b/tools/lib/bpf/Build
index d874975..567dcfd 100644
--- a/tools/lib/bpf/Build
+++ b/tools/lib/bpf/Build
@@ -1 +1,2 @@
libbpf-y := libbpf.o bpf.o
+libbpf-y += engine-kbpf.o
diff --git a/tools/lib/bpf/engine-kbpf.c b/tools/lib/bpf/engine-kbpf.c
new file mode 100644
index 0000000..7d81e16
--- /dev/null
+++ b/tools/lib/bpf/engine-kbpf.c
@@ -0,0 +1,131 @@
+#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)
+{
+ int *instances_entries;
+ int nr_instances = prog->instances.nr;
+
+ instances_entries = malloc(sizeof(int) * nr_instances);
+ if (!instances_entries) {
+ pr_warning("alloc memory failed for instances\n");
+ return -ENOMEM;
+ }
+
+ /* fill all fd with -1 */
+ memset(instances_entries, -1, sizeof(int) * nr_instances);
+
+ prog->instances.entries = instances_entries;
+
+ return 0;
+}
+
+static int engine__get_nth(struct bpf_program *prog, int n, void *ret)
+{
+ int *pfd = (int *)ret;
+
+ if (n >= prog->instances.nr || n < 0) {
+ pr_warning("Can't get the %dth fd from program %s: only %d instances\n",
+ n, prog->section_name, prog->instances.nr);
+ return -EINVAL;
+ }
+
+ *pfd = ((int *)prog->instances.entries)[n];
+ if (*pfd < 0) {
+ pr_warning("%dth instance of program '%s' is invalid\n",
+ n, prog->section_name);
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+static void engine__unload(struct bpf_program *prog, int index)
+{
+ zclose(((int *)prog->instances.entries)[index]);
+}
+
+static int
+load_program(struct bpf_insn *insns, int insns_cnt,
+ char *license, u32 kern_version, int *pfd)
+{
+ int ret;
+ char *log_buf;
+
+ if (!insns || !insns_cnt)
+ return -EINVAL;
+
+ log_buf = malloc(BPF_LOG_BUF_SIZE);
+ if (!log_buf)
+ pr_warning("Alloc log buffer for bpf loader error, continue without log\n");
+
+ ret = bpf_load_program(BPF_PROG_TYPE_KPROBE, insns,
+ insns_cnt, license, kern_version,
+ log_buf, BPF_LOG_BUF_SIZE);
+
+ if (ret >= 0) {
+ *pfd = ret;
+ ret = 0;
+ goto out;
+ }
+
+ ret = -LIBBPF_ERRNO__LOAD;
+ pr_warning("load bpf program failed: %s\n", strerror(errno));
+
+ if (log_buf && log_buf[0] != '\0') {
+ ret = -LIBBPF_ERRNO__VERIFY;
+ pr_warning("-- BEGIN DUMP LOG ---\n");
+ pr_warning("\n%s\n", log_buf);
+ pr_warning("-- END LOG --\n");
+ } else {
+ if (insns_cnt >= BPF_MAXINSNS) {
+ pr_warning("Program too large (%d insns), at most %d insns\n",
+ insns_cnt, BPF_MAXINSNS);
+ ret = -LIBBPF_ERRNO__PROG2BIG;
+ } else if (log_buf) {
+ pr_warning("log buffer is empty\n");
+ ret = -LIBBPF_ERRNO__KVER;
+ }
+ }
+
+out:
+ free(log_buf);
+ return ret;
+}
+
+static int engine__load(struct bpf_program *prog, struct bpf_insn *insns,
+ int insns_cnt, char *license,
+ u32 kern_version, int index)
+{
+ int err = 0;
+ int fd;
+
+ if (!insns || !insns_cnt) {
+ ((int *)prog->instances.entries)[index] = -1;
+ pr_debug("Skip loading the %dth instance of program '%s'\n",
+ index, prog->section_name);
+ return err;
+ }
+
+ err = load_program(insns, insns_cnt, license, kern_version, &fd);
+ if (!err)
+ ((int *)prog->instances.entries)[index] = fd;
+ else
+ pr_warning("Loading the %dth instance of program '%s' failed\n",
+ index, prog->section_name);
+
+ return err;
+}
+
+struct bpf_engine kengine = {
+ .init = engine__init,
+ .load = engine__load,
+ .unload = engine__unload,
+ .get_nth = engine__get_nth,
+};
diff --git a/tools/lib/bpf/libbpf-internal.h b/tools/lib/bpf/libbpf-internal.h
index 1c1619c..60b2f68 100644
--- a/tools/lib/bpf/libbpf-internal.h
+++ b/tools/lib/bpf/libbpf-internal.h
@@ -62,4 +62,15 @@ struct bpf_program {
bpf_program_clear_priv_t clear_priv;
};

+struct bpf_engine {
+ int (*init)(struct bpf_program *prog);
+ int (*load)(struct bpf_program *prog, struct bpf_insn *insns,
+ int insns_cnt, char *license,
+ u32 kern_version, int index);
+ void (*unload)(struct bpf_program *prog, int index);
+ int (*get_nth)(struct bpf_program *prog, int index, void *ret);
+};
+
+extern struct bpf_engine kengine;
+
#endif /* _LIBBPF_INTERNAL_H */
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 0ad6c9e..a53cb579 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -172,7 +172,7 @@ static void bpf_program__unload(struct bpf_program *prog)
*/
if (prog->instances.nr > 0) {
for (i = 0; i < prog->instances.nr; i++)
- zclose(((int *)prog->instances.entries)[i]);
+ prog->engine->unload(prog, i);
} else if (prog->instances.nr != -1) {
pr_warning("Internal error: instances.nr is %d\n",
prog->instances.nr);
@@ -230,6 +230,7 @@ bpf_program__init(void *data, size_t size, char *name, int idx,
memcpy(prog->insns, data,
prog->insns_cnt * sizeof(struct bpf_insn));
prog->idx = idx;
+ prog->engine = &kengine;
prog->instances.entries = NULL;
prog->instances.nr = -1;

@@ -827,58 +828,10 @@ static int bpf_object__collect_reloc(struct bpf_object *obj)
}

static int
-load_program(struct bpf_insn *insns, int insns_cnt,
- char *license, u32 kern_version, int *pfd)
-{
- int ret;
- char *log_buf;
-
- if (!insns || !insns_cnt)
- return -EINVAL;
-
- log_buf = malloc(BPF_LOG_BUF_SIZE);
- if (!log_buf)
- pr_warning("Alloc log buffer for bpf loader error, continue without log\n");
-
- ret = bpf_load_program(BPF_PROG_TYPE_KPROBE, insns,
- insns_cnt, license, kern_version,
- log_buf, BPF_LOG_BUF_SIZE);
-
- if (ret >= 0) {
- *pfd = ret;
- ret = 0;
- goto out;
- }
-
- ret = -LIBBPF_ERRNO__LOAD;
- pr_warning("load bpf program failed: %s\n", strerror(errno));
-
- if (log_buf && log_buf[0] != '\0') {
- ret = -LIBBPF_ERRNO__VERIFY;
- pr_warning("-- BEGIN DUMP LOG ---\n");
- pr_warning("\n%s\n", log_buf);
- pr_warning("-- END LOG --\n");
- } else {
- if (insns_cnt >= BPF_MAXINSNS) {
- pr_warning("Program too large (%d insns), at most %d insns\n",
- insns_cnt, BPF_MAXINSNS);
- ret = -LIBBPF_ERRNO__PROG2BIG;
- } else if (log_buf) {
- pr_warning("log buffer is empty\n");
- ret = -LIBBPF_ERRNO__KVER;
- }
- }
-
-out:
- free(log_buf);
- return ret;
-}
-
-static int
bpf_program__load(struct bpf_program *prog,
char *license, u32 kern_version)
{
- int err = 0, fd, i;
+ int err = 0, i;

if (prog->instances.nr < 0 || !prog->instances.entries) {
if (prog->preprocessor) {
@@ -887,14 +840,8 @@ bpf_program__load(struct bpf_program *prog,
return -LIBBPF_ERRNO__INTERNAL;
}

- prog->instances.entries = malloc(sizeof(int));
- if (!prog->instances.entries) {
- pr_warning("Not enough memory for BPF entries\n");
- return -ENOMEM;
- }
-
prog->instances.nr = 1;
- ((int *)prog->instances.entries)[0] = -1;
+ prog->engine->init(prog);
}

if (!prog->preprocessor) {
@@ -902,10 +849,8 @@ bpf_program__load(struct bpf_program *prog,
pr_warning("Program '%s' is inconsistent: nr(%d) != 1\n",
prog->section_name, prog->instances.nr);
}
- err = load_program(prog->insns, prog->insns_cnt,
- license, kern_version, &fd);
- if (!err)
- ((int *)prog->instances.entries)[0] = fd;
+ prog->engine->load(prog, prog->insns, prog->insns_cnt,
+ license, kern_version, 0);
goto out;
}

@@ -922,24 +867,11 @@ bpf_program__load(struct bpf_program *prog,
goto out;
}

- if (!result.new_insn_ptr || !result.new_insn_cnt) {
- pr_debug("Skip loading the %dth instance of program '%s'\n",
- i, prog->section_name);
- ((int *)prog->instances.entries)[i] = -1;
- continue;
- }
-
- err = load_program(result.new_insn_ptr,
- result.new_insn_cnt,
- license, kern_version, &fd);
-
- if (err) {
- pr_warning("Loading the %dth instance of program '%s' failed\n",
- i, prog->section_name);
+ err = prog->engine->load(prog, result.new_insn_ptr,
+ result.new_insn_cnt, license,
+ kern_version, i);
+ if (err)
goto out;
- }
-
- ((int *)prog->instances.entries)[i] = fd;
}
out:
if (err)
@@ -1201,8 +1133,6 @@ int bpf_program__fd(struct bpf_program *prog)
int bpf_program__set_prep(struct bpf_program *prog, int nr_instances,
bpf_program_prep_t prep)
{
- int *instances_entries;
-
if (nr_instances <= 0 || !prep)
return -EINVAL;

@@ -1211,17 +1141,9 @@ int bpf_program__set_prep(struct bpf_program *prog, int nr_instances,
return -EINVAL;
}

- instances_entries = malloc(sizeof(int) * nr_instances);
- if (!instances_entries) {
- pr_warning("alloc memory failed for entries\n");
- return -ENOMEM;
- }
-
- /* fill all fd with -1 */
- memset(instances_entries, -1, sizeof(int) * nr_instances);
-
prog->instances.nr = nr_instances;
- prog->instances.entries = instances_entries;
+ prog->engine->init(prog);
+
prog->preprocessor = prep;
return 0;
}
@@ -1230,18 +1152,7 @@ int bpf_program__nth_fd(struct bpf_program *prog, int n)
{
int fd;

- if (n >= prog->instances.nr || n < 0) {
- pr_warning("Can't get the %dth fd from program %s: only %d instances\n",
- n, prog->section_name, prog->instances.nr);
- return -EINVAL;
- }
-
- fd = ((int *)prog->instances.entries)[n];
- if (fd < 0) {
- pr_warning("%dth instance of program '%s' is invalid\n",
- n, prog->section_name);
- return -ENOENT;
- }
+ prog->engine->get_nth(prog, n, &fd);

return fd;
}
--
1.8.5.2