xref: /openbmc/qemu/tests/qtest/migration/precopy-tests.c (revision 9af3d9a931156142199c61518937506bfa5475f1)
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"
23*538e03d2SFabiano 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 
test_precopy_unix_plain(void)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 
test_precopy_unix_suspend_live(void)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 
test_precopy_unix_suspend_notlive(void)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 
test_precopy_unix_dirty_ring(void)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 
test_precopy_tcp_plain(void)1028a645544SFabiano Rosas static void test_precopy_tcp_plain(void)
1038a645544SFabiano Rosas {
1048a645544SFabiano Rosas     MigrateCommon args = {
1058a645544SFabiano Rosas         .listen_uri = "tcp:127.0.0.1:0",
1068a645544SFabiano Rosas     };
1078a645544SFabiano Rosas 
1088a645544SFabiano Rosas     test_precopy_common(&args);
1098a645544SFabiano Rosas }
1108a645544SFabiano Rosas 
migrate_hook_start_switchover_ack(QTestState * from,QTestState * to)1118a645544SFabiano Rosas static void *migrate_hook_start_switchover_ack(QTestState *from, QTestState *to)
1128a645544SFabiano Rosas {
1138a645544SFabiano Rosas 
1148a645544SFabiano Rosas     migrate_set_capability(from, "return-path", true);
1158a645544SFabiano Rosas     migrate_set_capability(to, "return-path", true);
1168a645544SFabiano Rosas 
1178a645544SFabiano Rosas     migrate_set_capability(from, "switchover-ack", true);
1188a645544SFabiano Rosas     migrate_set_capability(to, "switchover-ack", true);
1198a645544SFabiano Rosas 
1208a645544SFabiano Rosas     return NULL;
1218a645544SFabiano Rosas }
1228a645544SFabiano Rosas 
test_precopy_tcp_switchover_ack(void)1238a645544SFabiano Rosas static void test_precopy_tcp_switchover_ack(void)
1248a645544SFabiano Rosas {
1258a645544SFabiano Rosas     MigrateCommon args = {
1268a645544SFabiano Rosas         .listen_uri = "tcp:127.0.0.1:0",
1278a645544SFabiano Rosas         .start_hook = migrate_hook_start_switchover_ack,
1288a645544SFabiano Rosas         /*
1298a645544SFabiano Rosas          * Source VM must be running in order to consider the switchover ACK
1308a645544SFabiano Rosas          * when deciding to do switchover or not.
1318a645544SFabiano Rosas          */
1328a645544SFabiano Rosas         .live = true,
1338a645544SFabiano Rosas     };
1348a645544SFabiano Rosas 
1358a645544SFabiano Rosas     test_precopy_common(&args);
1368a645544SFabiano Rosas }
1378a645544SFabiano Rosas 
1388a645544SFabiano Rosas #ifndef _WIN32
migrate_hook_start_fd(QTestState * from,QTestState * to)1398a645544SFabiano Rosas static void *migrate_hook_start_fd(QTestState *from,
1408a645544SFabiano Rosas                                    QTestState *to)
1418a645544SFabiano Rosas {
1428a645544SFabiano Rosas     int ret;
1438a645544SFabiano Rosas     int pair[2];
1448a645544SFabiano Rosas 
1458a645544SFabiano Rosas     /* Create two connected sockets for migration */
1468a645544SFabiano Rosas     ret = qemu_socketpair(PF_LOCAL, SOCK_STREAM, 0, pair);
1478a645544SFabiano Rosas     g_assert_cmpint(ret, ==, 0);
1488a645544SFabiano Rosas 
1498a645544SFabiano Rosas     /* Send the 1st socket to the target */
1508a645544SFabiano Rosas     qtest_qmp_fds_assert_success(to, &pair[0], 1,
1518a645544SFabiano Rosas                                  "{ 'execute': 'getfd',"
1528a645544SFabiano Rosas                                  "  'arguments': { 'fdname': 'fd-mig' }}");
1538a645544SFabiano Rosas     close(pair[0]);
1548a645544SFabiano Rosas 
1558a645544SFabiano Rosas     /* Start incoming migration from the 1st socket */
15643ca9d18SSteve Sistare     migrate_incoming_qmp(to, "fd:fd-mig", NULL, "{}");
1578a645544SFabiano Rosas 
1588a645544SFabiano Rosas     /* Send the 2nd socket to the target */
1598a645544SFabiano Rosas     qtest_qmp_fds_assert_success(from, &pair[1], 1,
1608a645544SFabiano Rosas                                  "{ 'execute': 'getfd',"
1618a645544SFabiano Rosas                                  "  'arguments': { 'fdname': 'fd-mig' }}");
1628a645544SFabiano Rosas     close(pair[1]);
1638a645544SFabiano Rosas 
1648a645544SFabiano Rosas     return NULL;
1658a645544SFabiano Rosas }
1668a645544SFabiano Rosas 
migrate_hook_end_fd(QTestState * from,QTestState * to,void * opaque)1678a645544SFabiano Rosas static void migrate_hook_end_fd(QTestState *from,
1688a645544SFabiano Rosas                                 QTestState *to,
1698a645544SFabiano Rosas                                 void *opaque)
1708a645544SFabiano Rosas {
1718a645544SFabiano Rosas     QDict *rsp;
1728a645544SFabiano Rosas     const char *error_desc;
1738a645544SFabiano Rosas 
1748a645544SFabiano Rosas     /* Test closing fds */
1758a645544SFabiano Rosas     /*
1768a645544SFabiano Rosas      * We assume, that QEMU removes named fd from its list,
1778a645544SFabiano Rosas      * so this should fail.
1788a645544SFabiano Rosas      */
1798a645544SFabiano Rosas     rsp = qtest_qmp(from,
1808a645544SFabiano Rosas                     "{ 'execute': 'closefd',"
1818a645544SFabiano Rosas                     "  'arguments': { 'fdname': 'fd-mig' }}");
1828a645544SFabiano Rosas     g_assert_true(qdict_haskey(rsp, "error"));
1838a645544SFabiano Rosas     error_desc = qdict_get_str(qdict_get_qdict(rsp, "error"), "desc");
1848a645544SFabiano Rosas     g_assert_cmpstr(error_desc, ==, "File descriptor named 'fd-mig' not found");
1858a645544SFabiano Rosas     qobject_unref(rsp);
1868a645544SFabiano Rosas 
1878a645544SFabiano Rosas     rsp = qtest_qmp(to,
1888a645544SFabiano Rosas                     "{ 'execute': 'closefd',"
1898a645544SFabiano Rosas                     "  'arguments': { 'fdname': 'fd-mig' }}");
1908a645544SFabiano Rosas     g_assert_true(qdict_haskey(rsp, "error"));
1918a645544SFabiano Rosas     error_desc = qdict_get_str(qdict_get_qdict(rsp, "error"), "desc");
1928a645544SFabiano Rosas     g_assert_cmpstr(error_desc, ==, "File descriptor named 'fd-mig' not found");
1938a645544SFabiano Rosas     qobject_unref(rsp);
1948a645544SFabiano Rosas }
1958a645544SFabiano Rosas 
test_precopy_fd_socket(void)1968a645544SFabiano Rosas static void test_precopy_fd_socket(void)
1978a645544SFabiano Rosas {
1988a645544SFabiano Rosas     MigrateCommon args = {
1998a645544SFabiano Rosas         .listen_uri = "defer",
2008a645544SFabiano Rosas         .connect_uri = "fd:fd-mig",
2018a645544SFabiano Rosas         .start_hook = migrate_hook_start_fd,
2028a645544SFabiano Rosas         .end_hook = migrate_hook_end_fd,
2038a645544SFabiano Rosas     };
2048a645544SFabiano Rosas     test_precopy_common(&args);
2058a645544SFabiano Rosas }
2068a645544SFabiano Rosas 
migrate_hook_start_precopy_fd_file(QTestState * from,QTestState * to)2078a645544SFabiano Rosas static void *migrate_hook_start_precopy_fd_file(QTestState *from,
2088a645544SFabiano Rosas                                                 QTestState *to)
2098a645544SFabiano Rosas {
2108a645544SFabiano Rosas     g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
2118a645544SFabiano Rosas     int src_flags = O_CREAT | O_RDWR;
2128a645544SFabiano Rosas     int dst_flags = O_CREAT | O_RDWR;
2138a645544SFabiano Rosas     int fds[2];
2148a645544SFabiano Rosas 
2158a645544SFabiano Rosas     fds[0] = open(file, src_flags, 0660);
2168a645544SFabiano Rosas     assert(fds[0] != -1);
2178a645544SFabiano Rosas 
2188a645544SFabiano Rosas     fds[1] = open(file, dst_flags, 0660);
2198a645544SFabiano Rosas     assert(fds[1] != -1);
2208a645544SFabiano Rosas 
2218a645544SFabiano Rosas 
2228a645544SFabiano Rosas     qtest_qmp_fds_assert_success(to, &fds[0], 1,
2238a645544SFabiano Rosas                                  "{ 'execute': 'getfd',"
2248a645544SFabiano Rosas                                  "  'arguments': { 'fdname': 'fd-mig' }}");
2258a645544SFabiano Rosas 
2268a645544SFabiano Rosas     qtest_qmp_fds_assert_success(from, &fds[1], 1,
2278a645544SFabiano Rosas                                  "{ 'execute': 'getfd',"
2288a645544SFabiano Rosas                                  "  'arguments': { 'fdname': 'fd-mig' }}");
2298a645544SFabiano Rosas 
2308a645544SFabiano Rosas     close(fds[0]);
2318a645544SFabiano Rosas     close(fds[1]);
2328a645544SFabiano Rosas 
2338a645544SFabiano Rosas     return NULL;
2348a645544SFabiano Rosas }
2358a645544SFabiano Rosas 
test_precopy_fd_file(void)2368a645544SFabiano Rosas static void test_precopy_fd_file(void)
2378a645544SFabiano Rosas {
2388a645544SFabiano Rosas     MigrateCommon args = {
2398a645544SFabiano Rosas         .listen_uri = "defer",
2408a645544SFabiano Rosas         .connect_uri = "fd:fd-mig",
2418a645544SFabiano Rosas         .start_hook = migrate_hook_start_precopy_fd_file,
2428a645544SFabiano Rosas         .end_hook = migrate_hook_end_fd,
2438a645544SFabiano Rosas     };
2448a645544SFabiano Rosas     test_file_common(&args, true);
2458a645544SFabiano Rosas }
2468a645544SFabiano Rosas #endif /* _WIN32 */
2478a645544SFabiano Rosas 
2488a645544SFabiano Rosas /*
2498a645544SFabiano Rosas  * The way auto_converge works, we need to do too many passes to
2508a645544SFabiano Rosas  * run this test.  Auto_converge logic is only run once every
2518a645544SFabiano Rosas  * three iterations, so:
2528a645544SFabiano Rosas  *
2538a645544SFabiano Rosas  * - 3 iterations without auto_converge enabled
2548a645544SFabiano Rosas  * - 3 iterations with pct = 5
2558a645544SFabiano Rosas  * - 3 iterations with pct = 30
2568a645544SFabiano Rosas  * - 3 iterations with pct = 55
2578a645544SFabiano Rosas  * - 3 iterations with pct = 80
2588a645544SFabiano Rosas  * - 3 iterations with pct = 95 (max(95, 80 + 25))
2598a645544SFabiano Rosas  *
2608a645544SFabiano Rosas  * To make things even worse, we need to run the initial stage at
2618a645544SFabiano Rosas  * 3MB/s so we enter autoconverge even when host is (over)loaded.
2628a645544SFabiano Rosas  */
test_auto_converge(void)2638a645544SFabiano Rosas static void test_auto_converge(void)
2648a645544SFabiano Rosas {
2658a645544SFabiano Rosas     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
2668a645544SFabiano Rosas     MigrateStart args = {};
2678a645544SFabiano Rosas     QTestState *from, *to;
2688a645544SFabiano Rosas     int64_t percentage;
2698a645544SFabiano Rosas 
2708a645544SFabiano Rosas     /*
2718a645544SFabiano Rosas      * We want the test to be stable and as fast as possible.
2728a645544SFabiano Rosas      * E.g., with 1Gb/s bandwidth migration may pass without throttling,
2738a645544SFabiano Rosas      * so we need to decrease a bandwidth.
2748a645544SFabiano Rosas      */
2758a645544SFabiano Rosas     const int64_t init_pct = 5, inc_pct = 25, max_pct = 95;
2768a645544SFabiano Rosas     uint64_t prev_dirty_sync_cnt, dirty_sync_cnt;
2778a645544SFabiano Rosas     int max_try_count, hit = 0;
2788a645544SFabiano Rosas 
2798a645544SFabiano Rosas     if (migrate_start(&from, &to, uri, &args)) {
2808a645544SFabiano Rosas         return;
2818a645544SFabiano Rosas     }
2828a645544SFabiano Rosas 
2838a645544SFabiano Rosas     migrate_set_capability(from, "auto-converge", true);
2848a645544SFabiano Rosas     migrate_set_parameter_int(from, "cpu-throttle-initial", init_pct);
2858a645544SFabiano Rosas     migrate_set_parameter_int(from, "cpu-throttle-increment", inc_pct);
2868a645544SFabiano Rosas     migrate_set_parameter_int(from, "max-cpu-throttle", max_pct);
2878a645544SFabiano Rosas 
2888a645544SFabiano Rosas     /*
2898a645544SFabiano Rosas      * Set the initial parameters so that the migration could not converge
2908a645544SFabiano Rosas      * without throttling.
2918a645544SFabiano Rosas      */
2928a645544SFabiano Rosas     migrate_ensure_non_converge(from);
2938a645544SFabiano Rosas 
2948a645544SFabiano Rosas     /* To check remaining size after precopy */
2958a645544SFabiano Rosas     migrate_set_capability(from, "pause-before-switchover", true);
2968a645544SFabiano Rosas 
2978a645544SFabiano Rosas     /* Wait for the first serial output from the source */
2988a645544SFabiano Rosas     wait_for_serial("src_serial");
2998a645544SFabiano Rosas 
3008a645544SFabiano Rosas     migrate_qmp(from, to, uri, NULL, "{}");
3018a645544SFabiano Rosas 
3028a645544SFabiano Rosas     /* Wait for throttling begins */
3038a645544SFabiano Rosas     percentage = 0;
3048a645544SFabiano Rosas     do {
3058a645544SFabiano Rosas         percentage = read_migrate_property_int(from, "cpu-throttle-percentage");
3068a645544SFabiano Rosas         if (percentage != 0) {
3078a645544SFabiano Rosas             break;
3088a645544SFabiano Rosas         }
3098a645544SFabiano Rosas         usleep(20);
3108a645544SFabiano Rosas         g_assert_false(get_src()->stop_seen);
3118a645544SFabiano Rosas     } while (true);
3128a645544SFabiano Rosas     /* The first percentage of throttling should be at least init_pct */
3138a645544SFabiano Rosas     g_assert_cmpint(percentage, >=, init_pct);
3148a645544SFabiano Rosas 
3158a645544SFabiano Rosas     /*
3168a645544SFabiano Rosas      * End the loop when the dirty sync count greater than 1.
3178a645544SFabiano Rosas      */
3188a645544SFabiano Rosas     while ((dirty_sync_cnt = get_migration_pass(from)) < 2) {
3198a645544SFabiano Rosas         usleep(1000 * 1000);
3208a645544SFabiano Rosas     }
3218a645544SFabiano Rosas 
3228a645544SFabiano Rosas     prev_dirty_sync_cnt = dirty_sync_cnt;
3238a645544SFabiano Rosas 
3248a645544SFabiano Rosas     /*
3258a645544SFabiano Rosas      * The RAMBlock dirty sync count must changes in 5 seconds, here we set
3268a645544SFabiano Rosas      * the timeout to 10 seconds to ensure it changes.
3278a645544SFabiano Rosas      *
3288a645544SFabiano Rosas      * Note that migrate_ensure_non_converge set the max-bandwidth to 3MB/s,
3298a645544SFabiano Rosas      * while the qtest mem is >= 100MB, one iteration takes at least 33s (100/3)
3308a645544SFabiano Rosas      * to complete; this ensures that the RAMBlock dirty sync occurs.
3318a645544SFabiano Rosas      */
3328a645544SFabiano Rosas     max_try_count = 10;
3338a645544SFabiano Rosas     while (--max_try_count) {
3348a645544SFabiano Rosas         dirty_sync_cnt = get_migration_pass(from);
3358a645544SFabiano Rosas         if (dirty_sync_cnt != prev_dirty_sync_cnt) {
3368a645544SFabiano Rosas             hit = 1;
3378a645544SFabiano Rosas             break;
3388a645544SFabiano Rosas         }
3398a645544SFabiano Rosas         prev_dirty_sync_cnt = dirty_sync_cnt;
3408a645544SFabiano Rosas         sleep(1);
3418a645544SFabiano Rosas     }
3428a645544SFabiano Rosas     g_assert_cmpint(hit, ==, 1);
3438a645544SFabiano Rosas 
3448a645544SFabiano Rosas     /* Now, when we tested that throttling works, let it converge */
3458a645544SFabiano Rosas     migrate_ensure_converge(from);
3468a645544SFabiano Rosas 
3478a645544SFabiano Rosas     /*
3488a645544SFabiano Rosas      * Wait for pre-switchover status to check last throttle percentage
3498a645544SFabiano Rosas      * and remaining. These values will be zeroed later
3508a645544SFabiano Rosas      */
3518a645544SFabiano Rosas     wait_for_migration_status(from, "pre-switchover", NULL);
3528a645544SFabiano Rosas 
3538a645544SFabiano Rosas     /* The final percentage of throttling shouldn't be greater than max_pct */
3548a645544SFabiano Rosas     percentage = read_migrate_property_int(from, "cpu-throttle-percentage");
3558a645544SFabiano Rosas     g_assert_cmpint(percentage, <=, max_pct);
3568a645544SFabiano Rosas     migrate_continue(from, "pre-switchover");
3578a645544SFabiano Rosas 
3588a645544SFabiano Rosas     qtest_qmp_eventwait(to, "RESUME");
3598a645544SFabiano Rosas 
3608a645544SFabiano Rosas     wait_for_serial("dest_serial");
3618a645544SFabiano Rosas     wait_for_migration_complete(from);
3628a645544SFabiano Rosas 
3638a645544SFabiano Rosas     migrate_end(from, to, true);
3648a645544SFabiano Rosas }
3658a645544SFabiano Rosas 
3668a645544SFabiano Rosas static void *
migrate_hook_start_precopy_tcp_multifd(QTestState * from,QTestState * to)3678a645544SFabiano Rosas migrate_hook_start_precopy_tcp_multifd(QTestState *from,
3688a645544SFabiano Rosas                                        QTestState *to)
3698a645544SFabiano Rosas {
3708a645544SFabiano Rosas     return migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
3718a645544SFabiano Rosas }
3728a645544SFabiano Rosas 
3738a645544SFabiano Rosas static void *
migrate_hook_start_precopy_tcp_multifd_zero_page_legacy(QTestState * from,QTestState * to)3748a645544SFabiano Rosas migrate_hook_start_precopy_tcp_multifd_zero_page_legacy(QTestState *from,
3758a645544SFabiano Rosas                                                         QTestState *to)
3768a645544SFabiano Rosas {
3778a645544SFabiano Rosas     migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
3788a645544SFabiano Rosas     migrate_set_parameter_str(from, "zero-page-detection", "legacy");
3798a645544SFabiano Rosas     return NULL;
3808a645544SFabiano Rosas }
3818a645544SFabiano Rosas 
3828a645544SFabiano Rosas static void *
migrate_hook_start_precopy_tcp_multifd_no_zero_page(QTestState * from,QTestState * to)3838a645544SFabiano Rosas migrate_hook_start_precopy_tcp_multifd_no_zero_page(QTestState *from,
3848a645544SFabiano Rosas                                                     QTestState *to)
3858a645544SFabiano Rosas {
3868a645544SFabiano Rosas     migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
3878a645544SFabiano Rosas     migrate_set_parameter_str(from, "zero-page-detection", "none");
3888a645544SFabiano Rosas     return NULL;
3898a645544SFabiano Rosas }
3908a645544SFabiano Rosas 
test_multifd_tcp_uri_none(void)3918a645544SFabiano Rosas static void test_multifd_tcp_uri_none(void)
3928a645544SFabiano Rosas {
3938a645544SFabiano Rosas     MigrateCommon args = {
3948a645544SFabiano Rosas         .listen_uri = "defer",
3958a645544SFabiano Rosas         .start_hook = migrate_hook_start_precopy_tcp_multifd,
3968a645544SFabiano Rosas         /*
3978a645544SFabiano Rosas          * Multifd is more complicated than most of the features, it
3988a645544SFabiano Rosas          * directly takes guest page buffers when sending, make sure
3998a645544SFabiano Rosas          * everything will work alright even if guest page is changing.
4008a645544SFabiano Rosas          */
4018a645544SFabiano Rosas         .live = true,
4028a645544SFabiano Rosas     };
4038a645544SFabiano Rosas     test_precopy_common(&args);
4048a645544SFabiano Rosas }
4058a645544SFabiano Rosas 
test_multifd_tcp_zero_page_legacy(void)4068a645544SFabiano Rosas static void test_multifd_tcp_zero_page_legacy(void)
4078a645544SFabiano Rosas {
4088a645544SFabiano Rosas     MigrateCommon args = {
4098a645544SFabiano Rosas         .listen_uri = "defer",
4108a645544SFabiano Rosas         .start_hook = migrate_hook_start_precopy_tcp_multifd_zero_page_legacy,
4118a645544SFabiano Rosas         /*
4128a645544SFabiano Rosas          * Multifd is more complicated than most of the features, it
4138a645544SFabiano Rosas          * directly takes guest page buffers when sending, make sure
4148a645544SFabiano Rosas          * everything will work alright even if guest page is changing.
4158a645544SFabiano Rosas          */
4168a645544SFabiano Rosas         .live = true,
4178a645544SFabiano Rosas     };
4188a645544SFabiano Rosas     test_precopy_common(&args);
4198a645544SFabiano Rosas }
4208a645544SFabiano Rosas 
test_multifd_tcp_no_zero_page(void)4218a645544SFabiano Rosas static void test_multifd_tcp_no_zero_page(void)
4228a645544SFabiano Rosas {
4238a645544SFabiano Rosas     MigrateCommon args = {
4248a645544SFabiano Rosas         .listen_uri = "defer",
4258a645544SFabiano Rosas         .start_hook = migrate_hook_start_precopy_tcp_multifd_no_zero_page,
4268a645544SFabiano Rosas         /*
4278a645544SFabiano Rosas          * Multifd is more complicated than most of the features, it
4288a645544SFabiano Rosas          * directly takes guest page buffers when sending, make sure
4298a645544SFabiano Rosas          * everything will work alright even if guest page is changing.
4308a645544SFabiano Rosas          */
4318a645544SFabiano Rosas         .live = true,
4328a645544SFabiano Rosas     };
4338a645544SFabiano Rosas     test_precopy_common(&args);
4348a645544SFabiano Rosas }
4358a645544SFabiano Rosas 
test_multifd_tcp_channels_none(void)4368a645544SFabiano Rosas static void test_multifd_tcp_channels_none(void)
4378a645544SFabiano Rosas {
4388a645544SFabiano Rosas     MigrateCommon args = {
4398a645544SFabiano Rosas         .listen_uri = "defer",
4408a645544SFabiano Rosas         .start_hook = migrate_hook_start_precopy_tcp_multifd,
4418a645544SFabiano Rosas         .live = true,
4428a645544SFabiano Rosas         .connect_channels = ("[ { 'channel-type': 'main',"
4438a645544SFabiano Rosas                              "    'addr': { 'transport': 'socket',"
4448a645544SFabiano Rosas                              "              'type': 'inet',"
4458a645544SFabiano Rosas                              "              'host': '127.0.0.1',"
4468a645544SFabiano Rosas                              "              'port': '0' } } ]"),
4478a645544SFabiano Rosas     };
4488a645544SFabiano Rosas     test_precopy_common(&args);
4498a645544SFabiano Rosas }
4508a645544SFabiano Rosas 
4518a645544SFabiano Rosas /*
4528a645544SFabiano Rosas  * This test does:
4538a645544SFabiano Rosas  *  source               target
4548a645544SFabiano Rosas  *                       migrate_incoming
4558a645544SFabiano Rosas  *     migrate
4568a645544SFabiano Rosas  *     migrate_cancel
4578a645544SFabiano Rosas  *                       launch another target
4588a645544SFabiano Rosas  *     migrate
4598a645544SFabiano Rosas  *
4608a645544SFabiano Rosas  *  And see that it works
4618a645544SFabiano Rosas  */
test_multifd_tcp_cancel(void)4628a645544SFabiano Rosas static void test_multifd_tcp_cancel(void)
4638a645544SFabiano Rosas {
4648a645544SFabiano Rosas     MigrateStart args = {
4658a645544SFabiano Rosas         .hide_stderr = true,
4668a645544SFabiano Rosas     };
4678a645544SFabiano Rosas     QTestState *from, *to, *to2;
4688a645544SFabiano Rosas 
4698a645544SFabiano Rosas     if (migrate_start(&from, &to, "defer", &args)) {
4708a645544SFabiano Rosas         return;
4718a645544SFabiano Rosas     }
4728a645544SFabiano Rosas 
4738a645544SFabiano Rosas     migrate_ensure_non_converge(from);
4748a645544SFabiano Rosas     migrate_prepare_for_dirty_mem(from);
4758a645544SFabiano Rosas 
4768a645544SFabiano Rosas     migrate_set_parameter_int(from, "multifd-channels", 16);
4778a645544SFabiano Rosas     migrate_set_parameter_int(to, "multifd-channels", 16);
4788a645544SFabiano Rosas 
4798a645544SFabiano Rosas     migrate_set_capability(from, "multifd", true);
4808a645544SFabiano Rosas     migrate_set_capability(to, "multifd", true);
4818a645544SFabiano Rosas 
4828a645544SFabiano Rosas     /* Start incoming migration from the 1st socket */
48343ca9d18SSteve Sistare     migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, "{}");
4848a645544SFabiano Rosas 
4858a645544SFabiano Rosas     /* Wait for the first serial output from the source */
4868a645544SFabiano Rosas     wait_for_serial("src_serial");
4878a645544SFabiano Rosas 
4888a645544SFabiano Rosas     migrate_qmp(from, to, NULL, NULL, "{}");
4898a645544SFabiano Rosas 
4908a645544SFabiano Rosas     migrate_wait_for_dirty_mem(from, to);
4918a645544SFabiano Rosas 
4928a645544SFabiano Rosas     migrate_cancel(from);
4938a645544SFabiano Rosas 
4948a645544SFabiano Rosas     /* Make sure QEMU process "to" exited */
4958a645544SFabiano Rosas     qtest_set_expected_status(to, EXIT_FAILURE);
4968a645544SFabiano Rosas     qtest_wait_qemu(to);
4978a645544SFabiano Rosas     qtest_quit(to);
4988a645544SFabiano Rosas 
4998a645544SFabiano Rosas     /*
5008a645544SFabiano Rosas      * Ensure the source QEMU finishes its cancellation process before we
5018a645544SFabiano Rosas      * proceed with the setup of the next migration. The migrate_start()
5028a645544SFabiano Rosas      * function and others might want to interact with the source in a way that
5038a645544SFabiano Rosas      * is not possible while the migration is not canceled properly. For
5048a645544SFabiano Rosas      * example, setting migration capabilities when the migration is still
5058a645544SFabiano Rosas      * running leads to an error.
5068a645544SFabiano Rosas      */
5078a645544SFabiano Rosas     wait_for_migration_status(from, "cancelled", NULL);
5088a645544SFabiano Rosas 
5098a645544SFabiano Rosas     args = (MigrateStart){
5108a645544SFabiano Rosas         .only_target = true,
5118a645544SFabiano Rosas     };
5128a645544SFabiano Rosas 
5138a645544SFabiano Rosas     if (migrate_start(&from, &to2, "defer", &args)) {
5148a645544SFabiano Rosas         return;
5158a645544SFabiano Rosas     }
5168a645544SFabiano Rosas 
5178a645544SFabiano Rosas     migrate_set_parameter_int(to2, "multifd-channels", 16);
5188a645544SFabiano Rosas 
5198a645544SFabiano Rosas     migrate_set_capability(to2, "multifd", true);
5208a645544SFabiano Rosas 
5218a645544SFabiano Rosas     /* Start incoming migration from the 1st socket */
52243ca9d18SSteve Sistare     migrate_incoming_qmp(to2, "tcp:127.0.0.1:0", NULL, "{}");
5238a645544SFabiano Rosas 
5248a645544SFabiano Rosas     migrate_ensure_non_converge(from);
5258a645544SFabiano Rosas 
5268a645544SFabiano Rosas     migrate_qmp(from, to2, NULL, NULL, "{}");
5278a645544SFabiano Rosas 
5288a645544SFabiano Rosas     migrate_wait_for_dirty_mem(from, to2);
5298a645544SFabiano Rosas 
5308a645544SFabiano Rosas     migrate_ensure_converge(from);
5318a645544SFabiano Rosas 
5328a645544SFabiano Rosas     wait_for_stop(from, get_src());
5338a645544SFabiano Rosas     qtest_qmp_eventwait(to2, "RESUME");
5348a645544SFabiano Rosas 
5358a645544SFabiano Rosas     wait_for_serial("dest_serial");
5368a645544SFabiano Rosas     wait_for_migration_complete(from);
5378a645544SFabiano Rosas     migrate_end(from, to2, true);
5388a645544SFabiano Rosas }
5398a645544SFabiano Rosas 
test_cancel_src_after_failed(QTestState * from,QTestState * to,const char * uri,const char * phase)540*538e03d2SFabiano Rosas static void test_cancel_src_after_failed(QTestState *from, QTestState *to,
541*538e03d2SFabiano Rosas                                          const char *uri, const char *phase)
542*538e03d2SFabiano Rosas {
543*538e03d2SFabiano Rosas     /*
544*538e03d2SFabiano Rosas      * No migrate_incoming_qmp() at the start to force source into
545*538e03d2SFabiano Rosas      * failed state during migrate_qmp().
546*538e03d2SFabiano Rosas      */
547*538e03d2SFabiano Rosas 
548*538e03d2SFabiano Rosas     wait_for_serial("src_serial");
549*538e03d2SFabiano Rosas     migrate_ensure_converge(from);
550*538e03d2SFabiano Rosas 
551*538e03d2SFabiano Rosas     migrate_qmp(from, to, uri, NULL, "{}");
552*538e03d2SFabiano Rosas 
553*538e03d2SFabiano Rosas     migration_event_wait(from, phase);
554*538e03d2SFabiano Rosas     migrate_cancel(from);
555*538e03d2SFabiano Rosas 
556*538e03d2SFabiano Rosas     /* cancelling will not move the migration out of 'failed' */
557*538e03d2SFabiano Rosas 
558*538e03d2SFabiano Rosas     wait_for_migration_status(from, "failed",
559*538e03d2SFabiano Rosas                               (const char * []) { "completed", NULL });
560*538e03d2SFabiano Rosas 
561*538e03d2SFabiano Rosas     /*
562*538e03d2SFabiano Rosas      * Not waiting for the destination because it never started
563*538e03d2SFabiano Rosas      * migration.
564*538e03d2SFabiano Rosas      */
565*538e03d2SFabiano Rosas }
566*538e03d2SFabiano Rosas 
test_cancel_src_after_cancelled(QTestState * from,QTestState * to,const char * uri,const char * phase)567*538e03d2SFabiano Rosas static void test_cancel_src_after_cancelled(QTestState *from, QTestState *to,
568*538e03d2SFabiano Rosas                                             const char *uri, const char *phase)
569*538e03d2SFabiano Rosas {
570*538e03d2SFabiano Rosas     migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
571*538e03d2SFabiano Rosas 
572*538e03d2SFabiano Rosas     wait_for_serial("src_serial");
573*538e03d2SFabiano Rosas     migrate_ensure_converge(from);
574*538e03d2SFabiano Rosas 
575*538e03d2SFabiano Rosas     migrate_qmp(from, to, uri, NULL, "{}");
576*538e03d2SFabiano Rosas 
577*538e03d2SFabiano Rosas     /* To move to cancelled/cancelling */
578*538e03d2SFabiano Rosas     migrate_cancel(from);
579*538e03d2SFabiano Rosas     migration_event_wait(from, phase);
580*538e03d2SFabiano Rosas 
581*538e03d2SFabiano Rosas     /* The migrate_cancel under test */
582*538e03d2SFabiano Rosas     migrate_cancel(from);
583*538e03d2SFabiano Rosas 
584*538e03d2SFabiano Rosas     wait_for_migration_status(from, "cancelled",
585*538e03d2SFabiano Rosas                               (const char * []) { "completed", NULL });
586*538e03d2SFabiano Rosas 
587*538e03d2SFabiano Rosas     wait_for_migration_status(to, "failed",
588*538e03d2SFabiano Rosas                               (const char * []) { "completed", NULL });
589*538e03d2SFabiano Rosas }
590*538e03d2SFabiano Rosas 
test_cancel_src_after_complete(QTestState * from,QTestState * to,const char * uri,const char * phase)591*538e03d2SFabiano Rosas static void test_cancel_src_after_complete(QTestState *from, QTestState *to,
592*538e03d2SFabiano Rosas                                            const char *uri, const char *phase)
593*538e03d2SFabiano Rosas {
594*538e03d2SFabiano Rosas     migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
595*538e03d2SFabiano Rosas 
596*538e03d2SFabiano Rosas     wait_for_serial("src_serial");
597*538e03d2SFabiano Rosas     migrate_ensure_converge(from);
598*538e03d2SFabiano Rosas 
599*538e03d2SFabiano Rosas     migrate_qmp(from, to, uri, NULL, "{}");
600*538e03d2SFabiano Rosas 
601*538e03d2SFabiano Rosas     migration_event_wait(from, phase);
602*538e03d2SFabiano Rosas     migrate_cancel(from);
603*538e03d2SFabiano Rosas 
604*538e03d2SFabiano Rosas     /*
605*538e03d2SFabiano Rosas      * qmp_migrate_cancel() exits early if migration is not running
606*538e03d2SFabiano Rosas      * anymore, the status will not change to cancelled.
607*538e03d2SFabiano Rosas      */
608*538e03d2SFabiano Rosas     wait_for_migration_complete(from);
609*538e03d2SFabiano Rosas     wait_for_migration_complete(to);
610*538e03d2SFabiano Rosas }
611*538e03d2SFabiano Rosas 
test_cancel_src_after_none(QTestState * from,QTestState * to,const char * uri,const char * phase)612*538e03d2SFabiano Rosas static void test_cancel_src_after_none(QTestState *from, QTestState *to,
613*538e03d2SFabiano Rosas                                        const char *uri, const char *phase)
614*538e03d2SFabiano Rosas {
615*538e03d2SFabiano Rosas     /*
616*538e03d2SFabiano Rosas      * Test that cancelling without a migration happening does not
617*538e03d2SFabiano Rosas      * affect subsequent migrations
618*538e03d2SFabiano Rosas      */
619*538e03d2SFabiano Rosas     migrate_cancel(to);
620*538e03d2SFabiano Rosas 
621*538e03d2SFabiano Rosas     wait_for_serial("src_serial");
622*538e03d2SFabiano Rosas     migrate_cancel(from);
623*538e03d2SFabiano Rosas 
624*538e03d2SFabiano Rosas     migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
625*538e03d2SFabiano Rosas 
626*538e03d2SFabiano Rosas     migrate_ensure_converge(from);
627*538e03d2SFabiano Rosas     migrate_qmp(from, to, uri, NULL, "{}");
628*538e03d2SFabiano Rosas 
629*538e03d2SFabiano Rosas     wait_for_migration_complete(from);
630*538e03d2SFabiano Rosas     wait_for_migration_complete(to);
631*538e03d2SFabiano Rosas }
632*538e03d2SFabiano Rosas 
test_cancel_src_pre_switchover(QTestState * from,QTestState * to,const char * uri,const char * phase)633*538e03d2SFabiano Rosas static void test_cancel_src_pre_switchover(QTestState *from, QTestState *to,
634*538e03d2SFabiano Rosas                                            const char *uri, const char *phase)
635*538e03d2SFabiano Rosas {
636*538e03d2SFabiano Rosas     migrate_set_capability(from, "pause-before-switchover", true);
637*538e03d2SFabiano Rosas     migrate_set_capability(to, "pause-before-switchover", true);
638*538e03d2SFabiano Rosas 
639*538e03d2SFabiano Rosas     migrate_set_capability(from, "multifd", true);
640*538e03d2SFabiano Rosas     migrate_set_capability(to, "multifd", true);
641*538e03d2SFabiano Rosas 
642*538e03d2SFabiano Rosas     migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
643*538e03d2SFabiano Rosas 
644*538e03d2SFabiano Rosas     wait_for_serial("src_serial");
645*538e03d2SFabiano Rosas     migrate_ensure_converge(from);
646*538e03d2SFabiano Rosas 
647*538e03d2SFabiano Rosas     migrate_qmp(from, to, uri, NULL, "{}");
648*538e03d2SFabiano Rosas 
649*538e03d2SFabiano Rosas     migration_event_wait(from, phase);
650*538e03d2SFabiano Rosas     migrate_cancel(from);
651*538e03d2SFabiano Rosas     migration_event_wait(from, "cancelling");
652*538e03d2SFabiano Rosas 
653*538e03d2SFabiano Rosas     wait_for_migration_status(from, "cancelled",
654*538e03d2SFabiano Rosas                               (const char * []) { "completed", NULL });
655*538e03d2SFabiano Rosas 
656*538e03d2SFabiano Rosas     wait_for_migration_status(to, "failed",
657*538e03d2SFabiano Rosas                               (const char * []) { "completed", NULL });
658*538e03d2SFabiano Rosas }
659*538e03d2SFabiano Rosas 
test_cancel_src_after_status(void * opaque)660*538e03d2SFabiano Rosas static void test_cancel_src_after_status(void *opaque)
661*538e03d2SFabiano Rosas {
662*538e03d2SFabiano Rosas     const char *test_path = opaque;
663*538e03d2SFabiano Rosas     g_autofree char *phase = g_path_get_basename(test_path);
664*538e03d2SFabiano Rosas     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
665*538e03d2SFabiano Rosas     QTestState *from, *to;
666*538e03d2SFabiano Rosas     MigrateStart args = {
667*538e03d2SFabiano Rosas         .hide_stderr = true,
668*538e03d2SFabiano Rosas     };
669*538e03d2SFabiano Rosas 
670*538e03d2SFabiano Rosas     if (migrate_start(&from, &to, "defer", &args)) {
671*538e03d2SFabiano Rosas         return;
672*538e03d2SFabiano Rosas     }
673*538e03d2SFabiano Rosas 
674*538e03d2SFabiano Rosas     if (g_str_equal(phase, "cancelling") ||
675*538e03d2SFabiano Rosas         g_str_equal(phase, "cancelled")) {
676*538e03d2SFabiano Rosas         test_cancel_src_after_cancelled(from, to, uri, phase);
677*538e03d2SFabiano Rosas 
678*538e03d2SFabiano Rosas     } else if (g_str_equal(phase, "completed")) {
679*538e03d2SFabiano Rosas         test_cancel_src_after_complete(from, to, uri, phase);
680*538e03d2SFabiano Rosas 
681*538e03d2SFabiano Rosas     } else if (g_str_equal(phase, "failed")) {
682*538e03d2SFabiano Rosas         test_cancel_src_after_failed(from, to, uri, phase);
683*538e03d2SFabiano Rosas 
684*538e03d2SFabiano Rosas     } else if (g_str_equal(phase, "none")) {
685*538e03d2SFabiano Rosas         test_cancel_src_after_none(from, to, uri, phase);
686*538e03d2SFabiano Rosas 
687*538e03d2SFabiano Rosas     } else {
688*538e03d2SFabiano Rosas         /* any state that comes before pre-switchover */
689*538e03d2SFabiano Rosas         test_cancel_src_pre_switchover(from, to, uri, phase);
690*538e03d2SFabiano Rosas     }
691*538e03d2SFabiano Rosas 
692*538e03d2SFabiano Rosas     migrate_end(from, to, false);
693*538e03d2SFabiano Rosas }
694*538e03d2SFabiano Rosas 
calc_dirty_rate(QTestState * who,uint64_t calc_time)6958a645544SFabiano Rosas static void calc_dirty_rate(QTestState *who, uint64_t calc_time)
6968a645544SFabiano Rosas {
6978a645544SFabiano Rosas     qtest_qmp_assert_success(who,
6988a645544SFabiano Rosas                              "{ 'execute': 'calc-dirty-rate',"
6998a645544SFabiano Rosas                              "'arguments': { "
7008a645544SFabiano Rosas                              "'calc-time': %" PRIu64 ","
7018a645544SFabiano Rosas                              "'mode': 'dirty-ring' }}",
7028a645544SFabiano Rosas                              calc_time);
7038a645544SFabiano Rosas }
7048a645544SFabiano Rosas 
query_dirty_rate(QTestState * who)7058a645544SFabiano Rosas static QDict *query_dirty_rate(QTestState *who)
7068a645544SFabiano Rosas {
7078a645544SFabiano Rosas     return qtest_qmp_assert_success_ref(who,
7088a645544SFabiano Rosas                                         "{ 'execute': 'query-dirty-rate' }");
7098a645544SFabiano Rosas }
7108a645544SFabiano Rosas 
dirtylimit_set_all(QTestState * who,uint64_t dirtyrate)7118a645544SFabiano Rosas static void dirtylimit_set_all(QTestState *who, uint64_t dirtyrate)
7128a645544SFabiano Rosas {
7138a645544SFabiano Rosas     qtest_qmp_assert_success(who,
7148a645544SFabiano Rosas                              "{ 'execute': 'set-vcpu-dirty-limit',"
7158a645544SFabiano Rosas                              "'arguments': { "
7168a645544SFabiano Rosas                              "'dirty-rate': %" PRIu64 " } }",
7178a645544SFabiano Rosas                              dirtyrate);
7188a645544SFabiano Rosas }
7198a645544SFabiano Rosas 
cancel_vcpu_dirty_limit(QTestState * who)7208a645544SFabiano Rosas static void cancel_vcpu_dirty_limit(QTestState *who)
7218a645544SFabiano Rosas {
7228a645544SFabiano Rosas     qtest_qmp_assert_success(who,
7238a645544SFabiano Rosas                              "{ 'execute': 'cancel-vcpu-dirty-limit' }");
7248a645544SFabiano Rosas }
7258a645544SFabiano Rosas 
query_vcpu_dirty_limit(QTestState * who)7268a645544SFabiano Rosas static QDict *query_vcpu_dirty_limit(QTestState *who)
7278a645544SFabiano Rosas {
7288a645544SFabiano Rosas     QDict *rsp;
7298a645544SFabiano Rosas 
7308a645544SFabiano Rosas     rsp = qtest_qmp(who, "{ 'execute': 'query-vcpu-dirty-limit' }");
7318a645544SFabiano Rosas     g_assert(!qdict_haskey(rsp, "error"));
7328a645544SFabiano Rosas     g_assert(qdict_haskey(rsp, "return"));
7338a645544SFabiano Rosas 
7348a645544SFabiano Rosas     return rsp;
7358a645544SFabiano Rosas }
7368a645544SFabiano Rosas 
calc_dirtyrate_ready(QTestState * who)7378a645544SFabiano Rosas static bool calc_dirtyrate_ready(QTestState *who)
7388a645544SFabiano Rosas {
7398a645544SFabiano Rosas     QDict *rsp_return;
7408a645544SFabiano Rosas     const char *status;
7418a645544SFabiano Rosas     bool ready;
7428a645544SFabiano Rosas 
7438a645544SFabiano Rosas     rsp_return = query_dirty_rate(who);
7448a645544SFabiano Rosas     g_assert(rsp_return);
7458a645544SFabiano Rosas 
7468a645544SFabiano Rosas     status = qdict_get_str(rsp_return, "status");
7478a645544SFabiano Rosas     g_assert(status);
7488a645544SFabiano Rosas     ready = g_strcmp0(status, "measuring");
7498a645544SFabiano Rosas     qobject_unref(rsp_return);
7508a645544SFabiano Rosas 
7518a645544SFabiano Rosas     return ready;
7528a645544SFabiano Rosas }
7538a645544SFabiano Rosas 
wait_for_calc_dirtyrate_complete(QTestState * who,int64_t time_s)7548a645544SFabiano Rosas static void wait_for_calc_dirtyrate_complete(QTestState *who,
7558a645544SFabiano Rosas                                              int64_t time_s)
7568a645544SFabiano Rosas {
7578a645544SFabiano Rosas     int max_try_count = 10000;
7588a645544SFabiano Rosas     usleep(time_s * 1000000);
7598a645544SFabiano Rosas 
7608a645544SFabiano Rosas     while (!calc_dirtyrate_ready(who) && max_try_count--) {
7618a645544SFabiano Rosas         usleep(1000);
7628a645544SFabiano Rosas     }
7638a645544SFabiano Rosas 
7648a645544SFabiano Rosas     /*
7658a645544SFabiano Rosas      * Set the timeout with 10 s(max_try_count * 1000us),
7668a645544SFabiano Rosas      * if dirtyrate measurement not complete, fail test.
7678a645544SFabiano Rosas      */
7688a645544SFabiano Rosas     g_assert_cmpint(max_try_count, !=, 0);
7698a645544SFabiano Rosas }
7708a645544SFabiano Rosas 
get_dirty_rate(QTestState * who)7718a645544SFabiano Rosas static int64_t get_dirty_rate(QTestState *who)
7728a645544SFabiano Rosas {
7738a645544SFabiano Rosas     QDict *rsp_return;
7748a645544SFabiano Rosas     const char *status;
7758a645544SFabiano Rosas     QList *rates;
7768a645544SFabiano Rosas     const QListEntry *entry;
7778a645544SFabiano Rosas     QDict *rate;
7788a645544SFabiano Rosas     int64_t dirtyrate;
7798a645544SFabiano Rosas 
7808a645544SFabiano Rosas     rsp_return = query_dirty_rate(who);
7818a645544SFabiano Rosas     g_assert(rsp_return);
7828a645544SFabiano Rosas 
7838a645544SFabiano Rosas     status = qdict_get_str(rsp_return, "status");
7848a645544SFabiano Rosas     g_assert(status);
7858a645544SFabiano Rosas     g_assert_cmpstr(status, ==, "measured");
7868a645544SFabiano Rosas 
7878a645544SFabiano Rosas     rates = qdict_get_qlist(rsp_return, "vcpu-dirty-rate");
7888a645544SFabiano Rosas     g_assert(rates && !qlist_empty(rates));
7898a645544SFabiano Rosas 
7908a645544SFabiano Rosas     entry = qlist_first(rates);
7918a645544SFabiano Rosas     g_assert(entry);
7928a645544SFabiano Rosas 
7938a645544SFabiano Rosas     rate = qobject_to(QDict, qlist_entry_obj(entry));
7948a645544SFabiano Rosas     g_assert(rate);
7958a645544SFabiano Rosas 
7968a645544SFabiano Rosas     dirtyrate = qdict_get_try_int(rate, "dirty-rate", -1);
7978a645544SFabiano Rosas 
7988a645544SFabiano Rosas     qobject_unref(rsp_return);
7998a645544SFabiano Rosas     return dirtyrate;
8008a645544SFabiano Rosas }
8018a645544SFabiano Rosas 
get_limit_rate(QTestState * who)8028a645544SFabiano Rosas static int64_t get_limit_rate(QTestState *who)
8038a645544SFabiano Rosas {
8048a645544SFabiano Rosas     QDict *rsp_return;
8058a645544SFabiano Rosas     QList *rates;
8068a645544SFabiano Rosas     const QListEntry *entry;
8078a645544SFabiano Rosas     QDict *rate;
8088a645544SFabiano Rosas     int64_t dirtyrate;
8098a645544SFabiano Rosas 
8108a645544SFabiano Rosas     rsp_return = query_vcpu_dirty_limit(who);
8118a645544SFabiano Rosas     g_assert(rsp_return);
8128a645544SFabiano Rosas 
8138a645544SFabiano Rosas     rates = qdict_get_qlist(rsp_return, "return");
8148a645544SFabiano Rosas     g_assert(rates && !qlist_empty(rates));
8158a645544SFabiano Rosas 
8168a645544SFabiano Rosas     entry = qlist_first(rates);
8178a645544SFabiano Rosas     g_assert(entry);
8188a645544SFabiano Rosas 
8198a645544SFabiano Rosas     rate = qobject_to(QDict, qlist_entry_obj(entry));
8208a645544SFabiano Rosas     g_assert(rate);
8218a645544SFabiano Rosas 
8228a645544SFabiano Rosas     dirtyrate = qdict_get_try_int(rate, "limit-rate", -1);
8238a645544SFabiano Rosas 
8248a645544SFabiano Rosas     qobject_unref(rsp_return);
8258a645544SFabiano Rosas     return dirtyrate;
8268a645544SFabiano Rosas }
8278a645544SFabiano Rosas 
dirtylimit_start_vm(void)8288a645544SFabiano Rosas static QTestState *dirtylimit_start_vm(void)
8298a645544SFabiano Rosas {
8308a645544SFabiano Rosas     QTestState *vm = NULL;
8318a645544SFabiano Rosas     g_autofree gchar *cmd = NULL;
8328a645544SFabiano Rosas     const char *bootpath;
8338a645544SFabiano Rosas 
8348a645544SFabiano Rosas     bootpath = bootfile_create(qtest_get_arch(), tmpfs, false);
8358a645544SFabiano Rosas     cmd = g_strdup_printf("-accel kvm,dirty-ring-size=4096 "
8368a645544SFabiano Rosas                           "-name dirtylimit-test,debug-threads=on "
8378a645544SFabiano Rosas                           "-m 150M -smp 1 "
8388a645544SFabiano Rosas                           "-serial file:%s/vm_serial "
8398a645544SFabiano Rosas                           "-drive file=%s,format=raw ",
8408a645544SFabiano Rosas                           tmpfs, bootpath);
8418a645544SFabiano Rosas 
8428a645544SFabiano Rosas     vm = qtest_init(cmd);
8438a645544SFabiano Rosas     return vm;
8448a645544SFabiano Rosas }
8458a645544SFabiano Rosas 
dirtylimit_stop_vm(QTestState * vm)8468a645544SFabiano Rosas static void dirtylimit_stop_vm(QTestState *vm)
8478a645544SFabiano Rosas {
8488a645544SFabiano Rosas     g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, "vm_serial");
8498a645544SFabiano Rosas 
8508a645544SFabiano Rosas     qtest_quit(vm);
8518a645544SFabiano Rosas     unlink(path);
8528a645544SFabiano Rosas }
8538a645544SFabiano Rosas 
test_vcpu_dirty_limit(void)8548a645544SFabiano Rosas static void test_vcpu_dirty_limit(void)
8558a645544SFabiano Rosas {
8568a645544SFabiano Rosas     QTestState *vm;
8578a645544SFabiano Rosas     int64_t origin_rate;
8588a645544SFabiano Rosas     int64_t quota_rate;
8598a645544SFabiano Rosas     int64_t rate ;
8608a645544SFabiano Rosas     int max_try_count = 20;
8618a645544SFabiano Rosas     int hit = 0;
8628a645544SFabiano Rosas 
8638a645544SFabiano Rosas     /* Start vm for vcpu dirtylimit test */
8648a645544SFabiano Rosas     vm = dirtylimit_start_vm();
8658a645544SFabiano Rosas 
8668a645544SFabiano Rosas     /* Wait for the first serial output from the vm*/
8678a645544SFabiano Rosas     wait_for_serial("vm_serial");
8688a645544SFabiano Rosas 
8698a645544SFabiano Rosas     /* Do dirtyrate measurement with calc time equals 1s */
8708a645544SFabiano Rosas     calc_dirty_rate(vm, 1);
8718a645544SFabiano Rosas 
8728a645544SFabiano Rosas     /* Sleep calc time and wait for calc dirtyrate complete */
8738a645544SFabiano Rosas     wait_for_calc_dirtyrate_complete(vm, 1);
8748a645544SFabiano Rosas 
8758a645544SFabiano Rosas     /* Query original dirty page rate */
8768a645544SFabiano Rosas     origin_rate = get_dirty_rate(vm);
8778a645544SFabiano Rosas 
8788a645544SFabiano Rosas     /* VM booted from bootsect should dirty memory steadily */
8798a645544SFabiano Rosas     assert(origin_rate != 0);
8808a645544SFabiano Rosas 
8818a645544SFabiano Rosas     /* Setup quota dirty page rate at half of origin */
8828a645544SFabiano Rosas     quota_rate = origin_rate / 2;
8838a645544SFabiano Rosas 
8848a645544SFabiano Rosas     /* Set dirtylimit */
8858a645544SFabiano Rosas     dirtylimit_set_all(vm, quota_rate);
8868a645544SFabiano Rosas 
8878a645544SFabiano Rosas     /*
8888a645544SFabiano Rosas      * Check if set-vcpu-dirty-limit and query-vcpu-dirty-limit
8898a645544SFabiano Rosas      * works literally
8908a645544SFabiano Rosas      */
8918a645544SFabiano Rosas     g_assert_cmpint(quota_rate, ==, get_limit_rate(vm));
8928a645544SFabiano Rosas 
8938a645544SFabiano Rosas     /* Sleep a bit to check if it take effect */
8948a645544SFabiano Rosas     usleep(2000000);
8958a645544SFabiano Rosas 
8968a645544SFabiano Rosas     /*
8978a645544SFabiano Rosas      * Check if dirtylimit take effect realistically, set the
8988a645544SFabiano Rosas      * timeout with 20 s(max_try_count * 1s), if dirtylimit
8998a645544SFabiano Rosas      * doesn't take effect, fail test.
9008a645544SFabiano Rosas      */
9018a645544SFabiano Rosas     while (--max_try_count) {
9028a645544SFabiano Rosas         calc_dirty_rate(vm, 1);
9038a645544SFabiano Rosas         wait_for_calc_dirtyrate_complete(vm, 1);
9048a645544SFabiano Rosas         rate = get_dirty_rate(vm);
9058a645544SFabiano Rosas 
9068a645544SFabiano Rosas         /*
9078a645544SFabiano Rosas          * Assume hitting if current rate is less
9088a645544SFabiano Rosas          * than quota rate (within accepting error)
9098a645544SFabiano Rosas          */
9108a645544SFabiano Rosas         if (rate < (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) {
9118a645544SFabiano Rosas             hit = 1;
9128a645544SFabiano Rosas             break;
9138a645544SFabiano Rosas         }
9148a645544SFabiano Rosas     }
9158a645544SFabiano Rosas 
9168a645544SFabiano Rosas     g_assert_cmpint(hit, ==, 1);
9178a645544SFabiano Rosas 
9188a645544SFabiano Rosas     hit = 0;
9198a645544SFabiano Rosas     max_try_count = 20;
9208a645544SFabiano Rosas 
9218a645544SFabiano Rosas     /* Check if dirtylimit cancellation take effect */
9228a645544SFabiano Rosas     cancel_vcpu_dirty_limit(vm);
9238a645544SFabiano Rosas     while (--max_try_count) {
9248a645544SFabiano Rosas         calc_dirty_rate(vm, 1);
9258a645544SFabiano Rosas         wait_for_calc_dirtyrate_complete(vm, 1);
9268a645544SFabiano Rosas         rate = get_dirty_rate(vm);
9278a645544SFabiano Rosas 
9288a645544SFabiano Rosas         /*
9298a645544SFabiano Rosas          * Assume dirtylimit be canceled if current rate is
9308a645544SFabiano Rosas          * greater than quota rate (within accepting error)
9318a645544SFabiano Rosas          */
9328a645544SFabiano Rosas         if (rate > (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) {
9338a645544SFabiano Rosas             hit = 1;
9348a645544SFabiano Rosas             break;
9358a645544SFabiano Rosas         }
9368a645544SFabiano Rosas     }
9378a645544SFabiano Rosas 
9388a645544SFabiano Rosas     g_assert_cmpint(hit, ==, 1);
9398a645544SFabiano Rosas     dirtylimit_stop_vm(vm);
9408a645544SFabiano Rosas }
9418a645544SFabiano Rosas 
migrate_dirty_limit_wait_showup(QTestState * from,const int64_t period,const int64_t value)9428a645544SFabiano Rosas static void migrate_dirty_limit_wait_showup(QTestState *from,
9438a645544SFabiano Rosas                                             const int64_t period,
9448a645544SFabiano Rosas                                             const int64_t value)
9458a645544SFabiano Rosas {
9468a645544SFabiano Rosas     /* Enable dirty limit capability */
9478a645544SFabiano Rosas     migrate_set_capability(from, "dirty-limit", true);
9488a645544SFabiano Rosas 
9498a645544SFabiano Rosas     /* Set dirty limit parameters */
9508a645544SFabiano Rosas     migrate_set_parameter_int(from, "x-vcpu-dirty-limit-period", period);
9518a645544SFabiano Rosas     migrate_set_parameter_int(from, "vcpu-dirty-limit", value);
9528a645544SFabiano Rosas 
9538a645544SFabiano Rosas     /* Make sure migrate can't converge */
9548a645544SFabiano Rosas     migrate_ensure_non_converge(from);
9558a645544SFabiano Rosas 
9568a645544SFabiano Rosas     /* To check limit rate after precopy */
9578a645544SFabiano Rosas     migrate_set_capability(from, "pause-before-switchover", true);
9588a645544SFabiano Rosas 
9598a645544SFabiano Rosas     /* Wait for the serial output from the source */
9608a645544SFabiano Rosas     wait_for_serial("src_serial");
9618a645544SFabiano Rosas }
9628a645544SFabiano Rosas 
9638a645544SFabiano Rosas /*
9648a645544SFabiano Rosas  * This test does:
9658a645544SFabiano Rosas  *  source                          destination
9668a645544SFabiano Rosas  *  start vm
9678a645544SFabiano Rosas  *                                  start incoming vm
9688a645544SFabiano Rosas  *  migrate
9698a645544SFabiano Rosas  *  wait dirty limit to begin
9708a645544SFabiano Rosas  *  cancel migrate
9718a645544SFabiano Rosas  *  cancellation check
9728a645544SFabiano Rosas  *                                  restart incoming vm
9738a645544SFabiano Rosas  *  migrate
9748a645544SFabiano Rosas  *  wait dirty limit to begin
9758a645544SFabiano Rosas  *  wait pre-switchover event
9768a645544SFabiano Rosas  *  convergence condition check
9778a645544SFabiano Rosas  *
9788a645544SFabiano Rosas  * And see if dirty limit migration works correctly.
9798a645544SFabiano Rosas  * This test case involves many passes, so it runs in slow mode only.
9808a645544SFabiano Rosas  */
test_dirty_limit(void)9818a645544SFabiano Rosas static void test_dirty_limit(void)
9828a645544SFabiano Rosas {
9838a645544SFabiano Rosas     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
9848a645544SFabiano Rosas     QTestState *from, *to;
9858a645544SFabiano Rosas     int64_t remaining;
9868a645544SFabiano Rosas     uint64_t throttle_us_per_full;
9878a645544SFabiano Rosas     /*
9888a645544SFabiano Rosas      * We want the test to be stable and as fast as possible.
9898a645544SFabiano Rosas      * E.g., with 1Gb/s bandwidth migration may pass without dirty limit,
9908a645544SFabiano Rosas      * so we need to decrease a bandwidth.
9918a645544SFabiano Rosas      */
9928a645544SFabiano Rosas     const int64_t dirtylimit_period = 1000, dirtylimit_value = 50;
9938a645544SFabiano Rosas     const int64_t max_bandwidth = 400000000; /* ~400Mb/s */
9948a645544SFabiano Rosas     const int64_t downtime_limit = 250; /* 250ms */
9958a645544SFabiano Rosas     /*
9968a645544SFabiano Rosas      * We migrate through unix-socket (> 500Mb/s).
9978a645544SFabiano Rosas      * Thus, expected migration speed ~= bandwidth limit (< 500Mb/s).
9988a645544SFabiano Rosas      * So, we can predict expected_threshold
9998a645544SFabiano Rosas      */
10008a645544SFabiano Rosas     const int64_t expected_threshold = max_bandwidth * downtime_limit / 1000;
10018a645544SFabiano Rosas     int max_try_count = 10;
10028a645544SFabiano Rosas     MigrateCommon args = {
10038a645544SFabiano Rosas         .start = {
10048a645544SFabiano Rosas             .hide_stderr = true,
10058a645544SFabiano Rosas             .use_dirty_ring = true,
10068a645544SFabiano Rosas         },
10078a645544SFabiano Rosas         .listen_uri = uri,
10088a645544SFabiano Rosas         .connect_uri = uri,
10098a645544SFabiano Rosas     };
10108a645544SFabiano Rosas 
10118a645544SFabiano Rosas     /* Start src, dst vm */
10128a645544SFabiano Rosas     if (migrate_start(&from, &to, args.listen_uri, &args.start)) {
10138a645544SFabiano Rosas         return;
10148a645544SFabiano Rosas     }
10158a645544SFabiano Rosas 
10168a645544SFabiano Rosas     /* Prepare for dirty limit migration and wait src vm show up */
10178a645544SFabiano Rosas     migrate_dirty_limit_wait_showup(from, dirtylimit_period, dirtylimit_value);
10188a645544SFabiano Rosas 
10198a645544SFabiano Rosas     /* Start migrate */
10208a645544SFabiano Rosas     migrate_qmp(from, to, args.connect_uri, NULL, "{}");
10218a645544SFabiano Rosas 
10228a645544SFabiano Rosas     /* Wait for dirty limit throttle begin */
10238a645544SFabiano Rosas     throttle_us_per_full = 0;
10248a645544SFabiano Rosas     while (throttle_us_per_full == 0) {
10258a645544SFabiano Rosas         throttle_us_per_full =
10268a645544SFabiano Rosas             read_migrate_property_int(from,
10278a645544SFabiano Rosas                                       "dirty-limit-throttle-time-per-round");
10288a645544SFabiano Rosas         usleep(100);
10298a645544SFabiano Rosas         g_assert_false(get_src()->stop_seen);
10308a645544SFabiano Rosas     }
10318a645544SFabiano Rosas 
10328a645544SFabiano Rosas     /* Now cancel migrate and wait for dirty limit throttle switch off */
10338a645544SFabiano Rosas     migrate_cancel(from);
10348a645544SFabiano Rosas     wait_for_migration_status(from, "cancelled", NULL);
10358a645544SFabiano Rosas 
1036cd196679SFabiano Rosas     /* destination always fails after cancel */
1037cd196679SFabiano Rosas     migration_event_wait(to, "failed");
1038cd196679SFabiano Rosas     qtest_set_expected_status(to, EXIT_FAILURE);
1039cd196679SFabiano Rosas     qtest_quit(to);
1040cd196679SFabiano Rosas 
10418a645544SFabiano Rosas     /* Check if dirty limit throttle switched off, set timeout 1ms */
10428a645544SFabiano Rosas     do {
10438a645544SFabiano Rosas         throttle_us_per_full =
10448a645544SFabiano Rosas             read_migrate_property_int(from,
10458a645544SFabiano Rosas                                       "dirty-limit-throttle-time-per-round");
10468a645544SFabiano Rosas         usleep(100);
10478a645544SFabiano Rosas         g_assert_false(get_src()->stop_seen);
10488a645544SFabiano Rosas     } while (throttle_us_per_full != 0 && --max_try_count);
10498a645544SFabiano Rosas 
10508a645544SFabiano Rosas     /* Assert dirty limit is not in service */
10518a645544SFabiano Rosas     g_assert_cmpint(throttle_us_per_full, ==, 0);
10528a645544SFabiano Rosas 
10538a645544SFabiano Rosas     args = (MigrateCommon) {
10548a645544SFabiano Rosas         .start = {
10558a645544SFabiano Rosas             .only_target = true,
10568a645544SFabiano Rosas             .use_dirty_ring = true,
10578a645544SFabiano Rosas         },
10588a645544SFabiano Rosas         .listen_uri = uri,
10598a645544SFabiano Rosas         .connect_uri = uri,
10608a645544SFabiano Rosas     };
10618a645544SFabiano Rosas 
10628a645544SFabiano Rosas     /* Restart dst vm, src vm already show up so we needn't wait anymore */
10638a645544SFabiano Rosas     if (migrate_start(&from, &to, args.listen_uri, &args.start)) {
10648a645544SFabiano Rosas         return;
10658a645544SFabiano Rosas     }
10668a645544SFabiano Rosas 
10678a645544SFabiano Rosas     /* Start migrate */
10688a645544SFabiano Rosas     migrate_qmp(from, to, args.connect_uri, NULL, "{}");
10698a645544SFabiano Rosas 
10708a645544SFabiano Rosas     /* Wait for dirty limit throttle begin */
10718a645544SFabiano Rosas     throttle_us_per_full = 0;
10728a645544SFabiano Rosas     while (throttle_us_per_full == 0) {
10738a645544SFabiano Rosas         throttle_us_per_full =
10748a645544SFabiano Rosas             read_migrate_property_int(from,
10758a645544SFabiano Rosas                                       "dirty-limit-throttle-time-per-round");
10768a645544SFabiano Rosas         usleep(100);
10778a645544SFabiano Rosas         g_assert_false(get_src()->stop_seen);
10788a645544SFabiano Rosas     }
10798a645544SFabiano Rosas 
10808a645544SFabiano Rosas     /*
10818a645544SFabiano Rosas      * The dirty limit rate should equals the return value of
10828a645544SFabiano Rosas      * query-vcpu-dirty-limit if dirty limit cap set
10838a645544SFabiano Rosas      */
10848a645544SFabiano Rosas     g_assert_cmpint(dirtylimit_value, ==, get_limit_rate(from));
10858a645544SFabiano Rosas 
10868a645544SFabiano Rosas     /* Now, we have tested if dirty limit works, let it converge */
10878a645544SFabiano Rosas     migrate_set_parameter_int(from, "downtime-limit", downtime_limit);
10888a645544SFabiano Rosas     migrate_set_parameter_int(from, "max-bandwidth", max_bandwidth);
10898a645544SFabiano Rosas 
10908a645544SFabiano Rosas     /*
10918a645544SFabiano Rosas      * Wait for pre-switchover status to check if migration
10928a645544SFabiano Rosas      * satisfy the convergence condition
10938a645544SFabiano Rosas      */
10948a645544SFabiano Rosas     wait_for_migration_status(from, "pre-switchover", NULL);
10958a645544SFabiano Rosas 
10968a645544SFabiano Rosas     remaining = read_ram_property_int(from, "remaining");
10978a645544SFabiano Rosas     g_assert_cmpint(remaining, <,
10988a645544SFabiano Rosas                     (expected_threshold + expected_threshold / 100));
10998a645544SFabiano Rosas 
11008a645544SFabiano Rosas     migrate_continue(from, "pre-switchover");
11018a645544SFabiano Rosas 
11028a645544SFabiano Rosas     qtest_qmp_eventwait(to, "RESUME");
11038a645544SFabiano Rosas 
11048a645544SFabiano Rosas     wait_for_serial("dest_serial");
11058a645544SFabiano Rosas     wait_for_migration_complete(from);
11068a645544SFabiano Rosas 
11078a645544SFabiano Rosas     migrate_end(from, to, true);
11088a645544SFabiano Rosas }
11098a645544SFabiano Rosas 
migration_test_add_precopy_smoke(MigrationTestEnv * env)111043ab3fb3SFabiano Rosas static void migration_test_add_precopy_smoke(MigrationTestEnv *env)
11118a645544SFabiano Rosas {
11128a645544SFabiano Rosas     if (env->is_x86) {
11138a645544SFabiano Rosas         migration_test_add("/migration/precopy/unix/suspend/live",
11148a645544SFabiano Rosas                            test_precopy_unix_suspend_live);
11158a645544SFabiano Rosas         migration_test_add("/migration/precopy/unix/suspend/notlive",
11168a645544SFabiano Rosas                            test_precopy_unix_suspend_notlive);
11178a645544SFabiano Rosas     }
11188a645544SFabiano Rosas 
11198a645544SFabiano Rosas     migration_test_add("/migration/precopy/unix/plain",
11208a645544SFabiano Rosas                        test_precopy_unix_plain);
11218a645544SFabiano Rosas 
11228a645544SFabiano Rosas     migration_test_add("/migration/precopy/tcp/plain", test_precopy_tcp_plain);
112343ab3fb3SFabiano Rosas     migration_test_add("/migration/multifd/tcp/uri/plain/none",
112443ab3fb3SFabiano Rosas                        test_multifd_tcp_uri_none);
112543ab3fb3SFabiano Rosas     migration_test_add("/migration/multifd/tcp/plain/cancel",
112643ab3fb3SFabiano Rosas                        test_multifd_tcp_cancel);
112743ab3fb3SFabiano Rosas }
112843ab3fb3SFabiano Rosas 
migration_test_add_precopy(MigrationTestEnv * env)112943ab3fb3SFabiano Rosas void migration_test_add_precopy(MigrationTestEnv *env)
113043ab3fb3SFabiano Rosas {
113143ab3fb3SFabiano Rosas     tmpfs = env->tmpfs;
113243ab3fb3SFabiano Rosas 
113343ab3fb3SFabiano Rosas     migration_test_add_precopy_smoke(env);
113443ab3fb3SFabiano Rosas 
113543ab3fb3SFabiano Rosas     if (!env->full_set) {
113643ab3fb3SFabiano Rosas         return;
113743ab3fb3SFabiano Rosas     }
11388a645544SFabiano Rosas 
11398a645544SFabiano Rosas     migration_test_add("/migration/precopy/tcp/plain/switchover-ack",
11408a645544SFabiano Rosas                        test_precopy_tcp_switchover_ack);
11418a645544SFabiano Rosas 
11428a645544SFabiano Rosas #ifndef _WIN32
11438a645544SFabiano Rosas     migration_test_add("/migration/precopy/fd/tcp",
11448a645544SFabiano Rosas                        test_precopy_fd_socket);
11458a645544SFabiano Rosas     migration_test_add("/migration/precopy/fd/file",
11468a645544SFabiano Rosas                        test_precopy_fd_file);
11478a645544SFabiano Rosas #endif
11488a645544SFabiano Rosas 
11498a645544SFabiano Rosas     /*
11508a645544SFabiano Rosas      * See explanation why this test is slow on function definition
11518a645544SFabiano Rosas      */
11528a645544SFabiano Rosas     if (g_test_slow()) {
11538a645544SFabiano Rosas         migration_test_add("/migration/auto_converge",
11548a645544SFabiano Rosas                            test_auto_converge);
11558a645544SFabiano Rosas         if (g_str_equal(env->arch, "x86_64") &&
11568a645544SFabiano Rosas             env->has_kvm && env->has_dirty_ring) {
11578a645544SFabiano Rosas             migration_test_add("/dirty_limit",
11588a645544SFabiano Rosas                                test_dirty_limit);
11598a645544SFabiano Rosas         }
11608a645544SFabiano Rosas     }
11618a645544SFabiano Rosas     migration_test_add("/migration/multifd/tcp/channels/plain/none",
11628a645544SFabiano Rosas                        test_multifd_tcp_channels_none);
11638a645544SFabiano Rosas     migration_test_add("/migration/multifd/tcp/plain/zero-page/legacy",
11648a645544SFabiano Rosas                        test_multifd_tcp_zero_page_legacy);
11658a645544SFabiano Rosas     migration_test_add("/migration/multifd/tcp/plain/zero-page/none",
11668a645544SFabiano Rosas                        test_multifd_tcp_no_zero_page);
11678a645544SFabiano Rosas     if (g_str_equal(env->arch, "x86_64")
11688a645544SFabiano Rosas         && env->has_kvm && env->has_dirty_ring) {
11698a645544SFabiano Rosas 
11708a645544SFabiano Rosas         migration_test_add("/migration/dirty_ring",
11718a645544SFabiano Rosas                            test_precopy_unix_dirty_ring);
11728a645544SFabiano Rosas         if (qtest_has_machine("pc") && g_test_slow()) {
11738a645544SFabiano Rosas             migration_test_add("/migration/vcpu_dirty_limit",
11748a645544SFabiano Rosas                                test_vcpu_dirty_limit);
11758a645544SFabiano Rosas         }
11768a645544SFabiano Rosas     }
1177*538e03d2SFabiano Rosas 
1178*538e03d2SFabiano Rosas     /* ensure new status don't go unnoticed */
1179*538e03d2SFabiano Rosas     assert(MIGRATION_STATUS__MAX == 15);
1180*538e03d2SFabiano Rosas 
1181*538e03d2SFabiano Rosas     for (int i = MIGRATION_STATUS_NONE; i < MIGRATION_STATUS__MAX; i++) {
1182*538e03d2SFabiano Rosas         switch (i) {
1183*538e03d2SFabiano Rosas         case MIGRATION_STATUS_DEVICE: /* happens too fast */
1184*538e03d2SFabiano Rosas         case MIGRATION_STATUS_WAIT_UNPLUG: /* no support in tests */
1185*538e03d2SFabiano Rosas         case MIGRATION_STATUS_COLO: /* no support in tests */
1186*538e03d2SFabiano Rosas         case MIGRATION_STATUS_POSTCOPY_ACTIVE: /* postcopy can't be cancelled */
1187*538e03d2SFabiano Rosas         case MIGRATION_STATUS_POSTCOPY_PAUSED:
1188*538e03d2SFabiano Rosas         case MIGRATION_STATUS_POSTCOPY_RECOVER_SETUP:
1189*538e03d2SFabiano Rosas         case MIGRATION_STATUS_POSTCOPY_RECOVER:
1190*538e03d2SFabiano Rosas             continue;
1191*538e03d2SFabiano Rosas         default:
1192*538e03d2SFabiano Rosas             migration_test_add_suffix("/migration/cancel/src/after/",
1193*538e03d2SFabiano Rosas                                       MigrationStatus_str(i),
1194*538e03d2SFabiano Rosas                                       test_cancel_src_after_status);
1195*538e03d2SFabiano Rosas         }
1196*538e03d2SFabiano Rosas     }
11978a645544SFabiano Rosas }
1198