15fe97d88SStefano Garzarella /* 25fe97d88SStefano Garzarella * Vhost-user vsock virtio device 35fe97d88SStefano Garzarella * 45fe97d88SStefano Garzarella * Copyright 2020 Red Hat, Inc. 55fe97d88SStefano Garzarella * 65fe97d88SStefano Garzarella * This work is licensed under the terms of the GNU GPL, version 2 or 75fe97d88SStefano Garzarella * (at your option) any later version. See the COPYING file in the 85fe97d88SStefano Garzarella * top-level directory. 95fe97d88SStefano Garzarella */ 105fe97d88SStefano Garzarella 115fe97d88SStefano Garzarella #include "qemu/osdep.h" 125fe97d88SStefano Garzarella 135fe97d88SStefano Garzarella #include "qapi/error.h" 145fe97d88SStefano Garzarella #include "qemu/error-report.h" 155fe97d88SStefano Garzarella #include "hw/qdev-properties.h" 16ce35e229SEduardo Habkost #include "hw/qdev-properties-system.h" 175fe97d88SStefano Garzarella #include "hw/virtio/vhost-user-vsock.h" 185fe97d88SStefano Garzarella 195fe97d88SStefano Garzarella static const int user_feature_bits[] = { 205fe97d88SStefano Garzarella VIRTIO_F_VERSION_1, 215fe97d88SStefano Garzarella VIRTIO_RING_F_INDIRECT_DESC, 225fe97d88SStefano Garzarella VIRTIO_RING_F_EVENT_IDX, 235fe97d88SStefano Garzarella VIRTIO_F_NOTIFY_ON_EMPTY, 24c03213fdSJonah Palmer VIRTIO_F_IN_ORDER, 25b937fa89SJonah Palmer VIRTIO_F_NOTIFICATION_DATA, 265fe97d88SStefano Garzarella VHOST_INVALID_FEATURE_BIT 275fe97d88SStefano Garzarella }; 285fe97d88SStefano Garzarella 295fe97d88SStefano Garzarella static void vuv_get_config(VirtIODevice *vdev, uint8_t *config) 305fe97d88SStefano Garzarella { 315fe97d88SStefano Garzarella VHostUserVSock *vsock = VHOST_USER_VSOCK(vdev); 325fe97d88SStefano Garzarella 335fe97d88SStefano Garzarella memcpy(config, &vsock->vsockcfg, sizeof(struct virtio_vsock_config)); 345fe97d88SStefano Garzarella } 355fe97d88SStefano Garzarella 365fe97d88SStefano Garzarella static int vuv_handle_config_change(struct vhost_dev *dev) 375fe97d88SStefano Garzarella { 385fe97d88SStefano Garzarella VHostUserVSock *vsock = VHOST_USER_VSOCK(dev->vdev); 3950de5138SKevin Wolf Error *local_err = NULL; 405fe97d88SStefano Garzarella int ret = vhost_dev_get_config(dev, (uint8_t *)&vsock->vsockcfg, 4150de5138SKevin Wolf sizeof(struct virtio_vsock_config), 4250de5138SKevin Wolf &local_err); 435fe97d88SStefano Garzarella if (ret < 0) { 4450de5138SKevin Wolf error_report_err(local_err); 455fe97d88SStefano Garzarella return -1; 465fe97d88SStefano Garzarella } 475fe97d88SStefano Garzarella 485fe97d88SStefano Garzarella virtio_notify_config(dev->vdev); 495fe97d88SStefano Garzarella 505fe97d88SStefano Garzarella return 0; 515fe97d88SStefano Garzarella } 525fe97d88SStefano Garzarella 535fe97d88SStefano Garzarella const VhostDevConfigOps vsock_ops = { 545fe97d88SStefano Garzarella .vhost_dev_config_notifier = vuv_handle_config_change, 555fe97d88SStefano Garzarella }; 565fe97d88SStefano Garzarella 57*bc85aae4SHaoqian He static int vuv_set_status(VirtIODevice *vdev, uint8_t status) 585fe97d88SStefano Garzarella { 595fe97d88SStefano Garzarella VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 60259d69c0SAlex Bennée bool should_start = virtio_device_should_start(vdev, status); 61*bc85aae4SHaoqian He int ret; 625fe97d88SStefano Garzarella 63b8f3e6a1SAlex Bennée if (vhost_dev_is_started(&vvc->vhost_dev) == should_start) { 64*bc85aae4SHaoqian He return 0; 655fe97d88SStefano Garzarella } 665fe97d88SStefano Garzarella 675fe97d88SStefano Garzarella if (should_start) { 68*bc85aae4SHaoqian He ret = vhost_vsock_common_start(vdev); 695fe97d88SStefano Garzarella if (ret < 0) { 70*bc85aae4SHaoqian He return ret; 715fe97d88SStefano Garzarella } 725fe97d88SStefano Garzarella } else { 73*bc85aae4SHaoqian He ret = vhost_vsock_common_stop(vdev); 74*bc85aae4SHaoqian He if (ret < 0) { 75*bc85aae4SHaoqian He return ret; 765fe97d88SStefano Garzarella } 775fe97d88SStefano Garzarella } 78*bc85aae4SHaoqian He return 0; 79*bc85aae4SHaoqian He } 805fe97d88SStefano Garzarella 815fe97d88SStefano Garzarella static uint64_t vuv_get_features(VirtIODevice *vdev, 825fe97d88SStefano Garzarella uint64_t features, 835fe97d88SStefano Garzarella Error **errp) 845fe97d88SStefano Garzarella { 855fe97d88SStefano Garzarella VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 865fe97d88SStefano Garzarella 8746ce0171SStefano Garzarella features = vhost_get_features(&vvc->vhost_dev, user_feature_bits, features); 8846ce0171SStefano Garzarella 8946ce0171SStefano Garzarella return vhost_vsock_common_get_features(vdev, features, errp); 905fe97d88SStefano Garzarella } 915fe97d88SStefano Garzarella 925fe97d88SStefano Garzarella static const VMStateDescription vuv_vmstate = { 935fe97d88SStefano Garzarella .name = "vhost-user-vsock", 945fe97d88SStefano Garzarella .unmigratable = 1, 955fe97d88SStefano Garzarella }; 965fe97d88SStefano Garzarella 975fe97d88SStefano Garzarella static void vuv_device_realize(DeviceState *dev, Error **errp) 985fe97d88SStefano Garzarella { 995fe97d88SStefano Garzarella VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev); 1005fe97d88SStefano Garzarella VirtIODevice *vdev = VIRTIO_DEVICE(dev); 1015fe97d88SStefano Garzarella VHostUserVSock *vsock = VHOST_USER_VSOCK(dev); 1025fe97d88SStefano Garzarella int ret; 1035fe97d88SStefano Garzarella 1045fe97d88SStefano Garzarella if (!vsock->conf.chardev.chr) { 1055fe97d88SStefano Garzarella error_setg(errp, "missing chardev"); 1065fe97d88SStefano Garzarella return; 1075fe97d88SStefano Garzarella } 1085fe97d88SStefano Garzarella 1095fe97d88SStefano Garzarella if (!vhost_user_init(&vsock->vhost_user, &vsock->conf.chardev, errp)) { 1105fe97d88SStefano Garzarella return; 1115fe97d88SStefano Garzarella } 1125fe97d88SStefano Garzarella 1133857cd5cSJonah Palmer vhost_vsock_common_realize(vdev); 1145fe97d88SStefano Garzarella 1155fe97d88SStefano Garzarella vhost_dev_set_config_notifier(&vvc->vhost_dev, &vsock_ops); 1165fe97d88SStefano Garzarella 1175fe97d88SStefano Garzarella ret = vhost_dev_init(&vvc->vhost_dev, &vsock->vhost_user, 118a6945f22SKevin Wolf VHOST_BACKEND_TYPE_USER, 0, errp); 1195fe97d88SStefano Garzarella if (ret < 0) { 1205fe97d88SStefano Garzarella goto err_virtio; 1215fe97d88SStefano Garzarella } 1225fe97d88SStefano Garzarella 1235fe97d88SStefano Garzarella ret = vhost_dev_get_config(&vvc->vhost_dev, (uint8_t *)&vsock->vsockcfg, 12450de5138SKevin Wolf sizeof(struct virtio_vsock_config), errp); 1255fe97d88SStefano Garzarella if (ret < 0) { 1265fe97d88SStefano Garzarella goto err_vhost_dev; 1275fe97d88SStefano Garzarella } 1285fe97d88SStefano Garzarella 1295fe97d88SStefano Garzarella return; 1305fe97d88SStefano Garzarella 1315fe97d88SStefano Garzarella err_vhost_dev: 1325fe97d88SStefano Garzarella vhost_dev_cleanup(&vvc->vhost_dev); 1335fe97d88SStefano Garzarella err_virtio: 1345fe97d88SStefano Garzarella vhost_vsock_common_unrealize(vdev); 1355fe97d88SStefano Garzarella vhost_user_cleanup(&vsock->vhost_user); 1365fe97d88SStefano Garzarella } 1375fe97d88SStefano Garzarella 1385fe97d88SStefano Garzarella static void vuv_device_unrealize(DeviceState *dev) 1395fe97d88SStefano Garzarella { 1405fe97d88SStefano Garzarella VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev); 1415fe97d88SStefano Garzarella VirtIODevice *vdev = VIRTIO_DEVICE(dev); 1425fe97d88SStefano Garzarella VHostUserVSock *vsock = VHOST_USER_VSOCK(dev); 1435fe97d88SStefano Garzarella 1445fe97d88SStefano Garzarella /* This will stop vhost backend if appropriate. */ 1455fe97d88SStefano Garzarella vuv_set_status(vdev, 0); 1465fe97d88SStefano Garzarella 1475fe97d88SStefano Garzarella vhost_dev_cleanup(&vvc->vhost_dev); 1485fe97d88SStefano Garzarella 1495fe97d88SStefano Garzarella vhost_vsock_common_unrealize(vdev); 1505fe97d88SStefano Garzarella 1515fe97d88SStefano Garzarella vhost_user_cleanup(&vsock->vhost_user); 1525fe97d88SStefano Garzarella 1535fe97d88SStefano Garzarella } 1545fe97d88SStefano Garzarella 1551577a918SRichard Henderson static const Property vuv_properties[] = { 1565fe97d88SStefano Garzarella DEFINE_PROP_CHR("chardev", VHostUserVSock, conf.chardev), 1575fe97d88SStefano Garzarella }; 1585fe97d88SStefano Garzarella 15912d1a768SPhilippe Mathieu-Daudé static void vuv_class_init(ObjectClass *klass, const void *data) 1605fe97d88SStefano Garzarella { 1615fe97d88SStefano Garzarella DeviceClass *dc = DEVICE_CLASS(klass); 1625fe97d88SStefano Garzarella VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 1635fe97d88SStefano Garzarella 1645fe97d88SStefano Garzarella device_class_set_props(dc, vuv_properties); 1655fe97d88SStefano Garzarella dc->vmsd = &vuv_vmstate; 1665fe97d88SStefano Garzarella vdc->realize = vuv_device_realize; 1675fe97d88SStefano Garzarella vdc->unrealize = vuv_device_unrealize; 1685fe97d88SStefano Garzarella vdc->get_features = vuv_get_features; 1695fe97d88SStefano Garzarella vdc->get_config = vuv_get_config; 1705fe97d88SStefano Garzarella vdc->set_status = vuv_set_status; 1715fe97d88SStefano Garzarella } 1725fe97d88SStefano Garzarella 1735fe97d88SStefano Garzarella static const TypeInfo vuv_info = { 1745fe97d88SStefano Garzarella .name = TYPE_VHOST_USER_VSOCK, 1755fe97d88SStefano Garzarella .parent = TYPE_VHOST_VSOCK_COMMON, 1765fe97d88SStefano Garzarella .instance_size = sizeof(VHostUserVSock), 1775fe97d88SStefano Garzarella .class_init = vuv_class_init, 1785fe97d88SStefano Garzarella }; 1795fe97d88SStefano Garzarella 1805fe97d88SStefano Garzarella static void vuv_register_types(void) 1815fe97d88SStefano Garzarella { 1825fe97d88SStefano Garzarella type_register_static(&vuv_info); 1835fe97d88SStefano Garzarella } 1845fe97d88SStefano Garzarella 1855fe97d88SStefano Garzarella type_init(vuv_register_types) 186