Graceful drop to userspace virtio in case selected features are missing on the destination system. Currently used for 3 features that might be supported by the vhost kernel on the source machine and not supported on the destination machine: rss, hash reporting, packed ring.
Signed-off-by: Yuri Benditovich <yuri.benditov...@daynix.com> --- hw/net/virtio-net.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 96a3cc8357..97afca34e7 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -527,6 +527,15 @@ static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc) return info; } +static void virtio_net_allow_vhost(VirtIONet *n, bool allow) +{ + int i; + for (i = 0; i < n->max_queues; i++) { + NetClientState *nc = qemu_get_subqueue(n->nic, i)->peer; + nc->vhost_net_disabled = !allow; + } +} + static void virtio_net_reset(VirtIODevice *vdev) { VirtIONet *n = VIRTIO_NET(vdev); @@ -564,6 +573,7 @@ static void virtio_net_reset(VirtIODevice *vdev) assert(!virtio_net_get_subqueue(nc)->async_tx.elem); } } + virtio_net_allow_vhost(n, true); } static void peer_test_vnet_hdr(VirtIONet *n) @@ -701,6 +711,27 @@ static void virtio_net_set_queues(VirtIONet *n) } } +static bool can_disable_vhost(VirtIONet *n) +{ + NetClientState *peer = qemu_get_queue(n->nic)->peer; + NetdevInfo *ndi; + if (!get_vhost_net(peer)) { + return false; + } + if (!peer) { + return true; + } + if (peer->info->type != NET_CLIENT_DRIVER_TAP) { + return false; + } + ndi = peer->stored_config; + if (ndi && ndi->u.tap.has_vhostforce && ndi->u.tap.vhostforce) { + printf("vhost forced, can't drop it\n"); + return false; + } + return true; +} + static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue); static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features, @@ -3433,6 +3464,25 @@ static bool dev_unplug_pending(void *opaque) return vdc->primary_unplug_pending(dev); } +static bool virtio_net_missing_features_migrated(VirtIODevice *vdev, + uint64_t missing) +{ + VirtIONet *n = VIRTIO_NET(vdev); + bool disable_vhost = false; + if (virtio_has_feature(missing, VIRTIO_NET_F_HASH_REPORT) || + virtio_has_feature(missing, VIRTIO_NET_F_RSS) || + virtio_has_feature(missing, VIRTIO_F_RING_PACKED)) { + disable_vhost = true; + } + disable_vhost = disable_vhost && can_disable_vhost(n); + if (disable_vhost) { + warn_report("falling back to userspace virtio due to missing" + " features %lx", missing); + virtio_net_allow_vhost(n, false); + } + return disable_vhost; +} + static const VMStateDescription vmstate_virtio_net = { .name = "virtio-net", .minimum_version_id = VIRTIO_NET_VM_VERSION, @@ -3527,6 +3577,7 @@ static void virtio_net_class_init(ObjectClass *klass, void *data) vdc->get_features = virtio_net_get_features; vdc->set_features = virtio_net_set_features; vdc->bad_features = virtio_net_bad_features; + vdc->missing_features_migrated = virtio_net_missing_features_migrated; vdc->reset = virtio_net_reset; vdc->set_status = virtio_net_set_status; vdc->guest_notifier_mask = virtio_net_guest_notifier_mask; -- 2.26.2