]> Git Repo - qemu.git/blob - tests/vhost-user-test.c
char: allow specifying a GMainContext at opening time
[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, NULL);
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 }
This page took 0.082733 seconds and 4 git commands to generate.