1 /* 2 * Parent class for vhost-vsock devices 3 * 4 * Copyright 2015-2020 Red Hat, Inc. 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or 7 * (at your option) any later version. See the COPYING file in the 8 * top-level directory. 9 */ 10 11 #include "qemu/osdep.h" 12 #include "standard-headers/linux/virtio_vsock.h" 13 #include "qapi/error.h" 14 #include "hw/virtio/virtio-access.h" 15 #include "qemu/error-report.h" 16 #include "hw/qdev-properties.h" 17 #include "hw/virtio/vhost-vsock.h" 18 #include "qemu/iov.h" 19 #include "monitor/monitor.h" 20 21 int vhost_vsock_common_start(VirtIODevice *vdev) 22 { 23 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 24 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); 25 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 26 int ret; 27 int i; 28 29 if (!k->set_guest_notifiers) { 30 error_report("binding does not support guest notifiers"); 31 return -ENOSYS; 32 } 33 34 ret = vhost_dev_enable_notifiers(&vvc->vhost_dev, vdev); 35 if (ret < 0) { 36 error_report("Error enabling host notifiers: %d", -ret); 37 return ret; 38 } 39 40 ret = k->set_guest_notifiers(qbus->parent, vvc->vhost_dev.nvqs, true); 41 if (ret < 0) { 42 error_report("Error binding guest notifier: %d", -ret); 43 goto err_host_notifiers; 44 } 45 46 vvc->vhost_dev.acked_features = vdev->guest_features; 47 ret = vhost_dev_start(&vvc->vhost_dev, vdev); 48 if (ret < 0) { 49 error_report("Error starting vhost: %d", -ret); 50 goto err_guest_notifiers; 51 } 52 53 /* 54 * guest_notifier_mask/pending not used yet, so just unmask 55 * everything here. virtio-pci will do the right thing by 56 * enabling/disabling irqfd. 57 */ 58 for (i = 0; i < vvc->vhost_dev.nvqs; i++) { 59 vhost_virtqueue_mask(&vvc->vhost_dev, vdev, i, false); 60 } 61 62 return 0; 63 64 err_guest_notifiers: 65 k->set_guest_notifiers(qbus->parent, vvc->vhost_dev.nvqs, false); 66 err_host_notifiers: 67 vhost_dev_disable_notifiers(&vvc->vhost_dev, vdev); 68 return ret; 69 } 70 71 void vhost_vsock_common_stop(VirtIODevice *vdev) 72 { 73 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 74 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); 75 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 76 int ret; 77 78 if (!k->set_guest_notifiers) { 79 return; 80 } 81 82 vhost_dev_stop(&vvc->vhost_dev, vdev); 83 84 ret = k->set_guest_notifiers(qbus->parent, vvc->vhost_dev.nvqs, false); 85 if (ret < 0) { 86 error_report("vhost guest notifier cleanup failed: %d", ret); 87 return; 88 } 89 90 vhost_dev_disable_notifiers(&vvc->vhost_dev, vdev); 91 } 92 93 94 static void vhost_vsock_common_handle_output(VirtIODevice *vdev, VirtQueue *vq) 95 { 96 /* Do nothing */ 97 } 98 99 static void vhost_vsock_common_guest_notifier_mask(VirtIODevice *vdev, int idx, 100 bool mask) 101 { 102 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 103 104 vhost_virtqueue_mask(&vvc->vhost_dev, vdev, idx, mask); 105 } 106 107 static bool vhost_vsock_common_guest_notifier_pending(VirtIODevice *vdev, 108 int idx) 109 { 110 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 111 112 return vhost_virtqueue_pending(&vvc->vhost_dev, idx); 113 } 114 115 static void vhost_vsock_common_send_transport_reset(VHostVSockCommon *vvc) 116 { 117 VirtQueueElement *elem; 118 VirtQueue *vq = vvc->event_vq; 119 struct virtio_vsock_event event = { 120 .id = cpu_to_le32(VIRTIO_VSOCK_EVENT_TRANSPORT_RESET), 121 }; 122 123 elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); 124 if (!elem) { 125 error_report("vhost-vsock missed transport reset event"); 126 return; 127 } 128 129 if (elem->out_num) { 130 error_report("invalid vhost-vsock event virtqueue element with " 131 "out buffers"); 132 goto out; 133 } 134 135 if (iov_from_buf(elem->in_sg, elem->in_num, 0, 136 &event, sizeof(event)) != sizeof(event)) { 137 error_report("vhost-vsock event virtqueue element is too short"); 138 goto out; 139 } 140 141 virtqueue_push(vq, elem, sizeof(event)); 142 virtio_notify(VIRTIO_DEVICE(vvc), vq); 143 144 out: 145 g_free(elem); 146 } 147 148 static void vhost_vsock_common_post_load_timer_cleanup(VHostVSockCommon *vvc) 149 { 150 if (!vvc->post_load_timer) { 151 return; 152 } 153 154 timer_free(vvc->post_load_timer); 155 vvc->post_load_timer = NULL; 156 } 157 158 static void vhost_vsock_common_post_load_timer_cb(void *opaque) 159 { 160 VHostVSockCommon *vvc = opaque; 161 162 vhost_vsock_common_post_load_timer_cleanup(vvc); 163 vhost_vsock_common_send_transport_reset(vvc); 164 } 165 166 int vhost_vsock_common_pre_save(void *opaque) 167 { 168 VHostVSockCommon *vvc = opaque; 169 170 /* 171 * At this point, backend must be stopped, otherwise 172 * it might keep writing to memory. 173 */ 174 assert(!vvc->vhost_dev.started); 175 176 return 0; 177 } 178 179 int vhost_vsock_common_post_load(void *opaque, int version_id) 180 { 181 VHostVSockCommon *vvc = opaque; 182 VirtIODevice *vdev = VIRTIO_DEVICE(vvc); 183 184 if (virtio_queue_get_addr(vdev, 2)) { 185 /* 186 * Defer transport reset event to a vm clock timer so that virtqueue 187 * changes happen after migration has completed. 188 */ 189 assert(!vvc->post_load_timer); 190 vvc->post_load_timer = 191 timer_new_ns(QEMU_CLOCK_VIRTUAL, 192 vhost_vsock_common_post_load_timer_cb, 193 vvc); 194 timer_mod(vvc->post_load_timer, 1); 195 } 196 return 0; 197 } 198 199 void vhost_vsock_common_realize(VirtIODevice *vdev, const char *name) 200 { 201 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 202 203 virtio_init(vdev, name, VIRTIO_ID_VSOCK, 204 sizeof(struct virtio_vsock_config)); 205 206 /* Receive and transmit queues belong to vhost */ 207 vvc->recv_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, 208 vhost_vsock_common_handle_output); 209 vvc->trans_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, 210 vhost_vsock_common_handle_output); 211 212 /* The event queue belongs to QEMU */ 213 vvc->event_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, 214 vhost_vsock_common_handle_output); 215 216 vvc->vhost_dev.nvqs = ARRAY_SIZE(vvc->vhost_vqs); 217 vvc->vhost_dev.vqs = vvc->vhost_vqs; 218 219 vvc->post_load_timer = NULL; 220 } 221 222 void vhost_vsock_common_unrealize(VirtIODevice *vdev) 223 { 224 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 225 226 vhost_vsock_common_post_load_timer_cleanup(vvc); 227 228 virtio_delete_queue(vvc->recv_vq); 229 virtio_delete_queue(vvc->trans_vq); 230 virtio_delete_queue(vvc->event_vq); 231 virtio_cleanup(vdev); 232 } 233 234 static void vhost_vsock_common_class_init(ObjectClass *klass, void *data) 235 { 236 DeviceClass *dc = DEVICE_CLASS(klass); 237 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 238 239 set_bit(DEVICE_CATEGORY_MISC, dc->categories); 240 vdc->guest_notifier_mask = vhost_vsock_common_guest_notifier_mask; 241 vdc->guest_notifier_pending = vhost_vsock_common_guest_notifier_pending; 242 } 243 244 static const TypeInfo vhost_vsock_common_info = { 245 .name = TYPE_VHOST_VSOCK_COMMON, 246 .parent = TYPE_VIRTIO_DEVICE, 247 .instance_size = sizeof(VHostVSockCommon), 248 .class_init = vhost_vsock_common_class_init, 249 .abstract = true, 250 }; 251 252 static void vhost_vsock_common_register_types(void) 253 { 254 type_register_static(&vhost_vsock_common_info); 255 } 256 257 type_init(vhost_vsock_common_register_types) 258