[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC PATCH 2/4] vhost-user: add the vhost-user extension to
From: |
Wei Wang |
Subject: |
[Qemu-devel] [RFC PATCH 2/4] vhost-user: add the vhost-user extension to support the vhost-pci based inter-vm communication |
Date: |
Wed, 9 Nov 2016 21:47:47 -0500 |
This is the slave part of vhost-user implemented in QEMU, with an extension
to support vhost-pci.
Signed-off-by: Wei Wang <address@hidden>
---
hw/virtio/Makefile.objs | 1 +
hw/virtio/vhost-pci-server.c | 469 +++++++++++++++++++++++++++++++++++
hw/virtio/vhost-user.c | 86 +------
include/hw/virtio/vhost-pci-server.h | 45 ++++
include/hw/virtio/vhost-user.h | 110 ++++++++
include/sysemu/sysemu.h | 1 +
qemu-options.hx | 4 +
vl.c | 26 ++
8 files changed, 657 insertions(+), 85 deletions(-)
create mode 100644 hw/virtio/vhost-pci-server.c
create mode 100644 include/hw/virtio/vhost-pci-server.h
create mode 100644 include/hw/virtio/vhost-user.h
diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs
index 3e2b175..e44feb8 100644
--- a/hw/virtio/Makefile.objs
+++ b/hw/virtio/Makefile.objs
@@ -2,6 +2,7 @@ common-obj-y += virtio-rng.o
common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
common-obj-y += virtio-bus.o
common-obj-y += virtio-mmio.o
+common-obj-y += vhost-pci-server.o
obj-y += virtio.o virtio-balloon.o
obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o
diff --git a/hw/virtio/vhost-pci-server.c b/hw/virtio/vhost-pci-server.c
new file mode 100644
index 0000000..6ce8516
--- /dev/null
+++ b/hw/virtio/vhost-pci-server.c
@@ -0,0 +1,469 @@
+/*
+ * Vhost-pci server
+ *
+ * Copyright Intel Corp. 2016
+ *
+ * Authors:
+ * Wei Wang <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <qemu/osdep.h>
+#include <qemu/thread.h>
+#include <qemu/main-loop.h>
+#include <qemu/bitops.h>
+#include <qemu/bitmap.h>
+#include <qemu/sockets.h>
+#include <linux/virtio_net.h>
+#include "sysemu/char.h"
+#include "qapi/error.h"
+#include "hw/virtio/vhost-pci-server.h"
+#include "qemu/option.h"
+#include "monitor/qdev.h"
+#include "hw/virtio/vhost-user.h"
+#include "hw/qdev.h"
+
+#define VHOST_PCI_FEATURE_BITS (1ULL << VIRTIO_F_VERSION_1)
+
+#define VHOST_PCI_NET_FEATURE_BITS (1ULL << VIRTIO_NET_F_MRG_RXBUF) | \
+ (1ULL << VIRTIO_NET_F_CTRL_VQ) | \
+ (1ULL << VIRTIO_NET_F_MQ)
+
+#define VHOST_USER_SET_PEER_CONNECTION_OFF 0
+#define VHOST_USER_SET_PEER_CONNECTION_ON 1
+#define VHOST_USER_SET_PEER_CONNECTION_INIT 2
+
+VhostPCIServer *vp_server;
+
+QemuOptsList qemu_vhost_pci_server_opts = {
+ .name = "vhost-pci-server",
+ .implied_opt_name = "chardev",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_vhost_pci_server_opts.head),
+ .desc = {
+ /*
+ * no elements => accept any
+ * sanity checking will happen later
+ * when setting device properties
+ */
+ { /* end of list */ }
+ },
+};
+
+static int vhost_pci_server_write(CharDriverState *chr, VhostUserMsg *msg)
+{
+ int size = msg->size + VHOST_USER_HDR_SIZE;
+
+ if (!msg)
+ return 0;
+
+ msg->flags &= ~VHOST_USER_VERSION_MASK;
+ msg->flags |= VHOST_USER_VERSION;
+
+ return qemu_chr_fe_write_all_n(chr, msg->conn_id,
+ (const uint8_t *)msg, size) == size ? 0 : -1;
+}
+
+PeerConnectionTable *vp_server_find_table_ent(const char *dev_id)
+{
+ int i;
+ PeerConnectionTable *ent;
+ uint64_t max_connections = vp_server->chr->max_connections;
+
+ for (i = 0; i < max_connections; i++) {
+ ent = &vp_server->peer_table[i];
+ if (!strcmp(dev_id, ent->dev_id))
+ return ent;
+ }
+ return NULL;
+}
+
+static void vhost_pci_init_peer_table(uint64_t id)
+{
+ PeerConnectionTable *ent = &vp_server->peer_table[id];
+
+ ent->peer_feature_bits |= 1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
+ QLIST_INIT(&ent->vq_list);
+ ent->vq_num = 0;
+}
+
+static int vhost_pci_get_conn_id(CharDriverState *chr, VhostUserMsg *msg)
+{
+ unsigned long *conn_bitmap = chr->conn_bitmap;
+ unsigned long *old_conn_bitmap = vp_server->old_conn_bitmap;
+ uint64_t nbits = chr->max_connections;
+ uint64_t id;
+ int r;
+
+ bitmap_xor(old_conn_bitmap, old_conn_bitmap, conn_bitmap, (long)nbits);
+
+ for (id = find_first_bit(old_conn_bitmap, nbits); id < nbits;
+ id = find_next_bit(old_conn_bitmap, nbits, id + 1)) {
+ vhost_pci_init_peer_table(id);
+ msg->conn_id = id;
+ msg->payload.u64 = id;
+ msg->size = sizeof(msg->payload.u64);
+ msg->flags |= VHOST_USER_REPLY_MASK;
+ r = vhost_pci_server_write(chr, msg);
+ }
+ bitmap_copy(old_conn_bitmap, conn_bitmap, (long)nbits);
+
+ return r;
+}
+
+static int vhost_pci_get_peer_features(CharDriverState *chr, VhostUserMsg *msg)
+{
+ PeerConnectionTable *ent = &vp_server->peer_table[msg->conn_id];
+ msg->payload.u64 = ent->peer_feature_bits;
+ msg->size = sizeof(msg->payload.u64);
+ msg->flags |= VHOST_USER_REPLY_MASK;
+ return vhost_pci_server_write(chr, msg);
+}
+
+static int vhost_pci_get_queue_num(CharDriverState *chr, VhostUserMsg *msg)
+{
+ PeerConnectionTable *ent = &vp_server->peer_table[msg->conn_id];
+ switch (ent->virtio_id) {
+ case VIRTIO_ID_NET:
+ msg->payload.u64 = VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX;
+ break;
+ default:
+ printf("%s: device type not supported yet..\n", __func__);
+ }
+ msg->size = sizeof(msg->payload.u64);
+ msg->flags |= VHOST_USER_REPLY_MASK;
+ return vhost_pci_server_write(chr, msg);
+}
+
+static int vhost_pci_get_protocol_features(CharDriverState *chr, VhostUserMsg
*msg)
+{
+ msg->payload.u64 = VHOST_USER_PROTOCOL_FEATURES;
+ msg->size = sizeof(msg->payload.u64);
+ msg->flags |= VHOST_USER_REPLY_MASK;
+ return vhost_pci_server_write(chr, msg);
+}
+
+static void vhost_pci_set_protocol_features(VhostUserMsg *msg)
+{
+ vp_server->protocol_features = msg->payload.u64;
+}
+
+static int vhost_pci_device_create(uint64_t conn_id)
+{
+ PeerConnectionTable *ent = &vp_server->peer_table[conn_id];
+ Error *local_err = NULL;
+ QemuOpts *opts;
+ DeviceState *dev;
+ char params[50];
+
+ switch (ent->virtio_id) {
+ case VIRTIO_ID_NET:
+ sprintf(params, "driver=vhost-pci-net-pci,id=vhost-pci-%ld", conn_id);
+ sprintf(ent->dev_id, "vhost-pci-%ld", conn_id);
+ break;
+ default:
+ printf("%s: device type not supported yet..\n", __func__);
+ }
+
+ opts = qemu_opts_parse_noisily(qemu_find_opts("device"), params, true);
+ dev = qdev_device_add(opts, &local_err);
+ if (!dev) {
+ qemu_opts_del(opts);
+ return -1;
+ }
+ object_unref(OBJECT(dev));
+ return 0;
+}
+
+static void vhost_pci_set_device_info(VhostUserMsg *msg)
+{
+ PeerConnectionTable *ent = &vp_server->peer_table[msg->conn_id];
+ DeviceInfo *info = &msg->payload.dev_info;
+
+ memcpy(ent->uuid, info->uuid, sizeof(uuid_t));
+ ent->virtio_id = info->virtio_id;
+ switch (ent->virtio_id) {
+ case VIRTIO_ID_NET:
+ ent->peer_feature_bits |= (VHOST_PCI_FEATURE_BITS |
VHOST_PCI_NET_FEATURE_BITS);
+ break;
+ default:
+ printf("%s: device type not supported yet..\n", __func__);
+ }
+}
+
+static void vhost_pci_set_peer_feature_bits(VhostUserMsg *msg)
+{
+ PeerConnectionTable *ent = &vp_server->peer_table[msg->conn_id];
+
+ ent->peer_feature_bits = msg->payload.u64;
+}
+
+static uint64_t vhost_pci_peer_mem_size_get(VhostUserMemory *peer_mem)
+{
+ int i;
+ uint64_t total_size;
+ uint32_t nregions = peer_mem->nregions;
+ VhostUserMemoryRegion *regions = peer_mem->regions;
+
+ for (i = 0; i < nregions; i++) {
+ total_size += regions[i].memory_size;
+ }
+
+ return total_size;
+}
+
+static int vhost_pci_set_mem_table(uint64_t conn_id, VhostUserMemory
*peer_mem, int *fds)
+{
+ int i;
+ void *mr_qva;
+ PeerConnectionTable *ent = &vp_server->peer_table[conn_id];
+ uint32_t nregions = peer_mem->nregions;
+ VhostUserMemoryRegion *peer_mr = peer_mem->regions;
+ MemoryRegion *bar_mr = g_malloc(sizeof(MemoryRegion));
+ MemoryRegion *mr = g_malloc(nregions * sizeof(MemoryRegion));
+ uint64_t bar_size = 2 * vhost_pci_peer_mem_size_get(peer_mem);
+ uint64_t bar_map_offset = 0;
+
+ bar_size = pow2ceil(bar_size);
+ memory_region_init(bar_mr, NULL, "Peer Memory", bar_size);
+
+ for (i = 0; i < nregions; i++) {
+ mr_qva = mmap(NULL, peer_mr[i].memory_size + peer_mr[i].mmap_offset,
+ PROT_READ | PROT_READ, MAP_SHARED, fds[i], 0);
+ if (mr_qva == MAP_FAILED) {
+ printf("%s called: map failed \n", __func__);
+ return -1;
+ }
+ mr_qva += peer_mr[i].mmap_offset;
+ memory_region_init_ram_ptr(&mr[i], NULL, "Peer Memory",
peer_mr[i].memory_size, mr_qva);
+ memory_region_add_subregion(bar_mr, bar_map_offset, &mr[i]);
+ bar_map_offset += peer_mr[i].memory_size;
+ }
+ ent->bar_mr = bar_mr;
+ ent->bar_map_offset = bar_map_offset;
+
+ return 0;
+}
+
+static void vhost_pci_alloc_peer_vring_info(uint64_t conn_id)
+{
+ PeerConnectionTable *ent = &vp_server->peer_table[conn_id];
+ PeerVirtqInfo *virtq_info = g_malloc0(sizeof(PeerVirtqInfo));
+ QLIST_INSERT_HEAD(&ent->vq_list, virtq_info, node);
+ ent->vq_num++;
+}
+
+static void vhost_pci_set_vring_num(VhostUserMsg *msg)
+{
+ PeerConnectionTable *ent = &vp_server->peer_table[msg->conn_id];
+ PeerVirtqInfo *virtq_info = QLIST_FIRST(&ent->vq_list);
+
+ virtq_info->vring_num = msg->payload.u64;
+}
+
+static void vhost_pci_set_vring_base(VhostUserMsg *msg)
+{
+ PeerConnectionTable *ent = &vp_server->peer_table[msg->conn_id];
+ PeerVirtqInfo *virtq_info = QLIST_FIRST(&ent->vq_list);
+
+ virtq_info->last_avail_idx = msg->payload.u64;
+}
+
+static void vhost_pci_set_vring_addr(VhostUserMsg *msg)
+{
+ PeerConnectionTable *ent = &vp_server->peer_table[msg->conn_id];
+ PeerVirtqInfo *virtq_info = QLIST_FIRST(&ent->vq_list);
+ memcpy(&virtq_info->addr, &msg->payload.addr,
+ sizeof(struct vhost_vring_addr));
+}
+
+static void vhost_pci_set_vring_kick(uint64_t conn_id, int fd)
+{
+ PeerConnectionTable *ent = &vp_server->peer_table[conn_id];
+ PeerVirtqInfo *virtq_info = QLIST_FIRST(&ent->vq_list);
+ if (!virtq_info)
+ virtq_info->kickfd = fd;
+}
+
+static void vhost_pci_set_vring_call(uint64_t conn_id, int fd)
+{
+ PeerConnectionTable *ent = &vp_server->peer_table[conn_id];
+ PeerVirtqInfo *virtq_info = QLIST_FIRST(&ent->vq_list);
+ if (virtq_info)
+ virtq_info->callfd = fd;
+}
+
+static void vhost_pci_set_peer_connection(VhostUserMsg *msg)
+{
+ uint64_t cmd = msg->payload.u64;
+ uint64_t conn_id = msg->conn_id;
+
+ switch (cmd) {
+ case VHOST_USER_SET_PEER_CONNECTION_INIT:
+ vhost_pci_device_create(conn_id);
+ break;
+ default:
+ printf("%s called: cmd %lu not supported yet \n", __func__, cmd);
+ }
+}
+
+static void vhost_pci_server_read(void *opaque, const uint8_t *buf, int size)
+{
+ VhostUserMsg msg;
+ uint8_t *p = (uint8_t *) &msg;
+ CharDriverState *chr = (CharDriverState *)opaque;
+ int fds[8], fd_num;
+
+ if (size != VHOST_USER_HDR_SIZE) {
+ printf("Wrong message size received %d\n", size);
+ return;
+ }
+ memcpy(p, buf, VHOST_USER_HDR_SIZE);
+
+ if (msg.size) {
+ p += VHOST_USER_HDR_SIZE;
+ size = qemu_chr_fe_read_all_n(chr, msg.conn_id, p, msg.size);
+ if (size != msg.size) {
+ printf("Wrong message size received %d != %d\n",
+ size, msg.size);
+ return;
+ }
+ }
+
+ if (msg.request > VHOST_USER_MAX)
+ printf("vhost read incorrect msg \n");
+
+ switch(msg.request) {
+ case VHOST_USER_GET_CONN_ID:
+ vhost_pci_get_conn_id(chr, &msg);
+ break;
+ case VHOST_USER_GET_FEATURES:
+ vhost_pci_get_peer_features(chr, &msg);
+ break;
+ case VHOST_USER_GET_PROTOCOL_FEATURES:
+ vhost_pci_get_protocol_features(chr, &msg);
+ break;
+ case VHOST_USER_SET_PROTOCOL_FEATURES:
+ vhost_pci_set_protocol_features(&msg);
+ break;
+ case VHOST_USER_SET_DEV_INFO:
+ vhost_pci_set_device_info(&msg);
+ break;
+ case VHOST_USER_GET_QUEUE_NUM:
+ vhost_pci_get_queue_num(chr, &msg);
+ break;
+ case VHOST_USER_SET_OWNER:
+ break;
+ case VHOST_USER_SET_FEATURES:
+ vhost_pci_set_peer_feature_bits(&msg);
+ break;
+ case VHOST_USER_SET_VRING_NUM:
+ vhost_pci_alloc_peer_vring_info(msg.conn_id);
+ vhost_pci_set_vring_num(&msg);
+ break;
+ case VHOST_USER_SET_VRING_BASE:
+ vhost_pci_set_vring_base(&msg);
+ break;
+ case VHOST_USER_SET_VRING_ADDR:
+ vhost_pci_set_vring_addr(&msg);
+ break;
+ case VHOST_USER_SET_VRING_KICK:
+ /* consume the fd */
+ qemu_chr_fe_get_msgfds_n(chr, msg.conn_id, fds, 1);
+ printf("VHOST_USER_SET_VRING_KICK called:..kickfd = %d\n", fds[0]);
+ vhost_pci_set_vring_kick(msg.conn_id, fds[0]);
+ /*
+ * This is a non-blocking eventfd.
+ * The receive function forces it to be blocking,
+ * so revert it back to non-blocking.
+ */
+ qemu_set_nonblock(fds[0]);
+ break;
+ case VHOST_USER_SET_VRING_CALL:
+ /* consume the fd */
+ qemu_chr_fe_get_msgfds_n(chr, msg.conn_id, fds, 1);
+ vhost_pci_set_vring_call(msg.conn_id, fds[0]);
+ /*
+ * This is a non-blocking eventfd.
+ * The receive function forces it to be blocking,
+ * so revert it back to non-blocking.
+ */
+ qemu_set_nonblock(fds[0]);
+ break;
+ case VHOST_USER_SET_MEM_TABLE:
+ fd_num = qemu_chr_fe_get_msgfds_n(chr, msg.conn_id,
+ fds, sizeof(fds) / sizeof(int));
+ printf("VHOST_USER_SET_MEM_TABLE: fd = %d \n", fd_num);
+ vhost_pci_set_mem_table(msg.conn_id, &msg.payload.memory, fds);
+ break;
+ case VHOST_USER_SET_PEER_CONNECTION:
+ vhost_pci_set_peer_connection(&msg);
+ break;
+ default:
+ printf("default called..msg->request = %d \n", msg.request);
+ break;
+ }
+}
+
+static int vhost_pci_server_can_read(void *opaque)
+{
+ return VHOST_USER_HDR_SIZE;
+}
+
+static void vhost_pci_server_event(void *opaque, int event)
+{
+ switch (event) {
+ case CHR_EVENT_OPENED:
+ printf("vhost_pci_server_event called.. \n");
+ break;
+ case CHR_EVENT_CLOSED:
+ printf("vhost_pci_server_event called: event close..\n");
+ break;
+ }
+}
+
+static CharDriverState *vhost_pci_server_parse_chardev(const char *id)
+{
+ CharDriverState *chr = qemu_chr_find(id);
+ if (chr == NULL) {
+ printf("chardev \"%s\" not found", id);
+ return NULL;
+ }
+
+ qemu_chr_fe_claim_no_fail(chr);
+
+ return chr;
+}
+
+int vhost_pci_server_init(QemuOpts *opts)
+{
+ CharDriverState *chr;
+ const char *chardev_id = qemu_opt_get(opts, "chardev");
+ uint64_t max_connections;
+
+ vp_server = (VhostPCIServer *)malloc(sizeof(VhostPCIServer));
+
+ chr = vhost_pci_server_parse_chardev(chardev_id);
+ if (!chr) {
+ return -1;
+ }
+ max_connections = chr->max_connections;
+
+ qemu_chr_add_handlers(chr, vhost_pci_server_can_read,
vhost_pci_server_read, vhost_pci_server_event, chr);
+
+ vp_server->chr = chr;
+
+ vp_server->peer_table = (PeerConnectionTable *)g_malloc0(max_connections *
sizeof(PeerConnectionTable));
+
+ vp_server->old_conn_bitmap = bitmap_new(max_connections);
+
+ return 0;
+}
+
+int vhost_pci_server_cleanup(void)
+{
+ free(vp_server);
+ printf("vhost_pci_server_cleanup called.. \n");
+ return 0;
+}
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index b57454a..bce5181 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -13,6 +13,7 @@
#include "hw/virtio/vhost.h"
#include "hw/virtio/vhost-backend.h"
#include "hw/virtio/virtio-net.h"
+#include "hw/virtio/vhost-user.h"
#include "sysemu/char.h"
#include "sysemu/kvm.h"
#include "qemu/error-report.h"
@@ -24,91 +25,6 @@
#include <sys/un.h>
#include <linux/vhost.h>
-#define VHOST_MEMORY_MAX_NREGIONS 8
-#define VHOST_USER_F_PROTOCOL_FEATURES 30
-
-enum VhostUserProtocolFeature {
- VHOST_USER_PROTOCOL_F_MQ = 0,
- VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1,
- VHOST_USER_PROTOCOL_F_RARP = 2,
- VHOST_USER_PROTOCOL_F_REPLY_ACK = 3,
-
- VHOST_USER_PROTOCOL_F_MAX
-};
-
-#define VHOST_USER_PROTOCOL_FEATURE_MASK ((1 << VHOST_USER_PROTOCOL_F_MAX) - 1)
-
-typedef enum VhostUserRequest {
- VHOST_USER_NONE = 0,
- VHOST_USER_GET_FEATURES = 1,
- VHOST_USER_SET_FEATURES = 2,
- VHOST_USER_SET_OWNER = 3,
- VHOST_USER_RESET_OWNER = 4,
- VHOST_USER_SET_MEM_TABLE = 5,
- VHOST_USER_SET_LOG_BASE = 6,
- VHOST_USER_SET_LOG_FD = 7,
- VHOST_USER_SET_VRING_NUM = 8,
- VHOST_USER_SET_VRING_ADDR = 9,
- VHOST_USER_SET_VRING_BASE = 10,
- VHOST_USER_GET_VRING_BASE = 11,
- VHOST_USER_SET_VRING_KICK = 12,
- VHOST_USER_SET_VRING_CALL = 13,
- VHOST_USER_SET_VRING_ERR = 14,
- VHOST_USER_GET_PROTOCOL_FEATURES = 15,
- VHOST_USER_SET_PROTOCOL_FEATURES = 16,
- VHOST_USER_GET_QUEUE_NUM = 17,
- VHOST_USER_SET_VRING_ENABLE = 18,
- VHOST_USER_SEND_RARP = 19,
- VHOST_USER_MAX
-} VhostUserRequest;
-
-typedef struct VhostUserMemoryRegion {
- uint64_t guest_phys_addr;
- uint64_t memory_size;
- uint64_t userspace_addr;
- uint64_t mmap_offset;
-} VhostUserMemoryRegion;
-
-typedef struct VhostUserMemory {
- uint32_t nregions;
- uint32_t padding;
- VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
-} VhostUserMemory;
-
-typedef struct VhostUserLog {
- uint64_t mmap_size;
- uint64_t mmap_offset;
-} VhostUserLog;
-
-typedef struct VhostUserMsg {
- VhostUserRequest request;
-
-#define VHOST_USER_VERSION_MASK (0x3)
-#define VHOST_USER_REPLY_MASK (0x1<<2)
-#define VHOST_USER_NEED_REPLY_MASK (0x1 << 3)
- uint32_t flags;
- uint32_t size; /* the following payload size */
- union {
-#define VHOST_USER_VRING_IDX_MASK (0xff)
-#define VHOST_USER_VRING_NOFD_MASK (0x1<<8)
- uint64_t u64;
- struct vhost_vring_state state;
- struct vhost_vring_addr addr;
- VhostUserMemory memory;
- VhostUserLog log;
- } payload;
-} QEMU_PACKED VhostUserMsg;
-
-static VhostUserMsg m __attribute__ ((unused));
-#define VHOST_USER_HDR_SIZE (sizeof(m.request) \
- + sizeof(m.flags) \
- + sizeof(m.size))
-
-#define VHOST_USER_PAYLOAD_SIZE (sizeof(m) - VHOST_USER_HDR_SIZE)
-
-/* The version of the protocol we support */
-#define VHOST_USER_VERSION (0x1)
-
static bool ioeventfd_enabled(void)
{
return kvm_enabled() && kvm_eventfds_enabled();
diff --git a/include/hw/virtio/vhost-pci-server.h
b/include/hw/virtio/vhost-pci-server.h
new file mode 100644
index 0000000..c9c4a69
--- /dev/null
+++ b/include/hw/virtio/vhost-pci-server.h
@@ -0,0 +1,45 @@
+#ifndef QEMU_VHOST_PCI_SERVER_H
+#define QEMU_VHOST_PCI_SERVER_H
+
+#include <uuid/uuid.h>
+#include <linux/vhost.h>
+
+typedef struct PeerVirtqInfo {
+ int kickfd;
+ int callfd;
+ uint32_t vring_num;
+ uint16_t last_avail_idx;
+ struct vhost_vring_addr addr;
+ QLIST_ENTRY(PeerVirtqInfo) node;
+} PeerVirtqInfo;
+
+typedef struct PeerConnectionTable {
+ char dev_id[30];
+ uuid_t uuid;
+ uint16_t virtio_id;
+ uint32_t bar_id;
+ MemoryRegion *bar_mr;
+ uint64_t bar_map_offset;
+ uint64_t peer_feature_bits;
+ void *opaque;
+ uint16_t vq_num;
+ QLIST_HEAD(, PeerVirtqInfo) vq_list;
+} PeerConnectionTable;
+
+typedef struct VhostPCIServer {
+ CharDriverState *chr;
+ uint64_t protocol_features;
+ unsigned long *old_conn_bitmap;
+ /* a table indexed by the peer connection id */
+ PeerConnectionTable *peer_table;
+} VhostPCIServer;
+
+extern VhostPCIServer *vp_server;
+
+extern int vhost_pci_server_init(QemuOpts *opts);
+
+extern int vhost_pci_server_cleanup(void);
+
+extern PeerConnectionTable *vp_server_find_table_ent(const char *dev_id);
+
+#endif
diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h
new file mode 100644
index 0000000..794a8d8
--- /dev/null
+++ b/include/hw/virtio/vhost-user.h
@@ -0,0 +1,110 @@
+#ifndef VHOST_USER_H
+#define VHOST_USER_H
+
+#include <linux/vhost.h>
+#include <uuid/uuid.h>
+
+#define VHOST_MEMORY_MAX_NREGIONS 8
+#define VHOST_USER_F_PROTOCOL_FEATURES 30
+
+enum VhostUserProtocolFeature {
+ VHOST_USER_PROTOCOL_F_MQ = 0,
+ VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1,
+ VHOST_USER_PROTOCOL_F_RARP = 2,
+ VHOST_USER_PROTOCOL_F_REPLY_ACK = 3,
+ VHOST_USER_PROTOCOL_F_VHOST_PCI =4,
+
+ VHOST_USER_PROTOCOL_F_MAX
+};
+
+#define VHOST_USER_PROTOCOL_FEATURE_MASK ((1 << VHOST_USER_PROTOCOL_F_MAX) - 1)
+
+#define VHOST_USER_PROTOCOL_FEATURES ((1ULL << VHOST_USER_PROTOCOL_F_MQ) | \
+ (1ULL <<
VHOST_USER_PROTOCOL_F_LOG_SHMFD) | \
+ (1ULL << VHOST_USER_PROTOCOL_F_RARP)) | \
+ (1ULL << VHOST_USER_PROTOCOL_F_VHOST_PCI)
+
+typedef enum VhostUserRequest {
+ VHOST_USER_NONE = 0,
+ VHOST_USER_GET_FEATURES = 1,
+ VHOST_USER_SET_FEATURES = 2,
+ VHOST_USER_SET_OWNER = 3,
+ VHOST_USER_RESET_OWNER = 4,
+ VHOST_USER_SET_MEM_TABLE = 5,
+ VHOST_USER_SET_LOG_BASE = 6,
+ VHOST_USER_SET_LOG_FD = 7,
+ VHOST_USER_SET_VRING_NUM = 8,
+ VHOST_USER_SET_VRING_ADDR = 9,
+ VHOST_USER_SET_VRING_BASE = 10,
+ VHOST_USER_GET_VRING_BASE = 11,
+ VHOST_USER_SET_VRING_KICK = 12,
+ VHOST_USER_SET_VRING_CALL = 13,
+ VHOST_USER_SET_VRING_ERR = 14,
+ VHOST_USER_GET_PROTOCOL_FEATURES = 15,
+ VHOST_USER_SET_PROTOCOL_FEATURES = 16,
+ VHOST_USER_GET_QUEUE_NUM = 17,
+ VHOST_USER_SET_VRING_ENABLE = 18,
+ VHOST_USER_SEND_RARP = 19,
+ VHOST_USER_GET_CONN_ID = 20,
+ VHOST_USER_SET_DEV_INFO = 21,
+ VHOST_USER_SET_PEER_CONNECTION = 22,
+ VHOST_USER_MAX
+} VhostUserRequest;
+
+typedef struct VhostUserMemoryRegion {
+ uint64_t guest_phys_addr;
+ uint64_t memory_size;
+ uint64_t userspace_addr;
+ uint64_t mmap_offset;
+} VhostUserMemoryRegion;
+
+typedef struct VhostUserMemory {
+ uint32_t nregions;
+ uint32_t padding;
+ VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
+} VhostUserMemory;
+
+typedef struct VhostUserLog {
+ uint64_t mmap_size;
+ uint64_t mmap_offset;
+} VhostUserLog;
+
+typedef struct DeviceInfo {
+ uuid_t uuid;
+ uint16_t virtio_id;
+} DeviceInfo;
+
+typedef struct VhostUserMsg {
+ VhostUserRequest request;
+
+#define VHOST_USER_VERSION_MASK (0x3)
+#define VHOST_USER_REPLY_MASK (0x1<<2)
+#define VHOST_USER_NEED_REPLY_MASK (0x1 << 3)
+ uint32_t flags;
+ uint32_t size; /* the following payload size */
+ uint64_t conn_id;
+ union {
+#define VHOST_USER_VRING_IDX_MASK (0xff)
+#define VHOST_USER_VRING_NOFD_MASK (0x1<<8)
+ uint64_t u64;
+ struct vhost_vring_state state;
+ struct vhost_vring_addr addr;
+ VhostUserMemory memory;
+ VhostUserLog log;
+ DeviceInfo dev_info;
+ } payload;
+} QEMU_PACKED VhostUserMsg;
+
+static VhostUserMsg m __attribute__ ((unused));
+#define VHOST_USER_HDR_SIZE (sizeof(m.request) \
+ + sizeof(m.flags) \
+ + sizeof(m.size)) \
+ + sizeof(m.conn_id)
+
+#define VHOST_USER_PAYLOAD_SIZE (sizeof(m) - VHOST_USER_HDR_SIZE)
+
+/* The version of the protocol we support */
+#define VHOST_USER_VERSION (0x2)
+
+#endif
+
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index ee7c760..7f8b25c 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -244,5 +244,6 @@ extern QemuOptsList qemu_netdev_opts;
extern QemuOptsList qemu_net_opts;
extern QemuOptsList qemu_global_opts;
extern QemuOptsList qemu_mon_opts;
+extern QemuOptsList qemu_vhost_pci_server_opts;
#endif
diff --git a/qemu-options.hx b/qemu-options.hx
index a71aaf8..1fdb820 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3968,6 +3968,10 @@ contents of @code{iv.b64} to the second secret
ETEXI
+DEF("vhost-pci-server", HAS_ARG, QEMU_OPTION_vhost_pci_server,
+ "-vhost-pci-server socket,chrdev={id}\n"
+ " creates a vhost-pci-server",
+ QEMU_ARCH_I386)
HXCOMM This is the last statement. Insert new options before this line!
STEXI
diff --git a/vl.c b/vl.c
index b3c80d5..c1f038d 100644
--- a/vl.c
+++ b/vl.c
@@ -121,6 +121,7 @@ int main(int argc, char **argv)
#include "crypto/init.h"
#include "sysemu/replay.h"
#include "qapi/qmp/qerror.h"
+#include "hw/virtio/vhost-pci-server.h"
#define MAX_VIRTIO_CONSOLES 1
#define MAX_SCLP_CONSOLES 1
@@ -178,6 +179,7 @@ bool boot_strict;
uint8_t *boot_splash_filedata;
size_t boot_splash_filedata_size;
uint8_t qemu_extra_params_fw[2];
+bool vhost_pci_server_enabled;
int icount_align_option;
@@ -2980,6 +2982,7 @@ int main(int argc, char **argv, char **envp)
qemu_add_drive_opts(&qemu_drive_opts);
qemu_add_opts(&qemu_chardev_opts);
qemu_add_opts(&qemu_device_opts);
+ qemu_add_opts(&qemu_vhost_pci_server_opts);
qemu_add_opts(&qemu_netdev_opts);
qemu_add_opts(&qemu_net_opts);
qemu_add_opts(&qemu_rtc_opts);
@@ -3970,6 +3973,13 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
break;
+ case QEMU_OPTION_vhost_pci_server:
+ vhost_pci_server_enabled = true;
+ opts =
qemu_opts_parse_noisily(qemu_find_opts("vhost-pci-server"), optarg, false);
+ if (!opts) {
+ exit(1);
+ }
+ break;
default:
os_parse_cmd_args(popt->index, optarg);
}
@@ -4479,6 +4489,16 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
+ /* check if the vhost-pci-server is enabled */
+ if (vhost_pci_server_enabled) {
+ int ret;
+ ret = vhost_pci_server_init(qemu_opts_find(
+ qemu_find_opts("vhost-pci-server"),
+ NULL));
+ if (ret < 0)
+ exit(1);
+ }
+
/* init USB devices */
if (machine_usb(current_machine)) {
if (foreach_device_config(DEV_USB, usb_parse) < 0)
@@ -4607,6 +4627,12 @@ int main(int argc, char **argv, char **envp)
bdrv_close_all();
pause_all_vcpus();
res_free();
+ if (vhost_pci_server_enabled) {
+ int ret;
+ ret = vhost_pci_server_cleanup();
+ if (ret < 0)
+ exit(1);
+ }
#ifdef CONFIG_TPM
tpm_cleanup();
#endif
--
2.7.4