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 out; 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 out; 163 } 164 165 virtqueue_push(vq, elem, sizeof(event)); 166 virtio_notify(VIRTIO_DEVICE(vvc), vq); 167 168 out: 169 g_free(elem); 170 } 171 172 static void vhost_vsock_common_post_load_timer_cleanup(VHostVSockCommon *vvc) 173 { 174 if (!vvc->post_load_timer) { 175 return; 176 } 177 178 timer_free(vvc->post_load_timer); 179 vvc->post_load_timer = NULL; 180 } 181 182 static void vhost_vsock_common_post_load_timer_cb(void *opaque) 183 { 184 VHostVSockCommon *vvc = opaque; 185 186 vhost_vsock_common_post_load_timer_cleanup(vvc); 187 vhost_vsock_common_send_transport_reset(vvc); 188 } 189 190 int vhost_vsock_common_pre_save(void *opaque) 191 { 192 VHostVSockCommon *vvc = opaque; 193 194 /* 195 * At this point, backend must be stopped, otherwise 196 * it might keep writing to memory. 197 */ 198 assert(!vvc->vhost_dev.started); 199 200 return 0; 201 } 202 203 int vhost_vsock_common_post_load(void *opaque, int version_id) 204 { 205 VHostVSockCommon *vvc = opaque; 206 VirtIODevice *vdev = VIRTIO_DEVICE(vvc); 207 208 if (virtio_queue_get_addr(vdev, 2)) { 209 /* 210 * Defer transport reset event to a vm clock timer so that virtqueue 211 * changes happen after migration has completed. 212 */ 213 assert(!vvc->post_load_timer); 214 vvc->post_load_timer = 215 timer_new_ns(QEMU_CLOCK_VIRTUAL, 216 vhost_vsock_common_post_load_timer_cb, 217 vvc); 218 timer_mod(vvc->post_load_timer, 1); 219 } 220 return 0; 221 } 222 223 void vhost_vsock_common_realize(VirtIODevice *vdev, const char *name) 224 { 225 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 226 227 virtio_init(vdev, name, VIRTIO_ID_VSOCK, 228 sizeof(struct virtio_vsock_config)); 229 230 /* Receive and transmit queues belong to vhost */ 231 vvc->recv_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, 232 vhost_vsock_common_handle_output); 233 vvc->trans_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, 234 vhost_vsock_common_handle_output); 235 236 /* The event queue belongs to QEMU */ 237 vvc->event_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE, 238 vhost_vsock_common_handle_output); 239 240 vvc->vhost_dev.nvqs = ARRAY_SIZE(vvc->vhost_vqs); 241 vvc->vhost_dev.vqs = vvc->vhost_vqs; 242 243 vvc->post_load_timer = NULL; 244 } 245 246 void vhost_vsock_common_unrealize(VirtIODevice *vdev) 247 { 248 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 249 250 vhost_vsock_common_post_load_timer_cleanup(vvc); 251 252 virtio_delete_queue(vvc->recv_vq); 253 virtio_delete_queue(vvc->trans_vq); 254 virtio_delete_queue(vvc->event_vq); 255 virtio_cleanup(vdev); 256 } 257 258 static Property vhost_vsock_common_properties[] = { 259 DEFINE_PROP_ON_OFF_AUTO("seqpacket", VHostVSockCommon, seqpacket, 260 ON_OFF_AUTO_AUTO), 261 DEFINE_PROP_END_OF_LIST(), 262 }; 263 264 static void vhost_vsock_common_class_init(ObjectClass *klass, void *data) 265 { 266 DeviceClass *dc = DEVICE_CLASS(klass); 267 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 268 269 device_class_set_props(dc, vhost_vsock_common_properties); 270 set_bit(DEVICE_CATEGORY_MISC, dc->categories); 271 vdc->guest_notifier_mask = vhost_vsock_common_guest_notifier_mask; 272 vdc->guest_notifier_pending = vhost_vsock_common_guest_notifier_pending; 273 } 274 275 static const TypeInfo vhost_vsock_common_info = { 276 .name = TYPE_VHOST_VSOCK_COMMON, 277 .parent = TYPE_VIRTIO_DEVICE, 278 .instance_size = sizeof(VHostVSockCommon), 279 .class_init = vhost_vsock_common_class_init, 280 .abstract = true, 281 }; 282 283 static void vhost_vsock_common_register_types(void) 284 { 285 type_register_static(&vhost_vsock_common_info); 286 } 287 288 type_init(vhost_vsock_common_register_types) 289