diff mbox series

[RFC,v2,3/3] virtio-net: implement missing_features_migrated callback

Message ID 20210322122452.369750-4-yuri.benditovich@daynix.com (mailing list archive)
State New, archived
Headers show
Series virtio-net: graceful drop of vhost for TAP | expand

Commit Message

Yuri Benditovich March 22, 2021, 12:24 p.m. UTC
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.benditovich@daynix.com>
---
 hw/net/virtio-net.c | 51 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)
diff mbox series

Patch

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;