From: "Michael S. Tsirkin" <mst@redhat.com>
To: Anthony Liguori <anthony@codemonkey.ws>, qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH-RFC 11/13] vhost net support
Date: Mon, 11 Jan 2010 19:23:32 +0200 [thread overview]
Message-ID: <20100111172332.GC12084@redhat.com> (raw)
In-Reply-To: <cover.1263230079.git.mst@redhat.com>
This adds vhost net support in qemu. Will be tied to tap device and
virtio later. Raw backend is currently missing, will be worked
on/submitted separately.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
Makefile.target | 1 +
hw/vhost.c | 349 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
hw/vhost.h | 33 +++++
hw/vhost_net.c | 145 +++++++++++++++++++++++
hw/vhost_net.h | 20 +++
5 files changed, 548 insertions(+), 0 deletions(-)
create mode 100644 hw/vhost.c
create mode 100644 hw/vhost.h
create mode 100644 hw/vhost_net.c
create mode 100644 hw/vhost_net.h
diff --git a/Makefile.target b/Makefile.target
index 7c1f30c..61b7148 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -157,6 +157,7 @@ obj-y = vl.o async.o monitor.o pci.o pci_host.o pcie_host.o machine.o gdbstub.o
# virtio has to be here due to weird dependency between PCI and virtio-net.
# need to fix this properly
obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o virtio-pci.o
+obj-y += vhost_net.o vhost.o
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
LIBS+=-lz
diff --git a/hw/vhost.c b/hw/vhost.c
new file mode 100644
index 0000000..d23d94c
--- /dev/null
+++ b/hw/vhost.c
@@ -0,0 +1,349 @@
+#include "linux/vhost.h"
+#include <sys/ioctl.h>
+#include <sys/eventfd.h>
+#include "vhost.h"
+#include "hw/hw.h"
+/* For range_get_last */
+#include "pci.h"
+
+static void vhost_dev_unassign_memory(struct vhost_dev *dev,
+ struct vhost_memory *mem,
+ uint64_t start_addr,
+ uint64_t size)
+{
+ int from, to;
+ for (from = 0, to = 0; from < dev->mem->nregions; ++from, ++to) {
+ struct vhost_memory_region *reg = mem->regions + to;
+ uint64_t reglast;
+ uint64_t memlast;
+ uint64_t change;
+
+ /* clone old region */
+ memcpy(reg, dev->mem->regions + from, sizeof *reg);
+
+ /* No overlap is simple */
+ if (!ranges_overlap(reg->guest_phys_addr, reg->memory_size,
+ start_addr, size)) {
+ continue;
+ }
+ reglast = range_get_last(reg->guest_phys_addr, reg->memory_size);
+ memlast = range_get_last(start_addr, size);
+
+ /* Remove whole region */
+ if (start_addr <= reg->guest_phys_addr && memlast >= reglast) {
+ --to;
+ continue;
+ }
+
+ /* Shrink region */
+ if (memlast >= reglast) {
+ reg->memory_size = start_addr - reg->guest_phys_addr;
+ continue;
+ }
+
+ /* Shift region */
+ if (start_addr <= reg->guest_phys_addr) {
+ change = memlast + 1 - reg->guest_phys_addr;
+ reg->memory_size -= change;
+ reg->guest_phys_addr += change;
+ reg->userspace_addr += change;
+ continue;
+ }
+
+ /* Split region: shrink first part, shift second part. */
+ memcpy(reg + 1, reg, sizeof *reg);
+ reg[0].memory_size = start_addr - reg->guest_phys_addr;
+ change = memlast + 1 - reg->guest_phys_addr;
+ reg[1].memory_size -= change;
+ reg[1].guest_phys_addr += change;
+ reg[1].userspace_addr += change;
+ ++to;
+ }
+ mem->nregions = to;
+}
+
+/* Called after unassign, so no regions overlap the given range. */
+static void vhost_dev_assign_memory(struct vhost_dev *dev,
+ struct vhost_memory *mem,
+ uint64_t start_addr,
+ uint64_t size,
+ uint64_t uaddr)
+{
+ int from, to;
+ struct vhost_memory_region *merged = NULL;
+ for (from = 0, to = 0; from < dev->mem->nregions; ++from, ++to) {
+ struct vhost_memory_region *reg = mem->regions + to;
+ uint64_t prlast, urlast;
+ uint64_t pmlast, umlast;
+ uint64_t s, e, u;
+
+ /* clone old region */
+ memcpy(reg, dev->mem->regions + from, sizeof *reg);
+ prlast = range_get_last(reg->guest_phys_addr, reg->memory_size);
+ pmlast = range_get_last(start_addr, size);
+ urlast = range_get_last(reg->userspace_addr, reg->memory_size);
+ umlast = range_get_last(uaddr, size);
+
+ /* Not an adjecent region - do not merge. */
+ if ((prlast + 1 != start_addr || urlast + 1 != uaddr) &&
+ (pmlast + 1 != reg->guest_phys_addr ||
+ umlast + 1 != reg->userspace_addr)) {
+ continue;
+ }
+
+ if (!merged) {
+ --to;
+ } else {
+ merged = reg;
+ }
+ u = MIN(uaddr, reg->userspace_addr);
+ s = MIN(start_addr, reg->guest_phys_addr);
+ e = MAX(pmlast, prlast);
+ uaddr = merged->userspace_addr = u;
+ start_addr = merged->guest_phys_addr = s;
+ size = merged->memory_size = e - s + 1;
+ }
+
+ if (!merged) {
+ struct vhost_memory_region *reg = mem->regions + to;
+ reg->memory_size = size;
+ reg->guest_phys_addr = start_addr;
+ reg->userspace_addr = uaddr;
+ ++to;
+ }
+ mem->nregions = to;
+}
+
+static void vhost_client_set_memory(CPUPhysMemoryClient *client,
+ target_phys_addr_t start_addr,
+ ram_addr_t size,
+ ram_addr_t phys_offset)
+{
+ struct vhost_dev *dev = container_of(client, struct vhost_dev, client);
+ ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
+ int s = offsetof(struct vhost_memory, regions) +
+ (dev->mem->nregions + 1)* sizeof dev->mem->regions[0];
+ struct vhost_memory *mem = qemu_malloc(s);
+ memcpy(mem, dev->mem, s);
+
+ /* First, remove old mapping for this memory, if any. */
+ vhost_dev_unassign_memory(dev, mem, start_addr, size);
+ if (flags == IO_MEM_RAM) {
+ /* Add given mapping, merging adjacent regions if any */
+ vhost_dev_assign_memory(dev, mem, start_addr, size,
+ (uintptr_t)qemu_get_ram_ptr(phys_offset));
+ }
+ qemu_free(dev->mem);
+ dev->mem = mem;
+}
+
+static int vhost_client_sync_dirty_bitmap(struct CPUPhysMemoryClient *client,
+ target_phys_addr_t start_addr,
+ target_phys_addr_t end_addr)
+{
+ /* TODO: migration */
+ return 0;
+}
+
+static int vhost_client_migration_log(struct CPUPhysMemoryClient *client,
+ int enable)
+{
+ /* TODO: migration */
+ return 0;
+}
+
+static int vhost_virtqueue_init(struct vhost_dev *dev,
+ struct VirtIODevice *vdev,
+ struct vhost_virtqueue *vq,
+ struct VirtQueue *q,
+ unsigned idx)
+{
+ target_phys_addr_t s, l;
+ int r;
+ struct vhost_vring_addr addr = {
+ .index = idx,
+ };
+ struct vhost_vring_file file = {
+ .index = idx,
+ };
+ struct vhost_vring_state size = {
+ .index = idx,
+ };
+
+ size.num = q->vring.num;
+ r = ioctl(dev->control, VHOST_SET_VRING_NUM, &size);
+ if (r) {
+ return -errno;
+ }
+
+ file.fd = vq->kick = eventfd(0, 0);
+ r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file);
+ if (r) {
+ return -errno;
+ }
+
+ file.fd = vq->call = eventfd(0, 0);
+ r = ioctl(dev->control, VHOST_SET_VRING_CALL, &file);
+ if (r) {
+ r = -errno;
+ goto fail_call;
+ }
+
+ s = l = sizeof(struct vring_desc) * q->vring.num;
+ vq->desc = cpu_physical_memory_map(q->vring.desc, &l, 0);
+ if (!vq->desc || l != s) {
+ r = -ENOMEM;
+ goto fail_alloc;
+ }
+ s = l = offsetof(struct vring_avail, ring) +
+ sizeof(u_int64_t) * q->vring.num;
+ vq->avail = cpu_physical_memory_map(q->vring.avail, &l, 0);
+ if (!vq->avail || l != s) {
+ r = -ENOMEM;
+ goto fail_alloc;
+ }
+ s = l = offsetof(struct vring_used, ring) +
+ sizeof(struct vring_used_elem) * q->vring.num;
+ vq->used = cpu_physical_memory_map(q->vring.used, &l, 1);
+ if (!vq->used || l != s) {
+ r = -ENOMEM;
+ goto fail_alloc;
+ }
+
+ addr.desc_user_addr = (u_int64_t)(unsigned long)vq->desc;
+ addr.avail_user_addr = (u_int64_t)(unsigned long)vq->avail;
+ addr.used_user_addr = (u_int64_t)(unsigned long)vq->used;
+ r = ioctl(dev->control, VHOST_SET_VRING_ADDR, &addr);
+ if (r < 0) {
+ r = -errno;
+ goto fail_alloc;
+ }
+ if (!vdev->binding->set_irqfd || !vdev->binding->set_queuefd) {
+ fprintf(stderr, "binding does not support irqfd/queuefd\n");
+ r = -ENOSYS;
+ goto fail_alloc;
+ }
+ r = vdev->binding->set_irqfd(vdev->binding_opaque, idx, vq->call, true);
+ if (r < 0) {
+ goto fail_alloc;
+ }
+
+ r = vdev->binding->set_queuefd(vdev->binding_opaque, idx, vq->kick, true);
+ if (r < 0) {
+ goto fail_queuefd;
+ }
+ return 0;
+
+fail_queuefd:
+ vdev->binding->set_irqfd(vdev->binding_opaque, idx, vq->call, false);
+fail_alloc:
+ close(vq->call);
+fail_call:
+ close(vq->kick);
+ return r;
+}
+
+static void vhost_virtqueue_cleanup(struct vhost_dev *dev,
+ struct VirtIODevice *vdev,
+ struct vhost_virtqueue *vq,
+ struct VirtQueue *q,
+ unsigned idx)
+{
+ int r;
+ r = vdev->binding->set_irqfd(vdev->binding_opaque, idx, vq->call, false);
+ if (r < 0) {
+ fprintf(stderr, "VQ cleanup failed: %d\n", r);
+ }
+
+ r = vdev->binding->set_queuefd(vdev->binding_opaque, idx, vq->kick, false);
+ if (r < 0) {
+ fprintf(stderr, "VQ cleanup failed: %d\n", r);
+ }
+}
+
+int vhost_dev_init(struct vhost_dev *hdev, int devfd)
+{
+ uint64_t features;
+ int r;
+ if (devfd >= 0) {
+ hdev->control = devfd;
+ } else {
+ hdev->control = open("/dev/vhost-net", O_RDWR);
+ if (hdev->control < 0)
+ return -errno;
+ }
+ r = ioctl(hdev->control, VHOST_SET_OWNER, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = ioctl(hdev->control, VHOST_GET_FEATURES, &features);
+ if (r < 0)
+ goto fail;
+ hdev->features = features;
+
+ hdev->client.set_memory = vhost_client_set_memory;
+ hdev->client.sync_dirty_bitmap = vhost_client_sync_dirty_bitmap;
+ hdev->client.migration_log = vhost_client_migration_log;
+ hdev->mem = qemu_mallocz(offsetof(struct vhost_memory, regions));
+ cpu_register_phys_memory_client(&hdev->client);
+ return 0;
+fail:
+ r = -errno;
+ close(hdev->control);
+ return r;
+}
+
+void vhost_dev_cleanup(struct vhost_dev *hdev)
+{
+ cpu_unregister_phys_memory_client(&hdev->client);
+ qemu_free(hdev->mem);
+ close(hdev->control);
+}
+
+int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
+{
+ int i, r;
+
+ r = ioctl(hdev->control, VHOST_SET_FEATURES, &hdev->acked_features);
+ if (r < 0)
+ goto fail;
+ r = ioctl(hdev->control, VHOST_SET_MEM_TABLE, hdev->mem);
+ if (r < 0)
+ goto fail;
+
+ for (i = 0; i < hdev->nvqs; ++i) {
+ r = vhost_virtqueue_init(hdev,
+ vdev,
+ hdev->vqs + i,
+ vdev->vq + i,
+ i);
+ if (r < 0)
+ goto fail_vq;
+ }
+
+ return 0;
+fail_vq:
+ while (--i >= 0) {
+ vhost_virtqueue_cleanup(hdev,
+ vdev,
+ hdev->vqs + i,
+ vdev->vq + i,
+ i);
+ }
+fail:
+ return r;
+}
+
+void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
+{
+ int i;
+
+ for (i = 0; i < hdev->nvqs; ++i) {
+ vhost_virtqueue_cleanup(hdev,
+ vdev,
+ hdev->vqs + i,
+ vdev->vq + i,
+ i);
+ }
+}
+
diff --git a/hw/vhost.h b/hw/vhost.h
new file mode 100644
index 0000000..9f82b42
--- /dev/null
+++ b/hw/vhost.h
@@ -0,0 +1,33 @@
+#ifndef VHOST_H
+#define VHOST_H
+
+#include "hw/hw.h"
+#include "hw/virtio.h"
+
+/* Generic structures common for any vhost based device. */
+struct vhost_virtqueue {
+ int kick;
+ int call;
+ void *desc;
+ void *avail;
+ void *used;
+};
+
+struct vhost_memory;
+struct vhost_dev {
+ CPUPhysMemoryClient client;
+ int control;
+ struct vhost_memory *mem;
+ struct vhost_virtqueue *vqs;
+ int nvqs;
+ unsigned long long features;
+ unsigned long long acked_features;
+ unsigned long long backend_features;
+};
+
+int vhost_dev_init(struct vhost_dev *hdev, int devfd);
+void vhost_dev_cleanup(struct vhost_dev *hdev);
+int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev);
+void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev);
+
+#endif
diff --git a/hw/vhost_net.c b/hw/vhost_net.c
new file mode 100644
index 0000000..e2c97c0
--- /dev/null
+++ b/hw/vhost_net.c
@@ -0,0 +1,145 @@
+#include <sys/eventfd.h>
+#include <sys/socket.h>
+#include <linux/kvm.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/vhost.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 "net.h"
+#include "net/tap.h"
+
+#include "virtio-net.h"
+#include "vhost.h"
+#include "vhost_net.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);
+ if (!(net->dev.features & (1 << VIRTIO_NET_F_MRG_RXBUF)))
+ features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
+ 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) {
+ ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
+ }
+ 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) {
+ ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
+ }
+ 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);
+}
+/* TODO: log */
diff --git a/hw/vhost_net.h b/hw/vhost_net.h
new file mode 100644
index 0000000..21f0277
--- /dev/null
+++ b/hw/vhost_net.h
@@ -0,0 +1,20 @@
+#ifndef VHOST_NET_H
+#define VHOST_NET_H
+
+#include "net.h"
+
+struct vhost_net;
+
+struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd);
+
+int vhost_net_start(struct vhost_net *net,
+ VirtIODevice *dev);
+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);
+void vhost_net_ack_features(struct vhost_net *net, unsigned features);
+
+#endif
--
1.6.6.rc1.43.gf55cc
next prev parent reply other threads:[~2010-01-11 17:26 UTC|newest]
Thread overview: 41+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <cover.1263230079.git.mst@redhat.com>
2010-01-11 17:16 ` [Qemu-devel] [PATCH-RFC 01/13] virtio: export virtqueue structure Michael S. Tsirkin
2010-01-12 22:32 ` [Qemu-devel] " Anthony Liguori
2010-01-25 19:10 ` Michael S. Tsirkin
2010-01-25 19:23 ` Anthony Liguori
2010-01-11 17:17 ` [Qemu-devel] [PATCH-RFC 02/13] kvm: add API to set ioeventfd Michael S. Tsirkin
2010-01-12 22:35 ` [Qemu-devel] " Anthony Liguori
2010-01-25 19:20 ` Michael S. Tsirkin
2010-01-25 19:28 ` Anthony Liguori
2010-01-25 19:28 ` Michael S. Tsirkin
2010-01-25 19:44 ` Anthony Liguori
2010-01-11 17:17 ` [Qemu-devel] [PATCH-RFC 03/13] virtio: add iofd/irqfd support Michael S. Tsirkin
2010-01-12 22:36 ` [Qemu-devel] " Anthony Liguori
2010-01-13 10:50 ` Michael S. Tsirkin
2010-01-11 17:17 ` [Qemu-devel] [PATCH-RFC 04/13] virtio-pci: fill in irqfd/queufd support Michael S. Tsirkin
2010-01-11 17:19 ` [Qemu-devel] [PATCH-RFC 05/13] syborg_virtio: add irqfd/eventfd support Michael S. Tsirkin
2010-01-11 17:20 ` [Qemu-devel] [PATCH-RFC 06/13] s390-virtio: fill in irqfd support Michael S. Tsirkin
2010-01-11 17:20 ` [Qemu-devel] [PATCH-RFC 07/13] virtio: move typedef to qemu-common Michael S. Tsirkin
2010-01-11 17:20 ` [Qemu-devel] [PATCH-RFC 08/13] net/tap: add interface to get device fd Michael S. Tsirkin
2010-01-11 17:22 ` [Qemu-devel] [PATCH-RFC 09/13] tap: add vhost/vhostfd options Michael S. Tsirkin
2010-01-12 22:39 ` [Qemu-devel] " Anthony Liguori
2010-01-13 10:59 ` Michael S. Tsirkin
2010-01-12 22:42 ` Anthony Liguori
2010-01-11 17:22 ` [Qemu-devel] [PATCH-RFC 10/13] tap: add API to retrieve vhost net header Michael S. Tsirkin
2010-01-11 17:23 ` [Qemu-devel] [PATCH-RFC 12/13] virtio: add status change callback Michael S. Tsirkin
2010-01-11 17:23 ` [Qemu-devel] [PATCH-RFC 13/13] virtio-net: connect to vhost net backend Michael S. Tsirkin
2010-01-25 19:58 ` [Qemu-devel] " Anthony Liguori
2010-01-25 20:27 ` Michael S. Tsirkin
2010-01-25 21:00 ` Anthony Liguori
2010-01-25 21:01 ` Michael S. Tsirkin
2010-01-25 21:05 ` Michael S. Tsirkin
2010-01-25 21:11 ` Anthony Liguori
2010-02-24 3:14 ` Paul Brook
2010-02-24 5:29 ` Michael S. Tsirkin
2010-02-24 11:30 ` Paul Brook
2010-02-24 11:46 ` Michael S. Tsirkin
2010-02-24 12:26 ` Paul Brook
2010-02-24 12:40 ` Michael S. Tsirkin
2010-02-24 15:16 ` Anthony Liguori
2010-02-24 14:51 ` Anthony Liguori
2010-01-11 17:23 ` Michael S. Tsirkin [this message]
2010-01-12 22:45 ` [Qemu-devel] Re: [PATCH-RFC 11/13] vhost net support Anthony Liguori
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20100111172332.GC12084@redhat.com \
--to=mst@redhat.com \
--cc=anthony@codemonkey.ws \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.