1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
|
/*
* Vhost-user vsock virtio device
*
* Copyright 2020 Red Hat, Inc.
*
* This work is licensed under the terms of the GNU GPL, version 2 or
* (at your option) any later version. See the COPYING file in the
* top-level directory.
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
#include "hw/virtio/vhost-user-vsock.h"
static const int user_feature_bits[] = {
VIRTIO_F_VERSION_1,
VIRTIO_RING_F_INDIRECT_DESC,
VIRTIO_RING_F_EVENT_IDX,
VIRTIO_F_NOTIFY_ON_EMPTY,
VIRTIO_F_IN_ORDER,
VIRTIO_F_NOTIFICATION_DATA,
VHOST_INVALID_FEATURE_BIT
};
static void vuv_get_config(VirtIODevice *vdev, uint8_t *config)
{
VHostUserVSock *vsock = VHOST_USER_VSOCK(vdev);
memcpy(config, &vsock->vsockcfg, sizeof(struct virtio_vsock_config));
}
static int vuv_handle_config_change(struct vhost_dev *dev)
{
VHostUserVSock *vsock = VHOST_USER_VSOCK(dev->vdev);
Error *local_err = NULL;
int ret = vhost_dev_get_config(dev, (uint8_t *)&vsock->vsockcfg,
sizeof(struct virtio_vsock_config),
&local_err);
if (ret < 0) {
error_report_err(local_err);
return -1;
}
virtio_notify_config(dev->vdev);
return 0;
}
const VhostDevConfigOps vsock_ops = {
.vhost_dev_config_notifier = vuv_handle_config_change,
};
static void vuv_set_status(VirtIODevice *vdev, uint8_t status)
{
VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
bool should_start = virtio_device_should_start(vdev, status);
if (vhost_dev_is_started(&vvc->vhost_dev) == should_start) {
return;
}
if (should_start) {
int ret = vhost_vsock_common_start(vdev);
if (ret < 0) {
return;
}
} else {
vhost_vsock_common_stop(vdev);
}
}
static uint64_t vuv_get_features(VirtIODevice *vdev,
uint64_t features,
Error **errp)
{
VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
features = vhost_get_features(&vvc->vhost_dev, user_feature_bits, features);
return vhost_vsock_common_get_features(vdev, features, errp);
}
static const VMStateDescription vuv_vmstate = {
.name = "vhost-user-vsock",
.unmigratable = 1,
};
static void vuv_device_realize(DeviceState *dev, Error **errp)
{
VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev);
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserVSock *vsock = VHOST_USER_VSOCK(dev);
int ret;
if (!vsock->conf.chardev.chr) {
error_setg(errp, "missing chardev");
return;
}
if (!vhost_user_init(&vsock->vhost_user, &vsock->conf.chardev, errp)) {
return;
}
vhost_vsock_common_realize(vdev);
vhost_dev_set_config_notifier(&vvc->vhost_dev, &vsock_ops);
ret = vhost_dev_init(&vvc->vhost_dev, &vsock->vhost_user,
VHOST_BACKEND_TYPE_USER, 0, errp);
if (ret < 0) {
goto err_virtio;
}
ret = vhost_dev_get_config(&vvc->vhost_dev, (uint8_t *)&vsock->vsockcfg,
sizeof(struct virtio_vsock_config), errp);
if (ret < 0) {
goto err_vhost_dev;
}
return;
err_vhost_dev:
vhost_dev_cleanup(&vvc->vhost_dev);
err_virtio:
vhost_vsock_common_unrealize(vdev);
vhost_user_cleanup(&vsock->vhost_user);
return;
}
static void vuv_device_unrealize(DeviceState *dev)
{
VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev);
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserVSock *vsock = VHOST_USER_VSOCK(dev);
/* This will stop vhost backend if appropriate. */
vuv_set_status(vdev, 0);
vhost_dev_cleanup(&vvc->vhost_dev);
vhost_vsock_common_unrealize(vdev);
vhost_user_cleanup(&vsock->vhost_user);
}
static const Property vuv_properties[] = {
DEFINE_PROP_CHR("chardev", VHostUserVSock, conf.chardev),
};
static void vuv_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
device_class_set_props(dc, vuv_properties);
dc->vmsd = &vuv_vmstate;
vdc->realize = vuv_device_realize;
vdc->unrealize = vuv_device_unrealize;
vdc->get_features = vuv_get_features;
vdc->get_config = vuv_get_config;
vdc->set_status = vuv_set_status;
}
static const TypeInfo vuv_info = {
.name = TYPE_VHOST_USER_VSOCK,
.parent = TYPE_VHOST_VSOCK_COMMON,
.instance_size = sizeof(VHostUserVSock),
.class_init = vuv_class_init,
};
static void vuv_register_types(void)
{
type_register_static(&vuv_info);
}
type_init(vuv_register_types)
|