1 /* 2 * QTest testcase for the vhost-user 3 * 4 * Copyright (c) 2014 Virtual Open Systems Sarl. 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or later. 7 * See the COPYING file in the top-level directory. 8 * 9 */ 10 11 #include "qemu/osdep.h" 12 13 #include "libqtest-single.h" 14 #include "qapi/error.h" 15 #include "qobject/qdict.h" 16 #include "qemu/config-file.h" 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" 22 #include "qemu/module.h" 23 #include "system/system.h" 24 #include "libqos/libqos.h" 25 #include "libqos/pci-pc.h" 26 #include "libqos/virtio-pci.h" 27 28 #include "libqos/malloc-pc.h" 29 #include "hw/virtio/virtio-net.h" 30 31 #include "standard-headers/linux/vhost_types.h" 32 #include "standard-headers/linux/virtio_ids.h" 33 #include "standard-headers/linux/virtio_net.h" 34 #include "standard-headers/linux/virtio_gpio.h" 35 #include "standard-headers/linux/virtio_scmi.h" 36 37 #ifdef CONFIG_LINUX 38 #include <sys/vfs.h> 39 #endif 40 41 42 #define QEMU_CMD_MEM " -m %d -object memory-backend-file,id=mem,size=%dM," \ 43 "mem-path=%s,share=on -numa node,memdev=mem" 44 #define QEMU_CMD_MEMFD " -m %d -object memory-backend-memfd,id=mem,size=%dM," \ 45 " -numa node,memdev=mem" 46 #define QEMU_CMD_SHM " -m %d -object memory-backend-shm,id=mem,size=%dM," \ 47 " -numa node,memdev=mem" 48 #define QEMU_CMD_CHR " -chardev socket,id=%s,path=%s%s" 49 #define QEMU_CMD_NETDEV " -netdev vhost-user,id=hs0,chardev=%s,vhostforce=on" 50 51 #define HUGETLBFS_MAGIC 0x958458f6 52 53 /*********** FROM hw/virtio/vhost-user.c *************************************/ 54 55 #define VHOST_MEMORY_MAX_NREGIONS 8 56 #define VHOST_MAX_VIRTQUEUES 0x100 57 58 #define VHOST_USER_F_PROTOCOL_FEATURES 30 59 #define VIRTIO_F_VERSION_1 32 60 61 #define VHOST_USER_PROTOCOL_F_MQ 0 62 #define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1 63 #define VHOST_USER_PROTOCOL_F_CROSS_ENDIAN 6 64 #define VHOST_USER_PROTOCOL_F_CONFIG 9 65 66 #define VHOST_LOG_PAGE 0x1000 67 68 typedef enum VhostUserRequest { 69 VHOST_USER_NONE = 0, 70 VHOST_USER_GET_FEATURES = 1, 71 VHOST_USER_SET_FEATURES = 2, 72 VHOST_USER_SET_OWNER = 3, 73 VHOST_USER_RESET_OWNER = 4, 74 VHOST_USER_SET_MEM_TABLE = 5, 75 VHOST_USER_SET_LOG_BASE = 6, 76 VHOST_USER_SET_LOG_FD = 7, 77 VHOST_USER_SET_VRING_NUM = 8, 78 VHOST_USER_SET_VRING_ADDR = 9, 79 VHOST_USER_SET_VRING_BASE = 10, 80 VHOST_USER_GET_VRING_BASE = 11, 81 VHOST_USER_SET_VRING_KICK = 12, 82 VHOST_USER_SET_VRING_CALL = 13, 83 VHOST_USER_SET_VRING_ERR = 14, 84 VHOST_USER_GET_PROTOCOL_FEATURES = 15, 85 VHOST_USER_SET_PROTOCOL_FEATURES = 16, 86 VHOST_USER_GET_QUEUE_NUM = 17, 87 VHOST_USER_SET_VRING_ENABLE = 18, 88 VHOST_USER_GET_CONFIG = 24, 89 VHOST_USER_SET_CONFIG = 25, 90 VHOST_USER_MAX 91 } VhostUserRequest; 92 93 typedef struct VhostUserMemoryRegion { 94 uint64_t guest_phys_addr; 95 uint64_t memory_size; 96 uint64_t userspace_addr; 97 uint64_t mmap_offset; 98 } VhostUserMemoryRegion; 99 100 typedef struct VhostUserMemory { 101 uint32_t nregions; 102 uint32_t padding; 103 VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS]; 104 } VhostUserMemory; 105 106 typedef struct VhostUserLog { 107 uint64_t mmap_size; 108 uint64_t mmap_offset; 109 } VhostUserLog; 110 111 typedef struct VhostUserMsg { 112 VhostUserRequest request; 113 114 #define VHOST_USER_VERSION_MASK (0x3) 115 #define VHOST_USER_REPLY_MASK (0x1<<2) 116 uint32_t flags; 117 uint32_t size; /* the following payload size */ 118 union { 119 #define VHOST_USER_VRING_IDX_MASK (0xff) 120 #define VHOST_USER_VRING_NOFD_MASK (0x1<<8) 121 uint64_t u64; 122 struct vhost_vring_state state; 123 struct vhost_vring_addr addr; 124 VhostUserMemory memory; 125 VhostUserLog log; 126 } payload; 127 } QEMU_PACKED VhostUserMsg; 128 129 static VhostUserMsg m __attribute__ ((unused)); 130 #define VHOST_USER_HDR_SIZE (sizeof(m.request) \ 131 + sizeof(m.flags) \ 132 + sizeof(m.size)) 133 134 #define VHOST_USER_PAYLOAD_SIZE (sizeof(m) - VHOST_USER_HDR_SIZE) 135 136 /* The version of the protocol we support */ 137 #define VHOST_USER_VERSION (0x1) 138 /*****************************************************************************/ 139 140 enum { 141 TEST_FLAGS_OK, 142 TEST_FLAGS_DISCONNECT, 143 TEST_FLAGS_BAD, 144 TEST_FLAGS_END, 145 }; 146 147 enum { 148 VHOST_USER_NET, 149 VHOST_USER_GPIO, 150 VHOST_USER_SCMI, 151 }; 152 153 typedef struct TestServer { 154 gchar *socket_path; 155 gchar *mig_path; 156 gchar *chr_name; 157 gchar *tmpfs; 158 CharBackend chr; 159 int fds_num; 160 int fds[VHOST_MEMORY_MAX_NREGIONS]; 161 VhostUserMemory memory; 162 GMainContext *context; 163 GMainLoop *loop; 164 GThread *thread; 165 GMutex data_mutex; 166 GCond data_cond; 167 int log_fd; 168 uint64_t rings; 169 bool test_fail; 170 int test_flags; 171 int queues; 172 struct vhost_user_ops *vu_ops; 173 } TestServer; 174 175 struct vhost_user_ops { 176 /* Device types. */ 177 int type; 178 void (*append_opts)(TestServer *s, GString *cmd_line, 179 const char *chr_opts); 180 181 /* VHOST-USER commands. */ 182 uint64_t (*get_features)(TestServer *s); 183 void (*set_features)(TestServer *s, CharBackend *chr, 184 VhostUserMsg *msg); 185 void (*get_protocol_features)(TestServer *s, 186 CharBackend *chr, VhostUserMsg *msg); 187 }; 188 189 static const char *init_hugepagefs(void); 190 static TestServer *test_server_new(const gchar *name, 191 struct vhost_user_ops *ops); 192 static void test_server_free(TestServer *server); 193 static void test_server_listen(TestServer *server); 194 195 enum test_memfd { 196 TEST_MEMFD_AUTO, 197 TEST_MEMFD_YES, 198 TEST_MEMFD_NO, 199 TEST_MEMFD_SHM, 200 }; 201 202 static void append_vhost_net_opts(TestServer *s, GString *cmd_line, 203 const char *chr_opts) 204 { 205 g_string_append_printf(cmd_line, QEMU_CMD_CHR QEMU_CMD_NETDEV, 206 s->chr_name, s->socket_path, 207 chr_opts, s->chr_name); 208 } 209 210 /* 211 * For GPIO there are no other magic devices we need to add (like 212 * block or netdev) so all we need to worry about is the vhost-user 213 * chardev socket. 214 */ 215 static void append_vhost_gpio_opts(TestServer *s, GString *cmd_line, 216 const char *chr_opts) 217 { 218 g_string_append_printf(cmd_line, QEMU_CMD_CHR, 219 s->chr_name, s->socket_path, 220 chr_opts); 221 } 222 223 static void append_mem_opts(TestServer *server, GString *cmd_line, 224 int size, enum test_memfd memfd) 225 { 226 if (memfd == TEST_MEMFD_AUTO) { 227 memfd = qemu_memfd_check(MFD_ALLOW_SEALING) ? TEST_MEMFD_YES 228 : TEST_MEMFD_NO; 229 } 230 231 if (memfd == TEST_MEMFD_YES) { 232 g_string_append_printf(cmd_line, QEMU_CMD_MEMFD, size, size); 233 } else if (memfd == TEST_MEMFD_SHM) { 234 g_string_append_printf(cmd_line, QEMU_CMD_SHM, size, size); 235 } else { 236 const char *root = init_hugepagefs() ? : server->tmpfs; 237 238 g_string_append_printf(cmd_line, QEMU_CMD_MEM, size, size, root); 239 } 240 } 241 242 static bool wait_for_fds(TestServer *s) 243 { 244 gint64 end_time; 245 bool got_region; 246 int i; 247 248 g_mutex_lock(&s->data_mutex); 249 250 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND; 251 while (!s->fds_num) { 252 if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) { 253 /* timeout has passed */ 254 g_assert(s->fds_num); 255 break; 256 } 257 } 258 259 /* check for sanity */ 260 g_assert_cmpint(s->fds_num, >, 0); 261 g_assert_cmpint(s->fds_num, ==, s->memory.nregions); 262 263 g_mutex_unlock(&s->data_mutex); 264 265 got_region = false; 266 for (i = 0; i < s->memory.nregions; ++i) { 267 VhostUserMemoryRegion *reg = &s->memory.regions[i]; 268 if (reg->guest_phys_addr == 0) { 269 got_region = true; 270 break; 271 } 272 } 273 if (!got_region) { 274 g_test_skip("No memory at address 0x0"); 275 } 276 return got_region; 277 } 278 279 static void read_guest_mem_server(QTestState *qts, TestServer *s) 280 { 281 uint8_t *guest_mem; 282 int i, j; 283 size_t size; 284 285 g_mutex_lock(&s->data_mutex); 286 287 /* iterate all regions */ 288 for (i = 0; i < s->fds_num; i++) { 289 290 /* We'll check only the region starting at 0x0 */ 291 if (s->memory.regions[i].guest_phys_addr != 0x0) { 292 continue; 293 } 294 295 g_assert_cmpint(s->memory.regions[i].memory_size, >, 1024); 296 297 size = s->memory.regions[i].memory_size + 298 s->memory.regions[i].mmap_offset; 299 300 guest_mem = mmap(0, size, PROT_READ | PROT_WRITE, 301 MAP_SHARED, s->fds[i], 0); 302 303 g_assert(guest_mem != MAP_FAILED); 304 guest_mem += (s->memory.regions[i].mmap_offset / sizeof(*guest_mem)); 305 306 for (j = 0; j < 1024; j++) { 307 uint32_t a = qtest_readb(qts, s->memory.regions[i].guest_phys_addr + j); 308 uint32_t b = guest_mem[j]; 309 310 g_assert_cmpint(a, ==, b); 311 } 312 313 munmap(guest_mem, s->memory.regions[i].memory_size); 314 } 315 316 g_mutex_unlock(&s->data_mutex); 317 } 318 319 static void *thread_function(void *data) 320 { 321 GMainLoop *loop = data; 322 g_main_loop_run(loop); 323 return NULL; 324 } 325 326 static int chr_can_read(void *opaque) 327 { 328 return VHOST_USER_HDR_SIZE; 329 } 330 331 static void chr_read(void *opaque, const uint8_t *buf, int size) 332 { 333 g_autoptr(GError) err = NULL; 334 TestServer *s = opaque; 335 CharBackend *chr = &s->chr; 336 VhostUserMsg msg; 337 uint8_t *p = (uint8_t *) &msg; 338 int fd = -1; 339 340 if (s->test_fail) { 341 qemu_chr_fe_disconnect(chr); 342 /* now switch to non-failure */ 343 s->test_fail = false; 344 } 345 346 if (size != VHOST_USER_HDR_SIZE) { 347 g_test_message("Wrong message size received %d", size); 348 return; 349 } 350 351 g_mutex_lock(&s->data_mutex); 352 memcpy(p, buf, VHOST_USER_HDR_SIZE); 353 354 if (msg.size) { 355 p += VHOST_USER_HDR_SIZE; 356 size = qemu_chr_fe_read_all(chr, p, msg.size); 357 if (size != msg.size) { 358 g_test_message("Wrong message size received %d != %d", 359 size, msg.size); 360 goto out; 361 } 362 } 363 364 switch (msg.request) { 365 case VHOST_USER_GET_FEATURES: 366 /* Mandatory for tests to define get_features */ 367 g_assert(s->vu_ops->get_features); 368 369 /* send back features to qemu */ 370 msg.flags |= VHOST_USER_REPLY_MASK; 371 msg.size = sizeof(m.payload.u64); 372 373 if (s->test_flags >= TEST_FLAGS_BAD) { 374 msg.payload.u64 = 0; 375 s->test_flags = TEST_FLAGS_END; 376 } else { 377 msg.payload.u64 = s->vu_ops->get_features(s); 378 } 379 380 qemu_chr_fe_write_all(chr, (uint8_t *) &msg, 381 VHOST_USER_HDR_SIZE + msg.size); 382 break; 383 384 case VHOST_USER_SET_FEATURES: 385 if (s->vu_ops->set_features) { 386 s->vu_ops->set_features(s, chr, &msg); 387 } 388 break; 389 390 case VHOST_USER_SET_OWNER: 391 /* 392 * We don't need to do anything here, the remote is just 393 * letting us know it is in charge. Just log it. 394 */ 395 g_test_message("set_owner: start of session\n"); 396 break; 397 398 case VHOST_USER_GET_PROTOCOL_FEATURES: 399 if (s->vu_ops->get_protocol_features) { 400 s->vu_ops->get_protocol_features(s, chr, &msg); 401 } 402 break; 403 404 case VHOST_USER_GET_CONFIG: 405 /* 406 * Treat GET_CONFIG as a NOP and just reply and let the guest 407 * consider we have updated its memory. Tests currently don't 408 * require working configs. 409 */ 410 msg.flags |= VHOST_USER_REPLY_MASK; 411 p = (uint8_t *) &msg; 412 qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); 413 break; 414 415 case VHOST_USER_SET_PROTOCOL_FEATURES: 416 /* 417 * We did set VHOST_USER_F_PROTOCOL_FEATURES so its valid for 418 * the remote end to send this. There is no handshake reply so 419 * just log the details for debugging. 420 */ 421 g_test_message("set_protocol_features: 0x%"PRIx64 "\n", msg.payload.u64); 422 break; 423 424 /* 425 * A real vhost-user backend would actually set the size and 426 * address of the vrings but we can simply report them. 427 */ 428 case VHOST_USER_SET_VRING_NUM: 429 g_test_message("set_vring_num: %d/%d\n", 430 msg.payload.state.index, msg.payload.state.num); 431 break; 432 case VHOST_USER_SET_VRING_ADDR: 433 g_test_message("set_vring_addr: 0x%"PRIx64"/0x%"PRIx64"/0x%"PRIx64"\n", 434 msg.payload.addr.avail_user_addr, 435 msg.payload.addr.desc_user_addr, 436 msg.payload.addr.used_user_addr); 437 break; 438 439 case VHOST_USER_GET_VRING_BASE: 440 /* send back vring base to qemu */ 441 msg.flags |= VHOST_USER_REPLY_MASK; 442 msg.size = sizeof(m.payload.state); 443 msg.payload.state.num = 0; 444 p = (uint8_t *) &msg; 445 qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); 446 447 assert(msg.payload.state.index < s->queues * 2); 448 s->rings &= ~(0x1ULL << msg.payload.state.index); 449 g_cond_broadcast(&s->data_cond); 450 break; 451 452 case VHOST_USER_SET_MEM_TABLE: 453 /* received the mem table */ 454 memcpy(&s->memory, &msg.payload.memory, sizeof(msg.payload.memory)); 455 s->fds_num = qemu_chr_fe_get_msgfds(chr, s->fds, 456 G_N_ELEMENTS(s->fds)); 457 458 /* signal the test that it can continue */ 459 g_cond_broadcast(&s->data_cond); 460 break; 461 462 case VHOST_USER_SET_VRING_KICK: 463 case VHOST_USER_SET_VRING_CALL: 464 /* consume the fd */ 465 if (!qemu_chr_fe_get_msgfds(chr, &fd, 1) && fd < 0) { 466 g_test_message("call fd: %d, do not set non-blocking\n", fd); 467 break; 468 } 469 /* 470 * This is a non-blocking eventfd. 471 * The receive function forces it to be blocking, 472 * so revert it back to non-blocking. 473 */ 474 g_unix_set_fd_nonblocking(fd, true, &err); 475 g_assert_no_error(err); 476 break; 477 478 case VHOST_USER_SET_LOG_BASE: 479 if (s->log_fd != -1) { 480 close(s->log_fd); 481 s->log_fd = -1; 482 } 483 qemu_chr_fe_get_msgfds(chr, &s->log_fd, 1); 484 msg.flags |= VHOST_USER_REPLY_MASK; 485 msg.size = 0; 486 p = (uint8_t *) &msg; 487 qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE); 488 489 g_cond_broadcast(&s->data_cond); 490 break; 491 492 case VHOST_USER_SET_VRING_BASE: 493 assert(msg.payload.state.index < s->queues * 2); 494 s->rings |= 0x1ULL << msg.payload.state.index; 495 g_cond_broadcast(&s->data_cond); 496 break; 497 498 case VHOST_USER_GET_QUEUE_NUM: 499 msg.flags |= VHOST_USER_REPLY_MASK; 500 msg.size = sizeof(m.payload.u64); 501 msg.payload.u64 = s->queues; 502 p = (uint8_t *) &msg; 503 qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); 504 break; 505 506 case VHOST_USER_SET_VRING_ENABLE: 507 /* 508 * Another case we ignore as we don't need to respond. With a 509 * fully functioning vhost-user we would enable/disable the 510 * vring monitoring. 511 */ 512 g_test_message("set_vring(%d)=%s\n", msg.payload.state.index, 513 msg.payload.state.num ? "enabled" : "disabled"); 514 break; 515 516 default: 517 g_test_message("vhost-user: un-handled message: %d\n", msg.request); 518 break; 519 } 520 521 out: 522 g_mutex_unlock(&s->data_mutex); 523 } 524 525 static const char *init_hugepagefs(void) 526 { 527 #ifdef CONFIG_LINUX 528 static const char *hugepagefs; 529 const char *path = getenv("QTEST_HUGETLBFS_PATH"); 530 struct statfs fs; 531 int ret; 532 533 if (hugepagefs) { 534 return hugepagefs; 535 } 536 if (!path) { 537 return NULL; 538 } 539 540 if (access(path, R_OK | W_OK | X_OK)) { 541 g_test_message("access on path (%s): %s", path, strerror(errno)); 542 g_test_fail(); 543 return NULL; 544 } 545 546 do { 547 ret = statfs(path, &fs); 548 } while (ret != 0 && errno == EINTR); 549 550 if (ret != 0) { 551 g_test_message("statfs on path (%s): %s", path, strerror(errno)); 552 g_test_fail(); 553 return NULL; 554 } 555 556 if (fs.f_type != HUGETLBFS_MAGIC) { 557 g_test_message("Warning: path not on HugeTLBFS: %s", path); 558 g_test_fail(); 559 return NULL; 560 } 561 562 hugepagefs = path; 563 return hugepagefs; 564 #else 565 return NULL; 566 #endif 567 } 568 569 static TestServer *test_server_new(const gchar *name, 570 struct vhost_user_ops *ops) 571 { 572 TestServer *server = g_new0(TestServer, 1); 573 g_autofree const char *tmpfs = NULL; 574 GError *err = NULL; 575 576 server->context = g_main_context_new(); 577 server->loop = g_main_loop_new(server->context, FALSE); 578 579 /* run the main loop thread so the chardev may operate */ 580 server->thread = g_thread_new(NULL, thread_function, server->loop); 581 582 tmpfs = g_dir_make_tmp("vhost-test-XXXXXX", &err); 583 if (!tmpfs) { 584 g_test_message("Can't create temporary directory in %s: %s", 585 g_get_tmp_dir(), err->message); 586 g_error_free(err); 587 } 588 g_assert(tmpfs); 589 590 server->tmpfs = g_strdup(tmpfs); 591 server->socket_path = g_strdup_printf("%s/%s.sock", tmpfs, name); 592 server->mig_path = g_strdup_printf("%s/%s.mig", tmpfs, name); 593 server->chr_name = g_strdup_printf("chr-%s", name); 594 595 g_mutex_init(&server->data_mutex); 596 g_cond_init(&server->data_cond); 597 598 server->log_fd = -1; 599 server->queues = 1; 600 server->vu_ops = ops; 601 602 return server; 603 } 604 605 static void chr_event(void *opaque, QEMUChrEvent event) 606 { 607 TestServer *s = opaque; 608 609 if (s->test_flags == TEST_FLAGS_END && 610 event == CHR_EVENT_CLOSED) { 611 s->test_flags = TEST_FLAGS_OK; 612 } 613 } 614 615 static void test_server_create_chr(TestServer *server, const gchar *opt) 616 { 617 g_autofree gchar *chr_path = g_strdup_printf("unix:%s%s", 618 server->socket_path, opt); 619 Chardev *chr; 620 621 chr = qemu_chr_new(server->chr_name, chr_path, server->context); 622 g_assert(chr); 623 624 qemu_chr_fe_init(&server->chr, chr, &error_abort); 625 qemu_chr_fe_set_handlers(&server->chr, chr_can_read, chr_read, 626 chr_event, NULL, server, server->context, true); 627 } 628 629 static void test_server_listen(TestServer *server) 630 { 631 test_server_create_chr(server, ",server=on,wait=off"); 632 } 633 634 static void test_server_free(TestServer *server) 635 { 636 int i, ret; 637 638 /* finish the helper thread and dispatch pending sources */ 639 g_main_loop_quit(server->loop); 640 g_thread_join(server->thread); 641 while (g_main_context_pending(NULL)) { 642 g_main_context_iteration(NULL, TRUE); 643 } 644 645 unlink(server->socket_path); 646 g_free(server->socket_path); 647 648 unlink(server->mig_path); 649 g_free(server->mig_path); 650 651 ret = rmdir(server->tmpfs); 652 if (ret != 0) { 653 g_test_message("unable to rmdir: path (%s): %s", 654 server->tmpfs, strerror(errno)); 655 } 656 g_free(server->tmpfs); 657 658 qemu_chr_fe_deinit(&server->chr, true); 659 660 for (i = 0; i < server->fds_num; i++) { 661 close(server->fds[i]); 662 } 663 664 if (server->log_fd != -1) { 665 close(server->log_fd); 666 } 667 668 g_free(server->chr_name); 669 670 g_main_loop_unref(server->loop); 671 g_main_context_unref(server->context); 672 g_cond_clear(&server->data_cond); 673 g_mutex_clear(&server->data_mutex); 674 g_free(server); 675 } 676 677 static void wait_for_log_fd(TestServer *s) 678 { 679 gint64 end_time; 680 681 g_mutex_lock(&s->data_mutex); 682 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND; 683 while (s->log_fd == -1) { 684 if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) { 685 /* timeout has passed */ 686 g_assert(s->log_fd != -1); 687 break; 688 } 689 } 690 691 g_mutex_unlock(&s->data_mutex); 692 } 693 694 static void write_guest_mem(TestServer *s, uint32_t seed) 695 { 696 uint32_t *guest_mem; 697 int i, j; 698 size_t size; 699 700 /* iterate all regions */ 701 for (i = 0; i < s->fds_num; i++) { 702 703 /* We'll write only the region statring at 0x0 */ 704 if (s->memory.regions[i].guest_phys_addr != 0x0) { 705 continue; 706 } 707 708 g_assert_cmpint(s->memory.regions[i].memory_size, >, 1024); 709 710 size = s->memory.regions[i].memory_size + 711 s->memory.regions[i].mmap_offset; 712 713 guest_mem = mmap(0, size, PROT_READ | PROT_WRITE, 714 MAP_SHARED, s->fds[i], 0); 715 716 g_assert(guest_mem != MAP_FAILED); 717 guest_mem += (s->memory.regions[i].mmap_offset / sizeof(*guest_mem)); 718 719 for (j = 0; j < 256; j++) { 720 guest_mem[j] = seed + j; 721 } 722 723 munmap(guest_mem, s->memory.regions[i].memory_size); 724 break; 725 } 726 } 727 728 static guint64 get_log_size(TestServer *s) 729 { 730 guint64 log_size = 0; 731 int i; 732 733 for (i = 0; i < s->memory.nregions; ++i) { 734 VhostUserMemoryRegion *reg = &s->memory.regions[i]; 735 guint64 last = range_get_last(reg->guest_phys_addr, 736 reg->memory_size); 737 log_size = MAX(log_size, last / (8 * VHOST_LOG_PAGE) + 1); 738 } 739 740 return log_size; 741 } 742 743 typedef struct TestMigrateSource { 744 GSource source; 745 TestServer *src; 746 TestServer *dest; 747 } TestMigrateSource; 748 749 static gboolean 750 test_migrate_source_check(GSource *source) 751 { 752 TestMigrateSource *t = (TestMigrateSource *)source; 753 gboolean overlap = t->src->rings && t->dest->rings; 754 755 g_assert(!overlap); 756 757 return FALSE; 758 } 759 760 GSourceFuncs test_migrate_source_funcs = { 761 .check = test_migrate_source_check, 762 }; 763 764 static void vhost_user_test_cleanup(void *s) 765 { 766 TestServer *server = s; 767 768 qos_invalidate_command_line(); 769 test_server_free(server); 770 } 771 772 static void *vhost_user_test_setup(GString *cmd_line, void *arg) 773 { 774 TestServer *server = test_server_new("vhost-user-test", arg); 775 test_server_listen(server); 776 777 append_mem_opts(server, cmd_line, 256, TEST_MEMFD_AUTO); 778 server->vu_ops->append_opts(server, cmd_line, ""); 779 780 g_test_queue_destroy(vhost_user_test_cleanup, server); 781 782 return server; 783 } 784 785 static void *vhost_user_test_setup_memfd(GString *cmd_line, void *arg) 786 { 787 TestServer *server = test_server_new("vhost-user-test", arg); 788 test_server_listen(server); 789 790 append_mem_opts(server, cmd_line, 256, TEST_MEMFD_YES); 791 server->vu_ops->append_opts(server, cmd_line, ""); 792 793 g_test_queue_destroy(vhost_user_test_cleanup, server); 794 795 return server; 796 } 797 798 static void *vhost_user_test_setup_shm(GString *cmd_line, void *arg) 799 { 800 TestServer *server = test_server_new("vhost-user-test", arg); 801 test_server_listen(server); 802 803 append_mem_opts(server, cmd_line, 256, TEST_MEMFD_SHM); 804 server->vu_ops->append_opts(server, cmd_line, ""); 805 806 g_test_queue_destroy(vhost_user_test_cleanup, server); 807 808 return server; 809 } 810 811 static void test_read_guest_mem(void *obj, void *arg, QGuestAllocator *alloc) 812 { 813 TestServer *server = arg; 814 815 if (!wait_for_fds(server)) { 816 return; 817 } 818 819 read_guest_mem_server(global_qtest, server); 820 } 821 822 static void test_migrate(void *obj, void *arg, QGuestAllocator *alloc) 823 { 824 TestServer *s = arg; 825 TestServer *dest; 826 GString *dest_cmdline; 827 char *uri; 828 QTestState *to; 829 GSource *source; 830 QDict *rsp; 831 guint8 *log; 832 guint64 size; 833 834 if (!wait_for_fds(s)) { 835 return; 836 } 837 838 dest = test_server_new("dest", s->vu_ops); 839 dest_cmdline = g_string_new(qos_get_current_command_line()); 840 uri = g_strdup_printf("%s%s", "unix:", dest->mig_path); 841 842 size = get_log_size(s); 843 g_assert_cmpint(size, ==, (256 * 1024 * 1024) / (VHOST_LOG_PAGE * 8)); 844 845 test_server_listen(dest); 846 g_string_append_printf(dest_cmdline, " -incoming %s", uri); 847 append_mem_opts(dest, dest_cmdline, 256, TEST_MEMFD_AUTO); 848 dest->vu_ops->append_opts(dest, dest_cmdline, ""); 849 to = qtest_init(dest_cmdline->str); 850 851 /* This would be where you call qos_allocate_objects(to, NULL), if you want 852 * to talk to the QVirtioNet object on the destination. 853 */ 854 855 source = g_source_new(&test_migrate_source_funcs, 856 sizeof(TestMigrateSource)); 857 ((TestMigrateSource *)source)->src = s; 858 ((TestMigrateSource *)source)->dest = dest; 859 g_source_attach(source, s->context); 860 861 /* slow down migration to have time to fiddle with log */ 862 /* TODO: qtest could learn to break on some places */ 863 rsp = qmp("{ 'execute': 'migrate-set-parameters'," 864 "'arguments': { 'max-bandwidth': 10 } }"); 865 g_assert(qdict_haskey(rsp, "return")); 866 qobject_unref(rsp); 867 868 rsp = qmp("{ 'execute': 'migrate', 'arguments': { 'uri': %s } }", uri); 869 g_assert(qdict_haskey(rsp, "return")); 870 qobject_unref(rsp); 871 872 wait_for_log_fd(s); 873 874 log = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, s->log_fd, 0); 875 g_assert(log != MAP_FAILED); 876 877 /* modify first page */ 878 write_guest_mem(s, 0x42); 879 log[0] = 1; 880 munmap(log, size); 881 882 /* speed things up */ 883 rsp = qmp("{ 'execute': 'migrate-set-parameters'," 884 "'arguments': { 'max-bandwidth': 0 } }"); 885 g_assert(qdict_haskey(rsp, "return")); 886 qobject_unref(rsp); 887 888 qmp_eventwait("STOP"); 889 qtest_qmp_eventwait(to, "RESUME"); 890 891 g_assert(wait_for_fds(dest)); 892 read_guest_mem_server(to, dest); 893 894 g_source_destroy(source); 895 g_source_unref(source); 896 897 qtest_quit(to); 898 test_server_free(dest); 899 g_free(uri); 900 g_string_free(dest_cmdline, true); 901 } 902 903 static void wait_for_rings_started(TestServer *s, size_t count) 904 { 905 gint64 end_time; 906 907 g_mutex_lock(&s->data_mutex); 908 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND; 909 while (ctpop64(s->rings) != count) { 910 if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) { 911 /* timeout has passed */ 912 g_assert_cmpint(ctpop64(s->rings), ==, count); 913 break; 914 } 915 } 916 917 g_mutex_unlock(&s->data_mutex); 918 } 919 920 static inline void test_server_connect(TestServer *server) 921 { 922 test_server_create_chr(server, ",reconnect-ms=1000"); 923 } 924 925 static gboolean 926 reconnect_cb(gpointer user_data) 927 { 928 TestServer *s = user_data; 929 930 qemu_chr_fe_disconnect(&s->chr); 931 932 return FALSE; 933 } 934 935 static gpointer 936 connect_thread(gpointer data) 937 { 938 TestServer *s = data; 939 940 /* wait for qemu to start before first try, to avoid extra warnings */ 941 g_usleep(G_USEC_PER_SEC); 942 test_server_connect(s); 943 944 return NULL; 945 } 946 947 static void *vhost_user_test_setup_reconnect(GString *cmd_line, void *arg) 948 { 949 TestServer *s = test_server_new("reconnect", arg); 950 951 g_thread_unref(g_thread_new("connect", connect_thread, s)); 952 append_mem_opts(s, cmd_line, 256, TEST_MEMFD_AUTO); 953 s->vu_ops->append_opts(s, cmd_line, ",server=on"); 954 955 g_test_queue_destroy(vhost_user_test_cleanup, s); 956 957 return s; 958 } 959 960 static void test_reconnect(void *obj, void *arg, QGuestAllocator *alloc) 961 { 962 TestServer *s = arg; 963 GSource *src; 964 965 if (!wait_for_fds(s)) { 966 return; 967 } 968 969 wait_for_rings_started(s, 2); 970 971 /* reconnect */ 972 s->fds_num = 0; 973 s->rings = 0; 974 src = g_idle_source_new(); 975 g_source_set_callback(src, reconnect_cb, s, NULL); 976 g_source_attach(src, s->context); 977 g_source_unref(src); 978 g_assert(wait_for_fds(s)); 979 wait_for_rings_started(s, 2); 980 } 981 982 static void *vhost_user_test_setup_connect_fail(GString *cmd_line, void *arg) 983 { 984 TestServer *s = test_server_new("connect-fail", arg); 985 986 s->test_fail = true; 987 988 g_thread_unref(g_thread_new("connect", connect_thread, s)); 989 append_mem_opts(s, cmd_line, 256, TEST_MEMFD_AUTO); 990 s->vu_ops->append_opts(s, cmd_line, ",server=on"); 991 992 g_test_queue_destroy(vhost_user_test_cleanup, s); 993 994 return s; 995 } 996 997 static void *vhost_user_test_setup_flags_mismatch(GString *cmd_line, void *arg) 998 { 999 TestServer *s = test_server_new("flags-mismatch", arg); 1000 1001 s->test_flags = TEST_FLAGS_DISCONNECT; 1002 1003 g_thread_unref(g_thread_new("connect", connect_thread, s)); 1004 append_mem_opts(s, cmd_line, 256, TEST_MEMFD_AUTO); 1005 s->vu_ops->append_opts(s, cmd_line, ",server=on"); 1006 1007 g_test_queue_destroy(vhost_user_test_cleanup, s); 1008 1009 return s; 1010 } 1011 1012 static void test_vhost_user_started(void *obj, void *arg, QGuestAllocator *alloc) 1013 { 1014 TestServer *s = arg; 1015 1016 if (!wait_for_fds(s)) { 1017 return; 1018 } 1019 wait_for_rings_started(s, 2); 1020 } 1021 1022 static void *vhost_user_test_setup_multiqueue(GString *cmd_line, void *arg) 1023 { 1024 TestServer *s = vhost_user_test_setup(cmd_line, arg); 1025 1026 s->queues = 2; 1027 g_string_append_printf(cmd_line, 1028 " -set netdev.hs0.queues=%d" 1029 " -global virtio-net-pci.vectors=%d", 1030 s->queues, s->queues * 2 + 2); 1031 1032 return s; 1033 } 1034 1035 static void test_multiqueue(void *obj, void *arg, QGuestAllocator *alloc) 1036 { 1037 TestServer *s = arg; 1038 1039 wait_for_rings_started(s, s->queues * 2); 1040 } 1041 1042 1043 static uint64_t vu_net_get_features(TestServer *s) 1044 { 1045 uint64_t features = 0x1ULL << VIRTIO_F_VERSION_1 | 1046 0x1ULL << VHOST_F_LOG_ALL | 1047 0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES; 1048 1049 if (s->queues > 1) { 1050 features |= 0x1ULL << VIRTIO_NET_F_MQ; 1051 } 1052 1053 return features; 1054 } 1055 1056 static void vu_net_set_features(TestServer *s, CharBackend *chr, 1057 VhostUserMsg *msg) 1058 { 1059 g_assert(msg->payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES)); 1060 if (s->test_flags == TEST_FLAGS_DISCONNECT) { 1061 qemu_chr_fe_disconnect(chr); 1062 s->test_flags = TEST_FLAGS_BAD; 1063 } 1064 } 1065 1066 static void vu_net_get_protocol_features(TestServer *s, CharBackend *chr, 1067 VhostUserMsg *msg) 1068 { 1069 /* send back features to qemu */ 1070 msg->flags |= VHOST_USER_REPLY_MASK; 1071 msg->size = sizeof(m.payload.u64); 1072 msg->payload.u64 = 1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD; 1073 msg->payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_CROSS_ENDIAN; 1074 if (s->queues > 1) { 1075 msg->payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_MQ; 1076 } 1077 qemu_chr_fe_write_all(chr, (uint8_t *)msg, VHOST_USER_HDR_SIZE + msg->size); 1078 } 1079 1080 /* Each VHOST-USER device should have its ops structure defined. */ 1081 static struct vhost_user_ops g_vu_net_ops = { 1082 .type = VHOST_USER_NET, 1083 1084 .append_opts = append_vhost_net_opts, 1085 1086 .get_features = vu_net_get_features, 1087 .set_features = vu_net_set_features, 1088 .get_protocol_features = vu_net_get_protocol_features, 1089 }; 1090 1091 static void register_vhost_user_test(void) 1092 { 1093 QOSGraphTestOptions opts = { 1094 .before = vhost_user_test_setup, 1095 .subprocess = true, 1096 .arg = &g_vu_net_ops, 1097 }; 1098 1099 qemu_add_opts(&qemu_chardev_opts); 1100 1101 qos_add_test("vhost-user/read-guest-mem/memfile", 1102 "virtio-net", 1103 test_read_guest_mem, &opts); 1104 1105 opts.before = vhost_user_test_setup_shm; 1106 qos_add_test("vhost-user/read-guest-mem/shm", 1107 "virtio-net", 1108 test_read_guest_mem, &opts); 1109 1110 if (qemu_memfd_check(MFD_ALLOW_SEALING)) { 1111 opts.before = vhost_user_test_setup_memfd; 1112 qos_add_test("vhost-user/read-guest-mem/memfd", 1113 "virtio-net", 1114 test_read_guest_mem, &opts); 1115 } 1116 1117 qos_add_test("vhost-user/migrate", 1118 "virtio-net", 1119 test_migrate, &opts); 1120 1121 opts.before = vhost_user_test_setup_reconnect; 1122 qos_add_test("vhost-user/reconnect", "virtio-net", 1123 test_reconnect, &opts); 1124 1125 opts.before = vhost_user_test_setup_connect_fail; 1126 qos_add_test("vhost-user/connect-fail", "virtio-net", 1127 test_vhost_user_started, &opts); 1128 1129 opts.before = vhost_user_test_setup_flags_mismatch; 1130 qos_add_test("vhost-user/flags-mismatch", "virtio-net", 1131 test_vhost_user_started, &opts); 1132 1133 opts.before = vhost_user_test_setup_multiqueue; 1134 opts.edge.extra_device_opts = "mq=on"; 1135 qos_add_test("vhost-user/multiqueue", 1136 "virtio-net", 1137 test_multiqueue, &opts); 1138 } 1139 libqos_init(register_vhost_user_test); 1140 1141 static uint64_t vu_gpio_get_features(TestServer *s) 1142 { 1143 return 0x1ULL << VIRTIO_F_VERSION_1 | 1144 0x1ULL << VIRTIO_GPIO_F_IRQ | 1145 0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES; 1146 } 1147 1148 /* 1149 * This stub can't handle all the message types but we should reply 1150 * that we support VHOST_USER_PROTOCOL_F_CONFIG as gpio would use it 1151 * talking to a read vhost-user daemon. 1152 */ 1153 static void vu_gpio_get_protocol_features(TestServer *s, CharBackend *chr, 1154 VhostUserMsg *msg) 1155 { 1156 /* send back features to qemu */ 1157 msg->flags |= VHOST_USER_REPLY_MASK; 1158 msg->size = sizeof(m.payload.u64); 1159 msg->payload.u64 = 1ULL << VHOST_USER_PROTOCOL_F_CONFIG; 1160 1161 qemu_chr_fe_write_all(chr, (uint8_t *)msg, VHOST_USER_HDR_SIZE + msg->size); 1162 } 1163 1164 static struct vhost_user_ops g_vu_gpio_ops = { 1165 .type = VHOST_USER_GPIO, 1166 1167 .append_opts = append_vhost_gpio_opts, 1168 1169 .get_features = vu_gpio_get_features, 1170 .set_features = vu_net_set_features, 1171 .get_protocol_features = vu_gpio_get_protocol_features, 1172 }; 1173 1174 static void register_vhost_gpio_test(void) 1175 { 1176 QOSGraphTestOptions opts = { 1177 .before = vhost_user_test_setup, 1178 .subprocess = true, 1179 .arg = &g_vu_gpio_ops, 1180 }; 1181 1182 qemu_add_opts(&qemu_chardev_opts); 1183 1184 qos_add_test("read-guest-mem/memfile", 1185 "vhost-user-gpio", test_read_guest_mem, &opts); 1186 } 1187 libqos_init(register_vhost_gpio_test); 1188 1189 static uint64_t vu_scmi_get_features(TestServer *s) 1190 { 1191 return 0x1ULL << VIRTIO_F_VERSION_1 | 1192 0x1ULL << VIRTIO_SCMI_F_P2A_CHANNELS | 1193 0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES; 1194 } 1195 1196 static void vu_scmi_get_protocol_features(TestServer *s, CharBackend *chr, 1197 VhostUserMsg *msg) 1198 { 1199 msg->flags |= VHOST_USER_REPLY_MASK; 1200 msg->size = sizeof(m.payload.u64); 1201 msg->payload.u64 = 1ULL << VHOST_USER_PROTOCOL_F_MQ; 1202 1203 qemu_chr_fe_write_all(chr, (uint8_t *)msg, VHOST_USER_HDR_SIZE + msg->size); 1204 } 1205 1206 static struct vhost_user_ops g_vu_scmi_ops = { 1207 .type = VHOST_USER_SCMI, 1208 1209 .append_opts = append_vhost_gpio_opts, 1210 1211 .get_features = vu_scmi_get_features, 1212 .set_features = vu_net_set_features, 1213 .get_protocol_features = vu_scmi_get_protocol_features, 1214 }; 1215 1216 static void register_vhost_scmi_test(void) 1217 { 1218 QOSGraphTestOptions opts = { 1219 .before = vhost_user_test_setup, 1220 .subprocess = true, 1221 .arg = &g_vu_scmi_ops, 1222 }; 1223 1224 qemu_add_opts(&qemu_chardev_opts); 1225 1226 qos_add_test("scmi/read-guest-mem/memfile", 1227 "vhost-user-scmi", test_read_guest_mem, &opts); 1228 } 1229 libqos_init(register_vhost_scmi_test); 1230