vhost-user-test.c 25.7 KB
Newer Older
N
Nikolay Nikolaev 已提交
1 2 3 4 5 6 7 8 9 10
/*
 * QTest testcase for the vhost-user
 *
 * Copyright (c) 2014 Virtual Open Systems Sarl.
 *
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
 * See the COPYING file in the top-level directory.
 *
 */

P
Peter Maydell 已提交
11
#include "qemu/osdep.h"
12

N
Nikolay Nikolaev 已提交
13
#include "libqtest.h"
14
#include "qapi/error.h"
15
#include "qapi/qmp/qdict.h"
M
Marc-André Lureau 已提交
16
#include "qemu/config-file.h"
N
Nikolay Nikolaev 已提交
17
#include "qemu/option.h"
18
#include "qemu/range.h"
19
#include "qemu/sockets.h"
20
#include "chardev/char-fe.h"
N
Nikolay Nikolaev 已提交
21
#include "sysemu/sysemu.h"
22 23 24
#include "libqos/libqos.h"
#include "libqos/pci-pc.h"
#include "libqos/virtio-pci.h"
N
Nikolay Nikolaev 已提交
25

26 27 28
#include "libqos/malloc-pc.h"
#include "hw/virtio/virtio-net.h"

N
Nikolay Nikolaev 已提交
29
#include <linux/vhost.h>
30 31
#include <linux/virtio_ids.h>
#include <linux/virtio_net.h>
N
Nikolay Nikolaev 已提交
32 33
#include <sys/vfs.h>

34 35 36 37 38 39 40 41 42
/* GLIB version compatibility flags */
#if !GLIB_CHECK_VERSION(2, 26, 0)
#define G_TIME_SPAN_SECOND              (G_GINT64_CONSTANT(1000000))
#endif

#if GLIB_CHECK_VERSION(2, 28, 0)
#define HAVE_MONOTONIC_TIME
#endif

43
#define QEMU_CMD_MEM    " -m %d -object memory-backend-file,id=mem,size=%dM,"\
N
Nikolay Nikolaev 已提交
44
                        "mem-path=%s,share=on -numa node,memdev=mem"
45
#define QEMU_CMD_CHR    " -chardev socket,id=%s,path=%s%s"
46
#define QEMU_CMD_NETDEV " -netdev vhost-user,id=net0,chardev=%s,vhostforce"
47
#define QEMU_CMD_NET    " -device virtio-net-pci,netdev=net0"
N
Nikolay Nikolaev 已提交
48

49 50 51 52 53 54 55 56 57 58 59
#define QEMU_CMD        QEMU_CMD_MEM QEMU_CMD_CHR \
                        QEMU_CMD_NETDEV QEMU_CMD_NET

#define GET_QEMU_CMD(s)                                         \
    g_strdup_printf(QEMU_CMD, 512, 512, (root), (s)->chr_name,  \
                    (s)->socket_path, "", (s)->chr_name)

