Also, added dependencies for libbpf with bpf option.
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
---
meson.build | 7 ++++
meson_options.txt | 1 +
src/qemu/meson.build | 1 +
src/qemu/qemu_interface.c | 83 +++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_interface.h | 4 ++
5 files changed, 96 insertions(+)
diff --git a/meson.build b/meson.build
index e8b0094b91..e12a703a4d 100644
--- a/meson.build
+++ b/meson.build
@@ -998,6 +998,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'))
@@ -2283,6 +2289,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 9d729b3e1f..9b7bd9d1f8 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -48,6 +48,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 907893d431..de7ae87d5b 100644
--- a/src/qemu/meson.build
+++ b/src/qemu/meson.build
@@ -105,6 +105,7 @@ if conf.has('WITH_QEMU')
selinux_dep,
src_dep,
xdr_dep,
+ libbpf_dep,
],
include_directories: [
conf_inc_dir,
diff --git a/src/qemu/qemu_interface.c b/src/qemu/qemu_interface.c
index c2007c7043..ec8cf18d86 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,82 @@ 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);
+ err = libbpf_get_error(obj);
+ if (err) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%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 -1;
+}
+
+void
+qemuInterfaceCloseEbpf(void *libbpfObj G_GNUC_UNUSED)
+{
+}
+
+#endif
diff --git a/src/qemu/qemu_interface.h b/src/qemu/qemu_interface.h
index aee5f9efb0..b6f39550cd 100644
--- a/src/qemu/qemu_interface.h
+++ b/src/qemu/qemu_interface.h
@@ -44,3 +44,7 @@ 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.44.0
_______________________________________________
Devel mailing list -- devel@lists.libvirt.org
To unsubscribe send an email to devel-leave@lists.libvirt.org
On 5/12/24 21:45, Andrew Melnychenko wrote: > Also, added dependencies for libbpf with bpf option. > > Signed-off-by: Andrew Melnychenko <andrew@daynix.com> > --- > meson.build | 7 ++++ > meson_options.txt | 1 + > src/qemu/meson.build | 1 + > src/qemu/qemu_interface.c | 83 +++++++++++++++++++++++++++++++++++++++ > src/qemu/qemu_interface.h | 4 ++ > 5 files changed, 96 insertions(+) libvirt.spec.in should be changed too to either selectively disable this feature or enable it and drag in the requirement (preferred). > > diff --git a/meson.build b/meson.build > index e8b0094b91..e12a703a4d 100644 > --- a/meson.build > +++ b/meson.build > @@ -998,6 +998,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')) > > @@ -2283,6 +2289,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 9d729b3e1f..9b7bd9d1f8 100644 > --- a/meson_options.txt > +++ b/meson_options.txt > @@ -48,6 +48,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 907893d431..de7ae87d5b 100644 > --- a/src/qemu/meson.build > +++ b/src/qemu/meson.build > @@ -105,6 +105,7 @@ if conf.has('WITH_QEMU') > selinux_dep, > src_dep, > xdr_dep, > + libbpf_dep, We tend to keep this kind of lists sorted alphabetically. > ], > include_directories: [ > conf_inc_dir, > diff --git a/src/qemu/qemu_interface.c b/src/qemu/qemu_interface.c > index c2007c7043..ec8cf18d86 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> s/#include/# include/ if you'd install 'cppi' then a syntax-check rule of ours would have warned you about this. > +#endif > + > #define VIR_FROM_THIS VIR_FROM_QEMU > > VIR_LOG_INIT("qemu.qemu_interface"); > @@ -432,3 +436,82 @@ 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); > + err = libbpf_get_error(obj); > + if (err) { > + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("can't open eBPF object")); > + return -1; > + } IIUC, libbpf_get_error() is deprecated and upon failure bpf_object_*() APIs return NULL and set errno. Thus this (and the rest) could look something like this: obj = bpf_object__open_mem(...); if (!obj) { virReportSystemError(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 -1; Maybe this can return -2 so that callers can distinguish this version and the version above failing? > +} Michal
Hi all, On Fri, May 17, 2024 at 5:00 PM Michal Prívozník <mprivozn@redhat.com> wrote: > > On 5/12/24 21:45, Andrew Melnychenko wrote: > > Also, added dependencies for libbpf with bpf option. > > > > Signed-off-by: Andrew Melnychenko <andrew@daynix.com> > > --- > > meson.build | 7 ++++ > > meson_options.txt | 1 + > > src/qemu/meson.build | 1 + > > src/qemu/qemu_interface.c | 83 +++++++++++++++++++++++++++++++++++++++ > > src/qemu/qemu_interface.h | 4 ++ > > 5 files changed, 96 insertions(+) > > > libvirt.spec.in should be changed too to either selectively disable this > feature or enable it and drag in the requirement (preferred). Yes, I'll "enable it" in the next version. > > > > > diff --git a/meson.build b/meson.build > > index e8b0094b91..e12a703a4d 100644 > > --- a/meson.build > > +++ b/meson.build > > @@ -998,6 +998,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')) > > > > @@ -2283,6 +2289,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 9d729b3e1f..9b7bd9d1f8 100644 > > --- a/meson_options.txt > > +++ b/meson_options.txt > > @@ -48,6 +48,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 907893d431..de7ae87d5b 100644 > > --- a/src/qemu/meson.build > > +++ b/src/qemu/meson.build > > @@ -105,6 +105,7 @@ if conf.has('WITH_QEMU') > > selinux_dep, > > src_dep, > > xdr_dep, > > + libbpf_dep, > > We tend to keep this kind of lists sorted alphabetically. > > > ], > > include_directories: [ > > conf_inc_dir, > > diff --git a/src/qemu/qemu_interface.c b/src/qemu/qemu_interface.c > > index c2007c7043..ec8cf18d86 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> > > s/#include/# include/ > if you'd install 'cppi' then a syntax-check rule of ours would have > warned you about this. > > > +#endif > > + > > #define VIR_FROM_THIS VIR_FROM_QEMU > > > > VIR_LOG_INIT("qemu.qemu_interface"); > > @@ -432,3 +436,82 @@ 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); > > + err = libbpf_get_error(obj); > > + if (err) { > > + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("can't open eBPF object")); > > + return -1; > > + } > > IIUC, libbpf_get_error() is deprecated and upon failure bpf_object_*() > APIs return NULL and set errno. Thus this (and the rest) could look > something like this: > > obj = bpf_object__open_mem(...); > if (!obj) { > virReportSystemError(errno, "%s", _("can't open eBPF object")); > return -1; > } > Ok. originally I've tied to omit errno and use VIR_ERR* macros. > > + > > + > > + 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 -1; > > Maybe this can return -2 so that callers can distinguish this version > and the version above failing? > Ok. > > +} > > Michal >
© 2016 - 2024 Red Hat, Inc.