vhost-user-test.c 26.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"
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
#define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1
54
#define VHOST_USER_PROTOCOL_F_CROSS_ENDIAN   6
55 56

#define VHOST_LOG_PAGE 0x1000
57

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

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

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

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

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

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

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

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

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

163 164 165 166 167 168 169 170 171 172
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)
{
173
    if (memfd == TEST_MEMFD_AUTO && qemu_memfd_check(0)) {
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
        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);
    }
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

259
    wait_for_fds(s);
260

261
    g_mutex_lock(&s->data_mutex);
262

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

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

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

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

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

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

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

            g_assert_cmpint(a, ==, b);
        }

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

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

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

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

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

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

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

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

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

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

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

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

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

        /* signal the test that it can continue */
399
        g_cond_broadcast(&s->data_cond);
N
Nikolay Nikolaev 已提交
400 401 402 403 404
        break;

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

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

425
        g_cond_broadcast(&s->data_cond);
426 427
        break;

428
    case VHOST_USER_SET_VRING_BASE:
429
        assert(msg.payload.state.index < s->queues * 2);
430
        s->rings |= 0x1ULL << msg.payload.state.index;
431
        g_cond_broadcast(&s->data_cond);
432 433
        break;

434 435 436 437 438
    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;
439
        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
440 441
        break;

N
Nikolay Nikolaev 已提交
442 443 444
    default:
        break;
    }
445 446

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

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

476
static TestServer *test_server_new(const gchar *name)
477 478 479 480
{
    TestServer *server = g_new0(TestServer, 1);

    server->socket_path = g_strdup_printf("%s/%s.sock", tmpfs, name);
481
    server->mig_path = g_strdup_printf("%s/%s.mig", tmpfs, name);
482 483 484 485 486
    server->chr_name = g_strdup_printf("chr-%s", name);

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

487
    server->log_fd = -1;
488
    server->queues = 1;
489

490 491 492
    return server;
}

493 494 495 496 497 498 499 500 501 502
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;
    }
}

503 504 505
static void test_server_create_chr(TestServer *server, const gchar *opt)
{
    gchar *chr_path;
506
    Chardev *chr;
507

508
    chr_path = g_strdup_printf("unix:%s%s", server->socket_path, opt);
509
    chr = qemu_chr_new(server->chr_name, chr_path);
510 511
    g_free(chr_path);

512
    g_assert_nonnull(chr);
513 514
    qemu_chr_fe_init(&server->chr, chr, &error_abort);
    qemu_chr_fe_set_handlers(&server->chr, chr_can_read, chr_read,
515
                             chr_event, NULL, server, NULL, true);
516 517 518 519 520 521 522
}

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

523
static gboolean _test_server_free(TestServer *server)
524 525 526
{
    int i;

527
    qemu_chr_fe_deinit(&server->chr, true);
528 529 530 531 532

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

533 534 535 536
    if (server->log_fd != -1) {
        close(server->log_fd);
    }

537 538 539
    unlink(server->socket_path);
    g_free(server->socket_path);

540 541 542
    unlink(server->mig_path);
    g_free(server->mig_path);

543
    g_free(server->chr_name);
544
    g_assert(server->bus);
545 546
    qpci_free_pc(server->bus);

547
    g_free(server);
548 549 550 551 552 553 554

    return FALSE;
}

static void test_server_free(TestServer *server)
{
    g_idle_add((GSourceFunc)_test_server_free, server);
555 556
}

557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573
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);
}

574
static void write_guest_mem(TestServer *s, uint32_t seed)
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 620 621 622 623 624
{
    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;
}

625 626 627 628 629 630 631 632 633 634
typedef struct TestMigrateSource {
    GSource source;
    TestServer *src;
    TestServer *dest;
} TestMigrateSource;

static gboolean
test_migrate_source_check(GSource *source)
{
    TestMigrateSource *t = (TestMigrateSource *)source;
635
    gboolean overlap = t->src->rings && t->dest->rings;
636 637 638 639 640 641 642

    g_assert(!overlap);

    return FALSE;
}

GSourceFuncs test_migrate_source_funcs = {
643
    .check = test_migrate_source_check,
644 645
};

