]> Git Repo - qemu.git/blobdiff - hw/net/vhost_net.c
Include qemu/main-loop.h less
[qemu.git] / hw / net / vhost_net.c
index 318c3e6ad2132a883d9d506137d25af1f5b0a829..e975700f9515f52587e3464ff3dc89b258afd18f 100644 (file)
  * GNU GPL, version 2 or (at your option) any later version.
  */
 
+#include "qemu/osdep.h"
 #include "net/net.h"
 #include "net/tap.h"
 #include "net/vhost-user.h"
 
+#include "standard-headers/linux/vhost_types.h"
 #include "hw/virtio/virtio-net.h"
 #include "net/vhost_net.h"
 #include "qemu/error-report.h"
+#include "qemu/main-loop.h"
 
-#include "config.h"
-
-#ifdef CONFIG_VHOST_NET
-#include <linux/vhost.h>
 #include <sys/socket.h>
-#include <linux/kvm.h>
-#include <fcntl.h>
-#include <netpacket/packet.h>
-#include <net/ethernet.h>
 #include <net/if.h>
 #include <netinet/in.h>
 
-#include <stdio.h>
 
 #include "standard-headers/linux/virtio_ring.h"
 #include "hw/virtio/vhost.h"
 #include "hw/virtio/virtio-bus.h"
-#include "hw/virtio/virtio-access.h"
 
 struct vhost_net {
     struct vhost_dev dev;
@@ -54,6 +47,8 @@ static const int kernel_feature_bits[] = {
     VIRTIO_RING_F_EVENT_IDX,
     VIRTIO_NET_F_MRG_RXBUF,
     VIRTIO_F_VERSION_1,
+    VIRTIO_NET_F_MTU,
+    VIRTIO_F_IOMMU_PLATFORM,
     VHOST_INVALID_FEATURE_BIT
 };
 
@@ -77,6 +72,8 @@ static const int user_feature_bits[] = {
     VIRTIO_NET_F_HOST_ECN,
     VIRTIO_NET_F_HOST_UFO,
     VIRTIO_NET_F_MRG_RXBUF,
+    VIRTIO_NET_F_MTU,
+    VIRTIO_F_IOMMU_PLATFORM,
 
     /* This bit implies RARP isn't sent by QEMU out of band */
     VIRTIO_NET_F_GUEST_ANNOUNCE,
@@ -91,10 +88,10 @@ static const int *vhost_net_get_feature_bits(struct vhost_net *net)
     const int *feature_bits = 0;
 
     switch (net->nc->info->type) {
-    case NET_CLIENT_OPTIONS_KIND_TAP:
+    case NET_CLIENT_DRIVER_TAP:
         feature_bits = kernel_feature_bits;
         break;
-    case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
+    case NET_CLIENT_DRIVER_VHOST_USER:
         feature_bits = user_feature_bits;
         break;
     default:
@@ -123,14 +120,19 @@ uint64_t vhost_net_get_max_queues(VHostNetState *net)
     return net->dev.max_queues;
 }
 
+uint64_t vhost_net_get_acked_features(VHostNetState *net)
+{
+    return net->dev.acked_features;
+}
+
 static int vhost_net_get_fd(NetClientState *backend)
 {
     switch (backend->info->type) {
-    case NET_CLIENT_OPTIONS_KIND_TAP:
+    case NET_CLIENT_DRIVER_TAP:
         return tap_get_fd(backend);
     default:
         fprintf(stderr, "vhost-net requires tap backend\n");
-        return -EBADFD;
+        return -ENOSYS;
     }
 }
 
@@ -138,7 +140,8 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
 {
     int r;
     bool backend_kernel = options->backend_type == VHOST_BACKEND_TYPE_KERNEL;
-    struct vhost_net *net = g_malloc(sizeof *net);
+    struct vhost_net *net = g_new0(struct vhost_net, 1);
+    uint64_t features = 0;
 
     if (!options->net_backend) {
         fprintf(stderr, "vhost-net requires net backend to be setup\n");
@@ -169,7 +172,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
     }
 
     r = vhost_dev_init(&net->dev, options->opaque,
-                       options->backend_type);
+                       options->backend_type, options->busyloop_timeout);
     if (r < 0) {
         goto fail;
     }
@@ -182,14 +185,29 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
             fprintf(stderr, "vhost lacks feature mask %" PRIu64
                    " for backend\n",
                    (uint64_t)(~net->dev.features & net->dev.backend_features));
-            vhost_dev_cleanup(&net->dev);
             goto fail;
         }
     }
