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