[RFC PATCH v4 3/5] qemu_interface: Added routine for loading the eBPF objects.

Andrew Melnychenko posted 5 patches 3 months ago
[RFC PATCH v4 3/5] qemu_interface: Added routine for loading the eBPF objects.
Posted by Andrew Melnychenko 3 months ago
Also, added dependencies for libbpf with bpf option.

Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
---
 libvirt.spec.in           |  3 ++
 meson.build               |  7 ++++
 meson_options.txt         |  1 +
 src/qemu/meson.build      |  1 +
 src/qemu/qemu_interface.c | 87 +++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_interface.h |  7 ++++
 6 files changed, 106 insertions(+)

diff --git a/libvirt.spec.in b/libvirt.spec.in
index 29101e74fe..9a27123487 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -366,6 +366,7 @@ BuildRequires: yajl-devel
 BuildRequires: sanlock-devel >= 2.4
     %endif
 BuildRequires: libpcap-devel >= 1.5.0
+BuildRequires: libbpf-devel >= 1.1.0
 BuildRequires: libnl3-devel
 BuildRequires: libselinux-devel
 # For modprobe
@@ -1374,6 +1375,7 @@ export SOURCE_DATE_EPOCH=$(stat --printf='%Y' %{_specdir}/libvirt.spec)
            -Dlibpcap=enabled \
            %{?arg_nbdkit} \
            %{?arg_nbdkit_config_default} \
+           -Dlibbpf=enabled \
            -Dlibnl=enabled \
            -Daudit=enabled \
            -Ddtrace=enabled \
@@ -1444,6 +1446,7 @@ export SOURCE_DATE_EPOCH=$(stat --printf='%Y' %{_specdir}/libvirt.spec)
   -Dlibiscsi=disabled \
   -Dnbdkit=disabled \
   -Dnbdkit_config_default=disabled \
+  -Dlibbpf=disabled \
   -Dlibnl=disabled \
   -Dlibpcap=disabled \
   -Dlibssh2=disabled \
diff --git a/meson.build b/meson.build
index 231470e2ee..0647fc74bf 100644
--- a/meson.build
+++ b/meson.build
@@ -1025,6 +1025,12 @@ else
   libkvm_dep = dependency('', required: false)
 endif
 
+libbpf_version = '1.1.0'
+libbpf_dep = dependency('libbpf', version: '>=' + libbpf_version, required: get_option('libbpf'))
+if libbpf_dep.found()
+    conf.set('WITH_BPF', 1)
+endif
+
 libiscsi_version = '1.18.0'
 libiscsi_dep = dependency('libiscsi', version: '>=' + libiscsi_version, required: get_option('libiscsi'))
 
