From 493a2403c247bdcfc812303f8dc0801778de4798 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrangé" Date: Wed, 23 Oct 2024 09:50:57 +0100 Subject: hw/net: fix typo s/epbf/ebpf/ in virtio-net MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Daniel P. Berrangé Signed-off-by: Jason Wang --- hw/net/virtio-net.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'hw/net/virtio-net.c') diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index fb84d142ee..7c050246ea 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1254,7 +1254,7 @@ static void rss_data_to_rss_config(struct VirtioNetRssData *data, config->default_queue = data->default_queue; } -static bool virtio_net_attach_epbf_rss(VirtIONet *n) +static bool virtio_net_attach_ebpf_rss(VirtIONet *n) { struct EBPFRSSConfig config = {}; @@ -1276,7 +1276,7 @@ static bool virtio_net_attach_epbf_rss(VirtIONet *n) return true; } -static void virtio_net_detach_epbf_rss(VirtIONet *n) +static void virtio_net_detach_ebpf_rss(VirtIONet *n) { virtio_net_attach_ebpf_to_backend(n->nic, -1); } @@ -1286,8 +1286,8 @@ static void virtio_net_commit_rss_config(VirtIONet *n) if (n->rss_data.enabled) { n->rss_data.enabled_software_rss = n->rss_data.populate_hash; if (n->rss_data.populate_hash) { - virtio_net_detach_epbf_rss(n); - } else if (!virtio_net_attach_epbf_rss(n)) { + virtio_net_detach_ebpf_rss(n); + } else if (!virtio_net_attach_ebpf_rss(n)) { if (get_vhost_net(qemu_get_queue(n->nic)->peer)) { warn_report("Can't load eBPF RSS for vhost"); } else { @@ -1300,7 +1300,7 @@ static void virtio_net_commit_rss_config(VirtIONet *n) n->rss_data.indirections_len, sizeof(n->rss_data.key)); } else { - virtio_net_detach_epbf_rss(n); + virtio_net_detach_ebpf_rss(n); trace_virtio_net_rss_disable(); } } -- cgit 1.4.1 From 00b69f1d867ddcf8884c92f5647b424088e754e4 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrangé" Date: Wed, 23 Oct 2024 09:51:00 +0100 Subject: ebpf: add formal error reporting to all APIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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é Signed-off-by: Jason Wang --- ebpf/ebpf_rss-stub.c | 8 ++++--- ebpf/ebpf_rss.c | 59 ++++++++++++++++++++++++++++++++++++++++++---------- ebpf/ebpf_rss.h | 10 ++++++--- hw/net/virtio-net.c | 7 ++++--- 4 files changed, 64 insertions(+), 20 deletions(-) (limited to 'hw/net/virtio-net.c') diff --git a/ebpf/ebpf_rss-stub.c b/ebpf/ebpf_rss-stub.c index 8d7fae2ad9..d0e7f99fb9 100644 --- a/ebpf/ebpf_rss-stub.c +++ b/ebpf/ebpf_rss-stub.c @@ -23,19 +23,21 @@ bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx) return false; } -bool ebpf_rss_load(struct EBPFRSSContext *ctx) +bool ebpf_rss_load(struct EBPFRSSContext *ctx, Error **errp) { return false; } 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) { return false; } 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) { return false; } diff --git a/ebpf/ebpf_rss.c b/ebpf/ebpf_rss.c index d39916b368..67cdab197d 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 7c050246ea..289fba8152 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); } } -- cgit 1.4.1 From b5900dff14e5a8334766de6b37629c8020c6bbb0 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrangé" Date: Wed, 23 Oct 2024 09:51:01 +0100 Subject: hw/net: report errors from failing to use eBPF RSS FDs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the user/mgmt app passed in a set of pre-opened FDs for eBPF RSS, then it is expecting QEMU to use them. Any failure to do so must be considered a fatal error and propagated back up the stack, otherwise deployment mistakes will not be detectable in a prompt manner. When not using pre-opened FDs, then eBPF RSS is tried on a "best effort" basis only and thus fallback to software RSS is valid. Signed-off-by: Daniel P. Berrangé Signed-off-by: Jason Wang --- hw/net/virtio-net.c | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) (limited to 'hw/net/virtio-net.c') diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 289fba8152..c08ae55424 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1316,28 +1316,27 @@ static void virtio_net_disable_rss(VirtIONet *n) virtio_net_commit_rss_config(n); } -static bool virtio_net_load_ebpf_fds(VirtIONet *n) +static bool virtio_net_load_ebpf_fds(VirtIONet *n, Error **errp) { int fds[EBPF_RSS_MAX_FDS] = { [0 ... EBPF_RSS_MAX_FDS - 1] = -1}; int ret = true; int i = 0; if (n->nr_ebpf_rss_fds != EBPF_RSS_MAX_FDS) { - warn_report("Expected %d file descriptors but got %d", - EBPF_RSS_MAX_FDS, n->nr_ebpf_rss_fds); - return false; - } + error_setg(errp, "Expected %d file descriptors but got %d", + EBPF_RSS_MAX_FDS, n->nr_ebpf_rss_fds); + return false; + } for (i = 0; i < n->nr_ebpf_rss_fds; i++) { - fds[i] = monitor_fd_param(monitor_cur(), n->ebpf_rss_fds[i], - &error_warn); + fds[i] = monitor_fd_param(monitor_cur(), n->ebpf_rss_fds[i], errp); if (fds[i] < 0) { ret = false; goto exit; } } - ret = ebpf_rss_load_fds(&n->ebpf_rss, fds[0], fds[1], fds[2], fds[3], NULL); + ret = ebpf_rss_load_fds(&n->ebpf_rss, fds[0], fds[1], fds[2], fds[3], errp); exit: if (!ret) { @@ -1349,13 +1348,15 @@ exit: return ret; } -static bool virtio_net_load_ebpf(VirtIONet *n) +static bool virtio_net_load_ebpf(VirtIONet *n, Error **errp) { bool ret = false; 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, NULL); + if (n->ebpf_rss_fds) { + ret = virtio_net_load_ebpf_fds(n, errp); + } else { + ret = ebpf_rss_load(&n->ebpf_rss, errp); } } @@ -3761,7 +3762,23 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) net_rx_pkt_init(&n->rx_pkt); if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) { - virtio_net_load_ebpf(n); + Error *err = NULL; + if (!virtio_net_load_ebpf(n, &err)) { + /* + * If user explicitly gave QEMU RSS FDs to use, then + * failing to use them must be considered a fatal + * error. If no RSS FDs were provided, QEMU is trying + * eBPF on a "best effort" basis only, so report a + * warning and allow fallback to software RSS. + */ + if (n->ebpf_rss_fds) { + error_propagate(errp, err); + } else { + warn_report("unable to load eBPF RSS: %s", + error_get_pretty(err)); + error_free(err); + } + } } } -- cgit 1.4.1 From ae311fb31543ca4e9de38c8435ebbdf6eca664d9 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrangé" Date: Wed, 23 Oct 2024 09:51:03 +0100 Subject: hw/net: improve tracing of eBPF RSS setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds more trace events to key eBPF RSS setup operations, and also distinguishes events from multiple NIC instances. Signed-off-by: Daniel P. Berrangé Signed-off-by: Jason Wang --- hw/net/trace-events | 8 +++++--- hw/net/virtio-net.c | 9 ++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'hw/net/virtio-net.c') diff --git a/hw/net/trace-events b/hw/net/trace-events index 4c6687923e..91a3d0c054 100644 --- a/hw/net/trace-events +++ b/hw/net/trace-events @@ -394,9 +394,11 @@ virtio_net_announce_notify(void) "" virtio_net_announce_timer(int round) "%d" virtio_net_handle_announce(int round) "%d" virtio_net_post_load_device(void) -virtio_net_rss_disable(void) -virtio_net_rss_error(const char *msg, uint32_t value) "%s, value 0x%08x" -virtio_net_rss_enable(uint32_t p1, uint16_t p2, uint8_t p3) "hashes 0x%x, table of %d, key of %d" +virtio_net_rss_load(void *nic, size_t nfds, void *fds) "nic=%p nfds=%zu fds=%p" +virtio_net_rss_attach_ebpf(void *nic, int prog_fd) "nic=%p prog-fd=%d" +virtio_net_rss_disable(void *nic) "nic=%p" +virtio_net_rss_error(void *nic, const char *msg, uint32_t value) "nic=%p msg=%s, value 0x%08x" +virtio_net_rss_enable(void *nic, uint32_t p1, uint16_t p2, uint8_t p3) "nic=%p hashes 0x%x, table of %d, key of %d" # tulip.c tulip_reg_write(uint64_t addr, const char *name, int size, uint64_t val) "addr 0x%02"PRIx64" (%s) size %d value 0x%08"PRIx64 diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index c08ae55424..60e19bffcb 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1241,6 +1241,7 @@ static bool virtio_net_attach_ebpf_to_backend(NICState *nic, int prog_fd) return false; } + trace_virtio_net_rss_attach_ebpf(nic, prog_fd); return nc->info->set_steering_ebpf(nc, prog_fd); } @@ -1297,12 +1298,13 @@ static void virtio_net_commit_rss_config(VirtIONet *n) } } - trace_virtio_net_rss_enable(n->rss_data.hash_types, + trace_virtio_net_rss_enable(n, + n->rss_data.hash_types, n->rss_data.indirections_len, sizeof(n->rss_data.key)); } else { virtio_net_detach_ebpf_rss(n); - trace_virtio_net_rss_disable(); + trace_virtio_net_rss_disable(n); } } @@ -1353,6 +1355,7 @@ static bool virtio_net_load_ebpf(VirtIONet *n, Error **errp) bool ret = false; if (virtio_net_attach_ebpf_to_backend(n->nic, -1)) { + trace_virtio_net_rss_load(n, n->nr_ebpf_rss_fds, n->ebpf_rss_fds); if (n->ebpf_rss_fds) { ret = virtio_net_load_ebpf_fds(n, errp); } else { @@ -1484,7 +1487,7 @@ static uint16_t virtio_net_handle_rss(VirtIONet *n, virtio_net_commit_rss_config(n); return queue_pairs; error: - trace_virtio_net_rss_error(err_msg, err_value); + trace_virtio_net_rss_error(n, err_msg, err_value); virtio_net_disable_rss(n); return 0; } -- cgit 1.4.1 From cd76e8fcbe1a340776ae61b4e182be3a45b26219 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 8 Oct 2024 15:51:03 +0900 Subject: virtio-net: Avoid indirection_table_mask overflow We computes indirections_len by adding 1 to indirection_table_mask, but it may overflow indirection_table_mask is UINT16_MAX. Check if indirection_table_mask is small enough before adding 1. Fixes: 590790297c0d ("virtio-net: implement RSS configuration command") Signed-off-by: Akihiko Odaki Signed-off-by: Jason Wang --- hw/net/virtio-net.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'hw/net/virtio-net.c') diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 60e19bffcb..f2104ed364 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1406,17 +1406,17 @@ static uint16_t virtio_net_handle_rss(VirtIONet *n, n->rss_data.hash_types = virtio_ldl_p(vdev, &cfg.hash_types); n->rss_data.indirections_len = virtio_lduw_p(vdev, &cfg.indirection_table_mask); - n->rss_data.indirections_len++; if (!do_rss) { - n->rss_data.indirections_len = 1; + n->rss_data.indirections_len = 0; } - if (!is_power_of_2(n->rss_data.indirections_len)) { - err_msg = "Invalid size of indirection table"; + if (n->rss_data.indirections_len >= VIRTIO_NET_RSS_MAX_TABLE_LEN) { + err_msg = "Too large indirection table"; err_value = n->rss_data.indirections_len; goto error; } - if (n->rss_data.indirections_len > VIRTIO_NET_RSS_MAX_TABLE_LEN) { - err_msg = "Too large indirection table"; + n->rss_data.indirections_len++; + if (!is_power_of_2(n->rss_data.indirections_len)) { + err_msg = "Invalid size of indirection table"; err_value = n->rss_data.indirections_len; goto error; } -- cgit 1.4.1