]> git.proxmox.com Git - mirror_qemu.git/blame - tests/vhost-user-test.c
tests/tcg: target/mips: Add tests for MSA logic instructions
[mirror_qemu.git] / tests / vhost-user-test.c
CommitLineData
a77e6b14
NN
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
681c28a3 11#include "qemu/osdep.h"
bd95939f 12
a77e6b14 13#include "libqtest.h"
5345fdb4 14#include "qapi/error.h"
452fcdbc 15#include "qapi/qmp/qdict.h"
213dcb06 16#include "qemu/config-file.h"
a77e6b14 17#include "qemu/option.h"
b1819747 18#include "qemu/range.h"
a9c94277 19#include "qemu/sockets.h"
4d43a603 20#include "chardev/char-fe.h"
8e029fd6 21#include "qemu/memfd.h"
a77e6b14 22#include "sysemu/sysemu.h"
cdafe929
EH
23#include "libqos/libqos.h"
24#include "libqos/pci-pc.h"
25#include "libqos/virtio-pci.h"
a77e6b14 26
ed0a8d92
MAL
27#include "libqos/malloc-pc.h"
28#include "hw/virtio/virtio-net.h"
29
a77e6b14 30#include <linux/vhost.h>
cdafe929
EH
31#include <linux/virtio_ids.h>
32#include <linux/virtio_net.h>
a77e6b14 33#include <sys/vfs.h>
a77e6b14 34
30de46db 35
8e029fd6 36#define QEMU_CMD_MEM " -m %d -object memory-backend-file,id=mem,size=%dM," \
a77e6b14 37 "mem-path=%s,share=on -numa node,memdev=mem"
8e029fd6
MAL
38#define QEMU_CMD_MEMFD " -m %d -object memory-backend-memfd,id=mem,size=%dM," \
39 " -numa node,memdev=mem"
4616e359 40#define QEMU_CMD_CHR " -chardev socket,id=%s,path=%s%s"
704b2168 41#define QEMU_CMD_NETDEV " -netdev vhost-user,id=net0,chardev=%s,vhostforce"
cdafe929 42#define QEMU_CMD_NET " -device virtio-net-pci,netdev=net0"
a77e6b14 43
a77e6b14
NN
44#define HUGETLBFS_MAGIC 0x958458f6
45
46/*********** FROM hw/virtio/vhost-user.c *************************************/
47
48#define VHOST_MEMORY_MAX_NREGIONS 8
026eb179 49#define VHOST_MAX_VIRTQUEUES 0x100
a77e6b14 50
8a9b6b37 51#define VHOST_USER_F_PROTOCOL_FEATURES 30
ed0a8d92 52#define VHOST_USER_PROTOCOL_F_MQ 0
b1819747 53#define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1
5a583cc5 54#define VHOST_USER_PROTOCOL_F_CROSS_ENDIAN 6
b1819747
MAL
55
56#define VHOST_LOG_PAGE 0x1000
8a9b6b37 57
a77e6b14
NN
58typedef 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,
60915dc4 63 VHOST_USER_RESET_OWNER = 4,
a77e6b14
NN
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,
8a9b6b37
MT
74 VHOST_USER_GET_PROTOCOL_FEATURES = 15,
75 VHOST_USER_SET_PROTOCOL_FEATURES = 16,
ed0a8d92 76 VHOST_USER_GET_QUEUE_NUM = 17,
87656d50 77 VHOST_USER_SET_VRING_ENABLE = 18,
a77e6b14
NN
78 VHOST_USER_MAX
79} VhostUserRequest;
80
81typedef struct VhostUserMemoryRegion {
82 uint64_t guest_phys_addr;
83 uint64_t memory_size;
84 uint64_t userspace_addr;
d6970e3b 85 uint64_t mmap_offset;
a77e6b14
NN
86} VhostUserMemoryRegion;
87
88typedef struct VhostUserMemory {
89 uint32_t nregions;
90 uint32_t padding;
91 VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
92} VhostUserMemory;
93
2b8819c6
VK
94typedef struct VhostUserLog {
95 uint64_t mmap_size;
96 uint64_t mmap_offset;
97} VhostUserLog;
98
a77e6b14
NN
99typedef 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 {
2b8819c6
VK
107#define VHOST_USER_VRING_IDX_MASK (0xff)
108#define VHOST_USER_VRING_NOFD_MASK (0x1<<8)
a77e6b14
NN
109 uint64_t u64;
110 struct vhost_vring_state state;
111 struct vhost_vring_addr addr;
112 VhostUserMemory memory;
2b8819c6 113 VhostUserLog log;
12ebf690 114 } payload;
a77e6b14
NN
115} QEMU_PACKED VhostUserMsg;
116
117static 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
9294d76c
MAL
128enum {
129 TEST_FLAGS_OK,
130 TEST_FLAGS_DISCONNECT,
131 TEST_FLAGS_BAD,
132 TEST_FLAGS_END,
133};
134
ae31fb54 135typedef struct TestServer {
0c0eb302 136 QPCIBus *bus;
026eb179
MC
137 QVirtioPCIDevice *dev;
138 QVirtQueue *vq[VHOST_MAX_VIRTQUEUES];
ae31fb54 139 gchar *socket_path;
a899b1ea 140 gchar *mig_path;
ae31fb54 141 gchar *chr_name;
32a6ebec 142 CharBackend chr;
ae31fb54
MAL
143 int fds_num;
144 int fds[VHOST_MEMORY_MAX_NREGIONS];
145 VhostUserMemory memory;
e7b3af81
DB
146 GMutex data_mutex;
147 GCond data_cond;
b1819747 148 int log_fd;
d08e42a1 149 uint64_t rings;
5d443f5a 150 bool test_fail;
9294d76c 151 int test_flags;
ed0a8d92 152 int queues;
026eb179 153 QGuestAllocator *alloc;
ae31fb54 154} TestServer;
bd95939f 155
83265145
MAL
156static TestServer *test_server_new(const gchar *name);
157static void test_server_free(TestServer *server);
158static void test_server_listen(TestServer *server);
159
704b2168
MAL
160static const char *tmpfs;
161static const char *root;
162
8e029fd6
MAL
163enum test_memfd {
164 TEST_MEMFD_AUTO,
165 TEST_MEMFD_YES,
166 TEST_MEMFD_NO,
167};
168
169static 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{
38296400 173 if (memfd == TEST_MEMFD_AUTO && qemu_memfd_check(0)) {
8e029fd6
MAL
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
bae6b59d 190static void init_virtio_dev(QTestState *qts, TestServer *s, uint32_t features_mask)
cdafe929 191{
cdafe929 192 uint32_t features;
026eb179 193 int i;
cdafe929 194
bae6b59d 195 s->bus = qpci_init_pc(qts, NULL);
0c0eb302 196 g_assert_nonnull(s->bus);
cdafe929 197
026eb179
MC
198 s->dev = qvirtio_pci_device_find(s->bus, VIRTIO_ID_NET);
199 g_assert_nonnull(s->dev);
cdafe929 200
026eb179
MC
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);
cdafe929 205
bae6b59d 206 s->alloc = pc_alloc_init(qts);
026eb179
MC
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);
d3b2a5d1 213 features = features & features_mask;
026eb179
MC
214 qvirtio_set_features(&s->dev->vdev, features);
215
216 qvirtio_set_driver_ok(&s->dev->vdev);
217}
218
219static void uninit_virtio_dev(TestServer *s)
220{
221 int i;
cdafe929 222
026eb179
MC
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);
cdafe929
EH
229}
230
3b72ca38 231static bool wait_for_fds(TestServer *s)
a77e6b14 232{
a77e6b14 233 gint64 end_time;
3b72ca38
PB
234 bool got_region;
235 int i;
a77e6b14 236
ae31fb54 237 g_mutex_lock(&s->data_mutex);
a77e6b14 238
ca06d9cc 239 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
ae31fb54
MAL
240 while (!s->fds_num) {
241 if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
a77e6b14 242 /* timeout has passed */
ae31fb54 243 g_assert(s->fds_num);
a77e6b14
NN
244 break;
245 }
246 }
247
248 /* check for sanity */
ae31fb54
MAL
249 g_assert_cmpint(s->fds_num, >, 0);
250 g_assert_cmpint(s->fds_num, ==, s->memory.nregions);
a77e6b14 251
ae31fb54 252 g_mutex_unlock(&s->data_mutex);
3b72ca38
PB
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;
cf72b57f
MAL
266}
267
bae6b59d 268static void read_guest_mem_server(QTestState *qts, TestServer *s)
cf72b57f 269{
5a583cc5 270 uint8_t *guest_mem;
cf72b57f
MAL
271 int i, j;
272 size_t size;
273
ae31fb54 274 g_mutex_lock(&s->data_mutex);
cf72b57f 275
a77e6b14 276 /* iterate all regions */
ae31fb54 277 for (i = 0; i < s->fds_num; i++) {
a77e6b14
NN
278
279 /* We'll check only the region statring at 0x0*/
ae31fb54 280 if (s->memory.regions[i].guest_phys_addr != 0x0) {
a77e6b14
NN
281 continue;
282 }
283
ae31fb54 284 g_assert_cmpint(s->memory.regions[i].memory_size, >, 1024);
a77e6b14 285
ae31fb54
MAL
286 size = s->memory.regions[i].memory_size +
287 s->memory.regions[i].mmap_offset;
d6970e3b
NN
288
289 guest_mem = mmap(0, size, PROT_READ | PROT_WRITE,
ae31fb54 290 MAP_SHARED, s->fds[i], 0);
d6970e3b
NN
291
292 g_assert(guest_mem != MAP_FAILED);
ae31fb54 293 guest_mem += (s->memory.regions[i].mmap_offset / sizeof(*guest_mem));
a77e6b14 294
5a583cc5 295 for (j = 0; j < 1024; j++) {
bae6b59d 296 uint32_t a = qtest_readb(qts, s->memory.regions[i].guest_phys_addr + j);
a77e6b14
NN
297 uint32_t b = guest_mem[j];
298
299 g_assert_cmpint(a, ==, b);
300 }
301
ae31fb54 302 munmap(guest_mem, s->memory.regions[i].memory_size);
a77e6b14
NN
303 }
304
ae31fb54 305 g_mutex_unlock(&s->data_mutex);
a77e6b14
NN
306}
307
308static void *thread_function(void *data)
309{
9732baf6 310 GMainLoop *loop = data;
a77e6b14
NN
311 g_main_loop_run(loop);
312 return NULL;
313}
314
315static int chr_can_read(void *opaque)
316{
317 return VHOST_USER_HDR_SIZE;
318}
319
320static void chr_read(void *opaque, const uint8_t *buf, int size)
321{
ae31fb54 322 TestServer *s = opaque;
32a6ebec 323 CharBackend *chr = &s->chr;
a77e6b14
NN
324 VhostUserMsg msg;
325 uint8_t *p = (uint8_t *) &msg;
82248cd4 326 int fd = -1;
a77e6b14 327
5d443f5a 328 if (s->test_fail) {
5345fdb4 329 qemu_chr_fe_disconnect(chr);
5d443f5a
MAL
330 /* now switch to non-failure */
331 s->test_fail = false;
332 }
333
a77e6b14
NN
334 if (size != VHOST_USER_HDR_SIZE) {
335 g_test_message("Wrong message size received %d\n", size);
336 return;
337 }
338
ae31fb54 339 g_mutex_lock(&s->data_mutex);
a77e6b14
NN
340 memcpy(p, buf, VHOST_USER_HDR_SIZE);
341
342 if (msg.size) {
343 p += VHOST_USER_HDR_SIZE;
5345fdb4 344 size = qemu_chr_fe_read_all(chr, p, msg.size);
4616e359
MAL
345 if (size != msg.size) {
346 g_test_message("Wrong message size received %d != %d\n",
347 size, msg.size);
348 return;
349 }
a77e6b14
NN
350 }
351
352 switch (msg.request) {
353 case VHOST_USER_GET_FEATURES:
8a9b6b37
MT
354 /* send back features to qemu */
355 msg.flags |= VHOST_USER_REPLY_MASK;
12ebf690
MT
356 msg.size = sizeof(m.payload.u64);
357 msg.payload.u64 = 0x1ULL << VHOST_F_LOG_ALL |
b1819747 358 0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
ed0a8d92
MAL
359 if (s->queues > 1) {
360 msg.payload.u64 |= 0x1ULL << VIRTIO_NET_F_MQ;
361 }
9294d76c
MAL
362 if (s->test_flags >= TEST_FLAGS_BAD) {
363 msg.payload.u64 = 0;
364 s->test_flags = TEST_FLAGS_END;
365 }
8a9b6b37 366 p = (uint8_t *) &msg;
5345fdb4 367 qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
8a9b6b37
MT
368 break;
369
370 case VHOST_USER_SET_FEATURES:
7d37435b
PB
371 g_assert_cmpint(msg.payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES),
372 !=, 0ULL);
9294d76c 373 if (s->test_flags == TEST_FLAGS_DISCONNECT) {
5345fdb4 374 qemu_chr_fe_disconnect(chr);
9294d76c
MAL
375 s->test_flags = TEST_FLAGS_BAD;
376 }
8a9b6b37
MT
377 break;
378
379 case VHOST_USER_GET_PROTOCOL_FEATURES:
a77e6b14
NN
380 /* send back features to qemu */
381 msg.flags |= VHOST_USER_REPLY_MASK;
12ebf690
MT
382 msg.size = sizeof(m.payload.u64);
383 msg.payload.u64 = 1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD;
5a583cc5 384 msg.payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_CROSS_ENDIAN;
ed0a8d92
MAL
385 if (s->queues > 1) {
386 msg.payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_MQ;
387 }
a77e6b14 388 p = (uint8_t *) &msg;
5345fdb4 389 qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
a77e6b14
NN
390 break;
391
392 case VHOST_USER_GET_VRING_BASE:
393 /* send back vring base to qemu */
394 msg.flags |= VHOST_USER_REPLY_MASK;
12ebf690
MT
395 msg.size = sizeof(m.payload.state);
396 msg.payload.state.num = 0;
a77e6b14 397 p = (uint8_t *) &msg;
5345fdb4 398 qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
d08e42a1 399
ed0a8d92 400 assert(msg.payload.state.index < s->queues * 2);
d08e42a1 401 s->rings &= ~(0x1ULL << msg.payload.state.index);
acca950c 402 g_cond_broadcast(&s->data_cond);
a77e6b14
NN
403 break;
404
405 case VHOST_USER_SET_MEM_TABLE:
406 /* received the mem table */
12ebf690 407 memcpy(&s->memory, &msg.payload.memory, sizeof(msg.payload.memory));
5345fdb4 408 s->fds_num = qemu_chr_fe_get_msgfds(chr, s->fds,
32a6ebec 409 G_N_ELEMENTS(s->fds));
a77e6b14
NN
410
411 /* signal the test that it can continue */
04ad1bf6 412 g_cond_broadcast(&s->data_cond);
a77e6b14
NN
413 break;
414
415 case VHOST_USER_SET_VRING_KICK:
416 case VHOST_USER_SET_VRING_CALL:
417 /* consume the fd */
5345fdb4 418 qemu_chr_fe_get_msgfds(chr, &fd, 1);
a77e6b14
NN
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;
b1819747
MAL
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 }
5345fdb4 432 qemu_chr_fe_get_msgfds(chr, &s->log_fd, 1);
b1819747
MAL
433 msg.flags |= VHOST_USER_REPLY_MASK;
434 msg.size = 0;
435 p = (uint8_t *) &msg;
5345fdb4 436 qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE);
b1819747 437
04ad1bf6 438 g_cond_broadcast(&s->data_cond);
b1819747
MAL
439 break;
440
d08e42a1 441 case VHOST_USER_SET_VRING_BASE:
ed0a8d92 442 assert(msg.payload.state.index < s->queues * 2);
d08e42a1 443 s->rings |= 0x1ULL << msg.payload.state.index;
acca950c 444 g_cond_broadcast(&s->data_cond);
1d9edff7
MAL
445 break;
446
ed0a8d92
MAL
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;
5345fdb4 452 qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
ed0a8d92
MAL
453 break;
454
a77e6b14
NN
455 default:
456 break;
457 }
ae31fb54
MAL
458
459 g_mutex_unlock(&s->data_mutex);
a77e6b14
NN
460}
461
1b7e1e3b 462static const char *init_hugepagefs(const char *path)
a77e6b14 463{
a77e6b14
NN
464 struct statfs fs;
465 int ret;
466
a77e6b14
NN
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
704b2168 489static TestServer *test_server_new(const gchar *name)
ae31fb54
MAL
490{
491 TestServer *server = g_new0(TestServer, 1);
ae31fb54
MAL
492
493 server->socket_path = g_strdup_printf("%s/%s.sock", tmpfs, name);
a899b1ea 494 server->mig_path = g_strdup_printf("%s/%s.mig", tmpfs, name);
ae31fb54 495 server->chr_name = g_strdup_printf("chr-%s", name);
ae31fb54
MAL
496
497 g_mutex_init(&server->data_mutex);
498 g_cond_init(&server->data_cond);
499
b1819747 500 server->log_fd = -1;
ed0a8d92 501 server->queues = 1;
b1819747 502
ae31fb54
MAL
503 return server;
504}
505
9294d76c
MAL
506static 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
4616e359
MAL
516static void test_server_create_chr(TestServer *server, const gchar *opt)
517{
518 gchar *chr_path;
0ec7b3e7 519 Chardev *chr;
5345fdb4 520
4616e359 521 chr_path = g_strdup_printf("unix:%s%s", server->socket_path, opt);
4ad6f6cb 522 chr = qemu_chr_new(server->chr_name, chr_path, NULL);
4616e359
MAL
523 g_free(chr_path);
524
642e065a 525 g_assert_nonnull(chr);
5345fdb4
MAL
526 qemu_chr_fe_init(&server->chr, chr, &error_abort);
527 qemu_chr_fe_set_handlers(&server->chr, chr_can_read, chr_read,
81517ba3 528 chr_event, NULL, server, NULL, true);
4616e359
MAL
529}
530
531static void test_server_listen(TestServer *server)
532{
533 test_server_create_chr(server, ",server,nowait");
534}
535
9732baf6 536static gboolean _test_server_free(TestServer *server)
ae31fb54
MAL
537{
538 int i;
539
1ce2610c 540 qemu_chr_fe_deinit(&server->chr, true);
ae31fb54
MAL
541
542 for (i = 0; i < server->fds_num; i++) {
543 close(server->fds[i]);
544 }
545
b1819747
MAL
546 if (server->log_fd != -1) {
547 close(server->log_fd);
548 }
549
ae31fb54
MAL
550 unlink(server->socket_path);
551 g_free(server->socket_path);
552
a899b1ea
MAL
553 unlink(server->mig_path);
554 g_free(server->mig_path);
555
b1819747 556 g_free(server->chr_name);
9ee8a692 557 g_assert(server->bus);
0c0eb302
MAL
558 qpci_free_pc(server->bus);
559
ae31fb54 560 g_free(server);
9732baf6
MAL
561
562 return FALSE;
563}
564
565static void test_server_free(TestServer *server)
566{
567 g_idle_add((GSourceFunc)_test_server_free, server);
ae31fb54
MAL
568}
569
b1819747
MAL
570static 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
3a87d009 587static void write_guest_mem(TestServer *s, uint32_t seed)
b1819747
MAL
588{
589 uint32_t *guest_mem;
590 int i, j;
591 size_t size;
592
b1819747
MAL
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
621static 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
1d9edff7
MAL
636typedef struct TestMigrateSource {
637 GSource source;
638 TestServer *src;
639 TestServer *dest;
640} TestMigrateSource;
641
642static gboolean
643test_migrate_source_check(GSource *source)
644{
645 TestMigrateSource *t = (TestMigrateSource *)source;
d08e42a1 646 gboolean overlap = t->src->rings && t->dest->rings;
1d9edff7
MAL
647
648 g_assert(!overlap);
649
650 return FALSE;
651}
652
653GSourceFuncs test_migrate_source_funcs = {
45ce5126 654 .check = test_migrate_source_check,
1d9edff7
MAL
655};
656
8e029fd6 657static void test_read_guest_mem(const void *arg)
e364c703 658{
8e029fd6 659 enum test_memfd memfd = GPOINTER_TO_INT(arg);
e364c703
MC
660 TestServer *server = NULL;
661 char *qemu_cmd = NULL;
662 QTestState *s = NULL;
663
8e029fd6
MAL
664 server = test_server_new(memfd == TEST_MEMFD_YES ?
665 "read-guest-memfd" : "read-guest-mem");
e364c703
MC
666 test_server_listen(server);
667
8e029fd6 668 qemu_cmd = get_qemu_cmd(server, 512, memfd, root, "", "");
e364c703
MC
669
670 s = qtest_start(qemu_cmd);
671 g_free(qemu_cmd);
672
bae6b59d 673 init_virtio_dev(global_qtest, server, 1u << VIRTIO_NET_F_MAC);
e364c703 674
3b72ca38
PB
675 if (!wait_for_fds(server)) {
676 goto exit;
677 }
678
bae6b59d 679 read_guest_mem_server(global_qtest, server);
e364c703 680
3b72ca38 681exit:
026eb179
MC
682 uninit_virtio_dev(server);
683
e364c703
MC
684 qtest_quit(s);
685 test_server_free(server);
686}
687
b1819747
MAL
688static void test_migrate(void)
689{
690 TestServer *s = test_server_new("src");
691 TestServer *dest = test_server_new("dest");
a899b1ea 692 char *uri = g_strdup_printf("%s%s", "unix:", dest->mig_path);
bae6b59d 693 QTestState *from, *to;
1d9edff7 694 GSource *source;
8e029fd6 695 gchar *cmd, *tmp;
b1819747
MAL
696 QDict *rsp;
697 guint8 *log;
698 guint64 size;
699
4616e359
MAL
700 test_server_listen(s);
701 test_server_listen(dest);
702
8e029fd6 703 cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, "", "");
b1819747
MAL
704 from = qtest_start(cmd);
705 g_free(cmd);
706
bae6b59d 707 init_virtio_dev(from, s, 1u << VIRTIO_NET_F_MAC);
3b72ca38
PB
708 if (!wait_for_fds(s)) {
709 goto exit;
710 }
711
b1819747
MAL
712 size = get_log_size(s);
713 g_assert_cmpint(size, ==, (2 * 1024 * 1024) / (VHOST_LOG_PAGE * 8));
714
8e029fd6
MAL
715 tmp = g_strdup_printf(" -incoming %s", uri);
716 cmd = get_qemu_cmd(dest, 2, TEST_MEMFD_AUTO, root, "", tmp);
717 g_free(tmp);
b1819747
MAL
718 to = qtest_init(cmd);
719 g_free(cmd);
bae6b59d 720 init_virtio_dev(to, dest, 1u << VIRTIO_NET_F_MAC);
b1819747 721
1d9edff7
MAL
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
b1819747
MAL
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"));
cb3e7f08 733 qobject_unref(rsp);
b1819747 734
015715f5 735 rsp = qmp("{ 'execute': 'migrate', 'arguments': { 'uri': %s } }", uri);
b1819747 736 g_assert(qdict_haskey(rsp, "return"));
cb3e7f08 737 qobject_unref(rsp);
b1819747
MAL
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"));
cb3e7f08 753 qobject_unref(rsp);
b1819747
MAL
754
755 qmp_eventwait("STOP");
bae6b59d 756 qtest_qmp_eventwait(to, "RESUME");
b1819747 757
bae6b59d
PB
758 g_assert(wait_for_fds(dest));
759 read_guest_mem_server(to, dest);
b1819747 760
9ee8a692 761 uninit_virtio_dev(dest);
3b72ca38 762 qtest_quit(to);
026eb179 763
1d9edff7
MAL
764 g_source_destroy(source);
765 g_source_unref(source);
766
3b72ca38
PB
767exit:
768 uninit_virtio_dev(s);
769
b1819747
MAL
770 test_server_free(dest);
771 qtest_quit(from);
772 test_server_free(s);
a899b1ea 773 g_free(uri);
b1819747
MAL
774}
775
4616e359
MAL
776static 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
20784087
PMD
793static inline void test_server_connect(TestServer *server)
794{
795 test_server_create_chr(server, ",reconnect=1");
796}
797
4616e359
MAL
798static gboolean
799reconnect_cb(gpointer user_data)
800{
801 TestServer *s = user_data;
802
5345fdb4 803 qemu_chr_fe_disconnect(&s->chr);
4616e359
MAL
804
805 return FALSE;
806}
807
808static gpointer
809connect_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
820static 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);
8e029fd6 826 cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, ",server", "");
4616e359
MAL
827 qtest_start(cmd);
828 g_free(cmd);
829
bae6b59d 830 init_virtio_dev(global_qtest, s, 1u << VIRTIO_NET_F_MAC);
3b72ca38
PB
831 if (!wait_for_fds(s)) {
832 goto exit;
833 }
834
4616e359
MAL
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);
3b72ca38 841 g_assert(wait_for_fds(s));
4616e359
MAL
842 wait_for_rings_started(s, 2);
843
3b72ca38 844exit:
026eb179
MC
845 uninit_virtio_dev(s);
846
4616e359
MAL
847 qtest_end();
848 test_server_free(s);
849 return;
850}
851
852static 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();
69179fe2 858 g_free(path);
4616e359 859}
5d443f5a
MAL
860
861static 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);
8e029fd6 868 cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, ",server", "");
5d443f5a
MAL
869 qtest_start(cmd);
870 g_free(cmd);
871
bae6b59d 872 init_virtio_dev(global_qtest, s, 1u << VIRTIO_NET_F_MAC);
3b72ca38
PB
873 if (!wait_for_fds(s)) {
874 goto exit;
875 }
5d443f5a
MAL
876 wait_for_rings_started(s, 2);
877
3b72ca38 878exit:
026eb179
MC
879 uninit_virtio_dev(s);
880
5d443f5a
MAL
881 qtest_end();
882 test_server_free(s);
883}
884
885static 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
9294d76c
MAL
894static 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);
8e029fd6 901 cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, ",server", "");
9294d76c
MAL
902 qtest_start(cmd);
903 g_free(cmd);
904
bae6b59d 905 init_virtio_dev(global_qtest, s, 1u << VIRTIO_NET_F_MAC);
3b72ca38
PB
906 if (!wait_for_fds(s)) {
907 goto exit;
908 }
9294d76c
MAL
909 wait_for_rings_started(s, 2);
910
3b72ca38 911exit:
026eb179
MC
912 uninit_virtio_dev(s);
913
9294d76c
MAL
914 qtest_end();
915 test_server_free(s);
916}
917
918static 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
4616e359 927
ed0a8d92
MAL
928static void test_multiqueue(void)
929{
ed0a8d92 930 TestServer *s = test_server_new("mq");
ed0a8d92 931 char *cmd;
459f5d29
MC
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;
ed0a8d92
MAL
936 test_server_listen(s);
937
38296400 938 if (qemu_memfd_check(0)) {
8e029fd6
MAL
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 }
ed0a8d92
MAL
953 qtest_start(cmd);
954 g_free(cmd);
955
bae6b59d 956 init_virtio_dev(global_qtest, s, features_mask);
ed0a8d92 957
459f5d29 958 wait_for_rings_started(s, s->queues * 2);
ed0a8d92 959
459f5d29 960 uninit_virtio_dev(s);
ed0a8d92 961
ed0a8d92
MAL
962 qtest_end();
963
964 test_server_free(s);
965}
966
a77e6b14
NN
967int main(int argc, char **argv)
968{
1b7e1e3b 969 const char *hugefs;
a77e6b14 970 int ret;
1b7e1e3b 971 char template[] = "/tmp/vhost-test-XXXXXX";
9732baf6
MAL
972 GMainLoop *loop;
973 GThread *thread;
a77e6b14
NN
974
975 g_test_init(&argc, &argv, NULL);
976
977 module_call_init(MODULE_INIT_QOM);
ae31fb54 978 qemu_add_opts(&qemu_chardev_opts);
a77e6b14 979
1b7e1e3b
MT
980 tmpfs = mkdtemp(template);
981 if (!tmpfs) {
ae31fb54 982 g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno));
1b7e1e3b
MT
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;
a77e6b14
NN
992 }
993
9732baf6 994 loop = g_main_loop_new(NULL, FALSE);
a77e6b14 995 /* run the main loop thread so the chardev may operate */
9732baf6 996 thread = g_thread_new(NULL, thread_function, loop);
a77e6b14 997
38296400 998 if (qemu_memfd_check(0)) {
8e029fd6
MAL
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);
b1819747 1005 qtest_add_func("/vhost-user/migrate", test_migrate);
ed0a8d92 1006 qtest_add_func("/vhost-user/multiqueue", test_multiqueue);
20784087 1007
7a9ec654
MAL
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 }
a77e6b14
NN
1020
1021 ret = g_test_run();
1022
a77e6b14 1023 /* cleanup */
a77e6b14 1024
9732baf6
MAL
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
1b7e1e3b
MT
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
a77e6b14
NN
1040 return ret;
1041}