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.
11 #include "qemu/osdep.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"
27 #include "libqos/malloc-pc.h"
28 #include "hw/virtio/virtio-net.h"
30 #include "standard-headers/linux/vhost_types.h"
31 #include "standard-headers/linux/virtio_ids.h"
32 #include "standard-headers/linux/virtio_net.h"
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"
46 #define HUGETLBFS_MAGIC 0x958458f6
48 /*********** FROM hw/virtio/vhost-user.c *************************************/
50 #define VHOST_MEMORY_MAX_NREGIONS 8
51 #define VHOST_MAX_VIRTQUEUES 0x100
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
58 #define VHOST_LOG_PAGE 0x1000
60 typedef enum VhostUserRequest
{
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,
83 typedef struct VhostUserMemoryRegion
{
84 uint64_t guest_phys_addr
;
86 uint64_t userspace_addr
;
88 } VhostUserMemoryRegion
;
90 typedef struct VhostUserMemory
{
93 VhostUserMemoryRegion regions
[VHOST_MEMORY_MAX_NREGIONS
];
96 typedef struct VhostUserLog
{
101 typedef struct VhostUserMsg
{
102 VhostUserRequest request
;
104 #define VHOST_USER_VERSION_MASK (0x3)
105 #define VHOST_USER_REPLY_MASK (0x1<<2)
107 uint32_t size
; /* the following payload size */
109 #define VHOST_USER_VRING_IDX_MASK (0xff)
110 #define VHOST_USER_VRING_NOFD_MASK (0x1<<8)
112 struct vhost_vring_state state
;
113 struct vhost_vring_addr addr
;
114 VhostUserMemory memory
;
117 } QEMU_PACKED VhostUserMsg
;
119 static VhostUserMsg m
__attribute__ ((unused
));
120 #define VHOST_USER_HDR_SIZE (sizeof(m.request) \
124 #define VHOST_USER_PAYLOAD_SIZE (sizeof(m) - VHOST_USER_HDR_SIZE)
126 /* The version of the protocol we support */
127 #define VHOST_USER_VERSION (0x1)
128 /*****************************************************************************/
132 TEST_FLAGS_DISCONNECT
,
137 typedef struct TestServer
{
144 int fds
[VHOST_MEMORY_MAX_NREGIONS
];
145 VhostUserMemory memory
;
146 GMainContext
*context
;
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
);
169 static void append_vhost_opts(TestServer
*s
, GString
*cmd_line
,
170 const char *chr_opts
)
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
);
177 static void append_mem_opts(TestServer
*server
, GString
*cmd_line
,
178 int size
, enum test_memfd memfd
)
180 if (memfd
== TEST_MEMFD_AUTO
) {
181 memfd
= qemu_memfd_check(MFD_ALLOW_SEALING
) ? TEST_MEMFD_YES
185 if (memfd
== TEST_MEMFD_YES
) {
186 g_string_append_printf(cmd_line
, QEMU_CMD_MEMFD
, size
, size
);
188 const char *root
= init_hugepagefs() ? : server
->tmpfs
;
190 g_string_append_printf(cmd_line
, QEMU_CMD_MEM
, size
, size
, root
);
194 static bool wait_for_fds(TestServer
*s
)
200 g_mutex_lock(&s
->data_mutex
);
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
);
211 /* check for sanity */
212 g_assert_cmpint(s
->fds_num
, >, 0);
213 g_assert_cmpint(s
->fds_num
, ==, s
->memory
.nregions
);
215 g_mutex_unlock(&s
->data_mutex
);
218 for (i
= 0; i
< s
->memory
.nregions
; ++i
) {
219 VhostUserMemoryRegion
*reg
= &s
->memory
.regions
[i
];
220 if (reg
->guest_phys_addr
== 0) {
226 g_test_skip("No memory at address 0x0");
231 static void read_guest_mem_server(QTestState
*qts
, TestServer
*s
)
237 g_mutex_lock(&s
->data_mutex
);
239 /* iterate all regions */
240 for (i
= 0; i
< s
->fds_num
; i
++) {
242 /* We'll check only the region statring at 0x0*/
243 if (s
->memory
.regions
[i
].guest_phys_addr
!= 0x0) {
247 g_assert_cmpint(s
->memory
.regions
[i
].memory_size
, >, 1024);
249 size
= s
->memory
.regions
[i
].memory_size
+
250 s
->memory
.regions
[i
].mmap_offset
;
252 guest_mem
= mmap(0, size
, PROT_READ
| PROT_WRITE
,
253 MAP_SHARED
, s
->fds
[i
], 0);
255 g_assert(guest_mem
!= MAP_FAILED
);
256 guest_mem
+= (s
->memory
.regions
[i
].mmap_offset
/ sizeof(*guest_mem
));
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
];
262 g_assert_cmpint(a
, ==, b
);
265 munmap(guest_mem
, s
->memory
.regions
[i
].memory_size
);
268 g_mutex_unlock(&s
->data_mutex
);
271 static void *thread_function(void *data
)
273 GMainLoop
*loop
= data
;
274 g_main_loop_run(loop
);
278 static int chr_can_read(void *opaque
)
280 return VHOST_USER_HDR_SIZE
;
283 static void chr_read(void *opaque
, const uint8_t *buf
, int size
)
285 TestServer
*s
= opaque
;
286 CharBackend
*chr
= &s
->chr
;
288 uint8_t *p
= (uint8_t *) &msg
;
292 qemu_chr_fe_disconnect(chr
);
293 /* now switch to non-failure */
294 s
->test_fail
= false;
297 if (size
!= VHOST_USER_HDR_SIZE
) {
298 g_test_message("Wrong message size received %d", size
);
302 g_mutex_lock(&s
->data_mutex
);
303 memcpy(p
, buf
, VHOST_USER_HDR_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",
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
;
323 msg
.payload
.u64
|= 0x1ULL
<< VIRTIO_NET_F_MQ
;
325 if (s
->test_flags
>= TEST_FLAGS_BAD
) {
327 s
->test_flags
= TEST_FLAGS_END
;
329 p
= (uint8_t *) &msg
;
330 qemu_chr_fe_write_all(chr
, p
, VHOST_USER_HDR_SIZE
+ msg
.size
);
333 case VHOST_USER_SET_FEATURES
:
334 g_assert_cmpint(msg
.payload
.u64
& (0x1ULL
<< VHOST_USER_F_PROTOCOL_FEATURES
),
336 if (s
->test_flags
== TEST_FLAGS_DISCONNECT
) {
337 qemu_chr_fe_disconnect(chr
);
338 s
->test_flags
= TEST_FLAGS_BAD
;
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
;
349 msg
.payload
.u64
|= 1 << VHOST_USER_PROTOCOL_F_MQ
;
351 p
= (uint8_t *) &msg
;
352 qemu_chr_fe_write_all(chr
, p
, VHOST_USER_HDR_SIZE
+ msg
.size
);
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
);
363 assert(msg
.payload
.state
.index
< s
->queues
* 2);
364 s
->rings
&= ~(0x1ULL
<< msg
.payload
.state
.index
);
365 g_cond_broadcast(&s
->data_cond
);
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
));
374 /* signal the test that it can continue */
375 g_cond_broadcast(&s
->data_cond
);
378 case VHOST_USER_SET_VRING_KICK
:
379 case VHOST_USER_SET_VRING_CALL
:
381 qemu_chr_fe_get_msgfds(chr
, &fd
, 1);
383 * This is a non-blocking eventfd.
384 * The receive function forces it to be blocking,
385 * so revert it back to non-blocking.
387 qemu_set_nonblock(fd
);
390 case VHOST_USER_SET_LOG_BASE
:
391 if (s
->log_fd
!= -1) {
395 qemu_chr_fe_get_msgfds(chr
, &s
->log_fd
, 1);
396 msg
.flags
|= VHOST_USER_REPLY_MASK
;
398 p
= (uint8_t *) &msg
;
399 qemu_chr_fe_write_all(chr
, p
, VHOST_USER_HDR_SIZE
);
401 g_cond_broadcast(&s
->data_cond
);
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
);
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
);
422 g_mutex_unlock(&s
->data_mutex
);
425 static const char *init_hugepagefs(void)
428 static const char *hugepagefs
;
429 const char *path
= getenv("QTEST_HUGETLBFS_PATH");
440 if (access(path
, R_OK
| W_OK
| X_OK
)) {
441 g_test_message("access on path (%s): %s", path
, strerror(errno
));
447 ret
= statfs(path
, &fs
);
448 } while (ret
!= 0 && errno
== EINTR
);
451 g_test_message("statfs on path (%s): %s", path
, strerror(errno
));
456 if (fs
.f_type
!= HUGETLBFS_MAGIC
) {
457 g_test_message("Warning: path not on HugeTLBFS: %s", path
);
469 static TestServer
*test_server_new(const gchar
*name
)
471 TestServer
*server
= g_new0(TestServer
, 1);
472 char template[] = "/tmp/vhost-test-XXXXXX";
475 server
->context
= g_main_context_new();
476 server
->loop
= g_main_loop_new(server
->context
, FALSE
);
478 /* run the main loop thread so the chardev may operate */
479 server
->thread
= g_thread_new(NULL
, thread_function
, server
->loop
);
481 tmpfs
= mkdtemp(template);
483 g_test_message("mkdtemp on path (%s): %s", template, strerror(errno
));
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
);
492 g_mutex_init(&server
->data_mutex
);
493 g_cond_init(&server
->data_cond
);
501 static void chr_event(void *opaque
, int event
)
503 TestServer
*s
= opaque
;
505 if (s
->test_flags
== TEST_FLAGS_END
&&
506 event
== CHR_EVENT_CLOSED
) {
507 s
->test_flags
= TEST_FLAGS_OK
;
511 static void test_server_create_chr(TestServer
*server
, const gchar
*opt
)
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
);
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);
526 static void test_server_listen(TestServer
*server
)
528 test_server_create_chr(server
, ",server,nowait");
531 static void test_server_free(TestServer
*server
)
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
);
542 unlink(server
->socket_path
);
543 g_free(server
->socket_path
);
545 unlink(server
->mig_path
);
546 g_free(server
->mig_path
);
548 ret
= rmdir(server
->tmpfs
);
550 g_test_message("unable to rmdir: path (%s): %s",
551 server
->tmpfs
, strerror(errno
));
553 g_free(server
->tmpfs
);
555 qemu_chr_fe_deinit(&server
->chr
, true);
557 for (i
= 0; i
< server
->fds_num
; i
++) {
558 close(server
->fds
[i
]);
561 if (server
->log_fd
!= -1) {
562 close(server
->log_fd
);
565 g_free(server
->chr_name
);
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
);
574 static void wait_for_log_fd(TestServer
*s
)
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);
588 g_mutex_unlock(&s
->data_mutex
);
591 static void write_guest_mem(TestServer
*s
, uint32_t seed
)
597 /* iterate all regions */
598 for (i
= 0; i
< s
->fds_num
; i
++) {
600 /* We'll write only the region statring at 0x0 */
601 if (s
->memory
.regions
[i
].guest_phys_addr
!= 0x0) {
605 g_assert_cmpint(s
->memory
.regions
[i
].memory_size
, >, 1024);
607 size
= s
->memory
.regions
[i
].memory_size
+
608 s
->memory
.regions
[i
].mmap_offset
;
610 guest_mem
= mmap(0, size
, PROT_READ
| PROT_WRITE
,
611 MAP_SHARED
, s
->fds
[i
], 0);
613 g_assert(guest_mem
!= MAP_FAILED
);
614 guest_mem
+= (s
->memory
.regions
[i
].mmap_offset
/ sizeof(*guest_mem
));
616 for (j
= 0; j
< 256; j
++) {
617 guest_mem
[j
] = seed
+ j
;
620 munmap(guest_mem
, s
->memory
.regions
[i
].memory_size
);
625 static guint64
get_log_size(TestServer
*s
)
627 guint64 log_size
= 0;
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
,
634 log_size
= MAX(log_size
, last
/ (8 * VHOST_LOG_PAGE
) + 1);
640 typedef struct TestMigrateSource
{
647 test_migrate_source_check(GSource
*source
)
649 TestMigrateSource
*t
= (TestMigrateSource
*)source
;
650 gboolean overlap
= t
->src
->rings
&& t
->dest
->rings
;
657 GSourceFuncs test_migrate_source_funcs
= {
658 .check
= test_migrate_source_check
,
661 static void vhost_user_test_cleanup(void *s
)
663 TestServer
*server
= s
;
665 qos_invalidate_command_line();
666 test_server_free(server
);
669 static void *vhost_user_test_setup(GString
*cmd_line
, void *arg
)
671 TestServer
*server
= test_server_new("vhost-user-test");
672 test_server_listen(server
);
674 append_mem_opts(server
, cmd_line
, 256, TEST_MEMFD_AUTO
);
675 append_vhost_opts(server
, cmd_line
, "");
677 g_test_queue_destroy(vhost_user_test_cleanup
, server
);
682 static void *vhost_user_test_setup_memfd(GString
*cmd_line
, void *arg
)
684 TestServer
*server
= test_server_new("vhost-user-test");
685 test_server_listen(server
);
687 append_mem_opts(server
, cmd_line
, 256, TEST_MEMFD_YES
);
688 append_vhost_opts(server
, cmd_line
, "");
690 g_test_queue_destroy(vhost_user_test_cleanup
, server
);
695 static void test_read_guest_mem(void *obj
, void *arg
, QGuestAllocator
*alloc
)
697 TestServer
*server
= arg
;
699 if (!wait_for_fds(server
)) {
703 read_guest_mem_server(global_qtest
, server
);
706 static void test_migrate(void *obj
, void *arg
, QGuestAllocator
*alloc
)
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
);
718 if (!wait_for_fds(s
)) {
722 size
= get_log_size(s
);
723 g_assert_cmpint(size
, ==, (256 * 1024 * 1024) / (VHOST_LOG_PAGE
* 8));
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
);
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.
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
);
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"));
748 rsp
= qmp("{ 'execute': 'migrate', 'arguments': { 'uri': %s } }", uri
);
749 g_assert(qdict_haskey(rsp
, "return"));
754 log
= mmap(0, size
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, s
->log_fd
, 0);
755 g_assert(log
!= MAP_FAILED
);
757 /* modify first page */
758 write_guest_mem(s
, 0x42);
762 /* speed things up */
763 rsp
= qmp("{ 'execute': 'migrate_set_speed',"
764 "'arguments': { 'value': 0 } }");
765 g_assert(qdict_haskey(rsp
, "return"));
768 qmp_eventwait("STOP");
769 qtest_qmp_eventwait(to
, "RESUME");
771 g_assert(wait_for_fds(dest
));
772 read_guest_mem_server(to
, dest
);
774 g_source_destroy(source
);
775 g_source_unref(source
);
778 test_server_free(dest
);
782 static void wait_for_rings_started(TestServer
*s
, size_t count
)
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
);
796 g_mutex_unlock(&s
->data_mutex
);
799 static inline void test_server_connect(TestServer
*server
)
801 test_server_create_chr(server
, ",reconnect=1");
805 reconnect_cb(gpointer user_data
)
807 TestServer
*s
= user_data
;
809 qemu_chr_fe_disconnect(&s
->chr
);
815 connect_thread(gpointer data
)
817 TestServer
*s
= data
;
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
);
826 static void *vhost_user_test_setup_reconnect(GString
*cmd_line
, void *arg
)
828 TestServer
*s
= test_server_new("reconnect");
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");
834 g_test_queue_destroy(vhost_user_test_cleanup
, s
);
839 static void test_reconnect(void *obj
, void *arg
, QGuestAllocator
*alloc
)
844 if (!wait_for_fds(s
)) {
848 wait_for_rings_started(s
, 2);
853 src
= g_idle_source_new();
854 g_source_set_callback(src
, reconnect_cb
, s
, NULL
);
855 g_source_attach(src
, s
->context
);
857 g_assert(wait_for_fds(s
));
858 wait_for_rings_started(s
, 2);
861 static void *vhost_user_test_setup_connect_fail(GString
*cmd_line
, void *arg
)
863 TestServer
*s
= test_server_new("connect-fail");
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");
871 g_test_queue_destroy(vhost_user_test_cleanup
, s
);
876 static void *vhost_user_test_setup_flags_mismatch(GString
*cmd_line
, void *arg
)
878 TestServer
*s
= test_server_new("flags-mismatch");
880 s
->test_flags
= TEST_FLAGS_DISCONNECT
;
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");
886 g_test_queue_destroy(vhost_user_test_cleanup
, s
);
891 static void test_vhost_user_started(void *obj
, void *arg
, QGuestAllocator
*alloc
)
895 if (!wait_for_fds(s
)) {
898 wait_for_rings_started(s
, 2);
901 static void *vhost_user_test_setup_multiqueue(GString
*cmd_line
, void *arg
)
903 TestServer
*s
= vhost_user_test_setup(cmd_line
, arg
);
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);
914 static void test_multiqueue(void *obj
, void *arg
, QGuestAllocator
*alloc
)
918 wait_for_rings_started(s
, s
->queues
* 2);
921 static void register_vhost_user_test(void)
923 QOSGraphTestOptions opts
= {
924 .before
= vhost_user_test_setup
,
928 qemu_add_opts(&qemu_chardev_opts
);
930 qos_add_test("vhost-user/read-guest-mem/memfile",
932 test_read_guest_mem
, &opts
);
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",
938 test_read_guest_mem
, &opts
);
941 qos_add_test("vhost-user/migrate",
943 test_migrate
, &opts
);
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
);
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
);
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
);
960 opts
.before
= vhost_user_test_setup_multiqueue
;
961 opts
.edge
.extra_device_opts
= "mq=on";
962 qos_add_test("vhost-user/multiqueue",
964 test_multiqueue
, &opts
);
966 libqos_init(register_vhost_user_test
);