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