vhost-user-test.c 26.6 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"
21
#include "qemu/memfd.h"
N
Nikolay Nikolaev 已提交
22
#include "sysemu/sysemu.h"
23 24 25
#include "libqos/libqos.h"
#include "libqos/pci-pc.h"
#include "libqos/virtio-pci.h"
N
Nikolay Nikolaev 已提交
26

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

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

35

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

#define HUGETLBFS_MAGIC       0x958458f6

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

#define VHOST_MEMORY_MAX_NREGIONS    8
49
#define VHOST_MAX_VIRTQUEUES    0x100
N
Nikolay Nikolaev 已提交
50

51
#define VHOST_USER_F_PROTOCOL_FEATURES 30
52
#define VHOST_USER_PROTOCOL_F_MQ 0
53 54 55
#define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1

#define VHOST_LOG_PAGE 0x1000
56

N
Nikolay Nikolaev 已提交
57 58 59 60 61
typedef enum VhostUserRequest {
    VHOST_USER_NONE = 0,
    VHOST_USER_GET_FEATURES = 1,
    VHOST_USER_SET_FEATURES = 2,
    VHOST_USER_SET_OWNER = 3,
62
    VHOST_USER_RESET_OWNER = 4,
N
Nikolay Nikolaev 已提交
63 64 65 66 67 68 69 70 71 72
    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,
73 74
    VHOST_USER_GET_PROTOCOL_FEATURES = 15,
    VHOST_USER_SET_PROTOCOL_FEATURES = 16,
75
    VHOST_USER_GET_QUEUE_NUM = 17,
76
    VHOST_USER_SET_VRING_ENABLE = 18,
N
Nikolay Nikolaev 已提交
77 78 79 80 81 82 83
    VHOST_USER_MAX
} VhostUserRequest;

typedef struct VhostUserMemoryRegion {
    uint64_t guest_phys_addr;
    uint64_t memory_size;
    uint64_t userspace_addr;
84
    uint64_t mmap_offset;
N
Nikolay Nikolaev 已提交
85 86 87 88 89 90 91 92
} VhostUserMemoryRegion;

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

93 94 95 96 97
typedef struct VhostUserLog {
    uint64_t mmap_size;
    uint64_t mmap_offset;
} VhostUserLog;

N
Nikolay Nikolaev 已提交
98 99 100 101 102 103 104 105
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 {
106 107
#define VHOST_USER_VRING_IDX_MASK   (0xff)
#define VHOST_USER_VRING_NOFD_MASK  (0x1<<8)
N
Nikolay Nikolaev 已提交
108 109 110 111
        uint64_t u64;
        struct vhost_vring_state state;
        struct vhost_vring_addr addr;
        VhostUserMemory memory;
112
        VhostUserLog log;
113
    } payload;
N
Nikolay Nikolaev 已提交
114 115 116 117 118 119 120 121 122 123 124 125 126
} 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)
/*****************************************************************************/

127 128 129 130 131 132 133
enum {
    TEST_FLAGS_OK,
    TEST_FLAGS_DISCONNECT,
    TEST_FLAGS_BAD,
    TEST_FLAGS_END,
};

134
typedef struct TestServer {
135
    QPCIBus *bus;
136 137
    QVirtioPCIDevice *dev;
    QVirtQueue *vq[VHOST_MAX_VIRTQUEUES];
138
    gchar *socket_path;
139
    gchar *mig_path;
140
    gchar *chr_name;
141
    CharBackend chr;
142 143 144
    int fds_num;
    int fds[VHOST_MEMORY_MAX_NREGIONS];
    VhostUserMemory memory;
145 146
    GMutex data_mutex;
    GCond data_cond;
147
    int log_fd;
148
    uint64_t rings;
149
    bool test_fail;
150
    int test_flags;
151
    int queues;
152
    QGuestAllocator *alloc;
153
} TestServer;
154

155 156 157 158
static TestServer *test_server_new(const gchar *name);
static void test_server_free(TestServer *server);
static void test_server_listen(TestServer *server);

159 160 161
static const char *tmpfs;
static const char *root;

162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
enum test_memfd {
    TEST_MEMFD_AUTO,
    TEST_MEMFD_YES,
    TEST_MEMFD_NO,
};

