xref: /qemu/hw/virtio/vhost-vsock.c (revision b69c3c21a5d11075d42100d5cfe0a736593fae6b)
1fc0b9b0eSStefan Hajnoczi /*
2fc0b9b0eSStefan Hajnoczi  * Virtio vsock device
3fc0b9b0eSStefan Hajnoczi  *
4fc0b9b0eSStefan Hajnoczi  * Copyright 2015 Red Hat, Inc.
5fc0b9b0eSStefan Hajnoczi  *
6fc0b9b0eSStefan Hajnoczi  * Authors:
7fc0b9b0eSStefan Hajnoczi  *  Stefan Hajnoczi <stefanha@redhat.com>
8fc0b9b0eSStefan Hajnoczi  *
9fc0b9b0eSStefan Hajnoczi  * This work is licensed under the terms of the GNU GPL, version 2 or
10fc0b9b0eSStefan Hajnoczi  * (at your option) any later version.  See the COPYING file in the
11fc0b9b0eSStefan Hajnoczi  * top-level directory.
12fc0b9b0eSStefan Hajnoczi  */
13fc0b9b0eSStefan Hajnoczi 
14fc0b9b0eSStefan Hajnoczi #include "qemu/osdep.h"
15e9808d09SPhilippe Mathieu-Daudé #include <sys/ioctl.h>
16fc0b9b0eSStefan Hajnoczi #include "standard-headers/linux/virtio_vsock.h"
17fc0b9b0eSStefan Hajnoczi #include "qapi/error.h"
18fc0b9b0eSStefan Hajnoczi #include "hw/virtio/virtio-bus.h"
19fc0b9b0eSStefan Hajnoczi #include "hw/virtio/virtio-access.h"
20fc0b9b0eSStefan Hajnoczi #include "qemu/error-report.h"
21a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
22fc0b9b0eSStefan Hajnoczi #include "hw/virtio/vhost-vsock.h"
23fc0b9b0eSStefan Hajnoczi #include "qemu/iov.h"
240b8fa32fSMarkus Armbruster #include "qemu/module.h"
25fc0b9b0eSStefan Hajnoczi #include "monitor/monitor.h"
26fc0b9b0eSStefan Hajnoczi 
27fc0b9b0eSStefan Hajnoczi enum {
28fc0b9b0eSStefan Hajnoczi     VHOST_VSOCK_SAVEVM_VERSION = 0,
29fc0b9b0eSStefan Hajnoczi 
30fc0b9b0eSStefan Hajnoczi     VHOST_VSOCK_QUEUE_SIZE = 128,
31fc0b9b0eSStefan Hajnoczi };
32fc0b9b0eSStefan Hajnoczi 
33fc0b9b0eSStefan Hajnoczi static void vhost_vsock_get_config(VirtIODevice *vdev, uint8_t *config)
34fc0b9b0eSStefan Hajnoczi {
35fc0b9b0eSStefan Hajnoczi     VHostVSock *vsock = VHOST_VSOCK(vdev);
36fc0b9b0eSStefan Hajnoczi     struct virtio_vsock_config vsockcfg = {};
37fc0b9b0eSStefan Hajnoczi 
38fc0b9b0eSStefan Hajnoczi     virtio_stq_p(vdev, &vsockcfg.guest_cid, vsock->conf.guest_cid);
39fc0b9b0eSStefan Hajnoczi     memcpy(config, &vsockcfg, sizeof(vsockcfg));
40fc0b9b0eSStefan Hajnoczi }
41fc0b9b0eSStefan Hajnoczi 
42fc0b9b0eSStefan Hajnoczi static int vhost_vsock_set_guest_cid(VHostVSock *vsock)
43fc0b9b0eSStefan Hajnoczi {
44fc0b9b0eSStefan Hajnoczi     const VhostOps *vhost_ops = vsock->vhost_dev.vhost_ops;
45fc0b9b0eSStefan Hajnoczi     int ret;
46fc0b9b0eSStefan Hajnoczi 
47fc0b9b0eSStefan Hajnoczi     if (!vhost_ops->vhost_vsock_set_guest_cid) {
48fc0b9b0eSStefan Hajnoczi         return -ENOSYS;
49fc0b9b0eSStefan Hajnoczi     }
50fc0b9b0eSStefan Hajnoczi 
51fc0b9b0eSStefan Hajnoczi     ret = vhost_ops->vhost_vsock_set_guest_cid(&vsock->vhost_dev,
52fc0b9b0eSStefan Hajnoczi                                                vsock->conf.guest_cid);
53fc0b9b0eSStefan Hajnoczi     if (ret < 0) {
54fc0b9b0eSStefan Hajnoczi         return -errno;
55fc0b9b0eSStefan Hajnoczi     }
56fc0b9b0eSStefan Hajnoczi     return 0;
57fc0b9b0eSStefan Hajnoczi }
58fc0b9b0eSStefan Hajnoczi 
59fc0b9b0eSStefan Hajnoczi static int vhost_vsock_set_running(VHostVSock *vsock, int start)
60fc0b9b0eSStefan Hajnoczi {
61fc0b9b0eSStefan Hajnoczi     const VhostOps *vhost_ops = vsock->vhost_dev.vhost_ops;
62fc0b9b0eSStefan Hajnoczi     int ret;
63fc0b9b0eSStefan Hajnoczi 
64fc0b9b0eSStefan Hajnoczi     if (!vhost_ops->vhost_vsock_set_running) {
65fc0b9b0eSStefan Hajnoczi         return -ENOSYS;
66fc0b9b0eSStefan Hajnoczi     }
67fc0b9b0eSStefan Hajnoczi 
68fc0b9b0eSStefan Hajnoczi     ret = vhost_ops->vhost_vsock_set_running(&vsock->vhost_dev, start);
69fc0b9b0eSStefan Hajnoczi     if (ret < 0) {
70fc0b9b0eSStefan Hajnoczi         return -errno;
71fc0b9b0eSStefan Hajnoczi     }
72fc0b9b0eSStefan Hajnoczi     return 0;
73fc0b9b0eSStefan Hajnoczi }
74fc0b9b0eSStefan Hajnoczi 
75fc0b9b0eSStefan Hajnoczi static void vhost_vsock_start(VirtIODevice *vdev)
76fc0b9b0eSStefan Hajnoczi {
77fc0b9b0eSStefan Hajnoczi     VHostVSock *vsock = VHOST_VSOCK(vdev);
78fc0b9b0eSStefan Hajnoczi     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
79fc0b9b0eSStefan Hajnoczi     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
80fc0b9b0eSStefan Hajnoczi     int ret;
81fc0b9b0eSStefan Hajnoczi     int i;
82fc0b9b0eSStefan Hajnoczi 
83fc0b9b0eSStefan Hajnoczi     if (!k->set_guest_notifiers) {
84fc0b9b0eSStefan Hajnoczi         error_report("binding does not support guest notifiers");
85fc0b9b0eSStefan Hajnoczi         return;
86fc0b9b0eSStefan Hajnoczi     }
87fc0b9b0eSStefan Hajnoczi 
88fc0b9b0eSStefan Hajnoczi     ret = vhost_dev_enable_notifiers(&vsock->vhost_dev, vdev);
89fc0b9b0eSStefan Hajnoczi     if (ret < 0) {
90fc0b9b0eSStefan Hajnoczi         error_report("Error enabling host notifiers: %d", -ret);
91fc0b9b0eSStefan Hajnoczi         return;
92fc0b9b0eSStefan Hajnoczi     }
93fc0b9b0eSStefan Hajnoczi 
94fc0b9b0eSStefan Hajnoczi     ret = k->set_guest_notifiers(qbus->parent, vsock->vhost_dev.nvqs, true);
95fc0b9b0eSStefan Hajnoczi     if (ret < 0) {
96fc0b9b0eSStefan Hajnoczi         error_report("Error binding guest notifier: %d", -ret);
97fc0b9b0eSStefan Hajnoczi         goto err_host_notifiers;
98fc0b9b0eSStefan Hajnoczi     }
99fc0b9b0eSStefan Hajnoczi 
100fc0b9b0eSStefan Hajnoczi     vsock->vhost_dev.acked_features = vdev->guest_features;
101fc0b9b0eSStefan Hajnoczi     ret = vhost_dev_start(&vsock->vhost_dev, vdev);
102fc0b9b0eSStefan Hajnoczi     if (ret < 0) {
103fc0b9b0eSStefan Hajnoczi         error_report("Error starting vhost: %d", -ret);
104fc0b9b0eSStefan Hajnoczi         goto err_guest_notifiers;
105fc0b9b0eSStefan Hajnoczi     }
106fc0b9b0eSStefan Hajnoczi 
107fc0b9b0eSStefan Hajnoczi     ret = vhost_vsock_set_running(vsock, 1);
108fc0b9b0eSStefan Hajnoczi     if (ret < 0) {
109fc0b9b0eSStefan Hajnoczi         error_report("Error starting vhost vsock: %d", -ret);
110fc0b9b0eSStefan Hajnoczi         goto err_dev_start;
111fc0b9b0eSStefan Hajnoczi     }
112fc0b9b0eSStefan Hajnoczi 
113fc0b9b0eSStefan Hajnoczi     /* guest_notifier_mask/pending not used yet, so just unmask
114fc0b9b0eSStefan Hajnoczi      * everything here.  virtio-pci will do the right thing by
115fc0b9b0eSStefan Hajnoczi      * enabling/disabling irqfd.
116fc0b9b0eSStefan Hajnoczi      */
117fc0b9b0eSStefan Hajnoczi     for (i = 0; i < vsock->vhost_dev.nvqs; i++) {
118fc0b9b0eSStefan Hajnoczi         vhost_virtqueue_mask(&vsock->vhost_dev, vdev, i, false);
119fc0b9b0eSStefan Hajnoczi     }
120fc0b9b0eSStefan Hajnoczi 
121fc0b9b0eSStefan Hajnoczi     return;
122fc0b9b0eSStefan Hajnoczi 
123fc0b9b0eSStefan Hajnoczi err_dev_start:
124fc0b9b0eSStefan Hajnoczi     vhost_dev_stop(&vsock->vhost_dev, vdev);
125fc0b9b0eSStefan Hajnoczi err_guest_notifiers:
126fc0b9b0eSStefan Hajnoczi     k->set_guest_notifiers(qbus->parent, vsock->vhost_dev.nvqs, false);
127fc0b9b0eSStefan Hajnoczi err_host_notifiers:
128fc0b9b0eSStefan Hajnoczi     vhost_dev_disable_notifiers(&vsock->vhost_dev, vdev);
129fc0b9b0eSStefan Hajnoczi }
130fc0b9b0eSStefan Hajnoczi 
131fc0b9b0eSStefan Hajnoczi static void vhost_vsock_stop(VirtIODevice *vdev)
132fc0b9b0eSStefan Hajnoczi {
133fc0b9b0eSStefan Hajnoczi     VHostVSock *vsock = VHOST_VSOCK(vdev);
134fc0b9b0eSStefan Hajnoczi     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
135fc0b9b0eSStefan Hajnoczi     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
136fc0b9b0eSStefan Hajnoczi     int ret;
137fc0b9b0eSStefan Hajnoczi 
138fc0b9b0eSStefan Hajnoczi     if (!k->set_guest_notifiers) {
139fc0b9b0eSStefan Hajnoczi         return;
140fc0b9b0eSStefan Hajnoczi     }
141fc0b9b0eSStefan Hajnoczi 
142fc0b9b0eSStefan Hajnoczi     ret = vhost_vsock_set_running(vsock, 0);
143fc0b9b0eSStefan Hajnoczi     if (ret < 0) {
144fc0b9b0eSStefan Hajnoczi         error_report("vhost vsock set running failed: %d", ret);
145fc0b9b0eSStefan Hajnoczi         return;
146fc0b9b0eSStefan Hajnoczi     }
147fc0b9b0eSStefan Hajnoczi 
148fc0b9b0eSStefan Hajnoczi     vhost_dev_stop(&vsock->vhost_dev, vdev);
149fc0b9b0eSStefan Hajnoczi 
150fc0b9b0eSStefan Hajnoczi     ret = k->set_guest_notifiers(qbus->parent, vsock->vhost_dev.nvqs, false);
151fc0b9b0eSStefan Hajnoczi     if (ret < 0) {
152fc0b9b0eSStefan Hajnoczi         error_report("vhost guest notifier cleanup failed: %d", ret);
153fc0b9b0eSStefan Hajnoczi         return;
154fc0b9b0eSStefan Hajnoczi     }
155fc0b9b0eSStefan Hajnoczi 
156fc0b9b0eSStefan Hajnoczi     vhost_dev_disable_notifiers(&vsock->vhost_dev, vdev);
157fc0b9b0eSStefan Hajnoczi }
158fc0b9b0eSStefan Hajnoczi 
159fc0b9b0eSStefan Hajnoczi static void vhost_vsock_set_status(VirtIODevice *vdev, uint8_t status)
160fc0b9b0eSStefan Hajnoczi {
161fc0b9b0eSStefan Hajnoczi     VHostVSock *vsock = VHOST_VSOCK(vdev);
162fc0b9b0eSStefan Hajnoczi     bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK;
163fc0b9b0eSStefan Hajnoczi 
164fc0b9b0eSStefan Hajnoczi     if (!vdev->vm_running) {
165fc0b9b0eSStefan Hajnoczi         should_start = false;
166fc0b9b0eSStefan Hajnoczi     }
167fc0b9b0eSStefan Hajnoczi 
168fc0b9b0eSStefan Hajnoczi     if (vsock->vhost_dev.started == should_start) {
169fc0b9b0eSStefan Hajnoczi         return;
170fc0b9b0eSStefan Hajnoczi     }
171fc0b9b0eSStefan Hajnoczi 
172fc0b9b0eSStefan Hajnoczi     if (should_start) {
173fc0b9b0eSStefan Hajnoczi         vhost_vsock_start(vdev);
174fc0b9b0eSStefan Hajnoczi     } else {
175fc0b9b0eSStefan Hajnoczi         vhost_vsock_stop(vdev);
176fc0b9b0eSStefan Hajnoczi     }
177fc0b9b0eSStefan Hajnoczi }
178fc0b9b0eSStefan Hajnoczi 
179fc0b9b0eSStefan Hajnoczi static uint64_t vhost_vsock_get_features(VirtIODevice *vdev,
180fc0b9b0eSStefan Hajnoczi                                          uint64_t requested_features,
181fc0b9b0eSStefan Hajnoczi                                          Error **errp)
182fc0b9b0eSStefan Hajnoczi {
183fc0b9b0eSStefan Hajnoczi     /* No feature bits used yet */
184fc0b9b0eSStefan Hajnoczi     return requested_features;
185fc0b9b0eSStefan Hajnoczi }
186fc0b9b0eSStefan Hajnoczi 
187fc0b9b0eSStefan Hajnoczi static void vhost_vsock_handle_output(VirtIODevice *vdev, VirtQueue *vq)
188fc0b9b0eSStefan Hajnoczi {
189fc0b9b0eSStefan Hajnoczi     /* Do nothing */
190fc0b9b0eSStefan Hajnoczi }
191fc0b9b0eSStefan Hajnoczi 
192fc0b9b0eSStefan Hajnoczi static void vhost_vsock_guest_notifier_mask(VirtIODevice *vdev, int idx,
193fc0b9b0eSStefan Hajnoczi                                             bool mask)
194fc0b9b0eSStefan Hajnoczi {
195fc0b9b0eSStefan Hajnoczi     VHostVSock *vsock = VHOST_VSOCK(vdev);
196fc0b9b0eSStefan Hajnoczi 
197fc0b9b0eSStefan Hajnoczi     vhost_virtqueue_mask(&vsock->vhost_dev, vdev, idx, mask);
198fc0b9b0eSStefan Hajnoczi }
199fc0b9b0eSStefan Hajnoczi 
200fc0b9b0eSStefan Hajnoczi static bool vhost_vsock_guest_notifier_pending(VirtIODevice *vdev, int idx)
201fc0b9b0eSStefan Hajnoczi {
202fc0b9b0eSStefan Hajnoczi     VHostVSock *vsock = VHOST_VSOCK(vdev);
203fc0b9b0eSStefan Hajnoczi 
204fc0b9b0eSStefan Hajnoczi     return vhost_virtqueue_pending(&vsock->vhost_dev, idx);
205fc0b9b0eSStefan Hajnoczi }
206fc0b9b0eSStefan Hajnoczi 
207fc0b9b0eSStefan Hajnoczi static void vhost_vsock_send_transport_reset(VHostVSock *vsock)
208fc0b9b0eSStefan Hajnoczi {
209fc0b9b0eSStefan Hajnoczi     VirtQueueElement *elem;
210fc0b9b0eSStefan Hajnoczi     VirtQueue *vq = vsock->event_vq;
211fc0b9b0eSStefan Hajnoczi     struct virtio_vsock_event event = {
212fc0b9b0eSStefan Hajnoczi         .id = cpu_to_le32(VIRTIO_VSOCK_EVENT_TRANSPORT_RESET),
213fc0b9b0eSStefan Hajnoczi     };
214fc0b9b0eSStefan Hajnoczi 
215fc0b9b0eSStefan Hajnoczi     elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
216fc0b9b0eSStefan Hajnoczi     if (!elem) {
217fc0b9b0eSStefan Hajnoczi         error_report("vhost-vsock missed transport reset event");
218fc0b9b0eSStefan Hajnoczi         return;
219fc0b9b0eSStefan Hajnoczi     }
220fc0b9b0eSStefan Hajnoczi 
221fc0b9b0eSStefan Hajnoczi     if (elem->out_num) {
222fc0b9b0eSStefan Hajnoczi         error_report("invalid vhost-vsock event virtqueue element with "
223fc0b9b0eSStefan Hajnoczi                      "out buffers");
224fc0b9b0eSStefan Hajnoczi         goto out;
225fc0b9b0eSStefan Hajnoczi     }
226fc0b9b0eSStefan Hajnoczi 
227fc0b9b0eSStefan Hajnoczi     if (iov_from_buf(elem->in_sg, elem->in_num, 0,
228fc0b9b0eSStefan Hajnoczi                      &event, sizeof(event)) != sizeof(event)) {
229fc0b9b0eSStefan Hajnoczi         error_report("vhost-vsock event virtqueue element is too short");
230fc0b9b0eSStefan Hajnoczi         goto out;
231fc0b9b0eSStefan Hajnoczi     }
232fc0b9b0eSStefan Hajnoczi 
233fc0b9b0eSStefan Hajnoczi     virtqueue_push(vq, elem, sizeof(event));
234fc0b9b0eSStefan Hajnoczi     virtio_notify(VIRTIO_DEVICE(vsock), vq);
235fc0b9b0eSStefan Hajnoczi 
236fc0b9b0eSStefan Hajnoczi out:
237fc0b9b0eSStefan Hajnoczi     g_free(elem);
238fc0b9b0eSStefan Hajnoczi }
239fc0b9b0eSStefan Hajnoczi 
240fc0b9b0eSStefan Hajnoczi static void vhost_vsock_post_load_timer_cleanup(VHostVSock *vsock)
241fc0b9b0eSStefan Hajnoczi {
242fc0b9b0eSStefan Hajnoczi     if (!vsock->post_load_timer) {
243fc0b9b0eSStefan Hajnoczi         return;
244fc0b9b0eSStefan Hajnoczi     }
245fc0b9b0eSStefan Hajnoczi 
246fc0b9b0eSStefan Hajnoczi     timer_del(vsock->post_load_timer);
247fc0b9b0eSStefan Hajnoczi     timer_free(vsock->post_load_timer);
248fc0b9b0eSStefan Hajnoczi     vsock->post_load_timer = NULL;
249fc0b9b0eSStefan Hajnoczi }
250fc0b9b0eSStefan Hajnoczi 
251fc0b9b0eSStefan Hajnoczi static void vhost_vsock_post_load_timer_cb(void *opaque)
252fc0b9b0eSStefan Hajnoczi {
253fc0b9b0eSStefan Hajnoczi     VHostVSock *vsock = opaque;
254fc0b9b0eSStefan Hajnoczi 
255fc0b9b0eSStefan Hajnoczi     vhost_vsock_post_load_timer_cleanup(vsock);
256fc0b9b0eSStefan Hajnoczi     vhost_vsock_send_transport_reset(vsock);
257fc0b9b0eSStefan Hajnoczi }
258fc0b9b0eSStefan Hajnoczi 
25944b1ff31SDr. David Alan Gilbert static int vhost_vsock_pre_save(void *opaque)
26081cc8a65SHalil Pasic {
26181cc8a65SHalil Pasic     VHostVSock *vsock = opaque;
26281cc8a65SHalil Pasic 
26381cc8a65SHalil Pasic     /* At this point, backend must be stopped, otherwise
26481cc8a65SHalil Pasic      * it might keep writing to memory. */
26581cc8a65SHalil Pasic     assert(!vsock->vhost_dev.started);
26644b1ff31SDr. David Alan Gilbert 
26744b1ff31SDr. David Alan Gilbert     return 0;
26881cc8a65SHalil Pasic }
26981cc8a65SHalil Pasic 
27081cc8a65SHalil Pasic static int vhost_vsock_post_load(void *opaque, int version_id)
271fc0b9b0eSStefan Hajnoczi {
272fc0b9b0eSStefan Hajnoczi     VHostVSock *vsock = opaque;
273fc0b9b0eSStefan Hajnoczi     VirtIODevice *vdev = VIRTIO_DEVICE(vsock);
274fc0b9b0eSStefan Hajnoczi 
275fc0b9b0eSStefan Hajnoczi     if (virtio_queue_get_addr(vdev, 2)) {
276fc0b9b0eSStefan Hajnoczi         /* Defer transport reset event to a vm clock timer so that virtqueue
277fc0b9b0eSStefan Hajnoczi          * changes happen after migration has completed.
278fc0b9b0eSStefan Hajnoczi          */
279fc0b9b0eSStefan Hajnoczi         assert(!vsock->post_load_timer);
280fc0b9b0eSStefan Hajnoczi         vsock->post_load_timer =
281fc0b9b0eSStefan Hajnoczi             timer_new_ns(QEMU_CLOCK_VIRTUAL,
282fc0b9b0eSStefan Hajnoczi                          vhost_vsock_post_load_timer_cb,
283fc0b9b0eSStefan Hajnoczi                          vsock);
284fc0b9b0eSStefan Hajnoczi         timer_mod(vsock->post_load_timer, 1);
285fc0b9b0eSStefan Hajnoczi     }
286fc0b9b0eSStefan Hajnoczi     return 0;
287fc0b9b0eSStefan Hajnoczi }
288fc0b9b0eSStefan Hajnoczi 
28981cc8a65SHalil Pasic static const VMStateDescription vmstate_virtio_vhost_vsock = {
29081cc8a65SHalil Pasic     .name = "virtio-vhost_vsock",
29181cc8a65SHalil Pasic     .minimum_version_id = VHOST_VSOCK_SAVEVM_VERSION,
29281cc8a65SHalil Pasic     .version_id = VHOST_VSOCK_SAVEVM_VERSION,
29381cc8a65SHalil Pasic     .fields = (VMStateField[]) {
29481cc8a65SHalil Pasic         VMSTATE_VIRTIO_DEVICE,
29581cc8a65SHalil Pasic         VMSTATE_END_OF_LIST()
29681cc8a65SHalil Pasic     },
29781cc8a65SHalil Pasic     .pre_save = vhost_vsock_pre_save,
29881cc8a65SHalil Pasic     .post_load = vhost_vsock_post_load,
29981cc8a65SHalil Pasic };
300fc0b9b0eSStefan Hajnoczi 
301fc0b9b0eSStefan Hajnoczi static void vhost_vsock_device_realize(DeviceState *dev, Error **errp)
302fc0b9b0eSStefan Hajnoczi {
303fc0b9b0eSStefan Hajnoczi     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
304fc0b9b0eSStefan Hajnoczi     VHostVSock *vsock = VHOST_VSOCK(dev);
305fc0b9b0eSStefan Hajnoczi     int vhostfd;
306fc0b9b0eSStefan Hajnoczi     int ret;
307fc0b9b0eSStefan Hajnoczi 
308fc0b9b0eSStefan Hajnoczi     /* Refuse to use reserved CID numbers */
309fc0b9b0eSStefan Hajnoczi     if (vsock->conf.guest_cid <= 2) {
310fc0b9b0eSStefan Hajnoczi         error_setg(errp, "guest-cid property must be greater than 2");
311fc0b9b0eSStefan Hajnoczi         return;
312fc0b9b0eSStefan Hajnoczi     }
313fc0b9b0eSStefan Hajnoczi 
314fc0b9b0eSStefan Hajnoczi     if (vsock->conf.guest_cid > UINT32_MAX) {
315fc0b9b0eSStefan Hajnoczi         error_setg(errp, "guest-cid property must be a 32-bit number");
316fc0b9b0eSStefan Hajnoczi         return;
317fc0b9b0eSStefan Hajnoczi     }
318fc0b9b0eSStefan Hajnoczi 
319fc0b9b0eSStefan Hajnoczi     if (vsock->conf.vhostfd) {
320fc0b9b0eSStefan Hajnoczi         vhostfd = monitor_fd_param(cur_mon, vsock->conf.vhostfd, errp);
321fc0b9b0eSStefan Hajnoczi         if (vhostfd == -1) {
322fc0b9b0eSStefan Hajnoczi             error_prepend(errp, "vhost-vsock: unable to parse vhostfd: ");
323fc0b9b0eSStefan Hajnoczi             return;
324fc0b9b0eSStefan Hajnoczi         }
325fc0b9b0eSStefan Hajnoczi     } else {
326fc0b9b0eSStefan Hajnoczi         vhostfd = open("/dev/vhost-vsock", O_RDWR);
327fc0b9b0eSStefan Hajnoczi         if (vhostfd < 0) {
328f1e92c3dSNick Erdmann             error_setg_errno(errp, errno,
329fc0b9b0eSStefan Hajnoczi                              "vhost-vsock: failed to open vhost device");
330fc0b9b0eSStefan Hajnoczi             return;
331fc0b9b0eSStefan Hajnoczi         }
332fc0b9b0eSStefan Hajnoczi     }
333fc0b9b0eSStefan Hajnoczi 
334fc0b9b0eSStefan Hajnoczi     virtio_init(vdev, "vhost-vsock", VIRTIO_ID_VSOCK,
335fc0b9b0eSStefan Hajnoczi                 sizeof(struct virtio_vsock_config));
336fc0b9b0eSStefan Hajnoczi 
337fc0b9b0eSStefan Hajnoczi     /* Receive and transmit queues belong to vhost */
338e1932cf9SPan Nengyuan     vsock->recv_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE,
339e1932cf9SPan Nengyuan                                       vhost_vsock_handle_output);
340e1932cf9SPan Nengyuan     vsock->trans_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE,
341e1932cf9SPan Nengyuan                                        vhost_vsock_handle_output);
342fc0b9b0eSStefan Hajnoczi 
343fc0b9b0eSStefan Hajnoczi     /* The event queue belongs to QEMU */
344fc0b9b0eSStefan Hajnoczi     vsock->event_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE,
345fc0b9b0eSStefan Hajnoczi                                        vhost_vsock_handle_output);
346fc0b9b0eSStefan Hajnoczi 
347fc0b9b0eSStefan Hajnoczi     vsock->vhost_dev.nvqs = ARRAY_SIZE(vsock->vhost_vqs);
348fc0b9b0eSStefan Hajnoczi     vsock->vhost_dev.vqs = vsock->vhost_vqs;
349fc0b9b0eSStefan Hajnoczi     ret = vhost_dev_init(&vsock->vhost_dev, (void *)(uintptr_t)vhostfd,
350fc0b9b0eSStefan Hajnoczi                          VHOST_BACKEND_TYPE_KERNEL, 0);
351fc0b9b0eSStefan Hajnoczi     if (ret < 0) {
352fc0b9b0eSStefan Hajnoczi         error_setg_errno(errp, -ret, "vhost-vsock: vhost_dev_init failed");
353fc0b9b0eSStefan Hajnoczi         goto err_virtio;
354fc0b9b0eSStefan Hajnoczi     }
355fc0b9b0eSStefan Hajnoczi 
356fc0b9b0eSStefan Hajnoczi     ret = vhost_vsock_set_guest_cid(vsock);
357fc0b9b0eSStefan Hajnoczi     if (ret < 0) {
358fc0b9b0eSStefan Hajnoczi         error_setg_errno(errp, -ret, "vhost-vsock: unable to set guest cid");
359fc0b9b0eSStefan Hajnoczi         goto err_vhost_dev;
360fc0b9b0eSStefan Hajnoczi     }
361fc0b9b0eSStefan Hajnoczi 
362fc0b9b0eSStefan Hajnoczi     vsock->post_load_timer = NULL;
363fc0b9b0eSStefan Hajnoczi     return;
364fc0b9b0eSStefan Hajnoczi 
365fc0b9b0eSStefan Hajnoczi err_vhost_dev:
366fc0b9b0eSStefan Hajnoczi     vhost_dev_cleanup(&vsock->vhost_dev);
367e82cdba3SStefano Garzarella     /* vhost_dev_cleanup() closes the vhostfd passed to vhost_dev_init() */
368e82cdba3SStefano Garzarella     vhostfd = -1;
369fc0b9b0eSStefan Hajnoczi err_virtio:
370e1932cf9SPan Nengyuan     virtio_delete_queue(vsock->recv_vq);
371e1932cf9SPan Nengyuan     virtio_delete_queue(vsock->trans_vq);
372e1932cf9SPan Nengyuan     virtio_delete_queue(vsock->event_vq);
373fc0b9b0eSStefan Hajnoczi     virtio_cleanup(vdev);
374e82cdba3SStefano Garzarella     if (vhostfd >= 0) {
375fc0b9b0eSStefan Hajnoczi         close(vhostfd);
376e82cdba3SStefano Garzarella     }
377fc0b9b0eSStefan Hajnoczi     return;
378fc0b9b0eSStefan Hajnoczi }
379fc0b9b0eSStefan Hajnoczi 
380*b69c3c21SMarkus Armbruster static void vhost_vsock_device_unrealize(DeviceState *dev)
381fc0b9b0eSStefan Hajnoczi {
382fc0b9b0eSStefan Hajnoczi     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
383fc0b9b0eSStefan Hajnoczi     VHostVSock *vsock = VHOST_VSOCK(dev);
384fc0b9b0eSStefan Hajnoczi 
385fc0b9b0eSStefan Hajnoczi     vhost_vsock_post_load_timer_cleanup(vsock);
386fc0b9b0eSStefan Hajnoczi 
387fc0b9b0eSStefan Hajnoczi     /* This will stop vhost backend if appropriate. */
388fc0b9b0eSStefan Hajnoczi     vhost_vsock_set_status(vdev, 0);
389fc0b9b0eSStefan Hajnoczi 
390fc0b9b0eSStefan Hajnoczi     vhost_dev_cleanup(&vsock->vhost_dev);
391e1932cf9SPan Nengyuan     virtio_delete_queue(vsock->recv_vq);
392e1932cf9SPan Nengyuan     virtio_delete_queue(vsock->trans_vq);
393e1932cf9SPan Nengyuan     virtio_delete_queue(vsock->event_vq);
394fc0b9b0eSStefan Hajnoczi     virtio_cleanup(vdev);
395fc0b9b0eSStefan Hajnoczi }
396fc0b9b0eSStefan Hajnoczi 
397fc0b9b0eSStefan Hajnoczi static Property vhost_vsock_properties[] = {
398fc0b9b0eSStefan Hajnoczi     DEFINE_PROP_UINT64("guest-cid", VHostVSock, conf.guest_cid, 0),
399fc0b9b0eSStefan Hajnoczi     DEFINE_PROP_STRING("vhostfd", VHostVSock, conf.vhostfd),
400fc0b9b0eSStefan Hajnoczi     DEFINE_PROP_END_OF_LIST(),
401fc0b9b0eSStefan Hajnoczi };
402fc0b9b0eSStefan Hajnoczi 
403fc0b9b0eSStefan Hajnoczi static void vhost_vsock_class_init(ObjectClass *klass, void *data)
404fc0b9b0eSStefan Hajnoczi {
405fc0b9b0eSStefan Hajnoczi     DeviceClass *dc = DEVICE_CLASS(klass);
406fc0b9b0eSStefan Hajnoczi     VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
407fc0b9b0eSStefan Hajnoczi 
4084f67d30bSMarc-André Lureau     device_class_set_props(dc, vhost_vsock_properties);
409fc0b9b0eSStefan Hajnoczi     dc->vmsd = &vmstate_virtio_vhost_vsock;
410fc0b9b0eSStefan Hajnoczi     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
411fc0b9b0eSStefan Hajnoczi     vdc->realize = vhost_vsock_device_realize;
412fc0b9b0eSStefan Hajnoczi     vdc->unrealize = vhost_vsock_device_unrealize;
413fc0b9b0eSStefan Hajnoczi     vdc->get_features = vhost_vsock_get_features;
414fc0b9b0eSStefan Hajnoczi     vdc->get_config = vhost_vsock_get_config;
415fc0b9b0eSStefan Hajnoczi     vdc->set_status = vhost_vsock_set_status;
416fc0b9b0eSStefan Hajnoczi     vdc->guest_notifier_mask = vhost_vsock_guest_notifier_mask;
417fc0b9b0eSStefan Hajnoczi     vdc->guest_notifier_pending = vhost_vsock_guest_notifier_pending;
418fc0b9b0eSStefan Hajnoczi }
419fc0b9b0eSStefan Hajnoczi 
420fc0b9b0eSStefan Hajnoczi static const TypeInfo vhost_vsock_info = {
421fc0b9b0eSStefan Hajnoczi     .name = TYPE_VHOST_VSOCK,
422fc0b9b0eSStefan Hajnoczi     .parent = TYPE_VIRTIO_DEVICE,
423fc0b9b0eSStefan Hajnoczi     .instance_size = sizeof(VHostVSock),
424fc0b9b0eSStefan Hajnoczi     .class_init = vhost_vsock_class_init,
425fc0b9b0eSStefan Hajnoczi };
426fc0b9b0eSStefan Hajnoczi 
427fc0b9b0eSStefan Hajnoczi static void vhost_vsock_register_types(void)
428fc0b9b0eSStefan Hajnoczi {
429fc0b9b0eSStefan Hajnoczi     type_register_static(&vhost_vsock_info);
430fc0b9b0eSStefan Hajnoczi }
431fc0b9b0eSStefan Hajnoczi 
432fc0b9b0eSStefan Hajnoczi type_init(vhost_vsock_register_types)
433