xref: /qemu/hw/virtio/vhost-user-base.c (revision 9569fe0aacbe6c7752935c9ede427ca1e8aafe51)
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 
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 
6962759896SAlex Bennée static void 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) {
7762759896SAlex Bennée         return;
7862759896SAlex Bennée     }
7962759896SAlex Bennée 
8062759896SAlex Bennée     vhost_dev_stop(&vub->vhost_dev, vdev, true);
8162759896SAlex Bennée 
8262759896SAlex Bennée     ret = k->set_guest_notifiers(qbus->parent, vub->vhost_dev.nvqs, false);
8362759896SAlex Bennée     if (ret < 0) {
8462759896SAlex Bennée         error_report("vhost guest notifier cleanup failed: %d", ret);
8562759896SAlex Bennée         return;
8662759896SAlex Bennée     }
8762759896SAlex Bennée 
8862759896SAlex Bennée     vhost_dev_disable_notifiers(&vub->vhost_dev, vdev);
8962759896SAlex Bennée }
9062759896SAlex Bennée 
9162759896SAlex Bennée static void 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) {
9762759896SAlex Bennée         return;
9862759896SAlex Bennée     }
9962759896SAlex Bennée 
10062759896SAlex Bennée     if (should_start) {
10162759896SAlex Bennée         vub_start(vdev);
10262759896SAlex Bennée     } else {
10362759896SAlex Bennée         vub_stop(vdev);
10462759896SAlex Bennée     }
10562759896SAlex Bennée }
10662759896SAlex Bennée 
10762759896SAlex Bennée /*
10862759896SAlex Bennée  * For an implementation where everything is delegated to the backend
10962759896SAlex Bennée  * we don't do anything other than return the full feature set offered
11062759896SAlex Bennée  * by the daemon (module the reserved feature bit).
11162759896SAlex Bennée  */
11262759896SAlex Bennée static uint64_t vub_get_features(VirtIODevice *vdev,
11362759896SAlex Bennée                                  uint64_t requested_features, Error **errp)
11462759896SAlex Bennée {
11562759896SAlex Bennée     VHostUserBase *vub = VHOST_USER_BASE(vdev);
11662759896SAlex Bennée     /* This should be set when the vhost connection initialises */
11762759896SAlex Bennée     g_assert(vub->vhost_dev.features);
11862759896SAlex Bennée     return vub->vhost_dev.features & ~(1ULL << VHOST_USER_F_PROTOCOL_FEATURES);
11962759896SAlex Bennée }
12062759896SAlex Bennée 
12162759896SAlex Bennée /*
12262759896SAlex Bennée  * To handle VirtIO config we need to know the size of the config
12362759896SAlex Bennée  * space. We don't cache the config but re-fetch it from the guest
12462759896SAlex Bennée  * every time in case something has changed.
12562759896SAlex Bennée  */
12662759896SAlex Bennée static void vub_get_config(VirtIODevice *vdev, uint8_t *config)
12762759896SAlex Bennée {
12862759896SAlex Bennée     VHostUserBase *vub = VHOST_USER_BASE(vdev);
12962759896SAlex Bennée     Error *local_err = NULL;
13062759896SAlex Bennée 
13162759896SAlex Bennée     /*
13262759896SAlex Bennée      * There will have been a warning during vhost_dev_init, but lets
13362759896SAlex Bennée      * assert here as nothing will go right now.
13462759896SAlex Bennée      */
13562759896SAlex Bennée     g_assert(vub->config_size && vub->vhost_user.supports_config == true);
13662759896SAlex Bennée 
13762759896SAlex Bennée     if (vhost_dev_get_config(&vub->vhost_dev, config,
13862759896SAlex Bennée                              vub->config_size, &local_err)) {
13962759896SAlex Bennée         error_report_err(local_err);
14062759896SAlex Bennée     }
14162759896SAlex Bennée }
14262759896SAlex Bennée 
143a26105ddSLeo Yan static void vub_set_config(VirtIODevice *vdev, const uint8_t *config_data)
144a26105ddSLeo Yan {
145a26105ddSLeo Yan     VHostUserBase *vub = VHOST_USER_BASE(vdev);
146a26105ddSLeo Yan     int ret;
147a26105ddSLeo Yan 
148a26105ddSLeo Yan     g_assert(vub->config_size && vub->vhost_user.supports_config == true);
149a26105ddSLeo Yan 
150a26105ddSLeo Yan     ret = vhost_dev_set_config(&vub->vhost_dev, config_data,
151a26105ddSLeo Yan                                0, vub->config_size,
152a26105ddSLeo Yan                                VHOST_SET_CONFIG_TYPE_FRONTEND);
153a26105ddSLeo Yan     if (ret) {
154a26105ddSLeo Yan         error_report("vhost guest set device config space failed: %d", ret);
155a26105ddSLeo Yan         return;
156a26105ddSLeo Yan     }
157a26105ddSLeo Yan }
158a26105ddSLeo Yan 
15962759896SAlex Bennée /*
16062759896SAlex Bennée  * When the daemon signals an update to the config we just need to
16162759896SAlex Bennée  * signal the guest as we re-read the config on demand above.
16262759896SAlex Bennée  */
16362759896SAlex Bennée static int vub_config_notifier(struct vhost_dev *dev)
16462759896SAlex Bennée {
16562759896SAlex Bennée     virtio_notify_config(dev->vdev);
16662759896SAlex Bennée     return 0;
16762759896SAlex Bennée }
16862759896SAlex Bennée 
16962759896SAlex Bennée const VhostDevConfigOps vub_config_ops = {
17062759896SAlex Bennée     .vhost_dev_config_notifier = vub_config_notifier,
17162759896SAlex Bennée };
17262759896SAlex Bennée 
17362759896SAlex Bennée static void vub_handle_output(VirtIODevice *vdev, VirtQueue *vq)
17462759896SAlex Bennée {
17562759896SAlex Bennée     /*
17662759896SAlex Bennée      * Not normally called; it's the daemon that handles the queue;
17762759896SAlex Bennée      * however virtio's cleanup path can call this.
17862759896SAlex Bennée      */
17962759896SAlex Bennée }
18062759896SAlex Bennée 
18162759896SAlex Bennée static void do_vhost_user_cleanup(VirtIODevice *vdev, VHostUserBase *vub)
18262759896SAlex Bennée {
18362759896SAlex Bennée     vhost_user_cleanup(&vub->vhost_user);
18462759896SAlex Bennée 
18562759896SAlex Bennée     for (int i = 0; i < vub->num_vqs; i++) {
18662759896SAlex Bennée         VirtQueue *vq = g_ptr_array_index(vub->vqs, i);
18762759896SAlex Bennée         virtio_delete_queue(vq);
18862759896SAlex Bennée     }
18962759896SAlex Bennée 
19062759896SAlex Bennée     virtio_cleanup(vdev);
19162759896SAlex Bennée }
19262759896SAlex Bennée 
19362759896SAlex Bennée static int vub_connect(DeviceState *dev)
19462759896SAlex Bennée {
19562759896SAlex Bennée     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
19662759896SAlex Bennée     VHostUserBase *vub = VHOST_USER_BASE(vdev);
19762759896SAlex Bennée     struct vhost_dev *vhost_dev = &vub->vhost_dev;
19862759896SAlex Bennée 
19962759896SAlex Bennée     if (vub->connected) {
20062759896SAlex Bennée         return 0;
20162759896SAlex Bennée     }
20262759896SAlex Bennée     vub->connected = true;
20362759896SAlex Bennée 
20462759896SAlex Bennée     /*
20562759896SAlex Bennée      * If we support VHOST_USER_GET_CONFIG we must enable the notifier
20662759896SAlex Bennée      * so we can ping the guest when it updates.
20762759896SAlex Bennée      */
20862759896SAlex Bennée     if (vub->vhost_user.supports_config) {
20962759896SAlex Bennée         vhost_dev_set_config_notifier(vhost_dev, &vub_config_ops);
21062759896SAlex Bennée     }
21162759896SAlex Bennée 
21262759896SAlex Bennée     /* restore vhost state */
21362759896SAlex Bennée     if (virtio_device_started(vdev, vdev->status)) {
21462759896SAlex Bennée         vub_start(vdev);
21562759896SAlex Bennée     }
21662759896SAlex Bennée 
21762759896SAlex Bennée     return 0;
21862759896SAlex Bennée }
21962759896SAlex Bennée 
22064a312a2SAlex Bennée static void vub_event(void *opaque, QEMUChrEvent event);
22164a312a2SAlex Bennée 
22262759896SAlex Bennée static void vub_disconnect(DeviceState *dev)
22362759896SAlex Bennée {
22462759896SAlex Bennée     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
22562759896SAlex Bennée     VHostUserBase *vub = VHOST_USER_BASE(vdev);
22662759896SAlex Bennée 
22762759896SAlex Bennée     if (!vub->connected) {
22862759896SAlex Bennée         return;
22962759896SAlex Bennée     }
23062759896SAlex Bennée     vub->connected = false;
23162759896SAlex Bennée 
23262759896SAlex Bennée     vub_stop(vdev);
23364a312a2SAlex Bennée     vhost_dev_cleanup(&vub->vhost_dev);
23464a312a2SAlex Bennée 
23564a312a2SAlex Bennée     /* Re-instate the event handler for new connections */
23664a312a2SAlex Bennée     qemu_chr_fe_set_handlers(&vub->chardev,
23764a312a2SAlex Bennée                              NULL, NULL, vub_event,
23864a312a2SAlex Bennée                              NULL, dev, NULL, true);
23962759896SAlex Bennée }
24062759896SAlex Bennée 
24162759896SAlex Bennée static void vub_event(void *opaque, QEMUChrEvent event)
24262759896SAlex Bennée {
24362759896SAlex Bennée     DeviceState *dev = opaque;
24462759896SAlex Bennée     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
24562759896SAlex Bennée     VHostUserBase *vub = VHOST_USER_BASE(vdev);
24662759896SAlex Bennée 
24762759896SAlex Bennée     switch (event) {
24862759896SAlex Bennée     case CHR_EVENT_OPENED:
24962759896SAlex Bennée         if (vub_connect(dev) < 0) {
25062759896SAlex Bennée             qemu_chr_fe_disconnect(&vub->chardev);
25162759896SAlex Bennée             return;
25262759896SAlex Bennée         }
25362759896SAlex Bennée         break;
25462759896SAlex Bennée     case CHR_EVENT_CLOSED:
25564a312a2SAlex Bennée         /* defer close until later to avoid circular close */
25664a312a2SAlex Bennée         vhost_user_async_close(dev, &vub->chardev, &vub->vhost_dev,
257*9569fe0aSLi Feng                                vub_disconnect);
25862759896SAlex Bennée         break;
25962759896SAlex Bennée     case CHR_EVENT_BREAK:
26062759896SAlex Bennée     case CHR_EVENT_MUX_IN:
26162759896SAlex Bennée     case CHR_EVENT_MUX_OUT:
26262759896SAlex Bennée         /* Ignore */
26362759896SAlex Bennée         break;
26462759896SAlex Bennée     }
26562759896SAlex Bennée }
26662759896SAlex Bennée 
26762759896SAlex Bennée static void vub_device_realize(DeviceState *dev, Error **errp)
26862759896SAlex Bennée {
26962759896SAlex Bennée     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
27062759896SAlex Bennée     VHostUserBase *vub = VHOST_USER_BASE(dev);
27162759896SAlex Bennée     int ret;
27262759896SAlex Bennée 
27362759896SAlex Bennée     if (!vub->chardev.chr) {
27462759896SAlex Bennée         error_setg(errp, "vhost-user-base: missing chardev");
27562759896SAlex Bennée         return;
27662759896SAlex Bennée     }
27762759896SAlex Bennée 
27862759896SAlex Bennée     if (!vub->virtio_id) {
27962759896SAlex Bennée         error_setg(errp, "vhost-user-base: need to define device id");
28062759896SAlex Bennée         return;
28162759896SAlex Bennée     }
28262759896SAlex Bennée 
28362759896SAlex Bennée     if (!vub->num_vqs) {
28462759896SAlex Bennée         vub->num_vqs = 1; /* reasonable default? */
28562759896SAlex Bennée     }
28662759896SAlex Bennée 
28762759896SAlex Bennée     if (!vub->vq_size) {
28862759896SAlex Bennée         vub->vq_size = 64;
28962759896SAlex Bennée     }
29062759896SAlex Bennée 
29162759896SAlex Bennée     /*
29262759896SAlex Bennée      * We can't handle config requests unless we know the size of the
29362759896SAlex Bennée      * config region, specialisations of the vhost-user-base will be
29462759896SAlex Bennée      * able to set this.
29562759896SAlex Bennée      */
29662759896SAlex Bennée     if (vub->config_size) {
29762759896SAlex Bennée         vub->vhost_user.supports_config = true;
29862759896SAlex Bennée     }
29962759896SAlex Bennée 
30062759896SAlex Bennée     if (!vhost_user_init(&vub->vhost_user, &vub->chardev, errp)) {
30162759896SAlex Bennée         return;
30262759896SAlex Bennée     }
30362759896SAlex Bennée 
30462759896SAlex Bennée     virtio_init(vdev, vub->virtio_id, vub->config_size);
30562759896SAlex Bennée 
30662759896SAlex Bennée     /*
30762759896SAlex Bennée      * Disable guest notifiers, by default all notifications will be via the
30862759896SAlex Bennée      * asynchronous vhost-user socket.
30962759896SAlex Bennée      */
31062759896SAlex Bennée     vdev->use_guest_notifier_mask = false;
31162759896SAlex Bennée 
31262759896SAlex Bennée     /* Allocate queues */
31362759896SAlex Bennée     vub->vqs = g_ptr_array_sized_new(vub->num_vqs);
31462759896SAlex Bennée     for (int i = 0; i < vub->num_vqs; i++) {
31562759896SAlex Bennée         g_ptr_array_add(vub->vqs,
31662759896SAlex Bennée                         virtio_add_queue(vdev, vub->vq_size,
31762759896SAlex Bennée                                          vub_handle_output));
31862759896SAlex Bennée     }
31962759896SAlex Bennée 
32062759896SAlex Bennée     vub->vhost_dev.nvqs = vub->num_vqs;
32162759896SAlex Bennée     vub->vhost_dev.vqs = g_new0(struct vhost_virtqueue, vub->vhost_dev.nvqs);
32262759896SAlex Bennée 
32362759896SAlex Bennée     /* connect to backend */
32462759896SAlex Bennée     ret = vhost_dev_init(&vub->vhost_dev, &vub->vhost_user,
32562759896SAlex Bennée                          VHOST_BACKEND_TYPE_USER, 0, errp);
32662759896SAlex Bennée 
32762759896SAlex Bennée     if (ret < 0) {
32862759896SAlex Bennée         do_vhost_user_cleanup(vdev, vub);
32962759896SAlex Bennée     }
33062759896SAlex Bennée 
33162759896SAlex Bennée     qemu_chr_fe_set_handlers(&vub->chardev, NULL, NULL, vub_event, NULL,
33262759896SAlex Bennée                              dev, NULL, true);
33362759896SAlex Bennée }
33462759896SAlex Bennée 
33562759896SAlex Bennée static void vub_device_unrealize(DeviceState *dev)
33662759896SAlex Bennée {
33762759896SAlex Bennée     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
33862759896SAlex Bennée     VHostUserBase *vub = VHOST_USER_BASE(dev);
33962759896SAlex Bennée     struct vhost_virtqueue *vhost_vqs = vub->vhost_dev.vqs;
34062759896SAlex Bennée 
34162759896SAlex Bennée     /* This will stop vhost backend if appropriate. */
34262759896SAlex Bennée     vub_set_status(vdev, 0);
34362759896SAlex Bennée     vhost_dev_cleanup(&vub->vhost_dev);
34462759896SAlex Bennée     g_free(vhost_vqs);
34562759896SAlex Bennée     do_vhost_user_cleanup(vdev, vub);
34662759896SAlex Bennée }
34762759896SAlex Bennée 
34862759896SAlex Bennée static void vub_class_init(ObjectClass *klass, void *data)
34962759896SAlex Bennée {
35062759896SAlex Bennée     VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
35162759896SAlex Bennée 
35262759896SAlex Bennée     vdc->realize = vub_device_realize;
35362759896SAlex Bennée     vdc->unrealize = vub_device_unrealize;
35462759896SAlex Bennée     vdc->get_features = vub_get_features;
35562759896SAlex Bennée     vdc->get_config = vub_get_config;
356a26105ddSLeo Yan     vdc->set_config = vub_set_config;
35762759896SAlex Bennée     vdc->set_status = vub_set_status;
35862759896SAlex Bennée }
35962759896SAlex Bennée 
36062759896SAlex Bennée static const TypeInfo vub_types[] = {
36162759896SAlex Bennée     {
36262759896SAlex Bennée         .name = TYPE_VHOST_USER_BASE,
36362759896SAlex Bennée         .parent = TYPE_VIRTIO_DEVICE,
36462759896SAlex Bennée         .instance_size = sizeof(VHostUserBase),
36562759896SAlex Bennée         .class_init = vub_class_init,
36662759896SAlex Bennée         .class_size = sizeof(VHostUserBaseClass),
36762759896SAlex Bennée         .abstract = true
36862759896SAlex Bennée     }
36962759896SAlex Bennée };
37062759896SAlex Bennée 
37162759896SAlex Bennée DEFINE_TYPES(vub_types)
372