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