#define GET_QEMU_CMDE(s, mem, chr_opts, extra, ...)                     \
    g_strdup_printf(QEMU_CMD extra, (mem), (mem), (root), (s)->chr_name, \
                    (s)->socket_path, (chr_opts), (s)->chr_name, ##__VA_ARGS__)

N
Nikolay Nikolaev 已提交
60 61 62 63 64
#define HUGETLBFS_MAGIC       0x958458f6

/*********** FROM hw/virtio/vhost-user.c *************************************/

#define VHOST_MEMORY_MAX_NREGIONS    8
65
#define VHOST_MAX_VIRTQUEUES    0x100
N
Nikolay Nikolaev 已提交
66

67
#define VHOST_USER_F_PROTOCOL_FEATURES 30
68
#define VHOST_USER_PROTOCOL_F_MQ 0
69 70 71
#define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1

#define VHOST_LOG_PAGE 0x1000
72

N
Nikolay Nikolaev 已提交
73 74 75 76 77
typedef enum VhostUserRequest {
    VHOST_USER_NONE = 0,
    VHOST_USER_GET_FEATURES = 1,
    VHOST_USER_SET_FEATURES = 2,
    VHOST_USER_SET_OWNER = 3,
78
    VHOST_USER_RESET_OWNER = 4,
N
Nikolay Nikolaev 已提交
79 80 81 82 83 84 85 86 87 88
    VHOST_USER_SET_MEM_TABLE = 5,
    VHOST_USER_SET_LOG_BASE = 6,
    VHOST_USER_SET_LOG_FD = 7,
    VHOST_USER_SET_VRING_NUM = 8,
    VHOST_USER_SET_VRING_ADDR = 9,
    VHOST_USER_SET_VRING_BASE = 10,
    VHOST_USER_GET_VRING_BASE = 11,
    VHOST_USER_SET_VRING_KICK = 12,
    VHOST_USER_SET_VRING_CALL = 13,
    VHOST_USER_SET_VRING_ERR = 14,
89 90
    VHOST_USER_GET_PROTOCOL_FEATURES = 15,
    VHOST_USER_SET_PROTOCOL_FEATURES = 16,
91
    VHOST_USER_GET_QUEUE_NUM = 17,
92
    VHOST_USER_SET_VRING_ENABLE = 18,
N
Nikolay Nikolaev 已提交
93 94 95 96 97 98 99
    VHOST_USER_MAX
} VhostUserRequest;

typedef struct VhostUserMemoryRegion {
    uint64_t guest_phys_addr;
    uint64_t memory_size;
    uint64_t userspace_addr;
100
    uint64_t mmap_offset;
N
Nikolay Nikolaev 已提交
101 102 103 104 105 106 107 108
} VhostUserMemoryRegion;

typedef struct VhostUserMemory {
    uint32_t nregions;
    uint32_t padding;
    VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
} VhostUserMemory;

109 110 111 112 113
typedef struct VhostUserLog {
    uint64_t mmap_size;
    uint64_t mmap_offset;
} VhostUserLog;

N
Nikolay Nikolaev 已提交
114 115 116 117 118 119 120 121
typedef struct VhostUserMsg {
    VhostUserRequest request;

#define VHOST_USER_VERSION_MASK     (0x3)
#define VHOST_USER_REPLY_MASK       (0x1<<2)
    uint32_t flags;
    uint32_t size; /* the following payload size */
    union {
122 123
#define VHOST_USER_VRING_IDX_MASK   (0xff)
#define VHOST_USER_VRING_NOFD_MASK  (0x1<<8)
N
Nikolay Nikolaev 已提交
124 125 126 127
        uint64_t u64;
        struct vhost_vring_state state;
        struct vhost_vring_addr addr;
        VhostUserMemory memory;
128
        VhostUserLog log;
129
    } payload;
N
Nikolay Nikolaev 已提交
130 131 132 133 134 135 136 137 138 139 140 141 142
} QEMU_PACKED VhostUserMsg;

static VhostUserMsg m __attribute__ ((unused));
#define VHOST_USER_HDR_SIZE (sizeof(m.request) \
                            + sizeof(m.flags) \
                            + sizeof(m.size))

#define VHOST_USER_PAYLOAD_SIZE (sizeof(m) - VHOST_USER_HDR_SIZE)

/* The version of the protocol we support */
#define VHOST_USER_VERSION    (0x1)
/*****************************************************************************/

143 144 145 146 147 148 149
enum {
    TEST_FLAGS_OK,
    TEST_FLAGS_DISCONNECT,
    TEST_FLAGS_BAD,
    TEST_FLAGS_END,
};

150
typedef struct TestServer {
151
    QPCIBus *bus;
152 153
    QVirtioPCIDevice *dev;
    QVirtQueue *vq[VHOST_MAX_VIRTQUEUES];
154
    gchar *socket_path;
155
    gchar *mig_path;
156
    gchar *chr_name;
157
    CharBackend chr;
158 159 160
    int fds_num;
    int fds[VHOST_MEMORY_MAX_NREGIONS];
    VhostUserMemory memory;
161 162
    CompatGMutex data_mutex;
    CompatGCond data_cond;
163
    int log_fd;
164
    uint64_t rings;
165
    bool test_fail;
166
    int test_flags;
167
    int queues;
168
    QGuestAllocator *alloc;
169
} TestServer;
170

171 172 173 174
static TestServer *test_server_new(const gchar *name);
static void test_server_free(TestServer *server);
static void test_server_listen(TestServer *server);

175 176 177
static const char *tmpfs;
static const char *root;

178
static void init_virtio_dev(TestServer *s, uint32_t features_mask)
179 180
{
    uint32_t features;
181
    int i;
182

183
    s->bus = qpci_init_pc(global_qtest, NULL);
184
    g_assert_nonnull(s->bus);
185

186 187
    s->dev = qvirtio_pci_device_find(s->bus, VIRTIO_ID_NET);
    g_assert_nonnull(s->dev);
188

189 190 191 192
    qvirtio_pci_device_enable(s->dev);
    qvirtio_reset(&s->dev->vdev);
    qvirtio_set_acknowledge(&s->dev->vdev);
    qvirtio_set_driver(&s->dev->vdev);
193

194
    s->alloc = pc_alloc_init(global_qtest);
195 196 197 198 199 200

    for (i = 0; i < s->queues * 2; i++) {
        s->vq[i] = qvirtqueue_setup(&s->dev->vdev, s->alloc, i);
    }

    features = qvirtio_get_features(&s->dev->vdev);
201
    features = features & features_mask;
202 203 204 205 206 207 208 209
    qvirtio_set_features(&s->dev->vdev, features);

    qvirtio_set_driver_ok(&s->dev->vdev);
}

