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