static char *get_qemu_cmd(TestServer *s,
                          int mem, enum test_memfd memfd, const char *mem_path,
                          const char *chr_opts, const char *extra)
{
    if (memfd == TEST_MEMFD_AUTO && qemu_memfd_check()) {
        memfd = TEST_MEMFD_YES;
    }

    if (memfd == TEST_MEMFD_YES) {
        return g_strdup_printf(QEMU_CMD_MEMFD QEMU_CMD_CHR
                               QEMU_CMD_NETDEV QEMU_CMD_NET "%s", mem, mem,
                               s->chr_name, s->socket_path,
                               chr_opts, s->chr_name, extra);
    } else {
        return g_strdup_printf(QEMU_CMD_MEM QEMU_CMD_CHR
                               QEMU_CMD_NETDEV QEMU_CMD_NET "%s", mem, mem,
                               mem_path, s->chr_name, s->socket_path,
                               chr_opts, s->chr_name, extra);
    }
}

189
static void init_virtio_dev(TestServer *s, uint32_t features_mask)
190 191
{
    uint32_t features;
192
    int i;
193

194
    s->bus = qpci_init_pc(global_qtest, NULL);
195
    g_assert_nonnull(s->bus);
196

197 198
    s->dev = qvirtio_pci_device_find(s->bus, VIRTIO_ID_NET);
    g_assert_nonnull(s->dev);
199

200 201 202 203
    qvirtio_pci_device_enable(s->dev);
    qvirtio_reset(&s->dev->vdev);
    qvirtio_set_acknowledge(&s->dev->vdev);
    qvirtio_set_driver(&s->dev->vdev);
204

205
    s->alloc = pc_alloc_init(global_qtest);
206 207 208 209 210 211

    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);
212
    features = features & features_mask;
213 214 215 216 217 218 219 220
    qvirtio_set_features(&s->dev->vdev, features);

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

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

222 223 224 225 226 227
    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);
228 229
}

230
static void wait_for_fds(TestServer *s)
N
Nikolay Nikolaev 已提交
231 232 233
{
    gint64 end_time;

234
    g_mutex_lock(&s->data_mutex);
N
Nikolay Nikolaev 已提交
235

236
    end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
237 238
    while (!s->fds_num) {
        if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
N
Nikolay Nikolaev 已提交
239
            /* timeout has passed */
240
            g_assert(s->fds_num);
N
Nikolay Nikolaev 已提交
241 242 243 244 245
            break;
        }
    }

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

249
    g_mutex_unlock(&s->data_mutex);
250 251
}

252
static void read_guest_mem_server(TestServer *s)
253 254 255 256 257
{
    uint32_t *guest_mem;
    int i, j;
    size_t size;

258
    wait_for_fds(s);
259

260
    g_mutex_lock(&s->data_mutex);
261

N
Nikolay Nikolaev 已提交
262
    /* iterate all regions */
263
    for (i = 0; i < s->fds_num; i++) {
N
Nikolay Nikolaev 已提交
264 265

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

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

272 273
        size = s->memory.regions[i].memory_size +
            s->memory.regions[i].mmap_offset;
274 275

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

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

        for (j = 0; j < 256; j++) {
282
            uint32_t a = readl(s->memory.regions[i].guest_phys_addr + j*4);
N
Nikolay Nikolaev 已提交
283 284 285 286 287
            uint32_t b = guest_mem[j];

            g_assert_cmpint(a, ==, b);
        }

288
        munmap(guest_mem, s->memory.regions[i].memory_size);
N
Nikolay Nikolaev 已提交
289 290
    }

291
    g_mutex_unlock(&s->data_mutex);
N
Nikolay Nikolaev 已提交
292 293 294 295
}