static void uninit_virtio_dev(TestServer *s)
{
    int i;
210

211 212 213 214 215 216
    for (i = 0; i < s->queues * 2; i++) {
        qvirtqueue_cleanup(s->dev->vdev.bus, s->vq[i], s->alloc);
    }
    pc_alloc_uninit(s->alloc);

    qvirtio_pci_device_free(s->dev);
217 218
}

219
static void wait_for_fds(TestServer *s)
N
Nikolay Nikolaev 已提交
220 221 222
{
    gint64 end_time;

223
    g_mutex_lock(&s->data_mutex);
N
Nikolay Nikolaev 已提交
224

225
    end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
226 227
    while (!s->fds_num) {
        if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
N
Nikolay Nikolaev 已提交
228
            /* timeout has passed */
229
            g_assert(s->fds_num);
N
Nikolay Nikolaev 已提交
230 231 232 233 234
            break;
        }
    }

    /* check for sanity */
235 236
    g_assert_cmpint(s->fds_num, >, 0);
    g_assert_cmpint(s->fds_num, ==, s->memory.nregions);
N
Nikolay Nikolaev 已提交
237

238
    g_mutex_unlock(&s->data_mutex);
239 240
}

241
static void read_guest_mem_server(TestServer *s)
242 243 244 245 246
{
    uint32_t *guest_mem;
    int i, j;
    size_t size;

247
    wait_for_fds(s);
248

249
    g_mutex_lock(&s->data_mutex);
250

N
Nikolay Nikolaev 已提交
251
    /* iterate all regions */
252
    for (i = 0; i < s->fds_num; i++) {
N
Nikolay Nikolaev 已提交
253 254

        /* We'll check only the region statring at 0x0*/
255
        if (s->memory.regions[i].guest_phys_addr != 0x0) {
N
Nikolay Nikolaev 已提交
256 257 258
            continue;
        }

259
        g_assert_cmpint(s->memory.regions[i].memory_size, >, 1024);
N
Nikolay Nikolaev 已提交
260

261 262
        size = s->memory.regions[i].memory_size +
            s->memory.regions[i].mmap_offset;
263 264

        guest_mem = mmap(0, size, PROT_READ | PROT_WRITE,
265
                         MAP_SHARED, s->fds[i], 0);
266 267

        g_assert(guest_mem != MAP_FAILED);
268
        guest_mem += (s->memory.regions[i].mmap_offset / sizeof(*guest_mem));
N
Nikolay Nikolaev 已提交
269 270

        for (j = 0; j < 256; j++) {
271
            uint32_t a = readl(s->memory.regions[i].guest_phys_addr + j*4);
N
Nikolay Nikolaev 已提交
272 273 274 275 276
            uint32_t b = guest_mem[j];

            g_assert_cmpint(a, ==, b);
        }

277
        munmap(guest_mem, s->memory.regions[i].memory_size);
N
Nikolay Nikolaev 已提交
278 279
    }

280
    g_mutex_unlock(&s->data_mutex);
N
Nikolay Nikolaev 已提交
281 282 283 284
}

static void *thread_function(void *data)
{
285
    GMainLoop *loop = data;
N
Nikolay Nikolaev 已提交
286 287 288 289 290 291 292 293 294 295 296
    g_main_loop_run(loop);
    return NULL;
}

static int chr_can_read(void *opaque)
{
    return VHOST_USER_HDR_SIZE;
}

