1 #include "kvm/virtio-vsock.h"
2 #include "kvm/virtio-pci-dev.h"
3 #include "kvm/kvm.h"
4 #include "kvm/pci.h"
5 #include "kvm/ioeventfd.h"
6 #include "kvm/guest_compat.h"
7 #include "kvm/virtio-pci.h"
8 #include "kvm/virtio.h"
9
10 #include <linux/byteorder.h>
11 #include <linux/kernel.h>
12 #include <linux/virtio_vsock.h>
13 #include <linux/vhost.h>
14
15 #define VIRTIO_VSOCK_QUEUE_SIZE 128
16
17 static LIST_HEAD(vdevs);
18 static int compat_id = -1;
19
20 enum {
21 VSOCK_VQ_RX = 0, /* for host to guest data */
22 VSOCK_VQ_TX = 1, /* for guest to host data */
23 VSOCK_VQ_EVENT = 2,
24 VSOCK_VQ_MAX = 3,
25 };
26
27 struct vsock_dev {
28 struct virt_queue vqs[VSOCK_VQ_MAX];
29 struct virtio_vsock_config config;
30 u64 guest_cid;
31 u32 features;
32 int vhost_fd;
33 struct virtio_device vdev;
34 struct list_head list;
35 struct kvm *kvm;
36 };
37
get_config(struct kvm * kvm,void * dev)38 static u8 *get_config(struct kvm *kvm, void *dev)
39 {
40 struct vsock_dev *vdev = dev;
41
42 return ((u8 *)(&vdev->config));
43 }
44
get_config_size(struct kvm * kvm,void * dev)45 static size_t get_config_size(struct kvm *kvm, void *dev)
46 {
47 struct vsock_dev *vdev = dev;
48
49 return sizeof(vdev->config);
50 }
51
get_host_features(struct kvm * kvm,void * dev)52 static u64 get_host_features(struct kvm *kvm, void *dev)
53 {
54 int r;
55 u64 features;
56 struct vsock_dev *vdev = dev;
57
58 r = ioctl(vdev->vhost_fd, VHOST_GET_FEATURES, &features);
59 if (r != 0)
60 die_perror("VHOST_GET_FEATURES failed");
61
62 return features &
63 (1ULL << VIRTIO_RING_F_EVENT_IDX |
64 1ULL << VIRTIO_RING_F_INDIRECT_DESC);
65 }
66
is_event_vq(u32 vq)67 static bool is_event_vq(u32 vq)
68 {
69 return vq == VSOCK_VQ_EVENT;
70 }
71
init_vq(struct kvm * kvm,void * dev,u32 vq)72 static int init_vq(struct kvm *kvm, void *dev, u32 vq)
73 {
74 struct vsock_dev *vdev = dev;
75 struct virt_queue *queue;
76
77 compat__remove_message(compat_id);
78
79 queue = &vdev->vqs[vq];
80 virtio_init_device_vq(kvm, &vdev->vdev, queue, VIRTIO_VSOCK_QUEUE_SIZE);
81
82 if (vdev->vhost_fd == -1 || is_event_vq(vq))
83 return 0;
84
85 virtio_vhost_set_vring(kvm, vdev->vhost_fd, vq, queue);
86 return 0;
87 }
88
notify_vq_eventfd(struct kvm * kvm,void * dev,u32 vq,u32 efd)89 static void notify_vq_eventfd(struct kvm *kvm, void *dev, u32 vq, u32 efd)
90 {
91 struct vsock_dev *vdev = dev;
92
93 if (vdev->vhost_fd == -1 || is_event_vq(vq))
94 return;
95
96 virtio_vhost_set_vring_kick(kvm, vdev->vhost_fd, vq, efd);
97 }
98
notify_status(struct kvm * kvm,void * dev,u32 status)99 static void notify_status(struct kvm *kvm, void *dev, u32 status)
100 {
101 struct vsock_dev *vdev = dev;
102 int r, start;
103
104 if (status & VIRTIO__STATUS_CONFIG)
105 vdev->config.guest_cid = cpu_to_le64(vdev->guest_cid);
106
107 if (status & VIRTIO__STATUS_START) {
108 start = 1;
109
110 r = virtio_vhost_set_features(vdev->vhost_fd,
111 vdev->vdev.features);
112 if (r != 0)
113 die_perror("VHOST_SET_FEATURES failed");
114 } else if (status & VIRTIO__STATUS_STOP) {
115 start = 0;
116 } else {
117 return;
118 }
119
120 r = ioctl(vdev->vhost_fd, VHOST_VSOCK_SET_RUNNING, &start);
121 if (r != 0)
122 die("VHOST_VSOCK_SET_RUNNING failed %d", errno);
123 }
124
notify_vq(struct kvm * kvm,void * dev,u32 vq)125 static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
126 {
127 return 0;
128 }
129
get_vq(struct kvm * kvm,void * dev,u32 vq)130 static struct virt_queue *get_vq(struct kvm *kvm, void *dev, u32 vq)
131 {
132 struct vsock_dev *vdev = dev;
133
134 return &vdev->vqs[vq];
135 }
136
get_size_vq(struct kvm * kvm,void * dev,u32 vq)137 static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
138 {
139 return VIRTIO_VSOCK_QUEUE_SIZE;
140 }
141
set_size_vq(struct kvm * kvm,void * dev,u32 vq,int size)142 static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size)
143 {
144 return size;
145 }
146
notify_vq_gsi(struct kvm * kvm,void * dev,u32 vq,u32 gsi)147 static void notify_vq_gsi(struct kvm *kvm, void *dev, u32 vq, u32 gsi)
148 {
149 struct vsock_dev *vdev = dev;
150
151 if (vdev->vhost_fd == -1 || is_event_vq(vq))
152 return;
153
154 virtio_vhost_set_vring_irqfd(kvm, gsi, &vdev->vqs[vq]);
155 }
156
get_vq_count(struct kvm * kvm,void * dev)157 static unsigned int get_vq_count(struct kvm *kvm, void *dev)
158 {
159 return VSOCK_VQ_MAX;
160 }
161
162 static struct virtio_ops vsock_dev_virtio_ops = {
163 .get_config = get_config,
164 .get_config_size = get_config_size,
165 .get_host_features = get_host_features,
166 .init_vq = init_vq,
167 .get_vq = get_vq,
168 .get_size_vq = get_size_vq,
169 .set_size_vq = set_size_vq,
170 .notify_vq_eventfd = notify_vq_eventfd,
171 .notify_status = notify_status,
172 .notify_vq_gsi = notify_vq_gsi,
173 .notify_vq = notify_vq,
174 .get_vq_count = get_vq_count,
175 };
176
virtio_vhost_vsock_init(struct kvm * kvm,struct vsock_dev * vdev)177 static void virtio_vhost_vsock_init(struct kvm *kvm, struct vsock_dev *vdev)
178 {
179 int r;
180
181 vdev->vhost_fd = open("/dev/vhost-vsock", O_RDWR);
182 if (vdev->vhost_fd < 0)
183 die_perror("Failed opening vhost-vsock device");
184
185 virtio_vhost_init(kvm, vdev->vhost_fd);
186
187 r = ioctl(vdev->vhost_fd, VHOST_VSOCK_SET_GUEST_CID, &vdev->guest_cid);
188 if (r != 0)
189 die_perror("VHOST_VSOCK_SET_GUEST_CID failed");
190
191 vdev->vdev.use_vhost = true;
192 }
193
virtio_vsock_init_one(struct kvm * kvm,u64 guest_cid)194 static int virtio_vsock_init_one(struct kvm *kvm, u64 guest_cid)
195 {
196 struct vsock_dev *vdev;
197 int r;
198
199 vdev = calloc(1, sizeof(struct vsock_dev));
200 if (vdev == NULL)
201 return -ENOMEM;
202
203 *vdev = (struct vsock_dev) {
204 .guest_cid = guest_cid,
205 .vhost_fd = -1,
206 .kvm = kvm,
207 };
208
209 list_add_tail(&vdev->list, &vdevs);
210
211 r = virtio_init(kvm, vdev, &vdev->vdev, &vsock_dev_virtio_ops,
212 kvm->cfg.virtio_transport, PCI_DEVICE_ID_VIRTIO_VSOCK,
213 VIRTIO_ID_VSOCK, PCI_CLASS_VSOCK);
214 if (r < 0)
215 return r;
216
217 virtio_vhost_vsock_init(kvm, vdev);
218
219 if (compat_id == -1)
220 compat_id = virtio_compat_add_message("virtio-vsock", "CONFIG_VIRTIO_VSOCKETS");
221
222 return 0;
223 }
224
virtio_vsock_exit_one(struct kvm * kvm,struct vsock_dev * vdev)225 static int virtio_vsock_exit_one(struct kvm *kvm, struct vsock_dev *vdev)
226 {
227 list_del(&vdev->list);
228 free(vdev);
229
230 return 0;
231 }
232
virtio_vsock_init(struct kvm * kvm)233 int virtio_vsock_init(struct kvm *kvm)
234 {
235 int r;
236
237 if (kvm->cfg.vsock_cid == 0)
238 return 0;
239
240 r = virtio_vsock_init_one(kvm, kvm->cfg.vsock_cid);
241 if (r < 0)
242 goto cleanup;
243
244 return 0;
245 cleanup:
246 return virtio_vsock_exit(kvm);
247 }
248 virtio_dev_init(virtio_vsock_init);
249
virtio_vsock_exit(struct kvm * kvm)250 int virtio_vsock_exit(struct kvm *kvm)
251 {
252 while (!list_empty(&vdevs)) {
253 struct vsock_dev *vdev;
254
255 vdev = list_first_entry(&vdevs, struct vsock_dev, list);
256 virtio_vsock_exit_one(kvm, vdev);
257 }
258
259 return 0;
260 }
261 virtio_dev_exit(virtio_vsock_exit);
262