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