static void chr_read(void *opaque, const uint8_t *buf, int size)
{
297
    TestServer *s = opaque;
298
    CharBackend *chr = &s->chr;
N
Nikolay Nikolaev 已提交
299 300 301 302
    VhostUserMsg msg;
    uint8_t *p = (uint8_t *) &msg;
    int fd;

303
    if (s->test_fail) {
304
        qemu_chr_fe_disconnect(chr);
305 306 307 308
        /* now switch to non-failure */
        s->test_fail = false;
    }

N
Nikolay Nikolaev 已提交
309 310 311 312 313
    if (size != VHOST_USER_HDR_SIZE) {
        g_test_message("Wrong message size received %d\n", size);
        return;
    }

314
    g_mutex_lock(&s->data_mutex);
N
Nikolay Nikolaev 已提交
315 316 317 318
    memcpy(p, buf, VHOST_USER_HDR_SIZE);

    if (msg.size) {
        p += VHOST_USER_HDR_SIZE;
319
        size = qemu_chr_fe_read_all(chr, p, msg.size);
320 321 322 323 324
        if (size != msg.size) {
            g_test_message("Wrong message size received %d != %d\n",
                           size, msg.size);
            return;
        }
N
Nikolay Nikolaev 已提交
325 326 327 328
    }

    switch (msg.request) {
    case VHOST_USER_GET_FEATURES:
329 330
        /* send back features to qemu */
        msg.flags |= VHOST_USER_REPLY_MASK;
331 332
        msg.size = sizeof(m.payload.u64);
        msg.payload.u64 = 0x1ULL << VHOST_F_LOG_ALL |
333
            0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
334 335 336
        if (s->queues > 1) {
            msg.payload.u64 |= 0x1ULL << VIRTIO_NET_F_MQ;
        }
337 338 339 340
        if (s->test_flags >= TEST_FLAGS_BAD) {
            msg.payload.u64 = 0;
            s->test_flags = TEST_FLAGS_END;
        }
341
        p = (uint8_t *) &msg;
342
        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
343 344 345
        break;

    case VHOST_USER_SET_FEATURES:
346
	g_assert_cmpint(msg.payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES),
347
			!=, 0ULL);
348
        if (s->test_flags == TEST_FLAGS_DISCONNECT) {
349
            qemu_chr_fe_disconnect(chr);
350 351
            s->test_flags = TEST_FLAGS_BAD;
        }
352 353 354
        break;

    case VHOST_USER_GET_PROTOCOL_FEATURES:
N
Nikolay Nikolaev 已提交
355 356
        /* send back features to qemu */
        msg.flags |= VHOST_USER_REPLY_MASK;
357 358
        msg.size = sizeof(m.payload.u64);
        msg.payload.u64 = 1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD;
359 360 361
        if (s->queues > 1) {
            msg.payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_MQ;
        }
N
Nikolay Nikolaev 已提交
362
        p = (uint8_t *) &msg;
363
        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
N
Nikolay Nikolaev 已提交
364 365 366 367 368
        break;

    case VHOST_USER_GET_VRING_BASE:
        /* send back vring base to qemu */
        msg.flags |= VHOST_USER_REPLY_MASK;
369 370
        msg.size = sizeof(m.payload.state);
        msg.payload.state.num = 0;
N
Nikolay Nikolaev 已提交
371
        p = (uint8_t *) &msg;
372
        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
373

374
        assert(msg.payload.state.index < s->queues * 2);
375
        s->rings &= ~(0x1ULL << msg.payload.state.index);
N
Nikolay Nikolaev 已提交
376 377 378 379
        break;

    case VHOST_USER_SET_MEM_TABLE:
        /* received the mem table */
380
        memcpy(&s->memory, &msg.payload.memory, sizeof(msg.payload.memory));
381
        s->fds_num = qemu_chr_fe_get_msgfds(chr, s->fds,
382
                                            G_N_ELEMENTS(s->fds));
N
Nikolay Nikolaev 已提交
383 384

        /* signal the test that it can continue */
385
        g_cond_signal(&s->data_cond);
N
Nikolay Nikolaev 已提交
386 387 388 389 390
        break;

    case VHOST_USER_SET_VRING_KICK:
    case VHOST_USER_SET_VRING_CALL:
        /* consume the fd */
391
        qemu_chr_fe_get_msgfds(chr, &fd, 1);
N
Nikolay Nikolaev 已提交
392 393 394 395 396 397 398
        /*
         * This is a non-blocking eventfd.
         * The receive function forces it to be blocking,
         * so revert it back to non-blocking.
         */
        qemu_set_nonblock(fd);
        break;
399 400 401 402 403 404

    case VHOST_USER_SET_LOG_BASE:
        if (s->log_fd != -1) {
            close(s->log_fd);
            s->log_fd = -1;
        }
405
        qemu_chr_fe_get_msgfds(chr, &s->log_fd, 1);
406 407 408
        msg.flags |= VHOST_USER_REPLY_MASK;
        msg.size = 0;
        p = (uint8_t *) &msg;
409
        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE);
410 411 412 413

        g_cond_signal(&s->data_cond);
        break;

414
    case VHOST_USER_SET_VRING_BASE:
415
        assert(msg.payload.state.index < s->queues * 2);
416
        s->rings |= 0x1ULL << msg.payload.state.index;
417 418
        break;

419 420 421 422 423
    case VHOST_USER_GET_QUEUE_NUM:
        msg.flags |= VHOST_USER_REPLY_MASK;
        msg.size = sizeof(m.payload.u64);
        msg.payload.u64 = s->queues;
        p = (uint8_t *) &msg;
424
        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
425 426
        break;