+
     /* Set sane init value. Override when guest acks. */
-    vhost_net_ack_features(net, 0);
+#ifdef CONFIG_VHOST_NET_USER
+    if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
+        features = vhost_user_get_acked_features(net->nc);
+        if (~net->dev.features & features) {
+            fprintf(stderr, "vhost lacks feature mask %" PRIu64
+                    " for backend\n",
+                    (uint64_t)(~net->dev.features & features));
+            goto fail;
+        }
+    }
+#endif
+
+    vhost_net_ack_features(net, features);
+
     return net;
+
 fail:
+    vhost_dev_cleanup(&net->dev);
     g_free(net);
     return NULL;
 }
@@ -199,27 +217,6 @@ static void vhost_net_set_vq_index(struct vhost_net *net, int vq_index)
     net->dev.vq_index = vq_index;
 }
 
-static int vhost_net_set_vnet_endian(VirtIODevice *dev, NetClientState *peer,
-                                     bool set)
-{
-    int r = 0;
-
-    if (virtio_vdev_has_feature(dev, VIRTIO_F_VERSION_1) ||
-        (virtio_legacy_is_cross_endian(dev) && !virtio_is_big_endian(dev))) {
-        r = qemu_set_vnet_le(peer, set);
-        if (r) {
-            error_report("backend does not support LE vnet headers");
-        }
-    } else if (virtio_legacy_is_cross_endian(dev)) {
-        r = qemu_set_vnet_be(peer, set);
-        if (r) {
-            error_report("backend does not support BE vnet headers");
-        }
-    }
-
-    return r;
-}
-
 static int vhost_net_start_one(struct vhost_net *net,
                                VirtIODevice *dev)
 {
@@ -243,12 +240,16 @@ static int vhost_net_start_one(struct vhost_net *net,
         net->nc->info->poll(net->nc, false);
     }
 
-    if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) {
+    if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
         qemu_set_fd_handler(net->backend, NULL, NULL, NULL);
         file.fd = net->backend;
         for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
-            const VhostOps *vhost_ops = net->dev.vhost_ops;
-            r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
+            if (!virtio_queue_enabled(dev, net->dev.vq_index +
+                                      file.index)) {
+                /* Queue might not be ready for start */
+                continue;
+            }
+            r = vhost_net_set_backend(&net->dev, &file);
             if (r < 0) {
                 r = -errno;
                 goto fail;
@@ -258,10 +259,14 @@ static int vhost_net_start_one(struct vhost_net *net,
     return 0;
 fail:
     file.fd = -1;
-    if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) {
+    if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
         while (file.index-- > 0) {
-            const VhostOps *vhost_ops = net->dev.vhost_ops;
-            int r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
+            if (!virtio_queue_enabled(dev, net->dev.vq_index +
+                                      file.index)) {
+                /* Queue might not be ready for start */
+                continue;
+            }
+            int r = vhost_net_set_backend(&net->dev, &file);
             assert(r >= 0);
         }
     }
@@ -280,10 +285,9 @@ static void vhost_net_stop_one(struct vhost_net *net,
 {
     struct vhost_vring_file file = { .fd = -1 };
 
-    if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) {
+    if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
         for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
-            const VhostOps *vhost_ops = net->dev.vhost_ops;
-            int r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
+            int r = vhost_net_set_backend(&net->dev, &file);
             assert(r >= 0);
         }
     }
@@ -304,23 +308,28 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
 
     if (!k->set_guest_notifiers) {
         error_report("binding does not support guest notifiers");
-        r = -ENOSYS;
-        goto err;
-    }
-
-    r = vhost_net_set_vnet_endian(dev, ncs[0].peer, true);
-    if (r < 0) {
-        goto err;
+        return -ENOSYS;
     }
 
     for (i = 0; i < total_queues; i++) {
-        vhost_net_set_vq_index(get_vhost_net(ncs[i].peer), i * 2);
-    }
+        struct vhost_net *net;
+
+        net = get_vhost_net(ncs[i].peer);
+        vhost_net_set_vq_index(net, i * 2);
+
+        /* Suppress the masking guest notifiers on vhost user
+         * because vhost user doesn't interrupt masking/unmasking
+         * properly.
+         */
+        if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
+            dev->use_guest_notifier_mask = false;
+        }
+     }
 
     r = k->set_guest_notifiers(qbus->parent, total_queues * 2, true);
     if (r < 0) {
         error_report("Error binding guest notifier: %d", -r);
-        goto err_endian;
+        goto err;
     }
 
     for (i = 0; i < total_queues; i++) {
@@ -329,6 +338,15 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
         if (r < 0) {
             goto err_start;
         }
+
+        if (ncs[i].peer->vring_enable) {
+            /* restore vring enable state */
+            r = vhost_set_vring_enable(ncs[i].peer, ncs[i].peer->vring_enable);
+
+            if (r < 0) {
+                goto err_start;
+            }
+        }
     }
 
     return 0;
