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 14
#include "libqtest.h"
#include "qemu/option.h"
15
#include "qemu/range.h"
16
#include "qemu/sockets.h"
N
Nikolay Nikolaev 已提交
17 18
#include "sysemu/char.h"
#include "sysemu/sysemu.h"
19 20 21
#include "libqos/libqos.h"
#include "libqos/pci-pc.h"
#include "libqos/virtio-pci.h"
N
Nikolay Nikolaev 已提交
22

23 24 25 26 27
#include "libqos/pci-pc.h"
#include "libqos/virtio-pci.h"
#include "libqos/malloc-pc.h"
#include "hw/virtio/virtio-net.h"

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

33 34 35 36 37 38 39 40 41
/* 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

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

48
#define QEMU_CMD        QEMU_CMD_MEM QEMU_CMD_CHR \
49
                        QEMU_CMD_NETDEV QEMU_CMD_NET
N
Nikolay Nikolaev 已提交
50 51 52 53 54 55 56

#define HUGETLBFS_MAGIC       0x958458f6

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

#define VHOST_MEMORY_MAX_NREGIONS    8

57
#define VHOST_USER_F_PROTOCOL_FEATURES 30
58
#define VHOST_USER_PROTOCOL_F_MQ 0
59 60 61
#define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1

#define VHOST_LOG_PAGE 0x1000
62

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

typedef struct VhostUserMemoryRegion {
    uint64_t guest_phys_addr;
    uint64_t memory_size;
    uint64_t userspace_addr;
90
    uint64_t mmap_offset;
N
Nikolay Nikolaev 已提交
91 92 93 94 95 96 97 98
} VhostUserMemoryRegion;

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

99 100 101 102 103
typedef struct VhostUserLog {
    uint64_t mmap_size;
    uint64_t mmap_offset;
} VhostUserLog;

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

133 134 135 136 137 138 139
enum {
    TEST_FLAGS_OK,
    TEST_FLAGS_DISCONNECT,
    TEST_FLAGS_BAD,
    TEST_FLAGS_END,
};

140 141
typedef struct TestServer {
    gchar *socket_path;
142
    gchar *mig_path;
143 144 145 146 147
    gchar *chr_name;
    CharDriverState *chr;
    int fds_num;
    int fds[VHOST_MEMORY_MAX_NREGIONS];
    VhostUserMemory memory;
148 149
    CompatGMutex data_mutex;
    CompatGCond data_cond;
150
    int log_fd;
151
    uint64_t rings;
152
    bool test_fail;
153
    int test_flags;
154
    int queues;
155
} TestServer;
156

157 158 159
static const char *tmpfs;
static const char *root;

160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
static void init_virtio_dev(TestServer *s)
{
    QPCIBus *bus;
    QVirtioPCIDevice *dev;
    uint32_t features;

    bus = qpci_init_pc();
    g_assert_nonnull(bus);

    dev = qvirtio_pci_device_find(bus, VIRTIO_ID_NET);
    g_assert_nonnull(dev);

    qvirtio_pci_device_enable(dev);
    qvirtio_reset(&qvirtio_pci, &dev->vdev);
    qvirtio_set_acknowledge(&qvirtio_pci, &dev->vdev);
    qvirtio_set_driver(&qvirtio_pci, &dev->vdev);

    features = qvirtio_get_features(&qvirtio_pci, &dev->vdev);
    features = features & VIRTIO_NET_F_MAC;
    qvirtio_set_features(&qvirtio_pci, &dev->vdev, features);

    qvirtio_set_driver_ok(&qvirtio_pci, &dev->vdev);
}

184
static void wait_for_fds(TestServer *s)
N
Nikolay Nikolaev 已提交
185 186 187
{
    gint64 end_time;

188
    g_mutex_lock(&s->data_mutex);
N
Nikolay Nikolaev 已提交
189

190
    end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
191 192
    while (!s->fds_num) {
        if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
N
Nikolay Nikolaev 已提交
193
            /* timeout has passed */
194
            g_assert(s->fds_num);
N
Nikolay Nikolaev 已提交
195 196 197 198 199
            break;
        }
    }

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

