[PATCH v2 4/7] ebpf: add formal error reporting to all APIs

Daniel P. Berrangé posted 7 patches 2 months, 2 weeks ago
There is a newer version of this series
[PATCH v2 4/7] ebpf: add formal error reporting to all APIs
Posted by Daniel P. Berrangé 2 months, 2 weeks ago
The eBPF code is currently reporting error messages through trace
events. Trace events are fine for debugging, but they are not to be
considered the primary error reporting mechanism, as their output
is inaccessible to callers.

This adds an "Error **errp" parameter to all methods which have
important error scenarios to report to the caller.

Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 ebpf/ebpf_rss.c     | 59 ++++++++++++++++++++++++++++++++++++---------
 ebpf/ebpf_rss.h     | 10 +++++---
 hw/net/virtio-net.c |  7 +++---
 3 files changed, 59 insertions(+), 17 deletions(-)

diff --git a/ebpf/ebpf_rss.c b/ebpf/ebpf_rss.c
index 47186807ad..f65a58b0b6 100644
--- a/ebpf/ebpf_rss.c
+++ b/ebpf/ebpf_rss.c
@@ -47,13 +47,14 @@ bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx)
     return ctx != NULL && (ctx->obj != NULL || ctx->program_fd != -1);
 }
 
-static bool ebpf_rss_mmap(struct EBPFRSSContext *ctx)
+static bool ebpf_rss_mmap(struct EBPFRSSContext *ctx, Error **errp)
 {
     ctx->mmap_configuration = mmap(NULL, qemu_real_host_page_size(),
                                    PROT_READ | PROT_WRITE, MAP_SHARED,
                                    ctx->map_configuration, 0);
     if (ctx->mmap_configuration == MAP_FAILED) {
         trace_ebpf_rss_mmap_error(ctx, "configuration");
+        error_setg(errp, "Unable to map eBPF configuration array");
         return false;
     }
     ctx->mmap_toeplitz_key = mmap(NULL, qemu_real_host_page_size(),
@@ -61,6 +62,7 @@ static bool ebpf_rss_mmap(struct EBPFRSSContext *ctx)
                                    ctx->map_toeplitz_key, 0);
     if (ctx->mmap_toeplitz_key == MAP_FAILED) {
         trace_ebpf_rss_mmap_error(ctx, "toeplitz key");
+        error_setg(errp, "Unable to map eBPF toeplitz array");
         goto toeplitz_fail;
     }
     ctx->mmap_indirections_table = mmap(NULL, qemu_real_host_page_size(),
@@ -68,6 +70,7 @@ static bool ebpf_rss_mmap(struct EBPFRSSContext *ctx)
                                    ctx->map_indirections_table, 0);
     if (ctx->mmap_indirections_table == MAP_FAILED) {
         trace_ebpf_rss_mmap_error(ctx, "indirections table");
+        error_setg(errp, "Unable to map eBPF indirection array");
         goto indirection_fail;
     }
 
@@ -95,7 +98,7 @@ static void ebpf_rss_munmap(struct EBPFRSSContext *ctx)
     ctx->mmap_indirections_table = NULL;
 }
 