@@ -342,8 +360,6 @@ err_start:
         fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", e);
         fflush(stderr);
     }
-err_endian:
-    vhost_net_set_vnet_endian(dev, ncs[0].peer, false);
 err:
     return r;
 }
@@ -366,26 +382,21 @@ void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
         fflush(stderr);
     }
     assert(r >= 0);
-
-    assert(vhost_net_set_vnet_endian(dev, ncs[0].peer, false) >= 0);
 }
 
 void vhost_net_cleanup(struct vhost_net *net)
 {
     vhost_dev_cleanup(&net->dev);
-    g_free(net);
 }
 
 int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr)
 {
     const VhostOps *vhost_ops = net->dev.vhost_ops;
-    int r = -1;
 
-    if (vhost_ops->vhost_migration_done) {
-        r = vhost_ops->vhost_migration_done(&net->dev, mac_addr);
-    }
+    assert(vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
+    assert(vhost_ops->vhost_migration_done);
 
-    return r;
+    return vhost_ops->vhost_migration_done(&net->dev, mac_addr);
 }
 
 bool vhost_net_virtqueue_pending(VHostNetState *net, int idx)
@@ -408,12 +419,15 @@ VHostNetState *get_vhost_net(NetClientState *nc)
     }
 
     switch (nc->info->type) {
-    case NET_CLIENT_OPTIONS_KIND_TAP:
+    case NET_CLIENT_DRIVER_TAP:
         vhost_net = tap_get_vhost_net(nc);
         break;
-    case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
+#ifdef CONFIG_VHOST_NET_USER
+    case NET_CLIENT_DRIVER_VHOST_USER:
         vhost_net = vhost_user_get_vhost_net(nc);
+        assert(vhost_net);
         break;
+#endif
     default:
         break;
     }
@@ -426,71 +440,22 @@ int vhost_set_vring_enable(NetClientState *nc, int enable)
     VHostNetState *net = get_vhost_net(nc);
     const VhostOps *vhost_ops = net->dev.vhost_ops;
 
-    if (vhost_ops->vhost_set_vring_enable) {
+    nc->vring_enable = enable;
+
+    if (vhost_ops && vhost_ops->vhost_set_vring_enable) {
         return vhost_ops->vhost_set_vring_enable(&net->dev, enable);
     }
 
     return 0;
 }
 
-#else
-uint64_t vhost_net_get_max_queues(VHostNetState *net)
+int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu)
 {
-    return 1;
-}
-
-struct vhost_net *vhost_net_init(VhostNetOptions *options)
-{
-    error_report("vhost-net support is not compiled in");
-    return NULL;
-}
-
-int vhost_net_start(VirtIODevice *dev,
-                    NetClientState *ncs,
-                    int total_queues)
-{
-    return -ENOSYS;
-}
-void vhost_net_stop(VirtIODevice *dev,
-                    NetClientState *ncs,
-                    int total_queues)
-{
-}
-
-void vhost_net_cleanup(struct vhost_net *net)
-{
-}
-
-uint64_t vhost_net_get_features(struct vhost_net *net, uint64_t features)
-{
-    return features;
-}
-void vhost_net_ack_features(struct vhost_net *net, uint64_t features)
-{
-}
-
-bool vhost_net_virtqueue_pending(VHostNetState *net, int idx)
-{
-    return false;
-}
-
-void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev,
-                              int idx, bool mask)
-{
-}
-
-int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr)
-{
-    return -1;
-}
+    const VhostOps *vhost_ops = net->dev.vhost_ops;
 
-VHostNetState *get_vhost_net(NetClientState *nc)
-{
-    return 0;
-}
+    if (!vhost_ops->vhost_net_set_mtu) {
+        return 0;
+    }
 
-int vhost_set_vring_enable(NetClientState *nc, int enable)
-{
-    return 0;
+    return vhost_ops->vhost_net_set_mtu(&net->dev, mtu);
 }
-#endif
This page took 0.033869 seconds and 4 git commands to generate.