N
Nikolay Nikolaev 已提交
427 428 429
    default:
        break;
    }
430 431

    g_mutex_unlock(&s->data_mutex);
N
Nikolay Nikolaev 已提交
432 433
}

434
static const char *init_hugepagefs(const char *path)
N
Nikolay Nikolaev 已提交
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
{
    struct statfs fs;
    int ret;

    if (access(path, R_OK | W_OK | X_OK)) {
        g_test_message("access on path (%s): %s\n", path, strerror(errno));
        return NULL;
    }

    do {
        ret = statfs(path, &fs);
    } while (ret != 0 && errno == EINTR);

    if (ret != 0) {
        g_test_message("statfs on path (%s): %s\n", path, strerror(errno));
        return NULL;
    }

    if (fs.f_type != HUGETLBFS_MAGIC) {
        g_test_message("Warning: path not on HugeTLBFS: %s\n", path);
        return NULL;
    }

    return path;
}

461
static TestServer *test_server_new(const gchar *name)
462 463 464 465
{
    TestServer *server = g_new0(TestServer, 1);

    server->socket_path = g_strdup_printf("%s/%s.sock", tmpfs, name);
466
    server->mig_path = g_strdup_printf("%s/%s.mig", tmpfs, name);
467 468 469 470 471
    server->chr_name = g_strdup_printf("chr-%s", name);

    g_mutex_init(&server->data_mutex);
    g_cond_init(&server->data_cond);

472
    server->log_fd = -1;
473
    server->queues = 1;
474

475 476 477
    return server;
}

478 479 480 481 482 483 484 485 486 487
static void chr_event(void *opaque, int event)
{
    TestServer *s = opaque;

    if (s->test_flags == TEST_FLAGS_END &&
        event == CHR_EVENT_CLOSED) {
        s->test_flags = TEST_FLAGS_OK;
    }
}

488 489 490
static void test_server_create_chr(TestServer *server, const gchar *opt)
{
    gchar *chr_path;
491
    Chardev *chr;
492

493
    chr_path = g_strdup_printf("unix:%s%s", server->socket_path, opt);
494
    chr = qemu_chr_new(server->chr_name, chr_path);
495 496
    g_free(chr_path);

497
    g_assert_nonnull(chr);
498 499
    qemu_chr_fe_init(&server->chr, chr, &error_abort);
    qemu_chr_fe_set_handlers(&server->chr, chr_can_read, chr_read,
500
                             chr_event, NULL, server, NULL, true);
501 502 503 504 505 506 507
}

static void test_server_listen(TestServer *server)
{
    test_server_create_chr(server, ",server,nowait");
}

508
static gboolean _test_server_free(TestServer *server)
509 510 511
{
    int i;

512
    qemu_chr_fe_deinit(&server->chr, true);
513 514 515 516 517

    for (i = 0; i < server->fds_num; i++) {
        close(server->fds[i]);
    }

518 519 520 521
    if (server->log_fd != -1) {
        close(server->log_fd);
    }

522 523 524
    unlink(server->socket_path);
    g_free(server->socket_path);

525 526 527
    unlink(server->mig_path);
    g_free(server->mig_path);

528
    g_free(server->chr_name);
529 530
    qpci_free_pc(server->bus);

531
    g_free(server);
532 533 534 535 536 537 538

    return FALSE;
}

static void test_server_free(TestServer *server)
{
    g_idle_add((GSourceFunc)_test_server_free, server);
539 540
}

541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
static void wait_for_log_fd(TestServer *s)
{
    gint64 end_time;

    g_mutex_lock(&s->data_mutex);
    end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
    while (s->log_fd == -1) {
        if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
            /* timeout has passed */
            g_assert(s->log_fd != -1);
            break;
        }
    }

    g_mutex_unlock(&s->data_mutex);
}

558
static void write_guest_mem(TestServer *s, uint32_t seed)
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
{
    uint32_t *guest_mem;
    int i, j;
    size_t size;

    wait_for_fds(s);

    /* iterate all regions */
    for (i = 0; i < s->fds_num; i++) {

        /* We'll write only the region statring at 0x0 */
        if (s->memory.regions[i].guest_phys_addr != 0x0) {
            continue;
        }

        g_assert_cmpint(s->memory.regions[i].memory_size, >, 1024);

        size = s->memory.regions[i].memory_size +
            s->memory.regions[i].mmap_offset;

        guest_mem = mmap(0, size, PROT_READ | PROT_WRITE,
                         MAP_SHARED, s->fds[i], 0);

        g_assert(guest_mem != MAP_FAILED);
        guest_mem += (s->memory.regions[i].mmap_offset / sizeof(*guest_mem));

        for (j = 0; j < 256; j++) {
            guest_mem[j] = seed + j;
        }

        munmap(guest_mem, s->memory.regions[i].memory_size);
        break;
    }
}

