1fc0b9b0eSStefan Hajnoczi /* 2fc0b9b0eSStefan Hajnoczi * Virtio vsock device 3fc0b9b0eSStefan Hajnoczi * 4fc0b9b0eSStefan Hajnoczi * Copyright 2015 Red Hat, Inc. 5fc0b9b0eSStefan Hajnoczi * 6fc0b9b0eSStefan Hajnoczi * Authors: 7fc0b9b0eSStefan Hajnoczi * Stefan Hajnoczi <stefanha@redhat.com> 8fc0b9b0eSStefan Hajnoczi * 9fc0b9b0eSStefan Hajnoczi * This work is licensed under the terms of the GNU GPL, version 2 or 10fc0b9b0eSStefan Hajnoczi * (at your option) any later version. See the COPYING file in the 11fc0b9b0eSStefan Hajnoczi * top-level directory. 12fc0b9b0eSStefan Hajnoczi */ 13fc0b9b0eSStefan Hajnoczi 14fc0b9b0eSStefan Hajnoczi #include "qemu/osdep.h" 15e9808d09SPhilippe Mathieu-Daudé #include <sys/ioctl.h> 16fc0b9b0eSStefan Hajnoczi #include "standard-headers/linux/virtio_vsock.h" 17fc0b9b0eSStefan Hajnoczi #include "qapi/error.h" 18fc0b9b0eSStefan Hajnoczi #include "hw/virtio/virtio-bus.h" 19fc0b9b0eSStefan Hajnoczi #include "hw/virtio/virtio-access.h" 20fc0b9b0eSStefan Hajnoczi #include "qemu/error-report.h" 21a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 22fc0b9b0eSStefan Hajnoczi #include "hw/virtio/vhost-vsock.h" 23fc0b9b0eSStefan Hajnoczi #include "qemu/iov.h" 240b8fa32fSMarkus Armbruster #include "qemu/module.h" 25fc0b9b0eSStefan Hajnoczi #include "monitor/monitor.h" 26fc0b9b0eSStefan Hajnoczi 27fc0b9b0eSStefan Hajnoczi enum { 28fc0b9b0eSStefan Hajnoczi VHOST_VSOCK_SAVEVM_VERSION = 0, 29fc0b9b0eSStefan Hajnoczi 30fc0b9b0eSStefan Hajnoczi VHOST_VSOCK_QUEUE_SIZE = 128, 31fc0b9b0eSStefan Hajnoczi }; 32fc0b9b0eSStefan Hajnoczi 33fc0b9b0eSStefan Hajnoczi static void vhost_vsock_get_config(VirtIODevice *vdev, uint8_t *config) 34fc0b9b0eSStefan Hajnoczi { 35fc0b9b0eSStefan Hajnoczi VHostVSock *vsock = VHOST_VSOCK(vdev); 36fc0b9b0eSStefan Hajnoczi struct virtio_vsock_config vsockcfg = {}; 37fc0b9b0eSStefan Hajnoczi 38fc0b9b0eSStefan Hajnoczi virtio_stq_p(vdev, &vsockcfg.guest_cid, vsock->conf.guest_cid); 39fc0b9b0eSStefan Hajnoczi memcpy(config, &vsockcfg, sizeof(vsockcfg)); 40fc0b9b0eSStefan Hajnoczi } 41fc0b9b0eSStefan Hajnoczi 42fc0b9b0eSStefan Hajnoczi static int vhost_vsock_set_guest_cid(VHostVSock *vsock) 43fc0b9b0eSStefan Hajnoczi { 44fc0b9b0eSStefan Hajnoczi const VhostOps *vhost_ops = vsock->vhost_dev.vhost_ops; 45fc0b9b0eSStefan Hajnoczi int ret; 46fc0b9b0eSStefan Hajnoczi 47fc0b9b0eSStefan Hajnoczi if (!vhost_ops->vhost_vsock_set_guest_cid) { 48fc0b9b0eSStefan Hajnoczi return -ENOSYS; 49fc0b9b0eSStefan Hajnoczi } 50fc0b9b0eSStefan Hajnoczi 51fc0b9b0eSStefan Hajnoczi ret = vhost_ops->vhost_vsock_set_guest_cid(&vsock->vhost_dev, 52fc0b9b0eSStefan Hajnoczi vsock->conf.guest_cid); 53fc0b9b0eSStefan Hajnoczi if (ret < 0) { 54fc0b9b0eSStefan Hajnoczi return -errno; 55fc0b9b0eSStefan Hajnoczi } 56fc0b9b0eSStefan Hajnoczi return 0; 57fc0b9b0eSStefan Hajnoczi } 58fc0b9b0eSStefan Hajnoczi 59fc0b9b0eSStefan Hajnoczi static int vhost_vsock_set_running(VHostVSock *vsock, int start) 60fc0b9b0eSStefan Hajnoczi { 61fc0b9b0eSStefan Hajnoczi const VhostOps *vhost_ops = vsock->vhost_dev.vhost_ops; 62fc0b9b0eSStefan Hajnoczi int ret; 63fc0b9b0eSStefan Hajnoczi 64fc0b9b0eSStefan Hajnoczi if (!vhost_ops->vhost_vsock_set_running) { 65fc0b9b0eSStefan Hajnoczi return -ENOSYS; 66fc0b9b0eSStefan Hajnoczi } 67fc0b9b0eSStefan Hajnoczi 68fc0b9b0eSStefan Hajnoczi ret = vhost_ops->vhost_vsock_set_running(&vsock->vhost_dev, start); 69fc0b9b0eSStefan Hajnoczi if (ret < 0) { 70fc0b9b0eSStefan Hajnoczi return -errno; 71fc0b9b0eSStefan Hajnoczi } 72fc0b9b0eSStefan Hajnoczi return 0; 73fc0b9b0eSStefan Hajnoczi } 74fc0b9b0eSStefan Hajnoczi 75fc0b9b0eSStefan Hajnoczi static void vhost_vsock_start(VirtIODevice *vdev) 76fc0b9b0eSStefan Hajnoczi { 77fc0b9b0eSStefan Hajnoczi VHostVSock *vsock = VHOST_VSOCK(vdev); 78fc0b9b0eSStefan Hajnoczi BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); 79fc0b9b0eSStefan Hajnoczi VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 80fc0b9b0eSStefan Hajnoczi int ret; 81fc0b9b0eSStefan Hajnoczi int i; 82fc0b9b0eSStefan Hajnoczi 83fc0b9b0eSStefan Hajnoczi if (!k->set_guest_notifiers) { 84fc0b9b0eSStefan Hajnoczi error_report("binding does not support guest notifiers"); 85fc0b9b0eSStefan Hajnoczi return; 86fc0b9b0eSStefan Hajnoczi } 87fc0b9b0eSStefan Hajnoczi 88fc0b9b0eSStefan Hajnoczi ret = vhost_dev_enable_notifiers(&vsock->vhost_dev, vdev); 89fc0b9b0eSStefan Hajnoczi if (ret < 0) { 90fc0b9b0eSStefan Hajnoczi error_report("Error enabling host notifiers: %d", -ret); 91fc0b9b0eSStefan Hajnoczi return; 92fc0b9b0eSStefan Hajnoczi } 93fc0b9b0eSStefan Hajnoczi 94fc0b9b0eSStefan Hajnoczi ret = k->set_guest_notifiers(qbus->parent, vsock->vhost_dev.nvqs, true); 95fc0b9b0eSStefan Hajnoczi if (ret < 0) { 96fc0b9b0eSStefan Hajnoczi error_report("Error binding guest notifier: %d", -ret); 97fc0b9b0eSStefan Hajnoczi goto err_host_notifiers; 98fc0b9b0eSStefan Hajnoczi } 99fc0b9b0eSStefan Hajnoczi 100fc0b9b0eSStefan Hajnoczi vsock->vhost_dev.acked_features = vdev->guest_features; 101fc0b9b0eSStefan Hajnoczi ret = vhost_dev_start(&vsock->vhost_dev, vdev); 102fc0b9b0eSStefan Hajnoczi if (ret < 0) { 103fc0b9b0eSStefan Hajnoczi error_report("Error starting vhost: %d", -ret); 104fc0b9b0eSStefan Hajnoczi goto err_guest_notifiers; 105fc0b9b0eSStefan Hajnoczi } 106fc0b9b0eSStefan Hajnoczi 107fc0b9b0eSStefan Hajnoczi ret = vhost_vsock_set_running(vsock, 1); 108fc0b9b0eSStefan Hajnoczi if (ret < 0) { 109fc0b9b0eSStefan Hajnoczi error_report("Error starting vhost vsock: %d", -ret); 110fc0b9b0eSStefan Hajnoczi goto err_dev_start; 111fc0b9b0eSStefan Hajnoczi } 112fc0b9b0eSStefan Hajnoczi 113fc0b9b0eSStefan Hajnoczi /* guest_notifier_mask/pending not used yet, so just unmask 114fc0b9b0eSStefan Hajnoczi * everything here. virtio-pci will do the right thing by 115fc0b9b0eSStefan Hajnoczi * enabling/disabling irqfd. 116fc0b9b0eSStefan Hajnoczi */ 117fc0b9b0eSStefan Hajnoczi for (i = 0; i < vsock->vhost_dev.nvqs; i++) { 118fc0b9b0eSStefan Hajnoczi vhost_virtqueue_mask(&vsock->vhost_dev, vdev, i, false); 119fc0b9b0eSStefan Hajnoczi } 120fc0b9b0eSStefan Hajnoczi 121fc0b9b0eSStefan Hajnoczi return; 122fc0b9b0eSStefan Hajnoczi 123fc0b9b0eSStefan Hajnoczi err_dev_start: 124fc0b9b0eSStefan Hajnoczi vhost_dev_stop(&vsock->vhost_dev, vdev); 125fc0b9b0eSStefan Hajnoczi err_guest_notifiers: 126fc0b9b0eSStefan Hajnoczi k->set_guest_notifiers(qbus->parent, vsock->vhost_dev.nvqs, false); 127fc0b9b0eSStefan Hajnoczi err_host_notifiers: 128fc0b9b0eSStefan Hajnoczi vhost_dev_disable_notifiers(&vsock->vhost_dev, vdev); 129fc0b9b0eSStefan Hajnoczi } 130fc0b9b0eSStefan Hajnoczi 131fc0b9b0eSStefan Hajnoczi static void vhost_vsock_stop(VirtIODevice *vdev) 132fc0b9b0eSStefan Hajnoczi { 133fc0b9b0eSStefan Hajnoczi VHostVSock *vsock = VHOST_VSOCK(vdev); 134fc0b9b0eSStefan Hajnoczi BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); 135fc0b9b0eSStefan Hajnoczi VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 136fc0b9b0eSStefan Hajnoczi int ret; 137fc0b9b0eSStefan Hajnoczi 138fc0b9b0eSStefan Hajnoczi if (!k->set_guest_notifiers) { 139fc0b9b0eSStefan Hajnoczi return; 140fc0b9b0eSStefan Hajnoczi } 141fc0b9b0eSStefan Hajnoczi 142fc0b9b0eSStefan Hajnoczi ret = vhost_vsock_set_running(vsock, 0); 143fc0b9b0eSStefan Hajnoczi if (ret < 0) { 144fc0b9b0eSStefan Hajnoczi error_report("vhost vsock set running failed: %d", ret); 145fc0b9b0eSStefan Hajnoczi return; 146fc0b9b0eSStefan Hajnoczi } 147fc0b9b0eSStefan Hajnoczi 148fc0b9b0eSStefan Hajnoczi vhost_dev_stop(&vsock->vhost_dev, vdev); 149fc0b9b0eSStefan Hajnoczi 150fc0b9b0eSStefan Hajnoczi ret = k->set_guest_notifiers(qbus->parent, vsock->vhost_dev.nvqs, false); 151fc0b9b0eSStefan Hajnoczi if (ret < 0) { 152fc0b9b0eSStefan Hajnoczi error_report("vhost guest notifier cleanup failed: %d", ret); 153fc0b9b0eSStefan Hajnoczi return; 154fc0b9b0eSStefan Hajnoczi } 155fc0b9b0eSStefan Hajnoczi 156fc0b9b0eSStefan Hajnoczi vhost_dev_disable_notifiers(&vsock->vhost_dev, vdev); 157fc0b9b0eSStefan Hajnoczi } 158fc0b9b0eSStefan Hajnoczi 159fc0b9b0eSStefan Hajnoczi static void vhost_vsock_set_status(VirtIODevice *vdev, uint8_t status) 160fc0b9b0eSStefan Hajnoczi { 161fc0b9b0eSStefan Hajnoczi VHostVSock *vsock = VHOST_VSOCK(vdev); 162fc0b9b0eSStefan Hajnoczi bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK; 163fc0b9b0eSStefan Hajnoczi 164fc0b9b0eSStefan Hajnoczi if (!vdev->vm_running) { 165fc0b9b0eSStefan Hajnoczi should_start = false; 166fc0b9b0eSStefan Hajnoczi } 167fc0b9b0eSStefan Hajnoczi 168fc0b9b0eSStefan Hajnoczi if (vsock->vhost_dev.started == should_start) { 169fc0b9b0eSStefan Hajnoczi return; 170fc0b9b0eSStefan Hajnoczi } 171fc0b9b0eSStefan Hajnoczi 172fc0b9b0eSStefan Hajnoczi if (should_start) { 173fc0b9b0eSStefan Hajnoczi vhost_vsock_start(vdev); 174fc0b9b0eSStefan Hajnoczi } else { 175fc0b9b0eSStefan Hajnoczi vhost_vsock_stop(vdev); 176fc0b9b0eSStefan Hajnoczi } 177fc0b9b0eSStefan Hajnoczi } 178fc0b9b0eSStefan Hajnoczi 179fc0b9b0eSStefan Hajnoczi static uint64_t vhost_vsock_get_features(VirtIODevice *vdev, 180fc0b9b0eSStefan Hajnoczi uint64_t requested_features, 181fc0b9b0eSStefan Hajnoczi Error **errp) 182fc0b9b0eSStefan Hajnoczi { 183fc0b9b0eSStefan Hajnoczi /* No feature bits used yet */ 184fc0b9b0eSStefan Hajnoczi return requested_features; 185fc0b9b0eSStefan Hajnoczi } 186fc0b9b0eSStefan Hajnoczi 187fc0b9b0eSStefan Hajnoczi static void vhost_vsock_handle_output(VirtIODevice *vdev, VirtQueue *vq) 188fc0b9b0eSStefan Hajnoczi { 189fc0b9b0eSStefan Hajnoczi /* Do nothing */ 190fc0b9b0eSStefan Hajnoczi } 191fc0b9b0eSStefan Hajnoczi 192fc0b9b0eSStefan Hajnoczi static void vhost_vsock_guest_notifier_mask(VirtIODevice *vdev, int idx, 193fc0b9b0eSStefan Hajnoczi bool mask) 194fc0b9b0eSStefan Hajnoczi { 195fc0b9b0eSStefan Hajnoczi VHostVSock *vsock = VHOST_VSOCK(vdev); 196fc0b9b0eSStefan Hajnoczi 197fc0b9b0eSStefan Hajnoczi vhost_virtqueue_mask(&vsock->vhost_dev, vdev, idx, mask); 198fc0b9b0eSStefan Hajnoczi } 199fc0b9b0eSStefan Hajnoczi 200fc0b9b0eSStefan Hajnoczi static bool vhost_vsock_guest_notifier_pending(VirtIODevice *vdev, int idx) 201fc0b9b0eSStefan Hajnoczi { 202fc0b9b0eSStefan Hajnoczi VHostVSock *vsock = VHOST_VSOCK(vdev); 203fc0b9b0eSStefan Hajnoczi 204fc0b9b0eSStefan Hajnoczi return vhost_virtqueue_pending(&vsock->vhost_dev, idx); 205fc0b9b0eSStefan Hajnoczi } 206fc0b9b0eSStefan Hajnoczi 207fc0b9b0eSStefan Hajnoczi static void vhost_vsock_send_transport_reset(VHostVSock *vsock) 208fc0b9b0eSStefan Hajnoczi { 209fc0b9b0eSStefan Hajnoczi VirtQueueElement *elem; 210fc0b9b0eSStefan Hajnoczi VirtQueue *vq = vsock->event_vq; 211fc0b9b0eSStefan Hajnoczi struct virtio_vsock_event event = { 212fc0b9b0eSStefan Hajnoczi .id = cpu_to_le32(VIRTIO_VSOCK_EVENT_TRANSPORT_RESET), 213fc0b9b0eSStefan Hajnoczi }; 214fc0b9b0eSStefan Hajnoczi 215fc0b9b0eSStefan Hajnoczi elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); 216fc0b9b0eSStefan Hajnoczi if (!elem) { 217fc0b9b0eSStefan Hajnoczi error_report("vhost-vsock missed transport reset event"); 218fc0b9b0eSStefan Hajnoczi return; 219fc0b9b0eSStefan Hajnoczi } 220fc0b9b0eSStefan Hajnoczi 221fc0b9b0eSStefan Hajnoczi if (elem->out_num) { 222fc0b9b0eSStefan Hajnoczi error_report("invalid vhost-vsock event virtqueue element with " 223fc0b9b0eSStefan Hajnoczi "out buffers"); 224fc0b9b0eSStefan Hajnoczi goto out; 225fc0b9b0eSStefan Hajnoczi } 226fc0b9b0eSStefan Hajnoczi 227fc0b9b0eSStefan Hajnoczi if (iov_from_buf(elem->in_sg, elem->in_num, 0, 228fc0b9b0eSStefan Hajnoczi &event, sizeof(event)) != sizeof(event)) { 229fc0b9b0eSStefan Hajnoczi error_report("vhost-vsock event virtqueue element is too short"); 230fc0b9b0eSStefan Hajnoczi goto out; 231fc0b9b0eSStefan Hajnoczi } 232fc0b9b0eSStefan Hajnoczi 233fc0b9b0eSStefan Hajnoczi virtqueue_push(vq, elem, sizeof(event)); 234fc0b9b0eSStefan Hajnoczi virtio_notify(VIRTIO_DEVICE(vsock), vq); 235fc0b9b0eSStefan Hajnoczi 236fc0b9b0eSStefan Hajnoczi out: 237fc0b9b0eSStefan Hajnoczi g_free(elem); 238fc0b9b0eSStefan Hajnoczi } 239fc0b9b0eSStefan Hajnoczi 240fc0b9b0eSStefan Hajnoczi static void vhost_vsock_post_load_timer_cleanup(VHostVSock *vsock) 241fc0b9b0eSStefan Hajnoczi { 242fc0b9b0eSStefan Hajnoczi if (!vsock->post_load_timer) { 243fc0b9b0eSStefan Hajnoczi return; 244fc0b9b0eSStefan Hajnoczi } 245fc0b9b0eSStefan Hajnoczi 246fc0b9b0eSStefan Hajnoczi timer_del(vsock->post_load_timer); 247fc0b9b0eSStefan Hajnoczi timer_free(vsock->post_load_timer); 248fc0b9b0eSStefan Hajnoczi vsock->post_load_timer = NULL; 249fc0b9b0eSStefan Hajnoczi } 250fc0b9b0eSStefan Hajnoczi 251fc0b9b0eSStefan Hajnoczi static void vhost_vsock_post_load_timer_cb(void *opaque) 252fc0b9b0eSStefan Hajnoczi { 253fc0b9b0eSStefan Hajnoczi VHostVSock *vsock = opaque; 254fc0b9b0eSStefan Hajnoczi 255fc0b9b0eSStefan Hajnoczi vhost_vsock_post_load_timer_cleanup(vsock); 256fc0b9b0eSStefan Hajnoczi vhost_vsock_send_transport_reset(vsock); 257fc0b9b0eSStefan Hajnoczi } 258fc0b9b0eSStefan Hajnoczi 25944b1ff31SDr. David Alan Gilbert static int vhost_vsock_pre_save(void *opaque) 26081cc8a65SHalil Pasic { 26181cc8a65SHalil Pasic VHostVSock *vsock = opaque; 26281cc8a65SHalil Pasic 26381cc8a65SHalil Pasic /* At this point, backend must be stopped, otherwise 26481cc8a65SHalil Pasic * it might keep writing to memory. */ 26581cc8a65SHalil Pasic assert(!vsock->vhost_dev.started); 26644b1ff31SDr. David Alan Gilbert 26744b1ff31SDr. David Alan Gilbert return 0; 26881cc8a65SHalil Pasic } 26981cc8a65SHalil Pasic 27081cc8a65SHalil Pasic static int vhost_vsock_post_load(void *opaque, int version_id) 271fc0b9b0eSStefan Hajnoczi { 272fc0b9b0eSStefan Hajnoczi VHostVSock *vsock = opaque; 273fc0b9b0eSStefan Hajnoczi VirtIODevice *vdev = VIRTIO_DEVICE(vsock); 274fc0b9b0eSStefan Hajnoczi 275fc0b9b0eSStefan Hajnoczi if (virtio_queue_get_addr(vdev, 2)) { 276fc0b9b0eSStefan Hajnoczi /* Defer transport reset event to a vm clock timer so that virtqueue 277fc0b9b0eSStefan Hajnoczi * changes happen after migration has completed. 278fc0b9b0eSStefan Hajnoczi */ 279fc0b9b0eSStefan Hajnoczi assert(!vsock->post_load_timer); 280fc0b9b0eSStefan Hajnoczi vsock->post_load_timer = 281fc0b9b0eSStefan Hajnoczi timer_new_ns(QEMU_CLOCK_VIRTUAL, 282fc0b9b0eSStefan Hajnoczi vhost_vsock_post_load_timer_cb, 283fc0b9b0eSStefan Hajnoczi vsock); 284fc0b9b0eSStefan Hajnoczi timer_mod(vsock->post_load_timer, 1); 285fc0b9b0eSStefan Hajnoczi } 286fc0b9b0eSStefan Hajnoczi return 0; 287fc0b9b0eSStefan Hajnoczi } 288fc0b9b0eSStefan Hajnoczi 28981cc8a65SHalil Pasic static const VMStateDescription vmstate_virtio_vhost_vsock = { 29081cc8a65SHalil Pasic .name = "virtio-vhost_vsock", 29181cc8a65SHalil Pasic .minimum_version_id = VHOST_VSOCK_SAVEVM_VERSION, 29281cc8a65SHalil Pasic .version_id = VHOST_VSOCK_SAVEVM_VERSION, 29381cc8a65SHalil Pasic .fields = (VMStateField[]) { 29481cc8a65SHalil Pasic VMSTATE_VIRTIO_DEVICE, 29581cc8a65SHalil Pasic VMSTATE_END_OF_LIST() 29681cc8a65SHalil Pasic }, 29781cc8a65SHalil Pasic .pre_save = vhost_vsock_pre_save, 29881cc8a65SHalil Pasic .post_load = vhost_vsock_post_load, 29981cc8a65SHalil Pasic }; 300fc0b9b0eSStefan Hajnoczi 301fc0b9b0eSStefan Hajnoczi static void vhost_vsock_device_realize(DeviceState *dev, Error **errp) 302fc0b9b0eSStefan Hajnoczi { 303fc0b9b0eSStefan Hajnoczi VirtIODevice *vdev = VIRTIO_DEVICE(dev); 304fc0b9b0eSStefan Hajnoczi VHostVSock *vsock = VHOST_VSOCK(dev); 305fc0b9b0eSStefan Hajnoczi int vhostfd; 306fc0b9b0eSStefan Hajnoczi int ret; 307fc0b9b0eSStefan Hajnoczi 308fc0b9b0eSStefan Hajnoczi /* Refuse to use reserved CID numbers */ 309fc0b9b0eSStefan Hajnoczi if (vsock->conf.guest_cid <= 2) { 310fc0b9b0eSStefan Hajnoczi error_setg(errp, "guest-cid property must be greater than 2"); 311fc0b9b0eSStefan Hajnoczi return; 312fc0b9b0eSStefan Hajnoczi } 313fc0b9b0eSStefan Hajnoczi 314fc0b9b0eSStefan Hajnoczi if (vsock->conf.guest_cid > UINT32_MAX) { 315fc0b9b0eSStefan Hajnoczi error_setg(errp, "guest-cid property must be a 32-bit number"); 316fc0b9b0eSStefan Hajnoczi return; 317fc0b9b0eSStefan Hajnoczi } 318fc0b9b0eSStefan Hajnoczi 319fc0b9b0eSStefan Hajnoczi if (vsock->conf.vhostfd) { 320fc0b9b0eSStefan Hajnoczi vhostfd = monitor_fd_param(cur_mon, vsock->conf.vhostfd, errp); 321fc0b9b0eSStefan Hajnoczi if (vhostfd == -1) { 322fc0b9b0eSStefan Hajnoczi error_prepend(errp, "vhost-vsock: unable to parse vhostfd: "); 323fc0b9b0eSStefan Hajnoczi return; 324fc0b9b0eSStefan Hajnoczi } 325fc0b9b0eSStefan Hajnoczi } else { 326fc0b9b0eSStefan Hajnoczi vhostfd = open("/dev/vhost-vsock", O_RDWR); 327fc0b9b0eSStefan Hajnoczi if (vhostfd < 0) { 328f1e92c3dSNick Erdmann error_setg_errno(errp, errno, 329fc0b9b0eSStefan Hajnoczi "vhost-vsock: failed to open vhost device"); 330fc0b9b0eSStefan Hajnoczi return; 331fc0b9b0eSStefan Hajnoczi } 332fc0b9b0eSStefan Hajnoczi } 333fc0b9b0eSStefan Hajnoczi 334fc0b9b0eSStefan Hajnoczi virtio_init(vdev, "vhost-vsock", VIRTIO_ID_VSOCK, 335fc0b9b0eSStefan Hajnoczi sizeof(struct virtio_vsock_config)); 336fc0b9b0eSStefan Hajnoczi 337fc0b9b0eSStefan Hajnoczi /* Receive and transmit queues belong to vhost */ 338e1932cf9SPan Nengyuan vsock->recv_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, 339e1932cf9SPan Nengyuan vhost_vsock_handle_output); 340e1932cf9SPan Nengyuan vsock->trans_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, 341e1932cf9SPan Nengyuan vhost_vsock_handle_output); 342fc0b9b0eSStefan Hajnoczi 343fc0b9b0eSStefan Hajnoczi /* The event queue belongs to QEMU */ 344fc0b9b0eSStefan Hajnoczi vsock->event_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, 345fc0b9b0eSStefan Hajnoczi vhost_vsock_handle_output); 346fc0b9b0eSStefan Hajnoczi 347fc0b9b0eSStefan Hajnoczi vsock->vhost_dev.nvqs = ARRAY_SIZE(vsock->vhost_vqs); 348fc0b9b0eSStefan Hajnoczi vsock->vhost_dev.vqs = vsock->vhost_vqs; 349fc0b9b0eSStefan Hajnoczi ret = vhost_dev_init(&vsock->vhost_dev, (void *)(uintptr_t)vhostfd, 350fc0b9b0eSStefan Hajnoczi VHOST_BACKEND_TYPE_KERNEL, 0); 351fc0b9b0eSStefan Hajnoczi if (ret < 0) { 352fc0b9b0eSStefan Hajnoczi error_setg_errno(errp, -ret, "vhost-vsock: vhost_dev_init failed"); 353fc0b9b0eSStefan Hajnoczi goto err_virtio; 354fc0b9b0eSStefan Hajnoczi } 355fc0b9b0eSStefan Hajnoczi 356fc0b9b0eSStefan Hajnoczi ret = vhost_vsock_set_guest_cid(vsock); 357fc0b9b0eSStefan Hajnoczi if (ret < 0) { 358fc0b9b0eSStefan Hajnoczi error_setg_errno(errp, -ret, "vhost-vsock: unable to set guest cid"); 359fc0b9b0eSStefan Hajnoczi goto err_vhost_dev; 360fc0b9b0eSStefan Hajnoczi } 361fc0b9b0eSStefan Hajnoczi 362fc0b9b0eSStefan Hajnoczi vsock->post_load_timer = NULL; 363fc0b9b0eSStefan Hajnoczi return; 364fc0b9b0eSStefan Hajnoczi 365fc0b9b0eSStefan Hajnoczi err_vhost_dev: 366fc0b9b0eSStefan Hajnoczi vhost_dev_cleanup(&vsock->vhost_dev); 367e82cdba3SStefano Garzarella /* vhost_dev_cleanup() closes the vhostfd passed to vhost_dev_init() */ 368e82cdba3SStefano Garzarella vhostfd = -1; 369fc0b9b0eSStefan Hajnoczi err_virtio: 370e1932cf9SPan Nengyuan virtio_delete_queue(vsock->recv_vq); 371e1932cf9SPan Nengyuan virtio_delete_queue(vsock->trans_vq); 372e1932cf9SPan Nengyuan virtio_delete_queue(vsock->event_vq); 373fc0b9b0eSStefan Hajnoczi virtio_cleanup(vdev); 374e82cdba3SStefano Garzarella if (vhostfd >= 0) { 375fc0b9b0eSStefan Hajnoczi close(vhostfd); 376e82cdba3SStefano Garzarella } 377fc0b9b0eSStefan Hajnoczi return; 378fc0b9b0eSStefan Hajnoczi } 379fc0b9b0eSStefan Hajnoczi 380*b69c3c21SMarkus Armbruster static void vhost_vsock_device_unrealize(DeviceState *dev) 381fc0b9b0eSStefan Hajnoczi { 382fc0b9b0eSStefan Hajnoczi VirtIODevice *vdev = VIRTIO_DEVICE(dev); 383fc0b9b0eSStefan Hajnoczi VHostVSock *vsock = VHOST_VSOCK(dev); 384fc0b9b0eSStefan Hajnoczi 385fc0b9b0eSStefan Hajnoczi vhost_vsock_post_load_timer_cleanup(vsock); 386fc0b9b0eSStefan Hajnoczi 387fc0b9b0eSStefan Hajnoczi /* This will stop vhost backend if appropriate. */ 388fc0b9b0eSStefan Hajnoczi vhost_vsock_set_status(vdev, 0); 389fc0b9b0eSStefan Hajnoczi 390fc0b9b0eSStefan Hajnoczi vhost_dev_cleanup(&vsock->vhost_dev); 391e1932cf9SPan Nengyuan virtio_delete_queue(vsock->recv_vq); 392e1932cf9SPan Nengyuan virtio_delete_queue(vsock->trans_vq); 393e1932cf9SPan Nengyuan virtio_delete_queue(vsock->event_vq); 394fc0b9b0eSStefan Hajnoczi virtio_cleanup(vdev); 395fc0b9b0eSStefan Hajnoczi } 396fc0b9b0eSStefan Hajnoczi 397fc0b9b0eSStefan Hajnoczi static Property vhost_vsock_properties[] = { 398fc0b9b0eSStefan Hajnoczi DEFINE_PROP_UINT64("guest-cid", VHostVSock, conf.guest_cid, 0), 399fc0b9b0eSStefan Hajnoczi DEFINE_PROP_STRING("vhostfd", VHostVSock, conf.vhostfd), 400fc0b9b0eSStefan Hajnoczi DEFINE_PROP_END_OF_LIST(), 401fc0b9b0eSStefan Hajnoczi }; 402fc0b9b0eSStefan Hajnoczi 403fc0b9b0eSStefan Hajnoczi static void vhost_vsock_class_init(ObjectClass *klass, void *data) 404fc0b9b0eSStefan Hajnoczi { 405fc0b9b0eSStefan Hajnoczi DeviceClass *dc = DEVICE_CLASS(klass); 406fc0b9b0eSStefan Hajnoczi VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 407fc0b9b0eSStefan Hajnoczi 4084f67d30bSMarc-André Lureau device_class_set_props(dc, vhost_vsock_properties); 409fc0b9b0eSStefan Hajnoczi dc->vmsd = &vmstate_virtio_vhost_vsock; 410fc0b9b0eSStefan Hajnoczi set_bit(DEVICE_CATEGORY_MISC, dc->categories); 411fc0b9b0eSStefan Hajnoczi vdc->realize = vhost_vsock_device_realize; 412fc0b9b0eSStefan Hajnoczi vdc->unrealize = vhost_vsock_device_unrealize; 413fc0b9b0eSStefan Hajnoczi vdc->get_features = vhost_vsock_get_features; 414fc0b9b0eSStefan Hajnoczi vdc->get_config = vhost_vsock_get_config; 415fc0b9b0eSStefan Hajnoczi vdc->set_status = vhost_vsock_set_status; 416fc0b9b0eSStefan Hajnoczi vdc->guest_notifier_mask = vhost_vsock_guest_notifier_mask; 417fc0b9b0eSStefan Hajnoczi vdc->guest_notifier_pending = vhost_vsock_guest_notifier_pending; 418fc0b9b0eSStefan Hajnoczi } 419fc0b9b0eSStefan Hajnoczi 420fc0b9b0eSStefan Hajnoczi static const TypeInfo vhost_vsock_info = { 421fc0b9b0eSStefan Hajnoczi .name = TYPE_VHOST_VSOCK, 422fc0b9b0eSStefan Hajnoczi .parent = TYPE_VIRTIO_DEVICE, 423fc0b9b0eSStefan Hajnoczi .instance_size = sizeof(VHostVSock), 424fc0b9b0eSStefan Hajnoczi .class_init = vhost_vsock_class_init, 425fc0b9b0eSStefan Hajnoczi }; 426fc0b9b0eSStefan Hajnoczi 427fc0b9b0eSStefan Hajnoczi static void vhost_vsock_register_types(void) 428fc0b9b0eSStefan Hajnoczi { 429fc0b9b0eSStefan Hajnoczi type_register_static(&vhost_vsock_info); 430fc0b9b0eSStefan Hajnoczi } 431fc0b9b0eSStefan Hajnoczi 432fc0b9b0eSStefan Hajnoczi type_init(vhost_vsock_register_types) 433