203
    g_mutex_unlock(&s->data_mutex);
204 205
}

206
static void read_guest_mem(const void *data)
207
{
208
    TestServer *s = (void *)data;
209 210 211 212
    uint32_t *guest_mem;
    int i, j;
    size_t size;

213
    wait_for_fds(s);
214

215
    g_mutex_lock(&s->data_mutex);
216

N
Nikolay Nikolaev 已提交
217
    /* iterate all regions */
218
    for (i = 0; i < s->fds_num; i++) {
N
Nikolay Nikolaev 已提交
219 220

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

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

227 228
        size = s->memory.regions[i].memory_size +
            s->memory.regions[i].mmap_offset;
229 230

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

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

        for (j = 0; j < 256; j++) {
237
            uint32_t a = readl(s->memory.regions[i].guest_phys_addr + j*4);
N
Nikolay Nikolaev 已提交
238 239 240 241 242
            uint32_t b = guest_mem[j];

            g_assert_cmpint(a, ==, b);
        }

243
        munmap(guest_mem, s->memory.regions[i].memory_size);
N
Nikolay Nikolaev 已提交
244 245
    }

246
    g_mutex_unlock(&s->data_mutex);
N
Nikolay Nikolaev 已提交
247 248 249 250
}

static void *thread_function(void *data)
{
251
    GMainLoop *loop = data;
N
Nikolay Nikolaev 已提交
252 253 254 255 256 257 258 259 260 261 262
    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)
{
263 264
    TestServer *s = opaque;
    CharDriverState *chr = s->chr;
N
Nikolay Nikolaev 已提交
265 266 267 268
    VhostUserMsg msg;
    uint8_t *p = (uint8_t *) &msg;
    int fd;

269 270 271 272 273 274
    if (s->test_fail) {
        qemu_chr_disconnect(chr);
        /* now switch to non-failure */
        s->test_fail = false;
    }

N
Nikolay Nikolaev 已提交
275 276 277 278 279
    if (size != VHOST_USER_HDR_SIZE) {
        g_test_message("Wrong message size received %d\n", size);
        return;
    }

280
    g_mutex_lock(&s->data_mutex);
N
Nikolay Nikolaev 已提交
281 282 283 284
    memcpy(p, buf, VHOST_USER_HDR_SIZE);

    if (msg.size) {
        p += VHOST_USER_HDR_SIZE;
285 286 287 288 289 290
        size = qemu_chr_fe_read_all(chr, p, msg.size);
        if (size != msg.size) {
            g_test_message("Wrong message size received %d != %d\n",
                           size, msg.size);
            return;
        }
N
Nikolay Nikolaev 已提交
291 292 293 294
    }

    switch (msg.request) {
    case VHOST_USER_GET_FEATURES:
295 296
        /* send back features to qemu */
        msg.flags |= VHOST_USER_REPLY_MASK;
297 298
        msg.size = sizeof(m.payload.u64);
        msg.payload.u64 = 0x1ULL << VHOST_F_LOG_ALL |
299
            0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
300 301 302
        if (s->queues > 1) {
            msg.payload.u64 |= 0x1ULL << VIRTIO_NET_F_MQ;
        }
303 304 305 306
        if (s->test_flags >= TEST_FLAGS_BAD) {
            msg.payload.u64 = 0;
            s->test_flags = TEST_FLAGS_END;
        }
307 308 309 310 311
        p = (uint8_t *) &msg;
        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
        break;

    case VHOST_USER_SET_FEATURES:
312
	g_assert_cmpint(msg.payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES),
313
			!=, 0ULL);
314 315 316 317
        if (s->test_flags == TEST_FLAGS_DISCONNECT) {
            qemu_chr_disconnect(chr);
            s->test_flags = TEST_FLAGS_BAD;
        }
318 319 320
        break;

    case VHOST_USER_GET_PROTOCOL_FEATURES:
N
Nikolay Nikolaev 已提交
321 322
        /* send back features to qemu */
        msg.flags |= VHOST_USER_REPLY_MASK;
323 324
        msg.size = sizeof(m.payload.u64);
        msg.payload.u64 = 1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD;
325 326 327
        if (s->queues > 1) {
            msg.payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_MQ;
        }
N
Nikolay Nikolaev 已提交
328 329 330 331 332 333 334
        p = (uint8_t *) &msg;
        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
        break;

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

340
        assert(msg.payload.state.index < s->queues * 2);
341
        s->rings &= ~(0x1ULL << msg.payload.state.index);
N
Nikolay Nikolaev 已提交
342 343 344 345
        break;

    case VHOST_USER_SET_MEM_TABLE:
        /* received the mem table */
346
        memcpy(&s->memory, &msg.payload.memory, sizeof(msg.payload.memory));
347
        s->fds_num = qemu_chr_fe_get_msgfds(chr, s->fds, G_N_ELEMENTS(s->fds));
N
Nikolay Nikolaev 已提交
348 349

        /* signal the test that it can continue */
350
        g_cond_signal(&s->data_cond);
N
Nikolay Nikolaev 已提交
351 352 353 354 355 356 357 358 359 360 361 362 363
        break;

    case VHOST_USER_SET_VRING_KICK:
    case VHOST_USER_SET_VRING_CALL:
        /* consume the fd */
        qemu_chr_fe_get_msgfds(chr, &fd, 1);
        /*
         * 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;
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378

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

        g_cond_signal(&s->data_cond);
        break;

379
    case VHOST_USER_SET_VRING_BASE:
380
        assert(msg.payload.state.index < s->queues * 2);
381
        s->rings |= 0x1ULL << msg.payload.state.index;
382 383
        break;

384 385 386 387 388 389 390 391
    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;
        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
        break;

N
Nikolay Nikolaev 已提交
392 393 394
    default:
        break;
    }
395 396

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

399
static const char *init_hugepagefs(const char *path)
N
Nikolay Nikolaev 已提交
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
{
    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;
}

426
static TestServer *test_server_new(const gchar *name)
427 428 429 430
{
    TestServer *server = g_new0(TestServer, 1);

    server->socket_path = g_strdup_printf("%s/%s.sock", tmpfs, name);
431
    server->mig_path = g_strdup_printf("%s/%s.mig", tmpfs, name);
432 433 434 435 436
    server->chr_name = g_strdup_printf("chr-%s", name);

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

437
    server->log_fd = -1;
438
    server->queues = 1;
439

440 441 442
    return server;
}

443 444 445 446 447 448 449 450 451 452
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;
    }
}

453 454 455
static void test_server_create_chr(TestServer *server, const gchar *opt)
{
    gchar *chr_path;
456

457 458 459 460
    chr_path = g_strdup_printf("unix:%s%s", server->socket_path, opt);
    server->chr = qemu_chr_new(server->chr_name, chr_path, NULL);
    g_free(chr_path);

461 462
    qemu_chr_add_handlers(server->chr, chr_can_read, chr_read,
                          chr_event, server);
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
}

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

static inline void test_server_connect(TestServer *server)
{
    test_server_create_chr(server, ",reconnect=1");
}

#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__)
482

483
static gboolean _test_server_free(TestServer *server)
484 485 486 487 488 489 490 491 492
{
    int i;

    qemu_chr_delete(server->chr);

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

493 494 495 496
    if (server->log_fd != -1) {
        close(server->log_fd);
    }

497 498 499
    unlink(server->socket_path);
    g_free(server->socket_path);

500 501 502
    unlink(server->mig_path);
    g_free(server->mig_path);

503
    g_free(server->chr_name);
504
    g_free(server);
505 506 507 508 509 510 511

    return FALSE;
}

static void test_server_free(TestServer *server)
{
    g_idle_add((GSourceFunc)_test_server_free, server);
512 513
}

514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
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);
}

531
static void write_guest_mem(TestServer *s, uint32_t seed)
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
{
    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;
}

582 583 584 585 586 587 588 589 590 591
typedef struct TestMigrateSource {
    GSource source;
    TestServer *src;
    TestServer *dest;
} TestMigrateSource;

static gboolean
test_migrate_source_check(GSource *source)
{
    TestMigrateSource *t = (TestMigrateSource *)source;
592
    gboolean overlap = t->src->rings && t->dest->rings;
593 594 595 596 597 598

    g_assert(!overlap);

    return FALSE;
}

599 600 601 602 603 604 605 606 607 608 609
#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

610
GSourceFuncs test_migrate_source_funcs = {
611 612 613 614
#if !GLIB_CHECK_VERSION(2,36,0)
    .prepare = test_migrate_source_prepare,
#endif
    .check = test_migrate_source_check,
615 616
};

617 618 619 620
static void test_migrate(void)
{
    TestServer *s = test_server_new("src");
    TestServer *dest = test_server_new("dest");
621
    char *uri = g_strdup_printf("%s%s", "unix:", dest->mig_path);
622
    QTestState *global = global_qtest, *from, *to;
623
    GSource *source;
624 625 626 627 628
    gchar *cmd;
    QDict *rsp;
    guint8 *log;
    guint64 size;

629 630 631 632
    test_server_listen(s);
    test_server_listen(dest);

    cmd = GET_QEMU_CMDE(s, 2, "", "");
633 634 635
    from = qtest_start(cmd);
    g_free(cmd);

636
    init_virtio_dev(s);
637 638 639 640
    wait_for_fds(s);
    size = get_log_size(s);
    g_assert_cmpint(size, ==, (2 * 1024 * 1024) / (VHOST_LOG_PAGE * 8));

641
    cmd = GET_QEMU_CMDE(dest, 2, "", " -incoming %s", uri);
642 643 644
    to = qtest_init(cmd);
    g_free(cmd);

645 646 647 648 649 650
    source = g_source_new(&test_migrate_source_funcs,
                          sizeof(TestMigrateSource));
    ((TestMigrateSource *)source)->src = s;
    ((TestMigrateSource *)source)->dest = dest;
    g_source_attach(source, NULL);

651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688
    /* 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");

    read_guest_mem(dest);

689 690 691
    g_source_destroy(source);
    g_source_unref(source);

692 693 694 695
    qtest_quit(to);
    test_server_free(dest);
    qtest_quit(from);
    test_server_free(s);
696
    g_free(uri);
697 698 699 700

    global_qtest = global;
}

701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717
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);
}

718
#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750
static gboolean
reconnect_cb(gpointer user_data)
{
    TestServer *s = user_data;

    qemu_chr_disconnect(s->chr);

    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);
    cmd = GET_QEMU_CMDE(s, 2, ",server", "");
    qtest_start(cmd);
    g_free(cmd);

751
    init_virtio_dev(s);
752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772
    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);

    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();
773
    g_free(path);
774
}
775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803

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);
    cmd = GET_QEMU_CMDE(s, 2, ",server", "");
    qtest_start(cmd);
    g_free(cmd);

    init_virtio_dev(s);
    wait_for_fds(s);
    wait_for_rings_started(s, 2);

    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);
}

804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831
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);
    cmd = GET_QEMU_CMDE(s, 2, ",server", "");
    qtest_start(cmd);
    g_free(cmd);

    init_virtio_dev(s);
    wait_for_fds(s);
    wait_for_rings_started(s, 2);

    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);
}

832 833
#endif

834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912
static QVirtioPCIDevice *virtio_net_pci_init(QPCIBus *bus, int slot)
{
    QVirtioPCIDevice *dev;

    dev = qvirtio_pci_device_find(bus, VIRTIO_ID_NET);
    g_assert(dev != NULL);
    g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_NET);

    qvirtio_pci_device_enable(dev);
    qvirtio_reset(&qvirtio_pci, &dev->vdev);
    qvirtio_set_acknowledge(&qvirtio_pci, &dev->vdev);
    qvirtio_set_driver(&qvirtio_pci, &dev->vdev);

    return dev;
}

static void driver_init(const QVirtioBus *bus, QVirtioDevice *dev)
{
    uint32_t features;

    features = qvirtio_get_features(bus, dev);
    features = features & ~(QVIRTIO_F_BAD_FEATURE |
                            (1u << VIRTIO_RING_F_INDIRECT_DESC) |
                            (1u << VIRTIO_RING_F_EVENT_IDX));
    qvirtio_set_features(bus, dev, features);

    qvirtio_set_driver_ok(bus, dev);
}

#define PCI_SLOT                0x04

static void test_multiqueue(void)
{
    const int queues = 2;
    TestServer *s = test_server_new("mq");
    QVirtioPCIDevice *dev;
    QPCIBus *bus;
    QVirtQueuePCI *vq[queues * 2];
    QGuestAllocator *alloc;
    char *cmd;
    int i;

    s->queues = queues;
    test_server_listen(s);

    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,
                          queues, queues * 2 + 2);
    qtest_start(cmd);
    g_free(cmd);

    bus = qpci_init_pc();
    dev = virtio_net_pci_init(bus, PCI_SLOT);

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

    driver_init(&qvirtio_pci, &dev->vdev);
    wait_for_rings_started(s, queues * 2);

    /* End test */
    for (i = 0; i < queues * 2; i++) {
        qvirtqueue_cleanup(&qvirtio_pci, &vq[i]->vq, alloc);
    }
    pc_alloc_uninit(alloc);
    qvirtio_pci_device_disable(dev);
    g_free(dev->pdev);
    g_free(dev);
    qpci_free_pc(bus);
    qtest_end();

    test_server_free(s);
}

