aboutsummaryrefslogtreecommitdiff
path: root/hw/vhost_net.c
diff options
context:
space:
mode:
authorMichael S. Tsirkin <mst@redhat.com>2010-03-17 13:08:17 +0200
committerAnthony Liguori <aliguori@us.ibm.com>2010-04-01 13:56:43 -0500
commitd59700553ecbf052cce1e099e8f4dae2704fe424 (patch)
treef0f4d3afd94d374920b450ec14c18775762fcadb /hw/vhost_net.c
parentade80dc84527ae7418e9fcaf33e09574da0d2b29 (diff)
vhost: vhost net support
This adds vhost net device support in qemu. Will be tied to tap device and virtio by following patches. Raw backend is currently missing, will be worked on/submitted separately. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'hw/vhost_net.c')
-rw-r--r--hw/vhost_net.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/hw/vhost_net.c b/hw/vhost_net.c
new file mode 100644
index 0000000000..39643f1e99
--- /dev/null
+++ b/hw/vhost_net.c
@@ -0,0 +1,195 @@
+/*
+ * vhost-net support
+ *
+ * Copyright Red Hat, Inc. 2010
+ *
+ * Authors:
+ * Michael S. Tsirkin <mst@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "net.h"
+#include "net/tap.h"
+
+#include "virtio-net.h"
+#include "vhost_net.h"
+
+#include "config.h"
+
+#ifdef CONFIG_VHOST_NET
+#include <linux/vhost.h>
+#include <sys/eventfd.h>
+#include <sys/socket.h>
+#include <linux/kvm.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/virtio_ring.h>
+#include <netpacket/packet.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+
+#include "vhost.h"
+
+struct vhost_net {
+ struct vhost_dev dev;
+ struct vhost_virtqueue vqs[2];
+ int backend;
+ VLANClientState *vc;
+};
+
+unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
+{
+ /* Clear features not supported by host kernel. */
+ if (!(net->dev.features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY))) {
+ features &= ~(1 << VIRTIO_F_NOTIFY_ON_EMPTY);
+ }
+ if (!(net->dev.features & (1 << VIRTIO_RING_F_INDIRECT_DESC))) {
+ features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC);
+ }
+ return features;
+}
+
+void vhost_net_ack_features(struct vhost_net *net, unsigned features)
+{
+ net->dev.acked_features = net->dev.backend_features;
+ if (features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) {
+ net->dev.acked_features |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
+ }
+ if (features & (1 << VIRTIO_RING_F_INDIRECT_DESC)) {
+ net->dev.acked_features |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
+ }
+}
+
+static int vhost_net_get_fd(VLANClientState *backend)
+{
+ switch (backend->info->type) {
+ case NET_CLIENT_TYPE_TAP:
+ return tap_get_fd(backend);
+ default:
+ fprintf(stderr, "vhost-net requires tap backend\n");
+ return -EBADFD;
+ }
+}
+
+struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd)
+{
+ int r;
+ struct vhost_net *net = qemu_malloc(sizeof *net);
+ if (!backend) {
+ fprintf(stderr, "vhost-net requires backend to be setup\n");
+ goto fail;
+ }
+ r = vhost_net_get_fd(backend);
+ if (r < 0) {
+ goto fail;
+ }
+ net->vc = backend;
+ net->dev.backend_features = tap_has_vnet_hdr(backend) ? 0 :
+ (1 << VHOST_NET_F_VIRTIO_NET_HDR);
+ net->backend = r;
+
+ r = vhost_dev_init(&net->dev, devfd);
+ if (r < 0) {
+ goto fail;
+ }
+ if (~net->dev.features & net->dev.backend_features) {
+ fprintf(stderr, "vhost lacks feature mask %llu for backend\n",
+ ~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);
+ return net;
+fail:
+ qemu_free(net);
+ return NULL;
+}
+
+int vhost_net_start(struct vhost_net *net,
+ VirtIODevice *dev)
+{
+ struct vhost_vring_file file = { };
+ int r;
+
+ net->dev.nvqs = 2;
+ net->dev.vqs = net->vqs;
+ r = vhost_dev_start(&net->dev, dev);
+ if (r < 0) {
+ return r;
+ }
+
+ net->vc->info->poll(net->vc, false);
+ qemu_set_fd_handler(net->backend, NULL, NULL, NULL);
+ file.fd = net->backend;
+ for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
+ r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
+ if (r < 0) {
+ r = -errno;
+ goto fail;
+ }
+ }
+ return 0;
+fail:
+ file.fd = -1;
+ while (--file.index >= 0) {
+ int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
+ assert(r >= 0);
+ }
+ net->vc->info->poll(net->vc, true);
+ vhost_dev_stop(&net->dev, dev);
+ return r;
+}
+
+void vhost_net_stop(struct vhost_net *net,
+ VirtIODevice *dev)
+{
+ struct vhost_vring_file file = { .fd = -1 };
+
+ for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
+ int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
+ assert(r >= 0);
+ }
+ net->vc->info->poll(net->vc, true);
+ vhost_dev_stop(&net->dev, dev);
+}
+
+void vhost_net_cleanup(struct vhost_net *net)
+{
+ vhost_dev_cleanup(&net->dev);
+ qemu_free(net);
+}
+#else
+struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd)
+{
+ return NULL;
+}
+
+int vhost_net_start(struct vhost_net *net,
+ VirtIODevice *dev)
+{
+ return -ENOSYS;
+}
+void vhost_net_stop(struct vhost_net *net,
+ VirtIODevice *dev)
+{
+}
+
+void vhost_net_cleanup(struct vhost_net *net)
+{
+}
+
+unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
+{
+ return features;
+}
+void vhost_net_ack_features(struct vhost_net *net, unsigned features)
+{
+}
+#endif