qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

vhost-vsock: add virtio sockets device

Implement the new virtio sockets device for host<->guest communication
using the Sockets API. Most of the work is done in a vhost kernel
driver so that virtio-vsock can hook into the AF_VSOCK address family.
The QEMU vhost-vsock device handles configuration and live migration
while the rx/tx happens in the vhost_vsock.ko Linux kernel driver.

The vsock device must be given a CID (host-wide unique address):

# qemu -device vhost-vsock-pci,id=vhost-vsock-pci0,guest-cid=3 ...

For more information see:
http://qemu-project.org/Features/VirtioVsock

[Endianness fixes and virtio-ccw support by Claudio Imbrenda
<imbrenda@linux.vnet.ibm.com>]

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
[mst: rebase to master]
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

authored by

Stefan Hajnoczi and committed by
Michael S. Tsirkin
fc0b9b0e 947b205f

+631
+10
configure
··· 229 229 230 230 vhost_net="no" 231 231 vhost_scsi="no" 232 + vhost_vsock="no" 232 233 kvm="no" 233 234 rdma="" 234 235 gprof="no" ··· 674 675 kvm="yes" 675 676 vhost_net="yes" 676 677 vhost_scsi="yes" 678 + vhost_vsock="yes" 677 679 QEMU_INCLUDES="-I\$(SRC_PATH)/linux-headers -I$(pwd)/linux-headers $QEMU_INCLUDES" 678 680 ;; 679 681 esac ··· 1016 1018 --disable-vhost-scsi) vhost_scsi="no" 1017 1019 ;; 1018 1020 --enable-vhost-scsi) vhost_scsi="yes" 1021 + ;; 1022 + --disable-vhost-vsock) vhost_vsock="no" 1023 + ;; 1024 + --enable-vhost-vsock) vhost_vsock="yes" 1019 1025 ;; 1020 1026 --disable-opengl) opengl="no" 1021 1027 ;; ··· 4883 4889 echo "libcap-ng support $cap_ng" 4884 4890 echo "vhost-net support $vhost_net" 4885 4891 echo "vhost-scsi support $vhost_scsi" 4892 + echo "vhost-vsock support $vhost_vsock" 4886 4893 echo "Trace backends $trace_backends" 4887 4894 if have_backend "simple"; then 4888 4895 echo "Trace output file $trace_file-<pid>" ··· 5263 5270 fi 5264 5271 if test "$vhost_net" = "yes" ; then 5265 5272 echo "CONFIG_VHOST_NET_USED=y" >> $config_host_mak 5273 + fi 5274 + if test "$vhost_vsock" = "yes" ; then 5275 + echo "CONFIG_VHOST_VSOCK=y" >> $config_host_mak 5266 5276 fi 5267 5277 if test "$blobs" = "yes" ; then 5268 5278 echo "INSTALL_BLOBS=yes" >> $config_host_mak
+54
hw/s390x/virtio-ccw.c
··· 1658 1658 }; 1659 1659 #endif 1660 1660 1661 + #ifdef CONFIG_VHOST_VSOCK 1662 + 1663 + static Property vhost_vsock_ccw_properties[] = { 1664 + DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), 1665 + DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, 1666 + VIRTIO_CCW_MAX_REV), 1667 + DEFINE_PROP_END_OF_LIST(), 1668 + }; 1669 + 1670 + static void vhost_vsock_ccw_realize(VirtioCcwDevice *ccw_dev, Error **errp) 1671 + { 1672 + VHostVSockCCWState *dev = VHOST_VSOCK_CCW(ccw_dev); 1673 + DeviceState *vdev = DEVICE(&dev->vdev); 1674 + Error *err = NULL; 1675 + 1676 + qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); 1677 + object_property_set_bool(OBJECT(vdev), true, "realized", &err); 1678 + if (err) { 1679 + error_propagate(errp, err); 1680 + } 1681 + } 1682 + 1683 + static void vhost_vsock_ccw_class_init(ObjectClass *klass, void *data) 1684 + { 1685 + DeviceClass *dc = DEVICE_CLASS(klass); 1686 + VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); 1687 + 1688 + k->realize = vhost_vsock_ccw_realize; 1689 + k->exit = virtio_ccw_exit; 1690 + set_bit(DEVICE_CATEGORY_MISC, dc->categories); 1691 + dc->props = vhost_vsock_ccw_properties; 1692 + dc->reset = virtio_ccw_reset; 1693 + } 1694 + 1695 + static void vhost_vsock_ccw_instance_init(Object *obj) 1696 + { 1697 + VHostVSockCCWState *dev = VHOST_VSOCK_CCW(obj); 1698 + 1699 + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), 1700 + TYPE_VHOST_VSOCK); 1701 + } 1702 + 1703 + static const TypeInfo vhost_vsock_ccw_info = { 1704 + .name = TYPE_VHOST_VSOCK_CCW, 1705 + .parent = TYPE_VIRTIO_CCW_DEVICE, 1706 + .instance_size = sizeof(VHostVSockCCWState), 1707 + .instance_init = vhost_vsock_ccw_instance_init, 1708 + .class_init = vhost_vsock_ccw_class_init, 1709 + }; 1710 + #endif 1711 + 1661 1712 static void virtio_ccw_register(void) 1662 1713 { 1663 1714 type_register_static(&virtio_ccw_bus_info); ··· 1673 1724 type_register_static(&virtio_ccw_rng); 1674 1725 #ifdef CONFIG_VIRTFS 1675 1726 type_register_static(&virtio_ccw_9p_info); 1727 + #endif 1728 + #ifdef CONFIG_VHOST_VSOCK 1729 + type_register_static(&vhost_vsock_ccw_info); 1676 1730 #endif 1677 1731 } 1678 1732
+15
hw/s390x/virtio-ccw.h
··· 23 23 #include "hw/virtio/virtio-balloon.h" 24 24 #include "hw/virtio/virtio-rng.h" 25 25 #include "hw/virtio/virtio-bus.h" 26 + #ifdef CONFIG_VHOST_VSOCK 27 + #include "hw/virtio/vhost-vsock.h" 28 + #endif /* CONFIG_VHOST_VSOCK */ 26 29 27 30 #include "hw/s390x/s390_flic.h" 28 31 #include "hw/s390x/css.h" ··· 196 199 } V9fsCCWState; 197 200 198 201 #endif /* CONFIG_VIRTFS */ 202 + 203 + #ifdef CONFIG_VHOST_VSOCK 204 + #define TYPE_VHOST_VSOCK_CCW "vhost-vsock-ccw" 205 + #define VHOST_VSOCK_CCW(obj) \ 206 + OBJECT_CHECK(VHostVSockCCWState, (obj), TYPE_VHOST_VSOCK_CCW) 207 + 208 + typedef struct VHostVSockCCWState { 209 + VirtioCcwDevice parent_obj; 210 + VHostVSock vdev; 211 + } VHostVSockCCWState; 212 + 213 + #endif /* CONFIG_VHOST_VSOCK */ 199 214 200 215 #endif
+2
hw/virtio/Makefile.objs
··· 5 5 6 6 obj-y += virtio.o virtio-balloon.o 7 7 obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o 8 + 9 + obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o
+17
hw/virtio/vhost-backend.c
··· 172 172 return idx - dev->vq_index; 173 173 } 174 174 175 + #ifdef CONFIG_VHOST_VSOCK 176 + static int vhost_kernel_vsock_set_guest_cid(struct vhost_dev *dev, 177 + uint64_t guest_cid) 178 + { 179 + return vhost_kernel_call(dev, VHOST_VSOCK_SET_GUEST_CID, &guest_cid); 180 + } 181 + 182 + static int vhost_kernel_vsock_set_running(struct vhost_dev *dev, int start) 183 + { 184 + return vhost_kernel_call(dev, VHOST_VSOCK_SET_RUNNING, &start); 185 + } 186 + #endif /* CONFIG_VHOST_VSOCK */ 187 + 175 188 static const VhostOps kernel_ops = { 176 189 .backend_type = VHOST_BACKEND_TYPE_KERNEL, 177 190 .vhost_backend_init = vhost_kernel_init, ··· 197 210 .vhost_set_owner = vhost_kernel_set_owner, 198 211 .vhost_reset_device = vhost_kernel_reset_device, 199 212 .vhost_get_vq_index = vhost_kernel_get_vq_index, 213 + #ifdef CONFIG_VHOST_VSOCK 214 + .vhost_vsock_set_guest_cid = vhost_kernel_vsock_set_guest_cid, 215 + .vhost_vsock_set_running = vhost_kernel_vsock_set_running, 216 + #endif /* CONFIG_VHOST_VSOCK */ 200 217 }; 201 218 202 219 int vhost_set_backend_type(struct vhost_dev *dev, VhostBackendType backend_type)
+417
hw/virtio/vhost-vsock.c
··· 1 + /* 2 + * Virtio vsock device 3 + * 4 + * Copyright 2015 Red Hat, Inc. 5 + * 6 + * Authors: 7 + * Stefan Hajnoczi <stefanha@redhat.com> 8 + * 9 + * This work is licensed under the terms of the GNU GPL, version 2 or 10 + * (at your option) any later version. See the COPYING file in the 11 + * top-level directory. 12 + */ 13 + 14 + #include <sys/ioctl.h> 15 + #include "qemu/osdep.h" 16 + #include "standard-headers/linux/virtio_vsock.h" 17 + #include "qapi/error.h" 18 + #include "hw/virtio/virtio-bus.h" 19 + #include "hw/virtio/virtio-access.h" 20 + #include "migration/migration.h" 21 + #include "qemu/error-report.h" 22 + #include "hw/virtio/vhost-vsock.h" 23 + #include "qemu/iov.h" 24 + #include "monitor/monitor.h" 25 + 26 + enum { 27 + VHOST_VSOCK_SAVEVM_VERSION = 0, 28 + 29 + VHOST_VSOCK_QUEUE_SIZE = 128, 30 + }; 31 + 32 + static void vhost_vsock_get_config(VirtIODevice *vdev, uint8_t *config) 33 + { 34 + VHostVSock *vsock = VHOST_VSOCK(vdev); 35 + struct virtio_vsock_config vsockcfg = {}; 36 + 37 + virtio_stq_p(vdev, &vsockcfg.guest_cid, vsock->conf.guest_cid); 38 + memcpy(config, &vsockcfg, sizeof(vsockcfg)); 39 + } 40 + 41 + static int vhost_vsock_set_guest_cid(VHostVSock *vsock) 42 + { 43 + const VhostOps *vhost_ops = vsock->vhost_dev.vhost_ops; 44 + int ret; 45 + 46 + if (!vhost_ops->vhost_vsock_set_guest_cid) { 47 + return -ENOSYS; 48 + } 49 + 50 + ret = vhost_ops->vhost_vsock_set_guest_cid(&vsock->vhost_dev, 51 + vsock->conf.guest_cid); 52 + if (ret < 0) { 53 + return -errno; 54 + } 55 + return 0; 56 + } 57 + 58 + static int vhost_vsock_set_running(VHostVSock *vsock, int start) 59 + { 60 + const VhostOps *vhost_ops = vsock->vhost_dev.vhost_ops; 61 + int ret; 62 + 63 + if (!vhost_ops->vhost_vsock_set_running) { 64 + return -ENOSYS; 65 + } 66 + 67 + ret = vhost_ops->vhost_vsock_set_running(&vsock->vhost_dev, start); 68 + if (ret < 0) { 69 + return -errno; 70 + } 71 + return 0; 72 + } 73 + 74 + static void vhost_vsock_start(VirtIODevice *vdev) 75 + { 76 + VHostVSock *vsock = VHOST_VSOCK(vdev); 77 + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); 78 + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 79 + int ret; 80 + int i; 81 + 82 + if (!k->set_guest_notifiers) { 83 + error_report("binding does not support guest notifiers"); 84 + return; 85 + } 86 + 87 + ret = vhost_dev_enable_notifiers(&vsock->vhost_dev, vdev); 88 + if (ret < 0) { 89 + error_report("Error enabling host notifiers: %d", -ret); 90 + return; 91 + } 92 + 93 + ret = k->set_guest_notifiers(qbus->parent, vsock->vhost_dev.nvqs, true); 94 + if (ret < 0) { 95 + error_report("Error binding guest notifier: %d", -ret); 96 + goto err_host_notifiers; 97 + } 98 + 99 + vsock->vhost_dev.acked_features = vdev->guest_features; 100 + ret = vhost_dev_start(&vsock->vhost_dev, vdev); 101 + if (ret < 0) { 102 + error_report("Error starting vhost: %d", -ret); 103 + goto err_guest_notifiers; 104 + } 105 + 106 + ret = vhost_vsock_set_running(vsock, 1); 107 + if (ret < 0) { 108 + error_report("Error starting vhost vsock: %d", -ret); 109 + goto err_dev_start; 110 + } 111 + 112 + /* guest_notifier_mask/pending not used yet, so just unmask 113 + * everything here. virtio-pci will do the right thing by 114 + * enabling/disabling irqfd. 115 + */ 116 + for (i = 0; i < vsock->vhost_dev.nvqs; i++) { 117 + vhost_virtqueue_mask(&vsock->vhost_dev, vdev, i, false); 118 + } 119 + 120 + return; 121 + 122 + err_dev_start: 123 + vhost_dev_stop(&vsock->vhost_dev, vdev); 124 + err_guest_notifiers: 125 + k->set_guest_notifiers(qbus->parent, vsock->vhost_dev.nvqs, false); 126 + err_host_notifiers: 127 + vhost_dev_disable_notifiers(&vsock->vhost_dev, vdev); 128 + } 129 + 130 + static void vhost_vsock_stop(VirtIODevice *vdev) 131 + { 132 + VHostVSock *vsock = VHOST_VSOCK(vdev); 133 + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); 134 + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 135 + int ret; 136 + 137 + if (!k->set_guest_notifiers) { 138 + return; 139 + } 140 + 141 + ret = vhost_vsock_set_running(vsock, 0); 142 + if (ret < 0) { 143 + error_report("vhost vsock set running failed: %d", ret); 144 + return; 145 + } 146 + 147 + vhost_dev_stop(&vsock->vhost_dev, vdev); 148 + 149 + ret = k->set_guest_notifiers(qbus->parent, vsock->vhost_dev.nvqs, false); 150 + if (ret < 0) { 151 + error_report("vhost guest notifier cleanup failed: %d", ret); 152 + return; 153 + } 154 + 155 + vhost_dev_disable_notifiers(&vsock->vhost_dev, vdev); 156 + } 157 + 158 + static void vhost_vsock_set_status(VirtIODevice *vdev, uint8_t status) 159 + { 160 + VHostVSock *vsock = VHOST_VSOCK(vdev); 161 + bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK; 162 + 163 + if (!vdev->vm_running) { 164 + should_start = false; 165 + } 166 + 167 + if (vsock->vhost_dev.started == should_start) { 168 + return; 169 + } 170 + 171 + if (should_start) { 172 + vhost_vsock_start(vdev); 173 + } else { 174 + vhost_vsock_stop(vdev); 175 + } 176 + } 177 + 178 + static uint64_t vhost_vsock_get_features(VirtIODevice *vdev, 179 + uint64_t requested_features, 180 + Error **errp) 181 + { 182 + /* No feature bits used yet */ 183 + return requested_features; 184 + } 185 + 186 + static void vhost_vsock_handle_output(VirtIODevice *vdev, VirtQueue *vq) 187 + { 188 + /* Do nothing */ 189 + } 190 + 191 + static void vhost_vsock_guest_notifier_mask(VirtIODevice *vdev, int idx, 192 + bool mask) 193 + { 194 + VHostVSock *vsock = VHOST_VSOCK(vdev); 195 + 196 + vhost_virtqueue_mask(&vsock->vhost_dev, vdev, idx, mask); 197 + } 198 + 199 + static bool vhost_vsock_guest_notifier_pending(VirtIODevice *vdev, int idx) 200 + { 201 + VHostVSock *vsock = VHOST_VSOCK(vdev); 202 + 203 + return vhost_virtqueue_pending(&vsock->vhost_dev, idx); 204 + } 205 + 206 + static void vhost_vsock_send_transport_reset(VHostVSock *vsock) 207 + { 208 + VirtQueueElement *elem; 209 + VirtQueue *vq = vsock->event_vq; 210 + struct virtio_vsock_event event = { 211 + .id = cpu_to_le32(VIRTIO_VSOCK_EVENT_TRANSPORT_RESET), 212 + }; 213 + 214 + elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); 215 + if (!elem) { 216 + error_report("vhost-vsock missed transport reset event"); 217 + return; 218 + } 219 + 220 + if (elem->out_num) { 221 + error_report("invalid vhost-vsock event virtqueue element with " 222 + "out buffers"); 223 + goto out; 224 + } 225 + 226 + if (iov_from_buf(elem->in_sg, elem->in_num, 0, 227 + &event, sizeof(event)) != sizeof(event)) { 228 + error_report("vhost-vsock event virtqueue element is too short"); 229 + goto out; 230 + } 231 + 232 + virtqueue_push(vq, elem, sizeof(event)); 233 + virtio_notify(VIRTIO_DEVICE(vsock), vq); 234 + 235 + out: 236 + g_free(elem); 237 + } 238 + 239 + static void vhost_vsock_save(QEMUFile *f, void *opaque, size_t size) 240 + { 241 + VHostVSock *vsock = opaque; 242 + VirtIODevice *vdev = VIRTIO_DEVICE(vsock); 243 + 244 + /* At this point, backend must be stopped, otherwise 245 + * it might keep writing to memory. */ 246 + assert(!vsock->vhost_dev.started); 247 + virtio_save(vdev, f); 248 + } 249 + 250 + static void vhost_vsock_post_load_timer_cleanup(VHostVSock *vsock) 251 + { 252 + if (!vsock->post_load_timer) { 253 + return; 254 + } 255 + 256 + timer_del(vsock->post_load_timer); 257 + timer_free(vsock->post_load_timer); 258 + vsock->post_load_timer = NULL; 259 + } 260 + 261 + static void vhost_vsock_post_load_timer_cb(void *opaque) 262 + { 263 + VHostVSock *vsock = opaque; 264 + 265 + vhost_vsock_post_load_timer_cleanup(vsock); 266 + vhost_vsock_send_transport_reset(vsock); 267 + } 268 + 269 + static int vhost_vsock_load(QEMUFile *f, void *opaque, size_t size) 270 + { 271 + VHostVSock *vsock = opaque; 272 + VirtIODevice *vdev = VIRTIO_DEVICE(vsock); 273 + int ret; 274 + 275 + ret = virtio_load(vdev, f, VHOST_VSOCK_SAVEVM_VERSION); 276 + if (ret) { 277 + return ret; 278 + } 279 + 280 + if (virtio_queue_get_addr(vdev, 2)) { 281 + /* Defer transport reset event to a vm clock timer so that virtqueue 282 + * changes happen after migration has completed. 283 + */ 284 + assert(!vsock->post_load_timer); 285 + vsock->post_load_timer = 286 + timer_new_ns(QEMU_CLOCK_VIRTUAL, 287 + vhost_vsock_post_load_timer_cb, 288 + vsock); 289 + timer_mod(vsock->post_load_timer, 1); 290 + } 291 + 292 + return 0; 293 + } 294 + 295 + VMSTATE_VIRTIO_DEVICE(vhost_vsock, VHOST_VSOCK_SAVEVM_VERSION, 296 + vhost_vsock_load, vhost_vsock_save); 297 + 298 + static void vhost_vsock_device_realize(DeviceState *dev, Error **errp) 299 + { 300 + VirtIODevice *vdev = VIRTIO_DEVICE(dev); 301 + VHostVSock *vsock = VHOST_VSOCK(dev); 302 + int vhostfd; 303 + int ret; 304 + 305 + /* Refuse to use reserved CID numbers */ 306 + if (vsock->conf.guest_cid <= 2) { 307 + error_setg(errp, "guest-cid property must be greater than 2"); 308 + return; 309 + } 310 + 311 + if (vsock->conf.guest_cid > UINT32_MAX) { 312 + error_setg(errp, "guest-cid property must be a 32-bit number"); 313 + return; 314 + } 315 + 316 + if (vsock->conf.vhostfd) { 317 + vhostfd = monitor_fd_param(cur_mon, vsock->conf.vhostfd, errp); 318 + if (vhostfd == -1) { 319 + error_prepend(errp, "vhost-vsock: unable to parse vhostfd: "); 320 + return; 321 + } 322 + } else { 323 + vhostfd = open("/dev/vhost-vsock", O_RDWR); 324 + if (vhostfd < 0) { 325 + error_setg_errno(errp, -errno, 326 + "vhost-vsock: failed to open vhost device"); 327 + return; 328 + } 329 + } 330 + 331 + virtio_init(vdev, "vhost-vsock", VIRTIO_ID_VSOCK, 332 + sizeof(struct virtio_vsock_config)); 333 + 334 + /* Receive and transmit queues belong to vhost */ 335 + virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, vhost_vsock_handle_output); 336 + virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, vhost_vsock_handle_output); 337 + 338 + /* The event queue belongs to QEMU */ 339 + vsock->event_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, 340 + vhost_vsock_handle_output); 341 + 342 + vsock->vhost_dev.nvqs = ARRAY_SIZE(vsock->vhost_vqs); 343 + vsock->vhost_dev.vqs = vsock->vhost_vqs; 344 + ret = vhost_dev_init(&vsock->vhost_dev, (void *)(uintptr_t)vhostfd, 345 + VHOST_BACKEND_TYPE_KERNEL, 0); 346 + if (ret < 0) { 347 + error_setg_errno(errp, -ret, "vhost-vsock: vhost_dev_init failed"); 348 + goto err_virtio; 349 + } 350 + 351 + ret = vhost_vsock_set_guest_cid(vsock); 352 + if (ret < 0) { 353 + error_setg_errno(errp, -ret, "vhost-vsock: unable to set guest cid"); 354 + goto err_vhost_dev; 355 + } 356 + 357 + vsock->post_load_timer = NULL; 358 + return; 359 + 360 + err_vhost_dev: 361 + vhost_dev_cleanup(&vsock->vhost_dev); 362 + err_virtio: 363 + virtio_cleanup(vdev); 364 + close(vhostfd); 365 + return; 366 + } 367 + 368 + static void vhost_vsock_device_unrealize(DeviceState *dev, Error **errp) 369 + { 370 + VirtIODevice *vdev = VIRTIO_DEVICE(dev); 371 + VHostVSock *vsock = VHOST_VSOCK(dev); 372 + 373 + vhost_vsock_post_load_timer_cleanup(vsock); 374 + 375 + /* This will stop vhost backend if appropriate. */ 376 + vhost_vsock_set_status(vdev, 0); 377 + 378 + vhost_dev_cleanup(&vsock->vhost_dev); 379 + virtio_cleanup(vdev); 380 + } 381 + 382 + static Property vhost_vsock_properties[] = { 383 + DEFINE_PROP_UINT64("guest-cid", VHostVSock, conf.guest_cid, 0), 384 + DEFINE_PROP_STRING("vhostfd", VHostVSock, conf.vhostfd), 385 + DEFINE_PROP_END_OF_LIST(), 386 + }; 387 + 388 + static void vhost_vsock_class_init(ObjectClass *klass, void *data) 389 + { 390 + DeviceClass *dc = DEVICE_CLASS(klass); 391 + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 392 + 393 + dc->props = vhost_vsock_properties; 394 + dc->vmsd = &vmstate_virtio_vhost_vsock; 395 + set_bit(DEVICE_CATEGORY_MISC, dc->categories); 396 + vdc->realize = vhost_vsock_device_realize; 397 + vdc->unrealize = vhost_vsock_device_unrealize; 398 + vdc->get_features = vhost_vsock_get_features; 399 + vdc->get_config = vhost_vsock_get_config; 400 + vdc->set_status = vhost_vsock_set_status; 401 + vdc->guest_notifier_mask = vhost_vsock_guest_notifier_mask; 402 + vdc->guest_notifier_pending = vhost_vsock_guest_notifier_pending; 403 + } 404 + 405 + static const TypeInfo vhost_vsock_info = { 406 + .name = TYPE_VHOST_VSOCK, 407 + .parent = TYPE_VIRTIO_DEVICE, 408 + .instance_size = sizeof(VHostVSock), 409 + .class_init = vhost_vsock_class_init, 410 + }; 411 + 412 + static void vhost_vsock_register_types(void) 413 + { 414 + type_register_static(&vhost_vsock_info); 415 + } 416 + 417 + type_init(vhost_vsock_register_types)
+51
hw/virtio/virtio-pci.c
··· 2071 2071 }; 2072 2072 #endif 2073 2073 2074 + /* vhost-vsock-pci */ 2075 + 2076 + #ifdef CONFIG_VHOST_VSOCK 2077 + static Property vhost_vsock_pci_properties[] = { 2078 + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3), 2079 + DEFINE_PROP_END_OF_LIST(), 2080 + }; 2081 + 2082 + static void vhost_vsock_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) 2083 + { 2084 + VHostVSockPCI *dev = VHOST_VSOCK_PCI(vpci_dev); 2085 + DeviceState *vdev = DEVICE(&dev->vdev); 2086 + 2087 + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); 2088 + object_property_set_bool(OBJECT(vdev), true, "realized", errp); 2089 + } 2090 + 2091 + static void vhost_vsock_pci_class_init(ObjectClass *klass, void *data) 2092 + { 2093 + DeviceClass *dc = DEVICE_CLASS(klass); 2094 + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); 2095 + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); 2096 + k->realize = vhost_vsock_pci_realize; 2097 + set_bit(DEVICE_CATEGORY_MISC, dc->categories); 2098 + dc->props = vhost_vsock_pci_properties; 2099 + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; 2100 + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_VSOCK; 2101 + pcidev_k->revision = 0x00; 2102 + pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER; 2103 + } 2104 + 2105 + static void vhost_vsock_pci_instance_init(Object *obj) 2106 + { 2107 + VHostVSockPCI *dev = VHOST_VSOCK_PCI(obj); 2108 + 2109 + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), 2110 + TYPE_VHOST_VSOCK); 2111 + } 2112 + 2113 + static const TypeInfo vhost_vsock_pci_info = { 2114 + .name = TYPE_VHOST_VSOCK_PCI, 2115 + .parent = TYPE_VIRTIO_PCI, 2116 + .instance_size = sizeof(VHostVSockPCI), 2117 + .instance_init = vhost_vsock_pci_instance_init, 2118 + .class_init = vhost_vsock_pci_class_init, 2119 + }; 2120 + #endif 2121 + 2074 2122 /* virtio-balloon-pci */ 2075 2123 2076 2124 static Property virtio_balloon_pci_properties[] = { ··· 2500 2548 type_register_static(&virtio_net_pci_info); 2501 2549 #ifdef CONFIG_VHOST_SCSI 2502 2550 type_register_static(&vhost_scsi_pci_info); 2551 + #endif 2552 + #ifdef CONFIG_VHOST_VSOCK 2553 + type_register_static(&vhost_vsock_pci_info); 2503 2554 #endif 2504 2555 } 2505 2556
+18
hw/virtio/virtio-pci.h
··· 31 31 #ifdef CONFIG_VHOST_SCSI 32 32 #include "hw/virtio/vhost-scsi.h" 33 33 #endif 34 + #ifdef CONFIG_VHOST_VSOCK 35 + #include "hw/virtio/vhost-vsock.h" 36 + #endif 34 37 35 38 typedef struct VirtIOPCIProxy VirtIOPCIProxy; 36 39 typedef struct VirtIOBlkPCI VirtIOBlkPCI; ··· 44 47 typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI; 45 48 typedef struct VirtIOInputHostPCI VirtIOInputHostPCI; 46 49 typedef struct VirtIOGPUPCI VirtIOGPUPCI; 50 + typedef struct VHostVSockPCI VHostVSockPCI; 47 51 48 52 /* virtio-pci-bus */ 49 53 ··· 328 332 VirtIOPCIProxy parent_obj; 329 333 VirtIOGPU vdev; 330 334 }; 335 + 336 + #ifdef CONFIG_VHOST_VSOCK 337 + /* 338 + * vhost-vsock-pci: This extends VirtioPCIProxy. 339 + */ 340 + #define TYPE_VHOST_VSOCK_PCI "vhost-vsock-pci" 341 + #define VHOST_VSOCK_PCI(obj) \ 342 + OBJECT_CHECK(VHostVSockPCI, (obj), TYPE_VHOST_VSOCK_PCI) 343 + 344 + struct VHostVSockPCI { 345 + VirtIOPCIProxy parent_obj; 346 + VHostVSock vdev; 347 + }; 348 + #endif 331 349 332 350 /* Virtio ABI version, if we increment this, we break the guest driver. */ 333 351 #define VIRTIO_PCI_ABI_VERSION 0
+1
include/hw/pci/pci.h
··· 79 79 #define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004 80 80 #define PCI_DEVICE_ID_VIRTIO_RNG 0x1005 81 81 #define PCI_DEVICE_ID_VIRTIO_9P 0x1009 82 + #define PCI_DEVICE_ID_VIRTIO_VSOCK 0x1012 82 83 83 84 #define PCI_VENDOR_ID_REDHAT 0x1b36 84 85 #define PCI_DEVICE_ID_REDHAT_BRIDGE 0x0001
+5
include/hw/virtio/vhost-backend.h
··· 73 73 typedef bool (*vhost_backend_can_merge_op)(struct vhost_dev *dev, 74 74 uint64_t start1, uint64_t size1, 75 75 uint64_t start2, uint64_t size2); 76 + typedef int (*vhost_vsock_set_guest_cid_op)(struct vhost_dev *dev, 77 + uint64_t guest_cid); 78 + typedef int (*vhost_vsock_set_running_op)(struct vhost_dev *dev, int start); 76 79 77 80 typedef struct VhostOps { 78 81 VhostBackendType backend_type; ··· 102 105 vhost_requires_shm_log_op vhost_requires_shm_log; 103 106 vhost_migration_done_op vhost_migration_done; 104 107 vhost_backend_can_merge_op vhost_backend_can_merge; 108 + vhost_vsock_set_guest_cid_op vhost_vsock_set_guest_cid; 109 + vhost_vsock_set_running_op vhost_vsock_set_running; 105 110 } VhostOps; 106 111 107 112 extern const VhostOps user_ops;
+41
include/hw/virtio/vhost-vsock.h
··· 1 + /* 2 + * Vhost vsock virtio device 3 + * 4 + * Copyright 2015 Red Hat, Inc. 5 + * 6 + * Authors: 7 + * Stefan Hajnoczi <stefanha@redhat.com> 8 + * 9 + * This work is licensed under the terms of the GNU GPL, version 2 or 10 + * (at your option) any later version. See the COPYING file in the 11 + * top-level directory. 12 + */ 13 + 14 + #ifndef _QEMU_VHOST_VSOCK_H 15 + #define _QEMU_VHOST_VSOCK_H 16 + 17 + #include "hw/virtio/virtio.h" 18 + #include "hw/virtio/vhost.h" 19 + 20 + #define TYPE_VHOST_VSOCK "vhost-vsock-device" 21 + #define VHOST_VSOCK(obj) \ 22 + OBJECT_CHECK(VHostVSock, (obj), TYPE_VHOST_VSOCK) 23 + 24 + typedef struct { 25 + uint64_t guest_cid; 26 + char *vhostfd; 27 + } VHostVSockConf; 28 + 29 + typedef struct { 30 + /*< private >*/ 31 + VirtIODevice parent; 32 + VHostVSockConf conf; 33 + struct vhost_virtqueue vhost_vqs[2]; 34 + struct vhost_dev vhost_dev; 35 + VirtQueue *event_vq; 36 + QEMUTimer *post_load_timer; 37 + 38 + /*< public >*/ 39 + } VHostVSock; 40 + 41 + #endif /* _QEMU_VHOST_VSOCK_H */