diff mbox series

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

Message ID 20240905181330.3657590-5-berrange@redhat.com
State New
Headers show
Series Report fatal errors from failure with pre-opened eBPF RSS FDs | expand

Commit Message

Daniel P. Berrangé Sept. 5, 2024, 6:13 p.m. UTC
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(-)

Comments

Philippe Mathieu-Daudé Sept. 6, 2024, 10:07 a.m. UTC | #1
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>
Jason Wang Oct. 23, 2024, 3:55 a.m. UTC | #2
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
Daniel P. Berrangé Oct. 23, 2024, 8:52 a.m. UTC | #3
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
diff mbox series

Patch

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);
         }
     }