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); 375fe97d88SStefano Garzarella int ret = vhost_dev_get_config(dev, (uint8_t *)&vsock->vsockcfg, 385fe97d88SStefano Garzarella sizeof(struct virtio_vsock_config)); 395fe97d88SStefano Garzarella if (ret < 0) { 405fe97d88SStefano Garzarella error_report("get config space failed"); 415fe97d88SStefano Garzarella return -1; 425fe97d88SStefano Garzarella } 435fe97d88SStefano Garzarella 445fe97d88SStefano Garzarella virtio_notify_config(dev->vdev); 455fe97d88SStefano Garzarella 465fe97d88SStefano Garzarella return 0; 475fe97d88SStefano Garzarella } 485fe97d88SStefano Garzarella 495fe97d88SStefano Garzarella const VhostDevConfigOps vsock_ops = { 505fe97d88SStefano Garzarella .vhost_dev_config_notifier = vuv_handle_config_change, 515fe97d88SStefano Garzarella }; 525fe97d88SStefano Garzarella 535fe97d88SStefano Garzarella static void vuv_set_status(VirtIODevice *vdev, uint8_t status) 545fe97d88SStefano Garzarella { 555fe97d88SStefano Garzarella VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 565fe97d88SStefano Garzarella bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK; 575fe97d88SStefano Garzarella 585fe97d88SStefano Garzarella if (!vdev->vm_running) { 595fe97d88SStefano Garzarella should_start = false; 605fe97d88SStefano Garzarella } 615fe97d88SStefano Garzarella 625fe97d88SStefano Garzarella if (vvc->vhost_dev.started == should_start) { 635fe97d88SStefano Garzarella return; 645fe97d88SStefano Garzarella } 655fe97d88SStefano Garzarella 665fe97d88SStefano Garzarella if (should_start) { 675fe97d88SStefano Garzarella int ret = vhost_vsock_common_start(vdev); 685fe97d88SStefano Garzarella if (ret < 0) { 695fe97d88SStefano Garzarella return; 705fe97d88SStefano Garzarella } 715fe97d88SStefano Garzarella } else { 725fe97d88SStefano Garzarella vhost_vsock_common_stop(vdev); 735fe97d88SStefano Garzarella } 745fe97d88SStefano Garzarella } 755fe97d88SStefano Garzarella 765fe97d88SStefano Garzarella static uint64_t vuv_get_features(VirtIODevice *vdev, 775fe97d88SStefano Garzarella uint64_t features, 785fe97d88SStefano Garzarella Error **errp) 795fe97d88SStefano Garzarella { 805fe97d88SStefano Garzarella VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); 815fe97d88SStefano Garzarella 825fe97d88SStefano Garzarella return vhost_get_features(&vvc->vhost_dev, user_feature_bits, features); 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 1065fe97d88SStefano Garzarella vhost_vsock_common_realize(vdev, "vhost-user-vsock"); 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, 111*a6945f22SKevin 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, 1175fe97d88SStefano Garzarella sizeof(struct virtio_vsock_config)); 1185fe97d88SStefano Garzarella if (ret < 0) { 1195fe97d88SStefano Garzarella error_setg_errno(errp, -ret, "get config space failed"); 1205fe97d88SStefano Garzarella goto err_vhost_dev; 1215fe97d88SStefano Garzarella } 1225fe97d88SStefano Garzarella 1235fe97d88SStefano Garzarella return; 1245fe97d88SStefano Garzarella 1255fe97d88SStefano Garzarella err_vhost_dev: 1265fe97d88SStefano Garzarella vhost_dev_cleanup(&vvc->vhost_dev); 1275fe97d88SStefano Garzarella err_virtio: 1285fe97d88SStefano Garzarella vhost_vsock_common_unrealize(vdev); 1295fe97d88SStefano Garzarella vhost_user_cleanup(&vsock->vhost_user); 1305fe97d88SStefano Garzarella return; 1315fe97d88SStefano Garzarella } 1325fe97d88SStefano Garzarella 1335fe97d88SStefano Garzarella static void vuv_device_unrealize(DeviceState *dev) 1345fe97d88SStefano Garzarella { 1355fe97d88SStefano Garzarella VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev); 1365fe97d88SStefano Garzarella VirtIODevice *vdev = VIRTIO_DEVICE(dev); 1375fe97d88SStefano Garzarella VHostUserVSock *vsock = VHOST_USER_VSOCK(dev); 1385fe97d88SStefano Garzarella 1395fe97d88SStefano Garzarella /* This will stop vhost backend if appropriate. */ 1405fe97d88SStefano Garzarella vuv_set_status(vdev, 0); 1415fe97d88SStefano Garzarella 1425fe97d88SStefano Garzarella vhost_dev_cleanup(&vvc->vhost_dev); 1435fe97d88SStefano Garzarella 1445fe97d88SStefano Garzarella vhost_vsock_common_unrealize(vdev); 1455fe97d88SStefano Garzarella 1465fe97d88SStefano Garzarella vhost_user_cleanup(&vsock->vhost_user); 1475fe97d88SStefano Garzarella 1485fe97d88SStefano Garzarella } 1495fe97d88SStefano Garzarella 1505fe97d88SStefano Garzarella static Property vuv_properties[] = { 1515fe97d88SStefano Garzarella DEFINE_PROP_CHR("chardev", VHostUserVSock, conf.chardev), 1525fe97d88SStefano Garzarella DEFINE_PROP_END_OF_LIST(), 1535fe97d88SStefano Garzarella }; 1545fe97d88SStefano Garzarella 1555fe97d88SStefano Garzarella static void vuv_class_init(ObjectClass *klass, void *data) 1565fe97d88SStefano Garzarella { 1575fe97d88SStefano Garzarella DeviceClass *dc = DEVICE_CLASS(klass); 1585fe97d88SStefano Garzarella VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 1595fe97d88SStefano Garzarella 1605fe97d88SStefano Garzarella device_class_set_props(dc, vuv_properties); 1615fe97d88SStefano Garzarella dc->vmsd = &vuv_vmstate; 1625fe97d88SStefano Garzarella vdc->realize = vuv_device_realize; 1635fe97d88SStefano Garzarella vdc->unrealize = vuv_device_unrealize; 1645fe97d88SStefano Garzarella vdc->get_features = vuv_get_features; 1655fe97d88SStefano Garzarella vdc->get_config = vuv_get_config; 1665fe97d88SStefano Garzarella vdc->set_status = vuv_set_status; 1675fe97d88SStefano Garzarella } 1685fe97d88SStefano Garzarella 1695fe97d88SStefano Garzarella static const TypeInfo vuv_info = { 1705fe97d88SStefano Garzarella .name = TYPE_VHOST_USER_VSOCK, 1715fe97d88SStefano Garzarella .parent = TYPE_VHOST_VSOCK_COMMON, 1725fe97d88SStefano Garzarella .instance_size = sizeof(VHostUserVSock), 1735fe97d88SStefano Garzarella .class_init = vuv_class_init, 1745fe97d88SStefano Garzarella }; 1755fe97d88SStefano Garzarella 1765fe97d88SStefano Garzarella static void vuv_register_types(void) 1775fe97d88SStefano Garzarella { 1785fe97d88SStefano Garzarella type_register_static(&vuv_info); 1795fe97d88SStefano Garzarella } 1805fe97d88SStefano Garzarella 1815fe97d88SStefano Garzarella type_init(vuv_register_types) 182