N
Nikolay Nikolaev 已提交
913 914 915
int main(int argc, char **argv)
{
    QTestState *s = NULL;
916
    TestServer *server = NULL;
917
    const char *hugefs;
918
    char *qemu_cmd = NULL;
N
Nikolay Nikolaev 已提交
919
    int ret;
920
    char template[] = "/tmp/vhost-test-XXXXXX";
921 922
    GMainLoop *loop;
    GThread *thread;
N
Nikolay Nikolaev 已提交
923 924 925 926

    g_test_init(&argc, &argv, NULL);

    module_call_init(MODULE_INIT_QOM);
927
    qemu_add_opts(&qemu_chardev_opts);
N
Nikolay Nikolaev 已提交
928

929 930
    tmpfs = mkdtemp(template);
    if (!tmpfs) {
931
        g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno));
932 933 934 935 936 937 938 939 940
    }
    g_assert(tmpfs);

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

943
    server = test_server_new("test");
944
    test_server_listen(server);
N
Nikolay Nikolaev 已提交
945

946
    loop = g_main_loop_new(NULL, FALSE);
N
Nikolay Nikolaev 已提交
947
    /* run the main loop thread so the chardev may operate */
948
    thread = g_thread_new(NULL, thread_function, loop);
N
Nikolay Nikolaev 已提交
949