646
static void test_read_guest_mem(const void *arg)
647
{
648
    enum test_memfd memfd = GPOINTER_TO_INT(arg);
649 650 651 652
    TestServer *server = NULL;
    char *qemu_cmd = NULL;
    QTestState *s = NULL;

653 654
    server = test_server_new(memfd == TEST_MEMFD_YES ?
                             "read-guest-memfd" : "read-guest-mem");
655 656
    test_server_listen(server);

657
    qemu_cmd = get_qemu_cmd(server, 512, memfd, root, "", "");
658 659 660 661

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

662
    init_virtio_dev(server, 1u << VIRTIO_NET_F_MAC);
663

664
    read_guest_mem_server(server);
665

666 667
    uninit_virtio_dev(server);

668 669 670 671
    qtest_quit(s);
    test_server_free(server);
}

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

684 685 686
    test_server_listen(s);
    test_server_listen(dest);

687
    cmd = get_qemu_cmd(s, 2, TEST_MEMFD_AUTO, root, "", "");
688 689 690
    from = qtest_start(cmd);
    g_free(cmd);

691
    init_virtio_dev(s, 1u << VIRTIO_NET_F_MAC);
692
    init_virtio_dev(dest, 1u << VIRTIO_NET_F_MAC);
693 694 695 696
    wait_for_fds(s);
    size = get_log_size(s);
    g_assert_cmpint(size, ==, (2 * 1024 * 1024) / (VHOST_LOG_PAGE * 8));

697 698 699
    tmp = g_strdup_printf(" -incoming %s", uri);
    cmd = get_qemu_cmd(dest, 2, TEST_MEMFD_AUTO, root, "", tmp);
    g_free(tmp);
700 701 702
    to = qtest_init(cmd);
    g_free(cmd);

703 704 705 706 707 708
    source = g_source_new(&test_migrate_source_funcs,
                          sizeof(TestMigrateSource));
    ((TestMigrateSource *)source)->src = s;
    ((TestMigrateSource *)source)->dest = dest;
    g_source_attach(source, NULL);

709 710 711 712 713
    /* 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"));
714
    qobject_unref(rsp);
715

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

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

    qmp_eventwait("STOP");

    global_qtest = to;
    qmp_eventwait("RESUME");

741
    read_guest_mem_server(dest);
742

743
    uninit_virtio_dev(s);
744
    uninit_virtio_dev(dest);
745

746 747 748
    g_source_destroy(source);
    g_source_unref(source);

749 750 751 752
    qtest_quit(to);
    test_server_free(dest);
    qtest_quit(from);
    test_server_free(s);
753
    g_free(uri);
754 755 756 757

    global_qtest = global;
}

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

775 776 777 778 779
static inline void test_server_connect(TestServer *server)
{
    test_server_create_chr(server, ",reconnect=1");
}

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

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

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

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

823 824
    uninit_virtio_dev(s);

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

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

850
    init_virtio_dev(s, 1u << VIRTIO_NET_F_MAC);
851 852 853
    wait_for_fds(s);
    wait_for_rings_started(s, 2);

854 855
    uninit_virtio_dev(s);

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

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

880
    init_virtio_dev(s, 1u << VIRTIO_NET_F_MAC);
881 882 883
    wait_for_fds(s);
    wait_for_rings_started(s, 2);

884 885
    uninit_virtio_dev(s);

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

899

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

910
    if (qemu_memfd_check(0)) {
911 912 913 914 915 916 917 918 919 920 921 922 923 924
        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);
    }
925 926 927
    qtest_start(cmd);
    g_free(cmd);

928
    init_virtio_dev(s, features_mask);
929

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

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

    qtest_end();

    test_server_free(s);
}

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

    g_test_init(&argc, &argv, NULL);

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

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

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

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

970
    if (qemu_memfd_check(0)) {
971 972 973 974 975 976
        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);
977
    qtest_add_func("/vhost-user/migrate", test_migrate);
978
    qtest_add_func("/vhost-user/multiqueue", test_multiqueue);
979

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

    ret = g_test_run();

    /* cleanup */

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

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