qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

vhost-vsock.c (6890B)


      1 /*
      2  * Virtio vsock device
      3  *
      4  * Copyright 2015 Red Hat, Inc.
      5  *
      6  * Authors:
      7  *  Stefan Hajnoczi <stefanha@redhat.com>
      8  *
      9  * This work is licensed under the terms of the GNU GPL, version 2 or
     10  * (at your option) any later version.  See the COPYING file in the
     11  * top-level directory.
     12  */
     13 
     14 #include "qemu/osdep.h"
     15 #include "standard-headers/linux/virtio_vsock.h"
     16 #include "qapi/error.h"
     17 #include "hw/virtio/virtio-access.h"
     18 #include "qemu/error-report.h"
     19 #include "qemu/sockets.h"
     20 #include "hw/qdev-properties.h"
     21 #include "hw/virtio/vhost-vsock.h"
     22 #include "monitor/monitor.h"
     23 
     24 static void vhost_vsock_get_config(VirtIODevice *vdev, uint8_t *config)
     25 {
     26     VHostVSock *vsock = VHOST_VSOCK(vdev);
     27     struct virtio_vsock_config vsockcfg = {};
     28 
     29     virtio_stq_p(vdev, &vsockcfg.guest_cid, vsock->conf.guest_cid);
     30     memcpy(config, &vsockcfg, sizeof(vsockcfg));
     31 }
     32 
     33 static int vhost_vsock_set_guest_cid(VirtIODevice *vdev)
     34 {
     35     VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
     36     VHostVSock *vsock = VHOST_VSOCK(vdev);
     37     const VhostOps *vhost_ops = vvc->vhost_dev.vhost_ops;
     38     int ret;
     39 
     40     if (!vhost_ops->vhost_vsock_set_guest_cid) {
     41         return -ENOSYS;
     42     }
     43 
     44     ret = vhost_ops->vhost_vsock_set_guest_cid(&vvc->vhost_dev,
     45                                                vsock->conf.guest_cid);
     46     if (ret < 0) {
     47         return -errno;
     48     }
     49     return 0;
     50 }
     51 
     52 static int vhost_vsock_set_running(VirtIODevice *vdev, int start)
     53 {
     54     VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
     55     const VhostOps *vhost_ops = vvc->vhost_dev.vhost_ops;
     56     int ret;
     57 
     58     if (!vhost_ops->vhost_vsock_set_running) {
     59         return -ENOSYS;
     60     }
     61 
     62     ret = vhost_ops->vhost_vsock_set_running(&vvc->vhost_dev, start);
     63     if (ret < 0) {
     64         return -errno;
     65     }
     66     return 0;
     67 }
     68 
     69 
     70 static void vhost_vsock_set_status(VirtIODevice *vdev, uint8_t status)
     71 {
     72     VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
     73     bool should_start = virtio_device_should_start(vdev, status);
     74     int ret;
     75 
     76     if (vhost_dev_is_started(&vvc->vhost_dev) == should_start) {
     77         return;
     78     }
     79 
     80     if (should_start) {
     81         ret = vhost_vsock_common_start(vdev);
     82         if (ret < 0) {
     83             return;
     84         }
     85 
     86         ret = vhost_vsock_set_running(vdev, 1);
     87         if (ret < 0) {
     88             vhost_vsock_common_stop(vdev);
     89             error_report("Error starting vhost vsock: %d", -ret);
     90             return;
     91         }
     92     } else {
     93         ret = vhost_vsock_set_running(vdev, 0);
     94         if (ret < 0) {
     95             error_report("vhost vsock set running failed: %d", ret);
     96             return;
     97         }
     98 
     99         vhost_vsock_common_stop(vdev);
    100     }
    101 }
    102 
    103 static uint64_t vhost_vsock_get_features(VirtIODevice *vdev,
    104                                          uint64_t requested_features,
    105                                          Error **errp)
    106 {
    107     return vhost_vsock_common_get_features(vdev, requested_features, errp);
    108 }
    109 
    110 static const VMStateDescription vmstate_virtio_vhost_vsock = {
    111     .name = "virtio-vhost_vsock",
    112     .minimum_version_id = VHOST_VSOCK_SAVEVM_VERSION,
    113     .version_id = VHOST_VSOCK_SAVEVM_VERSION,
    114     .fields = (VMStateField[]) {
    115         VMSTATE_VIRTIO_DEVICE,
    116         VMSTATE_END_OF_LIST()
    117     },
    118     .pre_save = vhost_vsock_common_pre_save,
    119     .post_load = vhost_vsock_common_post_load,
    120 };
    121 
    122 static void vhost_vsock_device_realize(DeviceState *dev, Error **errp)
    123 {
    124     VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev);
    125     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
    126     VHostVSock *vsock = VHOST_VSOCK(dev);
    127     int vhostfd;
    128     int ret;
    129 
    130     /* Refuse to use reserved CID numbers */
    131     if (vsock->conf.guest_cid <= 2) {
    132         error_setg(errp, "guest-cid property must be greater than 2");
    133         return;
    134     }
    135 
    136     if (vsock->conf.guest_cid > UINT32_MAX) {
    137         error_setg(errp, "guest-cid property must be a 32-bit number");
    138         return;
    139     }
    140 
    141     if (vsock->conf.vhostfd) {
    142         vhostfd = monitor_fd_param(monitor_cur(), vsock->conf.vhostfd, errp);
    143         if (vhostfd == -1) {
    144             error_prepend(errp, "vhost-vsock: unable to parse vhostfd: ");
    145             return;
    146         }
    147 
    148         if (!g_unix_set_fd_nonblocking(vhostfd, true, NULL)) {
    149             error_setg_errno(errp, errno,
    150                              "vhost-vsock: unable to set non-blocking mode");
    151             return;
    152         }
    153     } else {
    154         vhostfd = open("/dev/vhost-vsock", O_RDWR);
    155         if (vhostfd < 0) {
    156             error_setg_errno(errp, errno,
    157                              "vhost-vsock: failed to open vhost device");
    158             return;
    159         }
    160 
    161         if (!g_unix_set_fd_nonblocking(vhostfd, true, NULL)) {
    162             error_setg_errno(errp, errno,
    163                              "Failed to set FD nonblocking");
    164             return;
    165         }
    166     }
    167 
    168     vhost_vsock_common_realize(vdev);
    169 
    170     ret = vhost_dev_init(&vvc->vhost_dev, (void *)(uintptr_t)vhostfd,
    171                          VHOST_BACKEND_TYPE_KERNEL, 0, errp);
    172     if (ret < 0) {
    173         /*
    174          * vhostfd is closed by vhost_dev_cleanup, which is called
    175          * by vhost_dev_init on initialization error.
    176          */
    177         goto err_virtio;
    178     }
    179 
    180     ret = vhost_vsock_set_guest_cid(vdev);
    181     if (ret < 0) {
    182         error_setg_errno(errp, -ret, "vhost-vsock: unable to set guest cid");
    183         goto err_vhost_dev;
    184     }
    185 
    186     return;
    187 
    188 err_vhost_dev:
    189     /* vhost_dev_cleanup() closes the vhostfd passed to vhost_dev_init() */
    190     vhost_dev_cleanup(&vvc->vhost_dev);
    191 err_virtio:
    192     vhost_vsock_common_unrealize(vdev);
    193 }
    194 
    195 static void vhost_vsock_device_unrealize(DeviceState *dev)
    196 {
    197     VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev);
    198     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
    199 
    200     /* This will stop vhost backend if appropriate. */
    201     vhost_vsock_set_status(vdev, 0);
    202 
    203     vhost_dev_cleanup(&vvc->vhost_dev);
    204     vhost_vsock_common_unrealize(vdev);
    205 }
    206 
    207 static Property vhost_vsock_properties[] = {
    208     DEFINE_PROP_UINT64("guest-cid", VHostVSock, conf.guest_cid, 0),
    209     DEFINE_PROP_STRING("vhostfd", VHostVSock, conf.vhostfd),
    210     DEFINE_PROP_END_OF_LIST(),
    211 };
    212 
    213 static void vhost_vsock_class_init(ObjectClass *klass, void *data)
    214 {
    215     DeviceClass *dc = DEVICE_CLASS(klass);
    216     VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
    217 
    218     device_class_set_props(dc, vhost_vsock_properties);
    219     dc->vmsd = &vmstate_virtio_vhost_vsock;
    220     vdc->realize = vhost_vsock_device_realize;
    221     vdc->unrealize = vhost_vsock_device_unrealize;
    222     vdc->get_features = vhost_vsock_get_features;
    223     vdc->get_config = vhost_vsock_get_config;
    224     vdc->set_status = vhost_vsock_set_status;
    225 }
    226 
    227 static const TypeInfo vhost_vsock_info = {
    228     .name = TYPE_VHOST_VSOCK,
    229     .parent = TYPE_VHOST_VSOCK_COMMON,
    230     .instance_size = sizeof(VHostVSock),
    231     .class_init = vhost_vsock_class_init,
    232 };
    233 
    234 static void vhost_vsock_register_types(void)
    235 {
    236     type_register_static(&vhost_vsock_info);
    237 }
    238 
    239 type_init(vhost_vsock_register_types)