static guint64 get_log_size(TestServer *s)
{
    guint64 log_size = 0;
    int i;

    for (i = 0; i < s->memory.nregions; ++i) {
        VhostUserMemoryRegion *reg = &s->memory.regions[i];
        guint64 last = range_get_last(reg->guest_phys_addr,
                                       reg->memory_size);
        log_size = MAX(log_size, last / (8 * VHOST_LOG_PAGE) + 1);
    }

    return log_size;
}

609 610 611 612 613 614 615 616 617 618
typedef struct TestMigrateSource {
    GSource source;
    TestServer *src;
    TestServer *dest;
} TestMigrateSource;

static gboolean
test_migrate_source_check(GSource *source)
{
    TestMigrateSource *t = (TestMigrateSource *)source;
619
    gboolean overlap = t->src->rings && t->dest->rings;
620 621 622 623 624 625

    g_assert(!overlap);

    return FALSE;
}

626 627 628 629 630 631 632 633 634 635 636
#if !GLIB_CHECK_VERSION(2,36,0)
/* this callback is unnecessary with glib >2.36, the default
 * prepare for the source does the same */
static gboolean
test_migrate_source_prepare(GSource *source, gint *timeout)
{
    *timeout = -1;
    return FALSE;
}
#endif

637
GSourceFuncs test_migrate_source_funcs = {
638 639 640 641
#if !GLIB_CHECK_VERSION(2,36,0)
    .prepare = test_migrate_source_prepare,
#endif
    .check = test_migrate_source_check,
642 643
};

644
static void test_read_guest_mem(void)
645 646 647 648 649 650 651 652
{
    TestServer *server = NULL;
    char *qemu_cmd = NULL;
    QTestState *s = NULL;

    server = test_server_new("test");
    test_server_listen(server);

653
    qemu_cmd = GET_QEMU_CMD(server);
654 655 656 657

    s = qtest_start(qemu_cmd);
    g_free(qemu_cmd);

658
    init_virtio_dev(server, 1u << VIRTIO_NET_F_MAC);
659

660
    read_guest_mem_server(server);
661

662 663
    uninit_virtio_dev(server);

664 665 666 667
    qtest_quit(s);
    test_server_free(server);
}

668 669 670 671
static void test_migrate(void)
{
    TestServer *s = test_server_new("src");
    TestServer *dest = test_server_new("dest");
672
    char *uri = g_strdup_printf("%s%s", "unix:", dest->mig_path);
673
    QTestState *global = global_qtest, *from, *to;
674
    GSource *source;
675
    gchar *cmd;
676 677 678 679
    QDict *rsp;
    guint8 *log;
    guint64 size;

680 681 682
    test_server_listen(s);
    test_server_listen(dest);

683
    cmd = GET_QEMU_CMDE(s, 2, "", "");
684 685 686
    from = qtest_start(cmd);
    g_free(cmd);

687
    init_virtio_dev(s, 1u << VIRTIO_NET_F_MAC);
688 689 690 691
    wait_for_fds(s);
    size = get_log_size(s);
    g_assert_cmpint(size, ==, (2 * 1024 * 1024) / (VHOST_LOG_PAGE * 8));

692
    cmd = GET_QEMU_CMDE(dest, 2, "", " -incoming %s", uri);
693 694 695
    to = qtest_init(cmd);
    g_free(cmd);

696 697 698 699 700 701
    source = g_source_new(&test_migrate_source_funcs,
                          sizeof(TestMigrateSource));
    ((TestMigrateSource *)source)->src = s;
    ((TestMigrateSource *)source)->dest = dest;
    g_source_attach(source, NULL);

702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737
    /* slow down migration to have time to fiddle with log */
    /* TODO: qtest could learn to break on some places */
    rsp = qmp("{ 'execute': 'migrate_set_speed',"
              "'arguments': { 'value': 10 } }");
    g_assert(qdict_haskey(rsp, "return"));
    QDECREF(rsp);

    cmd = g_strdup_printf("{ 'execute': 'migrate',"
                          "'arguments': { 'uri': '%s' } }",
                          uri);
    rsp = qmp(cmd);
    g_free(cmd);
    g_assert(qdict_haskey(rsp, "return"));
    QDECREF(rsp);

    wait_for_log_fd(s);

    log = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, s->log_fd, 0);
    g_assert(log != MAP_FAILED);

    /* modify first page */
    write_guest_mem(s, 0x42);
    log[0] = 1;
    munmap(log, size);

    /* speed things up */
    rsp = qmp("{ 'execute': 'migrate_set_speed',"
              "'arguments': { 'value': 0 } }");
    g_assert(qdict_haskey(rsp, "return"));
    QDECREF(rsp);

    qmp_eventwait("STOP");

    global_qtest = to;
    qmp_eventwait("RESUME");

