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, 245fe97d88SStefano Garzarella VHOST_INVALID_FEATURE_BIT 255fe97d88SStefano Garzarella }; 265fe97d88SStefano Garzarella 275fe97d88SStefano Garzarella static void vuv_get_config(VirtIODevice *vdev, uint8_t *config) 285fe97d88SStefano Garzarella { 295fe97d88SStefano Garzarella VHostUserVSock *vsock = VHOST_USER_VSOCK(vdev); 305fe97d88SStefano Garzarella 315fe97d88SStefano Garzarella memcpy(config, &vsock->vsockcfg, sizeof(struct virtio_vsock_config)); 325fe97d88SStefano Garzarella } 335fe97d88SStefano Garzarella 345fe97d88SStefano Garzarella static int vuv_handle_config_change(struct vhost_dev *dev) 355fe97d88SStefano Garzarella { 365fe97d88SStefano Garzarella VHostUserVSock *vsock = VHOST_USER_VSOCK(dev->vdev); 3750de5138SKevin Wolf Error *local_err = NULL; 385fe97d88SStefano Garzarella int ret = vhost_dev_get_config(dev, (uint8_t *)&vsock->vsockcfg, 3950de5138SKevin Wolf sizeof(struct virtio_vsock_config), 4050de5138SKevin Wolf &local_err); 415fe97d88SStefano Garzarella if (ret < 0) { 4250de5138SKevin Wolf error_report_err(local_err); 435fe97d88SStefano Garzarella return -1; 445fe97d88SStefano Garzarella } 455fe97d88SStefano Garzarella 465fe97d88SStefano Garzarella virtio_notify_config(dev->vdev); 475fe97d88SStefano Garzarella 485fe97d88SStefano Garzarella return 0; 495fe97d88SStefano Garzarella } 505fe97d88SStefano Garzarella 515fe97d88SStefano Garzarella const VhostDevConfigOps vsock_ops = { 525fe97d88SStefano Garzarella .vhost_dev_config_notifier = vuv_handle_config_change, 535fe97d88SStefano Garzarella }; 545fe97d88SStefano Garzarella 555fe97d88SStefano Garzarella static void vuv_set_status(VirtIODevice *vdev, uint8_t status) 565fe97d88SStefano Garzarella { 575fe97d88SStefano Garzarella VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 58*259d69c0SAlex Bennée bool should_start = virtio_device_should_start(vdev, status); 595fe97d88SStefano Garzarella 60b8f3e6a1SAlex Bennée if (vhost_dev_is_started(&vvc->vhost_dev) == should_start) { 615fe97d88SStefano Garzarella return; 625fe97d88SStefano Garzarella } 635fe97d88SStefano Garzarella 645fe97d88SStefano Garzarella if (should_start) { 655fe97d88SStefano Garzarella int ret = vhost_vsock_common_start(vdev); 665fe97d88SStefano Garzarella if (ret < 0) { 675fe97d88SStefano Garzarella return; 685fe97d88SStefano Garzarella } 695fe97d88SStefano Garzarella } else { 705fe97d88SStefano Garzarella vhost_vsock_common_stop(vdev); 715fe97d88SStefano Garzarella } 725fe97d88SStefano Garzarella } 735fe97d88SStefano Garzarella 745fe97d88SStefano Garzarella static uint64_t vuv_get_features(VirtIODevice *vdev, 755fe97d88SStefano Garzarella uint64_t features, 765fe97d88SStefano Garzarella Error **errp) 775fe97d88SStefano Garzarella { 785fe97d88SStefano Garzarella VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 795fe97d88SStefano Garzarella 8046ce0171SStefano Garzarella features = vhost_get_features(&vvc->vhost_dev, user_feature_bits, features); 8146ce0171SStefano Garzarella 8246ce0171SStefano Garzarella return vhost_vsock_common_get_features(vdev, features, errp); 835fe97d88SStefano Garzarella } 845fe97d88SStefano Garzarella 855fe97d88SStefano Garzarella static const VMStateDescription vuv_vmstate = { 865fe97d88SStefano Garzarella .name = "vhost-user-vsock", 875fe97d88SStefano Garzarella .unmigratable = 1, 885fe97d88SStefano Garzarella }; 895fe97d88SStefano Garzarella 905fe97d88SStefano Garzarella static void vuv_device_realize(DeviceState *dev, Error **errp) 915fe97d88SStefano Garzarella { 925fe97d88SStefano Garzarella VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev); 935fe97d88SStefano Garzarella VirtIODevice *vdev = VIRTIO_DEVICE(dev); 945fe97d88SStefano Garzarella VHostUserVSock *vsock = VHOST_USER_VSOCK(dev); 955fe97d88SStefano Garzarella int ret; 965fe97d88SStefano Garzarella 975fe97d88SStefano Garzarella if (!vsock->conf.chardev.chr) { 985fe97d88SStefano Garzarella error_setg(errp, "missing chardev"); 995fe97d88SStefano Garzarella return; 1005fe97d88SStefano Garzarella } 1015fe97d88SStefano Garzarella 1025fe97d88SStefano Garzarella if (!vhost_user_init(&vsock->vhost_user, &vsock->conf.chardev, errp)) { 1035fe97d88SStefano Garzarella return; 1045fe97d88SStefano Garzarella } 1055fe97d88SStefano Garzarella 1063857cd5cSJonah Palmer vhost_vsock_common_realize(vdev); 1075fe97d88SStefano Garzarella 1085fe97d88SStefano Garzarella vhost_dev_set_config_notifier(&vvc->vhost_dev, &vsock_ops); 1095fe97d88SStefano Garzarella 1105fe97d88SStefano Garzarella ret = vhost_dev_init(&vvc->vhost_dev, &vsock->vhost_user, 111a6945f22SKevin Wolf VHOST_BACKEND_TYPE_USER, 0, errp); 1125fe97d88SStefano Garzarella if (ret < 0) { 1135fe97d88SStefano Garzarella goto err_virtio; 1145fe97d88SStefano Garzarella } 1155fe97d88SStefano Garzarella 1165fe97d88SStefano Garzarella ret = vhost_dev_get_config(&vvc->vhost_dev, (uint8_t *)&vsock->vsockcfg, 11750de5138SKevin Wolf sizeof(struct virtio_vsock_config), errp); 1185fe97d88SStefano Garzarella if (ret < 0) { 1195fe97d88SStefano Garzarella goto err_vhost_dev; 1205fe97d88SStefano Garzarella } 1215fe97d88SStefano Garzarella 1225fe97d88SStefano Garzarella return; 1235fe97d88SStefano Garzarella 1245fe97d88SStefano Garzarella err_vhost_dev: 1255fe97d88SStefano Garzarella vhost_dev_cleanup(&vvc->vhost_dev); 1265fe97d88SStefano Garzarella err_virtio: 1275fe97d88SStefano Garzarella vhost_vsock_common_unrealize(vdev); 1285fe97d88SStefano Garzarella vhost_user_cleanup(&vsock->vhost_user); 1295fe97d88SStefano Garzarella return; 1305fe97d88SStefano Garzarella } 1315fe97d88SStefano Garzarella 1325fe97d88SStefano Garzarella static void vuv_device_unrealize(DeviceState *dev) 1335fe97d88SStefano Garzarella { 1345fe97d88SStefano Garzarella VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev); 1355fe97d88SStefano Garzarella VirtIODevice *vdev = VIRTIO_DEVICE(dev); 1365fe97d88SStefano Garzarella VHostUserVSock *vsock = VHOST_USER_VSOCK(dev); 1375fe97d88SStefano Garzarella 1385fe97d88SStefano Garzarella /* This will stop vhost backend if appropriate. */ 1395fe97d88SStefano Garzarella vuv_set_status(vdev, 0); 1405fe97d88SStefano Garzarella 1415fe97d88SStefano Garzarella vhost_dev_cleanup(&vvc->vhost_dev); 1425fe97d88SStefano Garzarella 1435fe97d88SStefano Garzarella vhost_vsock_common_unrealize(vdev); 1445fe97d88SStefano Garzarella 1455fe97d88SStefano Garzarella vhost_user_cleanup(&vsock->vhost_user); 1465fe97d88SStefano Garzarella 1475fe97d88SStefano Garzarella } 1485fe97d88SStefano Garzarella 1495fe97d88SStefano Garzarella static Property vuv_properties[] = { 1505fe97d88SStefano Garzarella DEFINE_PROP_CHR("chardev", VHostUserVSock, conf.chardev), 1515fe97d88SStefano Garzarella DEFINE_PROP_END_OF_LIST(), 1525fe97d88SStefano Garzarella }; 1535fe97d88SStefano Garzarella 1545fe97d88SStefano Garzarella static void vuv_class_init(ObjectClass *klass, void *data) 1555fe97d88SStefano Garzarella { 1565fe97d88SStefano Garzarella DeviceClass *dc = DEVICE_CLASS(klass); 1575fe97d88SStefano Garzarella VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 1585fe97d88SStefano Garzarella 1595fe97d88SStefano Garzarella device_class_set_props(dc, vuv_properties); 1605fe97d88SStefano Garzarella dc->vmsd = &vuv_vmstate; 1615fe97d88SStefano Garzarella vdc->realize = vuv_device_realize; 1625fe97d88SStefano Garzarella vdc->unrealize = vuv_device_unrealize; 1635fe97d88SStefano Garzarella vdc->get_features = vuv_get_features; 1645fe97d88SStefano Garzarella vdc->get_config = vuv_get_config; 1655fe97d88SStefano Garzarella vdc->set_status = vuv_set_status; 1665fe97d88SStefano Garzarella } 1675fe97d88SStefano Garzarella 1685fe97d88SStefano Garzarella static const TypeInfo vuv_info = { 1695fe97d88SStefano Garzarella .name = TYPE_VHOST_USER_VSOCK, 1705fe97d88SStefano Garzarella .parent = TYPE_VHOST_VSOCK_COMMON, 1715fe97d88SStefano Garzarella .instance_size = sizeof(VHostUserVSock), 1725fe97d88SStefano Garzarella .class_init = vuv_class_init, 1735fe97d88SStefano Garzarella }; 1745fe97d88SStefano Garzarella 1755fe97d88SStefano Garzarella static void vuv_register_types(void) 1765fe97d88SStefano Garzarella { 1775fe97d88SStefano Garzarella type_register_static(&vuv_info); 1785fe97d88SStefano Garzarella } 1795fe97d88SStefano Garzarella 1805fe97d88SStefano Garzarella type_init(vuv_register_types) 181