-bool ebpf_rss_load(struct EBPFRSSContext *ctx)
+bool ebpf_rss_load(struct EBPFRSSContext *ctx, Error **errp)
 {
     struct rss_bpf *rss_bpf_ctx;
 
@@ -106,6 +109,7 @@ bool ebpf_rss_load(struct EBPFRSSContext *ctx)
     rss_bpf_ctx = rss_bpf__open();
     if (rss_bpf_ctx == NULL) {
         trace_ebpf_rss_open_error(ctx);
+        error_setg(errp, "Unable to open eBPF RSS object");
         goto error;
     }
 
@@ -113,6 +117,7 @@ bool ebpf_rss_load(struct EBPFRSSContext *ctx)
 
     if (rss_bpf__load(rss_bpf_ctx)) {
         trace_ebpf_rss_load_error(ctx);
+        error_setg(errp, "Unable to load eBPF program");
         goto error;
     }
 
@@ -126,7 +131,7 @@ bool ebpf_rss_load(struct EBPFRSSContext *ctx)
     ctx->map_toeplitz_key = bpf_map__fd(
             rss_bpf_ctx->maps.tap_rss_map_toeplitz_key);
 
-    if (!ebpf_rss_mmap(ctx)) {
+    if (!ebpf_rss_mmap(ctx, errp)) {
         goto error;
     }
 
@@ -143,13 +148,28 @@ error:
 }
 
 bool ebpf_rss_load_fds(struct EBPFRSSContext *ctx, int program_fd,
-                       int config_fd, int toeplitz_fd, int table_fd)
+                       int config_fd, int toeplitz_fd, int table_fd,
+                       Error **errp)
 {
     if (ebpf_rss_is_loaded(ctx)) {
+        error_setg(errp, "eBPF program is already loaded");
         return false;
     }
 
-    if (program_fd < 0 || config_fd < 0 || toeplitz_fd < 0 || table_fd < 0) {
+    if (program_fd < 0) {
+        error_setg(errp, "eBPF program FD is not open");
+        return false;
+    }
+    if (config_fd < 0) {
+        error_setg(errp, "eBPF config FD is not open");
+        return false;
+    }
+    if (toeplitz_fd < 0) {
+        error_setg(errp, "eBPF toeplitz FD is not open");
+        return false;
+    }
+    if (table_fd < 0) {
+        error_setg(errp, "eBPF indirection FD is not open");
         return false;
     }
 
@@ -158,7 +178,7 @@ bool ebpf_rss_load_fds(struct EBPFRSSContext *ctx, int program_fd,
     ctx->map_toeplitz_key = toeplitz_fd;
     ctx->map_indirections_table = table_fd;
 
-    if (!ebpf_rss_mmap(ctx)) {
+    if (!ebpf_rss_mmap(ctx, errp)) {
         ctx->program_fd = -1;
         ctx->map_configuration = -1;
         ctx->map_toeplitz_key = -1;
@@ -177,11 +197,14 @@ static void ebpf_rss_set_config(struct EBPFRSSContext *ctx,
 
 static bool ebpf_rss_set_indirections_table(struct EBPFRSSContext *ctx,
                                             uint16_t *indirections_table,
-                                            size_t len)
+                                            size_t len,
+                                            Error **errp)
 {
     char *cursor = ctx->mmap_indirections_table;
 
     if (len > VIRTIO_NET_RSS_MAX_TABLE_LEN) {
+        error_setg(errp, "Indirections table length %zu exceeds limit %d",
+                   len, VIRTIO_NET_RSS_MAX_TABLE_LEN);
         return false;
     }
 
@@ -206,17 +229,31 @@ static void ebpf_rss_set_toepliz_key(struct EBPFRSSContext *ctx,
 }
 
 bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
-                      uint16_t *indirections_table, uint8_t *toeplitz_key)
+                      uint16_t *indirections_table, uint8_t *toeplitz_key,
+                      Error **errp)
 {
-    if (!ebpf_rss_is_loaded(ctx) || config == NULL ||
-        indirections_table == NULL || toeplitz_key == NULL) {
+    if (!ebpf_rss_is_loaded(ctx)) {
+        error_setg(errp, "eBPF program is not loaded");
+        return false;
+    }
+    if (config == NULL) {
+        error_setg(errp, "eBPF config table is NULL");
+        return false;
+    }
+    if (indirections_table == NULL) {
+        error_setg(errp, "eBPF indirections table is NULL");
+        return false;
+    }
+    if (toeplitz_key == NULL) {
+        error_setg(errp, "eBPF toeplitz key is NULL");
         return false;
     }
 
     ebpf_rss_set_config(ctx, config);
 
     if (!ebpf_rss_set_indirections_table(ctx, indirections_table,
-                                      config->indirections_len)) {
+                                         config->indirections_len,
+                                         errp)) {
         return false;
     }
 
diff --git a/ebpf/ebpf_rss.h b/ebpf/ebpf_rss.h
index 239242b0d2..86a5787789 100644
--- a/ebpf/ebpf_rss.h
+++ b/ebpf/ebpf_rss.h
@@ -14,6 +14,8 @@
 #ifndef QEMU_EBPF_RSS_H
 #define QEMU_EBPF_RSS_H
 
+#include "qapi/error.h"
+
 #define EBPF_RSS_MAX_FDS 4
 
 struct EBPFRSSContext {
@@ -41,13 +43,15 @@ void ebpf_rss_init(struct EBPFRSSContext *ctx);
 
 bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx);
 
-bool ebpf_rss_load(struct EBPFRSSContext *ctx);
+bool ebpf_rss_load(struct EBPFRSSContext *ctx, Error **errp);
 
 bool ebpf_rss_load_fds(struct EBPFRSSContext *ctx, int program_fd,
-                       int config_fd, int toeplitz_fd, int table_fd);
+                       int config_fd, int toeplitz_fd, int table_fd,
+                       Error **errp);
 
 bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
-                      uint16_t *indirections_table, uint8_t *toeplitz_key);
+                      uint16_t *indirections_table, uint8_t *toeplitz_key,
+                      Error **errp);
 
 void ebpf_rss_unload(struct EBPFRSSContext *ctx);
 
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 055fce1d78..558fc62844 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -1265,7 +1265,8 @@ static bool virtio_net_attach_ebpf_rss(VirtIONet *n)
     rss_data_to_rss_config(&n->rss_data, &config);
 
     if (!ebpf_rss_set_all(&n->ebpf_rss, &config,
-                          n->rss_data.indirections_table, n->rss_data.key)) {
+                          n->rss_data.indirections_table, n->rss_data.key,
+                          NULL)) {
         return false;
     }
 
@@ -1336,7 +1337,7 @@ static bool virtio_net_load_ebpf_fds(VirtIONet *n)
         }
     }
 
