qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] Re: [PATCH-RFC 11/13] vhost net support


From: Anthony Liguori
Subject: [Qemu-devel] Re: [PATCH-RFC 11/13] vhost net support
Date: Tue, 12 Jan 2010 16:45:08 -0600
User-agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.5) Gecko/20091209 Fedora/3.0-4.fc12 Lightning/1.0pre Thunderbird/3.0

On 01/11/2010 11:23 AM, Michael S. Tsirkin wrote:
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<address@hidden>

Hit send too quick.. here it is.

---
  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;
+}

This is gnarly and basically duplicated with kvm-all.c. Dunno if code sharing is practical though.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;
+};

Please follow CodingStyle.

Regards,

Anthony Liguori




reply via email to

[Prev in Thread] Current Thread [Next in Thread]