@@ -2339,6 +2345,7 @@ libs_summary = {
   'dlopen': dlopen_dep.found(),
   'fuse': fuse_dep.found(),
   'glusterfs': glusterfs_dep.found(),
+  'libbpf': libbpf_dep.found(),
   'libiscsi': libiscsi_dep.found(),
   'libkvm': libkvm_dep.found(),
   'libnbd': libnbd_dep.found(),
diff --git a/meson_options.txt b/meson_options.txt
index 2d440c63d8..be1582186e 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -51,6 +51,7 @@ option('udev', type: 'feature', value: 'auto', description: 'udev support')
 option('wireshark_dissector', type: 'feature', value: 'auto', description: 'wireshark support')
 option('wireshark_plugindir', type: 'string', value: '', description: 'wireshark plugins directory for use when installing wireshark plugin')
 option('yajl', type: 'feature', value: 'auto', description: 'yajl support')
+option('libbpf', type: 'feature', value: 'auto', description: 'qemu libbpf support')
 
 
 # build driver options
diff --git a/src/qemu/meson.build b/src/qemu/meson.build
index 57356451e4..60e7e02373 100644
--- a/src/qemu/meson.build
+++ b/src/qemu/meson.build
@@ -99,6 +99,7 @@ if conf.has('WITH_QEMU')
       access_dep,
       capng_dep,
       gnutls_dep,
+      libbpf_dep,
       libnbd_dep,
       libnl_dep,
       log_dep,
diff --git a/src/qemu/qemu_interface.c b/src/qemu/qemu_interface.c
index c2007c7043..3f141afd26 100644
--- a/src/qemu/qemu_interface.c
+++ b/src/qemu/qemu_interface.c
@@ -38,6 +38,10 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 
+#ifdef WITH_BPF
+# include <bpf/libbpf.h>
+#endif
+
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
 VIR_LOG_INIT("qemu.qemu_interface");
@@ -432,3 +436,86 @@ qemuInterfaceOpenVhostNet(virDomainObj *vm,
     virDomainAuditNetDevice(vm->def, net, vhostnet_path, vhostfdSize);
     return 0;
 }
+
+#ifdef WITH_BPF
+
+int
+qemuInterfaceLoadEbpf(const char *ebpfObject,
+                      void **retLibbpfObj,
+                      int *fds,
+                      size_t nfds)
+{
+    int err = 0;
+    size_t i = 0;
+    struct bpf_program *prog;
+    struct bpf_map *map;
+    struct bpf_object *obj;
+    size_t ebpfSize = 0;
+    g_autofree void *ebpfRawData = NULL;
+
+    ebpfRawData = g_base64_decode(ebpfObject, &ebpfSize);
+    if (ebpfRawData == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("can't decode the eBPF from base64"));
+        return -1;
+    }
+
+    obj = bpf_object__open_mem(ebpfRawData, ebpfSize, NULL);
+    if (!obj) {
+        virReportError(errno, "%s", _("can't open eBPF object"));
+        return -1;
+    }
+
+
+    err = bpf_object__load(obj);
+    if (err) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("can't load eBPF object"));
+        return -1;
+    }
+
+    bpf_object__for_each_program(prog, obj) {
+        fds[i] = bpf_program__fd(prog);
+        ++i;
+        if (i > nfds) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("to much file descriptors in eBPF"));
+            return -1;
+        }
+    }
+
+    bpf_object__for_each_map(map, obj) {
+        fds[i] = bpf_map__fd(map);
+        ++i;
+        if (i > nfds) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("to much file descriptors in eBPF"));
+            return -1;
+        }
+    }
+
+    *retLibbpfObj = obj;
+
+    return i - 1;
+}
+
+
+void
+qemuInterfaceCloseEbpf(void *libbpfObj)
+{
+    if (libbpfObj)
+        bpf_object__close(libbpfObj);
+}
+#else
+
+int
+qemuInterfaceLoadEbpf(const char *ebpfObject G_GNUC_UNUSED,
+                      void **retLibbpfObj G_GNUC_UNUSED,
+                      int *fds G_GNUC_UNUSED,
+                      size_t nfds G_GNUC_UNUSED)
+{
+    return -2;
+}
+
+void
+qemuInterfaceCloseEbpf(void *libbpfObj G_GNUC_UNUSED)
+{
+}
+
+#endif
diff --git a/src/qemu/qemu_interface.h b/src/qemu/qemu_interface.h
index aee5f9efb0..8ce86b8769 100644
--- a/src/qemu/qemu_interface.h
+++ b/src/qemu/qemu_interface.h
@@ -44,3 +44,10 @@ int qemuInterfaceOpenVhostNet(virDomainObj *def,
 
 int qemuInterfacePrepareSlirp(virQEMUDriver *driver,
                               virDomainNetDef *net);
+
+int qemuInterfaceLoadEbpf(const char *ebpfObject,
+                          void **retLibbpfObj,
+                          int *fds,
+                          size_t nfds);
+
+void qemuInterfaceCloseEbpf(void *libbpfObj);
-- 
2.45.2