static void *thread_function(void *data)
{
296
    GMainLoop *loop = data;
N
Nikolay Nikolaev 已提交
297 298 299 300 301 302 303 304 305 306 307
    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)
{
308
    TestServer *s = opaque;
309
    CharBackend *chr = &s->chr;
N
Nikolay Nikolaev 已提交
310 311 312 313
    VhostUserMsg msg;
    uint8_t *p = (uint8_t *) &msg;
    int fd;

314
    if (s->test_fail) {
315
        qemu_chr_fe_disconnect(chr);
316 317 318 319
        /* now switch to non-failure */
        s->test_fail = false;
    }

N
Nikolay Nikolaev 已提交
320 321 322 323 324
    if (size != VHOST_USER_HDR_SIZE) {
        g_test_message("Wrong message size received %d\n", size);
        return;
    }

325
    g_mutex_lock(&s->data_mutex);
N
Nikolay Nikolaev 已提交
326 327 328 329
    memcpy(p, buf, VHOST_USER_HDR_SIZE);

    if (msg.size) {
        p += VHOST_USER_HDR_SIZE;
330
        size = qemu_chr_fe_read_all(chr, p, msg.size);
331 332 333 334 335
        if (size != msg.size) {
            g_test_message("Wrong message size received %d != %d\n",
                           size, msg.size);
            return;
        }
N
Nikolay Nikolaev 已提交
336 337 338 339
    }

    switch (msg.request) {
    case VHOST_USER_GET_FEATURES:
340 341
        /* send back features to qemu */
        msg.flags |= VHOST_USER_REPLY_MASK;
342 343
        msg.size = sizeof(m.payload.u64);
        msg.payload.u64 = 0x1ULL << VHOST_F_LOG_ALL |
344
            0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
345 346 347
        if (s->queues > 1) {
            msg.payload.u64 |= 0x1ULL << VIRTIO_NET_F_MQ;
        }
348 349 350 351
        if (s->test_flags >= TEST_FLAGS_BAD) {
            msg.payload.u64 = 0;
            s->test_flags = TEST_FLAGS_END;
        }
352
        p = (uint8_t *) &msg;
353
        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
354 355 356
        break;

    case VHOST_USER_SET_FEATURES:
357
	g_assert_cmpint(msg.payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES),
358
			!=, 0ULL);
359
        if (s->test_flags == TEST_FLAGS_DISCONNECT) {
360
            qemu_chr_fe_disconnect(chr);
361 362
            s->test_flags = TEST_FLAGS_BAD;
        }
363 364 365
        break;

    case VHOST_USER_GET_PROTOCOL_FEATURES:
N
Nikolay Nikolaev 已提交
366 367
        /* send back features to qemu */
        msg.flags |= VHOST_USER_REPLY_MASK;
368 369
        msg.size = sizeof(m.payload.u64);
        msg.payload.u64 = 1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD;
370 371 372
        if (s->queues > 1) {
            msg.payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_MQ;
        }
N
Nikolay Nikolaev 已提交
373
        p = (uint8_t *) &msg;
374
        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
N
Nikolay Nikolaev 已提交
375 376 377 378 379
        break;

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

385
        assert(msg.payload.state.index < s->queues * 2);
386
        s->rings &= ~(0x1ULL << msg.payload.state.index);
N
Nikolay Nikolaev 已提交
387 388 389 390
        break;

    case VHOST_USER_SET_MEM_TABLE:
        /* received the mem table */
391
        memcpy(&s->memory, &msg.payload.memory, sizeof(msg.payload.memory));
392
        s->fds_num = qemu_chr_fe_get_msgfds(chr, s->fds,
393
                                            G_N_ELEMENTS(s->fds));
N
Nikolay Nikolaev 已提交
394 395

        /* signal the test that it can continue */
396
        g_cond_signal(&s->data_cond);
N
Nikolay Nikolaev 已提交
397 398 399 400 401
        break;

    case VHOST_USER_SET_VRING_KICK:
    case VHOST_USER_SET_VRING_CALL:
        /* consume the fd */
402
        qemu_chr_fe_get_msgfds(chr, &fd, 1);
N
Nikolay Nikolaev 已提交
403 404 405 406 407 408 409
        /*
         * 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;
410 411 412 413 414 415

    case VHOST_USER_SET_LOG_BASE:
        if (s->log_fd != -1) {
            close(s->log_fd);
            s->log_fd = -1;
        }
416
        qemu_chr_fe_get_msgfds(chr, &s->log_fd, 1);
417 418 419
        msg.flags |= VHOST_USER_REPLY_MASK;
        msg.size = 0;
        p = (uint8_t *) &msg;
420
        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE);
421 422 423 424

        g_cond_signal(&s->data_cond);
        break;

425
    case VHOST_USER_SET_VRING_BASE:
426
        assert(msg.payload.state.index < s->queues * 2);
427
        s->rings |= 0x1ULL << msg.payload.state.index;
428 429
        break;

430 431 432 433 434
    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;
435
        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
436 437
        break;

N
Nikolay Nikolaev 已提交
438 439 440
    default:
        break;
    }
441 442

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

445
static const char *init_hugepagefs(const char *path)
N
Nikolay Nikolaev 已提交
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
{
    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;
}

472
static TestServer *test_server_new(const gchar *name)
473 474 475 476
{
    TestServer *server = g_new0(TestServer, 1);

    server->socket_path = g_strdup_printf("%s/%s.sock", tmpfs, name);
477
    server->mig_path = g_strdup_printf("%s/%s.mig", tmpfs, name);
478 479 480 481 482
    server->chr_name = g_strdup_printf("chr-%s", name);

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

483
    server->log_fd = -1;
484
    server->queues = 1;
485

486 487 488
    return server;
}

489 490 491 492 493 494 495 496 497 498
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;
    }
}

499 500 501
static void test_server_create_chr(TestServer *server, const gchar *opt)
{
    gchar *chr_path;
502
    Chardev *chr;
503

504
    chr_path = g_strdup_printf("unix:%s%s", server->socket_path, opt);
505
    chr = qemu_chr_new(server->chr_name, chr_path);
506 507
    g_free(chr_path);

508
    g_assert_nonnull(chr);
509 510
    qemu_chr_fe_init(&server->chr, chr, &error_abort);
    qemu_chr_fe_set_handlers(&server->chr, chr_can_read, chr_read,
511
                             chr_event, NULL, server, NULL, true);
512 513 514 515 516 517 518
}

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

519
static gboolean _test_server_free(TestServer *server)
520 521 522
{
    int i;

523
    qemu_chr_fe_deinit(&server->chr, true);
524 525 526 527 528

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

529 530 531 532
    if (server->log_fd != -1) {
        close(server->log_fd);
    }

533 534 535
    unlink(server->socket_path);
    g_free(server->socket_path);

536 537 538
    unlink(server->mig_path);
    g_free(server->mig_path);

539
    g_free(server->chr_name);
540 541
    qpci_free_pc(server->bus);

542
    g_free(server);
543 544 545 546 547 548 549

    return FALSE;
}

static void test_server_free(TestServer *server)
{
    g_idle_add((GSourceFunc)_test_server_free, server);
550 551
}

552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
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);
}

569
static void write_guest_mem(TestServer *s, uint32_t seed)
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 609 610 611 612 613 614 615 616 617 618 619
{
    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;
}

620 621 622 623 624 625 626 627 628 629
typedef struct TestMigrateSource {
    GSource source;
    TestServer *src;
    TestServer *dest;
} TestMigrateSource;

static gboolean
test_migrate_source_check(GSource *source)
{
    TestMigrateSource *t = (TestMigrateSource *)source;
630
    gboolean overlap = t->src->rings && t->dest->rings;
631 632 633 634 635 636 637

    g_assert(!overlap);

    return FALSE;
}

GSourceFuncs test_migrate_source_funcs = {
638
    .check = test_migrate_source_check,
639 640
};

641
static void test_read_guest_mem(const void *arg)
642
{
643
    enum test_memfd memfd = GPOINTER_TO_INT(arg);
644 645 646 647
    TestServer *server = NULL;
    char *qemu_cmd = NULL;
    QTestState *s = NULL;

648 649
    server = test_server_new(memfd == TEST_MEMFD_YES ?
                             "read-guest-memfd" : "read-guest-mem");
650 651
    test_server_listen(server);

652
    qemu_cmd = get_qemu_cmd(server, 512, memfd, root, "", "");
653 654 655 656

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

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

659
    read_guest_mem_server(server);
660

661 662
    uninit_virtio_dev(server);

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

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

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

682
    cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, "", "");
683 684 685
    from = qtest_start(cmd);
    g_free(cmd);

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

691 692 693
    tmp = g_strdup_printf(" -incoming %s", uri);
    cmd = get_qemu_cmd(dest, 2, TEST_MEMFD_AUTO, root, "", tmp);
    g_free(tmp);
694 695 696
    to = qtest_init(cmd);
    g_free(cmd);

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

703 704 705 706 707
    /* 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"));
708
    qobject_unref(rsp);
709 710 711 712 713 714 715

    cmd = g_strdup_printf("{ 'execute': 'migrate',"
                          "'arguments': { 'uri': '%s' } }",
                          uri);
    rsp = qmp(cmd);
    g_free(cmd);
    g_assert(qdict_haskey(rsp, "return"));
716
    qobject_unref(rsp);
717 718 719 720 721 722 723 724 725 726 727 728 729 730 731

    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"));
732
    qobject_unref(rsp);
733 734 735 736 737 738

    qmp_eventwait("STOP");

    global_qtest = to;
    qmp_eventwait("RESUME");

739
    read_guest_mem_server(dest);
740

741 742
    uninit_virtio_dev(s);

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

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

    global_qtest = global;
}

755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771
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);
}

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

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

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

    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);
806
    cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, ",server", "");
807 808 809
    qtest_start(cmd);
    g_free(cmd);

810
    init_virtio_dev(s, 1u << VIRTIO_NET_F_MAC);
811 812 813 814 815 816 817 818 819 820
    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);

821 822
    uninit_virtio_dev(s);

823 824 825 826 827 828 829 830 831 832 833
    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();
834
    g_free(path);
835
}
836 837 838 839 840 841 842 843

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);
844
    cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, ",server", "");
845 846 847
    qtest_start(cmd);
    g_free(cmd);

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

852 853
    uninit_virtio_dev(s);

854 855 856 857 858 859 860 861 862 863 864 865 866
    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);
}

867 868 869 870 871 872 873
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);
874
    cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, ",server", "");
875 876 877
    qtest_start(cmd);
    g_free(cmd);

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

882 883
    uninit_virtio_dev(s);

884 885 886 887 888 889 890 891 892 893 894 895 896
    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);
}

897 898
#endif

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

909 910 911 912 913 914 915 916 917 918 919 920 921 922 923
    if (qemu_memfd_check()) {
        cmd = g_strdup_printf(
            QEMU_CMD_MEMFD QEMU_CMD_CHR QEMU_CMD_NETDEV ",queues=%d "
            "-device virtio-net-pci,netdev=net0,mq=on,vectors=%d",
            512, 512, s->chr_name,
            s->socket_path, "", s->chr_name,
            s->queues, s->queues * 2 + 2);
    } else {
        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);
    }
924 925 926
    qtest_start(cmd);
    g_free(cmd);

927
    init_virtio_dev(s, features_mask);
928

929
    wait_for_rings_started(s, s->queues * 2);
930

931
    uninit_virtio_dev(s);
932 933 934 935 936 937

    qtest_end();

    test_server_free(s);
}

N
Nikolay Nikolaev 已提交
938 939
int main(int argc, char **argv)
{
940
    const char *hugefs;
N
Nikolay Nikolaev 已提交
941
    int ret;
942
    char template[] = "/tmp/vhost-test-XXXXXX";
943 944
    GMainLoop *loop;
    GThread *thread;
N
Nikolay Nikolaev 已提交
945 946 947 948

    g_test_init(&argc, &argv, NULL);

    module_call_init(MODULE_INIT_QOM);
949
    qemu_add_opts(&qemu_chardev_opts);
N
Nikolay Nikolaev 已提交
950

951 952
    tmpfs = mkdtemp(template);
    if (!tmpfs) {
953
        g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno));
954 955 956 957 958 959 960 961 962
    }
    g_assert(tmpfs);

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

965
    loop = g_main_loop_new(NULL, FALSE);
N
Nikolay Nikolaev 已提交
966
    /* run the main loop thread so the chardev may operate */
967
    thread = g_thread_new(NULL, thread_function, loop);
N
Nikolay Nikolaev 已提交
968

969 970 971 972 973 974 975
    if (qemu_memfd_check()) {
        qtest_add_data_func("/vhost-user/read-guest-mem/memfd",
                            GINT_TO_POINTER(TEST_MEMFD_YES),
                            test_read_guest_mem);
    }
    qtest_add_data_func("/vhost-user/read-guest-mem/memfile",
                        GINT_TO_POINTER(TEST_MEMFD_NO), test_read_guest_mem);
976
    qtest_add_func("/vhost-user/migrate", test_migrate);
977
    qtest_add_func("/vhost-user/multiqueue", test_multiqueue);
978

979 980 981 982 983 984 985 986 987 988 989 990 991
#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);
    }
992
#endif
N
Nikolay Nikolaev 已提交
993 994 995 996 997

    ret = g_test_run();

    /* cleanup */

998 999 1000 1001 1002 1003 1004 1005
    /* 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);

1006 1007 1008 1009 1010 1011 1012
    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 已提交
1013 1014
    return ret;
}