xref: /qemu/hw/virtio/vhost-user-base.c (revision 21596064081e8d0c0153f68714981c7f0e040973)
162759896SAlex Bennée /*
262759896SAlex Bennée  * Base vhost-user-base implementation. This can be used to derive a
362759896SAlex Bennée  * more fully specified vhost-user backend either generically (see
462759896SAlex Bennée  * vhost-user-device) or via a specific stub for a device which
562759896SAlex Bennée  * encapsulates some fixed parameters.
662759896SAlex Bennée  *
762759896SAlex Bennée  * Copyright (c) 2023 Linaro Ltd
862759896SAlex Bennée  * Author: Alex Bennée <alex.bennee@linaro.org>
962759896SAlex Bennée  *
1062759896SAlex Bennée  * SPDX-License-Identifier: GPL-2.0-or-later
1162759896SAlex Bennée  */
1262759896SAlex Bennée 
1362759896SAlex Bennée #include "qemu/osdep.h"
1462759896SAlex Bennée #include "qapi/error.h"
1562759896SAlex Bennée #include "hw/qdev-properties.h"
1662759896SAlex Bennée #include "hw/virtio/virtio-bus.h"
1762759896SAlex Bennée #include "hw/virtio/vhost-user-base.h"
1862759896SAlex Bennée #include "qemu/error-report.h"
1962759896SAlex Bennée 
vub_start(VirtIODevice * vdev)2062759896SAlex Bennée static void vub_start(VirtIODevice *vdev)
2162759896SAlex Bennée {
2262759896SAlex Bennée     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
2362759896SAlex Bennée     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
2462759896SAlex Bennée     VHostUserBase *vub = VHOST_USER_BASE(vdev);
2562759896SAlex Bennée     int ret, i;
2662759896SAlex Bennée 
2762759896SAlex Bennée     if (!k->set_guest_notifiers) {
2862759896SAlex Bennée         error_report("binding does not support guest notifiers");
2962759896SAlex Bennée         return;
3062759896SAlex Bennée     }
3162759896SAlex Bennée 
3262759896SAlex Bennée     ret = vhost_dev_enable_notifiers(&vub->vhost_dev, vdev);
3362759896SAlex Bennée     if (ret < 0) {
3462759896SAlex Bennée         error_report("Error enabling host notifiers: %d", -ret);
3562759896SAlex Bennée         return;
3662759896SAlex Bennée     }
3762759896SAlex Bennée 
3862759896SAlex Bennée     ret = k->set_guest_notifiers(qbus->parent, vub->vhost_dev.nvqs, true);
3962759896SAlex Bennée     if (ret < 0) {
4062759896SAlex Bennée         error_report("Error binding guest notifier: %d", -ret);
4162759896SAlex Bennée         goto err_host_notifiers;
4262759896SAlex Bennée     }
4362759896SAlex Bennée 
4462759896SAlex Bennée     vub->vhost_dev.acked_features = vdev->guest_features;
4562759896SAlex Bennée 
4662759896SAlex Bennée     ret = vhost_dev_start(&vub->vhost_dev, vdev, true);
4762759896SAlex Bennée     if (ret < 0) {
4862759896SAlex Bennée         error_report("Error starting vhost-user-base: %d", -ret);
4962759896SAlex Bennée         goto err_guest_notifiers;
5062759896SAlex Bennée     }
5162759896SAlex Bennée 
5262759896SAlex Bennée     /*
5362759896SAlex Bennée      * guest_notifier_mask/pending not used yet, so just unmask
5462759896SAlex Bennée      * everything here. virtio-pci will do the right thing by
5562759896SAlex Bennée      * enabling/disabling irqfd.
5662759896SAlex Bennée      */
5762759896SAlex Bennée     for (i = 0; i < vub->vhost_dev.nvqs; i++) {
5862759896SAlex Bennée         vhost_virtqueue_mask(&vub->vhost_dev, vdev, i, false);
5962759896SAlex Bennée     }
6062759896SAlex Bennée 
6162759896SAlex Bennée     return;
6262759896SAlex Bennée 
6362759896SAlex Bennée err_guest_notifiers:
6462759896SAlex Bennée     k->set_guest_notifiers(qbus->parent, vub->vhost_dev.nvqs, false);
6562759896SAlex Bennée err_host_notifiers:
6662759896SAlex Bennée     vhost_dev_disable_notifiers(&vub->vhost_dev, vdev);
6762759896SAlex Bennée }
6862759896SAlex Bennée 
vub_stop(VirtIODevice * vdev)69*bc85aae4SHaoqian He static int vub_stop(VirtIODevice *vdev)
7062759896SAlex Bennée {
7162759896SAlex Bennée     VHostUserBase *vub = VHOST_USER_BASE(vdev);
7262759896SAlex Bennée     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
7362759896SAlex Bennée     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
7462759896SAlex Bennée     int ret;
7562759896SAlex Bennée 
7662759896SAlex Bennée     if (!k->set_guest_notifiers) {
77*bc85aae4SHaoqian He         return 0;
7862759896SAlex Bennée     }
7962759896SAlex Bennée 
80*bc85aae4SHaoqian He     ret = vhost_dev_stop(&vub->vhost_dev, vdev, true);
8162759896SAlex Bennée 
82*bc85aae4SHaoqian He     if (k->set_guest_notifiers(qbus->parent, vub->vhost_dev.nvqs, false) < 0) {
8362759896SAlex Bennée         error_report("vhost guest notifier cleanup failed: %d", ret);
84*bc85aae4SHaoqian He         return -1;
8562759896SAlex Bennée     }
8662759896SAlex Bennée 
8762759896SAlex Bennée     vhost_dev_disable_notifiers(&vub->vhost_dev, vdev);
88*bc85aae4SHaoqian He     return ret;
8962759896SAlex Bennée }
9062759896SAlex Bennée 
vub_set_status(VirtIODevice * vdev,uint8_t status)91*bc85aae4SHaoqian He static int vub_set_status(VirtIODevice *vdev, uint8_t status)
9262759896SAlex Bennée {
9362759896SAlex Bennée     VHostUserBase *vub = VHOST_USER_BASE(vdev);
9462759896SAlex Bennée     bool should_start = virtio_device_should_start(vdev, status);
9562759896SAlex Bennée 
9662759896SAlex Bennée     if (vhost_dev_is_started(&vub->vhost_dev) == should_start) {
97*bc85aae4SHaoqian He         return 0;
9862759896SAlex Bennée     }
9962759896SAlex Bennée 
10062759896SAlex Bennée     if (should_start) {
10162759896SAlex Bennée         vub_start(vdev);
10262759896SAlex Bennée     } else {
103*bc85aae4SHaoqian He         int ret;
104*bc85aae4SHaoqian He         ret = vub_stop(vdev);
105*bc85aae4SHaoqian He         if (ret < 0) {
106*bc85aae4SHaoqian He             return ret;
10762759896SAlex Bennée         }
10862759896SAlex Bennée     }
109*bc85aae4SHaoqian He     return 0;
110*bc85aae4SHaoqian He }
11162759896SAlex Bennée 
11262759896SAlex Bennée /*
11362759896SAlex Bennée  * For an implementation where everything is delegated to the backend
11462759896SAlex Bennée  * we don't do anything other than return the full feature set offered
11562759896SAlex Bennée  * by the daemon (module the reserved feature bit).
11662759896SAlex Bennée  */
vub_get_features(VirtIODevice * vdev,uint64_t requested_features,Error ** errp)11762759896SAlex Bennée static uint64_t vub_get_features(VirtIODevice *vdev,
11862759896SAlex Bennée                                  uint64_t requested_features, Error **errp)
11962759896SAlex Bennée {
12062759896SAlex Bennée     VHostUserBase *vub = VHOST_USER_BASE(vdev);
12162759896SAlex Bennée     /* This should be set when the vhost connection initialises */
12262759896SAlex Bennée     g_assert(vub->vhost_dev.features);
12362759896SAlex Bennée     return vub->vhost_dev.features & ~(1ULL << VHOST_USER_F_PROTOCOL_FEATURES);
12462759896SAlex Bennée }
12562759896SAlex Bennée 
12662759896SAlex Bennée /*
12762759896SAlex Bennée  * To handle VirtIO config we need to know the size of the config
12862759896SAlex Bennée  * space. We don't cache the config but re-fetch it from the guest
12962759896SAlex Bennée  * every time in case something has changed.
13062759896SAlex Bennée  */
vub_get_config(VirtIODevice * vdev,uint8_t * config)13162759896SAlex Bennée static void vub_get_config(VirtIODevice *vdev, uint8_t *config)
13262759896SAlex Bennée {
13362759896SAlex Bennée     VHostUserBase *vub = VHOST_USER_BASE(vdev);
13462759896SAlex Bennée     Error *local_err = NULL;
13562759896SAlex Bennée 
13662759896SAlex Bennée     /*
13762759896SAlex Bennée      * There will have been a warning during vhost_dev_init, but lets
13862759896SAlex Bennée      * assert here as nothing will go right now.
13962759896SAlex Bennée      */
14062759896SAlex Bennée     g_assert(vub->config_size && vub->vhost_user.supports_config == true);
14162759896SAlex Bennée 
14262759896SAlex Bennée     if (vhost_dev_get_config(&vub->vhost_dev, config,
14362759896SAlex Bennée                              vub->config_size, &local_err)) {
14462759896SAlex Bennée         error_report_err(local_err);
14562759896SAlex Bennée     }
14662759896SAlex Bennée }
14762759896SAlex Bennée 
vub_set_config(VirtIODevice * vdev,const uint8_t * config_data)148a26105ddSLeo Yan static void vub_set_config(VirtIODevice *vdev, const uint8_t *config_data)
149a26105ddSLeo Yan {
150a26105ddSLeo Yan     VHostUserBase *vub = VHOST_USER_BASE(vdev);
151a26105ddSLeo Yan     int ret;
152a26105ddSLeo Yan 
153a26105ddSLeo Yan     g_assert(vub->config_size && vub->vhost_user.supports_config == true);
154a26105ddSLeo Yan 
155a26105ddSLeo Yan     ret = vhost_dev_set_config(&vub->vhost_dev, config_data,
156a26105ddSLeo Yan                                0, vub->config_size,
157a26105ddSLeo Yan                                VHOST_SET_CONFIG_TYPE_FRONTEND);
158a26105ddSLeo Yan     if (ret) {
159a26105ddSLeo Yan         error_report("vhost guest set device config space failed: %d", ret);
160a26105ddSLeo Yan         return;
161a26105ddSLeo Yan     }
162a26105ddSLeo Yan }
163a26105ddSLeo Yan 
16462759896SAlex Bennée /*
16562759896SAlex Bennée  * When the daemon signals an update to the config we just need to
16662759896SAlex Bennée  * signal the guest as we re-read the config on demand above.
16762759896SAlex Bennée  */
vub_config_notifier(struct vhost_dev * dev)16862759896SAlex Bennée static int vub_config_notifier(struct vhost_dev *dev)
16962759896SAlex Bennée {
17062759896SAlex Bennée     virtio_notify_config(dev->vdev);
17162759896SAlex Bennée     return 0;
17262759896SAlex Bennée }
17362759896SAlex Bennée 
17462759896SAlex Bennée const VhostDevConfigOps vub_config_ops = {
17562759896SAlex Bennée     .vhost_dev_config_notifier = vub_config_notifier,
17662759896SAlex Bennée };
17762759896SAlex Bennée 
vub_handle_output(VirtIODevice * vdev,VirtQueue * vq)17862759896SAlex Bennée static void vub_handle_output(VirtIODevice *vdev, VirtQueue *vq)
17962759896SAlex Bennée {
18062759896SAlex Bennée     /*
18162759896SAlex Bennée      * Not normally called; it's the daemon that handles the queue;
18262759896SAlex Bennée      * however virtio's cleanup path can call this.
18362759896SAlex Bennée      */
18462759896SAlex Bennée }
18562759896SAlex Bennée 
do_vhost_user_cleanup(VirtIODevice * vdev,VHostUserBase * vub)18662759896SAlex Bennée static void do_vhost_user_cleanup(VirtIODevice *vdev, VHostUserBase *vub)
18762759896SAlex Bennée {
18862759896SAlex Bennée     vhost_user_cleanup(&vub->vhost_user);
18962759896SAlex Bennée 
19062759896SAlex Bennée     for (int i = 0; i < vub->num_vqs; i++) {
19162759896SAlex Bennée         VirtQueue *vq = g_ptr_array_index(vub->vqs, i);
19262759896SAlex Bennée         virtio_delete_queue(vq);
19362759896SAlex Bennée     }
19462759896SAlex Bennée 
19562759896SAlex Bennée     virtio_cleanup(vdev);
19662759896SAlex Bennée }
19762759896SAlex Bennée 
vub_connect(DeviceState * dev)19862759896SAlex Bennée static int vub_connect(DeviceState *dev)
19962759896SAlex Bennée {
20062759896SAlex Bennée     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
20162759896SAlex Bennée     VHostUserBase *vub = VHOST_USER_BASE(vdev);
20262759896SAlex Bennée     struct vhost_dev *vhost_dev = &vub->vhost_dev;
20362759896SAlex Bennée 
20462759896SAlex Bennée     if (vub->connected) {
20562759896SAlex Bennée         return 0;
20662759896SAlex Bennée     }
20762759896SAlex Bennée     vub->connected = true;
20862759896SAlex Bennée 
20962759896SAlex Bennée     /*
21062759896SAlex Bennée      * If we support VHOST_USER_GET_CONFIG we must enable the notifier
21162759896SAlex Bennée      * so we can ping the guest when it updates.
21262759896SAlex Bennée      */
21362759896SAlex Bennée     if (vub->vhost_user.supports_config) {
21462759896SAlex Bennée         vhost_dev_set_config_notifier(vhost_dev, &vub_config_ops);
21562759896SAlex Bennée     }
21662759896SAlex Bennée 
21762759896SAlex Bennée     /* restore vhost state */
21862759896SAlex Bennée     if (virtio_device_started(vdev, vdev->status)) {
21962759896SAlex Bennée         vub_start(vdev);
22062759896SAlex Bennée     }
22162759896SAlex Bennée 
22262759896SAlex Bennée     return 0;
22362759896SAlex Bennée }
22462759896SAlex Bennée 
22564a312a2SAlex Bennée static void vub_event(void *opaque, QEMUChrEvent event);
22664a312a2SAlex Bennée 
vub_disconnect(DeviceState * dev)22762759896SAlex Bennée static void vub_disconnect(DeviceState *dev)
22862759896SAlex Bennée {
22962759896SAlex Bennée     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
23062759896SAlex Bennée     VHostUserBase *vub = VHOST_USER_BASE(vdev);
23125b8a0f4SAkihiko Odaki     struct vhost_virtqueue *vhost_vqs = vub->vhost_dev.vqs;
23262759896SAlex Bennée 
23362759896SAlex Bennée     if (!vub->connected) {
2346eaf0e61SLi Feng         goto done;
23562759896SAlex Bennée     }
23662759896SAlex Bennée     vub->connected = false;
23762759896SAlex Bennée 
23862759896SAlex Bennée     vub_stop(vdev);
23964a312a2SAlex Bennée     vhost_dev_cleanup(&vub->vhost_dev);
24025b8a0f4SAkihiko Odaki     g_free(vhost_vqs);
24164a312a2SAlex Bennée 
2426eaf0e61SLi Feng done:
24364a312a2SAlex Bennée     /* Re-instate the event handler for new connections */
24464a312a2SAlex Bennée     qemu_chr_fe_set_handlers(&vub->chardev,
24564a312a2SAlex Bennée                              NULL, NULL, vub_event,
24664a312a2SAlex Bennée                              NULL, dev, NULL, true);
24762759896SAlex Bennée }
24862759896SAlex Bennée 
vub_event(void * opaque,QEMUChrEvent event)24962759896SAlex Bennée static void vub_event(void *opaque, QEMUChrEvent event)
25062759896SAlex Bennée {
25162759896SAlex Bennée     DeviceState *dev = opaque;
25262759896SAlex Bennée     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
25362759896SAlex Bennée     VHostUserBase *vub = VHOST_USER_BASE(vdev);
25462759896SAlex Bennée 
25562759896SAlex Bennée     switch (event) {
25662759896SAlex Bennée     case CHR_EVENT_OPENED:
25762759896SAlex Bennée         if (vub_connect(dev) < 0) {
25862759896SAlex Bennée             qemu_chr_fe_disconnect(&vub->chardev);
25962759896SAlex Bennée             return;
26062759896SAlex Bennée         }
26162759896SAlex Bennée         break;
26262759896SAlex Bennée     case CHR_EVENT_CLOSED:
26364a312a2SAlex Bennée         /* defer close until later to avoid circular close */
26464a312a2SAlex Bennée         vhost_user_async_close(dev, &vub->chardev, &vub->vhost_dev,
2659569fe0aSLi Feng                                vub_disconnect);
26662759896SAlex Bennée         break;
26762759896SAlex Bennée     case CHR_EVENT_BREAK:
26862759896SAlex Bennée     case CHR_EVENT_MUX_IN:
26962759896SAlex Bennée     case CHR_EVENT_MUX_OUT:
27062759896SAlex Bennée         /* Ignore */
27162759896SAlex Bennée         break;
27262759896SAlex Bennée     }
27362759896SAlex Bennée }
27462759896SAlex Bennée 
vub_device_realize(DeviceState * dev,Error ** errp)27562759896SAlex Bennée static void vub_device_realize(DeviceState *dev, Error **errp)
27662759896SAlex Bennée {
27762759896SAlex Bennée     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
27862759896SAlex Bennée     VHostUserBase *vub = VHOST_USER_BASE(dev);
27962759896SAlex Bennée     int ret;
28062759896SAlex Bennée 
28162759896SAlex Bennée     if (!vub->chardev.chr) {
28262759896SAlex Bennée         error_setg(errp, "vhost-user-base: missing chardev");
28362759896SAlex Bennée         return;
28462759896SAlex Bennée     }
28562759896SAlex Bennée 
28662759896SAlex Bennée     if (!vub->virtio_id) {
28762759896SAlex Bennée         error_setg(errp, "vhost-user-base: need to define device id");
28862759896SAlex Bennée         return;
28962759896SAlex Bennée     }
29062759896SAlex Bennée 
29162759896SAlex Bennée     if (!vub->num_vqs) {
29262759896SAlex Bennée         vub->num_vqs = 1; /* reasonable default? */
29362759896SAlex Bennée     }
29462759896SAlex Bennée 
29562759896SAlex Bennée     if (!vub->vq_size) {
29662759896SAlex Bennée         vub->vq_size = 64;
29762759896SAlex Bennée     }
29862759896SAlex Bennée 
29962759896SAlex Bennée     /*
30062759896SAlex Bennée      * We can't handle config requests unless we know the size of the
30162759896SAlex Bennée      * config region, specialisations of the vhost-user-base will be
30262759896SAlex Bennée      * able to set this.
30362759896SAlex Bennée      */
30462759896SAlex Bennée     if (vub->config_size) {
30562759896SAlex Bennée         vub->vhost_user.supports_config = true;
30662759896SAlex Bennée     }
30762759896SAlex Bennée 
30862759896SAlex Bennée     if (!vhost_user_init(&vub->vhost_user, &vub->chardev, errp)) {
30962759896SAlex Bennée         return;
31062759896SAlex Bennée     }
31162759896SAlex Bennée 
31262759896SAlex Bennée     virtio_init(vdev, vub->virtio_id, vub->config_size);
31362759896SAlex Bennée 
31462759896SAlex Bennée     /*
31562759896SAlex Bennée      * Disable guest notifiers, by default all notifications will be via the
31662759896SAlex Bennée      * asynchronous vhost-user socket.
31762759896SAlex Bennée      */
31862759896SAlex Bennée     vdev->use_guest_notifier_mask = false;
31962759896SAlex Bennée 
32062759896SAlex Bennée     /* Allocate queues */
32162759896SAlex Bennée     vub->vqs = g_ptr_array_sized_new(vub->num_vqs);
32262759896SAlex Bennée     for (int i = 0; i < vub->num_vqs; i++) {
32362759896SAlex Bennée         g_ptr_array_add(vub->vqs,
32462759896SAlex Bennée                         virtio_add_queue(vdev, vub->vq_size,
32562759896SAlex Bennée                                          vub_handle_output));
32662759896SAlex Bennée     }
32762759896SAlex Bennée 
32862759896SAlex Bennée     vub->vhost_dev.nvqs = vub->num_vqs;
32962759896SAlex Bennée     vub->vhost_dev.vqs = g_new0(struct vhost_virtqueue, vub->vhost_dev.nvqs);
33062759896SAlex Bennée 
33162759896SAlex Bennée     /* connect to backend */
33262759896SAlex Bennée     ret = vhost_dev_init(&vub->vhost_dev, &vub->vhost_user,
33362759896SAlex Bennée                          VHOST_BACKEND_TYPE_USER, 0, errp);
33462759896SAlex Bennée 
33562759896SAlex Bennée     if (ret < 0) {
33662759896SAlex Bennée         do_vhost_user_cleanup(vdev, vub);
33762759896SAlex Bennée     }
33862759896SAlex Bennée 
33962759896SAlex Bennée     qemu_chr_fe_set_handlers(&vub->chardev, NULL, NULL, vub_event, NULL,
34062759896SAlex Bennée                              dev, NULL, true);
34162759896SAlex Bennée }
34262759896SAlex Bennée 
vub_device_unrealize(DeviceState * dev)34362759896SAlex Bennée static void vub_device_unrealize(DeviceState *dev)
34462759896SAlex Bennée {
34562759896SAlex Bennée     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
34662759896SAlex Bennée     VHostUserBase *vub = VHOST_USER_BASE(dev);
34762759896SAlex Bennée     struct vhost_virtqueue *vhost_vqs = vub->vhost_dev.vqs;
34862759896SAlex Bennée 
34962759896SAlex Bennée     /* This will stop vhost backend if appropriate. */
35062759896SAlex Bennée     vub_set_status(vdev, 0);
35162759896SAlex Bennée     vhost_dev_cleanup(&vub->vhost_dev);
35262759896SAlex Bennée     g_free(vhost_vqs);
35362759896SAlex Bennée     do_vhost_user_cleanup(vdev, vub);
35462759896SAlex Bennée }
35562759896SAlex Bennée 
vub_class_init(ObjectClass * klass,const void * data)35612d1a768SPhilippe Mathieu-Daudé static void vub_class_init(ObjectClass *klass, const void *data)
35762759896SAlex Bennée {
35862759896SAlex Bennée     VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
35962759896SAlex Bennée 
36062759896SAlex Bennée     vdc->realize = vub_device_realize;
36162759896SAlex Bennée     vdc->unrealize = vub_device_unrealize;
36262759896SAlex Bennée     vdc->get_features = vub_get_features;
36362759896SAlex Bennée     vdc->get_config = vub_get_config;
364a26105ddSLeo Yan     vdc->set_config = vub_set_config;
36562759896SAlex Bennée     vdc->set_status = vub_set_status;
36662759896SAlex Bennée }
36762759896SAlex Bennée 
36862759896SAlex Bennée static const TypeInfo vub_types[] = {
36962759896SAlex Bennée     {
37062759896SAlex Bennée         .name = TYPE_VHOST_USER_BASE,
37162759896SAlex Bennée         .parent = TYPE_VIRTIO_DEVICE,
37262759896SAlex Bennée         .instance_size = sizeof(VHostUserBase),
37362759896SAlex Bennée         .class_init = vub_class_init,
37462759896SAlex Bennée         .class_size = sizeof(VHostUserBaseClass),
37562759896SAlex Bennée         .abstract = true
37662759896SAlex Bennée     }
37762759896SAlex Bennée };
37862759896SAlex Bennée 
37962759896SAlex Bennée DEFINE_TYPES(vub_types)
380