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); 585fe97d88SStefano Garzarella bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK; 595fe97d88SStefano Garzarella 605fe97d88SStefano Garzarella if (!vdev->vm_running) { 615fe97d88SStefano Garzarella should_start = false; 625fe97d88SStefano Garzarella } 635fe97d88SStefano Garzarella 645fe97d88SStefano Garzarella if (vvc->vhost_dev.started == should_start) { 655fe97d88SStefano Garzarella return; 665fe97d88SStefano Garzarella } 675fe97d88SStefano Garzarella 685fe97d88SStefano Garzarella if (should_start) { 695fe97d88SStefano Garzarella int ret = vhost_vsock_common_start(vdev); 705fe97d88SStefano Garzarella if (ret < 0) { 715fe97d88SStefano Garzarella return; 725fe97d88SStefano Garzarella } 735fe97d88SStefano Garzarella } else { 745fe97d88SStefano Garzarella vhost_vsock_common_stop(vdev); 755fe97d88SStefano Garzarella } 765fe97d88SStefano Garzarella } 775fe97d88SStefano Garzarella 785fe97d88SStefano Garzarella static uint64_t vuv_get_features(VirtIODevice *vdev, 795fe97d88SStefano Garzarella uint64_t features, 805fe97d88SStefano Garzarella Error **errp) 815fe97d88SStefano Garzarella { 825fe97d88SStefano Garzarella VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 835fe97d88SStefano Garzarella 84*46ce0171SStefano Garzarella features = vhost_get_features(&vvc->vhost_dev, user_feature_bits, features); 85*46ce0171SStefano Garzarella 86*46ce0171SStefano Garzarella return vhost_vsock_common_get_features(vdev, features, errp); 875fe97d88SStefano Garzarella } 885fe97d88SStefano Garzarella 895fe97d88SStefano Garzarella static const VMStateDescription vuv_vmstate = { 905fe97d88SStefano Garzarella .name = "vhost-user-vsock", 915fe97d88SStefano Garzarella .unmigratable = 1, 925fe97d88SStefano Garzarella }; 935fe97d88SStefano Garzarella 945fe97d88SStefano Garzarella static void vuv_device_realize(DeviceState *dev, Error **errp) 955fe97d88SStefano Garzarella { 965fe97d88SStefano Garzarella VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev); 975fe97d88SStefano Garzarella VirtIODevice *vdev = VIRTIO_DEVICE(dev); 985fe97d88SStefano Garzarella VHostUserVSock *vsock = VHOST_USER_VSOCK(dev); 995fe97d88SStefano Garzarella int ret; 1005fe97d88SStefano Garzarella 1015fe97d88SStefano Garzarella if (!vsock->conf.chardev.chr) { 1025fe97d88SStefano Garzarella error_setg(errp, "missing chardev"); 1035fe97d88SStefano Garzarella return; 1045fe97d88SStefano Garzarella } 1055fe97d88SStefano Garzarella 1065fe97d88SStefano Garzarella if (!vhost_user_init(&vsock->vhost_user, &vsock->conf.chardev, errp)) { 1075fe97d88SStefano Garzarella return; 1085fe97d88SStefano Garzarella } 1095fe97d88SStefano Garzarella 1105fe97d88SStefano Garzarella vhost_vsock_common_realize(vdev, "vhost-user-vsock"); 1115fe97d88SStefano Garzarella 1125fe97d88SStefano Garzarella vhost_dev_set_config_notifier(&vvc->vhost_dev, &vsock_ops); 1135fe97d88SStefano Garzarella 1145fe97d88SStefano Garzarella ret = vhost_dev_init(&vvc->vhost_dev, &vsock->vhost_user, 115a6945f22SKevin Wolf VHOST_BACKEND_TYPE_USER, 0, errp); 1165fe97d88SStefano Garzarella if (ret < 0) { 1175fe97d88SStefano Garzarella goto err_virtio; 1185fe97d88SStefano Garzarella } 1195fe97d88SStefano Garzarella 1205fe97d88SStefano Garzarella ret = vhost_dev_get_config(&vvc->vhost_dev, (uint8_t *)&vsock->vsockcfg, 12150de5138SKevin Wolf sizeof(struct virtio_vsock_config), errp); 1225fe97d88SStefano Garzarella if (ret < 0) { 1235fe97d88SStefano Garzarella goto err_vhost_dev; 1245fe97d88SStefano Garzarella } 1255fe97d88SStefano Garzarella 1265fe97d88SStefano Garzarella return; 1275fe97d88SStefano Garzarella 1285fe97d88SStefano Garzarella err_vhost_dev: 1295fe97d88SStefano Garzarella vhost_dev_cleanup(&vvc->vhost_dev); 1305fe97d88SStefano Garzarella err_virtio: 1315fe97d88SStefano Garzarella vhost_vsock_common_unrealize(vdev); 1325fe97d88SStefano Garzarella vhost_user_cleanup(&vsock->vhost_user); 1335fe97d88SStefano Garzarella return; 1345fe97d88SStefano Garzarella } 1355fe97d88SStefano Garzarella 1365fe97d88SStefano Garzarella static void vuv_device_unrealize(DeviceState *dev) 1375fe97d88SStefano Garzarella { 1385fe97d88SStefano Garzarella VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev); 1395fe97d88SStefano Garzarella VirtIODevice *vdev = VIRTIO_DEVICE(dev); 1405fe97d88SStefano Garzarella VHostUserVSock *vsock = VHOST_USER_VSOCK(dev); 1415fe97d88SStefano Garzarella 1425fe97d88SStefano Garzarella /* This will stop vhost backend if appropriate. */ 1435fe97d88SStefano Garzarella vuv_set_status(vdev, 0); 1445fe97d88SStefano Garzarella 1455fe97d88SStefano Garzarella vhost_dev_cleanup(&vvc->vhost_dev); 1465fe97d88SStefano Garzarella 1475fe97d88SStefano Garzarella vhost_vsock_common_unrealize(vdev); 1485fe97d88SStefano Garzarella 1495fe97d88SStefano Garzarella vhost_user_cleanup(&vsock->vhost_user); 1505fe97d88SStefano Garzarella 1515fe97d88SStefano Garzarella } 1525fe97d88SStefano Garzarella 1535fe97d88SStefano Garzarella static Property vuv_properties[] = { 1545fe97d88SStefano Garzarella DEFINE_PROP_CHR("chardev", VHostUserVSock, conf.chardev), 1555fe97d88SStefano Garzarella DEFINE_PROP_END_OF_LIST(), 1565fe97d88SStefano Garzarella }; 1575fe97d88SStefano Garzarella 1585fe97d88SStefano Garzarella static void vuv_class_init(ObjectClass *klass, void *data) 1595fe97d88SStefano Garzarella { 1605fe97d88SStefano Garzarella DeviceClass *dc = DEVICE_CLASS(klass); 1615fe97d88SStefano Garzarella VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 1625fe97d88SStefano Garzarella 1635fe97d88SStefano Garzarella device_class_set_props(dc, vuv_properties); 1645fe97d88SStefano Garzarella dc->vmsd = &vuv_vmstate; 1655fe97d88SStefano Garzarella vdc->realize = vuv_device_realize; 1665fe97d88SStefano Garzarella vdc->unrealize = vuv_device_unrealize; 1675fe97d88SStefano Garzarella vdc->get_features = vuv_get_features; 1685fe97d88SStefano Garzarella vdc->get_config = vuv_get_config; 1695fe97d88SStefano Garzarella vdc->set_status = vuv_set_status; 1705fe97d88SStefano Garzarella } 1715fe97d88SStefano Garzarella 1725fe97d88SStefano Garzarella static const TypeInfo vuv_info = { 1735fe97d88SStefano Garzarella .name = TYPE_VHOST_USER_VSOCK, 1745fe97d88SStefano Garzarella .parent = TYPE_VHOST_VSOCK_COMMON, 1755fe97d88SStefano Garzarella .instance_size = sizeof(VHostUserVSock), 1765fe97d88SStefano Garzarella .class_init = vuv_class_init, 1775fe97d88SStefano Garzarella }; 1785fe97d88SStefano Garzarella 1795fe97d88SStefano Garzarella static void vuv_register_types(void) 1805fe97d88SStefano Garzarella { 1815fe97d88SStefano Garzarella type_register_static(&vuv_info); 1825fe97d88SStefano Garzarella } 1835fe97d88SStefano Garzarella 1845fe97d88SStefano Garzarella type_init(vuv_register_types) 185