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