xref: /qemu/tests/qtest/migration/precopy-tests.c (revision 407bc4bf9027f7ac4333e47cd900d773b99a23e3)
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