-    ret = ebpf_rss_load_fds(&n->ebpf_rss, fds[0], fds[1], fds[2], fds[3]);
+    ret = ebpf_rss_load_fds(&n->ebpf_rss, fds[0], fds[1], fds[2], fds[3], NULL);
 
 exit:
     if (!ret) {
@@ -1354,7 +1355,7 @@ static bool virtio_net_load_ebpf(VirtIONet *n)
 
     if (virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
         if (!(n->ebpf_rss_fds && virtio_net_load_ebpf_fds(n))) {
-            ret = ebpf_rss_load(&n->ebpf_rss);
+            ret = ebpf_rss_load(&n->ebpf_rss, NULL);
         }
     }
 
-- 
2.45.2


Re: [PATCH v2 4/7] ebpf: add formal error reporting to all APIs
Posted by Jason Wang 1 month ago
On Fri, Sep 6, 2024 at 2:13 AM Daniel P. Berrangé <berrange@redhat.com> wrote:
>
> The eBPF code is currently reporting error messages through trace
> events. Trace events are fine for debugging, but they are not to be
> considered the primary error reporting mechanism, as their output
> is inaccessible to callers.
>
> This adds an "Error **errp" parameter to all methods which have
> important error scenarios to report to the caller.
>
> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>

This doesn't compile:

[3/84] Compiling C object libcommon.a.p/ebpf_ebpf_rss-stub.c.o
FAILED: libcommon.a.p/ebpf_ebpf_rss-stub.c.o
cc -m64 -Ilibcommon.a.p -Isubprojects/dtc/libfdt
-I../subprojects/dtc/libfdt -Isubprojects/slirp -I../subprojects/slirp
-I../subprojects/slirp/src -Isubprojects/libvduse
-I../subprojects/libvduse -I/usr/include/pixman-1
-I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include
-I/usr/include/sysprof-4 -I/usr/include/libmount -I/usr/include/blkid
-I/usr/include/gio-unix-2.0 -fdiagnostics-color=auto -Wall
-Winvalid-pch -Werror -std=gnu11 -O2 -g -fstack-protector-strong
-Wempty-body -Wendif-labels -Wexpansion-to-defined -Wformat-security
-Wformat-y2k -Wignored-qualifiers -Wimplicit-fallthrough=2 -Winit-self
-Wmissing-format-attribute -Wmissing-prototypes -Wnested-externs
-Wold-style-declaration -Wold-style-definition -Wredundant-decls
-Wshadow=local -Wstrict-prototypes -Wtype-limits -Wundef -Wvla
-Wwrite-strings -Wno-missing-include-dirs -Wno-psabi
-Wno-shift-negative-value -isystem /home/devel/git/qemu/linux-headers
-isystem linux-headers -iquote . -iquote /home/devel/git/qemu -iquote
/home/devel/git/qemu/include -iquote
/home/devel/git/qemu/host/include/x86_64 -iquote
/home/devel/git/qemu/host/include/generic -iquote
/home/devel/git/qemu/tcg/i386 -pthread -mcx16 -msse2 -D_GNU_SOURCE
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fno-strict-aliasing
-fno-common -fwrapv -fzero-call-used-regs=used-gpr -fPIE
-D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DNCURSES_WIDECHAR=1 -MD -MQ
libcommon.a.p/ebpf_ebpf_rss-stub.c.o -MF
libcommon.a.p/ebpf_ebpf_rss-stub.c.o.d -o
libcommon.a.p/ebpf_ebpf_rss-stub.c.o -c ../ebpf/ebpf_rss-stub.c
../ebpf/ebpf_rss-stub.c:26:6: error: conflicting types for
‘ebpf_rss_load’; have ‘_Bool(struct EBPFRSSContext *)’
   26 | bool ebpf_rss_load(struct EBPFRSSContext *ctx)
      |      ^~~~~~~~~~~~~
In file included from ../ebpf/ebpf_rss-stub.c:14:
/home/devel/git/qemu/ebpf/ebpf_rss.h:46:6: note: previous declaration
of ‘ebpf_rss_load’ with type ‘_Bool(struct EBPFRSSContext *, Error
**)’
   46 | bool ebpf_rss_load(struct EBPFRSSContext *ctx, Error **errp);
      |      ^~~~~~~~~~~~~
../ebpf/ebpf_rss-stub.c:31:6: error: conflicting types for
‘ebpf_rss_load_fds’; have ‘_Bool(struct EBPFRSSContext *, int,  int,
int,  int)’
   31 | bool ebpf_rss_load_fds(struct EBPFRSSContext *ctx, int program_fd,
      |      ^~~~~~~~~~~~~~~~~
In file included from ../ebpf/ebpf_rss-stub.c:14:
/home/devel/git/qemu/ebpf/ebpf_rss.h:48:6: note: previous declaration
of ‘ebpf_rss_load_fds’ with type ‘_Bool(struct EBPFRSSContext *, int,
int,  int,  int,  Error **)’
   48 | bool ebpf_rss_load_fds(struct EBPFRSSContext *ctx, int program_fd,
      |      ^~~~~~~~~~~~~~~~~
../ebpf/ebpf_rss-stub.c:37:6: error: conflicting types for
‘ebpf_rss_set_all’; have ‘_Bool(struct EBPFRSSContext *, struct
EBPFRSSConfig *, uint16_t *, uint8_t *)’ {aka ‘_Bool(struct
EBPFRSSContext *, struct EBPFRSSConfig *, short unsigned int *,
unsigned char *)’}
   37 | bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct
EBPFRSSConfig *config,
      |      ^~~~~~~~~~~~~~~~
In file included from ../ebpf/ebpf_rss-stub.c:14:
/home/devel/git/qemu/ebpf/ebpf_rss.h:52:6: note: previous declaration
of ‘ebpf_rss_set_all’ with type ‘_Bool(struct EBPFRSSContext *, struct
EBPFRSSConfig *, uint16_t *, uint8_t *, Error **)’ {aka ‘_Bool(struct
EBPFRSSContext *, struct EBPFRSSConfig *, short unsigned int *,
unsigned char *, Error **)’}
   52 | bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct
EBPFRSSConfig *config,
      |      ^~~~~~~~~~~~~~~~

Thanks
Re: [PATCH v2 4/7] ebpf: add formal error reporting to all APIs
Posted by Daniel P. Berrangé 1 month ago
On Wed, Oct 23, 2024 at 11:55:42AM +0800, Jason Wang wrote:
> On Fri, Sep 6, 2024 at 2:13 AM Daniel P. Berrangé <berrange@redhat.com> wrote:
> >
> > The eBPF code is currently reporting error messages through trace
> > events. Trace events are fine for debugging, but they are not to be
> > considered the primary error reporting mechanism, as their output
> > is inaccessible to callers.
> >
> > This adds an "Error **errp" parameter to all methods which have
> > important error scenarios to report to the caller.
> >
> > Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
> 
> This doesn't compile:
> 
> [3/84] Compiling C object libcommon.a.p/ebpf_ebpf_rss-stub.c.o

Opps, I didn't update the stub for the new Error parameter.

I've sent a new series with the fix


With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|


Re: [PATCH v2 4/7] ebpf: add formal error reporting to all APIs
Posted by Philippe Mathieu-Daudé 2 months, 2 weeks ago
On 5/9/24 20:13, Daniel P. Berrangé wrote:
> The eBPF code is currently reporting error messages through trace
> events. Trace events are fine for debugging, but they are not to be
> considered the primary error reporting mechanism, as their output
> is inaccessible to callers.
> 
> This adds an "Error **errp" parameter to all methods which have
> important error scenarios to report to the caller.
> 
> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
> ---
>   ebpf/ebpf_rss.c     | 59 ++++++++++++++++++++++++++++++++++++---------
>   ebpf/ebpf_rss.h     | 10 +++++---
>   hw/net/virtio-net.c |  7 +++---
>   3 files changed, 59 insertions(+), 17 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>