]> git.proxmox.com Git - mirror_qemu.git/blob - tests/vhost-user-test.c
Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20190304' into staging
[mirror_qemu.git] / tests / vhost-user-test.c
1 /*
2 * QTest testcase for the vhost-user
3 *
4 * Copyright (c) 2014 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
11 #include "qemu/osdep.h"
12
13 #include "libqtest.h"
14 #include "qapi/error.h"
15 #include "qapi/qmp/qdict.h"
16 #include "qemu/config-file.h"
17 #include "qemu/option.h"
18 #include "qemu/range.h"
19 #include "qemu/sockets.h"
20 #include "chardev/char-fe.h"
21 #include "qemu/memfd.h"
22 #include "sysemu/sysemu.h"
23 #include "libqos/libqos.h"
24 #include "libqos/pci-pc.h"
25 #include "libqos/virtio-pci.h"
26
27 #include "libqos/malloc-pc.h"
28 #include "hw/virtio/virtio-net.h"
29
30 #include "standard-headers/linux/vhost_types.h"
31 #include "standard-headers/linux/virtio_ids.h"
32 #include "standard-headers/linux/virtio_net.h"
33
34 #ifdef CONFIG_LINUX
35 #include <sys/vfs.h>
36 #endif
37
38
39 #define QEMU_CMD_MEM " -m %d -object memory-backend-file,id=mem,size=%dM," \
40 "mem-path=%s,share=on -numa node,memdev=mem"
41 #define QEMU_CMD_MEMFD " -m %d -object memory-backend-memfd,id=mem,size=%dM," \
42 " -numa node,memdev=mem"
43 #define QEMU_CMD_CHR " -chardev socket,id=%s,path=%s%s"
44 #define QEMU_CMD_NETDEV " -netdev vhost-user,id=net0,chardev=%s,vhostforce"
45 #define QEMU_CMD_NET " -device virtio-net-pci,netdev=net0"
46
47 #define HUGETLBFS_MAGIC 0x958458f6
48
49 /*********** FROM hw/virtio/vhost-user.c *************************************/
50
51 #define VHOST_MEMORY_MAX_NREGIONS 8
52 #define VHOST_MAX_VIRTQUEUES 0x100
53
54 #define VHOST_USER_F_PROTOCOL_FEATURES 30
55 #define VHOST_USER_PROTOCOL_F_MQ 0
56 #define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1
57 #define VHOST_USER_PROTOCOL_F_CROSS_ENDIAN 6
58
59 #define VHOST_LOG_PAGE 0x1000
60
61 typedef enum VhostUserRequest {
62 VHOST_USER_NONE = 0,
63 VHOST_USER_GET_FEATURES = 1,
64 VHOST_USER_SET_FEATURES = 2,
65 VHOST_USER_SET_OWNER = 3,
66 VHOST_USER_RESET_OWNER = 4,
67 VHOST_USER_SET_MEM_TABLE = 5,
68 VHOST_USER_SET_LOG_BASE = 6,
69 VHOST_USER_SET_LOG_FD = 7,
70 VHOST_USER_SET_VRING_NUM = 8,
71 VHOST_USER_SET_VRING_ADDR = 9,
72 VHOST_USER_SET_VRING_BASE = 10,
73 VHOST_USER_GET_VRING_BASE = 11,
74 VHOST_USER_SET_VRING_KICK = 12,
75 VHOST_USER_SET_VRING_CALL = 13,
76 VHOST_USER_SET_VRING_ERR = 14,
77 VHOST_USER_GET_PROTOCOL_FEATURES = 15,
78 VHOST_USER_SET_PROTOCOL_FEATURES = 16,
79 VHOST_USER_GET_QUEUE_NUM = 17,
80 VHOST_USER_SET_VRING_ENABLE = 18,
81 VHOST_USER_MAX
82 } VhostUserRequest;
83
84 typedef struct VhostUserMemoryRegion {
85 uint64_t guest_phys_addr;
86 uint64_t memory_size;
87 uint64_t userspace_addr;
88 uint64_t mmap_offset;
89 } VhostUserMemoryRegion;
90
91 typedef struct VhostUserMemory {
92 uint32_t nregions;
93 uint32_t padding;
94 VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
95 } VhostUserMemory;
96
97 typedef struct VhostUserLog {
98 uint64_t mmap_size;
99 uint64_t mmap_offset;
100 } VhostUserLog;
101
102 typedef struct VhostUserMsg {
103 VhostUserRequest request;
104
105 #define VHOST_USER_VERSION_MASK (0x3)
106 #define VHOST_USER_REPLY_MASK (0x1<<2)
107 uint32_t flags;
108 uint32_t size; /* the following payload size */
109 union {
110 #define VHOST_USER_VRING_IDX_MASK (0xff)
111 #define VHOST_USER_VRING_NOFD_MASK (0x1<<8)
112 uint64_t u64;
113 struct vhost_vring_state state;
114 struct vhost_vring_addr addr;
115 VhostUserMemory memory;
116 VhostUserLog log;
117 } payload;
118 } QEMU_PACKED VhostUserMsg;
119
120 static VhostUserMsg m __attribute__ ((unused));
121 #define VHOST_USER_HDR_SIZE (sizeof(m.request) \
122 + sizeof(m.flags) \
123 + sizeof(m.size))
124
125 #define VHOST_USER_PAYLOAD_SIZE (sizeof(m) - VHOST_USER_HDR_SIZE)
126
127 /* The version of the protocol we support */
128 #define VHOST_USER_VERSION (0x1)
129 /*****************************************************************************/
130
131 enum {
132 TEST_FLAGS_OK,
133 TEST_FLAGS_DISCONNECT,
134 TEST_FLAGS_BAD,
135 TEST_FLAGS_END,
136 };
137
138 typedef struct TestServer {
139 QPCIBus *bus;
140 QVirtioPCIDevice *dev;
141 QVirtQueue *vq[VHOST_MAX_VIRTQUEUES];
142 gchar *socket_path;
143 gchar *mig_path;
144 gchar *chr_name;
145 const gchar *mem_path;
146 gchar *tmpfs;
147 CharBackend chr;
148 int fds_num;
149 int fds[VHOST_MEMORY_MAX_NREGIONS];
150 VhostUserMemory memory;
151 GMainContext *context;
152 GMainLoop *loop;
153 GThread *thread;
154 GMutex data_mutex;
155 GCond data_cond;
156 int log_fd;
157 uint64_t rings;
158 bool test_fail;
159 int test_flags;
160 int queues;
161 QGuestAllocator *alloc;
162 } TestServer;
163
164 static TestServer *test_server_new(const gchar *name);
165 static void test_server_free(TestServer *server);
166 static void test_server_listen(TestServer *server);
167
168 enum test_memfd {
169 TEST_MEMFD_AUTO,
170 TEST_MEMFD_YES,
171 TEST_MEMFD_NO,
172 };
173
174 static char *get_qemu_cmd(TestServer *s,
175 int mem, enum test_memfd memfd,
176 const char *chr_opts, const char *extra)
177 {
178 if (memfd == TEST_MEMFD_AUTO && qemu_memfd_check(0)) {
179 memfd = TEST_MEMFD_YES;
180 }
181
182 if (memfd == TEST_MEMFD_YES) {
183 return g_strdup_printf(QEMU_CMD_MEMFD QEMU_CMD_CHR
184 QEMU_CMD_NETDEV QEMU_CMD_NET "%s", mem, mem,
185 s->chr_name, s->socket_path,
186 chr_opts, s->chr_name, extra);
187 } else {
188 return g_strdup_printf(QEMU_CMD_MEM QEMU_CMD_CHR
189 QEMU_CMD_NETDEV QEMU_CMD_NET "%s", mem, mem,
190 s->mem_path, s->chr_name, s->socket_path,
191 chr_opts, s->chr_name, extra);
192 }
193 }
194
195 static void init_virtio_dev(QTestState *qts, TestServer *s, uint32_t features_mask)
196 {
197 uint32_t features;
198 int i;
199
200 s->bus = qpci_init_pc(qts, NULL);
201 g_assert_nonnull(s->bus);
202
203 s->dev = qvirtio_pci_device_find(s->bus, VIRTIO_ID_NET);
204 g_assert_nonnull(s->dev);
205
206 qvirtio_pci_device_enable(s->dev);
207 qvirtio_reset(&s->dev->vdev);
208 qvirtio_set_acknowledge(&s->dev->vdev);
209 qvirtio_set_driver(&s->dev->vdev);
210
211 s->alloc = pc_alloc_init(qts);
212
213 for (i = 0; i < s->queues * 2; i++) {
214 s->vq[i] = qvirtqueue_setup(&s->dev->vdev, s->alloc, i);
215 }
216
217 features = qvirtio_get_features(&s->dev->vdev);
218 features = features & features_mask;
219 qvirtio_set_features(&s->dev->vdev, features);
220
221 qvirtio_set_driver_ok(&s->dev->vdev);
222 }
223
224 static void uninit_virtio_dev(TestServer *s)
225 {
226 int i;
227
228 for (i = 0; i < s->queues * 2; i++) {
229 qvirtqueue_cleanup(s->dev->vdev.bus, s->vq[i], s->alloc);
230 }
231 pc_alloc_uninit(s->alloc);
232
233 qvirtio_pci_device_free(s->dev);
234 }
235
236 static bool wait_for_fds(TestServer *s)
237 {
238 gint64 end_time;
239 bool got_region;
240 int i;
241
242 g_mutex_lock(&s->data_mutex);
243
244 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
245 while (!s->fds_num) {
246 if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
247 /* timeout has passed */
248 g_assert(s->fds_num);
249 break;
250 }
251 }
252
253 /* check for sanity */
254 g_assert_cmpint(s->fds_num, >, 0);
255 g_assert_cmpint(s->fds_num, ==, s->memory.nregions);
256
257 g_mutex_unlock(&s->data_mutex);
258
259 got_region = false;
260 for (i = 0; i < s->memory.nregions; ++i) {
261 VhostUserMemoryRegion *reg = &s->memory.regions[i];
262 if (reg->guest_phys_addr == 0) {
263 got_region = true;
264 break;
265 }
266 }
267 if (!got_region) {
268 g_test_skip("No memory at address 0x0");
269 }
270 return got_region;
271 }
272
273 static void read_guest_mem_server(QTestState *qts, TestServer *s)
274 {
275 uint8_t *guest_mem;
276 int i, j;
277 size_t size;
278
279 g_mutex_lock(&s->data_mutex);
280
281 /* iterate all regions */
282 for (i = 0; i < s->fds_num; i++) {
283
284 /* We'll check only the region statring at 0x0*/
285 if (s->memory.regions[i].guest_phys_addr != 0x0) {
286 continue;
287 }
288
289 g_assert_cmpint(s->memory.regions[i].memory_size, >, 1024);
290
291 size = s->memory.regions[i].memory_size +
292 s->memory.regions[i].mmap_offset;
293
294 guest_mem = mmap(0, size, PROT_READ | PROT_WRITE,
295 MAP_SHARED, s->fds[i], 0);
296
297 g_assert(guest_mem != MAP_FAILED);
298 guest_mem += (s->memory.regions[i].mmap_offset / sizeof(*guest_mem));
299
300 for (j = 0; j < 1024; j++) {
301 uint32_t a = qtest_readb(qts, s->memory.regions[i].guest_phys_addr + j);
302 uint32_t b = guest_mem[j];
303
304 g_assert_cmpint(a, ==, b);
305 }
306
307 munmap(guest_mem, s->memory.regions[i].memory_size);
308 }
309
310 g_mutex_unlock(&s->data_mutex);
311 }
312
313 static void *thread_function(void *data)
314 {
315 GMainLoop *loop = data;
316 g_main_loop_run(loop);
317 return NULL;
318 }
319
320 static int chr_can_read(void *opaque)
321 {
322 return VHOST_USER_HDR_SIZE;
323 }
324
325 static void chr_read(void *opaque, const uint8_t *buf, int size)
326 {
327 TestServer *s = opaque;
328 CharBackend *chr = &s->chr;
329 VhostUserMsg msg;
330 uint8_t *p = (uint8_t *) &msg;
331 int fd = -1;
332
333 if (s->test_fail) {
334 qemu_chr_fe_disconnect(chr);
335 /* now switch to non-failure */
336 s->test_fail = false;
337 }
338
339 if (size != VHOST_USER_HDR_SIZE) {
340 g_test_message("Wrong message size received %d\n", size);
341 return;
342 }
343
344 g_mutex_lock(&s->data_mutex);
345 memcpy(p, buf, VHOST_USER_HDR_SIZE);
346
347 if (msg.size) {
348 p += VHOST_USER_HDR_SIZE;
349 size = qemu_chr_fe_read_all(chr, p, msg.size);
350 if (size != msg.size) {
351 g_test_message("Wrong message size received %d != %d\n",
352 size, msg.size);
353 return;
354 }
355 }
356
357 switch (msg.request) {
358 case VHOST_USER_GET_FEATURES:
359 /* send back features to qemu */
360 msg.flags |= VHOST_USER_REPLY_MASK;
361 msg.size = sizeof(m.payload.u64);
362 msg.payload.u64 = 0x1ULL << VHOST_F_LOG_ALL |
363 0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
364 if (s->queues > 1) {
365 msg.payload.u64 |= 0x1ULL << VIRTIO_NET_F_MQ;
366 }
367 if (s->test_flags >= TEST_FLAGS_BAD) {
368 msg.payload.u64 = 0;
369 s->test_flags = TEST_FLAGS_END;
370 }
371 p = (uint8_t *) &msg;
372 qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
373 break;
374
375 case VHOST_USER_SET_FEATURES:
376 g_assert_cmpint(msg.payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES),
377 !=, 0ULL);
378 if (s->test_flags == TEST_FLAGS_DISCONNECT) {
379 qemu_chr_fe_disconnect(chr);
380 s->test_flags = TEST_FLAGS_BAD;
381 }
382 break;
383
384 case VHOST_USER_GET_PROTOCOL_FEATURES:
385 /* send back features to qemu */
386 msg.flags |= VHOST_USER_REPLY_MASK;
387 msg.size = sizeof(m.payload.u64);
388 msg.payload.u64 = 1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD;
389 msg.payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_CROSS_ENDIAN;
390 if (s->queues > 1) {
391 msg.payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_MQ;
392 }
393 p = (uint8_t *) &msg;
394 qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
395 break;
396
397 case VHOST_USER_GET_VRING_BASE:
398 /* send back vring base to qemu */
399 msg.flags |= VHOST_USER_REPLY_MASK;
400 msg.size = sizeof(m.payload.state);
401 msg.payload.state.num = 0;
402 p = (uint8_t *) &msg;
403 qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
404
405 assert(msg.payload.state.index < s->queues * 2);
406 s->rings &= ~(0x1ULL << msg.payload.state.index);
407 g_cond_broadcast(&s->data_cond);
408 break;
409
410 case VHOST_USER_SET_MEM_TABLE:
411 /* received the mem table */
412 memcpy(&s->memory, &msg.payload.memory, sizeof(msg.payload.memory));
413 s->fds_num = qemu_chr_fe_get_msgfds(chr, s->fds,
414 G_N_ELEMENTS(s->fds));
415
416 /* signal the test that it can continue */
417 g_cond_broadcast(&s->data_cond);
418 break;
419
420 case VHOST_USER_SET_VRING_KICK:
421 case VHOST_USER_SET_VRING_CALL:
422 /* consume the fd */
423 qemu_chr_fe_get_msgfds(chr, &fd, 1);
424 /*
425 * This is a non-blocking eventfd.
426 * The receive function forces it to be blocking,
427 * so revert it back to non-blocking.
428 */
429 qemu_set_nonblock(fd);
430 break;
431
432 case VHOST_USER_SET_LOG_BASE:
433 if (s->log_fd != -1) {
434 close(s->log_fd);
435 s->log_fd = -1;
436 }
437 qemu_chr_fe_get_msgfds(chr, &s->log_fd, 1);
438 msg.flags |= VHOST_USER_REPLY_MASK;
439 msg.size = 0;
440 p = (uint8_t *) &msg;
441 qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE);
442
443 g_cond_broadcast(&s->data_cond);
444 break;
445
446 case VHOST_USER_SET_VRING_BASE:
447 assert(msg.payload.state.index < s->queues * 2);
448 s->rings |= 0x1ULL << msg.payload.state.index;
449 g_cond_broadcast(&s->data_cond);
450 break;
451
452 case VHOST_USER_GET_QUEUE_NUM:
453 msg.flags |= VHOST_USER_REPLY_MASK;
454 msg.size = sizeof(m.payload.u64);
455 msg.payload.u64 = s->queues;
456 p = (uint8_t *) &msg;
457 qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
458 break;
459
460 default:
461 break;
462 }
463
464 g_mutex_unlock(&s->data_mutex);
465 }
466
467 static const char *init_hugepagefs(void)
468 {
469 #ifdef CONFIG_LINUX
470 const char *path = getenv("QTEST_HUGETLBFS_PATH");
471 struct statfs fs;
472 int ret;
473
474 if (!path) {
475 return NULL;
476 }
477
478 if (access(path, R_OK | W_OK | X_OK)) {
479 g_test_message("access on path (%s): %s\n", path, strerror(errno));
480 abort();
481 return NULL;
482 }
483
484 do {
485 ret = statfs(path, &fs);
486 } while (ret != 0 && errno == EINTR);
487
488 if (ret != 0) {
489 g_test_message("statfs on path (%s): %s\n", path, strerror(errno));
490 abort();
491 return NULL;
492 }
493
494 if (fs.f_type != HUGETLBFS_MAGIC) {
495 g_test_message("Warning: path not on HugeTLBFS: %s\n", path);
496 abort();
497 return NULL;
498 }
499
500 return path;
501 #else
502 return NULL;
503 #endif
504 }
505
506 static TestServer *test_server_new(const gchar *name)
507 {
508 TestServer *server = g_new0(TestServer, 1);
509 char template[] = "/tmp/vhost-test-XXXXXX";
510 const char *tmpfs;
511
512 server->context = g_main_context_new();
513 server->loop = g_main_loop_new(server->context, FALSE);
514
515 /* run the main loop thread so the chardev may operate */
516 server->thread = g_thread_new(NULL, thread_function, server->loop);
517
518 tmpfs = mkdtemp(template);
519 if (!tmpfs) {
520 g_test_message("mkdtemp on path (%s): %s", template, strerror(errno));
521 }
522 g_assert(tmpfs);
523
524 server->tmpfs = g_strdup(tmpfs);
525 server->mem_path = init_hugepagefs() ? : server->tmpfs;
526 server->socket_path = g_strdup_printf("%s/%s.sock", tmpfs, name);
527 server->mig_path = g_strdup_printf("%s/%s.mig", tmpfs, name);
528 server->chr_name = g_strdup_printf("chr-%s", name);
529
530 g_mutex_init(&server->data_mutex);
531 g_cond_init(&server->data_cond);
532
533 server->log_fd = -1;
534 server->queues = 1;
535
536 return server;
537 }
538
539 static void chr_event(void *opaque, int event)
540 {
541 TestServer *s = opaque;
542
543 if (s->test_flags == TEST_FLAGS_END &&
544 event == CHR_EVENT_CLOSED) {
545 s->test_flags = TEST_FLAGS_OK;
546 }
547 }
548
549 static void test_server_create_chr(TestServer *server, const gchar *opt)
550 {
551 gchar *chr_path;
552 Chardev *chr;
553
554 chr_path = g_strdup_printf("unix:%s%s", server->socket_path, opt);
555 chr = qemu_chr_new(server->chr_name, chr_path, server->context);
556 g_free(chr_path);
557
558 g_assert_nonnull(chr);
559 qemu_chr_fe_init(&server->chr, chr, &error_abort);
560 qemu_chr_fe_set_handlers(&server->chr, chr_can_read, chr_read,
561 chr_event, NULL, server, server->context, true);
562 }
563
564 static void test_server_listen(TestServer *server)
565 {
566 test_server_create_chr(server, ",server,nowait");
567 }
568
569 static void test_server_free(TestServer *server)
570 {
571 int i, ret;
572
573 /* finish the helper thread and dispatch pending sources */
574 g_main_loop_quit(server->loop);
575 g_thread_join(server->thread);
576 while (g_main_context_pending(NULL)) {
577 g_main_context_iteration(NULL, TRUE);
578 }
579
580 unlink(server->socket_path);
581 g_free(server->socket_path);
582
583 unlink(server->mig_path);
584 g_free(server->mig_path);
585
586 ret = rmdir(server->tmpfs);
587 if (ret != 0) {
588 g_test_message("unable to rmdir: path (%s): %s",
589 server->tmpfs, strerror(errno));
590 }
591
592 qemu_chr_fe_deinit(&server->chr, true);
593
594 for (i = 0; i < server->fds_num; i++) {
595 close(server->fds[i]);
596 }
597
598 if (server->log_fd != -1) {
599 close(server->log_fd);
600 }
601
602 g_free(server->chr_name);
603 g_assert(server->bus);
604 qpci_free_pc(server->bus);
605
606 g_main_loop_unref(server->loop);
607 g_main_context_unref(server->context);
608 g_free(server);
609 }
610
611 static void wait_for_log_fd(TestServer *s)
612 {
613 gint64 end_time;
614
615 g_mutex_lock(&s->data_mutex);
616 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
617 while (s->log_fd == -1) {
618 if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
619 /* timeout has passed */
620 g_assert(s->log_fd != -1);
621 break;
622 }
623 }
624
625 g_mutex_unlock(&s->data_mutex);
626 }
627
628 static void write_guest_mem(TestServer *s, uint32_t seed)
629 {
630 uint32_t *guest_mem;
631 int i, j;
632 size_t size;
633
634 /* iterate all regions */
635 for (i = 0; i < s->fds_num; i++) {
636
637 /* We'll write only the region statring at 0x0 */
638 if (s->memory.regions[i].guest_phys_addr != 0x0) {
639 continue;
640 }
641
642 g_assert_cmpint(s->memory.regions[i].memory_size, >, 1024);
643
644 size = s->memory.regions[i].memory_size +
645 s->memory.regions[i].mmap_offset;
646
647 guest_mem = mmap(0, size, PROT_READ | PROT_WRITE,
648 MAP_SHARED, s->fds[i], 0);
649
650 g_assert(guest_mem != MAP_FAILED);
651 guest_mem += (s->memory.regions[i].mmap_offset / sizeof(*guest_mem));
652
653 for (j = 0; j < 256; j++) {
654 guest_mem[j] = seed + j;
655 }
656
657 munmap(guest_mem, s->memory.regions[i].memory_size);
658 break;
659 }
660 }
661
662 static guint64 get_log_size(TestServer *s)
663 {
664 guint64 log_size = 0;
665 int i;
666
667 for (i = 0; i < s->memory.nregions; ++i) {
668 VhostUserMemoryRegion *reg = &s->memory.regions[i];
669 guint64 last = range_get_last(reg->guest_phys_addr,
670 reg->memory_size);
671 log_size = MAX(log_size, last / (8 * VHOST_LOG_PAGE) + 1);
672 }
673
674 return log_size;
675 }
676
677 typedef struct TestMigrateSource {
678 GSource source;
679 TestServer *src;
680 TestServer *dest;
681 } TestMigrateSource;
682
683 static gboolean
684 test_migrate_source_check(GSource *source)
685 {
686 TestMigrateSource *t = (TestMigrateSource *)source;
687 gboolean overlap = t->src->rings && t->dest->rings;
688
689 g_assert(!overlap);
690
691 return FALSE;
692 }
693
694 GSourceFuncs test_migrate_source_funcs = {
695 .check = test_migrate_source_check,
696 };
697
698 static void test_read_guest_mem(const void *arg)
699 {
700 enum test_memfd memfd = GPOINTER_TO_INT(arg);
701 TestServer *server = NULL;
702 char *qemu_cmd = NULL;
703 QTestState *s = NULL;
704
705 server = test_server_new(memfd == TEST_MEMFD_YES ?
706 "read-guest-memfd" : "read-guest-mem");
707 test_server_listen(server);
708
709 qemu_cmd = get_qemu_cmd(server, 512, memfd, "", "");
710
711 s = qtest_start(qemu_cmd);
712 g_free(qemu_cmd);
713
714 init_virtio_dev(global_qtest, server, 1u << VIRTIO_NET_F_MAC);
715
716 if (!wait_for_fds(server)) {
717 goto exit;
718 }
719
720 read_guest_mem_server(global_qtest, server);
721
722 exit:
723 uninit_virtio_dev(server);
724
725 qtest_quit(s);
726 test_server_free(server);
727 }
728
729 static void test_migrate(void)
730 {
731 TestServer *s = test_server_new("src");
732 TestServer *dest = test_server_new("dest");
733 char *uri = g_strdup_printf("%s%s", "unix:", dest->mig_path);
734 QTestState *from, *to;
735 GSource *source;
736 gchar *cmd, *tmp;
737 QDict *rsp;
738 guint8 *log;
739 guint64 size;
740
741 test_server_listen(s);
742 test_server_listen(dest);
743
744 cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, "", "");
745 from = qtest_start(cmd);
746 g_free(cmd);
747
748 init_virtio_dev(from, s, 1u << VIRTIO_NET_F_MAC);
749 if (!wait_for_fds(s)) {
750 goto exit;
751 }
752
753 size = get_log_size(s);
754 g_assert_cmpint(size, ==, (2 * 1024 * 1024) / (VHOST_LOG_PAGE * 8));
755
756 tmp = g_strdup_printf(" -incoming %s", uri);
757 cmd = get_qemu_cmd(dest, 2, TEST_MEMFD_AUTO, "", tmp);
758 g_free(tmp);
759 to = qtest_init(cmd);
760 g_free(cmd);
761 init_virtio_dev(to, dest, 1u << VIRTIO_NET_F_MAC);
762
763 source = g_source_new(&test_migrate_source_funcs,
764 sizeof(TestMigrateSource));
765 ((TestMigrateSource *)source)->src = s;
766 ((TestMigrateSource *)source)->dest = dest;
767 g_source_attach(source, s->context);
768
769 /* slow down migration to have time to fiddle with log */
770 /* TODO: qtest could learn to break on some places */
771 rsp = qmp("{ 'execute': 'migrate_set_speed',"
772 "'arguments': { 'value': 10 } }");
773 g_assert(qdict_haskey(rsp, "return"));
774 qobject_unref(rsp);
775
776 rsp = qmp("{ 'execute': 'migrate', 'arguments': { 'uri': %s } }", uri);
777 g_assert(qdict_haskey(rsp, "return"));
778 qobject_unref(rsp);
779
780 wait_for_log_fd(s);
781
782 log = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, s->log_fd, 0);
783 g_assert(log != MAP_FAILED);
784
785 /* modify first page */
786 write_guest_mem(s, 0x42);
787 log[0] = 1;
788 munmap(log, size);
789
790 /* speed things up */
791 rsp = qmp("{ 'execute': 'migrate_set_speed',"
792 "'arguments': { 'value': 0 } }");
793 g_assert(qdict_haskey(rsp, "return"));
794 qobject_unref(rsp);
795
796 qmp_eventwait("STOP");
797 qtest_qmp_eventwait(to, "RESUME");
798
799 g_assert(wait_for_fds(dest));
800 read_guest_mem_server(to, dest);
801
802 uninit_virtio_dev(dest);
803 qtest_quit(to);
804
805 g_source_destroy(source);
806 g_source_unref(source);
807
808 exit:
809 uninit_virtio_dev(s);
810
811 test_server_free(dest);
812 qtest_quit(from);
813 test_server_free(s);
814 g_free(uri);
815 }
816
817 static void wait_for_rings_started(TestServer *s, size_t count)
818 {
819 gint64 end_time;
820
821 g_mutex_lock(&s->data_mutex);
822 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
823 while (ctpop64(s->rings) != count) {
824 if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
825 /* timeout has passed */
826 g_assert_cmpint(ctpop64(s->rings), ==, count);
827 break;
828 }
829 }
830
831 g_mutex_unlock(&s->data_mutex);
832 }
833
834 static inline void test_server_connect(TestServer *server)
835 {
836 test_server_create_chr(server, ",reconnect=1");
837 }
838
839 static gboolean
840 reconnect_cb(gpointer user_data)
841 {
842 TestServer *s = user_data;
843
844 qemu_chr_fe_disconnect(&s->chr);
845
846 return FALSE;
847 }
848
849 static gpointer
850 connect_thread(gpointer data)
851 {
852 TestServer *s = data;
853
854 /* wait for qemu to start before first try, to avoid extra warnings */
855 g_usleep(G_USEC_PER_SEC);
856 test_server_connect(s);
857
858 return NULL;
859 }
860
861 static void test_reconnect_subprocess(void)
862 {
863 TestServer *s = test_server_new("reconnect");
864 GSource *src;
865 char *cmd;
866
867 g_thread_new("connect", connect_thread, s);
868 cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, ",server", "");
869 qtest_start(cmd);
870 g_free(cmd);
871
872 init_virtio_dev(global_qtest, s, 1u << VIRTIO_NET_F_MAC);
873 if (!wait_for_fds(s)) {
874 goto exit;
875 }
876
877 wait_for_rings_started(s, 2);
878
879 /* reconnect */
880 s->fds_num = 0;
881 s->rings = 0;
882 src = g_idle_source_new();
883 g_source_set_callback(src, reconnect_cb, s, NULL);
884 g_source_attach(src, s->context);
885 g_source_unref(src);
886 g_assert(wait_for_fds(s));
887 wait_for_rings_started(s, 2);
888
889 exit:
890 uninit_virtio_dev(s);
891
892 qtest_end();
893 test_server_free(s);
894 return;
895 }
896
897 static void test_reconnect(void)
898 {
899 gchar *path = g_strdup_printf("/%s/vhost-user/reconnect/subprocess",
900 qtest_get_arch());
901 g_test_trap_subprocess(path, 0, 0);
902 g_test_trap_assert_passed();
903 g_free(path);
904 }
905
906 static void test_connect_fail_subprocess(void)
907 {
908 TestServer *s = test_server_new("connect-fail");
909 char *cmd;
910
911 s->test_fail = true;
912 g_thread_new("connect", connect_thread, s);
913 cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, ",server", "");
914 qtest_start(cmd);
915 g_free(cmd);
916
917 init_virtio_dev(global_qtest, s, 1u << VIRTIO_NET_F_MAC);
918 if (!wait_for_fds(s)) {
919 goto exit;
920 }
921 wait_for_rings_started(s, 2);
922
923 exit:
924 uninit_virtio_dev(s);
925
926 qtest_end();
927 test_server_free(s);
928 }
929
930 static void test_connect_fail(void)
931 {
932 gchar *path = g_strdup_printf("/%s/vhost-user/connect-fail/subprocess",
933 qtest_get_arch());
934 g_test_trap_subprocess(path, 0, 0);
935 g_test_trap_assert_passed();
936 g_free(path);
937 }
938
939 static void test_flags_mismatch_subprocess(void)
940 {
941 TestServer *s = test_server_new("flags-mismatch");
942 char *cmd;
943
944 s->test_flags = TEST_FLAGS_DISCONNECT;
945 g_thread_new("connect", connect_thread, s);
946 cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, ",server", "");
947 qtest_start(cmd);
948 g_free(cmd);
949
950 init_virtio_dev(global_qtest, s, 1u << VIRTIO_NET_F_MAC);
951 if (!wait_for_fds(s)) {
952 goto exit;
953 }
954 wait_for_rings_started(s, 2);
955
956 exit:
957 uninit_virtio_dev(s);
958
959 qtest_end();
960 test_server_free(s);
961 }
962
963 static void test_flags_mismatch(void)
964 {
965 gchar *path = g_strdup_printf("/%s/vhost-user/flags-mismatch/subprocess",
966 qtest_get_arch());
967 g_test_trap_subprocess(path, 0, 0);
968 g_test_trap_assert_passed();
969 g_free(path);
970 }
971
972
973 static void test_multiqueue(void)
974 {
975 TestServer *s = test_server_new("mq");
976 char *cmd;
977 uint32_t features_mask = ~(QVIRTIO_F_BAD_FEATURE |
978 (1u << VIRTIO_RING_F_INDIRECT_DESC) |
979 (1u << VIRTIO_RING_F_EVENT_IDX));
980 s->queues = 2;
981 test_server_listen(s);
982
983 if (qemu_memfd_check(0)) {
984 cmd = g_strdup_printf(
985 QEMU_CMD_MEMFD QEMU_CMD_CHR QEMU_CMD_NETDEV ",queues=%d "
986 "-device virtio-net-pci,netdev=net0,mq=on,vectors=%d",
987 512, 512, s->chr_name,
988 s->socket_path, "", s->chr_name,
989 s->queues, s->queues * 2 + 2);
990 } else {
991 cmd = g_strdup_printf(
992 QEMU_CMD_MEM QEMU_CMD_CHR QEMU_CMD_NETDEV ",queues=%d "
993 "-device virtio-net-pci,netdev=net0,mq=on,vectors=%d",
994 512, 512, s->mem_path, s->chr_name,
995 s->socket_path, "", s->chr_name,
996 s->queues, s->queues * 2 + 2);
997 }
998 qtest_start(cmd);
999 g_free(cmd);
1000
1001 init_virtio_dev(global_qtest, s, features_mask);
1002
1003 wait_for_rings_started(s, s->queues * 2);
1004
1005 uninit_virtio_dev(s);
1006
1007 qtest_end();
1008
1009 test_server_free(s);
1010 }
1011
1012 int main(int argc, char **argv)
1013 {
1014 g_test_init(&argc, &argv, NULL);
1015
1016 module_call_init(MODULE_INIT_QOM);
1017 qemu_add_opts(&qemu_chardev_opts);
1018
1019 if (qemu_memfd_check(0)) {
1020 qtest_add_data_func("/vhost-user/read-guest-mem/memfd",
1021 GINT_TO_POINTER(TEST_MEMFD_YES),
1022 test_read_guest_mem);
1023 }
1024 qtest_add_data_func("/vhost-user/read-guest-mem/memfile",
1025 GINT_TO_POINTER(TEST_MEMFD_NO), test_read_guest_mem);
1026 qtest_add_func("/vhost-user/migrate", test_migrate);
1027 qtest_add_func("/vhost-user/multiqueue", test_multiqueue);
1028
1029 /* keeps failing on build-system since Aug 15 2017 */
1030 if (getenv("QTEST_VHOST_USER_FIXME")) {
1031 qtest_add_func("/vhost-user/reconnect/subprocess",
1032 test_reconnect_subprocess);
1033 qtest_add_func("/vhost-user/reconnect", test_reconnect);
1034 qtest_add_func("/vhost-user/connect-fail/subprocess",
1035 test_connect_fail_subprocess);
1036 qtest_add_func("/vhost-user/connect-fail", test_connect_fail);
1037 qtest_add_func("/vhost-user/flags-mismatch/subprocess",
1038 test_flags_mismatch_subprocess);
1039 qtest_add_func("/vhost-user/flags-mismatch", test_flags_mismatch);
1040 }
1041
1042 return g_test_run();
1043 }