]> git.proxmox.com Git - mirror_qemu.git/blame - hw/virtio/vhost-user.c
vhost: remove assertion to prevent crash
[mirror_qemu.git] / hw / virtio / vhost-user.c
CommitLineData
5f6f6664
NN
1/*
2 * vhost-user
3 *
4 * Copyright (c) 2013 Virtual Open Systems Sarl.
5 *
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
8 *
9 */
10
9b8bfe21 11#include "qemu/osdep.h"
da34e65c 12#include "qapi/error.h"
5f6f6664
NN
13#include "hw/virtio/vhost.h"
14#include "hw/virtio/vhost-backend.h"
3e866365 15#include "hw/virtio/virtio-net.h"
4d43a603 16#include "chardev/char-fe.h"
5f6f6664
NN
17#include "sysemu/kvm.h"
18#include "qemu/error-report.h"
19#include "qemu/sockets.h"
20
5f6f6664
NN
21#include <sys/ioctl.h>
22#include <sys/socket.h>
23#include <sys/un.h>
24#include <linux/vhost.h>
25
26#define VHOST_MEMORY_MAX_NREGIONS 8
dcb10c00 27#define VHOST_USER_F_PROTOCOL_FEATURES 30
e2051e9e 28
de1372d4
TC
29enum VhostUserProtocolFeature {
30 VHOST_USER_PROTOCOL_F_MQ = 0,
31 VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1,
32 VHOST_USER_PROTOCOL_F_RARP = 2,
ca525ce5 33 VHOST_USER_PROTOCOL_F_REPLY_ACK = 3,
c5f048d8 34 VHOST_USER_PROTOCOL_F_NET_MTU = 4,
4bbeeba0 35 VHOST_USER_PROTOCOL_F_SLAVE_REQ = 5,
5df04f17 36 VHOST_USER_PROTOCOL_F_CROSS_ENDIAN = 6,
de1372d4
TC
37
38 VHOST_USER_PROTOCOL_F_MAX
39};
40
41#define VHOST_USER_PROTOCOL_FEATURE_MASK ((1 << VHOST_USER_PROTOCOL_F_MAX) - 1)
5f6f6664
NN
42
43typedef enum VhostUserRequest {
44 VHOST_USER_NONE = 0,
45 VHOST_USER_GET_FEATURES = 1,
46 VHOST_USER_SET_FEATURES = 2,
47 VHOST_USER_SET_OWNER = 3,
60915dc4 48 VHOST_USER_RESET_OWNER = 4,
5f6f6664
NN
49 VHOST_USER_SET_MEM_TABLE = 5,
50 VHOST_USER_SET_LOG_BASE = 6,
51 VHOST_USER_SET_LOG_FD = 7,
52 VHOST_USER_SET_VRING_NUM = 8,
53 VHOST_USER_SET_VRING_ADDR = 9,
54 VHOST_USER_SET_VRING_BASE = 10,
55 VHOST_USER_GET_VRING_BASE = 11,
56 VHOST_USER_SET_VRING_KICK = 12,
57 VHOST_USER_SET_VRING_CALL = 13,
58 VHOST_USER_SET_VRING_ERR = 14,
dcb10c00
MT
59 VHOST_USER_GET_PROTOCOL_FEATURES = 15,
60 VHOST_USER_SET_PROTOCOL_FEATURES = 16,
e2051e9e 61 VHOST_USER_GET_QUEUE_NUM = 17,
7263a0ad 62 VHOST_USER_SET_VRING_ENABLE = 18,
3e866365 63 VHOST_USER_SEND_RARP = 19,
c5f048d8 64 VHOST_USER_NET_SET_MTU = 20,
4bbeeba0 65 VHOST_USER_SET_SLAVE_REQ_FD = 21,
6dcdd06e 66 VHOST_USER_IOTLB_MSG = 22,
5df04f17 67 VHOST_USER_SET_VRING_ENDIAN = 23,
5f6f6664
NN
68 VHOST_USER_MAX
69} VhostUserRequest;
70
4bbeeba0
MAL
71typedef enum VhostUserSlaveRequest {
72 VHOST_USER_SLAVE_NONE = 0,
6dcdd06e 73 VHOST_USER_SLAVE_IOTLB_MSG = 1,
4bbeeba0
MAL
74 VHOST_USER_SLAVE_MAX
75} VhostUserSlaveRequest;
76
5f6f6664
NN
77typedef struct VhostUserMemoryRegion {
78 uint64_t guest_phys_addr;
79 uint64_t memory_size;
80 uint64_t userspace_addr;
3fd74b84 81 uint64_t mmap_offset;
5f6f6664
NN
82} VhostUserMemoryRegion;
83
84typedef struct VhostUserMemory {
85 uint32_t nregions;
86 uint32_t padding;
87 VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
88} VhostUserMemory;
89
2b8819c6
VK
90typedef struct VhostUserLog {
91 uint64_t mmap_size;
92 uint64_t mmap_offset;
93} VhostUserLog;
94
5f6f6664
NN
95typedef struct VhostUserMsg {
96 VhostUserRequest request;
97
98#define VHOST_USER_VERSION_MASK (0x3)
99#define VHOST_USER_REPLY_MASK (0x1<<2)
ca525ce5 100#define VHOST_USER_NEED_REPLY_MASK (0x1 << 3)
5f6f6664
NN
101 uint32_t flags;
102 uint32_t size; /* the following payload size */
103 union {
104#define VHOST_USER_VRING_IDX_MASK (0xff)
105#define VHOST_USER_VRING_NOFD_MASK (0x1<<8)
106 uint64_t u64;
107 struct vhost_vring_state state;
108 struct vhost_vring_addr addr;
109 VhostUserMemory memory;
2b8819c6 110 VhostUserLog log;
6dcdd06e 111 struct vhost_iotlb_msg iotlb;
7f4a930e 112 } payload;
5f6f6664
NN
113} QEMU_PACKED VhostUserMsg;
114
115static VhostUserMsg m __attribute__ ((unused));
116#define VHOST_USER_HDR_SIZE (sizeof(m.request) \
117 + sizeof(m.flags) \
118 + sizeof(m.size))
119
120#define VHOST_USER_PAYLOAD_SIZE (sizeof(m) - VHOST_USER_HDR_SIZE)
121
122/* The version of the protocol we support */
123#define VHOST_USER_VERSION (0x1)
124
2152f3fe
MAL
125struct vhost_user {
126 CharBackend *chr;
4bbeeba0 127 int slave_fd;
2152f3fe
MAL
128};
129
5f6f6664
NN
130static bool ioeventfd_enabled(void)
131{
132 return kvm_enabled() && kvm_eventfds_enabled();
133}
134
5f6f6664
NN
135static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
136{
2152f3fe
MAL
137 struct vhost_user *u = dev->opaque;
138 CharBackend *chr = u->chr;
5f6f6664
NN
139 uint8_t *p = (uint8_t *) msg;
140 int r, size = VHOST_USER_HDR_SIZE;
141
142 r = qemu_chr_fe_read_all(chr, p, size);
143 if (r != size) {
5421f318
MT
144 error_report("Failed to read msg header. Read %d instead of %d."
145 " Original request %d.", r, size, msg->request);
5f6f6664
NN
146 goto fail;
147 }
148
149 /* validate received flags */
150 if (msg->flags != (VHOST_USER_REPLY_MASK | VHOST_USER_VERSION)) {
151 error_report("Failed to read msg header."
ab7c5aaf 152 " Flags 0x%x instead of 0x%x.", msg->flags,
5f6f6664
NN
153 VHOST_USER_REPLY_MASK | VHOST_USER_VERSION);
154 goto fail;
155 }
156
157 /* validate message size is sane */
158 if (msg->size > VHOST_USER_PAYLOAD_SIZE) {
159 error_report("Failed to read msg header."
ab7c5aaf 160 " Size %d exceeds the maximum %zu.", msg->size,
5f6f6664
NN
161 VHOST_USER_PAYLOAD_SIZE);
162 goto fail;
163 }
164
165 if (msg->size) {
166 p += VHOST_USER_HDR_SIZE;
167 size = msg->size;
168 r = qemu_chr_fe_read_all(chr, p, size);
169 if (r != size) {
170 error_report("Failed to read msg payload."
ab7c5aaf 171 " Read %d instead of %d.", r, msg->size);
5f6f6664
NN
172 goto fail;
173 }
174 }
175
176 return 0;
177
178fail:
179 return -1;
180}
181
ca525ce5 182static int process_message_reply(struct vhost_dev *dev,
3cf7daf8 183 const VhostUserMsg *msg)
ca525ce5 184{
60cd1102 185 VhostUserMsg msg_reply;
ca525ce5 186
3cf7daf8 187 if ((msg->flags & VHOST_USER_NEED_REPLY_MASK) == 0) {
60cd1102
ZY
188 return 0;
189 }
190
191 if (vhost_user_read(dev, &msg_reply) < 0) {
ca525ce5
PS
192 return -1;
193 }
194
3cf7daf8 195 if (msg_reply.request != msg->request) {
ca525ce5
PS
196 error_report("Received unexpected msg type."
197 "Expected %d received %d",
3cf7daf8 198 msg->request, msg_reply.request);
ca525ce5
PS
199 return -1;
200 }
201
60cd1102 202 return msg_reply.payload.u64 ? -1 : 0;
ca525ce5
PS
203}
204
21e70425
MAL
205static bool vhost_user_one_time_request(VhostUserRequest request)
206{
207 switch (request) {
208 case VHOST_USER_SET_OWNER:
60915dc4 209 case VHOST_USER_RESET_OWNER:
21e70425
MAL
210 case VHOST_USER_SET_MEM_TABLE:
211 case VHOST_USER_GET_QUEUE_NUM:
c5f048d8 212 case VHOST_USER_NET_SET_MTU:
21e70425
MAL
213 return true;
214 default:
215 return false;
216 }
217}
218
219/* most non-init callers ignore the error */
5f6f6664
NN
220static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg,
221 int *fds, int fd_num)
222{
2152f3fe
MAL
223 struct vhost_user *u = dev->opaque;
224 CharBackend *chr = u->chr;
f6b85710 225 int ret, size = VHOST_USER_HDR_SIZE + msg->size;
5f6f6664 226
21e70425
MAL
227 /*
228 * For non-vring specific requests, like VHOST_USER_SET_MEM_TABLE,
229 * we just need send it once in the first time. For later such
230 * request, we just ignore it.
231 */
232 if (vhost_user_one_time_request(msg->request) && dev->vq_index != 0) {
60cd1102 233 msg->flags &= ~VHOST_USER_NEED_REPLY_MASK;
21e70425
MAL
234 return 0;
235 }
236
6fab2f3f 237 if (qemu_chr_fe_set_msgfds(chr, fds, fd_num) < 0) {
f6b85710 238 error_report("Failed to set msg fds.");
6fab2f3f
MAL
239 return -1;
240 }
5f6f6664 241
f6b85710
MAL
242 ret = qemu_chr_fe_write_all(chr, (const uint8_t *) msg, size);
243 if (ret != size) {
244 error_report("Failed to write msg."
245 " Wrote %d instead of %d.", ret, size);
246 return -1;
247 }
248
249 return 0;
5f6f6664
NN
250}
251
21e70425
MAL
252static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base,
253 struct vhost_log *log)
b931bfbf 254{
21e70425
MAL
255 int fds[VHOST_MEMORY_MAX_NREGIONS];
256 size_t fd_num = 0;
257 bool shmfd = virtio_has_feature(dev->protocol_features,
258 VHOST_USER_PROTOCOL_F_LOG_SHMFD);
259 VhostUserMsg msg = {
260 .request = VHOST_USER_SET_LOG_BASE,
261 .flags = VHOST_USER_VERSION,
48854f57 262 .payload.log.mmap_size = log->size * sizeof(*(log->log)),
2b8819c6
VK
263 .payload.log.mmap_offset = 0,
264 .size = sizeof(msg.payload.log),
21e70425
MAL
265 };
266
267 if (shmfd && log->fd != -1) {
268 fds[fd_num++] = log->fd;
269 }
270
c4843a45
MAL
271 if (vhost_user_write(dev, &msg, fds, fd_num) < 0) {
272 return -1;
273 }
21e70425
MAL
274
275 if (shmfd) {
276 msg.size = 0;
277 if (vhost_user_read(dev, &msg) < 0) {
c4843a45 278 return -1;
21e70425
MAL
279 }
280
281 if (msg.request != VHOST_USER_SET_LOG_BASE) {
282 error_report("Received unexpected msg type. "
283 "Expected %d received %d",
284 VHOST_USER_SET_LOG_BASE, msg.request);
285 return -1;
286 }
b931bfbf 287 }
21e70425
MAL
288
289 return 0;
b931bfbf
CO
290}
291
94c9cb31
MT
292static int vhost_user_set_mem_table(struct vhost_dev *dev,
293 struct vhost_memory *mem)
294{
295 int fds[VHOST_MEMORY_MAX_NREGIONS];
296 int i, fd;
297 size_t fd_num = 0;
298 bool reply_supported = virtio_has_feature(dev->protocol_features,
299 VHOST_USER_PROTOCOL_F_REPLY_ACK);
300
301 VhostUserMsg msg = {
302 .request = VHOST_USER_SET_MEM_TABLE,
303 .flags = VHOST_USER_VERSION,
304 };
305
306 if (reply_supported) {
307 msg.flags |= VHOST_USER_NEED_REPLY_MASK;
308 }
309
310 for (i = 0; i < dev->mem->nregions; ++i) {
311 struct vhost_memory_region *reg = dev->mem->regions + i;
312 ram_addr_t offset;
313 MemoryRegion *mr;
314
315 assert((uintptr_t)reg->userspace_addr == reg->userspace_addr);
316 mr = memory_region_from_host((void *)(uintptr_t)reg->userspace_addr,
317 &offset);
318 fd = memory_region_get_fd(mr);
319 if (fd > 0) {
88bf4a70
JZ
320 if (fd_num == VHOST_MEMORY_MAX_NREGIONS) {
321 error_report("Failed preparing vhost-user memory table msg");
322 return -1;
323 }
94c9cb31
MT
324 msg.payload.memory.regions[fd_num].userspace_addr = reg->userspace_addr;
325 msg.payload.memory.regions[fd_num].memory_size = reg->memory_size;
326 msg.payload.memory.regions[fd_num].guest_phys_addr = reg->guest_phys_addr;
327 msg.payload.memory.regions[fd_num].mmap_offset = offset;
94c9cb31
MT
328 fds[fd_num++] = fd;
329 }
330 }
331
332 msg.payload.memory.nregions = fd_num;
333
334 if (!fd_num) {
335 error_report("Failed initializing vhost-user memory map, "
336 "consider using -object memory-backend-file share=on");
337 return -1;
338 }
339
340 msg.size = sizeof(msg.payload.memory.nregions);
341 msg.size += sizeof(msg.payload.memory.padding);
342 msg.size += fd_num * sizeof(VhostUserMemoryRegion);
343
344 if (vhost_user_write(dev, &msg, fds, fd_num) < 0) {
345 return -1;
346 }
347
348 if (reply_supported) {
3cf7daf8 349 return process_message_reply(dev, &msg);
94c9cb31
MT
350 }
351
352 return 0;
353}
354
21e70425
MAL
355static int vhost_user_set_vring_addr(struct vhost_dev *dev,
356 struct vhost_vring_addr *addr)
357{
358 VhostUserMsg msg = {
359 .request = VHOST_USER_SET_VRING_ADDR,
360 .flags = VHOST_USER_VERSION,
7f4a930e 361 .payload.addr = *addr,
7fc0246c 362 .size = sizeof(msg.payload.addr),
21e70425 363 };
5f6f6664 364
c4843a45
MAL
365 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
366 return -1;
367 }
5f6f6664 368
21e70425
MAL
369 return 0;
370}
5f6f6664 371
21e70425
MAL
372static int vhost_user_set_vring_endian(struct vhost_dev *dev,
373 struct vhost_vring_state *ring)
374{
5df04f17
FF
375 bool cross_endian = virtio_has_feature(dev->protocol_features,
376 VHOST_USER_PROTOCOL_F_CROSS_ENDIAN);
377 VhostUserMsg msg = {
378 .request = VHOST_USER_SET_VRING_ENDIAN,
379 .flags = VHOST_USER_VERSION,
380 .payload.state = *ring,
381 .size = sizeof(msg.payload.state),
382 };
383
384 if (!cross_endian) {
385 error_report("vhost-user trying to send unhandled ioctl");
386 return -1;
387 }
388
389 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
390 return -1;
391 }
392
393 return 0;
21e70425 394}
5f6f6664 395
21e70425
MAL
396static int vhost_set_vring(struct vhost_dev *dev,
397 unsigned long int request,
398 struct vhost_vring_state *ring)
399{
400 VhostUserMsg msg = {
401 .request = request,
402 .flags = VHOST_USER_VERSION,
7f4a930e 403 .payload.state = *ring,
7fc0246c 404 .size = sizeof(msg.payload.state),
21e70425
MAL
405 };
406
c4843a45
MAL
407 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
408 return -1;
409 }
21e70425
MAL
410
411 return 0;
412}
413
414static int vhost_user_set_vring_num(struct vhost_dev *dev,
415 struct vhost_vring_state *ring)
416{
417 return vhost_set_vring(dev, VHOST_USER_SET_VRING_NUM, ring);
418}
419
420static int vhost_user_set_vring_base(struct vhost_dev *dev,
421 struct vhost_vring_state *ring)
422{
423 return vhost_set_vring(dev, VHOST_USER_SET_VRING_BASE, ring);
424}
425
426static int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable)
427{
dc3db6ad 428 int i;
21e70425 429
923e2d98 430 if (!virtio_has_feature(dev->features, VHOST_USER_F_PROTOCOL_FEATURES)) {
5f6f6664 431 return -1;
5f6f6664
NN
432 }
433
dc3db6ad
MT
434 for (i = 0; i < dev->nvqs; ++i) {
435 struct vhost_vring_state state = {
436 .index = dev->vq_index + i,
437 .num = enable,
438 };
439
440 vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, &state);
441 }
21e70425 442
dc3db6ad
MT
443 return 0;
444}
21e70425
MAL
445
446static int vhost_user_get_vring_base(struct vhost_dev *dev,
447 struct vhost_vring_state *ring)
448{
449 VhostUserMsg msg = {
450 .request = VHOST_USER_GET_VRING_BASE,
451 .flags = VHOST_USER_VERSION,
7f4a930e 452 .payload.state = *ring,
7fc0246c 453 .size = sizeof(msg.payload.state),
21e70425
MAL
454 };
455
c4843a45
MAL
456 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
457 return -1;
458 }
21e70425
MAL
459
460 if (vhost_user_read(dev, &msg) < 0) {
c4843a45 461 return -1;
5f6f6664
NN
462 }
463
21e70425
MAL
464 if (msg.request != VHOST_USER_GET_VRING_BASE) {
465 error_report("Received unexpected msg type. Expected %d received %d",
466 VHOST_USER_GET_VRING_BASE, msg.request);
467 return -1;
468 }
5f6f6664 469
86abad0f 470 if (msg.size != sizeof(msg.payload.state)) {
21e70425
MAL
471 error_report("Received bad msg size.");
472 return -1;
5f6f6664
NN
473 }
474
7f4a930e 475 *ring = msg.payload.state;
21e70425 476
5f6f6664
NN
477 return 0;
478}
479
21e70425
MAL
480static int vhost_set_vring_file(struct vhost_dev *dev,
481 VhostUserRequest request,
482 struct vhost_vring_file *file)
c2bea314 483{
9a78a5dd
MAL
484 int fds[VHOST_MEMORY_MAX_NREGIONS];
485 size_t fd_num = 0;
c2bea314 486 VhostUserMsg msg = {
21e70425 487 .request = request,
c2bea314 488 .flags = VHOST_USER_VERSION,
7f4a930e 489 .payload.u64 = file->index & VHOST_USER_VRING_IDX_MASK,
86abad0f 490 .size = sizeof(msg.payload.u64),
c2bea314
MAL
491 };
492
21e70425
MAL
493 if (ioeventfd_enabled() && file->fd > 0) {
494 fds[fd_num++] = file->fd;
495 } else {
7f4a930e 496 msg.payload.u64 |= VHOST_USER_VRING_NOFD_MASK;
9a78a5dd
MAL
497 }
498
c4843a45
MAL
499 if (vhost_user_write(dev, &msg, fds, fd_num) < 0) {
500 return -1;
501 }
9a78a5dd 502
21e70425
MAL
503 return 0;
504}
9a78a5dd 505
21e70425
MAL
506static int vhost_user_set_vring_kick(struct vhost_dev *dev,
507 struct vhost_vring_file *file)
508{
509 return vhost_set_vring_file(dev, VHOST_USER_SET_VRING_KICK, file);
510}
511
512static int vhost_user_set_vring_call(struct vhost_dev *dev,
513 struct vhost_vring_file *file)
514{
515 return vhost_set_vring_file(dev, VHOST_USER_SET_VRING_CALL, file);
516}
517
518static int vhost_user_set_u64(struct vhost_dev *dev, int request, uint64_t u64)
519{
520 VhostUserMsg msg = {
521 .request = request,
522 .flags = VHOST_USER_VERSION,
7f4a930e 523 .payload.u64 = u64,
86abad0f 524 .size = sizeof(msg.payload.u64),
21e70425
MAL
525 };
526
c4843a45
MAL
527 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
528 return -1;
529 }
21e70425
MAL
530
531 return 0;
532}
533
534static int vhost_user_set_features(struct vhost_dev *dev,
535 uint64_t features)
536{
537 return vhost_user_set_u64(dev, VHOST_USER_SET_FEATURES, features);
538}
539
540static int vhost_user_set_protocol_features(struct vhost_dev *dev,
541 uint64_t features)
542{
543 return vhost_user_set_u64(dev, VHOST_USER_SET_PROTOCOL_FEATURES, features);
544}
545
546static int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64)
547{
548 VhostUserMsg msg = {
549 .request = request,
550 .flags = VHOST_USER_VERSION,
551 };
552
553 if (vhost_user_one_time_request(request) && dev->vq_index != 0) {
554 return 0;
9a78a5dd 555 }
c2bea314 556
c4843a45
MAL
557 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
558 return -1;
559 }
21e70425
MAL
560
561 if (vhost_user_read(dev, &msg) < 0) {
c4843a45 562 return -1;
21e70425
MAL
563 }
564
565 if (msg.request != request) {
566 error_report("Received unexpected msg type. Expected %d received %d",
567 request, msg.request);
568 return -1;
569 }
570
86abad0f 571 if (msg.size != sizeof(msg.payload.u64)) {
21e70425
MAL
572 error_report("Received bad msg size.");
573 return -1;
574 }
575
7f4a930e 576 *u64 = msg.payload.u64;
21e70425
MAL
577
578 return 0;
579}
580
581static int vhost_user_get_features(struct vhost_dev *dev, uint64_t *features)
582{
583 return vhost_user_get_u64(dev, VHOST_USER_GET_FEATURES, features);
584}
585
586static int vhost_user_set_owner(struct vhost_dev *dev)
587{
588 VhostUserMsg msg = {
589 .request = VHOST_USER_SET_OWNER,
590 .flags = VHOST_USER_VERSION,
591 };
592
c4843a45
MAL
593 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
594 return -1;
595 }
21e70425
MAL
596
597 return 0;
598}
599
600static int vhost_user_reset_device(struct vhost_dev *dev)
601{
602 VhostUserMsg msg = {
60915dc4 603 .request = VHOST_USER_RESET_OWNER,
21e70425
MAL
604 .flags = VHOST_USER_VERSION,
605 };
606
c4843a45
MAL
607 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
608 return -1;
609 }
21e70425 610
c2bea314
MAL
611 return 0;
612}
613
4bbeeba0
MAL
614static void slave_read(void *opaque)
615{
616 struct vhost_dev *dev = opaque;
617 struct vhost_user *u = dev->opaque;
618 VhostUserMsg msg = { 0, };
619 int size, ret = 0;
620
621 /* Read header */
622 size = read(u->slave_fd, &msg, VHOST_USER_HDR_SIZE);
623 if (size != VHOST_USER_HDR_SIZE) {
624 error_report("Failed to read from slave.");
625 goto err;
626 }
627
628 if (msg.size > VHOST_USER_PAYLOAD_SIZE) {
629 error_report("Failed to read msg header."
630 " Size %d exceeds the maximum %zu.", msg.size,
631 VHOST_USER_PAYLOAD_SIZE);
632 goto err;
633 }
634
635 /* Read payload */
636 size = read(u->slave_fd, &msg.payload, msg.size);
637 if (size != msg.size) {
638 error_report("Failed to read payload from slave.");
639 goto err;
640 }
641
642 switch (msg.request) {
6dcdd06e
MC
643 case VHOST_USER_SLAVE_IOTLB_MSG:
644 ret = vhost_backend_handle_iotlb_msg(dev, &msg.payload.iotlb);
645 break;
4bbeeba0
MAL
646 default:
647 error_report("Received unexpected msg type.");
648 ret = -EINVAL;
649 }
650
651 /*
652 * REPLY_ACK feature handling. Other reply types has to be managed
653 * directly in their request handlers.
654 */
655 if (msg.flags & VHOST_USER_NEED_REPLY_MASK) {
656 msg.flags &= ~VHOST_USER_NEED_REPLY_MASK;
657 msg.flags |= VHOST_USER_REPLY_MASK;
658
659 msg.payload.u64 = !!ret;
660 msg.size = sizeof(msg.payload.u64);
661
662 size = write(u->slave_fd, &msg, VHOST_USER_HDR_SIZE + msg.size);
663 if (size != VHOST_USER_HDR_SIZE + msg.size) {
664 error_report("Failed to send msg reply to slave.");
665 goto err;
666 }
667 }
668
669 return;
670
671err:
672 qemu_set_fd_handler(u->slave_fd, NULL, NULL, NULL);
673 close(u->slave_fd);
674 u->slave_fd = -1;
675 return;
676}
677
678static int vhost_setup_slave_channel(struct vhost_dev *dev)
679{
680 VhostUserMsg msg = {
681 .request = VHOST_USER_SET_SLAVE_REQ_FD,
682 .flags = VHOST_USER_VERSION,
683 };
684 struct vhost_user *u = dev->opaque;
685 int sv[2], ret = 0;
686 bool reply_supported = virtio_has_feature(dev->protocol_features,
687 VHOST_USER_PROTOCOL_F_REPLY_ACK);
688
689 if (!virtio_has_feature(dev->protocol_features,
690 VHOST_USER_PROTOCOL_F_SLAVE_REQ)) {
691 return 0;
692 }
693
694 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
695 error_report("socketpair() failed");
696 return -1;
697 }
698
699 u->slave_fd = sv[0];
700 qemu_set_fd_handler(u->slave_fd, slave_read, NULL, dev);
701
702 if (reply_supported) {
703 msg.flags |= VHOST_USER_NEED_REPLY_MASK;
704 }
705
706 ret = vhost_user_write(dev, &msg, &sv[1], 1);
707 if (ret) {
708 goto out;
709 }
710
711 if (reply_supported) {
712 ret = process_message_reply(dev, &msg);
713 }
714
715out:
716 close(sv[1]);
717 if (ret) {
718 qemu_set_fd_handler(u->slave_fd, NULL, NULL, NULL);
719 close(u->slave_fd);
720 u->slave_fd = -1;
721 }
722
723 return ret;
724}
725
5f6f6664
NN
726static int vhost_user_init(struct vhost_dev *dev, void *opaque)
727{
6dcdd06e 728 uint64_t features, protocol_features;
2152f3fe 729 struct vhost_user *u;
dcb10c00
MT
730 int err;
731
5f6f6664
NN
732 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
733
2152f3fe
MAL
734 u = g_new0(struct vhost_user, 1);
735 u->chr = opaque;
4bbeeba0 736 u->slave_fd = -1;
2152f3fe 737 dev->opaque = u;
5f6f6664 738
21e70425 739 err = vhost_user_get_features(dev, &features);
dcb10c00
MT
740 if (err < 0) {
741 return err;
742 }
743
744 if (virtio_has_feature(features, VHOST_USER_F_PROTOCOL_FEATURES)) {
745 dev->backend_features |= 1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
746
21e70425 747 err = vhost_user_get_u64(dev, VHOST_USER_GET_PROTOCOL_FEATURES,
6dcdd06e 748 &protocol_features);
dcb10c00
MT
749 if (err < 0) {
750 return err;
751 }
752
6dcdd06e
MC
753 dev->protocol_features =
754 protocol_features & VHOST_USER_PROTOCOL_FEATURE_MASK;
21e70425 755 err = vhost_user_set_protocol_features(dev, dev->protocol_features);
dcb10c00
MT
756 if (err < 0) {
757 return err;
758 }
e2051e9e
YL
759
760 /* query the max queues we support if backend supports Multiple Queue */
761 if (dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_MQ)) {
21e70425
MAL
762 err = vhost_user_get_u64(dev, VHOST_USER_GET_QUEUE_NUM,
763 &dev->max_queues);
e2051e9e
YL
764 if (err < 0) {
765 return err;
766 }
767 }
6dcdd06e
MC
768
769 if (virtio_has_feature(features, VIRTIO_F_IOMMU_PLATFORM) &&
770 !(virtio_has_feature(dev->protocol_features,
771 VHOST_USER_PROTOCOL_F_SLAVE_REQ) &&
772 virtio_has_feature(dev->protocol_features,
773 VHOST_USER_PROTOCOL_F_REPLY_ACK))) {
774 error_report("IOMMU support requires reply-ack and "
775 "slave-req protocol features.");
776 return -1;
777 }
dcb10c00
MT
778 }
779
d2fc4402
MAL
780 if (dev->migration_blocker == NULL &&
781 !virtio_has_feature(dev->protocol_features,
782 VHOST_USER_PROTOCOL_F_LOG_SHMFD)) {
783 error_setg(&dev->migration_blocker,
784 "Migration disabled: vhost-user backend lacks "
785 "VHOST_USER_PROTOCOL_F_LOG_SHMFD feature.");
786 }
787
4bbeeba0
MAL
788 err = vhost_setup_slave_channel(dev);
789 if (err < 0) {
790 return err;
791 }
792
5f6f6664
NN
793 return 0;
794}
795
796static int vhost_user_cleanup(struct vhost_dev *dev)
797{
2152f3fe
MAL
798 struct vhost_user *u;
799
5f6f6664
NN
800 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
801
2152f3fe 802 u = dev->opaque;
4bbeeba0 803 if (u->slave_fd >= 0) {
b9ec9bd4 804 qemu_set_fd_handler(u->slave_fd, NULL, NULL, NULL);
4bbeeba0
MAL
805 close(u->slave_fd);
806 u->slave_fd = -1;
807 }
2152f3fe 808 g_free(u);
5f6f6664
NN
809 dev->opaque = 0;
810
811 return 0;
812}
813
fc57fd99
YL
814static int vhost_user_get_vq_index(struct vhost_dev *dev, int idx)
815{
816 assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
817
818 return idx;
819}
820
2ce68e4c
IM
821static int vhost_user_memslots_limit(struct vhost_dev *dev)
822{
823 return VHOST_MEMORY_MAX_NREGIONS;
824}
825
1be0ac21
MAL
826static bool vhost_user_requires_shm_log(struct vhost_dev *dev)
827{
828 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
829
830 return virtio_has_feature(dev->protocol_features,
831 VHOST_USER_PROTOCOL_F_LOG_SHMFD);
832}
833
3e866365
TC
834static int vhost_user_migration_done(struct vhost_dev *dev, char* mac_addr)
835{
836 VhostUserMsg msg = { 0 };
3e866365
TC
837
838 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
839
840 /* If guest supports GUEST_ANNOUNCE do nothing */
841 if (virtio_has_feature(dev->acked_features, VIRTIO_NET_F_GUEST_ANNOUNCE)) {
842 return 0;
843 }
844
845 /* if backend supports VHOST_USER_PROTOCOL_F_RARP ask it to send the RARP */
846 if (virtio_has_feature(dev->protocol_features,
847 VHOST_USER_PROTOCOL_F_RARP)) {
848 msg.request = VHOST_USER_SEND_RARP;
849 msg.flags = VHOST_USER_VERSION;
7f4a930e 850 memcpy((char *)&msg.payload.u64, mac_addr, 6);
86abad0f 851 msg.size = sizeof(msg.payload.u64);
3e866365 852
c4843a45 853 return vhost_user_write(dev, &msg, NULL, 0);
3e866365
TC
854 }
855 return -1;
856}
857
ffe42cc1
MT
858static bool vhost_user_can_merge(struct vhost_dev *dev,
859 uint64_t start1, uint64_t size1,
860 uint64_t start2, uint64_t size2)
861{
07bdaa41 862 ram_addr_t offset;
ffe42cc1
MT
863 int mfd, rfd;
864 MemoryRegion *mr;
865
07bdaa41 866 mr = memory_region_from_host((void *)(uintptr_t)start1, &offset);
4ff87573 867 mfd = memory_region_get_fd(mr);
ffe42cc1 868
07bdaa41 869 mr = memory_region_from_host((void *)(uintptr_t)start2, &offset);
4ff87573 870 rfd = memory_region_get_fd(mr);
ffe42cc1
MT
871
872 return mfd == rfd;
873}
874
c5f048d8
MC
875static int vhost_user_net_set_mtu(struct vhost_dev *dev, uint16_t mtu)
876{
877 VhostUserMsg msg;
878 bool reply_supported = virtio_has_feature(dev->protocol_features,
879 VHOST_USER_PROTOCOL_F_REPLY_ACK);
880
881 if (!(dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_NET_MTU))) {
882 return 0;
883 }
884
885 msg.request = VHOST_USER_NET_SET_MTU;
886 msg.payload.u64 = mtu;
887 msg.size = sizeof(msg.payload.u64);
888 msg.flags = VHOST_USER_VERSION;
889 if (reply_supported) {
890 msg.flags |= VHOST_USER_NEED_REPLY_MASK;
891 }
892
893 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
894 return -1;
895 }
896
897 /* If reply_ack supported, slave has to ack specified MTU is valid */
898 if (reply_supported) {
3cf7daf8 899 return process_message_reply(dev, &msg);
c5f048d8
MC
900 }
901
902 return 0;
903}
904
6dcdd06e
MC
905static int vhost_user_send_device_iotlb_msg(struct vhost_dev *dev,
906 struct vhost_iotlb_msg *imsg)
907{
908 VhostUserMsg msg = {
909 .request = VHOST_USER_IOTLB_MSG,
910 .size = sizeof(msg.payload.iotlb),
911 .flags = VHOST_USER_VERSION | VHOST_USER_NEED_REPLY_MASK,
912 .payload.iotlb = *imsg,
913 };
914
915 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
916 return -EFAULT;
917 }
918
919 return process_message_reply(dev, &msg);
920}
921
922
923static void vhost_user_set_iotlb_callback(struct vhost_dev *dev, int enabled)
924{
925 /* No-op as the receive channel is not dedicated to IOTLB messages. */
926}
927
5f6f6664
NN
928const VhostOps user_ops = {
929 .backend_type = VHOST_BACKEND_TYPE_USER,
5f6f6664 930 .vhost_backend_init = vhost_user_init,
fc57fd99 931 .vhost_backend_cleanup = vhost_user_cleanup,
2ce68e4c 932 .vhost_backend_memslots_limit = vhost_user_memslots_limit,
21e70425
MAL
933 .vhost_set_log_base = vhost_user_set_log_base,
934 .vhost_set_mem_table = vhost_user_set_mem_table,
935 .vhost_set_vring_addr = vhost_user_set_vring_addr,
936 .vhost_set_vring_endian = vhost_user_set_vring_endian,
937 .vhost_set_vring_num = vhost_user_set_vring_num,
938 .vhost_set_vring_base = vhost_user_set_vring_base,
939 .vhost_get_vring_base = vhost_user_get_vring_base,
940 .vhost_set_vring_kick = vhost_user_set_vring_kick,
941 .vhost_set_vring_call = vhost_user_set_vring_call,
942 .vhost_set_features = vhost_user_set_features,
943 .vhost_get_features = vhost_user_get_features,
944 .vhost_set_owner = vhost_user_set_owner,
945 .vhost_reset_device = vhost_user_reset_device,
946 .vhost_get_vq_index = vhost_user_get_vq_index,
947 .vhost_set_vring_enable = vhost_user_set_vring_enable,
1be0ac21 948 .vhost_requires_shm_log = vhost_user_requires_shm_log,
3e866365 949 .vhost_migration_done = vhost_user_migration_done,
ffe42cc1 950 .vhost_backend_can_merge = vhost_user_can_merge,
c5f048d8 951 .vhost_net_set_mtu = vhost_user_net_set_mtu,
6dcdd06e
MC
952 .vhost_set_iotlb_callback = vhost_user_set_iotlb_callback,
953 .vhost_send_device_iotlb_msg = vhost_user_send_device_iotlb_msg,
fc57fd99 954};