On Tue, Oct 17, 2023 at 7:10 AM Akihiko Odaki <akihiko.od...@daynix.com> wrote:
> vhost requires eBPF for RSS. Even when eBPF is not available, virtio-net > reported RSS availability, and raised a warning only after the > guest requested RSS, and the guest could not know that RSS is not > available. > > The existing code suggests the RSS feature for vhost case only when the ebpf is loaded. https://github.com/qemu/qemu/blob/master/hw/net/virtio-net.c#L828 Am I wrong? > Check RSS availability during device realization and return an error > if RSS is requested but not available. Assert RSS availability when > the guest actually requests the feature. > > Signed-off-by: Akihiko Odaki <akihiko.od...@daynix.com> > --- > ebpf/ebpf_rss.h | 2 +- > ebpf/ebpf_rss-stub.c | 4 +- > ebpf/ebpf_rss.c | 68 +++++++++----------------- > hw/net/virtio-net.c | 114 +++++++++++++++++++++---------------------- > 4 files changed, 82 insertions(+), 106 deletions(-) > > diff --git a/ebpf/ebpf_rss.h b/ebpf/ebpf_rss.h > index bf3f2572c7..1128173572 100644 > --- a/ebpf/ebpf_rss.h > +++ b/ebpf/ebpf_rss.h > @@ -36,7 +36,7 @@ bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx); > > bool ebpf_rss_load(struct EBPFRSSContext *ctx); > > -bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig > *config, > +void ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig > *config, > uint16_t *indirections_table, uint8_t > *toeplitz_key); > > void ebpf_rss_unload(struct EBPFRSSContext *ctx); > diff --git a/ebpf/ebpf_rss-stub.c b/ebpf/ebpf_rss-stub.c > index e71e229190..525b358597 100644 > --- a/ebpf/ebpf_rss-stub.c > +++ b/ebpf/ebpf_rss-stub.c > @@ -28,10 +28,10 @@ bool ebpf_rss_load(struct EBPFRSSContext *ctx) > return false; > } > > -bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig > *config, > +void ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig > *config, > uint16_t *indirections_table, uint8_t *toeplitz_key) > { > - return false; > + g_assert_not_reached(); > } > > void ebpf_rss_unload(struct EBPFRSSContext *ctx) > diff --git a/ebpf/ebpf_rss.c b/ebpf/ebpf_rss.c > index cee658c158..6cdf82d059 100644 > --- a/ebpf/ebpf_rss.c > +++ b/ebpf/ebpf_rss.c > @@ -74,42 +74,32 @@ error: > return false; > } > > -static bool ebpf_rss_set_config(struct EBPFRSSContext *ctx, > +static void ebpf_rss_set_config(struct EBPFRSSContext *ctx, > struct EBPFRSSConfig *config) > { > uint32_t map_key = 0; > > - if (!ebpf_rss_is_loaded(ctx)) { > - return false; > - } > - if (bpf_map_update_elem(ctx->map_configuration, > - &map_key, config, 0) < 0) { > - return false; > - } > - return true; > + assert(ebpf_rss_is_loaded(ctx)); > + assert(!bpf_map_update_elem(ctx->map_configuration, &map_key, config, > 0)); > } > > -static bool ebpf_rss_set_indirections_table(struct EBPFRSSContext *ctx, > +static void ebpf_rss_set_indirections_table(struct EBPFRSSContext *ctx, > uint16_t *indirections_table, > size_t len) > { > uint32_t i = 0; > > - if (!ebpf_rss_is_loaded(ctx) || indirections_table == NULL || > - len > VIRTIO_NET_RSS_MAX_TABLE_LEN) { > - return false; > - } > + assert(ebpf_rss_is_loaded(ctx)); > + assert(indirections_table); > + assert(len <= VIRTIO_NET_RSS_MAX_TABLE_LEN); > > for (; i < len; ++i) { > - if (bpf_map_update_elem(ctx->map_indirections_table, &i, > - indirections_table + i, 0) < 0) { > - return false; > - } > + assert(!bpf_map_update_elem(ctx->map_indirections_table, &i, > + indirections_table + i, 0)); > } > - return true; > } > > -static bool ebpf_rss_set_toepliz_key(struct EBPFRSSContext *ctx, > +static void ebpf_rss_set_toepliz_key(struct EBPFRSSContext *ctx, > uint8_t *toeplitz_key) > { > uint32_t map_key = 0; > @@ -117,41 +107,29 @@ static bool ebpf_rss_set_toepliz_key(struct > EBPFRSSContext *ctx, > /* prepare toeplitz key */ > uint8_t toe[VIRTIO_NET_RSS_MAX_KEY_SIZE] = {}; > > - if (!ebpf_rss_is_loaded(ctx) || toeplitz_key == NULL) { > - return false; > - } > + assert(ebpf_rss_is_loaded(ctx)); > + assert(toeplitz_key); > + > memcpy(toe, toeplitz_key, VIRTIO_NET_RSS_MAX_KEY_SIZE); > *(uint32_t *)toe = ntohl(*(uint32_t *)toe); > > - if (bpf_map_update_elem(ctx->map_toeplitz_key, &map_key, toe, > - 0) < 0) { > - return false; > - } > - return true; > + assert(!bpf_map_update_elem(ctx->map_toeplitz_key, &map_key, toe, 0)); > } > > -bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig > *config, > +void ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig > *config, > uint16_t *indirections_table, uint8_t *toeplitz_key) > { > - if (!ebpf_rss_is_loaded(ctx) || config == NULL || > - indirections_table == NULL || toeplitz_key == NULL) { > - return false; > - } > - > - if (!ebpf_rss_set_config(ctx, config)) { > - return false; > - } > + assert(ebpf_rss_is_loaded(ctx)); > + assert(config); > + assert(indirections_table); > + assert(toeplitz_key); > > - if (!ebpf_rss_set_indirections_table(ctx, indirections_table, > - config->indirections_len)) { > - return false; > - } > + ebpf_rss_set_config(ctx, config); > > - if (!ebpf_rss_set_toepliz_key(ctx, toeplitz_key)) { > - return false; > - } > + ebpf_rss_set_indirections_table(ctx, indirections_table, > + config->indirections_len); > > - return true; > + ebpf_rss_set_toepliz_key(ctx, toeplitz_key); > } > > void ebpf_rss_unload(struct EBPFRSSContext *ctx) > diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c > index 25fc06bd93..20feb20bb1 100644 > --- a/hw/net/virtio-net.c > +++ b/hw/net/virtio-net.c > @@ -1242,14 +1242,10 @@ static bool virtio_net_attach_epbf_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)) { > - return false; > - } > + ebpf_rss_set_all(&n->ebpf_rss, &config, > + n->rss_data.indirections_table, n->rss_data.key); > > - if (!virtio_net_attach_ebpf_to_backend(n->nic, > n->ebpf_rss.program_fd)) { > - return false; > - } > + assert(virtio_net_attach_ebpf_to_backend(n->nic, > n->ebpf_rss.program_fd)); > > return true; > } > @@ -1266,12 +1262,7 @@ static void virtio_net_commit_rss_config(VirtIONet > *n) > if (n->rss_data.populate_hash) { > virtio_net_detach_epbf_rss(n); > } else if (!virtio_net_attach_epbf_rss(n)) { > - if (get_vhost_net(qemu_get_queue(n->nic)->peer)) { > - warn_report("Can't use eBPF RSS for vhost"); > - } else { > - warn_report("Can't use eBPF RSS - fallback to software > RSS"); > - n->rss_data.enabled_software_rss = true; > - } > + n->rss_data.enabled_software_rss = true; > } > > trace_virtio_net_rss_enable(n->rss_data.hash_types, > @@ -3514,6 +3505,50 @@ static bool > failover_hide_primary_device(DeviceListener *listener, > return qatomic_read(&n->failover_primary_hidden); > } > > +static void virtio_net_device_unrealize(DeviceState *dev) > +{ > + VirtIODevice *vdev = VIRTIO_DEVICE(dev); > + VirtIONet *n = VIRTIO_NET(dev); > + int i, max_queue_pairs; > + > + if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) { > + virtio_net_unload_ebpf(n); > + } > + > + /* This will stop vhost backend if appropriate. */ > + virtio_net_set_status(vdev, 0); > + > + g_free(n->netclient_name); > + n->netclient_name = NULL; > + g_free(n->netclient_type); > + n->netclient_type = NULL; > + > + g_free(n->mac_table.macs); > + g_free(n->vlans); > + > + if (n->failover) { > + qobject_unref(n->primary_opts); > + device_listener_unregister(&n->primary_listener); > + remove_migration_state_change_notifier(&n->migration_state); > + } else { > + assert(n->primary_opts == NULL); > + } > + > + max_queue_pairs = n->multiqueue ? n->max_queue_pairs : 1; > + for (i = 0; i < max_queue_pairs; i++) { > + virtio_net_del_queue(n, i); > + } > + /* delete also control vq */ > + virtio_del_queue(vdev, max_queue_pairs * 2); > + qemu_announce_timer_del(&n->announce_timer, false); > + g_free(n->vqs); > + qemu_del_nic(n->nic); > + virtio_net_rsc_cleanup(n); > + g_free(n->rss_data.indirections_table); > + net_rx_pkt_uninit(n->rx_pkt); > + virtio_cleanup(vdev); > +} > + > static void virtio_net_device_realize(DeviceState *dev, Error **errp) > { > VirtIODevice *vdev = VIRTIO_DEVICE(dev); > @@ -3685,53 +3720,16 @@ 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); > - } > -} > - > -static void virtio_net_device_unrealize(DeviceState *dev) > -{ > - VirtIODevice *vdev = VIRTIO_DEVICE(dev); > - VirtIONet *n = VIRTIO_NET(dev); > - int i, max_queue_pairs; > - > - if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) { > - virtio_net_unload_ebpf(n); > - } > - > - /* This will stop vhost backend if appropriate. */ > - virtio_net_set_status(vdev, 0); > - > - g_free(n->netclient_name); > - n->netclient_name = NULL; > - g_free(n->netclient_type); > - n->netclient_type = NULL; > - > - g_free(n->mac_table.macs); > - g_free(n->vlans); > - > - if (n->failover) { > - qobject_unref(n->primary_opts); > - device_listener_unregister(&n->primary_listener); > - remove_migration_state_change_notifier(&n->migration_state); > - } else { > - assert(n->primary_opts == NULL); > - } > + if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS) && > + !virtio_net_load_ebpf(n)) { > + if (get_vhost_net(nc->peer)) { > + error_setg(errp, "Can't load eBPF RSS for vhost"); > + virtio_net_device_unrealize(dev); > + return; > + } > > - max_queue_pairs = n->multiqueue ? n->max_queue_pairs : 1; > - for (i = 0; i < max_queue_pairs; i++) { > - virtio_net_del_queue(n, i); > + warn_report_once("Can't load eBPF RSS - fallback to software > RSS"); > } > - /* delete also control vq */ > - virtio_del_queue(vdev, max_queue_pairs * 2); > - qemu_announce_timer_del(&n->announce_timer, false); > - g_free(n->vqs); > - qemu_del_nic(n->nic); > - virtio_net_rsc_cleanup(n); > - g_free(n->rss_data.indirections_table); > - net_rx_pkt_uninit(n->rx_pkt); > - virtio_cleanup(vdev); > } > > static void virtio_net_reset(VirtIODevice *vdev) > -- > 2.42.0 > >