738
    read_guest_mem_server(dest);
739

740 741
    uninit_virtio_dev(s);

742 743 744
    g_source_destroy(source);
    g_source_unref(source);

745 746 747 748
    qtest_quit(to);
    test_server_free(dest);
    qtest_quit(from);
    test_server_free(s);
749
    g_free(uri);
750 751 752 753

    global_qtest = global;
}

754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770
static void wait_for_rings_started(TestServer *s, size_t count)
{
    gint64 end_time;

    g_mutex_lock(&s->data_mutex);
    end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
    while (ctpop64(s->rings) != count) {
        if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
            /* timeout has passed */
            g_assert_cmpint(ctpop64(s->rings), ==, count);
            break;
        }
    }

    g_mutex_unlock(&s->data_mutex);
}

771
#if defined(CONFIG_HAS_GLIB_SUBPROCESS_TESTS)
772 773 774 775 776
static inline void test_server_connect(TestServer *server)
{
    test_server_create_chr(server, ",reconnect=1");
}

777 778 779 780 781
static gboolean
reconnect_cb(gpointer user_data)
{
    TestServer *s = user_data;

782
    qemu_chr_fe_disconnect(&s->chr);
783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804

    return FALSE;
}

static gpointer
connect_thread(gpointer data)
{
    TestServer *s = data;

    /* wait for qemu to start before first try, to avoid extra warnings */
    g_usleep(G_USEC_PER_SEC);
    test_server_connect(s);

    return NULL;
}

static void test_reconnect_subprocess(void)
{
    TestServer *s = test_server_new("reconnect");
    char *cmd;

    g_thread_new("connect", connect_thread, s);
805
    cmd = GET_QEMU_CMDE(s, 2, ",server", "");
806 807 808
    qtest_start(cmd);
    g_free(cmd);

809
    init_virtio_dev(s, 1u << VIRTIO_NET_F_MAC);
810 811 812 813 814 815 816 817 818 819
    wait_for_fds(s);
    wait_for_rings_started(s, 2);

    /* reconnect */
    s->fds_num = 0;
    s->rings = 0;
    g_idle_add(reconnect_cb, s);
    wait_for_fds(s);
    wait_for_rings_started(s, 2);

820 821
    uninit_virtio_dev(s);

822 823 824 825 826 827 828 829 830 831 832
    qtest_end();
    test_server_free(s);
    return;
}

static void test_reconnect(void)
{
    gchar *path = g_strdup_printf("/%s/vhost-user/reconnect/subprocess",
                                  qtest_get_arch());
    g_test_trap_subprocess(path, 0, 0);
    g_test_trap_assert_passed();
833
    g_free(path);
834
}
835 836 837 838 839 840 841 842

static void test_connect_fail_subprocess(void)
{
    TestServer *s = test_server_new("connect-fail");
    char *cmd;

    s->test_fail = true;
    g_thread_new("connect", connect_thread, s);
843
    cmd = GET_QEMU_CMDE(s, 2, ",server", "");
844 845 846
    qtest_start(cmd);
    g_free(cmd);

847
    init_virtio_dev(s, 1u << VIRTIO_NET_F_MAC);
848 849 850
    wait_for_fds(s);
    wait_for_rings_started(s, 2);

851 852
    uninit_virtio_dev(s);

853 854 855 856 857 858 859 860 861 862 863 864 865
    qtest_end();
    test_server_free(s);
}

static void test_connect_fail(void)
{
    gchar *path = g_strdup_printf("/%s/vhost-user/connect-fail/subprocess",
                                  qtest_get_arch());
    g_test_trap_subprocess(path, 0, 0);
    g_test_trap_assert_passed();
    g_free(path);
}

866 867 868 869 870 871 872
static void test_flags_mismatch_subprocess(void)
{
    TestServer *s = test_server_new("flags-mismatch");
    char *cmd;

    s->test_flags = TEST_FLAGS_DISCONNECT;
    g_thread_new("connect", connect_thread, s);
873
    cmd = GET_QEMU_CMDE(s, 2, ",server", "");
874 875 876
    qtest_start(cmd);
    g_free(cmd);

877
    init_virtio_dev(s, 1u << VIRTIO_NET_F_MAC);
878 879 880
    wait_for_fds(s);
    wait_for_rings_started(s, 2);

881 882
    uninit_virtio_dev(s);

883 884 885 886 887 888 889 890 891 892 893 894 895
    qtest_end();
    test_server_free(s);
}

