18a645544SFabiano Rosas /* 28a645544SFabiano Rosas * QTest testcase for precopy migration 38a645544SFabiano Rosas * 48a645544SFabiano Rosas * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates 58a645544SFabiano Rosas * based on the vhost-user-test.c that is: 68a645544SFabiano Rosas * Copyright (c) 2014 Virtual Open Systems Sarl. 78a645544SFabiano Rosas * 88a645544SFabiano Rosas * This work is licensed under the terms of the GNU GPL, version 2 or later. 98a645544SFabiano Rosas * See the COPYING file in the top-level directory. 108a645544SFabiano Rosas * 118a645544SFabiano Rosas */ 128a645544SFabiano Rosas 138a645544SFabiano Rosas #include "qemu/osdep.h" 148a645544SFabiano Rosas #include "chardev/char.h" 158a645544SFabiano Rosas #include "crypto/tlscredspsk.h" 168a645544SFabiano Rosas #include "libqtest.h" 178a645544SFabiano Rosas #include "migration/bootfile.h" 188a645544SFabiano Rosas #include "migration/framework.h" 198a645544SFabiano Rosas #include "migration/migration-qmp.h" 208a645544SFabiano Rosas #include "migration/migration-util.h" 218a645544SFabiano Rosas #include "ppc-util.h" 22407bc4bfSDaniel P. Berrangé #include "qobject/qlist.h" 23538e03d2SFabiano Rosas #include "qapi-types-migration.h" 248a645544SFabiano Rosas #include "qemu/module.h" 258a645544SFabiano Rosas #include "qemu/option.h" 268a645544SFabiano Rosas #include "qemu/range.h" 278a645544SFabiano Rosas #include "qemu/sockets.h" 288a645544SFabiano Rosas 298a645544SFabiano Rosas 308a645544SFabiano Rosas /* 318a645544SFabiano Rosas * Dirtylimit stop working if dirty page rate error 328a645544SFabiano Rosas * value less than DIRTYLIMIT_TOLERANCE_RANGE 338a645544SFabiano Rosas */ 348a645544SFabiano Rosas #define DIRTYLIMIT_TOLERANCE_RANGE 25 /* MB/s */ 358a645544SFabiano Rosas 368a645544SFabiano Rosas static char *tmpfs; 378a645544SFabiano Rosas 388a645544SFabiano Rosas static void test_precopy_unix_plain(void) 398a645544SFabiano Rosas { 408a645544SFabiano Rosas g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); 418a645544SFabiano Rosas MigrateCommon args = { 428a645544SFabiano Rosas .listen_uri = uri, 438a645544SFabiano Rosas .connect_uri = uri, 448a645544SFabiano Rosas /* 458a645544SFabiano Rosas * The simplest use case of precopy, covering smoke tests of 468a645544SFabiano Rosas * get-dirty-log dirty tracking. 478a645544SFabiano Rosas */ 488a645544SFabiano Rosas .live = true, 498a645544SFabiano Rosas }; 508a645544SFabiano Rosas 518a645544SFabiano Rosas test_precopy_common(&args); 528a645544SFabiano Rosas } 538a645544SFabiano Rosas 548a645544SFabiano Rosas static void test_precopy_unix_suspend_live(void) 558a645544SFabiano Rosas { 568a645544SFabiano Rosas g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); 578a645544SFabiano Rosas MigrateCommon args = { 588a645544SFabiano Rosas .listen_uri = uri, 598a645544SFabiano Rosas .connect_uri = uri, 608a645544SFabiano Rosas /* 618a645544SFabiano Rosas * despite being live, the test is fast because the src 628a645544SFabiano Rosas * suspends immediately. 638a645544SFabiano Rosas */ 648a645544SFabiano Rosas .live = true, 658a645544SFabiano Rosas .start.suspend_me = true, 668a645544SFabiano Rosas }; 678a645544SFabiano Rosas 688a645544SFabiano Rosas test_precopy_common(&args); 698a645544SFabiano Rosas } 708a645544SFabiano Rosas 718a645544SFabiano Rosas static void test_precopy_unix_suspend_notlive(void) 728a645544SFabiano Rosas { 738a645544SFabiano Rosas g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); 748a645544SFabiano Rosas MigrateCommon args = { 758a645544SFabiano Rosas .listen_uri = uri, 768a645544SFabiano Rosas .connect_uri = uri, 778a645544SFabiano Rosas .start.suspend_me = true, 788a645544SFabiano Rosas }; 798a645544SFabiano Rosas 808a645544SFabiano Rosas test_precopy_common(&args); 818a645544SFabiano Rosas } 828a645544SFabiano Rosas 838a645544SFabiano Rosas static void test_precopy_unix_dirty_ring(void) 848a645544SFabiano Rosas { 858a645544SFabiano Rosas g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); 868a645544SFabiano Rosas MigrateCommon args = { 878a645544SFabiano Rosas .start = { 888a645544SFabiano Rosas .use_dirty_ring = true, 898a645544SFabiano Rosas }, 908a645544SFabiano Rosas .listen_uri = uri, 918a645544SFabiano Rosas .connect_uri = uri, 928a645544SFabiano Rosas /* 938a645544SFabiano Rosas * Besides the precopy/unix basic test, cover dirty ring interface 948a645544SFabiano Rosas * rather than get-dirty-log. 958a645544SFabiano Rosas */ 968a645544SFabiano Rosas .live = true, 978a645544SFabiano Rosas }; 988a645544SFabiano Rosas 998a645544SFabiano Rosas test_precopy_common(&args); 1008a645544SFabiano Rosas } 1018a645544SFabiano Rosas 1027d9849c3SLi Zhijian #ifdef CONFIG_RDMA 1037d9849c3SLi Zhijian 1047b2e4f78SLi Zhijian #include <sys/resource.h> 1057b2e4f78SLi Zhijian 1067b2e4f78SLi Zhijian /* 1077b2e4f78SLi Zhijian * During migration over RDMA, it will try to pin portions of guest memory, 1087b2e4f78SLi Zhijian * typically exceeding 100MB in this test, while the remainder will be 1097b2e4f78SLi Zhijian * transmitted as compressed zero pages. 1107b2e4f78SLi Zhijian * 1117b2e4f78SLi Zhijian * REQUIRED_MEMLOCK_SZ indicates the minimal mlock size in the current context. 1127b2e4f78SLi Zhijian */ 1137b2e4f78SLi Zhijian #define REQUIRED_MEMLOCK_SZ (128 << 20) /* 128MB */ 1147b2e4f78SLi Zhijian 1157b2e4f78SLi Zhijian /* check 'ulimit -l' */ 1167b2e4f78SLi Zhijian static bool mlock_check(void) 1177b2e4f78SLi Zhijian { 1187b2e4f78SLi Zhijian uid_t uid; 1197b2e4f78SLi Zhijian struct rlimit rlim; 1207b2e4f78SLi Zhijian 1217b2e4f78SLi Zhijian uid = getuid(); 1227b2e4f78SLi Zhijian if (uid == 0) { 1237b2e4f78SLi Zhijian return true; 1247b2e4f78SLi Zhijian } 1257b2e4f78SLi Zhijian 1267b2e4f78SLi Zhijian if (getrlimit(RLIMIT_MEMLOCK, &rlim) != 0) { 1277b2e4f78SLi Zhijian return false; 1287b2e4f78SLi Zhijian } 1297b2e4f78SLi Zhijian 1307b2e4f78SLi Zhijian return rlim.rlim_cur >= REQUIRED_MEMLOCK_SZ; 1317b2e4f78SLi Zhijian } 1327b2e4f78SLi Zhijian 1337d9849c3SLi Zhijian #define RDMA_MIGRATION_HELPER "scripts/rdma-migration-helper.sh" 134*6b84c46eSLi Zhijian static int new_rdma_link(char *buffer, bool ipv6) 1357d9849c3SLi Zhijian { 1367d9849c3SLi Zhijian char cmd[256]; 1377d9849c3SLi Zhijian bool verbose = g_getenv("QTEST_LOG"); 1387d9849c3SLi Zhijian 139*6b84c46eSLi Zhijian snprintf(cmd, sizeof(cmd), "IP_FAMILY=%s %s detect %s", 140*6b84c46eSLi Zhijian ipv6 ? "ipv6" : "ipv4", RDMA_MIGRATION_HELPER, 1417d9849c3SLi Zhijian verbose ? "" : "2>/dev/null"); 1427d9849c3SLi Zhijian 1437d9849c3SLi Zhijian FILE *pipe = popen(cmd, "r"); 1447d9849c3SLi Zhijian if (pipe == NULL) { 1457d9849c3SLi Zhijian perror("Failed to run script"); 1467d9849c3SLi Zhijian return -1; 1477d9849c3SLi Zhijian } 1487d9849c3SLi Zhijian 1497d9849c3SLi Zhijian int idx = 0; 1507d9849c3SLi Zhijian while (fgets(buffer + idx, 128 - idx, pipe) != NULL) { 1517d9849c3SLi Zhijian idx += strlen(buffer); 1527d9849c3SLi Zhijian } 1537d9849c3SLi Zhijian 1547d9849c3SLi Zhijian int status = pclose(pipe); 1557d9849c3SLi Zhijian if (status == -1) { 1567d9849c3SLi Zhijian perror("Error reported by pclose()"); 1577d9849c3SLi Zhijian return -1; 1587d9849c3SLi Zhijian } else if (WIFEXITED(status)) { 1597d9849c3SLi Zhijian return WEXITSTATUS(status); 1607d9849c3SLi Zhijian } 1617d9849c3SLi Zhijian 1627d9849c3SLi Zhijian return -1; 1637d9849c3SLi Zhijian } 1647d9849c3SLi Zhijian 165*6b84c46eSLi Zhijian static void __test_precopy_rdma_plain(bool ipv6) 1667d9849c3SLi Zhijian { 1677d9849c3SLi Zhijian char buffer[128] = {}; 1687d9849c3SLi Zhijian 1697b2e4f78SLi Zhijian if (!mlock_check()) { 1707b2e4f78SLi Zhijian g_test_skip("'ulimit -l' is too small, require >=128M"); 1717b2e4f78SLi Zhijian return; 1727b2e4f78SLi Zhijian } 1737b2e4f78SLi Zhijian 174*6b84c46eSLi Zhijian if (new_rdma_link(buffer, ipv6)) { 1757d9849c3SLi Zhijian g_test_skip("No rdma link available\n" 1767d9849c3SLi Zhijian "# To enable the test:\n" 1777d9849c3SLi Zhijian "# Run \'" RDMA_MIGRATION_HELPER " setup\' with root to " 1787d9849c3SLi Zhijian "setup a new rdma/rxe link and rerun the test\n" 1797d9849c3SLi Zhijian "# Optional: run 'scripts/rdma-migration-helper.sh clean' " 1807d9849c3SLi Zhijian "to revert the 'setup'"); 1817d9849c3SLi Zhijian return; 1827d9849c3SLi Zhijian } 1837d9849c3SLi Zhijian 1847d9849c3SLi Zhijian /* 1857d9849c3SLi Zhijian * TODO: query a free port instead of hard code. 1867d9849c3SLi Zhijian * 29200=('R'+'D'+'M'+'A')*100 1877d9849c3SLi Zhijian **/ 1887d9849c3SLi Zhijian g_autofree char *uri = g_strdup_printf("rdma:%s:29200", buffer); 1897d9849c3SLi Zhijian 1907d9849c3SLi Zhijian MigrateCommon args = { 1917d9849c3SLi Zhijian .listen_uri = uri, 1927d9849c3SLi Zhijian .connect_uri = uri, 1937d9849c3SLi Zhijian }; 1947d9849c3SLi Zhijian 1957d9849c3SLi Zhijian test_precopy_common(&args); 1967d9849c3SLi Zhijian } 197*6b84c46eSLi Zhijian 198*6b84c46eSLi Zhijian static void test_precopy_rdma_plain(void) 199*6b84c46eSLi Zhijian { 200*6b84c46eSLi Zhijian __test_precopy_rdma_plain(false); 201*6b84c46eSLi Zhijian } 202*6b84c46eSLi Zhijian 203*6b84c46eSLi Zhijian static void test_precopy_rdma_plain_ipv6(void) 204*6b84c46eSLi Zhijian { 205*6b84c46eSLi Zhijian __test_precopy_rdma_plain(true); 206*6b84c46eSLi Zhijian } 2077d9849c3SLi Zhijian #endif 2087d9849c3SLi Zhijian 2098a645544SFabiano Rosas static void test_precopy_tcp_plain(void) 2108a645544SFabiano Rosas { 2118a645544SFabiano Rosas MigrateCommon args = { 2128a645544SFabiano Rosas .listen_uri = "tcp:127.0.0.1:0", 2138a645544SFabiano Rosas }; 2148a645544SFabiano Rosas 2158a645544SFabiano Rosas test_precopy_common(&args); 2168a645544SFabiano Rosas } 2178a645544SFabiano Rosas 2188a645544SFabiano Rosas static void test_precopy_tcp_switchover_ack(void) 2198a645544SFabiano Rosas { 2208a645544SFabiano Rosas MigrateCommon args = { 2218a645544SFabiano Rosas .listen_uri = "tcp:127.0.0.1:0", 222115cec9dSPrasad Pandit .start = { 223115cec9dSPrasad Pandit .caps[MIGRATION_CAPABILITY_RETURN_PATH] = true, 224115cec9dSPrasad Pandit .caps[MIGRATION_CAPABILITY_SWITCHOVER_ACK] = true, 225115cec9dSPrasad Pandit }, 2268a645544SFabiano Rosas /* 2278a645544SFabiano Rosas * Source VM must be running in order to consider the switchover ACK 2288a645544SFabiano Rosas * when deciding to do switchover or not. 2298a645544SFabiano Rosas */ 2308a645544SFabiano Rosas .live = true, 2318a645544SFabiano Rosas }; 2328a645544SFabiano Rosas 2338a645544SFabiano Rosas test_precopy_common(&args); 2348a645544SFabiano Rosas } 2358a645544SFabiano Rosas 2368a645544SFabiano Rosas #ifndef _WIN32 2378a645544SFabiano Rosas static void *migrate_hook_start_fd(QTestState *from, 2388a645544SFabiano Rosas QTestState *to) 2398a645544SFabiano Rosas { 2408a645544SFabiano Rosas int ret; 2418a645544SFabiano Rosas int pair[2]; 2428a645544SFabiano Rosas 2438a645544SFabiano Rosas /* Create two connected sockets for migration */ 2448a645544SFabiano Rosas ret = qemu_socketpair(PF_LOCAL, SOCK_STREAM, 0, pair); 2458a645544SFabiano Rosas g_assert_cmpint(ret, ==, 0); 2468a645544SFabiano Rosas 2478a645544SFabiano Rosas /* Send the 1st socket to the target */ 2488a645544SFabiano Rosas qtest_qmp_fds_assert_success(to, &pair[0], 1, 2498a645544SFabiano Rosas "{ 'execute': 'getfd'," 2508a645544SFabiano Rosas " 'arguments': { 'fdname': 'fd-mig' }}"); 2518a645544SFabiano Rosas close(pair[0]); 2528a645544SFabiano Rosas 2538a645544SFabiano Rosas /* Start incoming migration from the 1st socket */ 25443ca9d18SSteve Sistare migrate_incoming_qmp(to, "fd:fd-mig", NULL, "{}"); 2558a645544SFabiano Rosas 2568a645544SFabiano Rosas /* Send the 2nd socket to the target */ 2578a645544SFabiano Rosas qtest_qmp_fds_assert_success(from, &pair[1], 1, 2588a645544SFabiano Rosas "{ 'execute': 'getfd'," 2598a645544SFabiano Rosas " 'arguments': { 'fdname': 'fd-mig' }}"); 2608a645544SFabiano Rosas close(pair[1]); 2618a645544SFabiano Rosas 2628a645544SFabiano Rosas return NULL; 2638a645544SFabiano Rosas } 2648a645544SFabiano Rosas 2658a645544SFabiano Rosas static void migrate_hook_end_fd(QTestState *from, 2668a645544SFabiano Rosas QTestState *to, 2678a645544SFabiano Rosas void *opaque) 2688a645544SFabiano Rosas { 2698a645544SFabiano Rosas QDict *rsp; 2708a645544SFabiano Rosas const char *error_desc; 2718a645544SFabiano Rosas 2728a645544SFabiano Rosas /* Test closing fds */ 2738a645544SFabiano Rosas /* 2748a645544SFabiano Rosas * We assume, that QEMU removes named fd from its list, 2758a645544SFabiano Rosas * so this should fail. 2768a645544SFabiano Rosas */ 2778a645544SFabiano Rosas rsp = qtest_qmp(from, 2788a645544SFabiano Rosas "{ 'execute': 'closefd'," 2798a645544SFabiano Rosas " 'arguments': { 'fdname': 'fd-mig' }}"); 2808a645544SFabiano Rosas g_assert_true(qdict_haskey(rsp, "error")); 2818a645544SFabiano Rosas error_desc = qdict_get_str(qdict_get_qdict(rsp, "error"), "desc"); 2828a645544SFabiano Rosas g_assert_cmpstr(error_desc, ==, "File descriptor named 'fd-mig' not found"); 2838a645544SFabiano Rosas qobject_unref(rsp); 2848a645544SFabiano Rosas 2858a645544SFabiano Rosas rsp = qtest_qmp(to, 2868a645544SFabiano Rosas "{ 'execute': 'closefd'," 2878a645544SFabiano Rosas " 'arguments': { 'fdname': 'fd-mig' }}"); 2888a645544SFabiano Rosas g_assert_true(qdict_haskey(rsp, "error")); 2898a645544SFabiano Rosas error_desc = qdict_get_str(qdict_get_qdict(rsp, "error"), "desc"); 2908a645544SFabiano Rosas g_assert_cmpstr(error_desc, ==, "File descriptor named 'fd-mig' not found"); 2918a645544SFabiano Rosas qobject_unref(rsp); 2928a645544SFabiano Rosas } 2938a645544SFabiano Rosas 2948a645544SFabiano Rosas static void test_precopy_fd_socket(void) 2958a645544SFabiano Rosas { 2968a645544SFabiano Rosas MigrateCommon args = { 2978a645544SFabiano Rosas .listen_uri = "defer", 2988a645544SFabiano Rosas .connect_uri = "fd:fd-mig", 2998a645544SFabiano Rosas .start_hook = migrate_hook_start_fd, 3008a645544SFabiano Rosas .end_hook = migrate_hook_end_fd, 3018a645544SFabiano Rosas }; 3028a645544SFabiano Rosas test_precopy_common(&args); 3038a645544SFabiano Rosas } 3048a645544SFabiano Rosas 3058a645544SFabiano Rosas static void *migrate_hook_start_precopy_fd_file(QTestState *from, 3068a645544SFabiano Rosas QTestState *to) 3078a645544SFabiano Rosas { 3088a645544SFabiano Rosas g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME); 3098a645544SFabiano Rosas int src_flags = O_CREAT | O_RDWR; 3108a645544SFabiano Rosas int dst_flags = O_CREAT | O_RDWR; 3118a645544SFabiano Rosas int fds[2]; 3128a645544SFabiano Rosas 3138a645544SFabiano Rosas fds[0] = open(file, src_flags, 0660); 3148a645544SFabiano Rosas assert(fds[0] != -1); 3158a645544SFabiano Rosas 3168a645544SFabiano Rosas fds[1] = open(file, dst_flags, 0660); 3178a645544SFabiano Rosas assert(fds[1] != -1); 3188a645544SFabiano Rosas 3198a645544SFabiano Rosas 3208a645544SFabiano Rosas qtest_qmp_fds_assert_success(to, &fds[0], 1, 3218a645544SFabiano Rosas "{ 'execute': 'getfd'," 3228a645544SFabiano Rosas " 'arguments': { 'fdname': 'fd-mig' }}"); 3238a645544SFabiano Rosas 3248a645544SFabiano Rosas qtest_qmp_fds_assert_success(from, &fds[1], 1, 3258a645544SFabiano Rosas "{ 'execute': 'getfd'," 3268a645544SFabiano Rosas " 'arguments': { 'fdname': 'fd-mig' }}"); 3278a645544SFabiano Rosas 3288a645544SFabiano Rosas close(fds[0]); 3298a645544SFabiano Rosas close(fds[1]); 3308a645544SFabiano Rosas 3318a645544SFabiano Rosas return NULL; 3328a645544SFabiano Rosas } 3338a645544SFabiano Rosas 3348a645544SFabiano Rosas static void test_precopy_fd_file(void) 3358a645544SFabiano Rosas { 3368a645544SFabiano Rosas MigrateCommon args = { 3378a645544SFabiano Rosas .listen_uri = "defer", 3388a645544SFabiano Rosas .connect_uri = "fd:fd-mig", 3398a645544SFabiano Rosas .start_hook = migrate_hook_start_precopy_fd_file, 3408a645544SFabiano Rosas .end_hook = migrate_hook_end_fd, 3418a645544SFabiano Rosas }; 3428a645544SFabiano Rosas test_file_common(&args, true); 3438a645544SFabiano Rosas } 3448a645544SFabiano Rosas #endif /* _WIN32 */ 3458a645544SFabiano Rosas 3468a645544SFabiano Rosas /* 3478a645544SFabiano Rosas * The way auto_converge works, we need to do too many passes to 3488a645544SFabiano Rosas * run this test. Auto_converge logic is only run once every 3498a645544SFabiano Rosas * three iterations, so: 3508a645544SFabiano Rosas * 3518a645544SFabiano Rosas * - 3 iterations without auto_converge enabled 3528a645544SFabiano Rosas * - 3 iterations with pct = 5 3538a645544SFabiano Rosas * - 3 iterations with pct = 30 3548a645544SFabiano Rosas * - 3 iterations with pct = 55 3558a645544SFabiano Rosas * - 3 iterations with pct = 80 3568a645544SFabiano Rosas * - 3 iterations with pct = 95 (max(95, 80 + 25)) 3578a645544SFabiano Rosas * 3588a645544SFabiano Rosas * To make things even worse, we need to run the initial stage at 3598a645544SFabiano Rosas * 3MB/s so we enter autoconverge even when host is (over)loaded. 3608a645544SFabiano Rosas */ 3618a645544SFabiano Rosas static void test_auto_converge(void) 3628a645544SFabiano Rosas { 3638a645544SFabiano Rosas g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); 3648a645544SFabiano Rosas MigrateStart args = {}; 3658a645544SFabiano Rosas QTestState *from, *to; 3668a645544SFabiano Rosas int64_t percentage; 3678a645544SFabiano Rosas 3688a645544SFabiano Rosas /* 3698a645544SFabiano Rosas * We want the test to be stable and as fast as possible. 3708a645544SFabiano Rosas * E.g., with 1Gb/s bandwidth migration may pass without throttling, 3718a645544SFabiano Rosas * so we need to decrease a bandwidth. 3728a645544SFabiano Rosas */ 3738a645544SFabiano Rosas const int64_t init_pct = 5, inc_pct = 25, max_pct = 95; 3748a645544SFabiano Rosas uint64_t prev_dirty_sync_cnt, dirty_sync_cnt; 3758a645544SFabiano Rosas int max_try_count, hit = 0; 3768a645544SFabiano Rosas 3778a645544SFabiano Rosas if (migrate_start(&from, &to, uri, &args)) { 3788a645544SFabiano Rosas return; 3798a645544SFabiano Rosas } 3808a645544SFabiano Rosas 3818a645544SFabiano Rosas migrate_set_capability(from, "auto-converge", true); 3828a645544SFabiano Rosas migrate_set_parameter_int(from, "cpu-throttle-initial", init_pct); 3838a645544SFabiano Rosas migrate_set_parameter_int(from, "cpu-throttle-increment", inc_pct); 3848a645544SFabiano Rosas migrate_set_parameter_int(from, "max-cpu-throttle", max_pct); 3858a645544SFabiano Rosas 3868a645544SFabiano Rosas /* 3878a645544SFabiano Rosas * Set the initial parameters so that the migration could not converge 3888a645544SFabiano Rosas * without throttling. 3898a645544SFabiano Rosas */ 3908a645544SFabiano Rosas migrate_ensure_non_converge(from); 3918a645544SFabiano Rosas 3928a645544SFabiano Rosas /* To check remaining size after precopy */ 3938a645544SFabiano Rosas migrate_set_capability(from, "pause-before-switchover", true); 3948a645544SFabiano Rosas 3958a645544SFabiano Rosas /* Wait for the first serial output from the source */ 3968a645544SFabiano Rosas wait_for_serial("src_serial"); 3978a645544SFabiano Rosas 3988a645544SFabiano Rosas migrate_qmp(from, to, uri, NULL, "{}"); 3998a645544SFabiano Rosas 4008a645544SFabiano Rosas /* Wait for throttling begins */ 4018a645544SFabiano Rosas percentage = 0; 4028a645544SFabiano Rosas do { 4038a645544SFabiano Rosas percentage = read_migrate_property_int(from, "cpu-throttle-percentage"); 4048a645544SFabiano Rosas if (percentage != 0) { 4058a645544SFabiano Rosas break; 4068a645544SFabiano Rosas } 4078a645544SFabiano Rosas usleep(20); 4088a645544SFabiano Rosas g_assert_false(get_src()->stop_seen); 4098a645544SFabiano Rosas } while (true); 4108a645544SFabiano Rosas /* The first percentage of throttling should be at least init_pct */ 4118a645544SFabiano Rosas g_assert_cmpint(percentage, >=, init_pct); 4128a645544SFabiano Rosas 4138a645544SFabiano Rosas /* 4148a645544SFabiano Rosas * End the loop when the dirty sync count greater than 1. 4158a645544SFabiano Rosas */ 4168a645544SFabiano Rosas while ((dirty_sync_cnt = get_migration_pass(from)) < 2) { 4178a645544SFabiano Rosas usleep(1000 * 1000); 4188a645544SFabiano Rosas } 4198a645544SFabiano Rosas 4208a645544SFabiano Rosas prev_dirty_sync_cnt = dirty_sync_cnt; 4218a645544SFabiano Rosas 4228a645544SFabiano Rosas /* 4238a645544SFabiano Rosas * The RAMBlock dirty sync count must changes in 5 seconds, here we set 4248a645544SFabiano Rosas * the timeout to 10 seconds to ensure it changes. 4258a645544SFabiano Rosas * 4268a645544SFabiano Rosas * Note that migrate_ensure_non_converge set the max-bandwidth to 3MB/s, 4278a645544SFabiano Rosas * while the qtest mem is >= 100MB, one iteration takes at least 33s (100/3) 4288a645544SFabiano Rosas * to complete; this ensures that the RAMBlock dirty sync occurs. 4298a645544SFabiano Rosas */ 4308a645544SFabiano Rosas max_try_count = 10; 4318a645544SFabiano Rosas while (--max_try_count) { 4328a645544SFabiano Rosas dirty_sync_cnt = get_migration_pass(from); 4338a645544SFabiano Rosas if (dirty_sync_cnt != prev_dirty_sync_cnt) { 4348a645544SFabiano Rosas hit = 1; 4358a645544SFabiano Rosas break; 4368a645544SFabiano Rosas } 4378a645544SFabiano Rosas prev_dirty_sync_cnt = dirty_sync_cnt; 4388a645544SFabiano Rosas sleep(1); 4398a645544SFabiano Rosas } 4408a645544SFabiano Rosas g_assert_cmpint(hit, ==, 1); 4418a645544SFabiano Rosas 4428a645544SFabiano Rosas /* Now, when we tested that throttling works, let it converge */ 4438a645544SFabiano Rosas migrate_ensure_converge(from); 4448a645544SFabiano Rosas 4458a645544SFabiano Rosas /* 4468a645544SFabiano Rosas * Wait for pre-switchover status to check last throttle percentage 4478a645544SFabiano Rosas * and remaining. These values will be zeroed later 4488a645544SFabiano Rosas */ 4498a645544SFabiano Rosas wait_for_migration_status(from, "pre-switchover", NULL); 4508a645544SFabiano Rosas 4518a645544SFabiano Rosas /* The final percentage of throttling shouldn't be greater than max_pct */ 4528a645544SFabiano Rosas percentage = read_migrate_property_int(from, "cpu-throttle-percentage"); 4538a645544SFabiano Rosas g_assert_cmpint(percentage, <=, max_pct); 4548a645544SFabiano Rosas migrate_continue(from, "pre-switchover"); 4558a645544SFabiano Rosas 4568a645544SFabiano Rosas qtest_qmp_eventwait(to, "RESUME"); 4578a645544SFabiano Rosas 4588a645544SFabiano Rosas wait_for_serial("dest_serial"); 4598a645544SFabiano Rosas wait_for_migration_complete(from); 4608a645544SFabiano Rosas 4618a645544SFabiano Rosas migrate_end(from, to, true); 4628a645544SFabiano Rosas } 4638a645544SFabiano Rosas 4648a645544SFabiano Rosas static void * 4658a645544SFabiano Rosas migrate_hook_start_precopy_tcp_multifd(QTestState *from, 4668a645544SFabiano Rosas QTestState *to) 4678a645544SFabiano Rosas { 4688a645544SFabiano Rosas return migrate_hook_start_precopy_tcp_multifd_common(from, to, "none"); 4698a645544SFabiano Rosas } 4708a645544SFabiano Rosas 4718a645544SFabiano Rosas static void * 4728a645544SFabiano Rosas migrate_hook_start_precopy_tcp_multifd_zero_page_legacy(QTestState *from, 4738a645544SFabiano Rosas QTestState *to) 4748a645544SFabiano Rosas { 4758a645544SFabiano Rosas migrate_hook_start_precopy_tcp_multifd_common(from, to, "none"); 4768a645544SFabiano Rosas migrate_set_parameter_str(from, "zero-page-detection", "legacy"); 4778a645544SFabiano Rosas return NULL; 4788a645544SFabiano Rosas } 4798a645544SFabiano Rosas 4808a645544SFabiano Rosas static void * 4818a645544SFabiano Rosas migrate_hook_start_precopy_tcp_multifd_no_zero_page(QTestState *from, 4828a645544SFabiano Rosas QTestState *to) 4838a645544SFabiano Rosas { 4848a645544SFabiano Rosas migrate_hook_start_precopy_tcp_multifd_common(from, to, "none"); 4858a645544SFabiano Rosas migrate_set_parameter_str(from, "zero-page-detection", "none"); 4868a645544SFabiano Rosas return NULL; 4878a645544SFabiano Rosas } 4888a645544SFabiano Rosas 4898a645544SFabiano Rosas static void test_multifd_tcp_uri_none(void) 4908a645544SFabiano Rosas { 4918a645544SFabiano Rosas MigrateCommon args = { 4928a645544SFabiano Rosas .listen_uri = "defer", 4938a645544SFabiano Rosas .start_hook = migrate_hook_start_precopy_tcp_multifd, 494115cec9dSPrasad Pandit .start = { 495115cec9dSPrasad Pandit .caps[MIGRATION_CAPABILITY_MULTIFD] = true, 496115cec9dSPrasad Pandit }, 4978a645544SFabiano Rosas /* 4988a645544SFabiano Rosas * Multifd is more complicated than most of the features, it 4998a645544SFabiano Rosas * directly takes guest page buffers when sending, make sure 5008a645544SFabiano Rosas * everything will work alright even if guest page is changing. 5018a645544SFabiano Rosas */ 5028a645544SFabiano Rosas .live = true, 5038a645544SFabiano Rosas }; 5048a645544SFabiano Rosas test_precopy_common(&args); 5058a645544SFabiano Rosas } 5068a645544SFabiano Rosas 5078a645544SFabiano Rosas static void test_multifd_tcp_zero_page_legacy(void) 5088a645544SFabiano Rosas { 5098a645544SFabiano Rosas MigrateCommon args = { 5108a645544SFabiano Rosas .listen_uri = "defer", 5118a645544SFabiano Rosas .start_hook = migrate_hook_start_precopy_tcp_multifd_zero_page_legacy, 512115cec9dSPrasad Pandit .start = { 513115cec9dSPrasad Pandit .caps[MIGRATION_CAPABILITY_MULTIFD] = true, 514115cec9dSPrasad Pandit }, 5158a645544SFabiano Rosas /* 5168a645544SFabiano Rosas * Multifd is more complicated than most of the features, it 5178a645544SFabiano Rosas * directly takes guest page buffers when sending, make sure 5188a645544SFabiano Rosas * everything will work alright even if guest page is changing. 5198a645544SFabiano Rosas */ 5208a645544SFabiano Rosas .live = true, 5218a645544SFabiano Rosas }; 5228a645544SFabiano Rosas test_precopy_common(&args); 5238a645544SFabiano Rosas } 5248a645544SFabiano Rosas 5258a645544SFabiano Rosas static void test_multifd_tcp_no_zero_page(void) 5268a645544SFabiano Rosas { 5278a645544SFabiano Rosas MigrateCommon args = { 5288a645544SFabiano Rosas .listen_uri = "defer", 5298a645544SFabiano Rosas .start_hook = migrate_hook_start_precopy_tcp_multifd_no_zero_page, 530115cec9dSPrasad Pandit .start = { 531115cec9dSPrasad Pandit .caps[MIGRATION_CAPABILITY_MULTIFD] = true, 532115cec9dSPrasad Pandit }, 5338a645544SFabiano Rosas /* 5348a645544SFabiano Rosas * Multifd is more complicated than most of the features, it 5358a645544SFabiano Rosas * directly takes guest page buffers when sending, make sure 5368a645544SFabiano Rosas * everything will work alright even if guest page is changing. 5378a645544SFabiano Rosas */ 5388a645544SFabiano Rosas .live = true, 5398a645544SFabiano Rosas }; 5408a645544SFabiano Rosas test_precopy_common(&args); 5418a645544SFabiano Rosas } 5428a645544SFabiano Rosas 5438a645544SFabiano Rosas static void test_multifd_tcp_channels_none(void) 5448a645544SFabiano Rosas { 5458a645544SFabiano Rosas MigrateCommon args = { 5468a645544SFabiano Rosas .listen_uri = "defer", 5478a645544SFabiano Rosas .start_hook = migrate_hook_start_precopy_tcp_multifd, 5488a645544SFabiano Rosas .live = true, 549115cec9dSPrasad Pandit .start = { 550115cec9dSPrasad Pandit .caps[MIGRATION_CAPABILITY_MULTIFD] = true, 551115cec9dSPrasad Pandit }, 5528a645544SFabiano Rosas .connect_channels = ("[ { 'channel-type': 'main'," 5538a645544SFabiano Rosas " 'addr': { 'transport': 'socket'," 5548a645544SFabiano Rosas " 'type': 'inet'," 5558a645544SFabiano Rosas " 'host': '127.0.0.1'," 5568a645544SFabiano Rosas " 'port': '0' } } ]"), 5578a645544SFabiano Rosas }; 5588a645544SFabiano Rosas test_precopy_common(&args); 5598a645544SFabiano Rosas } 5608a645544SFabiano Rosas 5618a645544SFabiano Rosas /* 5628a645544SFabiano Rosas * This test does: 5638a645544SFabiano Rosas * source target 5648a645544SFabiano Rosas * migrate_incoming 5658a645544SFabiano Rosas * migrate 5668a645544SFabiano Rosas * migrate_cancel 5678a645544SFabiano Rosas * launch another target 5688a645544SFabiano Rosas * migrate 5698a645544SFabiano Rosas * 5708a645544SFabiano Rosas * And see that it works 5718a645544SFabiano Rosas */ 5728a645544SFabiano Rosas static void test_multifd_tcp_cancel(void) 5738a645544SFabiano Rosas { 5748a645544SFabiano Rosas MigrateStart args = { 5758a645544SFabiano Rosas .hide_stderr = true, 5768a645544SFabiano Rosas }; 5778a645544SFabiano Rosas QTestState *from, *to, *to2; 5788a645544SFabiano Rosas 5798a645544SFabiano Rosas if (migrate_start(&from, &to, "defer", &args)) { 5808a645544SFabiano Rosas return; 5818a645544SFabiano Rosas } 5828a645544SFabiano Rosas 5838a645544SFabiano Rosas migrate_ensure_non_converge(from); 5848a645544SFabiano Rosas migrate_prepare_for_dirty_mem(from); 5858a645544SFabiano Rosas 5868a645544SFabiano Rosas migrate_set_parameter_int(from, "multifd-channels", 16); 5878a645544SFabiano Rosas migrate_set_parameter_int(to, "multifd-channels", 16); 5888a645544SFabiano Rosas 5898a645544SFabiano Rosas migrate_set_capability(from, "multifd", true); 5908a645544SFabiano Rosas migrate_set_capability(to, "multifd", true); 5918a645544SFabiano Rosas 5928a645544SFabiano Rosas /* Start incoming migration from the 1st socket */ 59343ca9d18SSteve Sistare migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, "{}"); 5948a645544SFabiano Rosas 5958a645544SFabiano Rosas /* Wait for the first serial output from the source */ 5968a645544SFabiano Rosas wait_for_serial("src_serial"); 5978a645544SFabiano Rosas 5988a645544SFabiano Rosas migrate_qmp(from, to, NULL, NULL, "{}"); 5998a645544SFabiano Rosas 6008a645544SFabiano Rosas migrate_wait_for_dirty_mem(from, to); 6018a645544SFabiano Rosas 6028a645544SFabiano Rosas migrate_cancel(from); 6038a645544SFabiano Rosas 6048a645544SFabiano Rosas /* Make sure QEMU process "to" exited */ 6058a645544SFabiano Rosas qtest_set_expected_status(to, EXIT_FAILURE); 6068a645544SFabiano Rosas qtest_wait_qemu(to); 6078a645544SFabiano Rosas qtest_quit(to); 6088a645544SFabiano Rosas 6098a645544SFabiano Rosas /* 6108a645544SFabiano Rosas * Ensure the source QEMU finishes its cancellation process before we 6118a645544SFabiano Rosas * proceed with the setup of the next migration. The migrate_start() 6128a645544SFabiano Rosas * function and others might want to interact with the source in a way that 6138a645544SFabiano Rosas * is not possible while the migration is not canceled properly. For 6148a645544SFabiano Rosas * example, setting migration capabilities when the migration is still 6158a645544SFabiano Rosas * running leads to an error. 6168a645544SFabiano Rosas */ 6178a645544SFabiano Rosas wait_for_migration_status(from, "cancelled", NULL); 6188a645544SFabiano Rosas 6198a645544SFabiano Rosas args = (MigrateStart){ 6208a645544SFabiano Rosas .only_target = true, 6218a645544SFabiano Rosas }; 6228a645544SFabiano Rosas 6238a645544SFabiano Rosas if (migrate_start(&from, &to2, "defer", &args)) { 6248a645544SFabiano Rosas return; 6258a645544SFabiano Rosas } 6268a645544SFabiano Rosas 6278a645544SFabiano Rosas migrate_set_parameter_int(to2, "multifd-channels", 16); 6288a645544SFabiano Rosas 6298a645544SFabiano Rosas migrate_set_capability(to2, "multifd", true); 6308a645544SFabiano Rosas 6318a645544SFabiano Rosas /* Start incoming migration from the 1st socket */ 63243ca9d18SSteve Sistare migrate_incoming_qmp(to2, "tcp:127.0.0.1:0", NULL, "{}"); 6338a645544SFabiano Rosas 6348a645544SFabiano Rosas migrate_ensure_non_converge(from); 6358a645544SFabiano Rosas 6368a645544SFabiano Rosas migrate_qmp(from, to2, NULL, NULL, "{}"); 6378a645544SFabiano Rosas 6388a645544SFabiano Rosas migrate_wait_for_dirty_mem(from, to2); 6398a645544SFabiano Rosas 6408a645544SFabiano Rosas migrate_ensure_converge(from); 6418a645544SFabiano Rosas 6428a645544SFabiano Rosas wait_for_stop(from, get_src()); 6438a645544SFabiano Rosas qtest_qmp_eventwait(to2, "RESUME"); 6448a645544SFabiano Rosas 6458a645544SFabiano Rosas wait_for_serial("dest_serial"); 6468a645544SFabiano Rosas wait_for_migration_complete(from); 6478a645544SFabiano Rosas migrate_end(from, to2, true); 6488a645544SFabiano Rosas } 6498a645544SFabiano Rosas 650538e03d2SFabiano Rosas static void test_cancel_src_after_failed(QTestState *from, QTestState *to, 651538e03d2SFabiano Rosas const char *uri, const char *phase) 652538e03d2SFabiano Rosas { 653538e03d2SFabiano Rosas /* 654538e03d2SFabiano Rosas * No migrate_incoming_qmp() at the start to force source into 655538e03d2SFabiano Rosas * failed state during migrate_qmp(). 656538e03d2SFabiano Rosas */ 657538e03d2SFabiano Rosas 658538e03d2SFabiano Rosas wait_for_serial("src_serial"); 659538e03d2SFabiano Rosas migrate_ensure_converge(from); 660538e03d2SFabiano Rosas 661538e03d2SFabiano Rosas migrate_qmp(from, to, uri, NULL, "{}"); 662538e03d2SFabiano Rosas 663538e03d2SFabiano Rosas migration_event_wait(from, phase); 664538e03d2SFabiano Rosas migrate_cancel(from); 665538e03d2SFabiano Rosas 666538e03d2SFabiano Rosas /* cancelling will not move the migration out of 'failed' */ 667538e03d2SFabiano Rosas 668538e03d2SFabiano Rosas wait_for_migration_status(from, "failed", 669538e03d2SFabiano Rosas (const char * []) { "completed", NULL }); 670538e03d2SFabiano Rosas 671538e03d2SFabiano Rosas /* 672538e03d2SFabiano Rosas * Not waiting for the destination because it never started 673538e03d2SFabiano Rosas * migration. 674538e03d2SFabiano Rosas */ 675538e03d2SFabiano Rosas } 676538e03d2SFabiano Rosas 677538e03d2SFabiano Rosas static void test_cancel_src_after_cancelled(QTestState *from, QTestState *to, 678538e03d2SFabiano Rosas const char *uri, const char *phase) 679538e03d2SFabiano Rosas { 680538e03d2SFabiano Rosas migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }"); 681538e03d2SFabiano Rosas 682538e03d2SFabiano Rosas wait_for_serial("src_serial"); 683538e03d2SFabiano Rosas migrate_ensure_converge(from); 684538e03d2SFabiano Rosas 685538e03d2SFabiano Rosas migrate_qmp(from, to, uri, NULL, "{}"); 686538e03d2SFabiano Rosas 687538e03d2SFabiano Rosas /* To move to cancelled/cancelling */ 688538e03d2SFabiano Rosas migrate_cancel(from); 689538e03d2SFabiano Rosas migration_event_wait(from, phase); 690538e03d2SFabiano Rosas 691538e03d2SFabiano Rosas /* The migrate_cancel under test */ 692538e03d2SFabiano Rosas migrate_cancel(from); 693538e03d2SFabiano Rosas 694538e03d2SFabiano Rosas wait_for_migration_status(from, "cancelled", 695538e03d2SFabiano Rosas (const char * []) { "completed", NULL }); 696538e03d2SFabiano Rosas 697538e03d2SFabiano Rosas wait_for_migration_status(to, "failed", 698538e03d2SFabiano Rosas (const char * []) { "completed", NULL }); 699538e03d2SFabiano Rosas } 700538e03d2SFabiano Rosas 701538e03d2SFabiano Rosas static void test_cancel_src_after_complete(QTestState *from, QTestState *to, 702538e03d2SFabiano Rosas const char *uri, const char *phase) 703538e03d2SFabiano Rosas { 704538e03d2SFabiano Rosas migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }"); 705538e03d2SFabiano Rosas 706538e03d2SFabiano Rosas wait_for_serial("src_serial"); 707538e03d2SFabiano Rosas migrate_ensure_converge(from); 708538e03d2SFabiano Rosas 709538e03d2SFabiano Rosas migrate_qmp(from, to, uri, NULL, "{}"); 710538e03d2SFabiano Rosas 711538e03d2SFabiano Rosas migration_event_wait(from, phase); 712538e03d2SFabiano Rosas migrate_cancel(from); 713538e03d2SFabiano Rosas 714538e03d2SFabiano Rosas /* 715538e03d2SFabiano Rosas * qmp_migrate_cancel() exits early if migration is not running 716538e03d2SFabiano Rosas * anymore, the status will not change to cancelled. 717538e03d2SFabiano Rosas */ 718538e03d2SFabiano Rosas wait_for_migration_complete(from); 719538e03d2SFabiano Rosas wait_for_migration_complete(to); 720538e03d2SFabiano Rosas } 721538e03d2SFabiano Rosas 722538e03d2SFabiano Rosas static void test_cancel_src_after_none(QTestState *from, QTestState *to, 723538e03d2SFabiano Rosas const char *uri, const char *phase) 724538e03d2SFabiano Rosas { 725538e03d2SFabiano Rosas /* 726538e03d2SFabiano Rosas * Test that cancelling without a migration happening does not 727538e03d2SFabiano Rosas * affect subsequent migrations 728538e03d2SFabiano Rosas */ 729538e03d2SFabiano Rosas migrate_cancel(to); 730538e03d2SFabiano Rosas 731538e03d2SFabiano Rosas wait_for_serial("src_serial"); 732538e03d2SFabiano Rosas migrate_cancel(from); 733538e03d2SFabiano Rosas 734538e03d2SFabiano Rosas migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }"); 735538e03d2SFabiano Rosas 736538e03d2SFabiano Rosas migrate_ensure_converge(from); 737538e03d2SFabiano Rosas migrate_qmp(from, to, uri, NULL, "{}"); 738538e03d2SFabiano Rosas 739538e03d2SFabiano Rosas wait_for_migration_complete(from); 740538e03d2SFabiano Rosas wait_for_migration_complete(to); 741538e03d2SFabiano Rosas } 742538e03d2SFabiano Rosas 743538e03d2SFabiano Rosas static void test_cancel_src_pre_switchover(QTestState *from, QTestState *to, 744538e03d2SFabiano Rosas const char *uri, const char *phase) 745538e03d2SFabiano Rosas { 746538e03d2SFabiano Rosas migrate_set_capability(from, "pause-before-switchover", true); 747538e03d2SFabiano Rosas migrate_set_capability(to, "pause-before-switchover", true); 748538e03d2SFabiano Rosas 749538e03d2SFabiano Rosas migrate_set_capability(from, "multifd", true); 750538e03d2SFabiano Rosas migrate_set_capability(to, "multifd", true); 751538e03d2SFabiano Rosas 752538e03d2SFabiano Rosas migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }"); 753538e03d2SFabiano Rosas 754538e03d2SFabiano Rosas wait_for_serial("src_serial"); 755538e03d2SFabiano Rosas migrate_ensure_converge(from); 756538e03d2SFabiano Rosas 757538e03d2SFabiano Rosas migrate_qmp(from, to, uri, NULL, "{}"); 758538e03d2SFabiano Rosas 759538e03d2SFabiano Rosas migration_event_wait(from, phase); 760538e03d2SFabiano Rosas migrate_cancel(from); 761538e03d2SFabiano Rosas migration_event_wait(from, "cancelling"); 762538e03d2SFabiano Rosas 763538e03d2SFabiano Rosas wait_for_migration_status(from, "cancelled", 764538e03d2SFabiano Rosas (const char * []) { "completed", NULL }); 765538e03d2SFabiano Rosas 766538e03d2SFabiano Rosas wait_for_migration_status(to, "failed", 767538e03d2SFabiano Rosas (const char * []) { "completed", NULL }); 768538e03d2SFabiano Rosas } 769538e03d2SFabiano Rosas 770538e03d2SFabiano Rosas static void test_cancel_src_after_status(void *opaque) 771538e03d2SFabiano Rosas { 772538e03d2SFabiano Rosas const char *test_path = opaque; 773538e03d2SFabiano Rosas g_autofree char *phase = g_path_get_basename(test_path); 774538e03d2SFabiano Rosas g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); 775538e03d2SFabiano Rosas QTestState *from, *to; 776538e03d2SFabiano Rosas MigrateStart args = { 777538e03d2SFabiano Rosas .hide_stderr = true, 778538e03d2SFabiano Rosas }; 779538e03d2SFabiano Rosas 780538e03d2SFabiano Rosas if (migrate_start(&from, &to, "defer", &args)) { 781538e03d2SFabiano Rosas return; 782538e03d2SFabiano Rosas } 783538e03d2SFabiano Rosas 784538e03d2SFabiano Rosas if (g_str_equal(phase, "cancelling") || 785538e03d2SFabiano Rosas g_str_equal(phase, "cancelled")) { 786538e03d2SFabiano Rosas test_cancel_src_after_cancelled(from, to, uri, phase); 787538e03d2SFabiano Rosas 788538e03d2SFabiano Rosas } else if (g_str_equal(phase, "completed")) { 789538e03d2SFabiano Rosas test_cancel_src_after_complete(from, to, uri, phase); 790538e03d2SFabiano Rosas 791538e03d2SFabiano Rosas } else if (g_str_equal(phase, "failed")) { 792538e03d2SFabiano Rosas test_cancel_src_after_failed(from, to, uri, phase); 793538e03d2SFabiano Rosas 794538e03d2SFabiano Rosas } else if (g_str_equal(phase, "none")) { 795538e03d2SFabiano Rosas test_cancel_src_after_none(from, to, uri, phase); 796538e03d2SFabiano Rosas 797538e03d2SFabiano Rosas } else { 798538e03d2SFabiano Rosas /* any state that comes before pre-switchover */ 799538e03d2SFabiano Rosas test_cancel_src_pre_switchover(from, to, uri, phase); 800538e03d2SFabiano Rosas } 801538e03d2SFabiano Rosas 802538e03d2SFabiano Rosas migrate_end(from, to, false); 803538e03d2SFabiano Rosas } 804538e03d2SFabiano Rosas 8058a645544SFabiano Rosas static void calc_dirty_rate(QTestState *who, uint64_t calc_time) 8068a645544SFabiano Rosas { 8078a645544SFabiano Rosas qtest_qmp_assert_success(who, 8088a645544SFabiano Rosas "{ 'execute': 'calc-dirty-rate'," 8098a645544SFabiano Rosas "'arguments': { " 8108a645544SFabiano Rosas "'calc-time': %" PRIu64 "," 8118a645544SFabiano Rosas "'mode': 'dirty-ring' }}", 8128a645544SFabiano Rosas calc_time); 8138a645544SFabiano Rosas } 8148a645544SFabiano Rosas 8158a645544SFabiano Rosas static QDict *query_dirty_rate(QTestState *who) 8168a645544SFabiano Rosas { 8178a645544SFabiano Rosas return qtest_qmp_assert_success_ref(who, 8188a645544SFabiano Rosas "{ 'execute': 'query-dirty-rate' }"); 8198a645544SFabiano Rosas } 8208a645544SFabiano Rosas 8218a645544SFabiano Rosas static void dirtylimit_set_all(QTestState *who, uint64_t dirtyrate) 8228a645544SFabiano Rosas { 8238a645544SFabiano Rosas qtest_qmp_assert_success(who, 8248a645544SFabiano Rosas "{ 'execute': 'set-vcpu-dirty-limit'," 8258a645544SFabiano Rosas "'arguments': { " 8268a645544SFabiano Rosas "'dirty-rate': %" PRIu64 " } }", 8278a645544SFabiano Rosas dirtyrate); 8288a645544SFabiano Rosas } 8298a645544SFabiano Rosas 8308a645544SFabiano Rosas static void cancel_vcpu_dirty_limit(QTestState *who) 8318a645544SFabiano Rosas { 8328a645544SFabiano Rosas qtest_qmp_assert_success(who, 8338a645544SFabiano Rosas "{ 'execute': 'cancel-vcpu-dirty-limit' }"); 8348a645544SFabiano Rosas } 8358a645544SFabiano Rosas 8368a645544SFabiano Rosas static QDict *query_vcpu_dirty_limit(QTestState *who) 8378a645544SFabiano Rosas { 8388a645544SFabiano Rosas QDict *rsp; 8398a645544SFabiano Rosas 8408a645544SFabiano Rosas rsp = qtest_qmp(who, "{ 'execute': 'query-vcpu-dirty-limit' }"); 8418a645544SFabiano Rosas g_assert(!qdict_haskey(rsp, "error")); 8428a645544SFabiano Rosas g_assert(qdict_haskey(rsp, "return")); 8438a645544SFabiano Rosas 8448a645544SFabiano Rosas return rsp; 8458a645544SFabiano Rosas } 8468a645544SFabiano Rosas 8478a645544SFabiano Rosas static bool calc_dirtyrate_ready(QTestState *who) 8488a645544SFabiano Rosas { 8498a645544SFabiano Rosas QDict *rsp_return; 8508a645544SFabiano Rosas const char *status; 8518a645544SFabiano Rosas bool ready; 8528a645544SFabiano Rosas 8538a645544SFabiano Rosas rsp_return = query_dirty_rate(who); 8548a645544SFabiano Rosas g_assert(rsp_return); 8558a645544SFabiano Rosas 8568a645544SFabiano Rosas status = qdict_get_str(rsp_return, "status"); 8578a645544SFabiano Rosas g_assert(status); 8588a645544SFabiano Rosas ready = g_strcmp0(status, "measuring"); 8598a645544SFabiano Rosas qobject_unref(rsp_return); 8608a645544SFabiano Rosas 8618a645544SFabiano Rosas return ready; 8628a645544SFabiano Rosas } 8638a645544SFabiano Rosas 8648a645544SFabiano Rosas static void wait_for_calc_dirtyrate_complete(QTestState *who, 8658a645544SFabiano Rosas int64_t time_s) 8668a645544SFabiano Rosas { 8678a645544SFabiano Rosas int max_try_count = 10000; 8688a645544SFabiano Rosas usleep(time_s * 1000000); 8698a645544SFabiano Rosas 8708a645544SFabiano Rosas while (!calc_dirtyrate_ready(who) && max_try_count--) { 8718a645544SFabiano Rosas usleep(1000); 8728a645544SFabiano Rosas } 8738a645544SFabiano Rosas 8748a645544SFabiano Rosas /* 8758a645544SFabiano Rosas * Set the timeout with 10 s(max_try_count * 1000us), 8768a645544SFabiano Rosas * if dirtyrate measurement not complete, fail test. 8778a645544SFabiano Rosas */ 8788a645544SFabiano Rosas g_assert_cmpint(max_try_count, !=, 0); 8798a645544SFabiano Rosas } 8808a645544SFabiano Rosas 8818a645544SFabiano Rosas static int64_t get_dirty_rate(QTestState *who) 8828a645544SFabiano Rosas { 8838a645544SFabiano Rosas QDict *rsp_return; 8848a645544SFabiano Rosas const char *status; 8858a645544SFabiano Rosas QList *rates; 8868a645544SFabiano Rosas const QListEntry *entry; 8878a645544SFabiano Rosas QDict *rate; 8888a645544SFabiano Rosas int64_t dirtyrate; 8898a645544SFabiano Rosas 8908a645544SFabiano Rosas rsp_return = query_dirty_rate(who); 8918a645544SFabiano Rosas g_assert(rsp_return); 8928a645544SFabiano Rosas 8938a645544SFabiano Rosas status = qdict_get_str(rsp_return, "status"); 8948a645544SFabiano Rosas g_assert(status); 8958a645544SFabiano Rosas g_assert_cmpstr(status, ==, "measured"); 8968a645544SFabiano Rosas 8978a645544SFabiano Rosas rates = qdict_get_qlist(rsp_return, "vcpu-dirty-rate"); 8988a645544SFabiano Rosas g_assert(rates && !qlist_empty(rates)); 8998a645544SFabiano Rosas 9008a645544SFabiano Rosas entry = qlist_first(rates); 9018a645544SFabiano Rosas g_assert(entry); 9028a645544SFabiano Rosas 9038a645544SFabiano Rosas rate = qobject_to(QDict, qlist_entry_obj(entry)); 9048a645544SFabiano Rosas g_assert(rate); 9058a645544SFabiano Rosas 9068a645544SFabiano Rosas dirtyrate = qdict_get_try_int(rate, "dirty-rate", -1); 9078a645544SFabiano Rosas 9088a645544SFabiano Rosas qobject_unref(rsp_return); 9098a645544SFabiano Rosas return dirtyrate; 9108a645544SFabiano Rosas } 9118a645544SFabiano Rosas 9128a645544SFabiano Rosas static int64_t get_limit_rate(QTestState *who) 9138a645544SFabiano Rosas { 9148a645544SFabiano Rosas QDict *rsp_return; 9158a645544SFabiano Rosas QList *rates; 9168a645544SFabiano Rosas const QListEntry *entry; 9178a645544SFabiano Rosas QDict *rate; 9188a645544SFabiano Rosas int64_t dirtyrate; 9198a645544SFabiano Rosas 9208a645544SFabiano Rosas rsp_return = query_vcpu_dirty_limit(who); 9218a645544SFabiano Rosas g_assert(rsp_return); 9228a645544SFabiano Rosas 9238a645544SFabiano Rosas rates = qdict_get_qlist(rsp_return, "return"); 9248a645544SFabiano Rosas g_assert(rates && !qlist_empty(rates)); 9258a645544SFabiano Rosas 9268a645544SFabiano Rosas entry = qlist_first(rates); 9278a645544SFabiano Rosas g_assert(entry); 9288a645544SFabiano Rosas 9298a645544SFabiano Rosas rate = qobject_to(QDict, qlist_entry_obj(entry)); 9308a645544SFabiano Rosas g_assert(rate); 9318a645544SFabiano Rosas 9328a645544SFabiano Rosas dirtyrate = qdict_get_try_int(rate, "limit-rate", -1); 9338a645544SFabiano Rosas 9348a645544SFabiano Rosas qobject_unref(rsp_return); 9358a645544SFabiano Rosas return dirtyrate; 9368a645544SFabiano Rosas } 9378a645544SFabiano Rosas 9388a645544SFabiano Rosas static QTestState *dirtylimit_start_vm(void) 9398a645544SFabiano Rosas { 9408a645544SFabiano Rosas QTestState *vm = NULL; 9418a645544SFabiano Rosas g_autofree gchar *cmd = NULL; 9428a645544SFabiano Rosas const char *bootpath; 9438a645544SFabiano Rosas 9448a645544SFabiano Rosas bootpath = bootfile_create(qtest_get_arch(), tmpfs, false); 9458a645544SFabiano Rosas cmd = g_strdup_printf("-accel kvm,dirty-ring-size=4096 " 9468a645544SFabiano Rosas "-name dirtylimit-test,debug-threads=on " 9478a645544SFabiano Rosas "-m 150M -smp 1 " 9488a645544SFabiano Rosas "-serial file:%s/vm_serial " 9498a645544SFabiano Rosas "-drive file=%s,format=raw ", 9508a645544SFabiano Rosas tmpfs, bootpath); 9518a645544SFabiano Rosas 9528a645544SFabiano Rosas vm = qtest_init(cmd); 9538a645544SFabiano Rosas return vm; 9548a645544SFabiano Rosas } 9558a645544SFabiano Rosas 9568a645544SFabiano Rosas static void dirtylimit_stop_vm(QTestState *vm) 9578a645544SFabiano Rosas { 9588a645544SFabiano Rosas g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, "vm_serial"); 9598a645544SFabiano Rosas 9608a645544SFabiano Rosas qtest_quit(vm); 9618a645544SFabiano Rosas unlink(path); 9628a645544SFabiano Rosas } 9638a645544SFabiano Rosas 9648a645544SFabiano Rosas static void test_vcpu_dirty_limit(void) 9658a645544SFabiano Rosas { 9668a645544SFabiano Rosas QTestState *vm; 9678a645544SFabiano Rosas int64_t origin_rate; 9688a645544SFabiano Rosas int64_t quota_rate; 9698a645544SFabiano Rosas int64_t rate ; 9708a645544SFabiano Rosas int max_try_count = 20; 9718a645544SFabiano Rosas int hit = 0; 9728a645544SFabiano Rosas 9738a645544SFabiano Rosas /* Start vm for vcpu dirtylimit test */ 9748a645544SFabiano Rosas vm = dirtylimit_start_vm(); 9758a645544SFabiano Rosas 9768a645544SFabiano Rosas /* Wait for the first serial output from the vm*/ 9778a645544SFabiano Rosas wait_for_serial("vm_serial"); 9788a645544SFabiano Rosas 9798a645544SFabiano Rosas /* Do dirtyrate measurement with calc time equals 1s */ 9808a645544SFabiano Rosas calc_dirty_rate(vm, 1); 9818a645544SFabiano Rosas 9828a645544SFabiano Rosas /* Sleep calc time and wait for calc dirtyrate complete */ 9838a645544SFabiano Rosas wait_for_calc_dirtyrate_complete(vm, 1); 9848a645544SFabiano Rosas 9858a645544SFabiano Rosas /* Query original dirty page rate */ 9868a645544SFabiano Rosas origin_rate = get_dirty_rate(vm); 9878a645544SFabiano Rosas 9888a645544SFabiano Rosas /* VM booted from bootsect should dirty memory steadily */ 9898a645544SFabiano Rosas assert(origin_rate != 0); 9908a645544SFabiano Rosas 9918a645544SFabiano Rosas /* Setup quota dirty page rate at half of origin */ 9928a645544SFabiano Rosas quota_rate = origin_rate / 2; 9938a645544SFabiano Rosas 9948a645544SFabiano Rosas /* Set dirtylimit */ 9958a645544SFabiano Rosas dirtylimit_set_all(vm, quota_rate); 9968a645544SFabiano Rosas 9978a645544SFabiano Rosas /* 9988a645544SFabiano Rosas * Check if set-vcpu-dirty-limit and query-vcpu-dirty-limit 9998a645544SFabiano Rosas * works literally 10008a645544SFabiano Rosas */ 10018a645544SFabiano Rosas g_assert_cmpint(quota_rate, ==, get_limit_rate(vm)); 10028a645544SFabiano Rosas 10038a645544SFabiano Rosas /* Sleep a bit to check if it take effect */ 10048a645544SFabiano Rosas usleep(2000000); 10058a645544SFabiano Rosas 10068a645544SFabiano Rosas /* 10078a645544SFabiano Rosas * Check if dirtylimit take effect realistically, set the 10088a645544SFabiano Rosas * timeout with 20 s(max_try_count * 1s), if dirtylimit 10098a645544SFabiano Rosas * doesn't take effect, fail test. 10108a645544SFabiano Rosas */ 10118a645544SFabiano Rosas while (--max_try_count) { 10128a645544SFabiano Rosas calc_dirty_rate(vm, 1); 10138a645544SFabiano Rosas wait_for_calc_dirtyrate_complete(vm, 1); 10148a645544SFabiano Rosas rate = get_dirty_rate(vm); 10158a645544SFabiano Rosas 10168a645544SFabiano Rosas /* 10178a645544SFabiano Rosas * Assume hitting if current rate is less 10188a645544SFabiano Rosas * than quota rate (within accepting error) 10198a645544SFabiano Rosas */ 10208a645544SFabiano Rosas if (rate < (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) { 10218a645544SFabiano Rosas hit = 1; 10228a645544SFabiano Rosas break; 10238a645544SFabiano Rosas } 10248a645544SFabiano Rosas } 10258a645544SFabiano Rosas 10268a645544SFabiano Rosas g_assert_cmpint(hit, ==, 1); 10278a645544SFabiano Rosas 10288a645544SFabiano Rosas hit = 0; 10298a645544SFabiano Rosas max_try_count = 20; 10308a645544SFabiano Rosas 10318a645544SFabiano Rosas /* Check if dirtylimit cancellation take effect */ 10328a645544SFabiano Rosas cancel_vcpu_dirty_limit(vm); 10338a645544SFabiano Rosas while (--max_try_count) { 10348a645544SFabiano Rosas calc_dirty_rate(vm, 1); 10358a645544SFabiano Rosas wait_for_calc_dirtyrate_complete(vm, 1); 10368a645544SFabiano Rosas rate = get_dirty_rate(vm); 10378a645544SFabiano Rosas 10388a645544SFabiano Rosas /* 10398a645544SFabiano Rosas * Assume dirtylimit be canceled if current rate is 10408a645544SFabiano Rosas * greater than quota rate (within accepting error) 10418a645544SFabiano Rosas */ 10428a645544SFabiano Rosas if (rate > (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) { 10438a645544SFabiano Rosas hit = 1; 10448a645544SFabiano Rosas break; 10458a645544SFabiano Rosas } 10468a645544SFabiano Rosas } 10478a645544SFabiano Rosas 10488a645544SFabiano Rosas g_assert_cmpint(hit, ==, 1); 10498a645544SFabiano Rosas dirtylimit_stop_vm(vm); 10508a645544SFabiano Rosas } 10518a645544SFabiano Rosas 10528a645544SFabiano Rosas static void migrate_dirty_limit_wait_showup(QTestState *from, 10538a645544SFabiano Rosas const int64_t period, 10548a645544SFabiano Rosas const int64_t value) 10558a645544SFabiano Rosas { 10568a645544SFabiano Rosas /* Enable dirty limit capability */ 10578a645544SFabiano Rosas migrate_set_capability(from, "dirty-limit", true); 10588a645544SFabiano Rosas 10598a645544SFabiano Rosas /* Set dirty limit parameters */ 10608a645544SFabiano Rosas migrate_set_parameter_int(from, "x-vcpu-dirty-limit-period", period); 10618a645544SFabiano Rosas migrate_set_parameter_int(from, "vcpu-dirty-limit", value); 10628a645544SFabiano Rosas 10638a645544SFabiano Rosas /* Make sure migrate can't converge */ 10648a645544SFabiano Rosas migrate_ensure_non_converge(from); 10658a645544SFabiano Rosas 10668a645544SFabiano Rosas /* To check limit rate after precopy */ 10678a645544SFabiano Rosas migrate_set_capability(from, "pause-before-switchover", true); 10688a645544SFabiano Rosas 10698a645544SFabiano Rosas /* Wait for the serial output from the source */ 10708a645544SFabiano Rosas wait_for_serial("src_serial"); 10718a645544SFabiano Rosas } 10728a645544SFabiano Rosas 10738a645544SFabiano Rosas /* 10748a645544SFabiano Rosas * This test does: 10758a645544SFabiano Rosas * source destination 10768a645544SFabiano Rosas * start vm 10778a645544SFabiano Rosas * start incoming vm 10788a645544SFabiano Rosas * migrate 10798a645544SFabiano Rosas * wait dirty limit to begin 10808a645544SFabiano Rosas * cancel migrate 10818a645544SFabiano Rosas * cancellation check 10828a645544SFabiano Rosas * restart incoming vm 10838a645544SFabiano Rosas * migrate 10848a645544SFabiano Rosas * wait dirty limit to begin 10858a645544SFabiano Rosas * wait pre-switchover event 10868a645544SFabiano Rosas * convergence condition check 10878a645544SFabiano Rosas * 10888a645544SFabiano Rosas * And see if dirty limit migration works correctly. 10898a645544SFabiano Rosas * This test case involves many passes, so it runs in slow mode only. 10908a645544SFabiano Rosas */ 10918a645544SFabiano Rosas static void test_dirty_limit(void) 10928a645544SFabiano Rosas { 10938a645544SFabiano Rosas g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); 10948a645544SFabiano Rosas QTestState *from, *to; 10958a645544SFabiano Rosas int64_t remaining; 10968a645544SFabiano Rosas uint64_t throttle_us_per_full; 10978a645544SFabiano Rosas /* 10988a645544SFabiano Rosas * We want the test to be stable and as fast as possible. 10998a645544SFabiano Rosas * E.g., with 1Gb/s bandwidth migration may pass without dirty limit, 11008a645544SFabiano Rosas * so we need to decrease a bandwidth. 11018a645544SFabiano Rosas */ 11028a645544SFabiano Rosas const int64_t dirtylimit_period = 1000, dirtylimit_value = 50; 11038a645544SFabiano Rosas const int64_t max_bandwidth = 400000000; /* ~400Mb/s */ 11048a645544SFabiano Rosas const int64_t downtime_limit = 250; /* 250ms */ 11058a645544SFabiano Rosas /* 11068a645544SFabiano Rosas * We migrate through unix-socket (> 500Mb/s). 11078a645544SFabiano Rosas * Thus, expected migration speed ~= bandwidth limit (< 500Mb/s). 11088a645544SFabiano Rosas * So, we can predict expected_threshold 11098a645544SFabiano Rosas */ 11108a645544SFabiano Rosas const int64_t expected_threshold = max_bandwidth * downtime_limit / 1000; 11118a645544SFabiano Rosas int max_try_count = 10; 11128a645544SFabiano Rosas MigrateCommon args = { 11138a645544SFabiano Rosas .start = { 11148a645544SFabiano Rosas .hide_stderr = true, 11158a645544SFabiano Rosas .use_dirty_ring = true, 11168a645544SFabiano Rosas }, 11178a645544SFabiano Rosas .listen_uri = uri, 11188a645544SFabiano Rosas .connect_uri = uri, 11198a645544SFabiano Rosas }; 11208a645544SFabiano Rosas 11218a645544SFabiano Rosas /* Start src, dst vm */ 11228a645544SFabiano Rosas if (migrate_start(&from, &to, args.listen_uri, &args.start)) { 11238a645544SFabiano Rosas return; 11248a645544SFabiano Rosas } 11258a645544SFabiano Rosas 11268a645544SFabiano Rosas /* Prepare for dirty limit migration and wait src vm show up */ 11278a645544SFabiano Rosas migrate_dirty_limit_wait_showup(from, dirtylimit_period, dirtylimit_value); 11288a645544SFabiano Rosas 11298a645544SFabiano Rosas /* Start migrate */ 11308a645544SFabiano Rosas migrate_qmp(from, to, args.connect_uri, NULL, "{}"); 11318a645544SFabiano Rosas 11328a645544SFabiano Rosas /* Wait for dirty limit throttle begin */ 11338a645544SFabiano Rosas throttle_us_per_full = 0; 11348a645544SFabiano Rosas while (throttle_us_per_full == 0) { 11358a645544SFabiano Rosas throttle_us_per_full = 11368a645544SFabiano Rosas read_migrate_property_int(from, 11378a645544SFabiano Rosas "dirty-limit-throttle-time-per-round"); 11388a645544SFabiano Rosas usleep(100); 11398a645544SFabiano Rosas g_assert_false(get_src()->stop_seen); 11408a645544SFabiano Rosas } 11418a645544SFabiano Rosas 11428a645544SFabiano Rosas /* Now cancel migrate and wait for dirty limit throttle switch off */ 11438a645544SFabiano Rosas migrate_cancel(from); 11448a645544SFabiano Rosas wait_for_migration_status(from, "cancelled", NULL); 11458a645544SFabiano Rosas 1146cd196679SFabiano Rosas /* destination always fails after cancel */ 1147cd196679SFabiano Rosas migration_event_wait(to, "failed"); 1148cd196679SFabiano Rosas qtest_set_expected_status(to, EXIT_FAILURE); 1149cd196679SFabiano Rosas qtest_quit(to); 1150cd196679SFabiano Rosas 11518a645544SFabiano Rosas /* Check if dirty limit throttle switched off, set timeout 1ms */ 11528a645544SFabiano Rosas do { 11538a645544SFabiano Rosas throttle_us_per_full = 11548a645544SFabiano Rosas read_migrate_property_int(from, 11558a645544SFabiano Rosas "dirty-limit-throttle-time-per-round"); 11568a645544SFabiano Rosas usleep(100); 11578a645544SFabiano Rosas g_assert_false(get_src()->stop_seen); 11588a645544SFabiano Rosas } while (throttle_us_per_full != 0 && --max_try_count); 11598a645544SFabiano Rosas 11608a645544SFabiano Rosas /* Assert dirty limit is not in service */ 11618a645544SFabiano Rosas g_assert_cmpint(throttle_us_per_full, ==, 0); 11628a645544SFabiano Rosas 11638a645544SFabiano Rosas args = (MigrateCommon) { 11648a645544SFabiano Rosas .start = { 11658a645544SFabiano Rosas .only_target = true, 11668a645544SFabiano Rosas .use_dirty_ring = true, 11678a645544SFabiano Rosas }, 11688a645544SFabiano Rosas .listen_uri = uri, 11698a645544SFabiano Rosas .connect_uri = uri, 11708a645544SFabiano Rosas }; 11718a645544SFabiano Rosas 11728a645544SFabiano Rosas /* Restart dst vm, src vm already show up so we needn't wait anymore */ 11738a645544SFabiano Rosas if (migrate_start(&from, &to, args.listen_uri, &args.start)) { 11748a645544SFabiano Rosas return; 11758a645544SFabiano Rosas } 11768a645544SFabiano Rosas 11778a645544SFabiano Rosas /* Start migrate */ 11788a645544SFabiano Rosas migrate_qmp(from, to, args.connect_uri, NULL, "{}"); 11798a645544SFabiano Rosas 11808a645544SFabiano Rosas /* Wait for dirty limit throttle begin */ 11818a645544SFabiano Rosas throttle_us_per_full = 0; 11828a645544SFabiano Rosas while (throttle_us_per_full == 0) { 11838a645544SFabiano Rosas throttle_us_per_full = 11848a645544SFabiano Rosas read_migrate_property_int(from, 11858a645544SFabiano Rosas "dirty-limit-throttle-time-per-round"); 11868a645544SFabiano Rosas usleep(100); 11878a645544SFabiano Rosas g_assert_false(get_src()->stop_seen); 11888a645544SFabiano Rosas } 11898a645544SFabiano Rosas 11908a645544SFabiano Rosas /* 11918a645544SFabiano Rosas * The dirty limit rate should equals the return value of 11928a645544SFabiano Rosas * query-vcpu-dirty-limit if dirty limit cap set 11938a645544SFabiano Rosas */ 11948a645544SFabiano Rosas g_assert_cmpint(dirtylimit_value, ==, get_limit_rate(from)); 11958a645544SFabiano Rosas 11968a645544SFabiano Rosas /* Now, we have tested if dirty limit works, let it converge */ 11978a645544SFabiano Rosas migrate_set_parameter_int(from, "downtime-limit", downtime_limit); 11988a645544SFabiano Rosas migrate_set_parameter_int(from, "max-bandwidth", max_bandwidth); 11998a645544SFabiano Rosas 12008a645544SFabiano Rosas /* 12018a645544SFabiano Rosas * Wait for pre-switchover status to check if migration 12028a645544SFabiano Rosas * satisfy the convergence condition 12038a645544SFabiano Rosas */ 12048a645544SFabiano Rosas wait_for_migration_status(from, "pre-switchover", NULL); 12058a645544SFabiano Rosas 12068a645544SFabiano Rosas remaining = read_ram_property_int(from, "remaining"); 12078a645544SFabiano Rosas g_assert_cmpint(remaining, <, 12088a645544SFabiano Rosas (expected_threshold + expected_threshold / 100)); 12098a645544SFabiano Rosas 12108a645544SFabiano Rosas migrate_continue(from, "pre-switchover"); 12118a645544SFabiano Rosas 12128a645544SFabiano Rosas qtest_qmp_eventwait(to, "RESUME"); 12138a645544SFabiano Rosas 12148a645544SFabiano Rosas wait_for_serial("dest_serial"); 12158a645544SFabiano Rosas wait_for_migration_complete(from); 12168a645544SFabiano Rosas 12178a645544SFabiano Rosas migrate_end(from, to, true); 12188a645544SFabiano Rosas } 12198a645544SFabiano Rosas 122043ab3fb3SFabiano Rosas static void migration_test_add_precopy_smoke(MigrationTestEnv *env) 12218a645544SFabiano Rosas { 12228a645544SFabiano Rosas if (env->is_x86) { 12238a645544SFabiano Rosas migration_test_add("/migration/precopy/unix/suspend/live", 12248a645544SFabiano Rosas test_precopy_unix_suspend_live); 12258a645544SFabiano Rosas migration_test_add("/migration/precopy/unix/suspend/notlive", 12268a645544SFabiano Rosas test_precopy_unix_suspend_notlive); 12278a645544SFabiano Rosas } 12288a645544SFabiano Rosas 12298a645544SFabiano Rosas migration_test_add("/migration/precopy/unix/plain", 12308a645544SFabiano Rosas test_precopy_unix_plain); 12318a645544SFabiano Rosas 12328a645544SFabiano Rosas migration_test_add("/migration/precopy/tcp/plain", test_precopy_tcp_plain); 123343ab3fb3SFabiano Rosas migration_test_add("/migration/multifd/tcp/uri/plain/none", 123443ab3fb3SFabiano Rosas test_multifd_tcp_uri_none); 123543ab3fb3SFabiano Rosas migration_test_add("/migration/multifd/tcp/plain/cancel", 123643ab3fb3SFabiano Rosas test_multifd_tcp_cancel); 12377d9849c3SLi Zhijian #ifdef CONFIG_RDMA 12387d9849c3SLi Zhijian migration_test_add("/migration/precopy/rdma/plain", 12397d9849c3SLi Zhijian test_precopy_rdma_plain); 1240*6b84c46eSLi Zhijian migration_test_add("/migration/precopy/rdma/plain/ipv6", 1241*6b84c46eSLi Zhijian test_precopy_rdma_plain_ipv6); 12427d9849c3SLi Zhijian #endif 124343ab3fb3SFabiano Rosas } 124443ab3fb3SFabiano Rosas 124543ab3fb3SFabiano Rosas void migration_test_add_precopy(MigrationTestEnv *env) 124643ab3fb3SFabiano Rosas { 124743ab3fb3SFabiano Rosas tmpfs = env->tmpfs; 124843ab3fb3SFabiano Rosas 124943ab3fb3SFabiano Rosas migration_test_add_precopy_smoke(env); 125043ab3fb3SFabiano Rosas 125143ab3fb3SFabiano Rosas if (!env->full_set) { 125243ab3fb3SFabiano Rosas return; 125343ab3fb3SFabiano Rosas } 12548a645544SFabiano Rosas 12558a645544SFabiano Rosas migration_test_add("/migration/precopy/tcp/plain/switchover-ack", 12568a645544SFabiano Rosas test_precopy_tcp_switchover_ack); 12578a645544SFabiano Rosas 12588a645544SFabiano Rosas #ifndef _WIN32 12598a645544SFabiano Rosas migration_test_add("/migration/precopy/fd/tcp", 12608a645544SFabiano Rosas test_precopy_fd_socket); 12618a645544SFabiano Rosas migration_test_add("/migration/precopy/fd/file", 12628a645544SFabiano Rosas test_precopy_fd_file); 12638a645544SFabiano Rosas #endif 12648a645544SFabiano Rosas 12658a645544SFabiano Rosas /* 12668a645544SFabiano Rosas * See explanation why this test is slow on function definition 12678a645544SFabiano Rosas */ 12688a645544SFabiano Rosas if (g_test_slow()) { 12698a645544SFabiano Rosas migration_test_add("/migration/auto_converge", 12708a645544SFabiano Rosas test_auto_converge); 12718a645544SFabiano Rosas if (g_str_equal(env->arch, "x86_64") && 12728a645544SFabiano Rosas env->has_kvm && env->has_dirty_ring) { 12738a645544SFabiano Rosas migration_test_add("/dirty_limit", 12748a645544SFabiano Rosas test_dirty_limit); 12758a645544SFabiano Rosas } 12768a645544SFabiano Rosas } 12778a645544SFabiano Rosas migration_test_add("/migration/multifd/tcp/channels/plain/none", 12788a645544SFabiano Rosas test_multifd_tcp_channels_none); 12798a645544SFabiano Rosas migration_test_add("/migration/multifd/tcp/plain/zero-page/legacy", 12808a645544SFabiano Rosas test_multifd_tcp_zero_page_legacy); 12818a645544SFabiano Rosas migration_test_add("/migration/multifd/tcp/plain/zero-page/none", 12828a645544SFabiano Rosas test_multifd_tcp_no_zero_page); 12838a645544SFabiano Rosas if (g_str_equal(env->arch, "x86_64") 12848a645544SFabiano Rosas && env->has_kvm && env->has_dirty_ring) { 12858a645544SFabiano Rosas 12868a645544SFabiano Rosas migration_test_add("/migration/dirty_ring", 12878a645544SFabiano Rosas test_precopy_unix_dirty_ring); 12888a645544SFabiano Rosas if (qtest_has_machine("pc") && g_test_slow()) { 12898a645544SFabiano Rosas migration_test_add("/migration/vcpu_dirty_limit", 12908a645544SFabiano Rosas test_vcpu_dirty_limit); 12918a645544SFabiano Rosas } 12928a645544SFabiano Rosas } 1293538e03d2SFabiano Rosas 1294538e03d2SFabiano Rosas /* ensure new status don't go unnoticed */ 1295538e03d2SFabiano Rosas assert(MIGRATION_STATUS__MAX == 15); 1296538e03d2SFabiano Rosas 1297538e03d2SFabiano Rosas for (int i = MIGRATION_STATUS_NONE; i < MIGRATION_STATUS__MAX; i++) { 1298538e03d2SFabiano Rosas switch (i) { 1299538e03d2SFabiano Rosas case MIGRATION_STATUS_DEVICE: /* happens too fast */ 1300538e03d2SFabiano Rosas case MIGRATION_STATUS_WAIT_UNPLUG: /* no support in tests */ 1301538e03d2SFabiano Rosas case MIGRATION_STATUS_COLO: /* no support in tests */ 1302538e03d2SFabiano Rosas case MIGRATION_STATUS_POSTCOPY_ACTIVE: /* postcopy can't be cancelled */ 1303538e03d2SFabiano Rosas case MIGRATION_STATUS_POSTCOPY_PAUSED: 1304538e03d2SFabiano Rosas case MIGRATION_STATUS_POSTCOPY_RECOVER_SETUP: 1305538e03d2SFabiano Rosas case MIGRATION_STATUS_POSTCOPY_RECOVER: 1306538e03d2SFabiano Rosas continue; 1307538e03d2SFabiano Rosas default: 1308538e03d2SFabiano Rosas migration_test_add_suffix("/migration/cancel/src/after/", 1309538e03d2SFabiano Rosas MigrationStatus_str(i), 1310538e03d2SFabiano Rosas test_cancel_src_after_status); 1311538e03d2SFabiano Rosas } 1312538e03d2SFabiano Rosas } 13138a645544SFabiano Rosas } 1314