vhost-user-vsock.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /*
  2. * Vhost-user vsock virtio device
  3. *
  4. * Copyright 2020 Red Hat, Inc.
  5. *
  6. * This work is licensed under the terms of the GNU GPL, version 2 or
  7. * (at your option) any later version. See the COPYING file in the
  8. * top-level directory.
  9. */
  10. #include "qemu/osdep.h"
  11. #include "qapi/error.h"
  12. #include "qemu/error-report.h"
  13. #include "hw/qdev-properties.h"
  14. #include "hw/virtio/vhost-user-vsock.h"
  15. static const int user_feature_bits[] = {
  16. VIRTIO_F_VERSION_1,
  17. VIRTIO_RING_F_INDIRECT_DESC,
  18. VIRTIO_RING_F_EVENT_IDX,
  19. VIRTIO_F_NOTIFY_ON_EMPTY,
  20. VHOST_INVALID_FEATURE_BIT
  21. };
  22. static void vuv_get_config(VirtIODevice *vdev, uint8_t *config)
  23. {
  24. VHostUserVSock *vsock = VHOST_USER_VSOCK(vdev);
  25. memcpy(config, &vsock->vsockcfg, sizeof(struct virtio_vsock_config));
  26. }
  27. static int vuv_handle_config_change(struct vhost_dev *dev)
  28. {
  29. VHostUserVSock *vsock = VHOST_USER_VSOCK(dev->vdev);
  30. int ret = vhost_dev_get_config(dev, (uint8_t *)&vsock->vsockcfg,
  31. sizeof(struct virtio_vsock_config));
  32. if (ret < 0) {
  33. error_report("get config space failed");
  34. return -1;
  35. }
  36. virtio_notify_config(dev->vdev);
  37. return 0;
  38. }
  39. const VhostDevConfigOps vsock_ops = {
  40. .vhost_dev_config_notifier = vuv_handle_config_change,
  41. };
  42. static void vuv_set_status(VirtIODevice *vdev, uint8_t status)
  43. {
  44. VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
  45. bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK;
  46. if (!vdev->vm_running) {
  47. should_start = false;
  48. }
  49. if (vvc->vhost_dev.started == should_start) {
  50. return;
  51. }
  52. if (should_start) {
  53. int ret = vhost_vsock_common_start(vdev);
  54. if (ret < 0) {
  55. return;
  56. }
  57. } else {
  58. vhost_vsock_common_stop(vdev);
  59. }
  60. }
  61. static uint64_t vuv_get_features(VirtIODevice *vdev,
  62. uint64_t features,
  63. Error **errp)
  64. {
  65. VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
  66. return vhost_get_features(&vvc->vhost_dev, user_feature_bits, features);
  67. }
  68. static const VMStateDescription vuv_vmstate = {
  69. .name = "vhost-user-vsock",
  70. .unmigratable = 1,
  71. };
  72. static void vuv_device_realize(DeviceState *dev, Error **errp)
  73. {
  74. VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev);
  75. VirtIODevice *vdev = VIRTIO_DEVICE(dev);
  76. VHostUserVSock *vsock = VHOST_USER_VSOCK(dev);
  77. int ret;
  78. if (!vsock->conf.chardev.chr) {
  79. error_setg(errp, "missing chardev");
  80. return;
  81. }
  82. if (!vhost_user_init(&vsock->vhost_user, &vsock->conf.chardev, errp)) {
  83. return;
  84. }
  85. vhost_vsock_common_realize(vdev, "vhost-user-vsock");
  86. vhost_dev_set_config_notifier(&vvc->vhost_dev, &vsock_ops);
  87. ret = vhost_dev_init(&vvc->vhost_dev, &vsock->vhost_user,
  88. VHOST_BACKEND_TYPE_USER, 0);
  89. if (ret < 0) {
  90. error_setg_errno(errp, -ret, "vhost_dev_init failed");
  91. goto err_virtio;
  92. }
  93. ret = vhost_dev_get_config(&vvc->vhost_dev, (uint8_t *)&vsock->vsockcfg,
  94. sizeof(struct virtio_vsock_config));
  95. if (ret < 0) {
  96. error_setg_errno(errp, -ret, "get config space failed");
  97. goto err_vhost_dev;
  98. }
  99. return;
  100. err_vhost_dev:
  101. vhost_dev_cleanup(&vvc->vhost_dev);
  102. err_virtio:
  103. vhost_vsock_common_unrealize(vdev);
  104. vhost_user_cleanup(&vsock->vhost_user);
  105. return;
  106. }
  107. static void vuv_device_unrealize(DeviceState *dev)
  108. {
  109. VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev);
  110. VirtIODevice *vdev = VIRTIO_DEVICE(dev);
  111. VHostUserVSock *vsock = VHOST_USER_VSOCK(dev);
  112. /* This will stop vhost backend if appropriate. */
  113. vuv_set_status(vdev, 0);
  114. vhost_dev_cleanup(&vvc->vhost_dev);
  115. vhost_vsock_common_unrealize(vdev);
  116. vhost_user_cleanup(&vsock->vhost_user);
  117. }
  118. static Property vuv_properties[] = {
  119. DEFINE_PROP_CHR("chardev", VHostUserVSock, conf.chardev),
  120. DEFINE_PROP_END_OF_LIST(),
  121. };
  122. static void vuv_class_init(ObjectClass *klass, void *data)
  123. {
  124. DeviceClass *dc = DEVICE_CLASS(klass);
  125. VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
  126. device_class_set_props(dc, vuv_properties);
  127. dc->vmsd = &vuv_vmstate;
  128. vdc->realize = vuv_device_realize;
  129. vdc->unrealize = vuv_device_unrealize;
  130. vdc->get_features = vuv_get_features;
  131. vdc->get_config = vuv_get_config;
  132. vdc->set_status = vuv_set_status;
  133. }
  134. static const TypeInfo vuv_info = {
  135. .name = TYPE_VHOST_USER_VSOCK,
  136. .parent = TYPE_VHOST_VSOCK_COMMON,
  137. .instance_size = sizeof(VHostUserVSock),
  138. .class_init = vuv_class_init,
  139. };
  140. static void vuv_register_types(void)
  141. {
  142. type_register_static(&vuv_info);
  143. }
  144. type_init(vuv_register_types)