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 const int feature_bits[] = { 22 VIRTIO_VSOCK_F_SEQPACKET, 23 VHOST_INVALID_FEATURE_BIT 24 }; 25 26 uint64_t vhost_vsock_common_get_features(VirtIODevice *vdev, uint64_t features, 27 Error **errp) 28 { 29 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 30 31 if (vvc->seqpacket != ON_OFF_AUTO_OFF) { 32 virtio_add_feature(&features, VIRTIO_VSOCK_F_SEQPACKET); 33 } 34 35 features = vhost_get_features(&vvc->vhost_dev, feature_bits, features); 36 37 if (vvc->seqpacket == ON_OFF_AUTO_ON && 38 !virtio_has_feature(features, VIRTIO_VSOCK_F_SEQPACKET)) { 39 error_setg(errp, "vhost-vsock backend doesn't support seqpacket"); 40 } 41 42 return features; 43 } 44 45 int vhost_vsock_common_start(VirtIODevice *vdev) 46 { 47 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 48 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); 49 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 50 int ret; 51 int i; 52 53 if (!k->set_guest_notifiers) { 54 error_report("binding does not support guest notifiers"); 55 return -ENOSYS; 56 } 57 58 ret = vhost_dev_enable_notifiers(&vvc->vhost_dev, vdev); 59 if (ret < 0) { 60 error_report("Error enabling host notifiers: %d", -ret); 61 return ret; 62 } 63 64 ret = k->set_guest_notifiers(qbus->parent, vvc->vhost_dev.nvqs, true); 65 if (ret < 0) { 66 error_report("Error binding guest notifier: %d", -ret); 67 goto err_host_notifiers; 68 } 69 70 vvc->vhost_dev.acked_features = vdev->guest_features; 71 ret = vhost_dev_start(&vvc->vhost_dev, vdev); 72 if (ret < 0) { 73 error_report("Error starting vhost: %d", -ret); 74 goto err_guest_notifiers; 75 } 76 77 /* 78 * guest_notifier_mask/pending not used yet, so just unmask 79 * everything here. virtio-pci will do the right thing by 80 * enabling/disabling irqfd. 81 */ 82 for (i = 0; i < vvc->vhost_dev.nvqs; i++) { 83 vhost_virtqueue_mask(&vvc->vhost_dev, vdev, i, false); 84 } 85 86 return 0; 87 88 err_guest_notifiers: 89 k->set_guest_notifiers(qbus->parent, vvc->vhost_dev.nvqs, false); 90 err_host_notifiers: 91 vhost_dev_disable_notifiers(&vvc->vhost_dev, vdev); 92 return ret; 93 } 94 95 void vhost_vsock_common_stop(VirtIODevice *vdev) 96 { 97 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 98 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); 99 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 100 int ret; 101 102 if (!k->set_guest_notifiers) { 103 return; 104 } 105 106 vhost_dev_stop(&vvc->vhost_dev, vdev); 107 108 ret = k->set_guest_notifiers(qbus->parent, vvc->vhost_dev.nvqs, false); 109 if (ret < 0) { 110 error_report("vhost guest notifier cleanup failed: %d", ret); 111 return; 112 } 113 114 vhost_dev_disable_notifiers(&vvc->vhost_dev, vdev); 115 } 116 117 118 static void vhost_vsock_common_handle_output(VirtIODevice *vdev, VirtQueue *vq) 119 { 120 /* Do nothing */ 121 } 122 123 static void vhost_vsock_common_guest_notifier_mask(VirtIODevice *vdev, int idx, 124 bool mask) 125 { 126 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 127 128 vhost_virtqueue_mask(&vvc->vhost_dev, vdev, idx, mask); 129 } 130 131 static bool vhost_vsock_common_guest_notifier_pending(VirtIODevice *vdev, 132 int idx) 133 { 134 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 135 136 return vhost_virtqueue_pending(&vvc->vhost_dev, idx); 137 } 138 139 static void vhost_vsock_common_send_transport_reset(VHostVSockCommon *vvc) 140 { 141 VirtQueueElement *elem; 142 VirtQueue *vq = vvc->event_vq; 143 struct virtio_vsock_event event = { 144 .id = cpu_to_le32(VIRTIO_VSOCK_EVENT_TRANSPORT_RESET), 145 }; 146 147 elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); 148 if (!elem) { 149 error_report("vhost-vsock missed transport reset event"); 150 return; 151 } 152 153 if (elem->out_num) { 154 error_report("invalid vhost-vsock event virtqueue element with " 155 "out buffers"); 156 goto err; 157 } 158 159 if (iov_from_buf(elem->in_sg, elem->in_num, 0, 160 &event, sizeof(event)) != sizeof(event)) { 161 error_report("vhost-vsock event virtqueue element is too short"); 162 goto err; 163 } 164 165 virtqueue_push(vq, elem, sizeof(event)); 166 virtio_notify(VIRTIO_DEVICE(vvc), vq); 167 168 g_free(elem); 169 return; 170 171 err: 172 virtqueue_detach_element(vq, elem, 0); 173 g_free(elem); 174 } 175 176 static void vhost_vsock_common_post_load_timer_cleanup(VHostVSockCommon *vvc) 177 { 178 if (!vvc->post_load_timer) { 179 return; 180 } 181 182 timer_free(vvc->post_load_timer); 183 vvc->post_load_timer = NULL; 184 } 185 186 static void vhost_vsock_common_post_load_timer_cb(void *opaque) 187 { 188 VHostVSockCommon *vvc = opaque; 189 190 vhost_vsock_common_post_load_timer_cleanup(vvc); 191 vhost_vsock_common_send_transport_reset(vvc); 192 } 193 194 int vhost_vsock_common_pre_save(void *opaque) 195 { 196 VHostVSockCommon *vvc = opaque; 197 198 /* 199 * At this point, backend must be stopped, otherwise 200 * it might keep writing to memory. 201 */ 202 assert(!vvc->vhost_dev.started); 203 204 return 0; 205 } 206 207 int vhost_vsock_common_post_load(void *opaque, int version_id) 208 { 209 VHostVSockCommon *vvc = opaque; 210 VirtIODevice *vdev = VIRTIO_DEVICE(vvc); 211 212 if (virtio_queue_get_addr(vdev, 2)) { 213 /* 214 * Defer transport reset event to a vm clock timer so that virtqueue 215 * changes happen after migration has completed. 216 */ 217 assert(!vvc->post_load_timer); 218 vvc->post_load_timer = 219 timer_new_ns(QEMU_CLOCK_VIRTUAL, 220 vhost_vsock_common_post_load_timer_cb, 221 vvc); 222 timer_mod(vvc->post_load_timer, 1); 223 } 224 return 0; 225 } 226 227 void vhost_vsock_common_realize(VirtIODevice *vdev) 228 { 229 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 230 231 virtio_init(vdev, VIRTIO_ID_VSOCK, sizeof(struct virtio_vsock_config)); 232 233 /* Receive and transmit queues belong to vhost */ 234 vvc->recv_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, 235 vhost_vsock_common_handle_output); 236 vvc->trans_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, 237 vhost_vsock_common_handle_output); 238 239 /* The event queue belongs to QEMU */ 240 vvc->event_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, 241 vhost_vsock_common_handle_output); 242 243 vvc->vhost_dev.nvqs = ARRAY_SIZE(vvc->vhost_vqs); 244 vvc->vhost_dev.vqs = vvc->vhost_vqs; 245 246 vvc->post_load_timer = NULL; 247 } 248 249 void vhost_vsock_common_unrealize(VirtIODevice *vdev) 250 { 251 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 252 253 vhost_vsock_common_post_load_timer_cleanup(vvc); 254 255 virtio_delete_queue(vvc->recv_vq); 256 virtio_delete_queue(vvc->trans_vq); 257 virtio_delete_queue(vvc->event_vq); 258 virtio_cleanup(vdev); 259 } 260 261 static struct vhost_dev *vhost_vsock_common_get_vhost(VirtIODevice *vdev) 262 { 263 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 264 return &vvc->vhost_dev; 265 } 266 267 static Property vhost_vsock_common_properties[] = { 268 DEFINE_PROP_ON_OFF_AUTO("seqpacket", VHostVSockCommon, seqpacket, 269 ON_OFF_AUTO_AUTO), 270 DEFINE_PROP_END_OF_LIST(), 271 }; 272 273 static void vhost_vsock_common_class_init(ObjectClass *klass, void *data) 274 { 275 DeviceClass *dc = DEVICE_CLASS(klass); 276 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 277 278 device_class_set_props(dc, vhost_vsock_common_properties); 279 set_bit(DEVICE_CATEGORY_MISC, dc->categories); 280 vdc->guest_notifier_mask = vhost_vsock_common_guest_notifier_mask; 281 vdc->guest_notifier_pending = vhost_vsock_common_guest_notifier_pending; 282 vdc->get_vhost = vhost_vsock_common_get_vhost; 283 } 284 285 static const TypeInfo vhost_vsock_common_info = { 286 .name = TYPE_VHOST_VSOCK_COMMON, 287 .parent = TYPE_VIRTIO_DEVICE, 288 .instance_size = sizeof(VHostVSockCommon), 289 .class_init = vhost_vsock_common_class_init, 290 .abstract = true, 291 }; 292 293 static void vhost_vsock_common_register_types(void) 294 { 295 type_register_static(&vhost_vsock_common_info); 296 } 297 298 type_init(vhost_vsock_common_register_types) 299