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" 22*407bc4bfSDaniel P. Berrangé #include "qobject/qlist.h" 238a645544SFabiano Rosas #include "qemu/module.h" 248a645544SFabiano Rosas #include "qemu/option.h" 258a645544SFabiano Rosas #include "qemu/range.h" 268a645544SFabiano Rosas #include "qemu/sockets.h" 278a645544SFabiano Rosas 288a645544SFabiano Rosas 298a645544SFabiano Rosas /* 308a645544SFabiano Rosas * Dirtylimit stop working if dirty page rate error 318a645544SFabiano Rosas * value less than DIRTYLIMIT_TOLERANCE_RANGE 328a645544SFabiano Rosas */ 338a645544SFabiano Rosas #define DIRTYLIMIT_TOLERANCE_RANGE 25 /* MB/s */ 348a645544SFabiano Rosas 358a645544SFabiano Rosas static char *tmpfs; 368a645544SFabiano Rosas 378a645544SFabiano Rosas static void test_precopy_unix_plain(void) 388a645544SFabiano Rosas { 398a645544SFabiano Rosas g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); 408a645544SFabiano Rosas MigrateCommon args = { 418a645544SFabiano Rosas .listen_uri = uri, 428a645544SFabiano Rosas .connect_uri = uri, 438a645544SFabiano Rosas /* 448a645544SFabiano Rosas * The simplest use case of precopy, covering smoke tests of 458a645544SFabiano Rosas * get-dirty-log dirty tracking. 468a645544SFabiano Rosas */ 478a645544SFabiano Rosas .live = true, 488a645544SFabiano Rosas }; 498a645544SFabiano Rosas 508a645544SFabiano Rosas test_precopy_common(&args); 518a645544SFabiano Rosas } 528a645544SFabiano Rosas 538a645544SFabiano Rosas static void test_precopy_unix_suspend_live(void) 548a645544SFabiano Rosas { 558a645544SFabiano Rosas g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); 568a645544SFabiano Rosas MigrateCommon args = { 578a645544SFabiano Rosas .listen_uri = uri, 588a645544SFabiano Rosas .connect_uri = uri, 598a645544SFabiano Rosas /* 608a645544SFabiano Rosas * despite being live, the test is fast because the src 618a645544SFabiano Rosas * suspends immediately. 628a645544SFabiano Rosas */ 638a645544SFabiano Rosas .live = true, 648a645544SFabiano Rosas .start.suspend_me = true, 658a645544SFabiano Rosas }; 668a645544SFabiano Rosas 678a645544SFabiano Rosas test_precopy_common(&args); 688a645544SFabiano Rosas } 698a645544SFabiano Rosas 708a645544SFabiano Rosas static void test_precopy_unix_suspend_notlive(void) 718a645544SFabiano Rosas { 728a645544SFabiano Rosas g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); 738a645544SFabiano Rosas MigrateCommon args = { 748a645544SFabiano Rosas .listen_uri = uri, 758a645544SFabiano Rosas .connect_uri = uri, 768a645544SFabiano Rosas .start.suspend_me = true, 778a645544SFabiano Rosas }; 788a645544SFabiano Rosas 798a645544SFabiano Rosas test_precopy_common(&args); 808a645544SFabiano Rosas } 818a645544SFabiano Rosas 828a645544SFabiano Rosas static void test_precopy_unix_dirty_ring(void) 838a645544SFabiano Rosas { 848a645544SFabiano Rosas g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); 858a645544SFabiano Rosas MigrateCommon args = { 868a645544SFabiano Rosas .start = { 878a645544SFabiano Rosas .use_dirty_ring = true, 888a645544SFabiano Rosas }, 898a645544SFabiano Rosas .listen_uri = uri, 908a645544SFabiano Rosas .connect_uri = uri, 918a645544SFabiano Rosas /* 928a645544SFabiano Rosas * Besides the precopy/unix basic test, cover dirty ring interface 938a645544SFabiano Rosas * rather than get-dirty-log. 948a645544SFabiano Rosas */ 958a645544SFabiano Rosas .live = true, 968a645544SFabiano Rosas }; 978a645544SFabiano Rosas 988a645544SFabiano Rosas test_precopy_common(&args); 998a645544SFabiano Rosas } 1008a645544SFabiano Rosas 1018a645544SFabiano Rosas static void test_precopy_tcp_plain(void) 1028a645544SFabiano Rosas { 1038a645544SFabiano Rosas MigrateCommon args = { 1048a645544SFabiano Rosas .listen_uri = "tcp:127.0.0.1:0", 1058a645544SFabiano Rosas }; 1068a645544SFabiano Rosas 1078a645544SFabiano Rosas test_precopy_common(&args); 1088a645544SFabiano Rosas } 1098a645544SFabiano Rosas 1108a645544SFabiano Rosas static void *migrate_hook_start_switchover_ack(QTestState *from, QTestState *to) 1118a645544SFabiano Rosas { 1128a645544SFabiano Rosas 1138a645544SFabiano Rosas migrate_set_capability(from, "return-path", true); 1148a645544SFabiano Rosas migrate_set_capability(to, "return-path", true); 1158a645544SFabiano Rosas 1168a645544SFabiano Rosas migrate_set_capability(from, "switchover-ack", true); 1178a645544SFabiano Rosas migrate_set_capability(to, "switchover-ack", true); 1188a645544SFabiano Rosas 1198a645544SFabiano Rosas return NULL; 1208a645544SFabiano Rosas } 1218a645544SFabiano Rosas 1228a645544SFabiano Rosas static void test_precopy_tcp_switchover_ack(void) 1238a645544SFabiano Rosas { 1248a645544SFabiano Rosas MigrateCommon args = { 1258a645544SFabiano Rosas .listen_uri = "tcp:127.0.0.1:0", 1268a645544SFabiano Rosas .start_hook = migrate_hook_start_switchover_ack, 1278a645544SFabiano Rosas /* 1288a645544SFabiano Rosas * Source VM must be running in order to consider the switchover ACK 1298a645544SFabiano Rosas * when deciding to do switchover or not. 1308a645544SFabiano Rosas */ 1318a645544SFabiano Rosas .live = true, 1328a645544SFabiano Rosas }; 1338a645544SFabiano Rosas 1348a645544SFabiano Rosas test_precopy_common(&args); 1358a645544SFabiano Rosas } 1368a645544SFabiano Rosas 1378a645544SFabiano Rosas #ifndef _WIN32 1388a645544SFabiano Rosas static void *migrate_hook_start_fd(QTestState *from, 1398a645544SFabiano Rosas QTestState *to) 1408a645544SFabiano Rosas { 1418a645544SFabiano Rosas int ret; 1428a645544SFabiano Rosas int pair[2]; 1438a645544SFabiano Rosas 1448a645544SFabiano Rosas /* Create two connected sockets for migration */ 1458a645544SFabiano Rosas ret = qemu_socketpair(PF_LOCAL, SOCK_STREAM, 0, pair); 1468a645544SFabiano Rosas g_assert_cmpint(ret, ==, 0); 1478a645544SFabiano Rosas 1488a645544SFabiano Rosas /* Send the 1st socket to the target */ 1498a645544SFabiano Rosas qtest_qmp_fds_assert_success(to, &pair[0], 1, 1508a645544SFabiano Rosas "{ 'execute': 'getfd'," 1518a645544SFabiano Rosas " 'arguments': { 'fdname': 'fd-mig' }}"); 1528a645544SFabiano Rosas close(pair[0]); 1538a645544SFabiano Rosas 1548a645544SFabiano Rosas /* Start incoming migration from the 1st socket */ 15543ca9d18SSteve Sistare migrate_incoming_qmp(to, "fd:fd-mig", NULL, "{}"); 1568a645544SFabiano Rosas 1578a645544SFabiano Rosas /* Send the 2nd socket to the target */ 1588a645544SFabiano Rosas qtest_qmp_fds_assert_success(from, &pair[1], 1, 1598a645544SFabiano Rosas "{ 'execute': 'getfd'," 1608a645544SFabiano Rosas " 'arguments': { 'fdname': 'fd-mig' }}"); 1618a645544SFabiano Rosas close(pair[1]); 1628a645544SFabiano Rosas 1638a645544SFabiano Rosas return NULL; 1648a645544SFabiano Rosas } 1658a645544SFabiano Rosas 1668a645544SFabiano Rosas static void migrate_hook_end_fd(QTestState *from, 1678a645544SFabiano Rosas QTestState *to, 1688a645544SFabiano Rosas void *opaque) 1698a645544SFabiano Rosas { 1708a645544SFabiano Rosas QDict *rsp; 1718a645544SFabiano Rosas const char *error_desc; 1728a645544SFabiano Rosas 1738a645544SFabiano Rosas /* Test closing fds */ 1748a645544SFabiano Rosas /* 1758a645544SFabiano Rosas * We assume, that QEMU removes named fd from its list, 1768a645544SFabiano Rosas * so this should fail. 1778a645544SFabiano Rosas */ 1788a645544SFabiano Rosas rsp = qtest_qmp(from, 1798a645544SFabiano Rosas "{ 'execute': 'closefd'," 1808a645544SFabiano Rosas " 'arguments': { 'fdname': 'fd-mig' }}"); 1818a645544SFabiano Rosas g_assert_true(qdict_haskey(rsp, "error")); 1828a645544SFabiano Rosas error_desc = qdict_get_str(qdict_get_qdict(rsp, "error"), "desc"); 1838a645544SFabiano Rosas g_assert_cmpstr(error_desc, ==, "File descriptor named 'fd-mig' not found"); 1848a645544SFabiano Rosas qobject_unref(rsp); 1858a645544SFabiano Rosas 1868a645544SFabiano Rosas rsp = qtest_qmp(to, 1878a645544SFabiano Rosas "{ 'execute': 'closefd'," 1888a645544SFabiano Rosas " 'arguments': { 'fdname': 'fd-mig' }}"); 1898a645544SFabiano Rosas g_assert_true(qdict_haskey(rsp, "error")); 1908a645544SFabiano Rosas error_desc = qdict_get_str(qdict_get_qdict(rsp, "error"), "desc"); 1918a645544SFabiano Rosas g_assert_cmpstr(error_desc, ==, "File descriptor named 'fd-mig' not found"); 1928a645544SFabiano Rosas qobject_unref(rsp); 1938a645544SFabiano Rosas } 1948a645544SFabiano Rosas 1958a645544SFabiano Rosas static void test_precopy_fd_socket(void) 1968a645544SFabiano Rosas { 1978a645544SFabiano Rosas MigrateCommon args = { 1988a645544SFabiano Rosas .listen_uri = "defer", 1998a645544SFabiano Rosas .connect_uri = "fd:fd-mig", 2008a645544SFabiano Rosas .start_hook = migrate_hook_start_fd, 2018a645544SFabiano Rosas .end_hook = migrate_hook_end_fd, 2028a645544SFabiano Rosas }; 2038a645544SFabiano Rosas test_precopy_common(&args); 2048a645544SFabiano Rosas } 2058a645544SFabiano Rosas 2068a645544SFabiano Rosas static void *migrate_hook_start_precopy_fd_file(QTestState *from, 2078a645544SFabiano Rosas QTestState *to) 2088a645544SFabiano Rosas { 2098a645544SFabiano Rosas g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME); 2108a645544SFabiano Rosas int src_flags = O_CREAT | O_RDWR; 2118a645544SFabiano Rosas int dst_flags = O_CREAT | O_RDWR; 2128a645544SFabiano Rosas int fds[2]; 2138a645544SFabiano Rosas 2148a645544SFabiano Rosas fds[0] = open(file, src_flags, 0660); 2158a645544SFabiano Rosas assert(fds[0] != -1); 2168a645544SFabiano Rosas 2178a645544SFabiano Rosas fds[1] = open(file, dst_flags, 0660); 2188a645544SFabiano Rosas assert(fds[1] != -1); 2198a645544SFabiano Rosas 2208a645544SFabiano Rosas 2218a645544SFabiano Rosas qtest_qmp_fds_assert_success(to, &fds[0], 1, 2228a645544SFabiano Rosas "{ 'execute': 'getfd'," 2238a645544SFabiano Rosas " 'arguments': { 'fdname': 'fd-mig' }}"); 2248a645544SFabiano Rosas 2258a645544SFabiano Rosas qtest_qmp_fds_assert_success(from, &fds[1], 1, 2268a645544SFabiano Rosas "{ 'execute': 'getfd'," 2278a645544SFabiano Rosas " 'arguments': { 'fdname': 'fd-mig' }}"); 2288a645544SFabiano Rosas 2298a645544SFabiano Rosas close(fds[0]); 2308a645544SFabiano Rosas close(fds[1]); 2318a645544SFabiano Rosas 2328a645544SFabiano Rosas return NULL; 2338a645544SFabiano Rosas } 2348a645544SFabiano Rosas 2358a645544SFabiano Rosas static void test_precopy_fd_file(void) 2368a645544SFabiano Rosas { 2378a645544SFabiano Rosas MigrateCommon args = { 2388a645544SFabiano Rosas .listen_uri = "defer", 2398a645544SFabiano Rosas .connect_uri = "fd:fd-mig", 2408a645544SFabiano Rosas .start_hook = migrate_hook_start_precopy_fd_file, 2418a645544SFabiano Rosas .end_hook = migrate_hook_end_fd, 2428a645544SFabiano Rosas }; 2438a645544SFabiano Rosas test_file_common(&args, true); 2448a645544SFabiano Rosas } 2458a645544SFabiano Rosas #endif /* _WIN32 */ 2468a645544SFabiano Rosas 2478a645544SFabiano Rosas /* 2488a645544SFabiano Rosas * The way auto_converge works, we need to do too many passes to 2498a645544SFabiano Rosas * run this test. Auto_converge logic is only run once every 2508a645544SFabiano Rosas * three iterations, so: 2518a645544SFabiano Rosas * 2528a645544SFabiano Rosas * - 3 iterations without auto_converge enabled 2538a645544SFabiano Rosas * - 3 iterations with pct = 5 2548a645544SFabiano Rosas * - 3 iterations with pct = 30 2558a645544SFabiano Rosas * - 3 iterations with pct = 55 2568a645544SFabiano Rosas * - 3 iterations with pct = 80 2578a645544SFabiano Rosas * - 3 iterations with pct = 95 (max(95, 80 + 25)) 2588a645544SFabiano Rosas * 2598a645544SFabiano Rosas * To make things even worse, we need to run the initial stage at 2608a645544SFabiano Rosas * 3MB/s so we enter autoconverge even when host is (over)loaded. 2618a645544SFabiano Rosas */ 2628a645544SFabiano Rosas static void test_auto_converge(void) 2638a645544SFabiano Rosas { 2648a645544SFabiano Rosas g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); 2658a645544SFabiano Rosas MigrateStart args = {}; 2668a645544SFabiano Rosas QTestState *from, *to; 2678a645544SFabiano Rosas int64_t percentage; 2688a645544SFabiano Rosas 2698a645544SFabiano Rosas /* 2708a645544SFabiano Rosas * We want the test to be stable and as fast as possible. 2718a645544SFabiano Rosas * E.g., with 1Gb/s bandwidth migration may pass without throttling, 2728a645544SFabiano Rosas * so we need to decrease a bandwidth. 2738a645544SFabiano Rosas */ 2748a645544SFabiano Rosas const int64_t init_pct = 5, inc_pct = 25, max_pct = 95; 2758a645544SFabiano Rosas uint64_t prev_dirty_sync_cnt, dirty_sync_cnt; 2768a645544SFabiano Rosas int max_try_count, hit = 0; 2778a645544SFabiano Rosas 2788a645544SFabiano Rosas if (migrate_start(&from, &to, uri, &args)) { 2798a645544SFabiano Rosas return; 2808a645544SFabiano Rosas } 2818a645544SFabiano Rosas 2828a645544SFabiano Rosas migrate_set_capability(from, "auto-converge", true); 2838a645544SFabiano Rosas migrate_set_parameter_int(from, "cpu-throttle-initial", init_pct); 2848a645544SFabiano Rosas migrate_set_parameter_int(from, "cpu-throttle-increment", inc_pct); 2858a645544SFabiano Rosas migrate_set_parameter_int(from, "max-cpu-throttle", max_pct); 2868a645544SFabiano Rosas 2878a645544SFabiano Rosas /* 2888a645544SFabiano Rosas * Set the initial parameters so that the migration could not converge 2898a645544SFabiano Rosas * without throttling. 2908a645544SFabiano Rosas */ 2918a645544SFabiano Rosas migrate_ensure_non_converge(from); 2928a645544SFabiano Rosas 2938a645544SFabiano Rosas /* To check remaining size after precopy */ 2948a645544SFabiano Rosas migrate_set_capability(from, "pause-before-switchover", true); 2958a645544SFabiano Rosas 2968a645544SFabiano Rosas /* Wait for the first serial output from the source */ 2978a645544SFabiano Rosas wait_for_serial("src_serial"); 2988a645544SFabiano Rosas 2998a645544SFabiano Rosas migrate_qmp(from, to, uri, NULL, "{}"); 3008a645544SFabiano Rosas 3018a645544SFabiano Rosas /* Wait for throttling begins */ 3028a645544SFabiano Rosas percentage = 0; 3038a645544SFabiano Rosas do { 3048a645544SFabiano Rosas percentage = read_migrate_property_int(from, "cpu-throttle-percentage"); 3058a645544SFabiano Rosas if (percentage != 0) { 3068a645544SFabiano Rosas break; 3078a645544SFabiano Rosas } 3088a645544SFabiano Rosas usleep(20); 3098a645544SFabiano Rosas g_assert_false(get_src()->stop_seen); 3108a645544SFabiano Rosas } while (true); 3118a645544SFabiano Rosas /* The first percentage of throttling should be at least init_pct */ 3128a645544SFabiano Rosas g_assert_cmpint(percentage, >=, init_pct); 3138a645544SFabiano Rosas 3148a645544SFabiano Rosas /* 3158a645544SFabiano Rosas * End the loop when the dirty sync count greater than 1. 3168a645544SFabiano Rosas */ 3178a645544SFabiano Rosas while ((dirty_sync_cnt = get_migration_pass(from)) < 2) { 3188a645544SFabiano Rosas usleep(1000 * 1000); 3198a645544SFabiano Rosas } 3208a645544SFabiano Rosas 3218a645544SFabiano Rosas prev_dirty_sync_cnt = dirty_sync_cnt; 3228a645544SFabiano Rosas 3238a645544SFabiano Rosas /* 3248a645544SFabiano Rosas * The RAMBlock dirty sync count must changes in 5 seconds, here we set 3258a645544SFabiano Rosas * the timeout to 10 seconds to ensure it changes. 3268a645544SFabiano Rosas * 3278a645544SFabiano Rosas * Note that migrate_ensure_non_converge set the max-bandwidth to 3MB/s, 3288a645544SFabiano Rosas * while the qtest mem is >= 100MB, one iteration takes at least 33s (100/3) 3298a645544SFabiano Rosas * to complete; this ensures that the RAMBlock dirty sync occurs. 3308a645544SFabiano Rosas */ 3318a645544SFabiano Rosas max_try_count = 10; 3328a645544SFabiano Rosas while (--max_try_count) { 3338a645544SFabiano Rosas dirty_sync_cnt = get_migration_pass(from); 3348a645544SFabiano Rosas if (dirty_sync_cnt != prev_dirty_sync_cnt) { 3358a645544SFabiano Rosas hit = 1; 3368a645544SFabiano Rosas break; 3378a645544SFabiano Rosas } 3388a645544SFabiano Rosas prev_dirty_sync_cnt = dirty_sync_cnt; 3398a645544SFabiano Rosas sleep(1); 3408a645544SFabiano Rosas } 3418a645544SFabiano Rosas g_assert_cmpint(hit, ==, 1); 3428a645544SFabiano Rosas 3438a645544SFabiano Rosas /* Now, when we tested that throttling works, let it converge */ 3448a645544SFabiano Rosas migrate_ensure_converge(from); 3458a645544SFabiano Rosas 3468a645544SFabiano Rosas /* 3478a645544SFabiano Rosas * Wait for pre-switchover status to check last throttle percentage 3488a645544SFabiano Rosas * and remaining. These values will be zeroed later 3498a645544SFabiano Rosas */ 3508a645544SFabiano Rosas wait_for_migration_status(from, "pre-switchover", NULL); 3518a645544SFabiano Rosas 3528a645544SFabiano Rosas /* The final percentage of throttling shouldn't be greater than max_pct */ 3538a645544SFabiano Rosas percentage = read_migrate_property_int(from, "cpu-throttle-percentage"); 3548a645544SFabiano Rosas g_assert_cmpint(percentage, <=, max_pct); 3558a645544SFabiano Rosas migrate_continue(from, "pre-switchover"); 3568a645544SFabiano Rosas 3578a645544SFabiano Rosas qtest_qmp_eventwait(to, "RESUME"); 3588a645544SFabiano Rosas 3598a645544SFabiano Rosas wait_for_serial("dest_serial"); 3608a645544SFabiano Rosas wait_for_migration_complete(from); 3618a645544SFabiano Rosas 3628a645544SFabiano Rosas migrate_end(from, to, true); 3638a645544SFabiano Rosas } 3648a645544SFabiano Rosas 3658a645544SFabiano Rosas static void * 3668a645544SFabiano Rosas migrate_hook_start_precopy_tcp_multifd(QTestState *from, 3678a645544SFabiano Rosas QTestState *to) 3688a645544SFabiano Rosas { 3698a645544SFabiano Rosas return migrate_hook_start_precopy_tcp_multifd_common(from, to, "none"); 3708a645544SFabiano Rosas } 3718a645544SFabiano Rosas 3728a645544SFabiano Rosas static void * 3738a645544SFabiano Rosas migrate_hook_start_precopy_tcp_multifd_zero_page_legacy(QTestState *from, 3748a645544SFabiano Rosas QTestState *to) 3758a645544SFabiano Rosas { 3768a645544SFabiano Rosas migrate_hook_start_precopy_tcp_multifd_common(from, to, "none"); 3778a645544SFabiano Rosas migrate_set_parameter_str(from, "zero-page-detection", "legacy"); 3788a645544SFabiano Rosas return NULL; 3798a645544SFabiano Rosas } 3808a645544SFabiano Rosas 3818a645544SFabiano Rosas static void * 3828a645544SFabiano Rosas migrate_hook_start_precopy_tcp_multifd_no_zero_page(QTestState *from, 3838a645544SFabiano Rosas QTestState *to) 3848a645544SFabiano Rosas { 3858a645544SFabiano Rosas migrate_hook_start_precopy_tcp_multifd_common(from, to, "none"); 3868a645544SFabiano Rosas migrate_set_parameter_str(from, "zero-page-detection", "none"); 3878a645544SFabiano Rosas return NULL; 3888a645544SFabiano Rosas } 3898a645544SFabiano Rosas 3908a645544SFabiano Rosas static void test_multifd_tcp_uri_none(void) 3918a645544SFabiano Rosas { 3928a645544SFabiano Rosas MigrateCommon args = { 3938a645544SFabiano Rosas .listen_uri = "defer", 3948a645544SFabiano Rosas .start_hook = migrate_hook_start_precopy_tcp_multifd, 3958a645544SFabiano Rosas /* 3968a645544SFabiano Rosas * Multifd is more complicated than most of the features, it 3978a645544SFabiano Rosas * directly takes guest page buffers when sending, make sure 3988a645544SFabiano Rosas * everything will work alright even if guest page is changing. 3998a645544SFabiano Rosas */ 4008a645544SFabiano Rosas .live = true, 4018a645544SFabiano Rosas }; 4028a645544SFabiano Rosas test_precopy_common(&args); 4038a645544SFabiano Rosas } 4048a645544SFabiano Rosas 4058a645544SFabiano Rosas static void test_multifd_tcp_zero_page_legacy(void) 4068a645544SFabiano Rosas { 4078a645544SFabiano Rosas MigrateCommon args = { 4088a645544SFabiano Rosas .listen_uri = "defer", 4098a645544SFabiano Rosas .start_hook = migrate_hook_start_precopy_tcp_multifd_zero_page_legacy, 4108a645544SFabiano Rosas /* 4118a645544SFabiano Rosas * Multifd is more complicated than most of the features, it 4128a645544SFabiano Rosas * directly takes guest page buffers when sending, make sure 4138a645544SFabiano Rosas * everything will work alright even if guest page is changing. 4148a645544SFabiano Rosas */ 4158a645544SFabiano Rosas .live = true, 4168a645544SFabiano Rosas }; 4178a645544SFabiano Rosas test_precopy_common(&args); 4188a645544SFabiano Rosas } 4198a645544SFabiano Rosas 4208a645544SFabiano Rosas static void test_multifd_tcp_no_zero_page(void) 4218a645544SFabiano Rosas { 4228a645544SFabiano Rosas MigrateCommon args = { 4238a645544SFabiano Rosas .listen_uri = "defer", 4248a645544SFabiano Rosas .start_hook = migrate_hook_start_precopy_tcp_multifd_no_zero_page, 4258a645544SFabiano Rosas /* 4268a645544SFabiano Rosas * Multifd is more complicated than most of the features, it 4278a645544SFabiano Rosas * directly takes guest page buffers when sending, make sure 4288a645544SFabiano Rosas * everything will work alright even if guest page is changing. 4298a645544SFabiano Rosas */ 4308a645544SFabiano Rosas .live = true, 4318a645544SFabiano Rosas }; 4328a645544SFabiano Rosas test_precopy_common(&args); 4338a645544SFabiano Rosas } 4348a645544SFabiano Rosas 4358a645544SFabiano Rosas static void test_multifd_tcp_channels_none(void) 4368a645544SFabiano Rosas { 4378a645544SFabiano Rosas MigrateCommon args = { 4388a645544SFabiano Rosas .listen_uri = "defer", 4398a645544SFabiano Rosas .start_hook = migrate_hook_start_precopy_tcp_multifd, 4408a645544SFabiano Rosas .live = true, 4418a645544SFabiano Rosas .connect_channels = ("[ { 'channel-type': 'main'," 4428a645544SFabiano Rosas " 'addr': { 'transport': 'socket'," 4438a645544SFabiano Rosas " 'type': 'inet'," 4448a645544SFabiano Rosas " 'host': '127.0.0.1'," 4458a645544SFabiano Rosas " 'port': '0' } } ]"), 4468a645544SFabiano Rosas }; 4478a645544SFabiano Rosas test_precopy_common(&args); 4488a645544SFabiano Rosas } 4498a645544SFabiano Rosas 4508a645544SFabiano Rosas /* 4518a645544SFabiano Rosas * This test does: 4528a645544SFabiano Rosas * source target 4538a645544SFabiano Rosas * migrate_incoming 4548a645544SFabiano Rosas * migrate 4558a645544SFabiano Rosas * migrate_cancel 4568a645544SFabiano Rosas * launch another target 4578a645544SFabiano Rosas * migrate 4588a645544SFabiano Rosas * 4598a645544SFabiano Rosas * And see that it works 4608a645544SFabiano Rosas */ 4618a645544SFabiano Rosas static void test_multifd_tcp_cancel(void) 4628a645544SFabiano Rosas { 4638a645544SFabiano Rosas MigrateStart args = { 4648a645544SFabiano Rosas .hide_stderr = true, 4658a645544SFabiano Rosas }; 4668a645544SFabiano Rosas QTestState *from, *to, *to2; 4678a645544SFabiano Rosas 4688a645544SFabiano Rosas if (migrate_start(&from, &to, "defer", &args)) { 4698a645544SFabiano Rosas return; 4708a645544SFabiano Rosas } 4718a645544SFabiano Rosas 4728a645544SFabiano Rosas migrate_ensure_non_converge(from); 4738a645544SFabiano Rosas migrate_prepare_for_dirty_mem(from); 4748a645544SFabiano Rosas 4758a645544SFabiano Rosas migrate_set_parameter_int(from, "multifd-channels", 16); 4768a645544SFabiano Rosas migrate_set_parameter_int(to, "multifd-channels", 16); 4778a645544SFabiano Rosas 4788a645544SFabiano Rosas migrate_set_capability(from, "multifd", true); 4798a645544SFabiano Rosas migrate_set_capability(to, "multifd", true); 4808a645544SFabiano Rosas 4818a645544SFabiano Rosas /* Start incoming migration from the 1st socket */ 48243ca9d18SSteve Sistare migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, "{}"); 4838a645544SFabiano Rosas 4848a645544SFabiano Rosas /* Wait for the first serial output from the source */ 4858a645544SFabiano Rosas wait_for_serial("src_serial"); 4868a645544SFabiano Rosas 4878a645544SFabiano Rosas migrate_qmp(from, to, NULL, NULL, "{}"); 4888a645544SFabiano Rosas 4898a645544SFabiano Rosas migrate_wait_for_dirty_mem(from, to); 4908a645544SFabiano Rosas 4918a645544SFabiano Rosas migrate_cancel(from); 4928a645544SFabiano Rosas 4938a645544SFabiano Rosas /* Make sure QEMU process "to" exited */ 4948a645544SFabiano Rosas qtest_set_expected_status(to, EXIT_FAILURE); 4958a645544SFabiano Rosas qtest_wait_qemu(to); 4968a645544SFabiano Rosas qtest_quit(to); 4978a645544SFabiano Rosas 4988a645544SFabiano Rosas /* 4998a645544SFabiano Rosas * Ensure the source QEMU finishes its cancellation process before we 5008a645544SFabiano Rosas * proceed with the setup of the next migration. The migrate_start() 5018a645544SFabiano Rosas * function and others might want to interact with the source in a way that 5028a645544SFabiano Rosas * is not possible while the migration is not canceled properly. For 5038a645544SFabiano Rosas * example, setting migration capabilities when the migration is still 5048a645544SFabiano Rosas * running leads to an error. 5058a645544SFabiano Rosas */ 5068a645544SFabiano Rosas wait_for_migration_status(from, "cancelled", NULL); 5078a645544SFabiano Rosas 5088a645544SFabiano Rosas args = (MigrateStart){ 5098a645544SFabiano Rosas .only_target = true, 5108a645544SFabiano Rosas }; 5118a645544SFabiano Rosas 5128a645544SFabiano Rosas if (migrate_start(&from, &to2, "defer", &args)) { 5138a645544SFabiano Rosas return; 5148a645544SFabiano Rosas } 5158a645544SFabiano Rosas 5168a645544SFabiano Rosas migrate_set_parameter_int(to2, "multifd-channels", 16); 5178a645544SFabiano Rosas 5188a645544SFabiano Rosas migrate_set_capability(to2, "multifd", true); 5198a645544SFabiano Rosas 5208a645544SFabiano Rosas /* Start incoming migration from the 1st socket */ 52143ca9d18SSteve Sistare migrate_incoming_qmp(to2, "tcp:127.0.0.1:0", NULL, "{}"); 5228a645544SFabiano Rosas 5238a645544SFabiano Rosas migrate_ensure_non_converge(from); 5248a645544SFabiano Rosas 5258a645544SFabiano Rosas migrate_qmp(from, to2, NULL, NULL, "{}"); 5268a645544SFabiano Rosas 5278a645544SFabiano Rosas migrate_wait_for_dirty_mem(from, to2); 5288a645544SFabiano Rosas 5298a645544SFabiano Rosas migrate_ensure_converge(from); 5308a645544SFabiano Rosas 5318a645544SFabiano Rosas wait_for_stop(from, get_src()); 5328a645544SFabiano Rosas qtest_qmp_eventwait(to2, "RESUME"); 5338a645544SFabiano Rosas 5348a645544SFabiano Rosas wait_for_serial("dest_serial"); 5358a645544SFabiano Rosas wait_for_migration_complete(from); 5368a645544SFabiano Rosas migrate_end(from, to2, true); 5378a645544SFabiano Rosas } 5388a645544SFabiano Rosas 5398a645544SFabiano Rosas static void calc_dirty_rate(QTestState *who, uint64_t calc_time) 5408a645544SFabiano Rosas { 5418a645544SFabiano Rosas qtest_qmp_assert_success(who, 5428a645544SFabiano Rosas "{ 'execute': 'calc-dirty-rate'," 5438a645544SFabiano Rosas "'arguments': { " 5448a645544SFabiano Rosas "'calc-time': %" PRIu64 "," 5458a645544SFabiano Rosas "'mode': 'dirty-ring' }}", 5468a645544SFabiano Rosas calc_time); 5478a645544SFabiano Rosas } 5488a645544SFabiano Rosas 5498a645544SFabiano Rosas static QDict *query_dirty_rate(QTestState *who) 5508a645544SFabiano Rosas { 5518a645544SFabiano Rosas return qtest_qmp_assert_success_ref(who, 5528a645544SFabiano Rosas "{ 'execute': 'query-dirty-rate' }"); 5538a645544SFabiano Rosas } 5548a645544SFabiano Rosas 5558a645544SFabiano Rosas static void dirtylimit_set_all(QTestState *who, uint64_t dirtyrate) 5568a645544SFabiano Rosas { 5578a645544SFabiano Rosas qtest_qmp_assert_success(who, 5588a645544SFabiano Rosas "{ 'execute': 'set-vcpu-dirty-limit'," 5598a645544SFabiano Rosas "'arguments': { " 5608a645544SFabiano Rosas "'dirty-rate': %" PRIu64 " } }", 5618a645544SFabiano Rosas dirtyrate); 5628a645544SFabiano Rosas } 5638a645544SFabiano Rosas 5648a645544SFabiano Rosas static void cancel_vcpu_dirty_limit(QTestState *who) 5658a645544SFabiano Rosas { 5668a645544SFabiano Rosas qtest_qmp_assert_success(who, 5678a645544SFabiano Rosas "{ 'execute': 'cancel-vcpu-dirty-limit' }"); 5688a645544SFabiano Rosas } 5698a645544SFabiano Rosas 5708a645544SFabiano Rosas static QDict *query_vcpu_dirty_limit(QTestState *who) 5718a645544SFabiano Rosas { 5728a645544SFabiano Rosas QDict *rsp; 5738a645544SFabiano Rosas 5748a645544SFabiano Rosas rsp = qtest_qmp(who, "{ 'execute': 'query-vcpu-dirty-limit' }"); 5758a645544SFabiano Rosas g_assert(!qdict_haskey(rsp, "error")); 5768a645544SFabiano Rosas g_assert(qdict_haskey(rsp, "return")); 5778a645544SFabiano Rosas 5788a645544SFabiano Rosas return rsp; 5798a645544SFabiano Rosas } 5808a645544SFabiano Rosas 5818a645544SFabiano Rosas static bool calc_dirtyrate_ready(QTestState *who) 5828a645544SFabiano Rosas { 5838a645544SFabiano Rosas QDict *rsp_return; 5848a645544SFabiano Rosas const char *status; 5858a645544SFabiano Rosas bool ready; 5868a645544SFabiano Rosas 5878a645544SFabiano Rosas rsp_return = query_dirty_rate(who); 5888a645544SFabiano Rosas g_assert(rsp_return); 5898a645544SFabiano Rosas 5908a645544SFabiano Rosas status = qdict_get_str(rsp_return, "status"); 5918a645544SFabiano Rosas g_assert(status); 5928a645544SFabiano Rosas ready = g_strcmp0(status, "measuring"); 5938a645544SFabiano Rosas qobject_unref(rsp_return); 5948a645544SFabiano Rosas 5958a645544SFabiano Rosas return ready; 5968a645544SFabiano Rosas } 5978a645544SFabiano Rosas 5988a645544SFabiano Rosas static void wait_for_calc_dirtyrate_complete(QTestState *who, 5998a645544SFabiano Rosas int64_t time_s) 6008a645544SFabiano Rosas { 6018a645544SFabiano Rosas int max_try_count = 10000; 6028a645544SFabiano Rosas usleep(time_s * 1000000); 6038a645544SFabiano Rosas 6048a645544SFabiano Rosas while (!calc_dirtyrate_ready(who) && max_try_count--) { 6058a645544SFabiano Rosas usleep(1000); 6068a645544SFabiano Rosas } 6078a645544SFabiano Rosas 6088a645544SFabiano Rosas /* 6098a645544SFabiano Rosas * Set the timeout with 10 s(max_try_count * 1000us), 6108a645544SFabiano Rosas * if dirtyrate measurement not complete, fail test. 6118a645544SFabiano Rosas */ 6128a645544SFabiano Rosas g_assert_cmpint(max_try_count, !=, 0); 6138a645544SFabiano Rosas } 6148a645544SFabiano Rosas 6158a645544SFabiano Rosas static int64_t get_dirty_rate(QTestState *who) 6168a645544SFabiano Rosas { 6178a645544SFabiano Rosas QDict *rsp_return; 6188a645544SFabiano Rosas const char *status; 6198a645544SFabiano Rosas QList *rates; 6208a645544SFabiano Rosas const QListEntry *entry; 6218a645544SFabiano Rosas QDict *rate; 6228a645544SFabiano Rosas int64_t dirtyrate; 6238a645544SFabiano Rosas 6248a645544SFabiano Rosas rsp_return = query_dirty_rate(who); 6258a645544SFabiano Rosas g_assert(rsp_return); 6268a645544SFabiano Rosas 6278a645544SFabiano Rosas status = qdict_get_str(rsp_return, "status"); 6288a645544SFabiano Rosas g_assert(status); 6298a645544SFabiano Rosas g_assert_cmpstr(status, ==, "measured"); 6308a645544SFabiano Rosas 6318a645544SFabiano Rosas rates = qdict_get_qlist(rsp_return, "vcpu-dirty-rate"); 6328a645544SFabiano Rosas g_assert(rates && !qlist_empty(rates)); 6338a645544SFabiano Rosas 6348a645544SFabiano Rosas entry = qlist_first(rates); 6358a645544SFabiano Rosas g_assert(entry); 6368a645544SFabiano Rosas 6378a645544SFabiano Rosas rate = qobject_to(QDict, qlist_entry_obj(entry)); 6388a645544SFabiano Rosas g_assert(rate); 6398a645544SFabiano Rosas 6408a645544SFabiano Rosas dirtyrate = qdict_get_try_int(rate, "dirty-rate", -1); 6418a645544SFabiano Rosas 6428a645544SFabiano Rosas qobject_unref(rsp_return); 6438a645544SFabiano Rosas return dirtyrate; 6448a645544SFabiano Rosas } 6458a645544SFabiano Rosas 6468a645544SFabiano Rosas static int64_t get_limit_rate(QTestState *who) 6478a645544SFabiano Rosas { 6488a645544SFabiano Rosas QDict *rsp_return; 6498a645544SFabiano Rosas QList *rates; 6508a645544SFabiano Rosas const QListEntry *entry; 6518a645544SFabiano Rosas QDict *rate; 6528a645544SFabiano Rosas int64_t dirtyrate; 6538a645544SFabiano Rosas 6548a645544SFabiano Rosas rsp_return = query_vcpu_dirty_limit(who); 6558a645544SFabiano Rosas g_assert(rsp_return); 6568a645544SFabiano Rosas 6578a645544SFabiano Rosas rates = qdict_get_qlist(rsp_return, "return"); 6588a645544SFabiano Rosas g_assert(rates && !qlist_empty(rates)); 6598a645544SFabiano Rosas 6608a645544SFabiano Rosas entry = qlist_first(rates); 6618a645544SFabiano Rosas g_assert(entry); 6628a645544SFabiano Rosas 6638a645544SFabiano Rosas rate = qobject_to(QDict, qlist_entry_obj(entry)); 6648a645544SFabiano Rosas g_assert(rate); 6658a645544SFabiano Rosas 6668a645544SFabiano Rosas dirtyrate = qdict_get_try_int(rate, "limit-rate", -1); 6678a645544SFabiano Rosas 6688a645544SFabiano Rosas qobject_unref(rsp_return); 6698a645544SFabiano Rosas return dirtyrate; 6708a645544SFabiano Rosas } 6718a645544SFabiano Rosas 6728a645544SFabiano Rosas static QTestState *dirtylimit_start_vm(void) 6738a645544SFabiano Rosas { 6748a645544SFabiano Rosas QTestState *vm = NULL; 6758a645544SFabiano Rosas g_autofree gchar *cmd = NULL; 6768a645544SFabiano Rosas const char *bootpath; 6778a645544SFabiano Rosas 6788a645544SFabiano Rosas bootpath = bootfile_create(qtest_get_arch(), tmpfs, false); 6798a645544SFabiano Rosas cmd = g_strdup_printf("-accel kvm,dirty-ring-size=4096 " 6808a645544SFabiano Rosas "-name dirtylimit-test,debug-threads=on " 6818a645544SFabiano Rosas "-m 150M -smp 1 " 6828a645544SFabiano Rosas "-serial file:%s/vm_serial " 6838a645544SFabiano Rosas "-drive file=%s,format=raw ", 6848a645544SFabiano Rosas tmpfs, bootpath); 6858a645544SFabiano Rosas 6868a645544SFabiano Rosas vm = qtest_init(cmd); 6878a645544SFabiano Rosas return vm; 6888a645544SFabiano Rosas } 6898a645544SFabiano Rosas 6908a645544SFabiano Rosas static void dirtylimit_stop_vm(QTestState *vm) 6918a645544SFabiano Rosas { 6928a645544SFabiano Rosas g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, "vm_serial"); 6938a645544SFabiano Rosas 6948a645544SFabiano Rosas qtest_quit(vm); 6958a645544SFabiano Rosas unlink(path); 6968a645544SFabiano Rosas } 6978a645544SFabiano Rosas 6988a645544SFabiano Rosas static void test_vcpu_dirty_limit(void) 6998a645544SFabiano Rosas { 7008a645544SFabiano Rosas QTestState *vm; 7018a645544SFabiano Rosas int64_t origin_rate; 7028a645544SFabiano Rosas int64_t quota_rate; 7038a645544SFabiano Rosas int64_t rate ; 7048a645544SFabiano Rosas int max_try_count = 20; 7058a645544SFabiano Rosas int hit = 0; 7068a645544SFabiano Rosas 7078a645544SFabiano Rosas /* Start vm for vcpu dirtylimit test */ 7088a645544SFabiano Rosas vm = dirtylimit_start_vm(); 7098a645544SFabiano Rosas 7108a645544SFabiano Rosas /* Wait for the first serial output from the vm*/ 7118a645544SFabiano Rosas wait_for_serial("vm_serial"); 7128a645544SFabiano Rosas 7138a645544SFabiano Rosas /* Do dirtyrate measurement with calc time equals 1s */ 7148a645544SFabiano Rosas calc_dirty_rate(vm, 1); 7158a645544SFabiano Rosas 7168a645544SFabiano Rosas /* Sleep calc time and wait for calc dirtyrate complete */ 7178a645544SFabiano Rosas wait_for_calc_dirtyrate_complete(vm, 1); 7188a645544SFabiano Rosas 7198a645544SFabiano Rosas /* Query original dirty page rate */ 7208a645544SFabiano Rosas origin_rate = get_dirty_rate(vm); 7218a645544SFabiano Rosas 7228a645544SFabiano Rosas /* VM booted from bootsect should dirty memory steadily */ 7238a645544SFabiano Rosas assert(origin_rate != 0); 7248a645544SFabiano Rosas 7258a645544SFabiano Rosas /* Setup quota dirty page rate at half of origin */ 7268a645544SFabiano Rosas quota_rate = origin_rate / 2; 7278a645544SFabiano Rosas 7288a645544SFabiano Rosas /* Set dirtylimit */ 7298a645544SFabiano Rosas dirtylimit_set_all(vm, quota_rate); 7308a645544SFabiano Rosas 7318a645544SFabiano Rosas /* 7328a645544SFabiano Rosas * Check if set-vcpu-dirty-limit and query-vcpu-dirty-limit 7338a645544SFabiano Rosas * works literally 7348a645544SFabiano Rosas */ 7358a645544SFabiano Rosas g_assert_cmpint(quota_rate, ==, get_limit_rate(vm)); 7368a645544SFabiano Rosas 7378a645544SFabiano Rosas /* Sleep a bit to check if it take effect */ 7388a645544SFabiano Rosas usleep(2000000); 7398a645544SFabiano Rosas 7408a645544SFabiano Rosas /* 7418a645544SFabiano Rosas * Check if dirtylimit take effect realistically, set the 7428a645544SFabiano Rosas * timeout with 20 s(max_try_count * 1s), if dirtylimit 7438a645544SFabiano Rosas * doesn't take effect, fail test. 7448a645544SFabiano Rosas */ 7458a645544SFabiano Rosas while (--max_try_count) { 7468a645544SFabiano Rosas calc_dirty_rate(vm, 1); 7478a645544SFabiano Rosas wait_for_calc_dirtyrate_complete(vm, 1); 7488a645544SFabiano Rosas rate = get_dirty_rate(vm); 7498a645544SFabiano Rosas 7508a645544SFabiano Rosas /* 7518a645544SFabiano Rosas * Assume hitting if current rate is less 7528a645544SFabiano Rosas * than quota rate (within accepting error) 7538a645544SFabiano Rosas */ 7548a645544SFabiano Rosas if (rate < (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) { 7558a645544SFabiano Rosas hit = 1; 7568a645544SFabiano Rosas break; 7578a645544SFabiano Rosas } 7588a645544SFabiano Rosas } 7598a645544SFabiano Rosas 7608a645544SFabiano Rosas g_assert_cmpint(hit, ==, 1); 7618a645544SFabiano Rosas 7628a645544SFabiano Rosas hit = 0; 7638a645544SFabiano Rosas max_try_count = 20; 7648a645544SFabiano Rosas 7658a645544SFabiano Rosas /* Check if dirtylimit cancellation take effect */ 7668a645544SFabiano Rosas cancel_vcpu_dirty_limit(vm); 7678a645544SFabiano Rosas while (--max_try_count) { 7688a645544SFabiano Rosas calc_dirty_rate(vm, 1); 7698a645544SFabiano Rosas wait_for_calc_dirtyrate_complete(vm, 1); 7708a645544SFabiano Rosas rate = get_dirty_rate(vm); 7718a645544SFabiano Rosas 7728a645544SFabiano Rosas /* 7738a645544SFabiano Rosas * Assume dirtylimit be canceled if current rate is 7748a645544SFabiano Rosas * greater than quota rate (within accepting error) 7758a645544SFabiano Rosas */ 7768a645544SFabiano Rosas if (rate > (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) { 7778a645544SFabiano Rosas hit = 1; 7788a645544SFabiano Rosas break; 7798a645544SFabiano Rosas } 7808a645544SFabiano Rosas } 7818a645544SFabiano Rosas 7828a645544SFabiano Rosas g_assert_cmpint(hit, ==, 1); 7838a645544SFabiano Rosas dirtylimit_stop_vm(vm); 7848a645544SFabiano Rosas } 7858a645544SFabiano Rosas 7868a645544SFabiano Rosas static void migrate_dirty_limit_wait_showup(QTestState *from, 7878a645544SFabiano Rosas const int64_t period, 7888a645544SFabiano Rosas const int64_t value) 7898a645544SFabiano Rosas { 7908a645544SFabiano Rosas /* Enable dirty limit capability */ 7918a645544SFabiano Rosas migrate_set_capability(from, "dirty-limit", true); 7928a645544SFabiano Rosas 7938a645544SFabiano Rosas /* Set dirty limit parameters */ 7948a645544SFabiano Rosas migrate_set_parameter_int(from, "x-vcpu-dirty-limit-period", period); 7958a645544SFabiano Rosas migrate_set_parameter_int(from, "vcpu-dirty-limit", value); 7968a645544SFabiano Rosas 7978a645544SFabiano Rosas /* Make sure migrate can't converge */ 7988a645544SFabiano Rosas migrate_ensure_non_converge(from); 7998a645544SFabiano Rosas 8008a645544SFabiano Rosas /* To check limit rate after precopy */ 8018a645544SFabiano Rosas migrate_set_capability(from, "pause-before-switchover", true); 8028a645544SFabiano Rosas 8038a645544SFabiano Rosas /* Wait for the serial output from the source */ 8048a645544SFabiano Rosas wait_for_serial("src_serial"); 8058a645544SFabiano Rosas } 8068a645544SFabiano Rosas 8078a645544SFabiano Rosas /* 8088a645544SFabiano Rosas * This test does: 8098a645544SFabiano Rosas * source destination 8108a645544SFabiano Rosas * start vm 8118a645544SFabiano Rosas * start incoming vm 8128a645544SFabiano Rosas * migrate 8138a645544SFabiano Rosas * wait dirty limit to begin 8148a645544SFabiano Rosas * cancel migrate 8158a645544SFabiano Rosas * cancellation check 8168a645544SFabiano Rosas * restart incoming vm 8178a645544SFabiano Rosas * migrate 8188a645544SFabiano Rosas * wait dirty limit to begin 8198a645544SFabiano Rosas * wait pre-switchover event 8208a645544SFabiano Rosas * convergence condition check 8218a645544SFabiano Rosas * 8228a645544SFabiano Rosas * And see if dirty limit migration works correctly. 8238a645544SFabiano Rosas * This test case involves many passes, so it runs in slow mode only. 8248a645544SFabiano Rosas */ 8258a645544SFabiano Rosas static void test_dirty_limit(void) 8268a645544SFabiano Rosas { 8278a645544SFabiano Rosas g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); 8288a645544SFabiano Rosas QTestState *from, *to; 8298a645544SFabiano Rosas int64_t remaining; 8308a645544SFabiano Rosas uint64_t throttle_us_per_full; 8318a645544SFabiano Rosas /* 8328a645544SFabiano Rosas * We want the test to be stable and as fast as possible. 8338a645544SFabiano Rosas * E.g., with 1Gb/s bandwidth migration may pass without dirty limit, 8348a645544SFabiano Rosas * so we need to decrease a bandwidth. 8358a645544SFabiano Rosas */ 8368a645544SFabiano Rosas const int64_t dirtylimit_period = 1000, dirtylimit_value = 50; 8378a645544SFabiano Rosas const int64_t max_bandwidth = 400000000; /* ~400Mb/s */ 8388a645544SFabiano Rosas const int64_t downtime_limit = 250; /* 250ms */ 8398a645544SFabiano Rosas /* 8408a645544SFabiano Rosas * We migrate through unix-socket (> 500Mb/s). 8418a645544SFabiano Rosas * Thus, expected migration speed ~= bandwidth limit (< 500Mb/s). 8428a645544SFabiano Rosas * So, we can predict expected_threshold 8438a645544SFabiano Rosas */ 8448a645544SFabiano Rosas const int64_t expected_threshold = max_bandwidth * downtime_limit / 1000; 8458a645544SFabiano Rosas int max_try_count = 10; 8468a645544SFabiano Rosas MigrateCommon args = { 8478a645544SFabiano Rosas .start = { 8488a645544SFabiano Rosas .hide_stderr = true, 8498a645544SFabiano Rosas .use_dirty_ring = true, 8508a645544SFabiano Rosas }, 8518a645544SFabiano Rosas .listen_uri = uri, 8528a645544SFabiano Rosas .connect_uri = uri, 8538a645544SFabiano Rosas }; 8548a645544SFabiano Rosas 8558a645544SFabiano Rosas /* Start src, dst vm */ 8568a645544SFabiano Rosas if (migrate_start(&from, &to, args.listen_uri, &args.start)) { 8578a645544SFabiano Rosas return; 8588a645544SFabiano Rosas } 8598a645544SFabiano Rosas 8608a645544SFabiano Rosas /* Prepare for dirty limit migration and wait src vm show up */ 8618a645544SFabiano Rosas migrate_dirty_limit_wait_showup(from, dirtylimit_period, dirtylimit_value); 8628a645544SFabiano Rosas 8638a645544SFabiano Rosas /* Start migrate */ 8648a645544SFabiano Rosas migrate_qmp(from, to, args.connect_uri, NULL, "{}"); 8658a645544SFabiano Rosas 8668a645544SFabiano Rosas /* Wait for dirty limit throttle begin */ 8678a645544SFabiano Rosas throttle_us_per_full = 0; 8688a645544SFabiano Rosas while (throttle_us_per_full == 0) { 8698a645544SFabiano Rosas throttle_us_per_full = 8708a645544SFabiano Rosas read_migrate_property_int(from, 8718a645544SFabiano Rosas "dirty-limit-throttle-time-per-round"); 8728a645544SFabiano Rosas usleep(100); 8738a645544SFabiano Rosas g_assert_false(get_src()->stop_seen); 8748a645544SFabiano Rosas } 8758a645544SFabiano Rosas 8768a645544SFabiano Rosas /* Now cancel migrate and wait for dirty limit throttle switch off */ 8778a645544SFabiano Rosas migrate_cancel(from); 8788a645544SFabiano Rosas wait_for_migration_status(from, "cancelled", NULL); 8798a645544SFabiano Rosas 880cd196679SFabiano Rosas /* destination always fails after cancel */ 881cd196679SFabiano Rosas migration_event_wait(to, "failed"); 882cd196679SFabiano Rosas qtest_set_expected_status(to, EXIT_FAILURE); 883cd196679SFabiano Rosas qtest_quit(to); 884cd196679SFabiano Rosas 8858a645544SFabiano Rosas /* Check if dirty limit throttle switched off, set timeout 1ms */ 8868a645544SFabiano Rosas do { 8878a645544SFabiano Rosas throttle_us_per_full = 8888a645544SFabiano Rosas read_migrate_property_int(from, 8898a645544SFabiano Rosas "dirty-limit-throttle-time-per-round"); 8908a645544SFabiano Rosas usleep(100); 8918a645544SFabiano Rosas g_assert_false(get_src()->stop_seen); 8928a645544SFabiano Rosas } while (throttle_us_per_full != 0 && --max_try_count); 8938a645544SFabiano Rosas 8948a645544SFabiano Rosas /* Assert dirty limit is not in service */ 8958a645544SFabiano Rosas g_assert_cmpint(throttle_us_per_full, ==, 0); 8968a645544SFabiano Rosas 8978a645544SFabiano Rosas args = (MigrateCommon) { 8988a645544SFabiano Rosas .start = { 8998a645544SFabiano Rosas .only_target = true, 9008a645544SFabiano Rosas .use_dirty_ring = true, 9018a645544SFabiano Rosas }, 9028a645544SFabiano Rosas .listen_uri = uri, 9038a645544SFabiano Rosas .connect_uri = uri, 9048a645544SFabiano Rosas }; 9058a645544SFabiano Rosas 9068a645544SFabiano Rosas /* Restart dst vm, src vm already show up so we needn't wait anymore */ 9078a645544SFabiano Rosas if (migrate_start(&from, &to, args.listen_uri, &args.start)) { 9088a645544SFabiano Rosas return; 9098a645544SFabiano Rosas } 9108a645544SFabiano Rosas 9118a645544SFabiano Rosas /* Start migrate */ 9128a645544SFabiano Rosas migrate_qmp(from, to, args.connect_uri, NULL, "{}"); 9138a645544SFabiano Rosas 9148a645544SFabiano Rosas /* Wait for dirty limit throttle begin */ 9158a645544SFabiano Rosas throttle_us_per_full = 0; 9168a645544SFabiano Rosas while (throttle_us_per_full == 0) { 9178a645544SFabiano Rosas throttle_us_per_full = 9188a645544SFabiano Rosas read_migrate_property_int(from, 9198a645544SFabiano Rosas "dirty-limit-throttle-time-per-round"); 9208a645544SFabiano Rosas usleep(100); 9218a645544SFabiano Rosas g_assert_false(get_src()->stop_seen); 9228a645544SFabiano Rosas } 9238a645544SFabiano Rosas 9248a645544SFabiano Rosas /* 9258a645544SFabiano Rosas * The dirty limit rate should equals the return value of 9268a645544SFabiano Rosas * query-vcpu-dirty-limit if dirty limit cap set 9278a645544SFabiano Rosas */ 9288a645544SFabiano Rosas g_assert_cmpint(dirtylimit_value, ==, get_limit_rate(from)); 9298a645544SFabiano Rosas 9308a645544SFabiano Rosas /* Now, we have tested if dirty limit works, let it converge */ 9318a645544SFabiano Rosas migrate_set_parameter_int(from, "downtime-limit", downtime_limit); 9328a645544SFabiano Rosas migrate_set_parameter_int(from, "max-bandwidth", max_bandwidth); 9338a645544SFabiano Rosas 9348a645544SFabiano Rosas /* 9358a645544SFabiano Rosas * Wait for pre-switchover status to check if migration 9368a645544SFabiano Rosas * satisfy the convergence condition 9378a645544SFabiano Rosas */ 9388a645544SFabiano Rosas wait_for_migration_status(from, "pre-switchover", NULL); 9398a645544SFabiano Rosas 9408a645544SFabiano Rosas remaining = read_ram_property_int(from, "remaining"); 9418a645544SFabiano Rosas g_assert_cmpint(remaining, <, 9428a645544SFabiano Rosas (expected_threshold + expected_threshold / 100)); 9438a645544SFabiano Rosas 9448a645544SFabiano Rosas migrate_continue(from, "pre-switchover"); 9458a645544SFabiano Rosas 9468a645544SFabiano Rosas qtest_qmp_eventwait(to, "RESUME"); 9478a645544SFabiano Rosas 9488a645544SFabiano Rosas wait_for_serial("dest_serial"); 9498a645544SFabiano Rosas wait_for_migration_complete(from); 9508a645544SFabiano Rosas 9518a645544SFabiano Rosas migrate_end(from, to, true); 9528a645544SFabiano Rosas } 9538a645544SFabiano Rosas 9548a645544SFabiano Rosas void migration_test_add_precopy(MigrationTestEnv *env) 9558a645544SFabiano Rosas { 9568a645544SFabiano Rosas tmpfs = env->tmpfs; 9578a645544SFabiano Rosas 9588a645544SFabiano Rosas if (env->is_x86) { 9598a645544SFabiano Rosas migration_test_add("/migration/precopy/unix/suspend/live", 9608a645544SFabiano Rosas test_precopy_unix_suspend_live); 9618a645544SFabiano Rosas migration_test_add("/migration/precopy/unix/suspend/notlive", 9628a645544SFabiano Rosas test_precopy_unix_suspend_notlive); 9638a645544SFabiano Rosas } 9648a645544SFabiano Rosas 9658a645544SFabiano Rosas migration_test_add("/migration/precopy/unix/plain", 9668a645544SFabiano Rosas test_precopy_unix_plain); 9678a645544SFabiano Rosas 9688a645544SFabiano Rosas migration_test_add("/migration/precopy/tcp/plain", test_precopy_tcp_plain); 9698a645544SFabiano Rosas 9708a645544SFabiano Rosas migration_test_add("/migration/precopy/tcp/plain/switchover-ack", 9718a645544SFabiano Rosas test_precopy_tcp_switchover_ack); 9728a645544SFabiano Rosas 9738a645544SFabiano Rosas #ifndef _WIN32 9748a645544SFabiano Rosas migration_test_add("/migration/precopy/fd/tcp", 9758a645544SFabiano Rosas test_precopy_fd_socket); 9768a645544SFabiano Rosas migration_test_add("/migration/precopy/fd/file", 9778a645544SFabiano Rosas test_precopy_fd_file); 9788a645544SFabiano Rosas #endif 9798a645544SFabiano Rosas 9808a645544SFabiano Rosas /* 9818a645544SFabiano Rosas * See explanation why this test is slow on function definition 9828a645544SFabiano Rosas */ 9838a645544SFabiano Rosas if (g_test_slow()) { 9848a645544SFabiano Rosas migration_test_add("/migration/auto_converge", 9858a645544SFabiano Rosas test_auto_converge); 9868a645544SFabiano Rosas if (g_str_equal(env->arch, "x86_64") && 9878a645544SFabiano Rosas env->has_kvm && env->has_dirty_ring) { 9888a645544SFabiano Rosas migration_test_add("/dirty_limit", 9898a645544SFabiano Rosas test_dirty_limit); 9908a645544SFabiano Rosas } 9918a645544SFabiano Rosas } 9928a645544SFabiano Rosas migration_test_add("/migration/multifd/tcp/uri/plain/none", 9938a645544SFabiano Rosas test_multifd_tcp_uri_none); 9948a645544SFabiano Rosas migration_test_add("/migration/multifd/tcp/channels/plain/none", 9958a645544SFabiano Rosas test_multifd_tcp_channels_none); 9968a645544SFabiano Rosas migration_test_add("/migration/multifd/tcp/plain/zero-page/legacy", 9978a645544SFabiano Rosas test_multifd_tcp_zero_page_legacy); 9988a645544SFabiano Rosas migration_test_add("/migration/multifd/tcp/plain/zero-page/none", 9998a645544SFabiano Rosas test_multifd_tcp_no_zero_page); 10008a645544SFabiano Rosas migration_test_add("/migration/multifd/tcp/plain/cancel", 10018a645544SFabiano Rosas test_multifd_tcp_cancel); 10028a645544SFabiano Rosas if (g_str_equal(env->arch, "x86_64") 10038a645544SFabiano Rosas && env->has_kvm && env->has_dirty_ring) { 10048a645544SFabiano Rosas 10058a645544SFabiano Rosas migration_test_add("/migration/dirty_ring", 10068a645544SFabiano Rosas test_precopy_unix_dirty_ring); 10078a645544SFabiano Rosas if (qtest_has_machine("pc") && g_test_slow()) { 10088a645544SFabiano Rosas migration_test_add("/migration/vcpu_dirty_limit", 10098a645544SFabiano Rosas test_vcpu_dirty_limit); 10108a645544SFabiano Rosas } 10118a645544SFabiano Rosas } 10128a645544SFabiano Rosas } 1013