ui: correctly reset framebuffer update state after processing dirty regions
[qemu/ar7.git] / tests / vhost-user-test.c
blobe2c89ed376a3b8ac4983f17527a177b758fa78a4
1 /*
2 * QTest testcase for the vhost-user
4 * Copyright (c) 2014 Virtual Open Systems Sarl.
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.
9 */
11 #include "qemu/osdep.h"
13 #include "libqtest.h"
14 #include "qapi/error.h"
15 #include "qemu/config-file.h"
16 #include "qemu/option.h"
17 #include "qemu/range.h"
18 #include "qemu/sockets.h"
19 #include "chardev/char-fe.h"
20 #include "sysemu/sysemu.h"
21 #include "libqos/libqos.h"
22 #include "libqos/pci-pc.h"
23 #include "libqos/virtio-pci.h"
25 #include "libqos/malloc-pc.h"
26 #include "hw/virtio/virtio-net.h"
28 #include <linux/vhost.h>
29 #include <linux/virtio_ids.h>
30 #include <linux/virtio_net.h>
31 #include <sys/vfs.h>
33 #define VHOST_USER_NET_TESTS_WORKING 0 /* broken as of 2.10.0 */
35 /* GLIB version compatibility flags */
36 #if !GLIB_CHECK_VERSION(2, 26, 0)
37 #define G_TIME_SPAN_SECOND (G_GINT64_CONSTANT(1000000))
38 #endif
40 #if GLIB_CHECK_VERSION(2, 28, 0)
41 #define HAVE_MONOTONIC_TIME
42 #endif
44 #define QEMU_CMD_MEM " -m %d -object memory-backend-file,id=mem,size=%dM,"\
45 "mem-path=%s,share=on -numa node,memdev=mem"
46 #define QEMU_CMD_CHR " -chardev socket,id=%s,path=%s%s"
47 #define QEMU_CMD_NETDEV " -netdev vhost-user,id=net0,chardev=%s,vhostforce"
48 #define QEMU_CMD_NET " -device virtio-net-pci,netdev=net0"
50 #define QEMU_CMD QEMU_CMD_MEM QEMU_CMD_CHR \
51 QEMU_CMD_NETDEV QEMU_CMD_NET
53 #define HUGETLBFS_MAGIC 0x958458f6
55 /*********** FROM hw/virtio/vhost-user.c *************************************/
57 #define VHOST_MEMORY_MAX_NREGIONS 8
59 #define VHOST_USER_F_PROTOCOL_FEATURES 30
60 #define VHOST_USER_PROTOCOL_F_MQ 0
61 #define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1
63 #define VHOST_LOG_PAGE 0x1000
65 typedef enum VhostUserRequest {
66 VHOST_USER_NONE = 0,
67 VHOST_USER_GET_FEATURES = 1,
68 VHOST_USER_SET_FEATURES = 2,
69 VHOST_USER_SET_OWNER = 3,
70 VHOST_USER_RESET_OWNER = 4,
71 VHOST_USER_SET_MEM_TABLE = 5,
72 VHOST_USER_SET_LOG_BASE = 6,
73 VHOST_USER_SET_LOG_FD = 7,
74 VHOST_USER_SET_VRING_NUM = 8,
75 VHOST_USER_SET_VRING_ADDR = 9,
76 VHOST_USER_SET_VRING_BASE = 10,
77 VHOST_USER_GET_VRING_BASE = 11,
78 VHOST_USER_SET_VRING_KICK = 12,
79 VHOST_USER_SET_VRING_CALL = 13,
80 VHOST_USER_SET_VRING_ERR = 14,
81 VHOST_USER_GET_PROTOCOL_FEATURES = 15,
82 VHOST_USER_SET_PROTOCOL_FEATURES = 16,
83 VHOST_USER_GET_QUEUE_NUM = 17,
84 VHOST_USER_SET_VRING_ENABLE = 18,
85 VHOST_USER_MAX
86 } VhostUserRequest;
88 typedef struct VhostUserMemoryRegion {
89 uint64_t guest_phys_addr;
90 uint64_t memory_size;
91 uint64_t userspace_addr;
92 uint64_t mmap_offset;
93 } VhostUserMemoryRegion;
95 typedef struct VhostUserMemory {
96 uint32_t nregions;
97 uint32_t padding;
98 VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
99 } VhostUserMemory;
101 typedef struct VhostUserLog {
102 uint64_t mmap_size;
103 uint64_t mmap_offset;
104 } VhostUserLog;
106 typedef struct VhostUserMsg {
107 VhostUserRequest request;
109 #define VHOST_USER_VERSION_MASK (0x3)
110 #define VHOST_USER_REPLY_MASK (0x1<<2)
111 uint32_t flags;
112 uint32_t size; /* the following payload size */
113 union {
114 #define VHOST_USER_VRING_IDX_MASK (0xff)
115 #define VHOST_USER_VRING_NOFD_MASK (0x1<<8)
116 uint64_t u64;
117 struct vhost_vring_state state;
118 struct vhost_vring_addr addr;
119 VhostUserMemory memory;
120 VhostUserLog log;
121 } payload;
122 } QEMU_PACKED VhostUserMsg;
124 static VhostUserMsg m __attribute__ ((unused));
125 #define VHOST_USER_HDR_SIZE (sizeof(m.request) \
126 + sizeof(m.flags) \
127 + sizeof(m.size))
129 #define VHOST_USER_PAYLOAD_SIZE (sizeof(m) - VHOST_USER_HDR_SIZE)
131 /* The version of the protocol we support */
132 #define VHOST_USER_VERSION (0x1)
133 /*****************************************************************************/
135 enum {
136 TEST_FLAGS_OK,
137 TEST_FLAGS_DISCONNECT,
138 TEST_FLAGS_BAD,
139 TEST_FLAGS_END,
142 typedef struct TestServer {
143 QPCIBus *bus;
144 gchar *socket_path;
145 gchar *mig_path;
146 gchar *chr_name;
147 CharBackend chr;
148 int fds_num;
149 int fds[VHOST_MEMORY_MAX_NREGIONS];
150 VhostUserMemory memory;
151 CompatGMutex data_mutex;
152 CompatGCond data_cond;
153 int log_fd;
154 uint64_t rings;
155 bool test_fail;
156 int test_flags;
157 int queues;
158 } TestServer;
160 static const char *tmpfs;
161 static const char *root;
163 static void init_virtio_dev(TestServer *s)
165 QVirtioPCIDevice *dev;
166 uint32_t features;
168 s->bus = qpci_init_pc(NULL);
169 g_assert_nonnull(s->bus);
171 dev = qvirtio_pci_device_find(s->bus, VIRTIO_ID_NET);
172 g_assert_nonnull(dev);
174 qvirtio_pci_device_enable(dev);
175 qvirtio_reset(&dev->vdev);
176 qvirtio_set_acknowledge(&dev->vdev);
177 qvirtio_set_driver(&dev->vdev);
179 features = qvirtio_get_features(&dev->vdev);
180 features = features & VIRTIO_NET_F_MAC;
181 qvirtio_set_features(&dev->vdev, features);
183 qvirtio_set_driver_ok(&dev->vdev);
184 qvirtio_pci_device_free(dev);
187 static void wait_for_fds(TestServer *s)
189 gint64 end_time;
191 g_mutex_lock(&s->data_mutex);
193 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
194 while (!s->fds_num) {
195 if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
196 /* timeout has passed */
197 g_assert(s->fds_num);
198 break;
202 /* check for sanity */
203 g_assert_cmpint(s->fds_num, >, 0);
204 g_assert_cmpint(s->fds_num, ==, s->memory.nregions);
206 g_mutex_unlock(&s->data_mutex);
209 static void read_guest_mem(const void *data)
211 TestServer *s = (void *)data;
212 uint32_t *guest_mem;
213 int i, j;
214 size_t size;
216 wait_for_fds(s);
218 g_mutex_lock(&s->data_mutex);
220 /* iterate all regions */
221 for (i = 0; i < s->fds_num; i++) {
223 /* We'll check only the region statring at 0x0*/
224 if (s->memory.regions[i].guest_phys_addr != 0x0) {
225 continue;
228 g_assert_cmpint(s->memory.regions[i].memory_size, >, 1024);
230 size = s->memory.regions[i].memory_size +
231 s->memory.regions[i].mmap_offset;
233 guest_mem = mmap(0, size, PROT_READ | PROT_WRITE,
234 MAP_SHARED, s->fds[i], 0);
236 g_assert(guest_mem != MAP_FAILED);
237 guest_mem += (s->memory.regions[i].mmap_offset / sizeof(*guest_mem));
239 for (j = 0; j < 256; j++) {
240 uint32_t a = readl(s->memory.regions[i].guest_phys_addr + j*4);
241 uint32_t b = guest_mem[j];
243 g_assert_cmpint(a, ==, b);
246 munmap(guest_mem, s->memory.regions[i].memory_size);
249 g_mutex_unlock(&s->data_mutex);
252 static void *thread_function(void *data)
254 GMainLoop *loop = data;
255 g_main_loop_run(loop);
256 return NULL;
259 static int chr_can_read(void *opaque)
261 return VHOST_USER_HDR_SIZE;
264 static void chr_read(void *opaque, const uint8_t *buf, int size)
266 TestServer *s = opaque;
267 CharBackend *chr = &s->chr;
268 VhostUserMsg msg;
269 uint8_t *p = (uint8_t *) &msg;
270 int fd;
272 if (s->test_fail) {
273 qemu_chr_fe_disconnect(chr);
274 /* now switch to non-failure */
275 s->test_fail = false;
278 if (size != VHOST_USER_HDR_SIZE) {
279 g_test_message("Wrong message size received %d\n", size);
280 return;
283 g_mutex_lock(&s->data_mutex);
284 memcpy(p, buf, VHOST_USER_HDR_SIZE);
286 if (msg.size) {
287 p += VHOST_USER_HDR_SIZE;
288 size = qemu_chr_fe_read_all(chr, p, msg.size);
289 if (size != msg.size) {
290 g_test_message("Wrong message size received %d != %d\n",
291 size, msg.size);
292 return;
296 switch (msg.request) {
297 case VHOST_USER_GET_FEATURES:
298 /* send back features to qemu */
299 msg.flags |= VHOST_USER_REPLY_MASK;
300 msg.size = sizeof(m.payload.u64);
301 msg.payload.u64 = 0x1ULL << VHOST_F_LOG_ALL |
302 0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
303 if (s->queues > 1) {
304 msg.payload.u64 |= 0x1ULL << VIRTIO_NET_F_MQ;
306 if (s->test_flags >= TEST_FLAGS_BAD) {
307 msg.payload.u64 = 0;
308 s->test_flags = TEST_FLAGS_END;
310 p = (uint8_t *) &msg;
311 qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
312 break;
314 case VHOST_USER_SET_FEATURES:
315 g_assert_cmpint(msg.payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES),
316 !=, 0ULL);
317 if (s->test_flags == TEST_FLAGS_DISCONNECT) {
318 qemu_chr_fe_disconnect(chr);
319 s->test_flags = TEST_FLAGS_BAD;
321 break;
323 case VHOST_USER_GET_PROTOCOL_FEATURES:
324 /* send back features to qemu */
325 msg.flags |= VHOST_USER_REPLY_MASK;
326 msg.size = sizeof(m.payload.u64);
327 msg.payload.u64 = 1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD;
328 if (s->queues > 1) {
329 msg.payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_MQ;
331 p = (uint8_t *) &msg;
332 qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
333 break;
335 case VHOST_USER_GET_VRING_BASE:
336 /* send back vring base to qemu */
337 msg.flags |= VHOST_USER_REPLY_MASK;
338 msg.size = sizeof(m.payload.state);
339 msg.payload.state.num = 0;
340 p = (uint8_t *) &msg;
341 qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
343 assert(msg.payload.state.index < s->queues * 2);
344 s->rings &= ~(0x1ULL << msg.payload.state.index);
345 break;
347 case VHOST_USER_SET_MEM_TABLE:
348 /* received the mem table */
349 memcpy(&s->memory, &msg.payload.memory, sizeof(msg.payload.memory));
350 s->fds_num = qemu_chr_fe_get_msgfds(chr, s->fds,
351 G_N_ELEMENTS(s->fds));
353 /* signal the test that it can continue */
354 g_cond_signal(&s->data_cond);
355 break;
357 case VHOST_USER_SET_VRING_KICK:
358 case VHOST_USER_SET_VRING_CALL:
359 /* consume the fd */
360 qemu_chr_fe_get_msgfds(chr, &fd, 1);
362 * This is a non-blocking eventfd.
363 * The receive function forces it to be blocking,
364 * so revert it back to non-blocking.
366 qemu_set_nonblock(fd);
367 break;
369 case VHOST_USER_SET_LOG_BASE:
370 if (s->log_fd != -1) {
371 close(s->log_fd);
372 s->log_fd = -1;
374 qemu_chr_fe_get_msgfds(chr, &s->log_fd, 1);
375 msg.flags |= VHOST_USER_REPLY_MASK;
376 msg.size = 0;
377 p = (uint8_t *) &msg;
378 qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE);
380 g_cond_signal(&s->data_cond);
381 break;
383 case VHOST_USER_SET_VRING_BASE:
384 assert(msg.payload.state.index < s->queues * 2);
385 s->rings |= 0x1ULL << msg.payload.state.index;
386 break;
388 case VHOST_USER_GET_QUEUE_NUM:
389 msg.flags |= VHOST_USER_REPLY_MASK;
390 msg.size = sizeof(m.payload.u64);
391 msg.payload.u64 = s->queues;
392 p = (uint8_t *) &msg;
393 qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
394 break;
396 default:
397 break;
400 g_mutex_unlock(&s->data_mutex);
403 static const char *init_hugepagefs(const char *path)
405 struct statfs fs;
406 int ret;
408 if (access(path, R_OK | W_OK | X_OK)) {
409 g_test_message("access on path (%s): %s\n", path, strerror(errno));
410 return NULL;
413 do {
414 ret = statfs(path, &fs);
415 } while (ret != 0 && errno == EINTR);
417 if (ret != 0) {
418 g_test_message("statfs on path (%s): %s\n", path, strerror(errno));
419 return NULL;
422 if (fs.f_type != HUGETLBFS_MAGIC) {
423 g_test_message("Warning: path not on HugeTLBFS: %s\n", path);
424 return NULL;
427 return path;
430 static TestServer *test_server_new(const gchar *name)
432 TestServer *server = g_new0(TestServer, 1);
434 server->socket_path = g_strdup_printf("%s/%s.sock", tmpfs, name);
435 server->mig_path = g_strdup_printf("%s/%s.mig", tmpfs, name);
436 server->chr_name = g_strdup_printf("chr-%s", name);
438 g_mutex_init(&server->data_mutex);
439 g_cond_init(&server->data_cond);
441 server->log_fd = -1;
442 server->queues = 1;
444 return server;
447 static void chr_event(void *opaque, int event)
449 TestServer *s = opaque;
451 if (s->test_flags == TEST_FLAGS_END &&
452 event == CHR_EVENT_CLOSED) {
453 s->test_flags = TEST_FLAGS_OK;
457 static void test_server_create_chr(TestServer *server, const gchar *opt)
459 gchar *chr_path;
460 Chardev *chr;
462 chr_path = g_strdup_printf("unix:%s%s", server->socket_path, opt);
463 chr = qemu_chr_new(server->chr_name, chr_path);
464 g_free(chr_path);
466 qemu_chr_fe_init(&server->chr, chr, &error_abort);
467 qemu_chr_fe_set_handlers(&server->chr, chr_can_read, chr_read,
468 chr_event, NULL, server, NULL, true);
471 static void test_server_listen(TestServer *server)
473 test_server_create_chr(server, ",server,nowait");
476 #define GET_QEMU_CMD(s) \
477 g_strdup_printf(QEMU_CMD, 512, 512, (root), (s)->chr_name, \
478 (s)->socket_path, "", (s)->chr_name)
480 #define GET_QEMU_CMDE(s, mem, chr_opts, extra, ...) \
481 g_strdup_printf(QEMU_CMD extra, (mem), (mem), (root), (s)->chr_name, \
482 (s)->socket_path, (chr_opts), (s)->chr_name, ##__VA_ARGS__)
484 static gboolean _test_server_free(TestServer *server)
486 int i;
488 qemu_chr_fe_deinit(&server->chr, true);
490 for (i = 0; i < server->fds_num; i++) {
491 close(server->fds[i]);
494 if (server->log_fd != -1) {
495 close(server->log_fd);
498 unlink(server->socket_path);
499 g_free(server->socket_path);
501 unlink(server->mig_path);
502 g_free(server->mig_path);
504 g_free(server->chr_name);
505 qpci_free_pc(server->bus);
507 g_free(server);
509 return FALSE;
512 static void test_server_free(TestServer *server)
514 g_idle_add((GSourceFunc)_test_server_free, server);
517 static void wait_for_log_fd(TestServer *s)
519 gint64 end_time;
521 g_mutex_lock(&s->data_mutex);
522 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
523 while (s->log_fd == -1) {
524 if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
525 /* timeout has passed */
526 g_assert(s->log_fd != -1);
527 break;
531 g_mutex_unlock(&s->data_mutex);
534 static void write_guest_mem(TestServer *s, uint32_t seed)
536 uint32_t *guest_mem;
537 int i, j;
538 size_t size;
540 wait_for_fds(s);
542 /* iterate all regions */
543 for (i = 0; i < s->fds_num; i++) {
545 /* We'll write only the region statring at 0x0 */
546 if (s->memory.regions[i].guest_phys_addr != 0x0) {
547 continue;
550 g_assert_cmpint(s->memory.regions[i].memory_size, >, 1024);
552 size = s->memory.regions[i].memory_size +
553 s->memory.regions[i].mmap_offset;
555 guest_mem = mmap(0, size, PROT_READ | PROT_WRITE,
556 MAP_SHARED, s->fds[i], 0);
558 g_assert(guest_mem != MAP_FAILED);
559 guest_mem += (s->memory.regions[i].mmap_offset / sizeof(*guest_mem));
561 for (j = 0; j < 256; j++) {
562 guest_mem[j] = seed + j;
565 munmap(guest_mem, s->memory.regions[i].memory_size);
566 break;
570 static guint64 get_log_size(TestServer *s)
572 guint64 log_size = 0;
573 int i;
575 for (i = 0; i < s->memory.nregions; ++i) {
576 VhostUserMemoryRegion *reg = &s->memory.regions[i];
577 guint64 last = range_get_last(reg->guest_phys_addr,
578 reg->memory_size);
579 log_size = MAX(log_size, last / (8 * VHOST_LOG_PAGE) + 1);
582 return log_size;
585 typedef struct TestMigrateSource {
586 GSource source;
587 TestServer *src;
588 TestServer *dest;
589 } TestMigrateSource;
591 static gboolean
592 test_migrate_source_check(GSource *source)
594 TestMigrateSource *t = (TestMigrateSource *)source;
595 gboolean overlap = t->src->rings && t->dest->rings;
597 g_assert(!overlap);
599 return FALSE;
602 #if !GLIB_CHECK_VERSION(2,36,0)
603 /* this callback is unnecessary with glib >2.36, the default
604 * prepare for the source does the same */
605 static gboolean
606 test_migrate_source_prepare(GSource *source, gint *timeout)
608 *timeout = -1;
609 return FALSE;
611 #endif
613 GSourceFuncs test_migrate_source_funcs = {
614 #if !GLIB_CHECK_VERSION(2,36,0)
615 .prepare = test_migrate_source_prepare,
616 #endif
617 .check = test_migrate_source_check,
620 static void test_migrate(void)
622 TestServer *s = test_server_new("src");
623 TestServer *dest = test_server_new("dest");
624 char *uri = g_strdup_printf("%s%s", "unix:", dest->mig_path);
625 QTestState *global = global_qtest, *from, *to;
626 GSource *source;
627 gchar *cmd;
628 QDict *rsp;
629 guint8 *log;
630 guint64 size;
632 test_server_listen(s);
633 test_server_listen(dest);
635 cmd = GET_QEMU_CMDE(s, 2, "", "");
636 from = qtest_start(cmd);
637 g_free(cmd);
639 init_virtio_dev(s);
640 wait_for_fds(s);
641 size = get_log_size(s);
642 g_assert_cmpint(size, ==, (2 * 1024 * 1024) / (VHOST_LOG_PAGE * 8));
644 cmd = GET_QEMU_CMDE(dest, 2, "", " -incoming %s", uri);
645 to = qtest_init(cmd);
646 g_free(cmd);
648 source = g_source_new(&test_migrate_source_funcs,
649 sizeof(TestMigrateSource));
650 ((TestMigrateSource *)source)->src = s;
651 ((TestMigrateSource *)source)->dest = dest;
652 g_source_attach(source, NULL);
654 /* slow down migration to have time to fiddle with log */
655 /* TODO: qtest could learn to break on some places */
656 rsp = qmp("{ 'execute': 'migrate_set_speed',"
657 "'arguments': { 'value': 10 } }");
658 g_assert(qdict_haskey(rsp, "return"));
659 QDECREF(rsp);
661 cmd = g_strdup_printf("{ 'execute': 'migrate',"
662 "'arguments': { 'uri': '%s' } }",
663 uri);
664 rsp = qmp(cmd);
665 g_free(cmd);
666 g_assert(qdict_haskey(rsp, "return"));
667 QDECREF(rsp);
669 wait_for_log_fd(s);
671 log = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, s->log_fd, 0);
672 g_assert(log != MAP_FAILED);
674 /* modify first page */
675 write_guest_mem(s, 0x42);
676 log[0] = 1;
677 munmap(log, size);
679 /* speed things up */
680 rsp = qmp("{ 'execute': 'migrate_set_speed',"
681 "'arguments': { 'value': 0 } }");
682 g_assert(qdict_haskey(rsp, "return"));
683 QDECREF(rsp);
685 qmp_eventwait("STOP");
687 global_qtest = to;
688 qmp_eventwait("RESUME");
690 read_guest_mem(dest);
692 g_source_destroy(source);
693 g_source_unref(source);
695 qtest_quit(to);
696 test_server_free(dest);
697 qtest_quit(from);
698 test_server_free(s);
699 g_free(uri);
701 global_qtest = global;
704 static void wait_for_rings_started(TestServer *s, size_t count)
706 gint64 end_time;
708 g_mutex_lock(&s->data_mutex);
709 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
710 while (ctpop64(s->rings) != count) {
711 if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
712 /* timeout has passed */
713 g_assert_cmpint(ctpop64(s->rings), ==, count);
714 break;
718 g_mutex_unlock(&s->data_mutex);
721 #if VHOST_USER_NET_TESTS_WORKING && defined(CONFIG_HAS_GLIB_SUBPROCESS_TESTS)
722 static inline void test_server_connect(TestServer *server)
724 test_server_create_chr(server, ",reconnect=1");
727 static gboolean
728 reconnect_cb(gpointer user_data)
730 TestServer *s = user_data;
732 qemu_chr_fe_disconnect(&s->chr);
734 return FALSE;
737 static gpointer
738 connect_thread(gpointer data)
740 TestServer *s = data;
742 /* wait for qemu to start before first try, to avoid extra warnings */
743 g_usleep(G_USEC_PER_SEC);
744 test_server_connect(s);
746 return NULL;
749 static void test_reconnect_subprocess(void)
751 TestServer *s = test_server_new("reconnect");
752 char *cmd;
754 g_thread_new("connect", connect_thread, s);
755 cmd = GET_QEMU_CMDE(s, 2, ",server", "");
756 qtest_start(cmd);
757 g_free(cmd);
759 init_virtio_dev(s);
760 wait_for_fds(s);
761 wait_for_rings_started(s, 2);
763 /* reconnect */
764 s->fds_num = 0;
765 s->rings = 0;
766 g_idle_add(reconnect_cb, s);
767 wait_for_fds(s);
768 wait_for_rings_started(s, 2);
770 qtest_end();
771 test_server_free(s);
772 return;
775 static void test_reconnect(void)
777 gchar *path = g_strdup_printf("/%s/vhost-user/reconnect/subprocess",
778 qtest_get_arch());
779 g_test_trap_subprocess(path, 0, 0);
780 g_test_trap_assert_passed();
781 g_free(path);
784 static void test_connect_fail_subprocess(void)
786 TestServer *s = test_server_new("connect-fail");
787 char *cmd;
789 s->test_fail = true;
790 g_thread_new("connect", connect_thread, s);
791 cmd = GET_QEMU_CMDE(s, 2, ",server", "");
792 qtest_start(cmd);
793 g_free(cmd);
795 init_virtio_dev(s);
796 wait_for_fds(s);
797 wait_for_rings_started(s, 2);
799 qtest_end();
800 test_server_free(s);
803 static void test_connect_fail(void)
805 gchar *path = g_strdup_printf("/%s/vhost-user/connect-fail/subprocess",
806 qtest_get_arch());
807 g_test_trap_subprocess(path, 0, 0);
808 g_test_trap_assert_passed();
809 g_free(path);
812 static void test_flags_mismatch_subprocess(void)
814 TestServer *s = test_server_new("flags-mismatch");
815 char *cmd;
817 s->test_flags = TEST_FLAGS_DISCONNECT;
818 g_thread_new("connect", connect_thread, s);
819 cmd = GET_QEMU_CMDE(s, 2, ",server", "");
820 qtest_start(cmd);
821 g_free(cmd);
823 init_virtio_dev(s);
824 wait_for_fds(s);
825 wait_for_rings_started(s, 2);
827 qtest_end();
828 test_server_free(s);
831 static void test_flags_mismatch(void)
833 gchar *path = g_strdup_printf("/%s/vhost-user/flags-mismatch/subprocess",
834 qtest_get_arch());
835 g_test_trap_subprocess(path, 0, 0);
836 g_test_trap_assert_passed();
837 g_free(path);
840 #endif
842 static QVirtioPCIDevice *virtio_net_pci_init(QPCIBus *bus, int slot)
844 QVirtioPCIDevice *dev;
846 dev = qvirtio_pci_device_find(bus, VIRTIO_ID_NET);
847 g_assert(dev != NULL);
848 g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_NET);
850 qvirtio_pci_device_enable(dev);
851 qvirtio_reset(&dev->vdev);
852 qvirtio_set_acknowledge(&dev->vdev);
853 qvirtio_set_driver(&dev->vdev);
855 return dev;
858 static void driver_init(QVirtioDevice *dev)
860 uint32_t features;
862 features = qvirtio_get_features(dev);
863 features = features & ~(QVIRTIO_F_BAD_FEATURE |
864 (1u << VIRTIO_RING_F_INDIRECT_DESC) |
865 (1u << VIRTIO_RING_F_EVENT_IDX));
866 qvirtio_set_features(dev, features);
868 qvirtio_set_driver_ok(dev);
871 #define PCI_SLOT 0x04
873 static void test_multiqueue(void)
875 const int queues = 2;
876 TestServer *s = test_server_new("mq");
877 QVirtioPCIDevice *dev;
878 QPCIBus *bus;
879 QVirtQueuePCI *vq[queues * 2];
880 QGuestAllocator *alloc;
881 char *cmd;
882 int i;
884 s->queues = queues;
885 test_server_listen(s);
887 cmd = g_strdup_printf(QEMU_CMD_MEM QEMU_CMD_CHR QEMU_CMD_NETDEV ",queues=%d "
888 "-device virtio-net-pci,netdev=net0,mq=on,vectors=%d",
889 512, 512, root, s->chr_name,
890 s->socket_path, "", s->chr_name,
891 queues, queues * 2 + 2);
892 qtest_start(cmd);
893 g_free(cmd);
895 bus = qpci_init_pc(NULL);
896 dev = virtio_net_pci_init(bus, PCI_SLOT);
898 alloc = pc_alloc_init();
899 for (i = 0; i < queues * 2; i++) {
900 vq[i] = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, alloc, i);
903 driver_init(&dev->vdev);
904 wait_for_rings_started(s, queues * 2);
906 /* End test */
907 for (i = 0; i < queues * 2; i++) {
908 qvirtqueue_cleanup(dev->vdev.bus, &vq[i]->vq, alloc);
910 pc_alloc_uninit(alloc);
911 qvirtio_pci_device_disable(dev);
912 g_free(dev->pdev);
913 g_free(dev);
914 qpci_free_pc(bus);
915 qtest_end();
917 test_server_free(s);
920 int main(int argc, char **argv)
922 QTestState *s = NULL;
923 TestServer *server = NULL;
924 const char *hugefs;
925 char *qemu_cmd = NULL;
926 int ret;
927 char template[] = "/tmp/vhost-test-XXXXXX";
928 GMainLoop *loop;
929 GThread *thread;
931 g_test_init(&argc, &argv, NULL);
933 module_call_init(MODULE_INIT_QOM);
934 qemu_add_opts(&qemu_chardev_opts);
936 tmpfs = mkdtemp(template);
937 if (!tmpfs) {
938 g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno));
940 g_assert(tmpfs);
942 hugefs = getenv("QTEST_HUGETLBFS_PATH");
943 if (hugefs) {
944 root = init_hugepagefs(hugefs);
945 g_assert(root);
946 } else {
947 root = tmpfs;
950 server = test_server_new("test");
951 test_server_listen(server);
953 loop = g_main_loop_new(NULL, FALSE);
954 /* run the main loop thread so the chardev may operate */
955 thread = g_thread_new(NULL, thread_function, loop);
957 qemu_cmd = GET_QEMU_CMD(server);
959 s = qtest_start(qemu_cmd);
960 g_free(qemu_cmd);
961 init_virtio_dev(server);
963 qtest_add_data_func("/vhost-user/read-guest-mem", server, read_guest_mem);
964 qtest_add_func("/vhost-user/migrate", test_migrate);
965 qtest_add_func("/vhost-user/multiqueue", test_multiqueue);
967 #if VHOST_USER_NET_TESTS_WORKING && defined(CONFIG_HAS_GLIB_SUBPROCESS_TESTS)
968 qtest_add_func("/vhost-user/reconnect/subprocess",
969 test_reconnect_subprocess);
970 qtest_add_func("/vhost-user/reconnect", test_reconnect);
971 qtest_add_func("/vhost-user/connect-fail/subprocess",
972 test_connect_fail_subprocess);
973 qtest_add_func("/vhost-user/connect-fail", test_connect_fail);
974 qtest_add_func("/vhost-user/flags-mismatch/subprocess",
975 test_flags_mismatch_subprocess);
976 qtest_add_func("/vhost-user/flags-mismatch", test_flags_mismatch);
977 #endif
979 ret = g_test_run();
981 if (s) {
982 qtest_quit(s);
985 /* cleanup */
986 test_server_free(server);
988 /* finish the helper thread and dispatch pending sources */
989 g_main_loop_quit(loop);
990 g_thread_join(thread);
991 while (g_main_context_pending(NULL)) {
992 g_main_context_iteration (NULL, TRUE);
994 g_main_loop_unref(loop);
996 ret = rmdir(tmpfs);
997 if (ret != 0) {
998 g_test_message("unable to rmdir: path (%s): %s\n",
999 tmpfs, strerror(errno));
1001 g_assert_cmpint(ret, ==, 0);
1003 return ret;