950
    qemu_cmd = GET_QEMU_CMD(server);
951

N
Nikolay Nikolaev 已提交
952 953
    s = qtest_start(qemu_cmd);
    g_free(qemu_cmd);
954
    init_virtio_dev(server);
N
Nikolay Nikolaev 已提交
955

956
    qtest_add_data_func("/vhost-user/read-guest-mem", server, read_guest_mem);
957
    qtest_add_func("/vhost-user/migrate", test_migrate);
958
    qtest_add_func("/vhost-user/multiqueue", test_multiqueue);
959 960 961 962
#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
    qtest_add_func("/vhost-user/reconnect/subprocess",
                   test_reconnect_subprocess);
    qtest_add_func("/vhost-user/reconnect", test_reconnect);
963 964 965
    qtest_add_func("/vhost-user/connect-fail/subprocess",
                   test_connect_fail_subprocess);
    qtest_add_func("/vhost-user/connect-fail", test_connect_fail);
966 967 968
    qtest_add_func("/vhost-user/flags-mismatch/subprocess",
                   test_flags_mismatch_subprocess);
    qtest_add_func("/vhost-user/flags-mismatch", test_flags_mismatch);
969
#endif
N
Nikolay Nikolaev 已提交
970 971 972 973 974 975 976 977

    ret = g_test_run();

    if (s) {
        qtest_quit(s);
    }

    /* cleanup */
978
    test_server_free(server);
N
Nikolay Nikolaev 已提交
979

980 981 982 983 984 985 986 987
    /* 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);

988 989 990 991 992 993 994
    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 已提交
995 996
    return ret;
}