static void test_flags_mismatch(void)
{
    gchar *path = g_strdup_printf("/%s/vhost-user/flags-mismatch/subprocess",
                                  qtest_get_arch());
    g_test_trap_subprocess(path, 0, 0);
    g_test_trap_assert_passed();
    g_free(path);
}

896 897
#endif

898 899 900 901
static void test_multiqueue(void)
{
    TestServer *s = test_server_new("mq");
    char *cmd;
902 903 904 905
    uint32_t features_mask = ~(QVIRTIO_F_BAD_FEATURE |
                            (1u << VIRTIO_RING_F_INDIRECT_DESC) |
                            (1u << VIRTIO_RING_F_EVENT_IDX));
    s->queues = 2;
906 907
    test_server_listen(s);

908 909 910 911 912
    cmd = g_strdup_printf(QEMU_CMD_MEM QEMU_CMD_CHR QEMU_CMD_NETDEV ",queues=%d "
                          "-device virtio-net-pci,netdev=net0,mq=on,vectors=%d",
                          512, 512, root, s->chr_name,
                          s->socket_path, "", s->chr_name,
                          s->queues, s->queues * 2 + 2);
913 914 915
    qtest_start(cmd);
    g_free(cmd);

916
    init_virtio_dev(s, features_mask);
917

918
    wait_for_rings_started(s, s->queues * 2);
919

920
    uninit_virtio_dev(s);
921 922 923 924 925 926

    qtest_end();

    test_server_free(s);
}

N
Nikolay Nikolaev 已提交
927 928
int main(int argc, char **argv)
{
929
    const char *hugefs;
N
Nikolay Nikolaev 已提交
930
    int ret;
931
    char template[] = "/tmp/vhost-test-XXXXXX";
932 933
    GMainLoop *loop;
    GThread *thread;
N
Nikolay Nikolaev 已提交
934 935 936 937

    g_test_init(&argc, &argv, NULL);

    module_call_init(MODULE_INIT_QOM);
938
    qemu_add_opts(&qemu_chardev_opts);
N
Nikolay Nikolaev 已提交
939

940 941
    tmpfs = mkdtemp(template);
    if (!tmpfs) {
942
        g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno));
943 944 945 946 947 948 949 950 951
    }
    g_assert(tmpfs);

    hugefs = getenv("QTEST_HUGETLBFS_PATH");
    if (hugefs) {
        root = init_hugepagefs(hugefs);
        g_assert(root);
    } else {
        root = tmpfs;
N
Nikolay Nikolaev 已提交
952 953
    }

954
    loop = g_main_loop_new(NULL, FALSE);
N
Nikolay Nikolaev 已提交
955
    /* run the main loop thread so the chardev may operate */
956
    thread = g_thread_new(NULL, thread_function, loop);
N
Nikolay Nikolaev 已提交
957

958
    qtest_add_func("/vhost-user/read-guest-mem", test_read_guest_mem);
959
    qtest_add_func("/vhost-user/migrate", test_migrate);
960
    qtest_add_func("/vhost-user/multiqueue", test_multiqueue);
961

962 963 964 965 966 967 968 969 970 971 972 973 974
#if defined(CONFIG_HAS_GLIB_SUBPROCESS_TESTS)
    /* keeps failing on build-system since Aug 15 2017 */
    if (getenv("QTEST_VHOST_USER_FIXME")) {
        qtest_add_func("/vhost-user/reconnect/subprocess",
                       test_reconnect_subprocess);
        qtest_add_func("/vhost-user/reconnect", test_reconnect);
        qtest_add_func("/vhost-user/connect-fail/subprocess",
                       test_connect_fail_subprocess);
        qtest_add_func("/vhost-user/connect-fail", test_connect_fail);
        qtest_add_func("/vhost-user/flags-mismatch/subprocess",
                       test_flags_mismatch_subprocess);
        qtest_add_func("/vhost-user/flags-mismatch", test_flags_mismatch);
    }
975
#endif
N
Nikolay Nikolaev 已提交
976 977 978 979 980

    ret = g_test_run();

    /* cleanup */

981 982 983 984 985 986 987 988
    /* finish the helper thread and dispatch pending sources */
    g_main_loop_quit(loop);
    g_thread_join(thread);
    while (g_main_context_pending(NULL)) {
        g_main_context_iteration (NULL, TRUE);
    }
    g_main_loop_unref(loop);

989 990 991 992 993 994 995
    ret = rmdir(tmpfs);
    if (ret != 0) {
        g_test_message("unable to rmdir: path (%s): %s\n",
                       tmpfs, strerror(errno));
    }
    g_assert_cmpint(ret, ==, 0);

N
Nikolay Nikolaev 已提交
996 997
    return ret;
}