qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC PATCH 2/6] ebpf: Added basic eBPF API.


From: Andrew Melnychenko
Subject: [RFC PATCH 2/6] ebpf: Added basic eBPF API.
Date: Mon, 2 Nov 2020 20:51:12 +0200

From: Andrew <andrew@daynix.com>

Added basic functions for creating eBPF maps and loading programs.
Also added helper function to 'fix' eBPF map descriptors in programs.
During runtime, different values of eBPF map file descriptors created,
and it required to place them into eBPF instructions for proper work.
It's similar to ELF's relocation table section routine.

Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
---
 ebpf/ebpf.c       | 107 ++++++++++++++++++++++++++++++++++++++++++++++
 ebpf/ebpf.h       |  35 +++++++++++++++
 ebpf/trace-events |   4 ++
 ebpf/trace.h      |   2 +
 4 files changed, 148 insertions(+)
 create mode 100644 ebpf/ebpf.c
 create mode 100644 ebpf/ebpf.h
 create mode 100644 ebpf/trace-events
 create mode 100644 ebpf/trace.h

diff --git a/ebpf/ebpf.c b/ebpf/ebpf.c
new file mode 100644
index 0000000000..cec35a484c
--- /dev/null
+++ b/ebpf/ebpf.c
@@ -0,0 +1,107 @@
+#include "ebpf/ebpf.h"
+#include <sys/syscall.h>
+#include "trace.h"
+
+#define ptr_to_u64(x) ((uint64_t)(uintptr_t)x)
+
+static inline int ebpf(enum bpf_cmd cmd, union bpf_attr *attr,
+        unsigned int size)
+{
+    int ret = syscall(__NR_bpf, cmd, attr, size);
+    if (ret < 0) {
+        trace_ebpf_error("eBPF syscall error", strerror(errno));
+    }
+
+    return ret;
+}
+
+int bpf_create_map(enum bpf_map_type map_type,
+                   unsigned int key_size,
+                   unsigned int value_size,
+                   unsigned int max_entries)
+{
+    union bpf_attr attr = {
+            .map_type    = map_type,
+            .key_size    = key_size,
+            .value_size  = value_size,
+            .max_entries = max_entries
+    };
+
+    return ebpf(BPF_MAP_CREATE, &attr, sizeof(attr));
+}
+
+int bpf_lookup_elem(int fd, const void *key, void *value)
+{
+    union bpf_attr attr = {
+            .map_fd = (uint32_t)fd,
+            .key    = ptr_to_u64(key),
+            .value  = ptr_to_u64(value),
+    };
+
+    return ebpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
+}
+
+int bpf_update_elem(int fd, const void *key, const void *value,
+                    uint64_t flags)
+{
+    union bpf_attr attr = {
+            .map_fd = (uint32_t)fd,
+            .key    = ptr_to_u64(key),
+            .value  = ptr_to_u64(value),
+            .flags  = flags,
+    };
+
+    return ebpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
+}
+
+int bpf_delete_elem(int fd, const void *key)
+{
+    union bpf_attr attr = {
+            .map_fd = (uint32_t)fd,
+            .key    = ptr_to_u64(key),
+    };
+
+    return ebpf(BPF_MAP_DELETE_ELEM, &attr, sizeof(attr));
+}
+
+#define BPF_LOG_BUF_SIZE (UINT32_MAX >> 8)
+static char bpf_log_buf[BPF_LOG_BUF_SIZE] = {};
+
+int bpf_prog_load(enum bpf_prog_type type,
+                  const struct bpf_insn *insns, int insn_cnt,
+                  const char *license)
+{
+    int ret = 0;
+    union bpf_attr attr = {};
+    attr.prog_type = type;
+    attr.insns     = ptr_to_u64(insns);
+    attr.insn_cnt  = (uint32_t)insn_cnt;
+    attr.license   = ptr_to_u64(license);
+    attr.log_buf   = ptr_to_u64(bpf_log_buf);
+    attr.log_size  = BPF_LOG_BUF_SIZE;
+    attr.log_level = 1;
+
+    ret = ebpf(BPF_PROG_LOAD, &attr, sizeof(attr));
+    if (ret < 0) {
+        trace_ebpf_error("eBPF program load error:", bpf_log_buf);
+    }
+
+    return ret;
+}
+
+unsigned int bpf_fixup_mapfd(struct fixup_mapfd_t *table,
+                             size_t table_size, struct bpf_insn *insn,
+                             size_t insn_len, const char *map_name, int fd) {
+    unsigned int ret = 0;
+    int i = 0;
+
+    for (; i < table_size; ++i) {
+        if (strcmp(table[i].map_name, map_name) == 0) {
+            insn[table[i].instruction_num].src_reg = 1;
+            insn[table[i].instruction_num].imm = fd;
+            ++ret;
+        }
+    }
+
+    return ret;
+}
diff --git a/ebpf/ebpf.h b/ebpf/ebpf.h
new file mode 100644
index 0000000000..511ad0a06f
--- /dev/null
+++ b/ebpf/ebpf.h
@@ -0,0 +1,35 @@
+#ifndef QEMU_EBPF_H
+#define QEMU_EBPF_H
+
+#include "qemu/osdep.h"
+
+#ifdef CONFIG_EBPF
+#include <linux/bpf.h>
+
+int bpf_create_map(enum bpf_map_type map_type,
+                   unsigned int key_size,
+                   unsigned int value_size,
+                   unsigned int max_entries);
+
+int bpf_lookup_elem(int fd, const void *key, void *value);
+
+int bpf_update_elem(int fd, const void *key, const void *value,
+                    uint64_t flags);
+
+int bpf_delete_elem(int fd, const void *key);
+
+int bpf_prog_load(enum bpf_prog_type type,
+                  const struct bpf_insn *insns, int insn_cnt,
+                  const char *license);
+
+struct fixup_mapfd_t {
+    const char *map_name;
+    size_t instruction_num;
+};
+
+unsigned int bpf_fixup_mapfd(struct fixup_mapfd_t *table,
+                             size_t table_size, struct bpf_insn *insn,
+                             size_t insn_len, const char *map_name, int fd);
+
+#endif /* CONFIG_EBPF */
+#endif /* QEMU_EBPF_H */
diff --git a/ebpf/trace-events b/ebpf/trace-events
new file mode 100644
index 0000000000..3c189516e3
--- /dev/null
+++ b/ebpf/trace-events
@@ -0,0 +1,4 @@
+# See docs/devel/tracing.txt for syntax documentation.
+
+# ebpf.c
+ebpf_error(const char *s1, const char *s2) "error in %s: %s"
diff --git a/ebpf/trace.h b/ebpf/trace.h
new file mode 100644
index 0000000000..ad570e6691
--- /dev/null
+++ b/ebpf/trace.h
@@ -0,0 +1,2 @@
+#include "trace/trace-ebpf.h"
+
-- 
2.28.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]