xref: /openbmc/qemu/tests/qtest/migration-test.c (revision 3f4ad55ea28f75804d999cd3e1169c188bde052a)
11e8a1faeSThomas Huth /*
21e8a1faeSThomas Huth  * QTest testcase for migration
31e8a1faeSThomas Huth  *
41e8a1faeSThomas Huth  * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
51e8a1faeSThomas Huth  *   based on the vhost-user-test.c that is:
61e8a1faeSThomas Huth  *      Copyright (c) 2014 Virtual Open Systems Sarl.
71e8a1faeSThomas Huth  *
81e8a1faeSThomas Huth  * This work is licensed under the terms of the GNU GPL, version 2 or later.
91e8a1faeSThomas Huth  * See the COPYING file in the top-level directory.
101e8a1faeSThomas Huth  *
111e8a1faeSThomas Huth  */
121e8a1faeSThomas Huth 
131e8a1faeSThomas Huth #include "qemu/osdep.h"
141e8a1faeSThomas Huth 
15907b5105SMarc-André Lureau #include "libqtest.h"
161e8a1faeSThomas Huth #include "qapi/qmp/qdict.h"
171e8a1faeSThomas Huth #include "qemu/module.h"
181e8a1faeSThomas Huth #include "qemu/option.h"
191e8a1faeSThomas Huth #include "qemu/range.h"
201e8a1faeSThomas Huth #include "qemu/sockets.h"
211e8a1faeSThomas Huth #include "chardev/char.h"
2258d25e97SDaniel P. Berrangé #include "crypto/tlscredspsk.h"
238aff6f50SHyman Huang(黄勇) #include "qapi/qmp/qlist.h"
24ea6ce910SNicholas Piggin #include "ppc-util.h"
251e8a1faeSThomas Huth 
261e8a1faeSThomas Huth #include "migration-helpers.h"
27a2ce7dbdSPaolo Bonzini #include "tests/migration/migration-test.h"
2858d25e97SDaniel P. Berrangé #ifdef CONFIG_GNUTLS
2958d25e97SDaniel P. Berrangé # include "tests/unit/crypto-tls-psk-helpers.h"
30d47b83b1SDaniel P. Berrangé # ifdef CONFIG_TASN1
31d47b83b1SDaniel P. Berrangé #  include "tests/unit/crypto-tls-x509-helpers.h"
32d47b83b1SDaniel P. Berrangé # endif /* CONFIG_TASN1 */
3358d25e97SDaniel P. Berrangé #endif /* CONFIG_GNUTLS */
341e8a1faeSThomas Huth 
3561c32485SPeter Xu /* For dirty ring test; so far only x86_64 is supported */
3661c32485SPeter Xu #if defined(__linux__) && defined(HOST_X86_64)
371f546b70SPeter Xu #include "linux/kvm.h"
381f546b70SPeter Xu #endif
391f546b70SPeter Xu 
401e8a1faeSThomas Huth unsigned start_address;
411e8a1faeSThomas Huth unsigned end_address;
421e8a1faeSThomas Huth static bool uffd_feature_thread_id;
43f0649758SSteve Sistare static QTestMigrationState src_state;
44f0649758SSteve Sistare static QTestMigrationState dst_state;
451e8a1faeSThomas Huth 
468aff6f50SHyman Huang(黄勇) /*
47e02f56e3SDaniel P. Berrangé  * An initial 3 MB offset is used as that corresponds
48e02f56e3SDaniel P. Berrangé  * to ~1 sec of data transfer with our bandwidth setting.
49e02f56e3SDaniel P. Berrangé  */
50e02f56e3SDaniel P. Berrangé #define MAGIC_OFFSET_BASE (3 * 1024 * 1024)
51e02f56e3SDaniel P. Berrangé /*
52e02f56e3SDaniel P. Berrangé  * A further 1k is added to ensure we're not a multiple
53e02f56e3SDaniel P. Berrangé  * of TEST_MEM_PAGE_SIZE, thus avoid clash with writes
54e02f56e3SDaniel P. Berrangé  * from the migration guest workload.
55e02f56e3SDaniel P. Berrangé  */
56e02f56e3SDaniel P. Berrangé #define MAGIC_OFFSET_SHUFFLE 1024
57e02f56e3SDaniel P. Berrangé #define MAGIC_OFFSET (MAGIC_OFFSET_BASE + MAGIC_OFFSET_SHUFFLE)
58e02f56e3SDaniel P. Berrangé #define MAGIC_MARKER 0xFEED12345678CAFEULL
59e02f56e3SDaniel P. Berrangé 
60e02f56e3SDaniel P. Berrangé /*
618aff6f50SHyman Huang(黄勇)  * Dirtylimit stop working if dirty page rate error
628aff6f50SHyman Huang(黄勇)  * value less than DIRTYLIMIT_TOLERANCE_RANGE
638aff6f50SHyman Huang(黄勇)  */
648aff6f50SHyman Huang(黄勇) #define DIRTYLIMIT_TOLERANCE_RANGE  25  /* MB/s */
658aff6f50SHyman Huang(黄勇) 
66d864756eSFabiano Rosas #define ANALYZE_SCRIPT "scripts/analyze-migration.py"
67d864756eSFabiano Rosas 
683dc35470SFabiano Rosas #define QEMU_VM_FILE_MAGIC 0x5145564d
693dc35470SFabiano Rosas #define FILE_TEST_FILENAME "migfile"
703dc35470SFabiano Rosas #define FILE_TEST_OFFSET 0x1000
7155fc0c2fSFabiano Rosas #define FILE_TEST_MARKER 'X'
725050ad2aSFabiano Rosas #define QEMU_ENV_SRC "QTEST_QEMU_BINARY_SRC"
735050ad2aSFabiano Rosas #define QEMU_ENV_DST "QTEST_QEMU_BINARY_DST"
743dc35470SFabiano Rosas 
756cf56a87SPeter Xu typedef enum PostcopyRecoveryFailStage {
766cf56a87SPeter Xu     /*
776cf56a87SPeter Xu      * "no failure" must be 0 as it's the default.  OTOH, real failure
786cf56a87SPeter Xu      * cases must be >0 to make sure they trigger by a "if" test.
796cf56a87SPeter Xu      */
806cf56a87SPeter Xu     POSTCOPY_FAIL_NONE = 0,
816cf56a87SPeter Xu     POSTCOPY_FAIL_CHANNEL_ESTABLISH,
826cf56a87SPeter Xu     POSTCOPY_FAIL_RECOVERY,
836cf56a87SPeter Xu     POSTCOPY_FAIL_MAX
846cf56a87SPeter Xu } PostcopyRecoveryFailStage;
856cf56a87SPeter Xu 
861e8a1faeSThomas Huth #if defined(__linux__)
871e8a1faeSThomas Huth #include <sys/syscall.h>
881e8a1faeSThomas Huth #include <sys/vfs.h>
891e8a1faeSThomas Huth #endif
901e8a1faeSThomas Huth 
911e8a1faeSThomas Huth #if defined(__linux__) && defined(__NR_userfaultfd) && defined(CONFIG_EVENTFD)
921e8a1faeSThomas Huth #include <sys/eventfd.h>
931e8a1faeSThomas Huth #include <sys/ioctl.h>
94d5890ea0SPeter Xu #include "qemu/userfaultfd.h"
951e8a1faeSThomas Huth 
ufd_version_check(void)961e8a1faeSThomas Huth static bool ufd_version_check(void)
971e8a1faeSThomas Huth {
981e8a1faeSThomas Huth     struct uffdio_api api_struct;
991e8a1faeSThomas Huth     uint64_t ioctl_mask;
1001e8a1faeSThomas Huth 
101d5890ea0SPeter Xu     int ufd = uffd_open(O_CLOEXEC);
1021e8a1faeSThomas Huth 
1031e8a1faeSThomas Huth     if (ufd == -1) {
1041e8a1faeSThomas Huth         g_test_message("Skipping test: userfaultfd not available");
1051e8a1faeSThomas Huth         return false;
1061e8a1faeSThomas Huth     }
1071e8a1faeSThomas Huth 
1081e8a1faeSThomas Huth     api_struct.api = UFFD_API;
1091e8a1faeSThomas Huth     api_struct.features = 0;
1101e8a1faeSThomas Huth     if (ioctl(ufd, UFFDIO_API, &api_struct)) {
1111e8a1faeSThomas Huth         g_test_message("Skipping test: UFFDIO_API failed");
1121e8a1faeSThomas Huth         return false;
1131e8a1faeSThomas Huth     }
1141e8a1faeSThomas Huth     uffd_feature_thread_id = api_struct.features & UFFD_FEATURE_THREAD_ID;
1151e8a1faeSThomas Huth 
116*19e56616SFabiano Rosas     ioctl_mask = (1ULL << _UFFDIO_REGISTER |
117*19e56616SFabiano Rosas                   1ULL << _UFFDIO_UNREGISTER);
1181e8a1faeSThomas Huth     if ((api_struct.ioctls & ioctl_mask) != ioctl_mask) {
1191e8a1faeSThomas Huth         g_test_message("Skipping test: Missing userfault feature");
1201e8a1faeSThomas Huth         return false;
1211e8a1faeSThomas Huth     }
1221e8a1faeSThomas Huth 
1231e8a1faeSThomas Huth     return true;
1241e8a1faeSThomas Huth }
1251e8a1faeSThomas Huth 
1261e8a1faeSThomas Huth #else
ufd_version_check(void)1271e8a1faeSThomas Huth static bool ufd_version_check(void)
1281e8a1faeSThomas Huth {
1291e8a1faeSThomas Huth     g_test_message("Skipping test: Userfault not available (builtdtime)");
1301e8a1faeSThomas Huth     return false;
1311e8a1faeSThomas Huth }
1321e8a1faeSThomas Huth 
1331e8a1faeSThomas Huth #endif
1341e8a1faeSThomas Huth 
135e5553c1bSBin Meng static char *tmpfs;
136877cec63SJuan Quintela static char *bootpath;
1371e8a1faeSThomas Huth 
1381e8a1faeSThomas Huth /* The boot file modifies memory area in [start_address, end_address)
1391e8a1faeSThomas Huth  * repeatedly. It outputs a 'B' at a fixed rate while it's still running.
1401e8a1faeSThomas Huth  */
1411e8a1faeSThomas Huth #include "tests/migration/i386/a-b-bootblock.h"
1421e8a1faeSThomas Huth #include "tests/migration/aarch64/a-b-kernel.h"
14334cc54fbSNicholas Piggin #include "tests/migration/ppc64/a-b-kernel.h"
1441e8a1faeSThomas Huth #include "tests/migration/s390x/a-b-bios.h"
1451e8a1faeSThomas Huth 
bootfile_delete(void)146aee07f25SAkihiko Odaki static void bootfile_delete(void)
147aee07f25SAkihiko Odaki {
148d278455eSPeter Maydell     if (!bootpath) {
149d278455eSPeter Maydell         return;
150d278455eSPeter Maydell     }
151aee07f25SAkihiko Odaki     unlink(bootpath);
152aee07f25SAkihiko Odaki     g_free(bootpath);
153aee07f25SAkihiko Odaki     bootpath = NULL;
154aee07f25SAkihiko Odaki }
155aee07f25SAkihiko Odaki 
bootfile_create(char * dir,bool suspend_me)1565014478eSSteve Sistare static void bootfile_create(char *dir, bool suspend_me)
1571e8a1faeSThomas Huth {
1580c690d3eSJuan Quintela     const char *arch = qtest_get_arch();
1590c690d3eSJuan Quintela     unsigned char *content;
1600c690d3eSJuan Quintela     size_t len;
1610c690d3eSJuan Quintela 
162aee07f25SAkihiko Odaki     bootfile_delete();
1630c690d3eSJuan Quintela     bootpath = g_strdup_printf("%s/bootsect", dir);
1640c690d3eSJuan Quintela     if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
1650c690d3eSJuan Quintela         /* the assembled x86 boot sector should be exactly one sector large */
1660c690d3eSJuan Quintela         g_assert(sizeof(x86_bootsect) == 512);
1675014478eSSteve Sistare         x86_bootsect[SYM_suspend_me - SYM_start] = suspend_me;
1680c690d3eSJuan Quintela         content = x86_bootsect;
1690c690d3eSJuan Quintela         len = sizeof(x86_bootsect);
1700c690d3eSJuan Quintela     } else if (g_str_equal(arch, "s390x")) {
1710c690d3eSJuan Quintela         content = s390x_elf;
1720c690d3eSJuan Quintela         len = sizeof(s390x_elf);
1730c690d3eSJuan Quintela     } else if (strcmp(arch, "ppc64") == 0) {
17434cc54fbSNicholas Piggin         content = ppc64_kernel;
17534cc54fbSNicholas Piggin         len = sizeof(ppc64_kernel);
1760c690d3eSJuan Quintela     } else if (strcmp(arch, "aarch64") == 0) {
1770c690d3eSJuan Quintela         content = aarch64_kernel;
1780c690d3eSJuan Quintela         len = sizeof(aarch64_kernel);
1790c690d3eSJuan Quintela         g_assert(sizeof(aarch64_kernel) <= ARM_TEST_MAX_KERNEL_SIZE);
1800c690d3eSJuan Quintela     } else {
1810c690d3eSJuan Quintela         g_assert_not_reached();
1820c690d3eSJuan Quintela     }
1830c690d3eSJuan Quintela 
1841e8a1faeSThomas Huth     FILE *bootfile = fopen(bootpath, "wb");
1851e8a1faeSThomas Huth 
1861e8a1faeSThomas Huth     g_assert_cmpint(fwrite(content, len, 1, bootfile), ==, 1);
1871e8a1faeSThomas Huth     fclose(bootfile);
1881e8a1faeSThomas Huth }
1891e8a1faeSThomas Huth 
1901e8a1faeSThomas Huth /*
1911e8a1faeSThomas Huth  * Wait for some output in the serial output file,
1921e8a1faeSThomas Huth  * we get an 'A' followed by an endless string of 'B's
193b1fdd21eSSteve Sistare  * but on the destination we won't have the A (unless we enabled suspend/resume)
1941e8a1faeSThomas Huth  */
wait_for_serial(const char * side)1951e8a1faeSThomas Huth static void wait_for_serial(const char *side)
1961e8a1faeSThomas Huth {
197ff7b9b56SPeter Maydell     g_autofree char *serialpath = g_strdup_printf("%s/%s", tmpfs, side);
1981e8a1faeSThomas Huth     FILE *serialfile = fopen(serialpath, "r");
1991e8a1faeSThomas Huth 
2001e8a1faeSThomas Huth     do {
2011e8a1faeSThomas Huth         int readvalue = fgetc(serialfile);
2021e8a1faeSThomas Huth 
2031e8a1faeSThomas Huth         switch (readvalue) {
2041e8a1faeSThomas Huth         case 'A':
2051e8a1faeSThomas Huth             /* Fine */
2061e8a1faeSThomas Huth             break;
2071e8a1faeSThomas Huth 
2081e8a1faeSThomas Huth         case 'B':
2091e8a1faeSThomas Huth             /* It's alive! */
2101e8a1faeSThomas Huth             fclose(serialfile);
2111e8a1faeSThomas Huth             return;
2121e8a1faeSThomas Huth 
2131e8a1faeSThomas Huth         case EOF:
2141e8a1faeSThomas Huth             fseek(serialfile, 0, SEEK_SET);
2151e8a1faeSThomas Huth             usleep(1000);
2161e8a1faeSThomas Huth             break;
2171e8a1faeSThomas Huth 
2181e8a1faeSThomas Huth         default:
2191e8a1faeSThomas Huth             fprintf(stderr, "Unexpected %d on %s serial\n", readvalue, side);
2201e8a1faeSThomas Huth             g_assert_not_reached();
2211e8a1faeSThomas Huth         }
2221e8a1faeSThomas Huth     } while (true);
2231e8a1faeSThomas Huth }
2241e8a1faeSThomas Huth 
wait_for_stop(QTestState * who,QTestMigrationState * state)225f0649758SSteve Sistare static void wait_for_stop(QTestState *who, QTestMigrationState *state)
226f0649758SSteve Sistare {
227f0649758SSteve Sistare     if (!state->stop_seen) {
228f0649758SSteve Sistare         qtest_qmp_eventwait(who, "STOP");
229f0649758SSteve Sistare     }
230f0649758SSteve Sistare }
231f0649758SSteve Sistare 
wait_for_resume(QTestState * who,QTestMigrationState * state)232f0649758SSteve Sistare static void wait_for_resume(QTestState *who, QTestMigrationState *state)
233f0649758SSteve Sistare {
234f0649758SSteve Sistare     if (!state->resume_seen) {
235f0649758SSteve Sistare         qtest_qmp_eventwait(who, "RESUME");
236f0649758SSteve Sistare     }
237f0649758SSteve Sistare }
238f0649758SSteve Sistare 
wait_for_suspend(QTestState * who,QTestMigrationState * state)239b1fdd21eSSteve Sistare static void wait_for_suspend(QTestState *who, QTestMigrationState *state)
240b1fdd21eSSteve Sistare {
241b1fdd21eSSteve Sistare     if (state->suspend_me && !state->suspend_seen) {
242b1fdd21eSSteve Sistare         qtest_qmp_eventwait(who, "SUSPEND");
243b1fdd21eSSteve Sistare     }
244b1fdd21eSSteve Sistare }
245b1fdd21eSSteve Sistare 
2461e8a1faeSThomas Huth /*
2471e8a1faeSThomas Huth  * It's tricky to use qemu's migration event capability with qtest,
2481e8a1faeSThomas Huth  * events suddenly appearing confuse the qmp()/hmp() responses.
2491e8a1faeSThomas Huth  */
2501e8a1faeSThomas Huth 
read_ram_property_int(QTestState * who,const char * property)2511e8a1faeSThomas Huth static int64_t read_ram_property_int(QTestState *who, const char *property)
2521e8a1faeSThomas Huth {
2531e8a1faeSThomas Huth     QDict *rsp_return, *rsp_ram;
2541e8a1faeSThomas Huth     int64_t result;
2551e8a1faeSThomas Huth 
256fd3540adSDaniel P. Berrangé     rsp_return = migrate_query_not_failed(who);
2571e8a1faeSThomas Huth     if (!qdict_haskey(rsp_return, "ram")) {
2581e8a1faeSThomas Huth         /* Still in setup */
2591e8a1faeSThomas Huth         result = 0;
2601e8a1faeSThomas Huth     } else {
2611e8a1faeSThomas Huth         rsp_ram = qdict_get_qdict(rsp_return, "ram");
2621e8a1faeSThomas Huth         result = qdict_get_try_int(rsp_ram, property, 0);
2631e8a1faeSThomas Huth     }
2641e8a1faeSThomas Huth     qobject_unref(rsp_return);
2651e8a1faeSThomas Huth     return result;
2661e8a1faeSThomas Huth }
2671e8a1faeSThomas Huth 
read_migrate_property_int(QTestState * who,const char * property)2681e8a1faeSThomas Huth static int64_t read_migrate_property_int(QTestState *who, const char *property)
2691e8a1faeSThomas Huth {
2701e8a1faeSThomas Huth     QDict *rsp_return;
2711e8a1faeSThomas Huth     int64_t result;
2721e8a1faeSThomas Huth 
273fd3540adSDaniel P. Berrangé     rsp_return = migrate_query_not_failed(who);
2741e8a1faeSThomas Huth     result = qdict_get_try_int(rsp_return, property, 0);
2751e8a1faeSThomas Huth     qobject_unref(rsp_return);
2761e8a1faeSThomas Huth     return result;
2771e8a1faeSThomas Huth }
2781e8a1faeSThomas Huth 
get_migration_pass(QTestState * who)2791e8a1faeSThomas Huth static uint64_t get_migration_pass(QTestState *who)
2801e8a1faeSThomas Huth {
2811e8a1faeSThomas Huth     return read_ram_property_int(who, "dirty-sync-count");
2821e8a1faeSThomas Huth }
2831e8a1faeSThomas Huth 
read_blocktime(QTestState * who)2841e8a1faeSThomas Huth static void read_blocktime(QTestState *who)
2851e8a1faeSThomas Huth {
2861e8a1faeSThomas Huth     QDict *rsp_return;
2871e8a1faeSThomas Huth 
288fd3540adSDaniel P. Berrangé     rsp_return = migrate_query_not_failed(who);
2891e8a1faeSThomas Huth     g_assert(qdict_haskey(rsp_return, "postcopy-blocktime"));
2901e8a1faeSThomas Huth     qobject_unref(rsp_return);
2911e8a1faeSThomas Huth }
2921e8a1faeSThomas Huth 
293f0649758SSteve Sistare /*
294f0649758SSteve Sistare  * Wait for two changes in the migration pass count, but bail if we stop.
295f0649758SSteve Sistare  */
wait_for_migration_pass(QTestState * who)2961e8a1faeSThomas Huth static void wait_for_migration_pass(QTestState *who)
2971e8a1faeSThomas Huth {
298f0649758SSteve Sistare     uint64_t pass, prev_pass = 0, changes = 0;
2991e8a1faeSThomas Huth 
300b1fdd21eSSteve Sistare     while (changes < 2 && !src_state.stop_seen && !src_state.suspend_seen) {
3011e8a1faeSThomas Huth         usleep(1000);
3021e8a1faeSThomas Huth         pass = get_migration_pass(who);
303f0649758SSteve Sistare         changes += (pass != prev_pass);
304f0649758SSteve Sistare         prev_pass = pass;
305f0649758SSteve Sistare     }
3061e8a1faeSThomas Huth }
3071e8a1faeSThomas Huth 
check_guests_ram(QTestState * who)3081e8a1faeSThomas Huth static void check_guests_ram(QTestState *who)
3091e8a1faeSThomas Huth {
3101e8a1faeSThomas Huth     /* Our ASM test will have been incrementing one byte from each page from
3111e8a1faeSThomas Huth      * start_address to < end_address in order. This gives us a constraint
3121e8a1faeSThomas Huth      * that any page's byte should be equal or less than the previous pages
3131e8a1faeSThomas Huth      * byte (mod 256); and they should all be equal except for one transition
3141e8a1faeSThomas Huth      * at the point where we meet the incrementer. (We're running this with
3151e8a1faeSThomas Huth      * the guest stopped).
3161e8a1faeSThomas Huth      */
3171e8a1faeSThomas Huth     unsigned address;
3181e8a1faeSThomas Huth     uint8_t first_byte;
3191e8a1faeSThomas Huth     uint8_t last_byte;
3201e8a1faeSThomas Huth     bool hit_edge = false;
3211e8a1faeSThomas Huth     int bad = 0;
3221e8a1faeSThomas Huth 
3231e8a1faeSThomas Huth     qtest_memread(who, start_address, &first_byte, 1);
3241e8a1faeSThomas Huth     last_byte = first_byte;
3251e8a1faeSThomas Huth 
3261e8a1faeSThomas Huth     for (address = start_address + TEST_MEM_PAGE_SIZE; address < end_address;
3271e8a1faeSThomas Huth          address += TEST_MEM_PAGE_SIZE)
3281e8a1faeSThomas Huth     {
3291e8a1faeSThomas Huth         uint8_t b;
3301e8a1faeSThomas Huth         qtest_memread(who, address, &b, 1);
3311e8a1faeSThomas Huth         if (b != last_byte) {
3321e8a1faeSThomas Huth             if (((b + 1) % 256) == last_byte && !hit_edge) {
3331e8a1faeSThomas Huth                 /* This is OK, the guest stopped at the point of
3341e8a1faeSThomas Huth                  * incrementing the previous page but didn't get
3351e8a1faeSThomas Huth                  * to us yet.
3361e8a1faeSThomas Huth                  */
3371e8a1faeSThomas Huth                 hit_edge = true;
3381e8a1faeSThomas Huth                 last_byte = b;
3391e8a1faeSThomas Huth             } else {
3401e8a1faeSThomas Huth                 bad++;
3411e8a1faeSThomas Huth                 if (bad <= 10) {
3421e8a1faeSThomas Huth                     fprintf(stderr, "Memory content inconsistency at %x"
3431e8a1faeSThomas Huth                             " first_byte = %x last_byte = %x current = %x"
3441e8a1faeSThomas Huth                             " hit_edge = %x\n",
3451e8a1faeSThomas Huth                             address, first_byte, last_byte, b, hit_edge);
3461e8a1faeSThomas Huth                 }
3471e8a1faeSThomas Huth             }
3481e8a1faeSThomas Huth         }
3491e8a1faeSThomas Huth     }
3501e8a1faeSThomas Huth     if (bad >= 10) {
3511e8a1faeSThomas Huth         fprintf(stderr, "and in another %d pages", bad - 10);
3521e8a1faeSThomas Huth     }
3531e8a1faeSThomas Huth     g_assert(bad == 0);
3541e8a1faeSThomas Huth }
3551e8a1faeSThomas Huth 
cleanup(const char * filename)3561e8a1faeSThomas Huth static void cleanup(const char *filename)
3571e8a1faeSThomas Huth {
358ff7b9b56SPeter Maydell     g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, filename);
3591e8a1faeSThomas Huth 
3601e8a1faeSThomas Huth     unlink(path);
3611e8a1faeSThomas Huth }
3621e8a1faeSThomas Huth 
migrate_get_parameter_int(QTestState * who,const char * parameter)3631e8a1faeSThomas Huth static long long migrate_get_parameter_int(QTestState *who,
3641e8a1faeSThomas Huth                                            const char *parameter)
3651e8a1faeSThomas Huth {
3661e8a1faeSThomas Huth     QDict *rsp;
3671e8a1faeSThomas Huth     long long result;
3681e8a1faeSThomas Huth 
369aca04069SDaniel P. Berrangé     rsp = qtest_qmp_assert_success_ref(
370aca04069SDaniel P. Berrangé         who, "{ 'execute': 'query-migrate-parameters' }");
3711e8a1faeSThomas Huth     result = qdict_get_int(rsp, parameter);
3721e8a1faeSThomas Huth     qobject_unref(rsp);
3731e8a1faeSThomas Huth     return result;
3741e8a1faeSThomas Huth }
3751e8a1faeSThomas Huth 
migrate_check_parameter_int(QTestState * who,const char * parameter,long long value)3761e8a1faeSThomas Huth static void migrate_check_parameter_int(QTestState *who, const char *parameter,
3771e8a1faeSThomas Huth                                         long long value)
3781e8a1faeSThomas Huth {
3791e8a1faeSThomas Huth     long long result;
3801e8a1faeSThomas Huth 
3811e8a1faeSThomas Huth     result = migrate_get_parameter_int(who, parameter);
3821e8a1faeSThomas Huth     g_assert_cmpint(result, ==, value);
3831e8a1faeSThomas Huth }
3841e8a1faeSThomas Huth 
migrate_set_parameter_int(QTestState * who,const char * parameter,long long value)3851e8a1faeSThomas Huth static void migrate_set_parameter_int(QTestState *who, const char *parameter,
3861e8a1faeSThomas Huth                                       long long value)
3871e8a1faeSThomas Huth {
38811936f0eSDaniel P. Berrangé     qtest_qmp_assert_success(who,
3891e8a1faeSThomas Huth                              "{ 'execute': 'migrate-set-parameters',"
3901e8a1faeSThomas Huth                              "'arguments': { %s: %lld } }",
3911e8a1faeSThomas Huth                              parameter, value);
3921e8a1faeSThomas Huth     migrate_check_parameter_int(who, parameter, value);
3931e8a1faeSThomas Huth }
3941e8a1faeSThomas Huth 
migrate_get_parameter_str(QTestState * who,const char * parameter)3956a22c544SJuan Quintela static char *migrate_get_parameter_str(QTestState *who,
3966a22c544SJuan Quintela                                        const char *parameter)
3976a22c544SJuan Quintela {
3986a22c544SJuan Quintela     QDict *rsp;
3996a22c544SJuan Quintela     char *result;
4006a22c544SJuan Quintela 
401aca04069SDaniel P. Berrangé     rsp = qtest_qmp_assert_success_ref(
402aca04069SDaniel P. Berrangé         who, "{ 'execute': 'query-migrate-parameters' }");
4036a22c544SJuan Quintela     result = g_strdup(qdict_get_str(rsp, parameter));
4046a22c544SJuan Quintela     qobject_unref(rsp);
4056a22c544SJuan Quintela     return result;
4066a22c544SJuan Quintela }
4076a22c544SJuan Quintela 
migrate_check_parameter_str(QTestState * who,const char * parameter,const char * value)4086a22c544SJuan Quintela static void migrate_check_parameter_str(QTestState *who, const char *parameter,
4096a22c544SJuan Quintela                                         const char *value)
4106a22c544SJuan Quintela {
411ff7b9b56SPeter Maydell     g_autofree char *result = migrate_get_parameter_str(who, parameter);
4126a22c544SJuan Quintela     g_assert_cmpstr(result, ==, value);
4136a22c544SJuan Quintela }
4146a22c544SJuan Quintela 
migrate_set_parameter_str(QTestState * who,const char * parameter,const char * value)4156a22c544SJuan Quintela static void migrate_set_parameter_str(QTestState *who, const char *parameter,
4166a22c544SJuan Quintela                                       const char *value)
4176a22c544SJuan Quintela {
41811936f0eSDaniel P. Berrangé     qtest_qmp_assert_success(who,
4196a22c544SJuan Quintela                              "{ 'execute': 'migrate-set-parameters',"
4206a22c544SJuan Quintela                              "'arguments': { %s: %s } }",
4216a22c544SJuan Quintela                              parameter, value);
4226a22c544SJuan Quintela     migrate_check_parameter_str(who, parameter, value);
4236a22c544SJuan Quintela }
4246a22c544SJuan Quintela 
migrate_get_parameter_bool(QTestState * who,const char * parameter)425408d295dSFabiano Rosas static long long migrate_get_parameter_bool(QTestState *who,
426408d295dSFabiano Rosas                                             const char *parameter)
427408d295dSFabiano Rosas {
428408d295dSFabiano Rosas     QDict *rsp;
429408d295dSFabiano Rosas     int result;
430408d295dSFabiano Rosas 
431408d295dSFabiano Rosas     rsp = qtest_qmp_assert_success_ref(
432408d295dSFabiano Rosas         who, "{ 'execute': 'query-migrate-parameters' }");
433408d295dSFabiano Rosas     result = qdict_get_bool(rsp, parameter);
434408d295dSFabiano Rosas     qobject_unref(rsp);
435408d295dSFabiano Rosas     return !!result;
436408d295dSFabiano Rosas }
437408d295dSFabiano Rosas 
migrate_check_parameter_bool(QTestState * who,const char * parameter,int value)438408d295dSFabiano Rosas static void migrate_check_parameter_bool(QTestState *who, const char *parameter,
439408d295dSFabiano Rosas                                          int value)
440408d295dSFabiano Rosas {
441408d295dSFabiano Rosas     int result;
442408d295dSFabiano Rosas 
443408d295dSFabiano Rosas     result = migrate_get_parameter_bool(who, parameter);
444408d295dSFabiano Rosas     g_assert_cmpint(result, ==, value);
445408d295dSFabiano Rosas }
446408d295dSFabiano Rosas 
migrate_set_parameter_bool(QTestState * who,const char * parameter,int value)447408d295dSFabiano Rosas static void migrate_set_parameter_bool(QTestState *who, const char *parameter,
448408d295dSFabiano Rosas                                        int value)
449408d295dSFabiano Rosas {
450408d295dSFabiano Rosas     qtest_qmp_assert_success(who,
451408d295dSFabiano Rosas                              "{ 'execute': 'migrate-set-parameters',"
452408d295dSFabiano Rosas                              "'arguments': { %s: %i } }",
453408d295dSFabiano Rosas                              parameter, value);
454408d295dSFabiano Rosas     migrate_check_parameter_bool(who, parameter, value);
455408d295dSFabiano Rosas }
456408d295dSFabiano Rosas 
migrate_ensure_non_converge(QTestState * who)457886dfe9dSDaniel P. Berrangé static void migrate_ensure_non_converge(QTestState *who)
458886dfe9dSDaniel P. Berrangé {
4591bfc8ddeSDr. David Alan Gilbert     /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */
4601bfc8ddeSDr. David Alan Gilbert     migrate_set_parameter_int(who, "max-bandwidth", 3 * 1000 * 1000);
461886dfe9dSDaniel P. Berrangé     migrate_set_parameter_int(who, "downtime-limit", 1);
462886dfe9dSDaniel P. Berrangé }
463886dfe9dSDaniel P. Berrangé 
migrate_ensure_converge(QTestState * who)464886dfe9dSDaniel P. Berrangé static void migrate_ensure_converge(QTestState *who)
465886dfe9dSDaniel P. Berrangé {
466886dfe9dSDaniel P. Berrangé     /* Should converge with 30s downtime + 1 gbs bandwidth limit */
467886dfe9dSDaniel P. Berrangé     migrate_set_parameter_int(who, "max-bandwidth", 1 * 1000 * 1000 * 1000);
468886dfe9dSDaniel P. Berrangé     migrate_set_parameter_int(who, "downtime-limit", 30 * 1000);
469886dfe9dSDaniel P. Berrangé }
470886dfe9dSDaniel P. Berrangé 
471e02f56e3SDaniel P. Berrangé /*
472e02f56e3SDaniel P. Berrangé  * Our goal is to ensure that we run a single full migration
473e02f56e3SDaniel P. Berrangé  * iteration, and also dirty memory, ensuring that at least
474e02f56e3SDaniel P. Berrangé  * one further iteration is required.
475e02f56e3SDaniel P. Berrangé  *
476e02f56e3SDaniel P. Berrangé  * We can't directly synchronize with the start of a migration
477e02f56e3SDaniel P. Berrangé  * so we have to apply some tricks monitoring memory that is
478e02f56e3SDaniel P. Berrangé  * transferred.
479e02f56e3SDaniel P. Berrangé  *
480e02f56e3SDaniel P. Berrangé  * Initially we set the migration bandwidth to an insanely
481e02f56e3SDaniel P. Berrangé  * low value, with tiny max downtime too. This basically
482e02f56e3SDaniel P. Berrangé  * guarantees migration will never complete.
483e02f56e3SDaniel P. Berrangé  *
484e02f56e3SDaniel P. Berrangé  * This will result in a test that is unacceptably slow though,
485e02f56e3SDaniel P. Berrangé  * so we can't let the entire migration pass run at this speed.
486e02f56e3SDaniel P. Berrangé  * Our intent is to let it run just long enough that we can
487e02f56e3SDaniel P. Berrangé  * prove data prior to the marker has been transferred *AND*
488e02f56e3SDaniel P. Berrangé  * also prove this transferred data is dirty again.
489e02f56e3SDaniel P. Berrangé  *
490e02f56e3SDaniel P. Berrangé  * Before migration starts, we write a 64-bit magic marker
491e02f56e3SDaniel P. Berrangé  * into a fixed location in the src VM RAM.
492e02f56e3SDaniel P. Berrangé  *
493e02f56e3SDaniel P. Berrangé  * Then watch dst memory until the marker appears. This is
494e02f56e3SDaniel P. Berrangé  * proof that start_address -> MAGIC_OFFSET_BASE has been
495e02f56e3SDaniel P. Berrangé  * transferred.
496e02f56e3SDaniel P. Berrangé  *
497e02f56e3SDaniel P. Berrangé  * Finally we go back to the source and read a byte just
49896420a30SMichael Tokarev  * before the marker until we see it flip in value. This
499e02f56e3SDaniel P. Berrangé  * is proof that start_address -> MAGIC_OFFSET_BASE
500e02f56e3SDaniel P. Berrangé  * is now dirty again.
501e02f56e3SDaniel P. Berrangé  *
502e02f56e3SDaniel P. Berrangé  * IOW, we're guaranteed at least a 2nd migration pass
503e02f56e3SDaniel P. Berrangé  * at this point.
504e02f56e3SDaniel P. Berrangé  *
505e02f56e3SDaniel P. Berrangé  * We can now let migration run at full speed to finish
506e02f56e3SDaniel P. Berrangé  * the test
507e02f56e3SDaniel P. Berrangé  */
migrate_prepare_for_dirty_mem(QTestState * from)508e02f56e3SDaniel P. Berrangé static void migrate_prepare_for_dirty_mem(QTestState *from)
509e02f56e3SDaniel P. Berrangé {
510e02f56e3SDaniel P. Berrangé     /*
511e02f56e3SDaniel P. Berrangé      * The guest workflow iterates from start_address to
512e02f56e3SDaniel P. Berrangé      * end_address, writing 1 byte every TEST_MEM_PAGE_SIZE
513e02f56e3SDaniel P. Berrangé      * bytes.
514e02f56e3SDaniel P. Berrangé      *
515e02f56e3SDaniel P. Berrangé      * IOW, if we write to mem at a point which is NOT
516e02f56e3SDaniel P. Berrangé      * a multiple of TEST_MEM_PAGE_SIZE, our write won't
517e02f56e3SDaniel P. Berrangé      * conflict with the migration workflow.
518e02f56e3SDaniel P. Berrangé      *
519e02f56e3SDaniel P. Berrangé      * We put in a marker here, that we'll use to determine
520e02f56e3SDaniel P. Berrangé      * when the data has been transferred to the dst.
521e02f56e3SDaniel P. Berrangé      */
522e02f56e3SDaniel P. Berrangé     qtest_writeq(from, start_address + MAGIC_OFFSET, MAGIC_MARKER);
523e02f56e3SDaniel P. Berrangé }
524e02f56e3SDaniel P. Berrangé 
migrate_wait_for_dirty_mem(QTestState * from,QTestState * to)525e02f56e3SDaniel P. Berrangé static void migrate_wait_for_dirty_mem(QTestState *from,
526e02f56e3SDaniel P. Berrangé                                        QTestState *to)
527e02f56e3SDaniel P. Berrangé {
528e02f56e3SDaniel P. Berrangé     uint64_t watch_address = start_address + MAGIC_OFFSET_BASE;
529e02f56e3SDaniel P. Berrangé     uint64_t marker_address = start_address + MAGIC_OFFSET;
530e02f56e3SDaniel P. Berrangé     uint8_t watch_byte;
531e02f56e3SDaniel P. Berrangé 
532e02f56e3SDaniel P. Berrangé     /*
533e02f56e3SDaniel P. Berrangé      * Wait for the MAGIC_MARKER to get transferred, as an
534e02f56e3SDaniel P. Berrangé      * indicator that a migration pass has made some known
535e02f56e3SDaniel P. Berrangé      * amount of progress.
536e02f56e3SDaniel P. Berrangé      */
537e02f56e3SDaniel P. Berrangé     do {
538e02f56e3SDaniel P. Berrangé         usleep(1000 * 10);
539e02f56e3SDaniel P. Berrangé     } while (qtest_readq(to, marker_address) != MAGIC_MARKER);
540e02f56e3SDaniel P. Berrangé 
541b1fdd21eSSteve Sistare 
542b1fdd21eSSteve Sistare     /* If suspended, src only iterates once, and watch_byte may never change */
543b1fdd21eSSteve Sistare     if (src_state.suspend_me) {
544b1fdd21eSSteve Sistare         return;
545b1fdd21eSSteve Sistare     }
546b1fdd21eSSteve Sistare 
547e02f56e3SDaniel P. Berrangé     /*
548e02f56e3SDaniel P. Berrangé      * Now ensure that already transferred bytes are
549e02f56e3SDaniel P. Berrangé      * dirty again from the guest workload. Note the
550e02f56e3SDaniel P. Berrangé      * guest byte value will wrap around and by chance
551e02f56e3SDaniel P. Berrangé      * match the original watch_byte. This is harmless
552e02f56e3SDaniel P. Berrangé      * as we'll eventually see a different value if we
553e02f56e3SDaniel P. Berrangé      * keep watching
554e02f56e3SDaniel P. Berrangé      */
555e02f56e3SDaniel P. Berrangé     watch_byte = qtest_readb(from, watch_address);
556e02f56e3SDaniel P. Berrangé     do {
557e02f56e3SDaniel P. Berrangé         usleep(1000 * 10);
558e02f56e3SDaniel P. Berrangé     } while (qtest_readb(from, watch_address) == watch_byte);
559e02f56e3SDaniel P. Berrangé }
560e02f56e3SDaniel P. Berrangé 
561e02f56e3SDaniel P. Berrangé 
migrate_pause(QTestState * who)5621e8a1faeSThomas Huth static void migrate_pause(QTestState *who)
5631e8a1faeSThomas Huth {
564aca04069SDaniel P. Berrangé     qtest_qmp_assert_success(who, "{ 'execute': 'migrate-pause' }");
5651e8a1faeSThomas Huth }
5661e8a1faeSThomas Huth 
migrate_continue(QTestState * who,const char * state)5671e8a1faeSThomas Huth static void migrate_continue(QTestState *who, const char *state)
5681e8a1faeSThomas Huth {
569aca04069SDaniel P. Berrangé     qtest_qmp_assert_success(who,
5701e8a1faeSThomas Huth                              "{ 'execute': 'migrate-continue',"
5711e8a1faeSThomas Huth                              "  'arguments': { 'state': %s } }",
5721e8a1faeSThomas Huth                              state);
5731e8a1faeSThomas Huth }
5741e8a1faeSThomas Huth 
migrate_recover(QTestState * who,const char * uri)5751e8a1faeSThomas Huth static void migrate_recover(QTestState *who, const char *uri)
5761e8a1faeSThomas Huth {
577aca04069SDaniel P. Berrangé     qtest_qmp_assert_success(who,
5781e8a1faeSThomas Huth                              "{ 'execute': 'migrate-recover', "
5791e8a1faeSThomas Huth                              "  'id': 'recover-cmd', "
5801e8a1faeSThomas Huth                              "  'arguments': { 'uri': %s } }",
5811e8a1faeSThomas Huth                              uri);
5821e8a1faeSThomas Huth }
5831e8a1faeSThomas Huth 
migrate_cancel(QTestState * who)584d795f474SJuan Quintela static void migrate_cancel(QTestState *who)
585d795f474SJuan Quintela {
586aca04069SDaniel P. Berrangé     qtest_qmp_assert_success(who, "{ 'execute': 'migrate_cancel' }");
587d795f474SJuan Quintela }
588d795f474SJuan Quintela 
migrate_postcopy_start(QTestState * from,QTestState * to)5891e8a1faeSThomas Huth static void migrate_postcopy_start(QTestState *from, QTestState *to)
5901e8a1faeSThomas Huth {
591aca04069SDaniel P. Berrangé     qtest_qmp_assert_success(from, "{ 'execute': 'migrate-start-postcopy' }");
5921e8a1faeSThomas Huth 
593f0649758SSteve Sistare     wait_for_stop(from, &src_state);
5941e8a1faeSThomas Huth     qtest_qmp_eventwait(to, "RESUME");
5951e8a1faeSThomas Huth }
5961e8a1faeSThomas Huth 
5971e8a1faeSThomas Huth typedef struct {
598a4729501SPeter Xu     /*
599a4729501SPeter Xu      * QTEST_LOG=1 may override this.  When QTEST_LOG=1, we always dump errors
600a4729501SPeter Xu      * unconditionally, because it means the user would like to be verbose.
601a4729501SPeter Xu      */
6021e8a1faeSThomas Huth     bool hide_stderr;
6031e8a1faeSThomas Huth     bool use_shmem;
604d795f474SJuan Quintela     /* only launch the target process */
605d795f474SJuan Quintela     bool only_target;
6061f546b70SPeter Xu     /* Use dirty ring if true; dirty logging otherwise */
6071f546b70SPeter Xu     bool use_dirty_ring;
60819da6edfSDaniel P. Berrangé     const char *opts_source;
60919da6edfSDaniel P. Berrangé     const char *opts_target;
6105014478eSSteve Sistare     /* suspend the src before migrating to dest. */
6115014478eSSteve Sistare     bool suspend_me;
6121e8a1faeSThomas Huth } MigrateStart;
6131e8a1faeSThomas Huth 
614312e9dd0SPeter Xu /*
615312e9dd0SPeter Xu  * A hook that runs after the src and dst QEMUs have been
616312e9dd0SPeter Xu  * created, but before the migration is started. This can
617312e9dd0SPeter Xu  * be used to set migration parameters and capabilities.
618312e9dd0SPeter Xu  *
619312e9dd0SPeter Xu  * Returns: NULL, or a pointer to opaque state to be
620312e9dd0SPeter Xu  *          later passed to the TestMigrateFinishHook
621312e9dd0SPeter Xu  */
622312e9dd0SPeter Xu typedef void * (*TestMigrateStartHook)(QTestState *from,
623312e9dd0SPeter Xu                                        QTestState *to);
624312e9dd0SPeter Xu 
625312e9dd0SPeter Xu /*
626312e9dd0SPeter Xu  * A hook that runs after the migration has finished,
627312e9dd0SPeter Xu  * regardless of whether it succeeded or failed, but
628312e9dd0SPeter Xu  * before QEMU has terminated (unless it self-terminated
629312e9dd0SPeter Xu  * due to migration error)
630312e9dd0SPeter Xu  *
631312e9dd0SPeter Xu  * @opaque is a pointer to state previously returned
632312e9dd0SPeter Xu  * by the TestMigrateStartHook if any, or NULL.
633312e9dd0SPeter Xu  */
634312e9dd0SPeter Xu typedef void (*TestMigrateFinishHook)(QTestState *from,
635312e9dd0SPeter Xu                                       QTestState *to,
636312e9dd0SPeter Xu                                       void *opaque);
637312e9dd0SPeter Xu 
638312e9dd0SPeter Xu typedef struct {
639312e9dd0SPeter Xu     /* Optional: fine tune start parameters */
640312e9dd0SPeter Xu     MigrateStart start;
641312e9dd0SPeter Xu 
642312e9dd0SPeter Xu     /* Required: the URI for the dst QEMU to listen on */
643312e9dd0SPeter Xu     const char *listen_uri;
644312e9dd0SPeter Xu 
645312e9dd0SPeter Xu     /*
646312e9dd0SPeter Xu      * Optional: the URI for the src QEMU to connect to
647312e9dd0SPeter Xu      * If NULL, then it will query the dst QEMU for its actual
648312e9dd0SPeter Xu      * listening address and use that as the connect address.
649312e9dd0SPeter Xu      * This allows for dynamically picking a free TCP port.
650312e9dd0SPeter Xu      */
651312e9dd0SPeter Xu     const char *connect_uri;
652312e9dd0SPeter Xu 
6539d36d62cSHet Gala     /*
6549d36d62cSHet Gala      * Optional: JSON-formatted list of src QEMU URIs. If a port is
6559d36d62cSHet Gala      * defined as '0' in any QDict key a value of '0' will be
6569d36d62cSHet Gala      * automatically converted to the correct destination port.
6579d36d62cSHet Gala      */
6589d36d62cSHet Gala     const char *connect_channels;
6599d36d62cSHet Gala 
660312e9dd0SPeter Xu     /* Optional: callback to run at start to set migration parameters */
661312e9dd0SPeter Xu     TestMigrateStartHook start_hook;
662312e9dd0SPeter Xu     /* Optional: callback to run at finish to cleanup */
663312e9dd0SPeter Xu     TestMigrateFinishHook finish_hook;
664312e9dd0SPeter Xu 
665312e9dd0SPeter Xu     /*
666312e9dd0SPeter Xu      * Optional: normally we expect the migration process to complete.
667312e9dd0SPeter Xu      *
668312e9dd0SPeter Xu      * There can be a variety of reasons and stages in which failure
669312e9dd0SPeter Xu      * can happen during tests.
670312e9dd0SPeter Xu      *
671312e9dd0SPeter Xu      * If a failure is expected to happen at time of establishing
672312e9dd0SPeter Xu      * the connection, then MIG_TEST_FAIL will indicate that the dst
673312e9dd0SPeter Xu      * QEMU is expected to stay running and accept future migration
674312e9dd0SPeter Xu      * connections.
675312e9dd0SPeter Xu      *
676312e9dd0SPeter Xu      * If a failure is expected to happen while processing the
677312e9dd0SPeter Xu      * migration stream, then MIG_TEST_FAIL_DEST_QUIT_ERR will indicate
678312e9dd0SPeter Xu      * that the dst QEMU is expected to quit with non-zero exit status
679312e9dd0SPeter Xu      */
680312e9dd0SPeter Xu     enum {
681312e9dd0SPeter Xu         /* This test should succeed, the default */
682312e9dd0SPeter Xu         MIG_TEST_SUCCEED = 0,
683312e9dd0SPeter Xu         /* This test should fail, dest qemu should keep alive */
684312e9dd0SPeter Xu         MIG_TEST_FAIL,
685312e9dd0SPeter Xu         /* This test should fail, dest qemu should fail with abnormal status */
686312e9dd0SPeter Xu         MIG_TEST_FAIL_DEST_QUIT_ERR,
6875274274cSFabiano Rosas         /* The QMP command for this migration should fail with an error */
6885274274cSFabiano Rosas         MIG_TEST_QMP_ERROR,
689312e9dd0SPeter Xu     } result;
690312e9dd0SPeter Xu 
691e02f56e3SDaniel P. Berrangé     /*
692e02f56e3SDaniel P. Berrangé      * Optional: set number of migration passes to wait for, if live==true.
693e02f56e3SDaniel P. Berrangé      * If zero, then merely wait for a few MB of dirty data
694e02f56e3SDaniel P. Berrangé      */
695312e9dd0SPeter Xu     unsigned int iterations;
696d1a27b16SPeter Xu 
697b861383cSPeter Xu     /*
698b861383cSPeter Xu      * Optional: whether the guest CPUs should be running during a precopy
699b861383cSPeter Xu      * migration test.  We used to always run with live but it took much
700b861383cSPeter Xu      * longer so we reduced live tests to only the ones that have solid
701b861383cSPeter Xu      * reason to be tested live-only.  For each of the new test cases for
702b861383cSPeter Xu      * precopy please provide justifications to use live explicitly (please
703b861383cSPeter Xu      * refer to existing ones with live=true), or use live=off by default.
704b861383cSPeter Xu      */
7053c4fb177SDaniel P. Berrangé     bool live;
7063c4fb177SDaniel P. Berrangé 
707d1a27b16SPeter Xu     /* Postcopy specific fields */
708d1a27b16SPeter Xu     void *postcopy_data;
7098f6fe915SPeter Xu     bool postcopy_preempt;
7106cf56a87SPeter Xu     PostcopyRecoveryFailStage postcopy_recovery_fail_stage;
711312e9dd0SPeter Xu } MigrateCommon;
712312e9dd0SPeter Xu 
test_migrate_start(QTestState ** from,QTestState ** to,const char * uri,MigrateStart * args)7131e8a1faeSThomas Huth static int test_migrate_start(QTestState **from, QTestState **to,
71419da6edfSDaniel P. Berrangé                               const char *uri, MigrateStart *args)
7151e8a1faeSThomas Huth {
716ff7b9b56SPeter Maydell     g_autofree gchar *arch_source = NULL;
717ff7b9b56SPeter Maydell     g_autofree gchar *arch_target = NULL;
718832c732cSJuan Quintela     /* options for source and target */
719832c732cSJuan Quintela     g_autofree gchar *arch_opts = NULL;
720ff7b9b56SPeter Maydell     g_autofree gchar *cmd_source = NULL;
721ff7b9b56SPeter Maydell     g_autofree gchar *cmd_target = NULL;
7221e8a1faeSThomas Huth     const gchar *ignore_stderr;
723ff7b9b56SPeter Maydell     g_autofree char *shmem_opts = NULL;
724ff7b9b56SPeter Maydell     g_autofree char *shmem_path = NULL;
72571d36124SJuan Quintela     const char *kvm_opts = NULL;
7261e8a1faeSThomas Huth     const char *arch = qtest_get_arch();
7271e8a1faeSThomas Huth     const char *memory_size;
728c9961391SFabiano Rosas     const char *machine_alias, *machine_opts = "";
7295050ad2aSFabiano Rosas     g_autofree char *machine = NULL;
7301e8a1faeSThomas Huth 
7311e8a1faeSThomas Huth     if (args->use_shmem) {
7321e8a1faeSThomas Huth         if (!g_file_test("/dev/shm", G_FILE_TEST_IS_DIR)) {
7331e8a1faeSThomas Huth             g_test_skip("/dev/shm is not supported");
73419da6edfSDaniel P. Berrangé             return -1;
7351e8a1faeSThomas Huth         }
7361e8a1faeSThomas Huth     }
7371e8a1faeSThomas Huth 
738f0649758SSteve Sistare     dst_state = (QTestMigrationState) { };
739f0649758SSteve Sistare     src_state = (QTestMigrationState) { };
7405014478eSSteve Sistare     bootfile_create(tmpfs, args->suspend_me);
741b1fdd21eSSteve Sistare     src_state.suspend_me = args->suspend_me;
7425014478eSSteve Sistare 
7431e8a1faeSThomas Huth     if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
7441e8a1faeSThomas Huth         memory_size = "150M";
745fa35b0cbSFabiano Rosas 
746fa35b0cbSFabiano Rosas         if (g_str_equal(arch, "i386")) {
747c9961391SFabiano Rosas             machine_alias = "pc";
748fa35b0cbSFabiano Rosas         } else {
749fa35b0cbSFabiano Rosas             machine_alias = "q35";
750fa35b0cbSFabiano Rosas         }
7513cb9c655SFabiano Rosas         arch_opts = g_strdup_printf(
7523cb9c655SFabiano Rosas             "-drive if=none,id=d0,file=%s,format=raw "
7533cb9c655SFabiano Rosas             "-device ide-hd,drive=d0,secs=1,cyls=1,heads=1", bootpath);
7541e8a1faeSThomas Huth         start_address = X86_TEST_MEM_START;
7551e8a1faeSThomas Huth         end_address = X86_TEST_MEM_END;
7561e8a1faeSThomas Huth     } else if (g_str_equal(arch, "s390x")) {
7571e8a1faeSThomas Huth         memory_size = "128M";
758c9961391SFabiano Rosas         machine_alias = "s390-ccw-virtio";
759832c732cSJuan Quintela         arch_opts = g_strdup_printf("-bios %s", bootpath);
7601e8a1faeSThomas Huth         start_address = S390_TEST_MEM_START;
7611e8a1faeSThomas Huth         end_address = S390_TEST_MEM_END;
7621e8a1faeSThomas Huth     } else if (strcmp(arch, "ppc64") == 0) {
7631e8a1faeSThomas Huth         memory_size = "256M";
76416c5c692SLaurent Vivier         start_address = PPC_TEST_MEM_START;
76516c5c692SLaurent Vivier         end_address = PPC_TEST_MEM_END;
766c9961391SFabiano Rosas         machine_alias = "pseries";
767c9961391SFabiano Rosas         machine_opts = "vsmt=8";
76834cc54fbSNicholas Piggin         arch_opts = g_strdup_printf(
76934cc54fbSNicholas Piggin             "-nodefaults -machine " PSERIES_DEFAULT_CAPABILITIES " "
77034cc54fbSNicholas Piggin             "-bios %s", bootpath);
7711e8a1faeSThomas Huth     } else if (strcmp(arch, "aarch64") == 0) {
7721e8a1faeSThomas Huth         memory_size = "150M";
773c9961391SFabiano Rosas         machine_alias = "virt";
774bdb0ade6SPeter Xu         machine_opts = "gic-version=3";
775c9961391SFabiano Rosas         arch_opts = g_strdup_printf("-cpu max -kernel %s", bootpath);
7761e8a1faeSThomas Huth         start_address = ARM_TEST_MEM_START;
7771e8a1faeSThomas Huth         end_address = ARM_TEST_MEM_END;
7781e8a1faeSThomas Huth     } else {
7791e8a1faeSThomas Huth         g_assert_not_reached();
7801e8a1faeSThomas Huth     }
7811e8a1faeSThomas Huth 
782a4729501SPeter Xu     if (!getenv("QTEST_LOG") && args->hide_stderr) {
7834dc8be38SBin Meng #ifndef _WIN32
7841e8a1faeSThomas Huth         ignore_stderr = "2>/dev/null";
7854dc8be38SBin Meng #else
7864dc8be38SBin Meng         /*
7874dc8be38SBin Meng          * On Windows the QEMU executable is created via CreateProcess() and
7884dc8be38SBin Meng          * IO redirection does not work, so don't bother adding IO redirection
7894dc8be38SBin Meng          * to the command line.
7904dc8be38SBin Meng          */
7914dc8be38SBin Meng         ignore_stderr = "";
7924dc8be38SBin Meng #endif
7931e8a1faeSThomas Huth     } else {
7941e8a1faeSThomas Huth         ignore_stderr = "";
7951e8a1faeSThomas Huth     }
7961e8a1faeSThomas Huth 
7971e8a1faeSThomas Huth     if (args->use_shmem) {
7981e8a1faeSThomas Huth         shmem_path = g_strdup_printf("/dev/shm/qemu-%d", getpid());
7991e8a1faeSThomas Huth         shmem_opts = g_strdup_printf(
8001e8a1faeSThomas Huth             "-object memory-backend-file,id=mem0,size=%s"
8011e8a1faeSThomas Huth             ",mem-path=%s,share=on -numa node,memdev=mem0",
8021e8a1faeSThomas Huth             memory_size, shmem_path);
8031e8a1faeSThomas Huth     }
8041e8a1faeSThomas Huth 
80571d36124SJuan Quintela     if (args->use_dirty_ring) {
80671d36124SJuan Quintela         kvm_opts = ",dirty-ring-size=4096";
80771d36124SJuan Quintela     }
80871d36124SJuan Quintela 
8096bd92a7cSPaolo Bonzini     if (!qtest_has_machine(machine_alias)) {
8106bd92a7cSPaolo Bonzini         g_autofree char *msg = g_strdup_printf("machine %s not supported", machine_alias);
8116bd92a7cSPaolo Bonzini         g_test_skip(msg);
8126bd92a7cSPaolo Bonzini         return -1;
8136bd92a7cSPaolo Bonzini     }
8146bd92a7cSPaolo Bonzini 
8156c6d2330SFabiano Rosas     machine = resolve_machine_version(machine_alias, QEMU_ENV_SRC,
8165050ad2aSFabiano Rosas                                       QEMU_ENV_DST);
8176c6d2330SFabiano Rosas 
8185050ad2aSFabiano Rosas     g_test_message("Using machine type: %s", machine);
8195050ad2aSFabiano Rosas 
820bc28a611SJuan Quintela     cmd_source = g_strdup_printf("-accel kvm%s -accel tcg "
821c9961391SFabiano Rosas                                  "-machine %s,%s "
8221e8a1faeSThomas Huth                                  "-name source,debug-threads=on "
8231e8a1faeSThomas Huth                                  "-m %s "
8241e8a1faeSThomas Huth                                  "-serial file:%s/src_serial "
825832c732cSJuan Quintela                                  "%s %s %s %s %s",
82671d36124SJuan Quintela                                  kvm_opts ? kvm_opts : "",
8275050ad2aSFabiano Rosas                                  machine, machine_opts,
8281e8a1faeSThomas Huth                                  memory_size, tmpfs,
829832c732cSJuan Quintela                                  arch_opts ? arch_opts : "",
830832c732cSJuan Quintela                                  arch_source ? arch_source : "",
8310368ace8SJuan Quintela                                  shmem_opts ? shmem_opts : "",
83219da6edfSDaniel P. Berrangé                                  args->opts_source ? args->opts_source : "",
8331e8a1faeSThomas Huth                                  ignore_stderr);
834d795f474SJuan Quintela     if (!args->only_target) {
8355050ad2aSFabiano Rosas         *from = qtest_init_with_env(QEMU_ENV_SRC, cmd_source);
836cdf5ab55SDaniel P. Berrangé         qtest_qmp_set_event_callback(*from,
837f0649758SSteve Sistare                                      migrate_watch_for_events,
838f0649758SSteve Sistare                                      &src_state);
839d795f474SJuan Quintela     }
8401e8a1faeSThomas Huth 
841bc28a611SJuan Quintela     cmd_target = g_strdup_printf("-accel kvm%s -accel tcg "
842c9961391SFabiano Rosas                                  "-machine %s,%s "
8431e8a1faeSThomas Huth                                  "-name target,debug-threads=on "
8441e8a1faeSThomas Huth                                  "-m %s "
8451e8a1faeSThomas Huth                                  "-serial file:%s/dest_serial "
8461e8a1faeSThomas Huth                                  "-incoming %s "
847832c732cSJuan Quintela                                  "%s %s %s %s %s",
84871d36124SJuan Quintela                                  kvm_opts ? kvm_opts : "",
8495050ad2aSFabiano Rosas                                  machine, machine_opts,
8501e8a1faeSThomas Huth                                  memory_size, tmpfs, uri,
851832c732cSJuan Quintela                                  arch_opts ? arch_opts : "",
852832c732cSJuan Quintela                                  arch_target ? arch_target : "",
8530368ace8SJuan Quintela                                  shmem_opts ? shmem_opts : "",
85419da6edfSDaniel P. Berrangé                                  args->opts_target ? args->opts_target : "",
85519da6edfSDaniel P. Berrangé                                  ignore_stderr);
8565050ad2aSFabiano Rosas     *to = qtest_init_with_env(QEMU_ENV_DST, cmd_target);
857266ea334SDaniel P. Berrangé     qtest_qmp_set_event_callback(*to,
858f0649758SSteve Sistare                                  migrate_watch_for_events,
859f0649758SSteve Sistare                                  &dst_state);
8601e8a1faeSThomas Huth 
8611e8a1faeSThomas Huth     /*
8621e8a1faeSThomas Huth      * Remove shmem file immediately to avoid memory leak in test failed case.
86396420a30SMichael Tokarev      * It's valid because QEMU has already opened this file
8641e8a1faeSThomas Huth      */
8651e8a1faeSThomas Huth     if (args->use_shmem) {
8661e8a1faeSThomas Huth         unlink(shmem_path);
8671e8a1faeSThomas Huth     }
8681e8a1faeSThomas Huth 
869cd313b66SPeter Xu     /*
870cd313b66SPeter Xu      * Always enable migration events.  Libvirt always uses it, let's try
871cd313b66SPeter Xu      * to mimic as closer as that.
872cd313b66SPeter Xu      */
873cd313b66SPeter Xu     migrate_set_capability(*from, "events", true);
874cd313b66SPeter Xu     migrate_set_capability(*to, "events", true);
875cd313b66SPeter Xu 
87619da6edfSDaniel P. Berrangé     return 0;
8771e8a1faeSThomas Huth }
8781e8a1faeSThomas Huth 
test_migrate_end(QTestState * from,QTestState * to,bool test_dest)8791e8a1faeSThomas Huth static void test_migrate_end(QTestState *from, QTestState *to, bool test_dest)
8801e8a1faeSThomas Huth {
8811e8a1faeSThomas Huth     unsigned char dest_byte_a, dest_byte_b, dest_byte_c, dest_byte_d;
8821e8a1faeSThomas Huth 
8831e8a1faeSThomas Huth     qtest_quit(from);
8841e8a1faeSThomas Huth 
8851e8a1faeSThomas Huth     if (test_dest) {
8861e8a1faeSThomas Huth         qtest_memread(to, start_address, &dest_byte_a, 1);
8871e8a1faeSThomas Huth 
8881e8a1faeSThomas Huth         /* Destination still running, wait for a byte to change */
8891e8a1faeSThomas Huth         do {
8901e8a1faeSThomas Huth             qtest_memread(to, start_address, &dest_byte_b, 1);
8911e8a1faeSThomas Huth             usleep(1000 * 10);
8921e8a1faeSThomas Huth         } while (dest_byte_a == dest_byte_b);
8931e8a1faeSThomas Huth 
894855436dbSDaniel P. Berrangé         qtest_qmp_assert_success(to, "{ 'execute' : 'stop'}");
8951e8a1faeSThomas Huth 
8961e8a1faeSThomas Huth         /* With it stopped, check nothing changes */
8971e8a1faeSThomas Huth         qtest_memread(to, start_address, &dest_byte_c, 1);
8981e8a1faeSThomas Huth         usleep(1000 * 200);
8991e8a1faeSThomas Huth         qtest_memread(to, start_address, &dest_byte_d, 1);
9001e8a1faeSThomas Huth         g_assert_cmpint(dest_byte_c, ==, dest_byte_d);
9011e8a1faeSThomas Huth 
9021e8a1faeSThomas Huth         check_guests_ram(to);
9031e8a1faeSThomas Huth     }
9041e8a1faeSThomas Huth 
9051e8a1faeSThomas Huth     qtest_quit(to);
9061e8a1faeSThomas Huth 
9071e8a1faeSThomas Huth     cleanup("migsocket");
9081e8a1faeSThomas Huth     cleanup("src_serial");
9091e8a1faeSThomas Huth     cleanup("dest_serial");
9103dc35470SFabiano Rosas     cleanup(FILE_TEST_FILENAME);
9111e8a1faeSThomas Huth }
9121e8a1faeSThomas Huth 
91358d25e97SDaniel P. Berrangé #ifdef CONFIG_GNUTLS
91458d25e97SDaniel P. Berrangé struct TestMigrateTLSPSKData {
91558d25e97SDaniel P. Berrangé     char *workdir;
91658d25e97SDaniel P. Berrangé     char *workdiralt;
91758d25e97SDaniel P. Berrangé     char *pskfile;
91858d25e97SDaniel P. Berrangé     char *pskfilealt;
91958d25e97SDaniel P. Berrangé };
92058d25e97SDaniel P. Berrangé 
92158d25e97SDaniel P. Berrangé static void *
test_migrate_tls_psk_start_common(QTestState * from,QTestState * to,bool mismatch)92258d25e97SDaniel P. Berrangé test_migrate_tls_psk_start_common(QTestState *from,
92358d25e97SDaniel P. Berrangé                                   QTestState *to,
92458d25e97SDaniel P. Berrangé                                   bool mismatch)
92558d25e97SDaniel P. Berrangé {
92658d25e97SDaniel P. Berrangé     struct TestMigrateTLSPSKData *data =
92758d25e97SDaniel P. Berrangé         g_new0(struct TestMigrateTLSPSKData, 1);
92858d25e97SDaniel P. Berrangé 
92958d25e97SDaniel P. Berrangé     data->workdir = g_strdup_printf("%s/tlscredspsk0", tmpfs);
93058d25e97SDaniel P. Berrangé     data->pskfile = g_strdup_printf("%s/%s", data->workdir,
93158d25e97SDaniel P. Berrangé                                     QCRYPTO_TLS_CREDS_PSKFILE);
932413bebc0SBin Meng     g_mkdir_with_parents(data->workdir, 0700);
93358d25e97SDaniel P. Berrangé     test_tls_psk_init(data->pskfile);
93458d25e97SDaniel P. Berrangé 
93558d25e97SDaniel P. Berrangé     if (mismatch) {
93658d25e97SDaniel P. Berrangé         data->workdiralt = g_strdup_printf("%s/tlscredspskalt0", tmpfs);
93758d25e97SDaniel P. Berrangé         data->pskfilealt = g_strdup_printf("%s/%s", data->workdiralt,
93858d25e97SDaniel P. Berrangé                                            QCRYPTO_TLS_CREDS_PSKFILE);
939413bebc0SBin Meng         g_mkdir_with_parents(data->workdiralt, 0700);
94058d25e97SDaniel P. Berrangé         test_tls_psk_init_alt(data->pskfilealt);
94158d25e97SDaniel P. Berrangé     }
94258d25e97SDaniel P. Berrangé 
943aca04069SDaniel P. Berrangé     qtest_qmp_assert_success(from,
94458d25e97SDaniel P. Berrangé                              "{ 'execute': 'object-add',"
94558d25e97SDaniel P. Berrangé                              "  'arguments': { 'qom-type': 'tls-creds-psk',"
94658d25e97SDaniel P. Berrangé                              "                 'id': 'tlscredspsk0',"
94758d25e97SDaniel P. Berrangé                              "                 'endpoint': 'client',"
94858d25e97SDaniel P. Berrangé                              "                 'dir': %s,"
94958d25e97SDaniel P. Berrangé                              "                 'username': 'qemu'} }",
95058d25e97SDaniel P. Berrangé                              data->workdir);
95158d25e97SDaniel P. Berrangé 
952aca04069SDaniel P. Berrangé     qtest_qmp_assert_success(to,
95358d25e97SDaniel P. Berrangé                              "{ 'execute': 'object-add',"
95458d25e97SDaniel P. Berrangé                              "  'arguments': { 'qom-type': 'tls-creds-psk',"
95558d25e97SDaniel P. Berrangé                              "                 'id': 'tlscredspsk0',"
95658d25e97SDaniel P. Berrangé                              "                 'endpoint': 'server',"
95758d25e97SDaniel P. Berrangé                              "                 'dir': %s } }",
95858d25e97SDaniel P. Berrangé                              mismatch ? data->workdiralt : data->workdir);
95958d25e97SDaniel P. Berrangé 
96058d25e97SDaniel P. Berrangé     migrate_set_parameter_str(from, "tls-creds", "tlscredspsk0");
96158d25e97SDaniel P. Berrangé     migrate_set_parameter_str(to, "tls-creds", "tlscredspsk0");
96258d25e97SDaniel P. Berrangé 
96358d25e97SDaniel P. Berrangé     return data;
96458d25e97SDaniel P. Berrangé }
96558d25e97SDaniel P. Berrangé 
96658d25e97SDaniel P. Berrangé static void *
test_migrate_tls_psk_start_match(QTestState * from,QTestState * to)96758d25e97SDaniel P. Berrangé test_migrate_tls_psk_start_match(QTestState *from,
96858d25e97SDaniel P. Berrangé                                  QTestState *to)
96958d25e97SDaniel P. Berrangé {
97058d25e97SDaniel P. Berrangé     return test_migrate_tls_psk_start_common(from, to, false);
97158d25e97SDaniel P. Berrangé }
97258d25e97SDaniel P. Berrangé 
97358d25e97SDaniel P. Berrangé static void *
test_migrate_tls_psk_start_mismatch(QTestState * from,QTestState * to)97458d25e97SDaniel P. Berrangé test_migrate_tls_psk_start_mismatch(QTestState *from,
97558d25e97SDaniel P. Berrangé                                     QTestState *to)
97658d25e97SDaniel P. Berrangé {
97758d25e97SDaniel P. Berrangé     return test_migrate_tls_psk_start_common(from, to, true);
97858d25e97SDaniel P. Berrangé }
97958d25e97SDaniel P. Berrangé 
98058d25e97SDaniel P. Berrangé static void
test_migrate_tls_psk_finish(QTestState * from,QTestState * to,void * opaque)98158d25e97SDaniel P. Berrangé test_migrate_tls_psk_finish(QTestState *from,
98258d25e97SDaniel P. Berrangé                             QTestState *to,
98358d25e97SDaniel P. Berrangé                             void *opaque)
98458d25e97SDaniel P. Berrangé {
98558d25e97SDaniel P. Berrangé     struct TestMigrateTLSPSKData *data = opaque;
98658d25e97SDaniel P. Berrangé 
98758d25e97SDaniel P. Berrangé     test_tls_psk_cleanup(data->pskfile);
98858d25e97SDaniel P. Berrangé     if (data->pskfilealt) {
98958d25e97SDaniel P. Berrangé         test_tls_psk_cleanup(data->pskfilealt);
99058d25e97SDaniel P. Berrangé     }
99158d25e97SDaniel P. Berrangé     rmdir(data->workdir);
99258d25e97SDaniel P. Berrangé     if (data->workdiralt) {
99358d25e97SDaniel P. Berrangé         rmdir(data->workdiralt);
99458d25e97SDaniel P. Berrangé     }
99558d25e97SDaniel P. Berrangé 
99658d25e97SDaniel P. Berrangé     g_free(data->workdiralt);
99758d25e97SDaniel P. Berrangé     g_free(data->pskfilealt);
99858d25e97SDaniel P. Berrangé     g_free(data->workdir);
99958d25e97SDaniel P. Berrangé     g_free(data->pskfile);
100058d25e97SDaniel P. Berrangé     g_free(data);
100158d25e97SDaniel P. Berrangé }
1002d47b83b1SDaniel P. Berrangé 
1003d47b83b1SDaniel P. Berrangé #ifdef CONFIG_TASN1
1004d47b83b1SDaniel P. Berrangé typedef struct {
1005d47b83b1SDaniel P. Berrangé     char *workdir;
1006d47b83b1SDaniel P. Berrangé     char *keyfile;
1007d47b83b1SDaniel P. Berrangé     char *cacert;
1008d47b83b1SDaniel P. Berrangé     char *servercert;
1009d47b83b1SDaniel P. Berrangé     char *serverkey;
1010d47b83b1SDaniel P. Berrangé     char *clientcert;
1011d47b83b1SDaniel P. Berrangé     char *clientkey;
1012d47b83b1SDaniel P. Berrangé } TestMigrateTLSX509Data;
1013d47b83b1SDaniel P. Berrangé 
1014d47b83b1SDaniel P. Berrangé typedef struct {
1015d47b83b1SDaniel P. Berrangé     bool verifyclient;
1016d47b83b1SDaniel P. Berrangé     bool clientcert;
1017d47b83b1SDaniel P. Berrangé     bool hostileclient;
1018d47b83b1SDaniel P. Berrangé     bool authzclient;
1019d47b83b1SDaniel P. Berrangé     const char *certhostname;
1020d47b83b1SDaniel P. Berrangé     const char *certipaddr;
1021d47b83b1SDaniel P. Berrangé } TestMigrateTLSX509;
1022d47b83b1SDaniel P. Berrangé 
1023d47b83b1SDaniel P. Berrangé static void *
test_migrate_tls_x509_start_common(QTestState * from,QTestState * to,TestMigrateTLSX509 * args)1024d47b83b1SDaniel P. Berrangé test_migrate_tls_x509_start_common(QTestState *from,
1025d47b83b1SDaniel P. Berrangé                                    QTestState *to,
1026d47b83b1SDaniel P. Berrangé                                    TestMigrateTLSX509 *args)
1027d47b83b1SDaniel P. Berrangé {
1028d47b83b1SDaniel P. Berrangé     TestMigrateTLSX509Data *data = g_new0(TestMigrateTLSX509Data, 1);
1029d47b83b1SDaniel P. Berrangé 
1030d47b83b1SDaniel P. Berrangé     data->workdir = g_strdup_printf("%s/tlscredsx5090", tmpfs);
1031d47b83b1SDaniel P. Berrangé     data->keyfile = g_strdup_printf("%s/key.pem", data->workdir);
1032d47b83b1SDaniel P. Berrangé 
1033d47b83b1SDaniel P. Berrangé     data->cacert = g_strdup_printf("%s/ca-cert.pem", data->workdir);
1034d47b83b1SDaniel P. Berrangé     data->serverkey = g_strdup_printf("%s/server-key.pem", data->workdir);
1035d47b83b1SDaniel P. Berrangé     data->servercert = g_strdup_printf("%s/server-cert.pem", data->workdir);
1036d47b83b1SDaniel P. Berrangé     if (args->clientcert) {
1037d47b83b1SDaniel P. Berrangé         data->clientkey = g_strdup_printf("%s/client-key.pem", data->workdir);
1038d47b83b1SDaniel P. Berrangé         data->clientcert = g_strdup_printf("%s/client-cert.pem", data->workdir);
1039d47b83b1SDaniel P. Berrangé     }
1040d47b83b1SDaniel P. Berrangé 
1041413bebc0SBin Meng     g_mkdir_with_parents(data->workdir, 0700);
1042d47b83b1SDaniel P. Berrangé 
1043d47b83b1SDaniel P. Berrangé     test_tls_init(data->keyfile);
10442549f610SBin Meng #ifndef _WIN32
1045d47b83b1SDaniel P. Berrangé     g_assert(link(data->keyfile, data->serverkey) == 0);
10462549f610SBin Meng #else
10472549f610SBin Meng     g_assert(CreateHardLink(data->serverkey, data->keyfile, NULL) != 0);
10482549f610SBin Meng #endif
1049d47b83b1SDaniel P. Berrangé     if (args->clientcert) {
10502549f610SBin Meng #ifndef _WIN32
1051d47b83b1SDaniel P. Berrangé         g_assert(link(data->keyfile, data->clientkey) == 0);
10522549f610SBin Meng #else
10532549f610SBin Meng         g_assert(CreateHardLink(data->clientkey, data->keyfile, NULL) != 0);
10542549f610SBin Meng #endif
1055d47b83b1SDaniel P. Berrangé     }
1056d47b83b1SDaniel P. Berrangé 
1057d47b83b1SDaniel P. Berrangé     TLS_ROOT_REQ_SIMPLE(cacertreq, data->cacert);
1058d47b83b1SDaniel P. Berrangé     if (args->clientcert) {
1059d47b83b1SDaniel P. Berrangé         TLS_CERT_REQ_SIMPLE_CLIENT(servercertreq, cacertreq,
1060d47b83b1SDaniel P. Berrangé                                    args->hostileclient ?
1061d47b83b1SDaniel P. Berrangé                                    QCRYPTO_TLS_TEST_CLIENT_HOSTILE_NAME :
1062d47b83b1SDaniel P. Berrangé                                    QCRYPTO_TLS_TEST_CLIENT_NAME,
1063d47b83b1SDaniel P. Berrangé                                    data->clientcert);
10642cf6dc41SPeter Maydell         test_tls_deinit_cert(&servercertreq);
1065d47b83b1SDaniel P. Berrangé     }
1066d47b83b1SDaniel P. Berrangé 
1067d47b83b1SDaniel P. Berrangé     TLS_CERT_REQ_SIMPLE_SERVER(clientcertreq, cacertreq,
1068d47b83b1SDaniel P. Berrangé                                data->servercert,
1069d47b83b1SDaniel P. Berrangé                                args->certhostname,
1070d47b83b1SDaniel P. Berrangé                                args->certipaddr);
10712cf6dc41SPeter Maydell     test_tls_deinit_cert(&clientcertreq);
10722cf6dc41SPeter Maydell     test_tls_deinit_cert(&cacertreq);
1073d47b83b1SDaniel P. Berrangé 
1074aca04069SDaniel P. Berrangé     qtest_qmp_assert_success(from,
1075d47b83b1SDaniel P. Berrangé                              "{ 'execute': 'object-add',"
1076d47b83b1SDaniel P. Berrangé                              "  'arguments': { 'qom-type': 'tls-creds-x509',"
1077d47b83b1SDaniel P. Berrangé                              "                 'id': 'tlscredsx509client0',"
1078d47b83b1SDaniel P. Berrangé                              "                 'endpoint': 'client',"
1079d47b83b1SDaniel P. Berrangé                              "                 'dir': %s,"
1080d47b83b1SDaniel P. Berrangé                              "                 'sanity-check': true,"
1081d47b83b1SDaniel P. Berrangé                              "                 'verify-peer': true} }",
1082d47b83b1SDaniel P. Berrangé                              data->workdir);
1083d47b83b1SDaniel P. Berrangé     migrate_set_parameter_str(from, "tls-creds", "tlscredsx509client0");
1084d47b83b1SDaniel P. Berrangé     if (args->certhostname) {
1085d47b83b1SDaniel P. Berrangé         migrate_set_parameter_str(from, "tls-hostname", args->certhostname);
1086d47b83b1SDaniel P. Berrangé     }
1087d47b83b1SDaniel P. Berrangé 
1088aca04069SDaniel P. Berrangé     qtest_qmp_assert_success(to,
1089d47b83b1SDaniel P. Berrangé                              "{ 'execute': 'object-add',"
1090d47b83b1SDaniel P. Berrangé                              "  'arguments': { 'qom-type': 'tls-creds-x509',"
1091d47b83b1SDaniel P. Berrangé                              "                 'id': 'tlscredsx509server0',"
1092d47b83b1SDaniel P. Berrangé                              "                 'endpoint': 'server',"
1093d47b83b1SDaniel P. Berrangé                              "                 'dir': %s,"
1094d47b83b1SDaniel P. Berrangé                              "                 'sanity-check': true,"
1095d47b83b1SDaniel P. Berrangé                              "                 'verify-peer': %i} }",
1096d47b83b1SDaniel P. Berrangé                              data->workdir, args->verifyclient);
1097d47b83b1SDaniel P. Berrangé     migrate_set_parameter_str(to, "tls-creds", "tlscredsx509server0");
1098d47b83b1SDaniel P. Berrangé 
1099d47b83b1SDaniel P. Berrangé     if (args->authzclient) {
1100aca04069SDaniel P. Berrangé         qtest_qmp_assert_success(to,
1101d47b83b1SDaniel P. Berrangé                                  "{ 'execute': 'object-add',"
1102d47b83b1SDaniel P. Berrangé                                  "  'arguments': { 'qom-type': 'authz-simple',"
1103d47b83b1SDaniel P. Berrangé                                  "                 'id': 'tlsauthz0',"
1104d47b83b1SDaniel P. Berrangé                                  "                 'identity': %s} }",
1105d47b83b1SDaniel P. Berrangé                                  "CN=" QCRYPTO_TLS_TEST_CLIENT_NAME);
1106d47b83b1SDaniel P. Berrangé         migrate_set_parameter_str(to, "tls-authz", "tlsauthz0");
1107d47b83b1SDaniel P. Berrangé     }
1108d47b83b1SDaniel P. Berrangé 
1109d47b83b1SDaniel P. Berrangé     return data;
1110d47b83b1SDaniel P. Berrangé }
1111d47b83b1SDaniel P. Berrangé 
1112d47b83b1SDaniel P. Berrangé /*
1113d47b83b1SDaniel P. Berrangé  * The normal case: match server's cert hostname against
1114d47b83b1SDaniel P. Berrangé  * whatever host we were telling QEMU to connect to (if any)
1115d47b83b1SDaniel P. Berrangé  */
1116d47b83b1SDaniel P. Berrangé static void *
test_migrate_tls_x509_start_default_host(QTestState * from,QTestState * to)1117d47b83b1SDaniel P. Berrangé test_migrate_tls_x509_start_default_host(QTestState *from,
1118d47b83b1SDaniel P. Berrangé                                          QTestState *to)
1119d47b83b1SDaniel P. Berrangé {
1120d47b83b1SDaniel P. Berrangé     TestMigrateTLSX509 args = {
1121d47b83b1SDaniel P. Berrangé         .verifyclient = true,
1122d47b83b1SDaniel P. Berrangé         .clientcert = true,
1123d47b83b1SDaniel P. Berrangé         .certipaddr = "127.0.0.1"
1124d47b83b1SDaniel P. Berrangé     };
1125d47b83b1SDaniel P. Berrangé     return test_migrate_tls_x509_start_common(from, to, &args);
1126d47b83b1SDaniel P. Berrangé }
1127d47b83b1SDaniel P. Berrangé 
1128d47b83b1SDaniel P. Berrangé /*
1129d47b83b1SDaniel P. Berrangé  * The unusual case: the server's cert is different from
1130d47b83b1SDaniel P. Berrangé  * the address we're telling QEMU to connect to (if any),
1131d47b83b1SDaniel P. Berrangé  * so we must give QEMU an explicit hostname to validate
1132d47b83b1SDaniel P. Berrangé  */
1133d47b83b1SDaniel P. Berrangé static void *
test_migrate_tls_x509_start_override_host(QTestState * from,QTestState * to)1134d47b83b1SDaniel P. Berrangé test_migrate_tls_x509_start_override_host(QTestState *from,
1135d47b83b1SDaniel P. Berrangé                                           QTestState *to)
1136d47b83b1SDaniel P. Berrangé {
1137d47b83b1SDaniel P. Berrangé     TestMigrateTLSX509 args = {
1138d47b83b1SDaniel P. Berrangé         .verifyclient = true,
1139d47b83b1SDaniel P. Berrangé         .clientcert = true,
1140d47b83b1SDaniel P. Berrangé         .certhostname = "qemu.org",
1141d47b83b1SDaniel P. Berrangé     };
1142d47b83b1SDaniel P. Berrangé     return test_migrate_tls_x509_start_common(from, to, &args);
1143d47b83b1SDaniel P. Berrangé }
1144d47b83b1SDaniel P. Berrangé 
1145d47b83b1SDaniel P. Berrangé /*
1146d47b83b1SDaniel P. Berrangé  * The unusual case: the server's cert is different from
1147d47b83b1SDaniel P. Berrangé  * the address we're telling QEMU to connect to, and so we
1148d47b83b1SDaniel P. Berrangé  * expect the client to reject the server
1149d47b83b1SDaniel P. Berrangé  */
1150d47b83b1SDaniel P. Berrangé static void *
test_migrate_tls_x509_start_mismatch_host(QTestState * from,QTestState * to)1151d47b83b1SDaniel P. Berrangé test_migrate_tls_x509_start_mismatch_host(QTestState *from,
1152d47b83b1SDaniel P. Berrangé                                           QTestState *to)
1153d47b83b1SDaniel P. Berrangé {
1154d47b83b1SDaniel P. Berrangé     TestMigrateTLSX509 args = {
1155d47b83b1SDaniel P. Berrangé         .verifyclient = true,
1156d47b83b1SDaniel P. Berrangé         .clientcert = true,
1157d47b83b1SDaniel P. Berrangé         .certipaddr = "10.0.0.1",
1158d47b83b1SDaniel P. Berrangé     };
1159d47b83b1SDaniel P. Berrangé     return test_migrate_tls_x509_start_common(from, to, &args);
1160d47b83b1SDaniel P. Berrangé }
1161d47b83b1SDaniel P. Berrangé 
1162d47b83b1SDaniel P. Berrangé static void *
test_migrate_tls_x509_start_friendly_client(QTestState * from,QTestState * to)1163d47b83b1SDaniel P. Berrangé test_migrate_tls_x509_start_friendly_client(QTestState *from,
1164d47b83b1SDaniel P. Berrangé                                             QTestState *to)
1165d47b83b1SDaniel P. Berrangé {
1166d47b83b1SDaniel P. Berrangé     TestMigrateTLSX509 args = {
1167d47b83b1SDaniel P. Berrangé         .verifyclient = true,
1168d47b83b1SDaniel P. Berrangé         .clientcert = true,
1169d47b83b1SDaniel P. Berrangé         .authzclient = true,
1170d47b83b1SDaniel P. Berrangé         .certipaddr = "127.0.0.1",
1171d47b83b1SDaniel P. Berrangé     };
1172d47b83b1SDaniel P. Berrangé     return test_migrate_tls_x509_start_common(from, to, &args);
1173d47b83b1SDaniel P. Berrangé }
1174d47b83b1SDaniel P. Berrangé 
1175d47b83b1SDaniel P. Berrangé static void *
test_migrate_tls_x509_start_hostile_client(QTestState * from,QTestState * to)1176d47b83b1SDaniel P. Berrangé test_migrate_tls_x509_start_hostile_client(QTestState *from,
1177d47b83b1SDaniel P. Berrangé                                            QTestState *to)
1178d47b83b1SDaniel P. Berrangé {
1179d47b83b1SDaniel P. Berrangé     TestMigrateTLSX509 args = {
1180d47b83b1SDaniel P. Berrangé         .verifyclient = true,
1181d47b83b1SDaniel P. Berrangé         .clientcert = true,
1182d47b83b1SDaniel P. Berrangé         .hostileclient = true,
1183d47b83b1SDaniel P. Berrangé         .authzclient = true,
1184d47b83b1SDaniel P. Berrangé         .certipaddr = "127.0.0.1",
1185d47b83b1SDaniel P. Berrangé     };
1186d47b83b1SDaniel P. Berrangé     return test_migrate_tls_x509_start_common(from, to, &args);
1187d47b83b1SDaniel P. Berrangé }
1188d47b83b1SDaniel P. Berrangé 
1189d47b83b1SDaniel P. Berrangé /*
1190d47b83b1SDaniel P. Berrangé  * The case with no client certificate presented,
1191d47b83b1SDaniel P. Berrangé  * and no server verification
1192d47b83b1SDaniel P. Berrangé  */
1193d47b83b1SDaniel P. Berrangé static void *
test_migrate_tls_x509_start_allow_anon_client(QTestState * from,QTestState * to)1194d47b83b1SDaniel P. Berrangé test_migrate_tls_x509_start_allow_anon_client(QTestState *from,
1195d47b83b1SDaniel P. Berrangé                                               QTestState *to)
1196d47b83b1SDaniel P. Berrangé {
1197d47b83b1SDaniel P. Berrangé     TestMigrateTLSX509 args = {
1198d47b83b1SDaniel P. Berrangé         .certipaddr = "127.0.0.1",
1199d47b83b1SDaniel P. Berrangé     };
1200d47b83b1SDaniel P. Berrangé     return test_migrate_tls_x509_start_common(from, to, &args);
1201d47b83b1SDaniel P. Berrangé }
1202d47b83b1SDaniel P. Berrangé 
1203d47b83b1SDaniel P. Berrangé /*
1204d47b83b1SDaniel P. Berrangé  * The case with no client certificate presented,
1205d47b83b1SDaniel P. Berrangé  * and server verification rejecting
1206d47b83b1SDaniel P. Berrangé  */
1207d47b83b1SDaniel P. Berrangé static void *
test_migrate_tls_x509_start_reject_anon_client(QTestState * from,QTestState * to)1208d47b83b1SDaniel P. Berrangé test_migrate_tls_x509_start_reject_anon_client(QTestState *from,
1209d47b83b1SDaniel P. Berrangé                                                QTestState *to)
1210d47b83b1SDaniel P. Berrangé {
1211d47b83b1SDaniel P. Berrangé     TestMigrateTLSX509 args = {
1212d47b83b1SDaniel P. Berrangé         .verifyclient = true,
1213d47b83b1SDaniel P. Berrangé         .certipaddr = "127.0.0.1",
1214d47b83b1SDaniel P. Berrangé     };
1215d47b83b1SDaniel P. Berrangé     return test_migrate_tls_x509_start_common(from, to, &args);
1216d47b83b1SDaniel P. Berrangé }
1217d47b83b1SDaniel P. Berrangé 
1218d47b83b1SDaniel P. Berrangé static void
test_migrate_tls_x509_finish(QTestState * from,QTestState * to,void * opaque)1219d47b83b1SDaniel P. Berrangé test_migrate_tls_x509_finish(QTestState *from,
1220d47b83b1SDaniel P. Berrangé                              QTestState *to,
1221d47b83b1SDaniel P. Berrangé                              void *opaque)
1222d47b83b1SDaniel P. Berrangé {
1223d47b83b1SDaniel P. Berrangé     TestMigrateTLSX509Data *data = opaque;
1224d47b83b1SDaniel P. Berrangé 
1225d47b83b1SDaniel P. Berrangé     test_tls_cleanup(data->keyfile);
1226d47b83b1SDaniel P. Berrangé     g_free(data->keyfile);
12270f0a9e4eSThomas Huth 
12280f0a9e4eSThomas Huth     unlink(data->cacert);
12290f0a9e4eSThomas Huth     g_free(data->cacert);
12300f0a9e4eSThomas Huth     unlink(data->servercert);
12310f0a9e4eSThomas Huth     g_free(data->servercert);
12320f0a9e4eSThomas Huth     unlink(data->serverkey);
12330f0a9e4eSThomas Huth     g_free(data->serverkey);
12340f0a9e4eSThomas Huth 
12350f0a9e4eSThomas Huth     if (data->clientcert) {
12360f0a9e4eSThomas Huth         unlink(data->clientcert);
12370f0a9e4eSThomas Huth         g_free(data->clientcert);
12380f0a9e4eSThomas Huth     }
12390f0a9e4eSThomas Huth     if (data->clientkey) {
12400f0a9e4eSThomas Huth         unlink(data->clientkey);
12410f0a9e4eSThomas Huth         g_free(data->clientkey);
12420f0a9e4eSThomas Huth     }
12430f0a9e4eSThomas Huth 
12440f0a9e4eSThomas Huth     rmdir(data->workdir);
12450f0a9e4eSThomas Huth     g_free(data->workdir);
12460f0a9e4eSThomas Huth 
1247d47b83b1SDaniel P. Berrangé     g_free(data);
1248d47b83b1SDaniel P. Berrangé }
1249d47b83b1SDaniel P. Berrangé #endif /* CONFIG_TASN1 */
125058d25e97SDaniel P. Berrangé #endif /* CONFIG_GNUTLS */
125158d25e97SDaniel P. Berrangé 
migrate_postcopy_prepare(QTestState ** from_ptr,QTestState ** to_ptr,MigrateCommon * args)12521e8a1faeSThomas Huth static int migrate_postcopy_prepare(QTestState **from_ptr,
12531e8a1faeSThomas Huth                                     QTestState **to_ptr,
1254d1a27b16SPeter Xu                                     MigrateCommon *args)
12551e8a1faeSThomas Huth {
12561e8a1faeSThomas Huth     QTestState *from, *to;
12571e8a1faeSThomas Huth 
125806c48d6bSWei Wang     if (test_migrate_start(&from, &to, "defer", &args->start)) {
12591e8a1faeSThomas Huth         return -1;
12601e8a1faeSThomas Huth     }
12611e8a1faeSThomas Huth 
1262d1a27b16SPeter Xu     if (args->start_hook) {
1263d1a27b16SPeter Xu         args->postcopy_data = args->start_hook(from, to);
1264d1a27b16SPeter Xu     }
1265d1a27b16SPeter Xu 
12661e8a1faeSThomas Huth     migrate_set_capability(from, "postcopy-ram", true);
12671e8a1faeSThomas Huth     migrate_set_capability(to, "postcopy-ram", true);
12681e8a1faeSThomas Huth     migrate_set_capability(to, "postcopy-blocktime", true);
12691e8a1faeSThomas Huth 
12708f6fe915SPeter Xu     if (args->postcopy_preempt) {
12718f6fe915SPeter Xu         migrate_set_capability(from, "postcopy-preempt", true);
12728f6fe915SPeter Xu         migrate_set_capability(to, "postcopy-preempt", true);
12738f6fe915SPeter Xu     }
12748f6fe915SPeter Xu 
1275886dfe9dSDaniel P. Berrangé     migrate_ensure_non_converge(from);
12761e8a1faeSThomas Huth 
1277e02f56e3SDaniel P. Berrangé     migrate_prepare_for_dirty_mem(from);
127806c48d6bSWei Wang     qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming',"
12798e3766eeSHet Gala                              "  'arguments': { "
12808e3766eeSHet Gala                              "      'channels': [ { 'channel-type': 'main',"
12818e3766eeSHet Gala                              "      'addr': { 'transport': 'socket',"
12828e3766eeSHet Gala                              "                'type': 'inet',"
12838e3766eeSHet Gala                              "                'host': '127.0.0.1',"
12848e3766eeSHet Gala                              "                'port': '0' } } ] } }");
1285e02f56e3SDaniel P. Berrangé 
12861e8a1faeSThomas Huth     /* Wait for the first serial output from the source */
12871e8a1faeSThomas Huth     wait_for_serial("src_serial");
12882b58a8b9SSteve Sistare     wait_for_suspend(from, &src_state);
12891e8a1faeSThomas Huth 
1290d5ee387dSHet Gala     migrate_qmp(from, to, NULL, NULL, "{}");
12911e8a1faeSThomas Huth 
1292e02f56e3SDaniel P. Berrangé     migrate_wait_for_dirty_mem(from, to);
12931e8a1faeSThomas Huth 
12941e8a1faeSThomas Huth     *from_ptr = from;
12951e8a1faeSThomas Huth     *to_ptr = to;
12961e8a1faeSThomas Huth 
12971e8a1faeSThomas Huth     return 0;
12981e8a1faeSThomas Huth }
12991e8a1faeSThomas Huth 
migrate_postcopy_complete(QTestState * from,QTestState * to,MigrateCommon * args)1300d1a27b16SPeter Xu static void migrate_postcopy_complete(QTestState *from, QTestState *to,
1301d1a27b16SPeter Xu                                       MigrateCommon *args)
13021e8a1faeSThomas Huth {
13031e8a1faeSThomas Huth     wait_for_migration_complete(from);
13041e8a1faeSThomas Huth 
13052b58a8b9SSteve Sistare     if (args->start.suspend_me) {
13062b58a8b9SSteve Sistare         /* wakeup succeeds only if guest is suspended */
13072b58a8b9SSteve Sistare         qtest_qmp_assert_success(to, "{'execute': 'system_wakeup'}");
13082b58a8b9SSteve Sistare     }
13092b58a8b9SSteve Sistare 
13101e8a1faeSThomas Huth     /* Make sure we get at least one "B" on destination */
13111e8a1faeSThomas Huth     wait_for_serial("dest_serial");
13121e8a1faeSThomas Huth 
13131e8a1faeSThomas Huth     if (uffd_feature_thread_id) {
13141e8a1faeSThomas Huth         read_blocktime(to);
13151e8a1faeSThomas Huth     }
13161e8a1faeSThomas Huth 
1317d1a27b16SPeter Xu     if (args->finish_hook) {
1318d1a27b16SPeter Xu         args->finish_hook(from, to, args->postcopy_data);
1319d1a27b16SPeter Xu         args->postcopy_data = NULL;
1320d1a27b16SPeter Xu     }
1321d1a27b16SPeter Xu 
13221e8a1faeSThomas Huth     test_migrate_end(from, to, true);
13231e8a1faeSThomas Huth }
13241e8a1faeSThomas Huth 
test_postcopy_common(MigrateCommon * args)1325d1a27b16SPeter Xu static void test_postcopy_common(MigrateCommon *args)
1326d1a27b16SPeter Xu {
1327d1a27b16SPeter Xu     QTestState *from, *to;
1328d1a27b16SPeter Xu 
1329d1a27b16SPeter Xu     if (migrate_postcopy_prepare(&from, &to, args)) {
1330d1a27b16SPeter Xu         return;
1331d1a27b16SPeter Xu     }
1332d1a27b16SPeter Xu     migrate_postcopy_start(from, to);
1333d1a27b16SPeter Xu     migrate_postcopy_complete(from, to, args);
1334d1a27b16SPeter Xu }
1335d1a27b16SPeter Xu 
test_postcopy(void)13361e8a1faeSThomas Huth static void test_postcopy(void)
13371e8a1faeSThomas Huth {
1338d1a27b16SPeter Xu     MigrateCommon args = { };
13391e8a1faeSThomas Huth 
1340d1a27b16SPeter Xu     test_postcopy_common(&args);
13411e8a1faeSThomas Huth }
1342d1a27b16SPeter Xu 
test_postcopy_suspend(void)13432b58a8b9SSteve Sistare static void test_postcopy_suspend(void)
13442b58a8b9SSteve Sistare {
13452b58a8b9SSteve Sistare     MigrateCommon args = {
13462b58a8b9SSteve Sistare         .start.suspend_me = true,
13472b58a8b9SSteve Sistare     };
13482b58a8b9SSteve Sistare 
13492b58a8b9SSteve Sistare     test_postcopy_common(&args);
13502b58a8b9SSteve Sistare }
13512b58a8b9SSteve Sistare 
test_postcopy_preempt(void)13528f6fe915SPeter Xu static void test_postcopy_preempt(void)
13538f6fe915SPeter Xu {
13548f6fe915SPeter Xu     MigrateCommon args = {
13558f6fe915SPeter Xu         .postcopy_preempt = true,
13568f6fe915SPeter Xu     };
13578f6fe915SPeter Xu 
13588f6fe915SPeter Xu     test_postcopy_common(&args);
13598f6fe915SPeter Xu }
13608f6fe915SPeter Xu 
1361d1a27b16SPeter Xu #ifdef CONFIG_GNUTLS
test_postcopy_tls_psk(void)1362d1a27b16SPeter Xu static void test_postcopy_tls_psk(void)
1363d1a27b16SPeter Xu {
1364d1a27b16SPeter Xu     MigrateCommon args = {
1365d1a27b16SPeter Xu         .start_hook = test_migrate_tls_psk_start_match,
1366d1a27b16SPeter Xu         .finish_hook = test_migrate_tls_psk_finish,
1367d1a27b16SPeter Xu     };
1368d1a27b16SPeter Xu 
1369d1a27b16SPeter Xu     test_postcopy_common(&args);
13701e8a1faeSThomas Huth }
13718f6fe915SPeter Xu 
test_postcopy_preempt_tls_psk(void)13728f6fe915SPeter Xu static void test_postcopy_preempt_tls_psk(void)
13738f6fe915SPeter Xu {
13748f6fe915SPeter Xu     MigrateCommon args = {
13758f6fe915SPeter Xu         .postcopy_preempt = true,
13768f6fe915SPeter Xu         .start_hook = test_migrate_tls_psk_start_match,
13778f6fe915SPeter Xu         .finish_hook = test_migrate_tls_psk_finish,
13788f6fe915SPeter Xu     };
13798f6fe915SPeter Xu 
13808f6fe915SPeter Xu     test_postcopy_common(&args);
13818f6fe915SPeter Xu }
1382d1a27b16SPeter Xu #endif
13831e8a1faeSThomas Huth 
wait_for_postcopy_status(QTestState * one,const char * status)13847bca2bb7SFabiano Rosas static void wait_for_postcopy_status(QTestState *one, const char *status)
13857bca2bb7SFabiano Rosas {
13867bca2bb7SFabiano Rosas     wait_for_migration_status(one, status,
1387*19e56616SFabiano Rosas                               (const char * []) {
1388*19e56616SFabiano Rosas                                   "failed", "active",
1389*19e56616SFabiano Rosas                                   "completed", NULL
1390*19e56616SFabiano Rosas                               });
13917bca2bb7SFabiano Rosas }
13927bca2bb7SFabiano Rosas 
postcopy_recover_fail(QTestState * from,QTestState * to,PostcopyRecoveryFailStage stage)13936cf56a87SPeter Xu static void postcopy_recover_fail(QTestState *from, QTestState *to,
13946cf56a87SPeter Xu                                   PostcopyRecoveryFailStage stage)
13957bca2bb7SFabiano Rosas {
13960fd39735SPeter Xu #ifndef _WIN32
13976cf56a87SPeter Xu     bool fail_early = (stage == POSTCOPY_FAIL_CHANNEL_ESTABLISH);
13987bca2bb7SFabiano Rosas     int ret, pair1[2], pair2[2];
13997bca2bb7SFabiano Rosas     char c;
14007bca2bb7SFabiano Rosas 
14016cf56a87SPeter Xu     g_assert(stage > POSTCOPY_FAIL_NONE && stage < POSTCOPY_FAIL_MAX);
14026cf56a87SPeter Xu 
14037bca2bb7SFabiano Rosas     /* Create two unrelated socketpairs */
14047bca2bb7SFabiano Rosas     ret = qemu_socketpair(PF_LOCAL, SOCK_STREAM, 0, pair1);
14057bca2bb7SFabiano Rosas     g_assert_cmpint(ret, ==, 0);
14067bca2bb7SFabiano Rosas 
14077bca2bb7SFabiano Rosas     ret = qemu_socketpair(PF_LOCAL, SOCK_STREAM, 0, pair2);
14087bca2bb7SFabiano Rosas     g_assert_cmpint(ret, ==, 0);
14097bca2bb7SFabiano Rosas 
14107bca2bb7SFabiano Rosas     /*
14117bca2bb7SFabiano Rosas      * Give the guests unpaired ends of the sockets, so they'll all blocked
14127bca2bb7SFabiano Rosas      * at reading.  This mimics a wrong channel established.
14137bca2bb7SFabiano Rosas      */
14147bca2bb7SFabiano Rosas     qtest_qmp_fds_assert_success(from, &pair1[0], 1,
14157bca2bb7SFabiano Rosas                                  "{ 'execute': 'getfd',"
14167bca2bb7SFabiano Rosas                                  "  'arguments': { 'fdname': 'fd-mig' }}");
14177bca2bb7SFabiano Rosas     qtest_qmp_fds_assert_success(to, &pair2[0], 1,
14187bca2bb7SFabiano Rosas                                  "{ 'execute': 'getfd',"
14197bca2bb7SFabiano Rosas                                  "  'arguments': { 'fdname': 'fd-mig' }}");
14207bca2bb7SFabiano Rosas 
14217bca2bb7SFabiano Rosas     /*
14227bca2bb7SFabiano Rosas      * Write the 1st byte as QEMU_VM_COMMAND (0x8) for the dest socket, to
14237bca2bb7SFabiano Rosas      * emulate the 1st byte of a real recovery, but stops from there to
14247bca2bb7SFabiano Rosas      * keep dest QEMU in RECOVER.  This is needed so that we can kick off
14257bca2bb7SFabiano Rosas      * the recover process on dest QEMU (by triggering the G_IO_IN event).
14267bca2bb7SFabiano Rosas      *
14277bca2bb7SFabiano Rosas      * NOTE: this trick is not needed on src QEMUs, because src doesn't
14287bca2bb7SFabiano Rosas      * rely on an pre-existing G_IO_IN event, so it will always trigger the
14297bca2bb7SFabiano Rosas      * upcoming recovery anyway even if it can read nothing.
14307bca2bb7SFabiano Rosas      */
14317bca2bb7SFabiano Rosas #define QEMU_VM_COMMAND              0x08
14327bca2bb7SFabiano Rosas     c = QEMU_VM_COMMAND;
14337bca2bb7SFabiano Rosas     ret = send(pair2[1], &c, 1, 0);
14347bca2bb7SFabiano Rosas     g_assert_cmpint(ret, ==, 1);
14357bca2bb7SFabiano Rosas 
14366cf56a87SPeter Xu     if (stage == POSTCOPY_FAIL_CHANNEL_ESTABLISH) {
14376cf56a87SPeter Xu         /*
14386cf56a87SPeter Xu          * This will make src QEMU to fail at an early stage when trying to
14396cf56a87SPeter Xu          * resume later, where it shouldn't reach RECOVER stage at all.
14406cf56a87SPeter Xu          */
14416cf56a87SPeter Xu         close(pair1[1]);
14426cf56a87SPeter Xu     }
14436cf56a87SPeter Xu 
14447bca2bb7SFabiano Rosas     migrate_recover(to, "fd:fd-mig");
1445d5ee387dSHet Gala     migrate_qmp(from, to, "fd:fd-mig", NULL, "{'resume': true}");
14467bca2bb7SFabiano Rosas 
14477bca2bb7SFabiano Rosas     /*
14488dbd24d3SPeter Xu      * Source QEMU has an extra RECOVER_SETUP phase, dest doesn't have it.
14498dbd24d3SPeter Xu      * Make sure it appears along the way.
14508dbd24d3SPeter Xu      */
14518dbd24d3SPeter Xu     migration_event_wait(from, "postcopy-recover-setup");
14528dbd24d3SPeter Xu 
14536cf56a87SPeter Xu     if (fail_early) {
14548dbd24d3SPeter Xu         /*
14556cf56a87SPeter Xu          * When fails at reconnection, src QEMU will automatically goes
14566cf56a87SPeter Xu          * back to PAUSED state.  Making sure there is an event in this
14576cf56a87SPeter Xu          * case: Libvirt relies on this to detect early reconnection
14586cf56a87SPeter Xu          * errors.
14597bca2bb7SFabiano Rosas          */
14606cf56a87SPeter Xu         migration_event_wait(from, "postcopy-paused");
14616cf56a87SPeter Xu     } else {
14626cf56a87SPeter Xu         /*
14636cf56a87SPeter Xu          * We want to test "fail later" at RECOVER stage here.  Make sure
14646cf56a87SPeter Xu          * both QEMU instances will go into RECOVER stage first, then test
14656cf56a87SPeter Xu          * kicking them out using migrate-pause.
14666cf56a87SPeter Xu          *
14676cf56a87SPeter Xu          * Explicitly check the RECOVER event on src, that's what Libvirt
14686cf56a87SPeter Xu          * relies on, rather than polling.
14696cf56a87SPeter Xu          */
14706cf56a87SPeter Xu         migration_event_wait(from, "postcopy-recover");
14717bca2bb7SFabiano Rosas         wait_for_postcopy_status(from, "postcopy-recover");
14726cf56a87SPeter Xu 
14736cf56a87SPeter Xu         /* Need an explicit kick on src QEMU in this case */
14746cf56a87SPeter Xu         migrate_pause(from);
14756cf56a87SPeter Xu     }
14766cf56a87SPeter Xu 
14776cf56a87SPeter Xu     /*
14786cf56a87SPeter Xu      * For all failure cases, we'll reach such states on both sides now.
14796cf56a87SPeter Xu      * Check them.
14806cf56a87SPeter Xu      */
14816cf56a87SPeter Xu     wait_for_postcopy_status(from, "postcopy-paused");
14827bca2bb7SFabiano Rosas     wait_for_postcopy_status(to, "postcopy-recover");
14837bca2bb7SFabiano Rosas 
14847bca2bb7SFabiano Rosas     /*
14856cf56a87SPeter Xu      * Kick dest QEMU out too. This is normally not needed in reality
14866cf56a87SPeter Xu      * because when the channel is shutdown it should also happen on src.
14876cf56a87SPeter Xu      * However here we used separate socket pairs so we need to do that
14886cf56a87SPeter Xu      * explicitly.
14897bca2bb7SFabiano Rosas      */
14907bca2bb7SFabiano Rosas     migrate_pause(to);
14917bca2bb7SFabiano Rosas     wait_for_postcopy_status(to, "postcopy-paused");
14927bca2bb7SFabiano Rosas 
14937bca2bb7SFabiano Rosas     close(pair1[0]);
14947bca2bb7SFabiano Rosas     close(pair2[0]);
14957bca2bb7SFabiano Rosas     close(pair2[1]);
14966cf56a87SPeter Xu 
14976cf56a87SPeter Xu     if (stage != POSTCOPY_FAIL_CHANNEL_ESTABLISH) {
14986cf56a87SPeter Xu         close(pair1[1]);
14996cf56a87SPeter Xu     }
15000fd39735SPeter Xu #endif
15017bca2bb7SFabiano Rosas }
15027bca2bb7SFabiano Rosas 
test_postcopy_recovery_common(MigrateCommon * args)1503767fa9cfSPeter Xu static void test_postcopy_recovery_common(MigrateCommon *args)
15041e8a1faeSThomas Huth {
15051e8a1faeSThomas Huth     QTestState *from, *to;
1506ff7b9b56SPeter Maydell     g_autofree char *uri = NULL;
15071e8a1faeSThomas Huth 
1508767fa9cfSPeter Xu     /* Always hide errors for postcopy recover tests since they're expected */
1509767fa9cfSPeter Xu     args->start.hide_stderr = true;
1510767fa9cfSPeter Xu 
1511767fa9cfSPeter Xu     if (migrate_postcopy_prepare(&from, &to, args)) {
15121e8a1faeSThomas Huth         return;
15131e8a1faeSThomas Huth     }
15141e8a1faeSThomas Huth 
15151e8a1faeSThomas Huth     /* Turn postcopy speed down, 4K/s is slow enough on any machines */
15161e8a1faeSThomas Huth     migrate_set_parameter_int(from, "max-postcopy-bandwidth", 4096);
15171e8a1faeSThomas Huth 
15181e8a1faeSThomas Huth     /* Now we start the postcopy */
15191e8a1faeSThomas Huth     migrate_postcopy_start(from, to);
15201e8a1faeSThomas Huth 
15211e8a1faeSThomas Huth     /*
15221e8a1faeSThomas Huth      * Wait until postcopy is really started; we can only run the
15231e8a1faeSThomas Huth      * migrate-pause command during a postcopy
15241e8a1faeSThomas Huth      */
15251e8a1faeSThomas Huth     wait_for_migration_status(from, "postcopy-active", NULL);
15261e8a1faeSThomas Huth 
15271e8a1faeSThomas Huth     /*
15281e8a1faeSThomas Huth      * Manually stop the postcopy migration. This emulates a network
15291e8a1faeSThomas Huth      * failure with the migration socket
15301e8a1faeSThomas Huth      */
15311e8a1faeSThomas Huth     migrate_pause(from);
15321e8a1faeSThomas Huth 
15331e8a1faeSThomas Huth     /*
15341e8a1faeSThomas Huth      * Wait for destination side to reach postcopy-paused state.  The
15351e8a1faeSThomas Huth      * migrate-recover command can only succeed if destination machine
15361e8a1faeSThomas Huth      * is in the paused state
15371e8a1faeSThomas Huth      */
15387bca2bb7SFabiano Rosas     wait_for_postcopy_status(to, "postcopy-paused");
15397bca2bb7SFabiano Rosas     wait_for_postcopy_status(from, "postcopy-paused");
15407bca2bb7SFabiano Rosas 
15416cf56a87SPeter Xu     if (args->postcopy_recovery_fail_stage) {
15427bca2bb7SFabiano Rosas         /*
15437bca2bb7SFabiano Rosas          * Test when a wrong socket specified for recover, and then the
15447bca2bb7SFabiano Rosas          * ability to kick it out, and continue with a correct socket.
15457bca2bb7SFabiano Rosas          */
15466cf56a87SPeter Xu         postcopy_recover_fail(from, to, args->postcopy_recovery_fail_stage);
15477bca2bb7SFabiano Rosas         /* continue with a good recovery */
15487bca2bb7SFabiano Rosas     }
15491e8a1faeSThomas Huth 
15501e8a1faeSThomas Huth     /*
15511e8a1faeSThomas Huth      * Create a new socket to emulate a new channel that is different
15521e8a1faeSThomas Huth      * from the broken migration channel; tell the destination to
15531e8a1faeSThomas Huth      * listen to the new port
15541e8a1faeSThomas Huth      */
15551e8a1faeSThomas Huth     uri = g_strdup_printf("unix:%s/migsocket-recover", tmpfs);
15561e8a1faeSThomas Huth     migrate_recover(to, uri);
15571e8a1faeSThomas Huth 
15581e8a1faeSThomas Huth     /*
15591e8a1faeSThomas Huth      * Try to rebuild the migration channel using the resume flag and
15601e8a1faeSThomas Huth      * the newly created channel
15611e8a1faeSThomas Huth      */
1562d5ee387dSHet Gala     migrate_qmp(from, to, uri, NULL, "{'resume': true}");
15631e8a1faeSThomas Huth 
15641e8a1faeSThomas Huth     /* Restore the postcopy bandwidth to unlimited */
15651e8a1faeSThomas Huth     migrate_set_parameter_int(from, "max-postcopy-bandwidth", 0);
15661e8a1faeSThomas Huth 
1567767fa9cfSPeter Xu     migrate_postcopy_complete(from, to, args);
15681e8a1faeSThomas Huth }
15691e8a1faeSThomas Huth 
test_postcopy_recovery(void)1570767fa9cfSPeter Xu static void test_postcopy_recovery(void)
1571767fa9cfSPeter Xu {
1572767fa9cfSPeter Xu     MigrateCommon args = { };
1573767fa9cfSPeter Xu 
1574767fa9cfSPeter Xu     test_postcopy_recovery_common(&args);
1575767fa9cfSPeter Xu }
1576767fa9cfSPeter Xu 
test_postcopy_recovery_fail_handshake(void)15776cf56a87SPeter Xu static void test_postcopy_recovery_fail_handshake(void)
15787bca2bb7SFabiano Rosas {
15797bca2bb7SFabiano Rosas     MigrateCommon args = {
15806cf56a87SPeter Xu         .postcopy_recovery_fail_stage = POSTCOPY_FAIL_RECOVERY,
15816cf56a87SPeter Xu     };
15826cf56a87SPeter Xu 
15836cf56a87SPeter Xu     test_postcopy_recovery_common(&args);
15846cf56a87SPeter Xu }
15856cf56a87SPeter Xu 
test_postcopy_recovery_fail_reconnect(void)15866cf56a87SPeter Xu static void test_postcopy_recovery_fail_reconnect(void)
15876cf56a87SPeter Xu {
15886cf56a87SPeter Xu     MigrateCommon args = {
15896cf56a87SPeter Xu         .postcopy_recovery_fail_stage = POSTCOPY_FAIL_CHANNEL_ESTABLISH,
15907bca2bb7SFabiano Rosas     };
15917bca2bb7SFabiano Rosas 
15927bca2bb7SFabiano Rosas     test_postcopy_recovery_common(&args);
15937bca2bb7SFabiano Rosas }
15947bca2bb7SFabiano Rosas 
1595767fa9cfSPeter Xu #ifdef CONFIG_GNUTLS
test_postcopy_recovery_tls_psk(void)1596767fa9cfSPeter Xu static void test_postcopy_recovery_tls_psk(void)
1597767fa9cfSPeter Xu {
1598767fa9cfSPeter Xu     MigrateCommon args = {
1599767fa9cfSPeter Xu         .start_hook = test_migrate_tls_psk_start_match,
1600767fa9cfSPeter Xu         .finish_hook = test_migrate_tls_psk_finish,
1601767fa9cfSPeter Xu     };
1602767fa9cfSPeter Xu 
1603767fa9cfSPeter Xu     test_postcopy_recovery_common(&args);
1604767fa9cfSPeter Xu }
1605767fa9cfSPeter Xu #endif
1606767fa9cfSPeter Xu 
test_postcopy_preempt_recovery(void)16078f6fe915SPeter Xu static void test_postcopy_preempt_recovery(void)
16088f6fe915SPeter Xu {
16098f6fe915SPeter Xu     MigrateCommon args = {
16108f6fe915SPeter Xu         .postcopy_preempt = true,
16118f6fe915SPeter Xu     };
16128f6fe915SPeter Xu 
16138f6fe915SPeter Xu     test_postcopy_recovery_common(&args);
16148f6fe915SPeter Xu }
16158f6fe915SPeter Xu 
16168f6fe915SPeter Xu #ifdef CONFIG_GNUTLS
16178f6fe915SPeter Xu /* This contains preempt+recovery+tls test altogether */
test_postcopy_preempt_all(void)16188f6fe915SPeter Xu static void test_postcopy_preempt_all(void)
16198f6fe915SPeter Xu {
16208f6fe915SPeter Xu     MigrateCommon args = {
16218f6fe915SPeter Xu         .postcopy_preempt = true,
16228f6fe915SPeter Xu         .start_hook = test_migrate_tls_psk_start_match,
16238f6fe915SPeter Xu         .finish_hook = test_migrate_tls_psk_finish,
16248f6fe915SPeter Xu     };
16258f6fe915SPeter Xu 
16268f6fe915SPeter Xu     test_postcopy_recovery_common(&args);
16278f6fe915SPeter Xu }
1628dc066da8SLukas Straub 
16298f6fe915SPeter Xu #endif
16308f6fe915SPeter Xu 
test_baddest(void)16311e8a1faeSThomas Huth static void test_baddest(void)
16321e8a1faeSThomas Huth {
163319da6edfSDaniel P. Berrangé     MigrateStart args = {
163419da6edfSDaniel P. Berrangé         .hide_stderr = true
163519da6edfSDaniel P. Berrangé     };
16361e8a1faeSThomas Huth     QTestState *from, *to;
16371e8a1faeSThomas Huth 
16383ff57401SPeter Xu     if (test_migrate_start(&from, &to, "tcp:127.0.0.1:0", &args)) {
16391e8a1faeSThomas Huth         return;
16401e8a1faeSThomas Huth     }
1641d5ee387dSHet Gala     migrate_qmp(from, to, "tcp:127.0.0.1:0", NULL, "{}");
16421e8a1faeSThomas Huth     wait_for_migration_fail(from, false);
16431e8a1faeSThomas Huth     test_migrate_end(from, to, false);
16441e8a1faeSThomas Huth }
16451e8a1faeSThomas Huth 
1646d864756eSFabiano Rosas #ifndef _WIN32
test_analyze_script(void)1647d864756eSFabiano Rosas static void test_analyze_script(void)
1648d864756eSFabiano Rosas {
1649d864756eSFabiano Rosas     MigrateStart args = {
1650d864756eSFabiano Rosas         .opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
1651d864756eSFabiano Rosas     };
1652d864756eSFabiano Rosas     QTestState *from, *to;
1653d864756eSFabiano Rosas     g_autofree char *uri = NULL;
1654d864756eSFabiano Rosas     g_autofree char *file = NULL;
1655d864756eSFabiano Rosas     int pid, wstatus;
1656d864756eSFabiano Rosas     const char *python = g_getenv("PYTHON");
1657d864756eSFabiano Rosas 
1658d864756eSFabiano Rosas     if (!python) {
1659d864756eSFabiano Rosas         g_test_skip("PYTHON variable not set");
1660d864756eSFabiano Rosas         return;
1661d864756eSFabiano Rosas     }
1662d864756eSFabiano Rosas 
1663d864756eSFabiano Rosas     /* dummy url */
1664d864756eSFabiano Rosas     if (test_migrate_start(&from, &to, "tcp:127.0.0.1:0", &args)) {
1665d864756eSFabiano Rosas         return;
1666d864756eSFabiano Rosas     }
1667d864756eSFabiano Rosas 
1668d864756eSFabiano Rosas     /*
1669d864756eSFabiano Rosas      * Setting these two capabilities causes the "configuration"
1670d864756eSFabiano Rosas      * vmstate to include subsections for them. The script needs to
1671d864756eSFabiano Rosas      * parse those subsections properly.
1672d864756eSFabiano Rosas      */
1673d864756eSFabiano Rosas     migrate_set_capability(from, "validate-uuid", true);
1674d864756eSFabiano Rosas     migrate_set_capability(from, "x-ignore-shared", true);
1675d864756eSFabiano Rosas 
1676d864756eSFabiano Rosas     file = g_strdup_printf("%s/migfile", tmpfs);
1677d864756eSFabiano Rosas     uri = g_strdup_printf("exec:cat > %s", file);
1678d864756eSFabiano Rosas 
1679d864756eSFabiano Rosas     migrate_ensure_converge(from);
1680d5ee387dSHet Gala     migrate_qmp(from, to, uri, NULL, "{}");
1681d864756eSFabiano Rosas     wait_for_migration_complete(from);
1682d864756eSFabiano Rosas 
1683d864756eSFabiano Rosas     pid = fork();
1684d864756eSFabiano Rosas     if (!pid) {
1685d864756eSFabiano Rosas         close(1);
1686d864756eSFabiano Rosas         open("/dev/null", O_WRONLY);
1687d864756eSFabiano Rosas         execl(python, python, ANALYZE_SCRIPT, "-f", file, NULL);
1688d864756eSFabiano Rosas         g_assert_not_reached();
1689d864756eSFabiano Rosas     }
1690d864756eSFabiano Rosas 
1691d864756eSFabiano Rosas     g_assert(waitpid(pid, &wstatus, 0) == pid);
16928f023a0bSThomas Huth     if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0) {
1693d864756eSFabiano Rosas         g_test_message("Failed to analyze the migration stream");
1694d864756eSFabiano Rosas         g_test_fail();
1695d864756eSFabiano Rosas     }
1696d864756eSFabiano Rosas     test_migrate_end(from, to, false);
1697d864756eSFabiano Rosas     cleanup("migfile");
1698d864756eSFabiano Rosas }
1699d864756eSFabiano Rosas #endif
1700d864756eSFabiano Rosas 
test_precopy_common(MigrateCommon * args)1701ffed54f6SDaniel P. Berrangé static void test_precopy_common(MigrateCommon *args)
17021e8a1faeSThomas Huth {
17031e8a1faeSThomas Huth     QTestState *from, *to;
1704b3caa7b5SDaniel P. Berrangé     void *data_hook = NULL;
17051e8a1faeSThomas Huth 
1706ffed54f6SDaniel P. Berrangé     if (test_migrate_start(&from, &to, args->listen_uri, &args->start)) {
17071e8a1faeSThomas Huth         return;
17081e8a1faeSThomas Huth     }
17091e8a1faeSThomas Huth 
1710b3caa7b5SDaniel P. Berrangé     if (args->start_hook) {
1711b3caa7b5SDaniel P. Berrangé         data_hook = args->start_hook(from, to);
1712b3caa7b5SDaniel P. Berrangé     }
1713b3caa7b5SDaniel P. Berrangé 
17141e8a1faeSThomas Huth     /* Wait for the first serial output from the source */
1715e25636a1SThomas Huth     if (args->result == MIG_TEST_SUCCEED) {
17161e8a1faeSThomas Huth         wait_for_serial("src_serial");
1717b1fdd21eSSteve Sistare         wait_for_suspend(from, &src_state);
1718e25636a1SThomas Huth     }
17191e8a1faeSThomas Huth 
17203c4fb177SDaniel P. Berrangé     if (args->live) {
17213c4fb177SDaniel P. Berrangé         migrate_ensure_non_converge(from);
1722e02f56e3SDaniel P. Berrangé         migrate_prepare_for_dirty_mem(from);
17233c4fb177SDaniel P. Berrangé     } else {
17243c4fb177SDaniel P. Berrangé         /*
17253c4fb177SDaniel P. Berrangé          * Testing non-live migration, we allow it to run at
17263c4fb177SDaniel P. Berrangé          * full speed to ensure short test case duration.
17273c4fb177SDaniel P. Berrangé          * For tests expected to fail, we don't need to
17283c4fb177SDaniel P. Berrangé          * change anything.
17293c4fb177SDaniel P. Berrangé          */
17303c4fb177SDaniel P. Berrangé         if (args->result == MIG_TEST_SUCCEED) {
17313c4fb177SDaniel P. Berrangé             qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}");
1732f0649758SSteve Sistare             wait_for_stop(from, &src_state);
17333c4fb177SDaniel P. Berrangé             migrate_ensure_converge(from);
17343c4fb177SDaniel P. Berrangé         }
17353c4fb177SDaniel P. Berrangé     }
17363c4fb177SDaniel P. Berrangé 
17375274274cSFabiano Rosas     if (args->result == MIG_TEST_QMP_ERROR) {
1738bc6307a5SHet Gala         migrate_qmp_fail(from, args->connect_uri, args->connect_channels, "{}");
17395274274cSFabiano Rosas         goto finish;
17405274274cSFabiano Rosas     }
17415274274cSFabiano Rosas 
17429d36d62cSHet Gala     migrate_qmp(from, to, args->connect_uri, args->connect_channels, "{}");
17431e8a1faeSThomas Huth 
174400fbe7f6SDaniel P. Berrangé     if (args->result != MIG_TEST_SUCCEED) {
174500fbe7f6SDaniel P. Berrangé         bool allow_active = args->result == MIG_TEST_FAIL;
174600fbe7f6SDaniel P. Berrangé         wait_for_migration_fail(from, allow_active);
174700fbe7f6SDaniel P. Berrangé 
174800fbe7f6SDaniel P. Berrangé         if (args->result == MIG_TEST_FAIL_DEST_QUIT_ERR) {
17491b0f1b14SBin Meng             qtest_set_expected_status(to, EXIT_FAILURE);
175000fbe7f6SDaniel P. Berrangé         }
175100fbe7f6SDaniel P. Berrangé     } else {
17523c4fb177SDaniel P. Berrangé         if (args->live) {
1753e02f56e3SDaniel P. Berrangé             /*
1754e02f56e3SDaniel P. Berrangé              * For initial iteration(s) we must do a full pass,
1755e02f56e3SDaniel P. Berrangé              * but for the final iteration, we need only wait
1756e02f56e3SDaniel P. Berrangé              * for some dirty mem before switching to converge
1757e02f56e3SDaniel P. Berrangé              */
1758e02f56e3SDaniel P. Berrangé             while (args->iterations > 1) {
17591e8a1faeSThomas Huth                 wait_for_migration_pass(from);
1760e02f56e3SDaniel P. Berrangé                 args->iterations--;
176183bcba1eSDaniel P. Berrangé             }
1762e02f56e3SDaniel P. Berrangé             migrate_wait_for_dirty_mem(from, to);
17631e8a1faeSThomas Huth 
1764886dfe9dSDaniel P. Berrangé             migrate_ensure_converge(from);
17651e8a1faeSThomas Huth 
17663c4fb177SDaniel P. Berrangé             /*
17673c4fb177SDaniel P. Berrangé              * We do this first, as it has a timeout to stop us
17683c4fb177SDaniel P. Berrangé              * hanging forever if migration didn't converge
17693c4fb177SDaniel P. Berrangé              */
17708d4e897aSDaniel P. Berrangé             wait_for_migration_complete(from);
17718d4e897aSDaniel P. Berrangé 
1772f0649758SSteve Sistare             wait_for_stop(from, &src_state);
1773f0649758SSteve Sistare 
17743c4fb177SDaniel P. Berrangé         } else {
17753c4fb177SDaniel P. Berrangé             wait_for_migration_complete(from);
17763c4fb177SDaniel P. Berrangé             /*
17773c4fb177SDaniel P. Berrangé              * Must wait for dst to finish reading all incoming
17783c4fb177SDaniel P. Berrangé              * data on the socket before issuing 'cont' otherwise
17793c4fb177SDaniel P. Berrangé              * it'll be ignored
17803c4fb177SDaniel P. Berrangé              */
17813c4fb177SDaniel P. Berrangé             wait_for_migration_complete(to);
17821e8a1faeSThomas Huth 
17833c4fb177SDaniel P. Berrangé             qtest_qmp_assert_success(to, "{ 'execute' : 'cont'}");
17843c4fb177SDaniel P. Berrangé         }
17853c4fb177SDaniel P. Berrangé 
1786f0649758SSteve Sistare         wait_for_resume(to, &dst_state);
17871e8a1faeSThomas Huth 
1788b1fdd21eSSteve Sistare         if (args->start.suspend_me) {
1789b1fdd21eSSteve Sistare             /* wakeup succeeds only if guest is suspended */
1790b1fdd21eSSteve Sistare             qtest_qmp_assert_success(to, "{'execute': 'system_wakeup'}");
1791b1fdd21eSSteve Sistare         }
1792b1fdd21eSSteve Sistare 
17931e8a1faeSThomas Huth         wait_for_serial("dest_serial");
179400fbe7f6SDaniel P. Berrangé     }
17951e8a1faeSThomas Huth 
17965274274cSFabiano Rosas finish:
1797b3caa7b5SDaniel P. Berrangé     if (args->finish_hook) {
1798b3caa7b5SDaniel P. Berrangé         args->finish_hook(from, to, data_hook);
1799b3caa7b5SDaniel P. Berrangé     }
1800b3caa7b5SDaniel P. Berrangé 
180100fbe7f6SDaniel P. Berrangé     test_migrate_end(from, to, args->result == MIG_TEST_SUCCEED);
18021e8a1faeSThomas Huth }
18031e8a1faeSThomas Huth 
file_dirty_offset_region(void)180455fc0c2fSFabiano Rosas static void file_dirty_offset_region(void)
180555fc0c2fSFabiano Rosas {
180655fc0c2fSFabiano Rosas     g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
180755fc0c2fSFabiano Rosas     size_t size = FILE_TEST_OFFSET;
180855fc0c2fSFabiano Rosas     g_autofree char *data = g_new0(char, size);
180955fc0c2fSFabiano Rosas 
181055fc0c2fSFabiano Rosas     memset(data, FILE_TEST_MARKER, size);
181155fc0c2fSFabiano Rosas     g_assert(g_file_set_contents(path, data, size, NULL));
181255fc0c2fSFabiano Rosas }
181355fc0c2fSFabiano Rosas 
file_check_offset_region(void)181455fc0c2fSFabiano Rosas static void file_check_offset_region(void)
181555fc0c2fSFabiano Rosas {
181655fc0c2fSFabiano Rosas     g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
181755fc0c2fSFabiano Rosas     size_t size = FILE_TEST_OFFSET;
181855fc0c2fSFabiano Rosas     g_autofree char *expected = g_new0(char, size);
181955fc0c2fSFabiano Rosas     g_autofree char *actual = NULL;
182055fc0c2fSFabiano Rosas     uint64_t *stream_start;
182155fc0c2fSFabiano Rosas 
182255fc0c2fSFabiano Rosas     /*
182355fc0c2fSFabiano Rosas      * Ensure the skipped offset region's data has not been touched
182455fc0c2fSFabiano Rosas      * and the migration stream starts at the right place.
182555fc0c2fSFabiano Rosas      */
182655fc0c2fSFabiano Rosas 
182755fc0c2fSFabiano Rosas     memset(expected, FILE_TEST_MARKER, size);
182855fc0c2fSFabiano Rosas 
182955fc0c2fSFabiano Rosas     g_assert(g_file_get_contents(path, &actual, NULL, NULL));
183055fc0c2fSFabiano Rosas     g_assert(!memcmp(actual, expected, size));
183155fc0c2fSFabiano Rosas 
183255fc0c2fSFabiano Rosas     stream_start = (uint64_t *)(actual + size);
183355fc0c2fSFabiano Rosas     g_assert_cmpint(cpu_to_be64(*stream_start) >> 32, ==, QEMU_VM_FILE_MAGIC);
183455fc0c2fSFabiano Rosas }
183555fc0c2fSFabiano Rosas 
test_file_common(MigrateCommon * args,bool stop_src)18363dc35470SFabiano Rosas static void test_file_common(MigrateCommon *args, bool stop_src)
18373dc35470SFabiano Rosas {
18383dc35470SFabiano Rosas     QTestState *from, *to;
18393dc35470SFabiano Rosas     void *data_hook = NULL;
184055fc0c2fSFabiano Rosas     bool check_offset = false;
18413dc35470SFabiano Rosas 
18423dc35470SFabiano Rosas     if (test_migrate_start(&from, &to, args->listen_uri, &args->start)) {
18433dc35470SFabiano Rosas         return;
18443dc35470SFabiano Rosas     }
18453dc35470SFabiano Rosas 
18463dc35470SFabiano Rosas     /*
18473dc35470SFabiano Rosas      * File migration is never live. We can keep the source VM running
18483dc35470SFabiano Rosas      * during migration, but the destination will not be running
18493dc35470SFabiano Rosas      * concurrently.
18503dc35470SFabiano Rosas      */
18513dc35470SFabiano Rosas     g_assert_false(args->live);
18523dc35470SFabiano Rosas 
185355fc0c2fSFabiano Rosas     if (g_strrstr(args->connect_uri, "offset=")) {
185455fc0c2fSFabiano Rosas         check_offset = true;
185555fc0c2fSFabiano Rosas         /*
185655fc0c2fSFabiano Rosas          * This comes before the start_hook because it's equivalent to
185755fc0c2fSFabiano Rosas          * a management application creating the file and writing to
185855fc0c2fSFabiano Rosas          * it so hooks should expect the file to be already present.
185955fc0c2fSFabiano Rosas          */
186055fc0c2fSFabiano Rosas         file_dirty_offset_region();
186155fc0c2fSFabiano Rosas     }
186255fc0c2fSFabiano Rosas 
18633dc35470SFabiano Rosas     if (args->start_hook) {
18643dc35470SFabiano Rosas         data_hook = args->start_hook(from, to);
18653dc35470SFabiano Rosas     }
18663dc35470SFabiano Rosas 
18673dc35470SFabiano Rosas     migrate_ensure_converge(from);
18683dc35470SFabiano Rosas     wait_for_serial("src_serial");
18693dc35470SFabiano Rosas 
18703dc35470SFabiano Rosas     if (stop_src) {
18713dc35470SFabiano Rosas         qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}");
1872f0649758SSteve Sistare         wait_for_stop(from, &src_state);
18733dc35470SFabiano Rosas     }
18743dc35470SFabiano Rosas 
18753dc35470SFabiano Rosas     if (args->result == MIG_TEST_QMP_ERROR) {
1876387dc407SHet Gala         migrate_qmp_fail(from, args->connect_uri, NULL, "{}");
18773dc35470SFabiano Rosas         goto finish;
18783dc35470SFabiano Rosas     }
18793dc35470SFabiano Rosas 
1880d5ee387dSHet Gala     migrate_qmp(from, to, args->connect_uri, NULL, "{}");
18813dc35470SFabiano Rosas     wait_for_migration_complete(from);
18823dc35470SFabiano Rosas 
18833dc35470SFabiano Rosas     /*
18843dc35470SFabiano Rosas      * We need to wait for the source to finish before starting the
18853dc35470SFabiano Rosas      * destination.
18863dc35470SFabiano Rosas      */
1887d1155fd4SHet Gala     migrate_incoming_qmp(to, args->connect_uri, "{}");
18883dc35470SFabiano Rosas     wait_for_migration_complete(to);
18893dc35470SFabiano Rosas 
18903dc35470SFabiano Rosas     if (stop_src) {
18913dc35470SFabiano Rosas         qtest_qmp_assert_success(to, "{ 'execute' : 'cont'}");
18923dc35470SFabiano Rosas     }
1893f0649758SSteve Sistare     wait_for_resume(to, &dst_state);
18943dc35470SFabiano Rosas 
18953dc35470SFabiano Rosas     wait_for_serial("dest_serial");
18963dc35470SFabiano Rosas 
189755fc0c2fSFabiano Rosas     if (check_offset) {
189855fc0c2fSFabiano Rosas         file_check_offset_region();
189955fc0c2fSFabiano Rosas     }
190055fc0c2fSFabiano Rosas 
19013dc35470SFabiano Rosas finish:
19023dc35470SFabiano Rosas     if (args->finish_hook) {
19033dc35470SFabiano Rosas         args->finish_hook(from, to, data_hook);
19043dc35470SFabiano Rosas     }
19053dc35470SFabiano Rosas 
19063dc35470SFabiano Rosas     test_migrate_end(from, to, args->result == MIG_TEST_SUCCEED);
19073dc35470SFabiano Rosas }
19083dc35470SFabiano Rosas 
test_precopy_unix_plain(void)190958d25e97SDaniel P. Berrangé static void test_precopy_unix_plain(void)
19101f546b70SPeter Xu {
1911ffed54f6SDaniel P. Berrangé     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
1912ffed54f6SDaniel P. Berrangé     MigrateCommon args = {
1913ffed54f6SDaniel P. Berrangé         .listen_uri = uri,
1914ffed54f6SDaniel P. Berrangé         .connect_uri = uri,
1915b861383cSPeter Xu         /*
1916b861383cSPeter Xu          * The simplest use case of precopy, covering smoke tests of
1917b861383cSPeter Xu          * get-dirty-log dirty tracking.
1918b861383cSPeter Xu          */
19193c4fb177SDaniel P. Berrangé         .live = true,
1920ffed54f6SDaniel P. Berrangé     };
1921ffed54f6SDaniel P. Berrangé 
1922ffed54f6SDaniel P. Berrangé     test_precopy_common(&args);
19231f546b70SPeter Xu }
19241f546b70SPeter Xu 
test_precopy_unix_suspend_live(void)1925b1fdd21eSSteve Sistare static void test_precopy_unix_suspend_live(void)
1926b1fdd21eSSteve Sistare {
1927b1fdd21eSSteve Sistare     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
1928b1fdd21eSSteve Sistare     MigrateCommon args = {
1929b1fdd21eSSteve Sistare         .listen_uri = uri,
1930b1fdd21eSSteve Sistare         .connect_uri = uri,
1931b1fdd21eSSteve Sistare         /*
1932b1fdd21eSSteve Sistare          * despite being live, the test is fast because the src
1933b1fdd21eSSteve Sistare          * suspends immediately.
1934b1fdd21eSSteve Sistare          */
1935b1fdd21eSSteve Sistare         .live = true,
1936b1fdd21eSSteve Sistare         .start.suspend_me = true,
1937b1fdd21eSSteve Sistare     };
1938b1fdd21eSSteve Sistare 
1939b1fdd21eSSteve Sistare     test_precopy_common(&args);
1940b1fdd21eSSteve Sistare }
1941b1fdd21eSSteve Sistare 
test_precopy_unix_suspend_notlive(void)1942b1fdd21eSSteve Sistare static void test_precopy_unix_suspend_notlive(void)
1943b1fdd21eSSteve Sistare {
1944b1fdd21eSSteve Sistare     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
1945b1fdd21eSSteve Sistare     MigrateCommon args = {
1946b1fdd21eSSteve Sistare         .listen_uri = uri,
1947b1fdd21eSSteve Sistare         .connect_uri = uri,
1948b1fdd21eSSteve Sistare         .start.suspend_me = true,
1949b1fdd21eSSteve Sistare     };
1950b1fdd21eSSteve Sistare 
1951b1fdd21eSSteve Sistare     test_precopy_common(&args);
1952b1fdd21eSSteve Sistare }
195358d25e97SDaniel P. Berrangé 
test_precopy_unix_dirty_ring(void)19541f546b70SPeter Xu static void test_precopy_unix_dirty_ring(void)
19551f546b70SPeter Xu {
1956ffed54f6SDaniel P. Berrangé     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
1957ffed54f6SDaniel P. Berrangé     MigrateCommon args = {
1958ffed54f6SDaniel P. Berrangé         .start = {
1959ffed54f6SDaniel P. Berrangé             .use_dirty_ring = true,
1960ffed54f6SDaniel P. Berrangé         },
1961ffed54f6SDaniel P. Berrangé         .listen_uri = uri,
1962ffed54f6SDaniel P. Berrangé         .connect_uri = uri,
1963b861383cSPeter Xu         /*
1964b861383cSPeter Xu          * Besides the precopy/unix basic test, cover dirty ring interface
1965b861383cSPeter Xu          * rather than get-dirty-log.
1966b861383cSPeter Xu          */
19673c4fb177SDaniel P. Berrangé         .live = true,
1968ffed54f6SDaniel P. Berrangé     };
1969ffed54f6SDaniel P. Berrangé 
1970ffed54f6SDaniel P. Berrangé     test_precopy_common(&args);
19711f546b70SPeter Xu }
19721f546b70SPeter Xu 
1973d47b83b1SDaniel P. Berrangé #ifdef CONFIG_GNUTLS
test_precopy_unix_tls_psk(void)1974d47b83b1SDaniel P. Berrangé static void test_precopy_unix_tls_psk(void)
1975d47b83b1SDaniel P. Berrangé {
1976d47b83b1SDaniel P. Berrangé     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
1977d47b83b1SDaniel P. Berrangé     MigrateCommon args = {
1978d47b83b1SDaniel P. Berrangé         .connect_uri = uri,
1979d47b83b1SDaniel P. Berrangé         .listen_uri = uri,
1980d47b83b1SDaniel P. Berrangé         .start_hook = test_migrate_tls_psk_start_match,
1981d47b83b1SDaniel P. Berrangé         .finish_hook = test_migrate_tls_psk_finish,
1982d47b83b1SDaniel P. Berrangé     };
1983d47b83b1SDaniel P. Berrangé 
1984d47b83b1SDaniel P. Berrangé     test_precopy_common(&args);
1985d47b83b1SDaniel P. Berrangé }
1986d47b83b1SDaniel P. Berrangé 
1987d47b83b1SDaniel P. Berrangé #ifdef CONFIG_TASN1
test_precopy_unix_tls_x509_default_host(void)1988d47b83b1SDaniel P. Berrangé static void test_precopy_unix_tls_x509_default_host(void)
1989d47b83b1SDaniel P. Berrangé {
1990d47b83b1SDaniel P. Berrangé     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
1991d47b83b1SDaniel P. Berrangé     MigrateCommon args = {
1992d47b83b1SDaniel P. Berrangé         .start = {
1993d47b83b1SDaniel P. Berrangé             .hide_stderr = true,
1994d47b83b1SDaniel P. Berrangé         },
1995d47b83b1SDaniel P. Berrangé         .connect_uri = uri,
1996d47b83b1SDaniel P. Berrangé         .listen_uri = uri,
1997d47b83b1SDaniel P. Berrangé         .start_hook = test_migrate_tls_x509_start_default_host,
1998d47b83b1SDaniel P. Berrangé         .finish_hook = test_migrate_tls_x509_finish,
1999d47b83b1SDaniel P. Berrangé         .result = MIG_TEST_FAIL_DEST_QUIT_ERR,
2000d47b83b1SDaniel P. Berrangé     };
2001d47b83b1SDaniel P. Berrangé 
2002d47b83b1SDaniel P. Berrangé     test_precopy_common(&args);
2003d47b83b1SDaniel P. Berrangé }
2004d47b83b1SDaniel P. Berrangé 
test_precopy_unix_tls_x509_override_host(void)2005d47b83b1SDaniel P. Berrangé static void test_precopy_unix_tls_x509_override_host(void)
2006d47b83b1SDaniel P. Berrangé {
2007d47b83b1SDaniel P. Berrangé     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
2008d47b83b1SDaniel P. Berrangé     MigrateCommon args = {
2009d47b83b1SDaniel P. Berrangé         .connect_uri = uri,
2010d47b83b1SDaniel P. Berrangé         .listen_uri = uri,
2011d47b83b1SDaniel P. Berrangé         .start_hook = test_migrate_tls_x509_start_override_host,
2012d47b83b1SDaniel P. Berrangé         .finish_hook = test_migrate_tls_x509_finish,
2013d47b83b1SDaniel P. Berrangé     };
2014d47b83b1SDaniel P. Berrangé 
2015d47b83b1SDaniel P. Berrangé     test_precopy_common(&args);
2016d47b83b1SDaniel P. Berrangé }
2017d47b83b1SDaniel P. Berrangé #endif /* CONFIG_TASN1 */
2018d47b83b1SDaniel P. Berrangé #endif /* CONFIG_GNUTLS */
2019d47b83b1SDaniel P. Berrangé 
20201e8a1faeSThomas Huth #if 0
20211e8a1faeSThomas Huth /* Currently upset on aarch64 TCG */
20221e8a1faeSThomas Huth static void test_ignore_shared(void)
20231e8a1faeSThomas Huth {
2024ff7b9b56SPeter Maydell     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
20251e8a1faeSThomas Huth     QTestState *from, *to;
20261e8a1faeSThomas Huth 
20271e8a1faeSThomas Huth     if (test_migrate_start(&from, &to, uri, false, true, NULL, NULL)) {
20281e8a1faeSThomas Huth         return;
20291e8a1faeSThomas Huth     }
20301e8a1faeSThomas Huth 
2031e02f56e3SDaniel P. Berrangé     migrate_ensure_non_converge(from);
2032e02f56e3SDaniel P. Berrangé     migrate_prepare_for_dirty_mem(from);
2033e02f56e3SDaniel P. Berrangé 
20341e8a1faeSThomas Huth     migrate_set_capability(from, "x-ignore-shared", true);
20351e8a1faeSThomas Huth     migrate_set_capability(to, "x-ignore-shared", true);
20361e8a1faeSThomas Huth 
20371e8a1faeSThomas Huth     /* Wait for the first serial output from the source */
20381e8a1faeSThomas Huth     wait_for_serial("src_serial");
20391e8a1faeSThomas Huth 
2040d5ee387dSHet Gala     migrate_qmp(from, to, uri, NULL, "{}");
20411e8a1faeSThomas Huth 
2042e02f56e3SDaniel P. Berrangé     migrate_wait_for_dirty_mem(from, to);
20431e8a1faeSThomas Huth 
2044f0649758SSteve Sistare     wait_for_stop(from, &src_state);
20451e8a1faeSThomas Huth 
20461e8a1faeSThomas Huth     qtest_qmp_eventwait(to, "RESUME");
20471e8a1faeSThomas Huth 
20481e8a1faeSThomas Huth     wait_for_serial("dest_serial");
20491e8a1faeSThomas Huth     wait_for_migration_complete(from);
20501e8a1faeSThomas Huth 
20511e8a1faeSThomas Huth     /* Check whether shared RAM has been really skipped */
20521e8a1faeSThomas Huth     g_assert_cmpint(read_ram_property_int(from, "transferred"), <, 1024 * 1024);
20531e8a1faeSThomas Huth 
20541e8a1faeSThomas Huth     test_migrate_end(from, to, true);
20551e8a1faeSThomas Huth }
20561e8a1faeSThomas Huth #endif
20571e8a1faeSThomas Huth 
205883bcba1eSDaniel P. Berrangé static void *
test_migrate_xbzrle_start(QTestState * from,QTestState * to)205983bcba1eSDaniel P. Berrangé test_migrate_xbzrle_start(QTestState *from,
206083bcba1eSDaniel P. Berrangé                           QTestState *to)
20611e8a1faeSThomas Huth {
20621e8a1faeSThomas Huth     migrate_set_parameter_int(from, "xbzrle-cache-size", 33554432);
20631e8a1faeSThomas Huth 
2064a1209bb7SDr. David Alan Gilbert     migrate_set_capability(from, "xbzrle", true);
2065a1209bb7SDr. David Alan Gilbert     migrate_set_capability(to, "xbzrle", true);
20661e8a1faeSThomas Huth 
206783bcba1eSDaniel P. Berrangé     return NULL;
20681e8a1faeSThomas Huth }
20691e8a1faeSThomas Huth 
test_precopy_unix_xbzrle(void)207083bcba1eSDaniel P. Berrangé static void test_precopy_unix_xbzrle(void)
20711e8a1faeSThomas Huth {
2072ff7b9b56SPeter Maydell     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
207383bcba1eSDaniel P. Berrangé     MigrateCommon args = {
207483bcba1eSDaniel P. Berrangé         .connect_uri = uri,
207583bcba1eSDaniel P. Berrangé         .listen_uri = uri,
207683bcba1eSDaniel P. Berrangé         .start_hook = test_migrate_xbzrle_start,
207783bcba1eSDaniel P. Berrangé         .iterations = 2,
2078b861383cSPeter Xu         /*
2079b861383cSPeter Xu          * XBZRLE needs pages to be modified when doing the 2nd+ round
2080b861383cSPeter Xu          * iteration to have real data pushed to the stream.
2081b861383cSPeter Xu          */
20823c4fb177SDaniel P. Berrangé         .live = true,
208383bcba1eSDaniel P. Berrangé     };
208483bcba1eSDaniel P. Berrangé 
208583bcba1eSDaniel P. Berrangé     test_precopy_common(&args);
20861e8a1faeSThomas Huth }
20871e8a1faeSThomas Huth 
test_precopy_file(void)20883dc35470SFabiano Rosas static void test_precopy_file(void)
20893dc35470SFabiano Rosas {
20903dc35470SFabiano Rosas     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
20913dc35470SFabiano Rosas                                            FILE_TEST_FILENAME);
20923dc35470SFabiano Rosas     MigrateCommon args = {
20933dc35470SFabiano Rosas         .connect_uri = uri,
20943dc35470SFabiano Rosas         .listen_uri = "defer",
20953dc35470SFabiano Rosas     };
20963dc35470SFabiano Rosas 
20973dc35470SFabiano Rosas     test_file_common(&args, true);
20983dc35470SFabiano Rosas }
20993dc35470SFabiano Rosas 
2100926554c0SFabiano Rosas #ifndef _WIN32
fdset_add_fds(QTestState * qts,const char * file,int flags,int num_fds,bool direct_io)2101926554c0SFabiano Rosas static void fdset_add_fds(QTestState *qts, const char *file, int flags,
210231a5a303SFabiano Rosas                           int num_fds, bool direct_io)
2103926554c0SFabiano Rosas {
2104926554c0SFabiano Rosas     for (int i = 0; i < num_fds; i++) {
2105926554c0SFabiano Rosas         int fd;
2106926554c0SFabiano Rosas 
210731a5a303SFabiano Rosas #ifdef O_DIRECT
210831a5a303SFabiano Rosas         /* only secondary channels can use direct-io */
210931a5a303SFabiano Rosas         if (direct_io && i != 0) {
211031a5a303SFabiano Rosas             flags |= O_DIRECT;
211131a5a303SFabiano Rosas         }
211231a5a303SFabiano Rosas #endif
211331a5a303SFabiano Rosas 
2114926554c0SFabiano Rosas         fd = open(file, flags, 0660);
2115926554c0SFabiano Rosas         assert(fd != -1);
2116926554c0SFabiano Rosas 
2117926554c0SFabiano Rosas         qtest_qmp_fds_assert_success(qts, &fd, 1, "{'execute': 'add-fd', "
2118926554c0SFabiano Rosas                                      "'arguments': {'fdset-id': 1}}");
2119926554c0SFabiano Rosas         close(fd);
2120926554c0SFabiano Rosas     }
2121926554c0SFabiano Rosas }
2122926554c0SFabiano Rosas 
file_offset_fdset_start_hook(QTestState * from,QTestState * to)2123926554c0SFabiano Rosas static void *file_offset_fdset_start_hook(QTestState *from, QTestState *to)
2124926554c0SFabiano Rosas {
2125926554c0SFabiano Rosas     g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
2126926554c0SFabiano Rosas 
212731a5a303SFabiano Rosas     fdset_add_fds(from, file, O_WRONLY, 1, false);
212831a5a303SFabiano Rosas     fdset_add_fds(to, file, O_RDONLY, 1, false);
2129926554c0SFabiano Rosas 
2130926554c0SFabiano Rosas     return NULL;
2131926554c0SFabiano Rosas }
2132926554c0SFabiano Rosas 
test_precopy_file_offset_fdset(void)2133926554c0SFabiano Rosas static void test_precopy_file_offset_fdset(void)
2134926554c0SFabiano Rosas {
2135926554c0SFabiano Rosas     g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
2136926554c0SFabiano Rosas                                            FILE_TEST_OFFSET);
2137926554c0SFabiano Rosas     MigrateCommon args = {
2138926554c0SFabiano Rosas         .connect_uri = uri,
2139926554c0SFabiano Rosas         .listen_uri = "defer",
2140926554c0SFabiano Rosas         .start_hook = file_offset_fdset_start_hook,
2141926554c0SFabiano Rosas     };
2142926554c0SFabiano Rosas 
2143926554c0SFabiano Rosas     test_file_common(&args, false);
2144926554c0SFabiano Rosas }
2145926554c0SFabiano Rosas #endif
2146926554c0SFabiano Rosas 
test_precopy_file_offset(void)21473dc35470SFabiano Rosas static void test_precopy_file_offset(void)
21483dc35470SFabiano Rosas {
21493dc35470SFabiano Rosas     g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=%d", tmpfs,
21503dc35470SFabiano Rosas                                            FILE_TEST_FILENAME,
21513dc35470SFabiano Rosas                                            FILE_TEST_OFFSET);
21523dc35470SFabiano Rosas     MigrateCommon args = {
21533dc35470SFabiano Rosas         .connect_uri = uri,
21543dc35470SFabiano Rosas         .listen_uri = "defer",
21553dc35470SFabiano Rosas     };
21563dc35470SFabiano Rosas 
21573dc35470SFabiano Rosas     test_file_common(&args, false);
21583dc35470SFabiano Rosas }
21593dc35470SFabiano Rosas 
test_precopy_file_offset_bad(void)21603dc35470SFabiano Rosas static void test_precopy_file_offset_bad(void)
21613dc35470SFabiano Rosas {
21623dc35470SFabiano Rosas     /* using a value not supported by qemu_strtosz() */
21633dc35470SFabiano Rosas     g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=0x20M",
21643dc35470SFabiano Rosas                                            tmpfs, FILE_TEST_FILENAME);
21653dc35470SFabiano Rosas     MigrateCommon args = {
21663dc35470SFabiano Rosas         .connect_uri = uri,
21673dc35470SFabiano Rosas         .listen_uri = "defer",
21683dc35470SFabiano Rosas         .result = MIG_TEST_QMP_ERROR,
21693dc35470SFabiano Rosas     };
21703dc35470SFabiano Rosas 
21713dc35470SFabiano Rosas     test_file_common(&args, false);
21723dc35470SFabiano Rosas }
21733dc35470SFabiano Rosas 
test_mode_reboot_start(QTestState * from,QTestState * to)2174e7b428d6SSteve Sistare static void *test_mode_reboot_start(QTestState *from, QTestState *to)
2175e7b428d6SSteve Sistare {
2176e7b428d6SSteve Sistare     migrate_set_parameter_str(from, "mode", "cpr-reboot");
2177e7b428d6SSteve Sistare     migrate_set_parameter_str(to, "mode", "cpr-reboot");
2178e7b428d6SSteve Sistare 
2179e7b428d6SSteve Sistare     migrate_set_capability(from, "x-ignore-shared", true);
2180e7b428d6SSteve Sistare     migrate_set_capability(to, "x-ignore-shared", true);
2181e7b428d6SSteve Sistare 
2182e7b428d6SSteve Sistare     return NULL;
2183e7b428d6SSteve Sistare }
2184e7b428d6SSteve Sistare 
migrate_mapped_ram_start(QTestState * from,QTestState * to)2185c7076ec3SFabiano Rosas static void *migrate_mapped_ram_start(QTestState *from, QTestState *to)
2186c7076ec3SFabiano Rosas {
2187c7076ec3SFabiano Rosas     migrate_set_capability(from, "mapped-ram", true);
2188c7076ec3SFabiano Rosas     migrate_set_capability(to, "mapped-ram", true);
2189c7076ec3SFabiano Rosas 
2190c7076ec3SFabiano Rosas     return NULL;
2191c7076ec3SFabiano Rosas }
2192c7076ec3SFabiano Rosas 
test_mode_reboot(void)2193e7b428d6SSteve Sistare static void test_mode_reboot(void)
2194e7b428d6SSteve Sistare {
2195e7b428d6SSteve Sistare     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
2196e7b428d6SSteve Sistare                                            FILE_TEST_FILENAME);
2197e7b428d6SSteve Sistare     MigrateCommon args = {
2198e7b428d6SSteve Sistare         .start.use_shmem = true,
2199e7b428d6SSteve Sistare         .connect_uri = uri,
2200e7b428d6SSteve Sistare         .listen_uri = "defer",
2201e7b428d6SSteve Sistare         .start_hook = test_mode_reboot_start
2202e7b428d6SSteve Sistare     };
2203e7b428d6SSteve Sistare 
2204e7b428d6SSteve Sistare     test_file_common(&args, true);
2205e7b428d6SSteve Sistare }
2206e7b428d6SSteve Sistare 
test_precopy_file_mapped_ram_live(void)2207c7076ec3SFabiano Rosas static void test_precopy_file_mapped_ram_live(void)
2208c7076ec3SFabiano Rosas {
2209c7076ec3SFabiano Rosas     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
2210c7076ec3SFabiano Rosas                                            FILE_TEST_FILENAME);
2211c7076ec3SFabiano Rosas     MigrateCommon args = {
2212c7076ec3SFabiano Rosas         .connect_uri = uri,
2213c7076ec3SFabiano Rosas         .listen_uri = "defer",
2214c7076ec3SFabiano Rosas         .start_hook = migrate_mapped_ram_start,
2215c7076ec3SFabiano Rosas     };
2216c7076ec3SFabiano Rosas 
2217c7076ec3SFabiano Rosas     test_file_common(&args, false);
2218c7076ec3SFabiano Rosas }
2219c7076ec3SFabiano Rosas 
test_precopy_file_mapped_ram(void)2220c7076ec3SFabiano Rosas static void test_precopy_file_mapped_ram(void)
2221c7076ec3SFabiano Rosas {
2222c7076ec3SFabiano Rosas     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
2223c7076ec3SFabiano Rosas                                            FILE_TEST_FILENAME);
2224c7076ec3SFabiano Rosas     MigrateCommon args = {
2225c7076ec3SFabiano Rosas         .connect_uri = uri,
2226c7076ec3SFabiano Rosas         .listen_uri = "defer",
2227c7076ec3SFabiano Rosas         .start_hook = migrate_mapped_ram_start,
2228c7076ec3SFabiano Rosas     };
2229c7076ec3SFabiano Rosas 
2230c7076ec3SFabiano Rosas     test_file_common(&args, true);
2231c7076ec3SFabiano Rosas }
2232c7076ec3SFabiano Rosas 
migrate_multifd_mapped_ram_start(QTestState * from,QTestState * to)22337a09f092SFabiano Rosas static void *migrate_multifd_mapped_ram_start(QTestState *from, QTestState *to)
22347a09f092SFabiano Rosas {
22357a09f092SFabiano Rosas     migrate_mapped_ram_start(from, to);
22367a09f092SFabiano Rosas 
22377a09f092SFabiano Rosas     migrate_set_parameter_int(from, "multifd-channels", 4);
22387a09f092SFabiano Rosas     migrate_set_parameter_int(to, "multifd-channels", 4);
22397a09f092SFabiano Rosas 
22407a09f092SFabiano Rosas     migrate_set_capability(from, "multifd", true);
22417a09f092SFabiano Rosas     migrate_set_capability(to, "multifd", true);
22427a09f092SFabiano Rosas 
22437a09f092SFabiano Rosas     return NULL;
22447a09f092SFabiano Rosas }
22457a09f092SFabiano Rosas 
test_multifd_file_mapped_ram_live(void)22467a09f092SFabiano Rosas static void test_multifd_file_mapped_ram_live(void)
22477a09f092SFabiano Rosas {
22487a09f092SFabiano Rosas     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
22497a09f092SFabiano Rosas                                            FILE_TEST_FILENAME);
22507a09f092SFabiano Rosas     MigrateCommon args = {
22517a09f092SFabiano Rosas         .connect_uri = uri,
22527a09f092SFabiano Rosas         .listen_uri = "defer",
22537a09f092SFabiano Rosas         .start_hook = migrate_multifd_mapped_ram_start,
22547a09f092SFabiano Rosas     };
22557a09f092SFabiano Rosas 
22567a09f092SFabiano Rosas     test_file_common(&args, false);
22577a09f092SFabiano Rosas }
22587a09f092SFabiano Rosas 
test_multifd_file_mapped_ram(void)22597a09f092SFabiano Rosas static void test_multifd_file_mapped_ram(void)
22607a09f092SFabiano Rosas {
22617a09f092SFabiano Rosas     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
22627a09f092SFabiano Rosas                                            FILE_TEST_FILENAME);
22637a09f092SFabiano Rosas     MigrateCommon args = {
22647a09f092SFabiano Rosas         .connect_uri = uri,
22657a09f092SFabiano Rosas         .listen_uri = "defer",
22667a09f092SFabiano Rosas         .start_hook = migrate_multifd_mapped_ram_start,
22677a09f092SFabiano Rosas     };
22687a09f092SFabiano Rosas 
22697a09f092SFabiano Rosas     test_file_common(&args, true);
22707a09f092SFabiano Rosas }
22717a09f092SFabiano Rosas 
multifd_mapped_ram_dio_start(QTestState * from,QTestState * to)2272408d295dSFabiano Rosas static void *multifd_mapped_ram_dio_start(QTestState *from, QTestState *to)
2273408d295dSFabiano Rosas {
2274408d295dSFabiano Rosas     migrate_multifd_mapped_ram_start(from, to);
2275408d295dSFabiano Rosas 
2276408d295dSFabiano Rosas     migrate_set_parameter_bool(from, "direct-io", true);
2277408d295dSFabiano Rosas     migrate_set_parameter_bool(to, "direct-io", true);
2278408d295dSFabiano Rosas 
2279408d295dSFabiano Rosas     return NULL;
2280408d295dSFabiano Rosas }
2281408d295dSFabiano Rosas 
test_multifd_file_mapped_ram_dio(void)2282408d295dSFabiano Rosas static void test_multifd_file_mapped_ram_dio(void)
2283408d295dSFabiano Rosas {
2284408d295dSFabiano Rosas     g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
2285408d295dSFabiano Rosas                                            FILE_TEST_FILENAME);
2286408d295dSFabiano Rosas     MigrateCommon args = {
2287408d295dSFabiano Rosas         .connect_uri = uri,
2288408d295dSFabiano Rosas         .listen_uri = "defer",
2289408d295dSFabiano Rosas         .start_hook = multifd_mapped_ram_dio_start,
2290408d295dSFabiano Rosas     };
2291408d295dSFabiano Rosas 
2292408d295dSFabiano Rosas     if (!probe_o_direct_support(tmpfs)) {
2293408d295dSFabiano Rosas         g_test_skip("Filesystem does not support O_DIRECT");
2294408d295dSFabiano Rosas         return;
2295408d295dSFabiano Rosas     }
2296408d295dSFabiano Rosas 
2297408d295dSFabiano Rosas     test_file_common(&args, true);
2298408d295dSFabiano Rosas }
22997a09f092SFabiano Rosas 
230031a5a303SFabiano Rosas #ifndef _WIN32
multifd_mapped_ram_fdset_end(QTestState * from,QTestState * to,void * opaque)230131a5a303SFabiano Rosas static void multifd_mapped_ram_fdset_end(QTestState *from, QTestState *to,
230231a5a303SFabiano Rosas                                          void *opaque)
230331a5a303SFabiano Rosas {
230431a5a303SFabiano Rosas     QDict *resp;
230531a5a303SFabiano Rosas     QList *fdsets;
230631a5a303SFabiano Rosas 
230731a5a303SFabiano Rosas     /*
230831a5a303SFabiano Rosas      * Remove the fdsets after migration, otherwise a second migration
230931a5a303SFabiano Rosas      * would fail due fdset reuse.
231031a5a303SFabiano Rosas      */
231131a5a303SFabiano Rosas     qtest_qmp_assert_success(from, "{'execute': 'remove-fd', "
231231a5a303SFabiano Rosas                              "'arguments': { 'fdset-id': 1}}");
231331a5a303SFabiano Rosas 
231431a5a303SFabiano Rosas     /*
231531a5a303SFabiano Rosas      * Make sure no fdsets are left after migration, otherwise a
231631a5a303SFabiano Rosas      * second migration would fail due fdset reuse.
231731a5a303SFabiano Rosas      */
231831a5a303SFabiano Rosas     resp = qtest_qmp(from, "{'execute': 'query-fdsets', "
231931a5a303SFabiano Rosas                      "'arguments': {}}");
232031a5a303SFabiano Rosas     g_assert(qdict_haskey(resp, "return"));
232131a5a303SFabiano Rosas     fdsets = qdict_get_qlist(resp, "return");
232231a5a303SFabiano Rosas     g_assert(fdsets && qlist_empty(fdsets));
23230fa2cf81SPeter Maydell     qobject_unref(resp);
232431a5a303SFabiano Rosas }
232531a5a303SFabiano Rosas 
multifd_mapped_ram_fdset_dio(QTestState * from,QTestState * to)232631a5a303SFabiano Rosas static void *multifd_mapped_ram_fdset_dio(QTestState *from, QTestState *to)
232731a5a303SFabiano Rosas {
232831a5a303SFabiano Rosas     g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
232931a5a303SFabiano Rosas 
233031a5a303SFabiano Rosas     fdset_add_fds(from, file, O_WRONLY, 2, true);
233131a5a303SFabiano Rosas     fdset_add_fds(to, file, O_RDONLY, 2, true);
233231a5a303SFabiano Rosas 
233331a5a303SFabiano Rosas     migrate_multifd_mapped_ram_start(from, to);
233431a5a303SFabiano Rosas     migrate_set_parameter_bool(from, "direct-io", true);
233531a5a303SFabiano Rosas     migrate_set_parameter_bool(to, "direct-io", true);
233631a5a303SFabiano Rosas 
233731a5a303SFabiano Rosas     return NULL;
233831a5a303SFabiano Rosas }
233931a5a303SFabiano Rosas 
multifd_mapped_ram_fdset(QTestState * from,QTestState * to)234031a5a303SFabiano Rosas static void *multifd_mapped_ram_fdset(QTestState *from, QTestState *to)
234131a5a303SFabiano Rosas {
234231a5a303SFabiano Rosas     g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
234331a5a303SFabiano Rosas 
234431a5a303SFabiano Rosas     fdset_add_fds(from, file, O_WRONLY, 2, false);
234531a5a303SFabiano Rosas     fdset_add_fds(to, file, O_RDONLY, 2, false);
234631a5a303SFabiano Rosas 
234731a5a303SFabiano Rosas     migrate_multifd_mapped_ram_start(from, to);
234831a5a303SFabiano Rosas 
234931a5a303SFabiano Rosas     return NULL;
235031a5a303SFabiano Rosas }
235131a5a303SFabiano Rosas 
test_multifd_file_mapped_ram_fdset(void)235231a5a303SFabiano Rosas static void test_multifd_file_mapped_ram_fdset(void)
235331a5a303SFabiano Rosas {
235431a5a303SFabiano Rosas     g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
235531a5a303SFabiano Rosas                                            FILE_TEST_OFFSET);
235631a5a303SFabiano Rosas     MigrateCommon args = {
235731a5a303SFabiano Rosas         .connect_uri = uri,
235831a5a303SFabiano Rosas         .listen_uri = "defer",
235931a5a303SFabiano Rosas         .start_hook = multifd_mapped_ram_fdset,
236031a5a303SFabiano Rosas         .finish_hook = multifd_mapped_ram_fdset_end,
236131a5a303SFabiano Rosas     };
236231a5a303SFabiano Rosas 
236331a5a303SFabiano Rosas     test_file_common(&args, true);
236431a5a303SFabiano Rosas }
236531a5a303SFabiano Rosas 
test_multifd_file_mapped_ram_fdset_dio(void)236631a5a303SFabiano Rosas static void test_multifd_file_mapped_ram_fdset_dio(void)
236731a5a303SFabiano Rosas {
236831a5a303SFabiano Rosas     g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d",
236931a5a303SFabiano Rosas                                            FILE_TEST_OFFSET);
237031a5a303SFabiano Rosas     MigrateCommon args = {
237131a5a303SFabiano Rosas         .connect_uri = uri,
237231a5a303SFabiano Rosas         .listen_uri = "defer",
237331a5a303SFabiano Rosas         .start_hook = multifd_mapped_ram_fdset_dio,
237431a5a303SFabiano Rosas         .finish_hook = multifd_mapped_ram_fdset_end,
237531a5a303SFabiano Rosas     };
237631a5a303SFabiano Rosas 
237731a5a303SFabiano Rosas     if (!probe_o_direct_support(tmpfs)) {
237831a5a303SFabiano Rosas         g_test_skip("Filesystem does not support O_DIRECT");
237931a5a303SFabiano Rosas         return;
238031a5a303SFabiano Rosas     }
238131a5a303SFabiano Rosas 
238231a5a303SFabiano Rosas     test_file_common(&args, true);
238331a5a303SFabiano Rosas }
238431a5a303SFabiano Rosas #endif /* !_WIN32 */
238531a5a303SFabiano Rosas 
test_precopy_tcp_plain(void)238658d25e97SDaniel P. Berrangé static void test_precopy_tcp_plain(void)
23871e8a1faeSThomas Huth {
2388ffed54f6SDaniel P. Berrangé     MigrateCommon args = {
2389ffed54f6SDaniel P. Berrangé         .listen_uri = "tcp:127.0.0.1:0",
2390ffed54f6SDaniel P. Berrangé     };
23911e8a1faeSThomas Huth 
2392ffed54f6SDaniel P. Berrangé     test_precopy_common(&args);
23931e8a1faeSThomas Huth }
23941e8a1faeSThomas Huth 
test_migrate_switchover_ack_start(QTestState * from,QTestState * to)23957e6a5c73SAvihai Horon static void *test_migrate_switchover_ack_start(QTestState *from, QTestState *to)
23967e6a5c73SAvihai Horon {
23977e6a5c73SAvihai Horon 
23987e6a5c73SAvihai Horon     migrate_set_capability(from, "return-path", true);
23997e6a5c73SAvihai Horon     migrate_set_capability(to, "return-path", true);
24007e6a5c73SAvihai Horon 
24017e6a5c73SAvihai Horon     migrate_set_capability(from, "switchover-ack", true);
24027e6a5c73SAvihai Horon     migrate_set_capability(to, "switchover-ack", true);
24037e6a5c73SAvihai Horon 
24047e6a5c73SAvihai Horon     return NULL;
24057e6a5c73SAvihai Horon }
24067e6a5c73SAvihai Horon 
test_precopy_tcp_switchover_ack(void)24077e6a5c73SAvihai Horon static void test_precopy_tcp_switchover_ack(void)
24087e6a5c73SAvihai Horon {
24097e6a5c73SAvihai Horon     MigrateCommon args = {
24107e6a5c73SAvihai Horon         .listen_uri = "tcp:127.0.0.1:0",
24117e6a5c73SAvihai Horon         .start_hook = test_migrate_switchover_ack_start,
24127e6a5c73SAvihai Horon         /*
24137e6a5c73SAvihai Horon          * Source VM must be running in order to consider the switchover ACK
24147e6a5c73SAvihai Horon          * when deciding to do switchover or not.
24157e6a5c73SAvihai Horon          */
24167e6a5c73SAvihai Horon         .live = true,
24177e6a5c73SAvihai Horon     };
24187e6a5c73SAvihai Horon 
24197e6a5c73SAvihai Horon     test_precopy_common(&args);
24207e6a5c73SAvihai Horon }
24217e6a5c73SAvihai Horon 
242258d25e97SDaniel P. Berrangé #ifdef CONFIG_GNUTLS
test_precopy_tcp_tls_psk_match(void)242358d25e97SDaniel P. Berrangé static void test_precopy_tcp_tls_psk_match(void)
242458d25e97SDaniel P. Berrangé {
242558d25e97SDaniel P. Berrangé     MigrateCommon args = {
242658d25e97SDaniel P. Berrangé         .listen_uri = "tcp:127.0.0.1:0",
242758d25e97SDaniel P. Berrangé         .start_hook = test_migrate_tls_psk_start_match,
242858d25e97SDaniel P. Berrangé         .finish_hook = test_migrate_tls_psk_finish,
242958d25e97SDaniel P. Berrangé     };
243058d25e97SDaniel P. Berrangé 
243158d25e97SDaniel P. Berrangé     test_precopy_common(&args);
243258d25e97SDaniel P. Berrangé }
243358d25e97SDaniel P. Berrangé 
test_precopy_tcp_tls_psk_mismatch(void)243458d25e97SDaniel P. Berrangé static void test_precopy_tcp_tls_psk_mismatch(void)
243558d25e97SDaniel P. Berrangé {
243658d25e97SDaniel P. Berrangé     MigrateCommon args = {
243758d25e97SDaniel P. Berrangé         .start = {
243858d25e97SDaniel P. Berrangé             .hide_stderr = true,
243958d25e97SDaniel P. Berrangé         },
244058d25e97SDaniel P. Berrangé         .listen_uri = "tcp:127.0.0.1:0",
244158d25e97SDaniel P. Berrangé         .start_hook = test_migrate_tls_psk_start_mismatch,
244258d25e97SDaniel P. Berrangé         .finish_hook = test_migrate_tls_psk_finish,
244358d25e97SDaniel P. Berrangé         .result = MIG_TEST_FAIL,
244458d25e97SDaniel P. Berrangé     };
244558d25e97SDaniel P. Berrangé 
244658d25e97SDaniel P. Berrangé     test_precopy_common(&args);
244758d25e97SDaniel P. Berrangé }
2448d47b83b1SDaniel P. Berrangé 
2449d47b83b1SDaniel P. Berrangé #ifdef CONFIG_TASN1
test_precopy_tcp_tls_x509_default_host(void)2450d47b83b1SDaniel P. Berrangé static void test_precopy_tcp_tls_x509_default_host(void)
2451d47b83b1SDaniel P. Berrangé {
2452d47b83b1SDaniel P. Berrangé     MigrateCommon args = {
2453d47b83b1SDaniel P. Berrangé         .listen_uri = "tcp:127.0.0.1:0",
2454d47b83b1SDaniel P. Berrangé         .start_hook = test_migrate_tls_x509_start_default_host,
2455d47b83b1SDaniel P. Berrangé         .finish_hook = test_migrate_tls_x509_finish,
2456d47b83b1SDaniel P. Berrangé     };
2457d47b83b1SDaniel P. Berrangé 
2458d47b83b1SDaniel P. Berrangé     test_precopy_common(&args);
2459d47b83b1SDaniel P. Berrangé }
2460d47b83b1SDaniel P. Berrangé 
test_precopy_tcp_tls_x509_override_host(void)2461d47b83b1SDaniel P. Berrangé static void test_precopy_tcp_tls_x509_override_host(void)
2462d47b83b1SDaniel P. Berrangé {
2463d47b83b1SDaniel P. Berrangé     MigrateCommon args = {
2464d47b83b1SDaniel P. Berrangé         .listen_uri = "tcp:127.0.0.1:0",
2465d47b83b1SDaniel P. Berrangé         .start_hook = test_migrate_tls_x509_start_override_host,
2466d47b83b1SDaniel P. Berrangé         .finish_hook = test_migrate_tls_x509_finish,
2467d47b83b1SDaniel P. Berrangé     };
2468d47b83b1SDaniel P. Berrangé 
2469d47b83b1SDaniel P. Berrangé     test_precopy_common(&args);
2470d47b83b1SDaniel P. Berrangé }
2471d47b83b1SDaniel P. Berrangé 
test_precopy_tcp_tls_x509_mismatch_host(void)2472d47b83b1SDaniel P. Berrangé static void test_precopy_tcp_tls_x509_mismatch_host(void)
2473d47b83b1SDaniel P. Berrangé {
2474d47b83b1SDaniel P. Berrangé     MigrateCommon args = {
2475d47b83b1SDaniel P. Berrangé         .start = {
2476d47b83b1SDaniel P. Berrangé             .hide_stderr = true,
2477d47b83b1SDaniel P. Berrangé         },
2478d47b83b1SDaniel P. Berrangé         .listen_uri = "tcp:127.0.0.1:0",
2479d47b83b1SDaniel P. Berrangé         .start_hook = test_migrate_tls_x509_start_mismatch_host,
2480d47b83b1SDaniel P. Berrangé         .finish_hook = test_migrate_tls_x509_finish,
2481d47b83b1SDaniel P. Berrangé         .result = MIG_TEST_FAIL_DEST_QUIT_ERR,
2482d47b83b1SDaniel P. Berrangé     };
2483d47b83b1SDaniel P. Berrangé 
2484d47b83b1SDaniel P. Berrangé     test_precopy_common(&args);
2485d47b83b1SDaniel P. Berrangé }
2486d47b83b1SDaniel P. Berrangé 
test_precopy_tcp_tls_x509_friendly_client(void)2487d47b83b1SDaniel P. Berrangé static void test_precopy_tcp_tls_x509_friendly_client(void)
2488d47b83b1SDaniel P. Berrangé {
2489d47b83b1SDaniel P. Berrangé     MigrateCommon args = {
2490d47b83b1SDaniel P. Berrangé         .listen_uri = "tcp:127.0.0.1:0",
2491d47b83b1SDaniel P. Berrangé         .start_hook = test_migrate_tls_x509_start_friendly_client,
2492d47b83b1SDaniel P. Berrangé         .finish_hook = test_migrate_tls_x509_finish,
2493d47b83b1SDaniel P. Berrangé     };
2494d47b83b1SDaniel P. Berrangé 
2495d47b83b1SDaniel P. Berrangé     test_precopy_common(&args);
2496d47b83b1SDaniel P. Berrangé }
2497d47b83b1SDaniel P. Berrangé 
test_precopy_tcp_tls_x509_hostile_client(void)2498d47b83b1SDaniel P. Berrangé static void test_precopy_tcp_tls_x509_hostile_client(void)
2499d47b83b1SDaniel P. Berrangé {
2500d47b83b1SDaniel P. Berrangé     MigrateCommon args = {
2501d47b83b1SDaniel P. Berrangé         .start = {
2502d47b83b1SDaniel P. Berrangé             .hide_stderr = true,
2503d47b83b1SDaniel P. Berrangé         },
2504d47b83b1SDaniel P. Berrangé         .listen_uri = "tcp:127.0.0.1:0",
2505d47b83b1SDaniel P. Berrangé         .start_hook = test_migrate_tls_x509_start_hostile_client,
2506d47b83b1SDaniel P. Berrangé         .finish_hook = test_migrate_tls_x509_finish,
2507d47b83b1SDaniel P. Berrangé         .result = MIG_TEST_FAIL,
2508d47b83b1SDaniel P. Berrangé     };
2509d47b83b1SDaniel P. Berrangé 
2510d47b83b1SDaniel P. Berrangé     test_precopy_common(&args);
2511d47b83b1SDaniel P. Berrangé }
2512d47b83b1SDaniel P. Berrangé 
test_precopy_tcp_tls_x509_allow_anon_client(void)2513d47b83b1SDaniel P. Berrangé static void test_precopy_tcp_tls_x509_allow_anon_client(void)
2514d47b83b1SDaniel P. Berrangé {
2515d47b83b1SDaniel P. Berrangé     MigrateCommon args = {
2516d47b83b1SDaniel P. Berrangé         .listen_uri = "tcp:127.0.0.1:0",
2517d47b83b1SDaniel P. Berrangé         .start_hook = test_migrate_tls_x509_start_allow_anon_client,
2518d47b83b1SDaniel P. Berrangé         .finish_hook = test_migrate_tls_x509_finish,
2519d47b83b1SDaniel P. Berrangé     };
2520d47b83b1SDaniel P. Berrangé 
2521d47b83b1SDaniel P. Berrangé     test_precopy_common(&args);
2522d47b83b1SDaniel P. Berrangé }
2523d47b83b1SDaniel P. Berrangé 
test_precopy_tcp_tls_x509_reject_anon_client(void)2524d47b83b1SDaniel P. Berrangé static void test_precopy_tcp_tls_x509_reject_anon_client(void)
2525d47b83b1SDaniel P. Berrangé {
2526d47b83b1SDaniel P. Berrangé     MigrateCommon args = {
2527d47b83b1SDaniel P. Berrangé         .start = {
2528d47b83b1SDaniel P. Berrangé             .hide_stderr = true,
2529d47b83b1SDaniel P. Berrangé         },
2530d47b83b1SDaniel P. Berrangé         .listen_uri = "tcp:127.0.0.1:0",
2531d47b83b1SDaniel P. Berrangé         .start_hook = test_migrate_tls_x509_start_reject_anon_client,
2532d47b83b1SDaniel P. Berrangé         .finish_hook = test_migrate_tls_x509_finish,
2533d47b83b1SDaniel P. Berrangé         .result = MIG_TEST_FAIL,
2534d47b83b1SDaniel P. Berrangé     };
2535d47b83b1SDaniel P. Berrangé 
2536d47b83b1SDaniel P. Berrangé     test_precopy_common(&args);
2537d47b83b1SDaniel P. Berrangé }
2538d47b83b1SDaniel P. Berrangé #endif /* CONFIG_TASN1 */
253958d25e97SDaniel P. Berrangé #endif /* CONFIG_GNUTLS */
254058d25e97SDaniel P. Berrangé 
2541d7613ee2SBin Meng #ifndef _WIN32
test_migrate_fd_start_hook(QTestState * from,QTestState * to)2542243e0066SDaniel P. Berrangé static void *test_migrate_fd_start_hook(QTestState *from,
2543243e0066SDaniel P. Berrangé                                         QTestState *to)
25441e8a1faeSThomas Huth {
25451e8a1faeSThomas Huth     int ret;
25461e8a1faeSThomas Huth     int pair[2];
25471e8a1faeSThomas Huth 
25481e8a1faeSThomas Huth     /* Create two connected sockets for migration */
25490038e9a2SGuoyi Tu     ret = qemu_socketpair(PF_LOCAL, SOCK_STREAM, 0, pair);
25501e8a1faeSThomas Huth     g_assert_cmpint(ret, ==, 0);
25511e8a1faeSThomas Huth 
25521e8a1faeSThomas Huth     /* Send the 1st socket to the target */
2553aca04069SDaniel P. Berrangé     qtest_qmp_fds_assert_success(to, &pair[0], 1,
25541e8a1faeSThomas Huth                                  "{ 'execute': 'getfd',"
25551e8a1faeSThomas Huth                                  "  'arguments': { 'fdname': 'fd-mig' }}");
25561e8a1faeSThomas Huth     close(pair[0]);
25571e8a1faeSThomas Huth 
25581e8a1faeSThomas Huth     /* Start incoming migration from the 1st socket */
25596830e53bSFabiano Rosas     migrate_incoming_qmp(to, "fd:fd-mig", "{}");
25601e8a1faeSThomas Huth 
25611e8a1faeSThomas Huth     /* Send the 2nd socket to the target */
2562aca04069SDaniel P. Berrangé     qtest_qmp_fds_assert_success(from, &pair[1], 1,
25631e8a1faeSThomas Huth                                  "{ 'execute': 'getfd',"
25641e8a1faeSThomas Huth                                  "  'arguments': { 'fdname': 'fd-mig' }}");
25651e8a1faeSThomas Huth     close(pair[1]);
25661e8a1faeSThomas Huth 
2567243e0066SDaniel P. Berrangé     return NULL;
25681e8a1faeSThomas Huth }
2569243e0066SDaniel P. Berrangé 
test_migrate_fd_finish_hook(QTestState * from,QTestState * to,void * opaque)2570243e0066SDaniel P. Berrangé static void test_migrate_fd_finish_hook(QTestState *from,
2571243e0066SDaniel P. Berrangé                                         QTestState *to,
2572243e0066SDaniel P. Berrangé                                         void *opaque)
2573243e0066SDaniel P. Berrangé {
2574243e0066SDaniel P. Berrangé     QDict *rsp;
2575243e0066SDaniel P. Berrangé     const char *error_desc;
25761e8a1faeSThomas Huth 
25771e8a1faeSThomas Huth     /* Test closing fds */
25781e8a1faeSThomas Huth     /* We assume, that QEMU removes named fd from its list,
25791e8a1faeSThomas Huth      * so this should fail */
2580*19e56616SFabiano Rosas     rsp = qtest_qmp(from,
2581*19e56616SFabiano Rosas                     "{ 'execute': 'closefd',"
25821e8a1faeSThomas Huth                     "  'arguments': { 'fdname': 'fd-mig' }}");
25831e8a1faeSThomas Huth     g_assert_true(qdict_haskey(rsp, "error"));
25841e8a1faeSThomas Huth     error_desc = qdict_get_str(qdict_get_qdict(rsp, "error"), "desc");
25851e8a1faeSThomas Huth     g_assert_cmpstr(error_desc, ==, "File descriptor named 'fd-mig' not found");
25861e8a1faeSThomas Huth     qobject_unref(rsp);
25871e8a1faeSThomas Huth 
2588*19e56616SFabiano Rosas     rsp = qtest_qmp(to,
2589*19e56616SFabiano Rosas                     "{ 'execute': 'closefd',"
25901e8a1faeSThomas Huth                     "  'arguments': { 'fdname': 'fd-mig' }}");
25911e8a1faeSThomas Huth     g_assert_true(qdict_haskey(rsp, "error"));
25921e8a1faeSThomas Huth     error_desc = qdict_get_str(qdict_get_qdict(rsp, "error"), "desc");
25931e8a1faeSThomas Huth     g_assert_cmpstr(error_desc, ==, "File descriptor named 'fd-mig' not found");
25941e8a1faeSThomas Huth     qobject_unref(rsp);
2595243e0066SDaniel P. Berrangé }
25961e8a1faeSThomas Huth 
test_migrate_precopy_fd_socket(void)259785cf9abdSFabiano Rosas static void test_migrate_precopy_fd_socket(void)
2598243e0066SDaniel P. Berrangé {
2599243e0066SDaniel P. Berrangé     MigrateCommon args = {
2600243e0066SDaniel P. Berrangé         .listen_uri = "defer",
2601243e0066SDaniel P. Berrangé         .connect_uri = "fd:fd-mig",
2602243e0066SDaniel P. Berrangé         .start_hook = test_migrate_fd_start_hook,
2603243e0066SDaniel P. Berrangé         .finish_hook = test_migrate_fd_finish_hook
2604243e0066SDaniel P. Berrangé     };
2605243e0066SDaniel P. Berrangé     test_precopy_common(&args);
26061e8a1faeSThomas Huth }
26076d79bd68SFabiano Rosas 
migrate_precopy_fd_file_start(QTestState * from,QTestState * to)26086d79bd68SFabiano Rosas static void *migrate_precopy_fd_file_start(QTestState *from, QTestState *to)
26096d79bd68SFabiano Rosas {
26106d79bd68SFabiano Rosas     g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
26116d79bd68SFabiano Rosas     int src_flags = O_CREAT | O_RDWR;
26126d79bd68SFabiano Rosas     int dst_flags = O_CREAT | O_RDWR;
26136d79bd68SFabiano Rosas     int fds[2];
26146d79bd68SFabiano Rosas 
26156d79bd68SFabiano Rosas     fds[0] = open(file, src_flags, 0660);
26166d79bd68SFabiano Rosas     assert(fds[0] != -1);
26176d79bd68SFabiano Rosas 
26186d79bd68SFabiano Rosas     fds[1] = open(file, dst_flags, 0660);
26196d79bd68SFabiano Rosas     assert(fds[1] != -1);
26206d79bd68SFabiano Rosas 
26216d79bd68SFabiano Rosas 
26226d79bd68SFabiano Rosas     qtest_qmp_fds_assert_success(to, &fds[0], 1,
26236d79bd68SFabiano Rosas                                  "{ 'execute': 'getfd',"
26246d79bd68SFabiano Rosas                                  "  'arguments': { 'fdname': 'fd-mig' }}");
26256d79bd68SFabiano Rosas 
26266d79bd68SFabiano Rosas     qtest_qmp_fds_assert_success(from, &fds[1], 1,
26276d79bd68SFabiano Rosas                                  "{ 'execute': 'getfd',"
26286d79bd68SFabiano Rosas                                  "  'arguments': { 'fdname': 'fd-mig' }}");
26296d79bd68SFabiano Rosas 
26306d79bd68SFabiano Rosas     close(fds[0]);
26316d79bd68SFabiano Rosas     close(fds[1]);
26326d79bd68SFabiano Rosas 
26336d79bd68SFabiano Rosas     return NULL;
26346d79bd68SFabiano Rosas }
26356d79bd68SFabiano Rosas 
test_migrate_precopy_fd_file(void)26366d79bd68SFabiano Rosas static void test_migrate_precopy_fd_file(void)
26376d79bd68SFabiano Rosas {
26386d79bd68SFabiano Rosas     MigrateCommon args = {
26396d79bd68SFabiano Rosas         .listen_uri = "defer",
26406d79bd68SFabiano Rosas         .connect_uri = "fd:fd-mig",
26416d79bd68SFabiano Rosas         .start_hook = migrate_precopy_fd_file_start,
26426d79bd68SFabiano Rosas         .finish_hook = test_migrate_fd_finish_hook
26436d79bd68SFabiano Rosas     };
26446d79bd68SFabiano Rosas     test_file_common(&args, true);
26456d79bd68SFabiano Rosas }
2646d7613ee2SBin Meng #endif /* _WIN32 */
26471e8a1faeSThomas Huth 
do_test_validate_uuid(MigrateStart * args,bool should_fail)26481e8a1faeSThomas Huth static void do_test_validate_uuid(MigrateStart *args, bool should_fail)
26491e8a1faeSThomas Huth {
2650ff7b9b56SPeter Maydell     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
26511e8a1faeSThomas Huth     QTestState *from, *to;
26521e8a1faeSThomas Huth 
265319da6edfSDaniel P. Berrangé     if (test_migrate_start(&from, &to, uri, args)) {
26541e8a1faeSThomas Huth         return;
26551e8a1faeSThomas Huth     }
26561e8a1faeSThomas Huth 
26571e8a1faeSThomas Huth     /*
26581e8a1faeSThomas Huth      * UUID validation is at the begin of migration. So, the main process of
26591e8a1faeSThomas Huth      * migration is not interesting for us here. Thus, set huge downtime for
26601e8a1faeSThomas Huth      * very fast migration.
26611e8a1faeSThomas Huth      */
26621e8a1faeSThomas Huth     migrate_set_parameter_int(from, "downtime-limit", 1000000);
26631e8a1faeSThomas Huth     migrate_set_capability(from, "validate-uuid", true);
26641e8a1faeSThomas Huth 
26651e8a1faeSThomas Huth     /* Wait for the first serial output from the source */
26661e8a1faeSThomas Huth     wait_for_serial("src_serial");
26671e8a1faeSThomas Huth 
2668d5ee387dSHet Gala     migrate_qmp(from, to, uri, NULL, "{}");
26691e8a1faeSThomas Huth 
26701e8a1faeSThomas Huth     if (should_fail) {
26711b0f1b14SBin Meng         qtest_set_expected_status(to, EXIT_FAILURE);
26721e8a1faeSThomas Huth         wait_for_migration_fail(from, true);
26731e8a1faeSThomas Huth     } else {
26741e8a1faeSThomas Huth         wait_for_migration_complete(from);
26751e8a1faeSThomas Huth     }
26761e8a1faeSThomas Huth 
26771e8a1faeSThomas Huth     test_migrate_end(from, to, false);
26781e8a1faeSThomas Huth }
26791e8a1faeSThomas Huth 
test_validate_uuid(void)26801e8a1faeSThomas Huth static void test_validate_uuid(void)
26811e8a1faeSThomas Huth {
268219da6edfSDaniel P. Berrangé     MigrateStart args = {
268319da6edfSDaniel P. Berrangé         .opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
268419da6edfSDaniel P. Berrangé         .opts_target = "-uuid 11111111-1111-1111-1111-111111111111",
268519da6edfSDaniel P. Berrangé     };
26861e8a1faeSThomas Huth 
268719da6edfSDaniel P. Berrangé     do_test_validate_uuid(&args, false);
26881e8a1faeSThomas Huth }
26891e8a1faeSThomas Huth 
test_validate_uuid_error(void)26901e8a1faeSThomas Huth static void test_validate_uuid_error(void)
26911e8a1faeSThomas Huth {
269219da6edfSDaniel P. Berrangé     MigrateStart args = {
269319da6edfSDaniel P. Berrangé         .opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
269419da6edfSDaniel P. Berrangé         .opts_target = "-uuid 22222222-2222-2222-2222-222222222222",
269519da6edfSDaniel P. Berrangé         .hide_stderr = true,
269619da6edfSDaniel P. Berrangé     };
26971e8a1faeSThomas Huth 
269819da6edfSDaniel P. Berrangé     do_test_validate_uuid(&args, true);
26991e8a1faeSThomas Huth }
27001e8a1faeSThomas Huth 
test_validate_uuid_src_not_set(void)27011e8a1faeSThomas Huth static void test_validate_uuid_src_not_set(void)
27021e8a1faeSThomas Huth {
270319da6edfSDaniel P. Berrangé     MigrateStart args = {
270419da6edfSDaniel P. Berrangé         .opts_target = "-uuid 22222222-2222-2222-2222-222222222222",
270519da6edfSDaniel P. Berrangé         .hide_stderr = true,
270619da6edfSDaniel P. Berrangé     };
27071e8a1faeSThomas Huth 
270819da6edfSDaniel P. Berrangé     do_test_validate_uuid(&args, false);
27091e8a1faeSThomas Huth }
27101e8a1faeSThomas Huth 
test_validate_uuid_dst_not_set(void)27111e8a1faeSThomas Huth static void test_validate_uuid_dst_not_set(void)
27121e8a1faeSThomas Huth {
271319da6edfSDaniel P. Berrangé     MigrateStart args = {
271419da6edfSDaniel P. Berrangé         .opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
271519da6edfSDaniel P. Berrangé         .hide_stderr = true,
271619da6edfSDaniel P. Berrangé     };
27171e8a1faeSThomas Huth 
271819da6edfSDaniel P. Berrangé     do_test_validate_uuid(&args, false);
27191e8a1faeSThomas Huth }
27201e8a1faeSThomas Huth 
do_test_validate_uri_channel(MigrateCommon * args)2721bc6307a5SHet Gala static void do_test_validate_uri_channel(MigrateCommon *args)
2722bc6307a5SHet Gala {
2723bc6307a5SHet Gala     QTestState *from, *to;
2724bc6307a5SHet Gala 
2725bc6307a5SHet Gala     if (test_migrate_start(&from, &to, args->listen_uri, &args->start)) {
2726bc6307a5SHet Gala         return;
2727bc6307a5SHet Gala     }
2728bc6307a5SHet Gala 
2729bc6307a5SHet Gala     /* Wait for the first serial output from the source */
2730bc6307a5SHet Gala     wait_for_serial("src_serial");
2731bc6307a5SHet Gala 
2732bc6307a5SHet Gala     /*
2733bc6307a5SHet Gala      * 'uri' and 'channels' validation is checked even before the migration
2734bc6307a5SHet Gala      * starts.
2735bc6307a5SHet Gala      */
2736bc6307a5SHet Gala     migrate_qmp_fail(from, args->connect_uri, args->connect_channels, "{}");
2737bc6307a5SHet Gala     test_migrate_end(from, to, false);
2738bc6307a5SHet Gala }
2739bc6307a5SHet Gala 
test_validate_uri_channels_both_set(void)2740bc6307a5SHet Gala static void test_validate_uri_channels_both_set(void)
2741bc6307a5SHet Gala {
2742bc6307a5SHet Gala     MigrateCommon args = {
2743bc6307a5SHet Gala         .start = {
2744bc6307a5SHet Gala             .hide_stderr = true,
2745bc6307a5SHet Gala         },
2746bc6307a5SHet Gala         .listen_uri = "defer",
2747bc6307a5SHet Gala         .connect_uri = "tcp:127.0.0.1:0",
2748*19e56616SFabiano Rosas         .connect_channels = ("[ { ""'channel-type': 'main',"
2749bc6307a5SHet Gala                              "    'addr': { 'transport': 'socket',"
2750bc6307a5SHet Gala                              "              'type': 'inet',"
2751bc6307a5SHet Gala                              "              'host': '127.0.0.1',"
2752*19e56616SFabiano Rosas                              "              'port': '0' } } ]"),
2753bc6307a5SHet Gala     };
2754bc6307a5SHet Gala 
2755bc6307a5SHet Gala     do_test_validate_uri_channel(&args);
2756bc6307a5SHet Gala }
2757bc6307a5SHet Gala 
test_validate_uri_channels_none_set(void)2758bc6307a5SHet Gala static void test_validate_uri_channels_none_set(void)
2759bc6307a5SHet Gala {
2760bc6307a5SHet Gala     MigrateCommon args = {
2761bc6307a5SHet Gala         .start = {
2762bc6307a5SHet Gala             .hide_stderr = true,
2763bc6307a5SHet Gala         },
2764bc6307a5SHet Gala         .listen_uri = "defer",
2765bc6307a5SHet Gala     };
2766bc6307a5SHet Gala 
2767bc6307a5SHet Gala     do_test_validate_uri_channel(&args);
2768bc6307a5SHet Gala }
2769bc6307a5SHet Gala 
277074902af7SJuan Quintela /*
277174902af7SJuan Quintela  * The way auto_converge works, we need to do too many passes to
277274902af7SJuan Quintela  * run this test.  Auto_converge logic is only run once every
277374902af7SJuan Quintela  * three iterations, so:
277474902af7SJuan Quintela  *
277574902af7SJuan Quintela  * - 3 iterations without auto_converge enabled
277674902af7SJuan Quintela  * - 3 iterations with pct = 5
277774902af7SJuan Quintela  * - 3 iterations with pct = 30
277874902af7SJuan Quintela  * - 3 iterations with pct = 55
277974902af7SJuan Quintela  * - 3 iterations with pct = 80
278074902af7SJuan Quintela  * - 3 iterations with pct = 95 (max(95, 80 + 25))
278174902af7SJuan Quintela  *
278274902af7SJuan Quintela  * To make things even worse, we need to run the initial stage at
278374902af7SJuan Quintela  * 3MB/s so we enter autoconverge even when host is (over)loaded.
278474902af7SJuan Quintela  */
test_migrate_auto_converge(void)27851e8a1faeSThomas Huth static void test_migrate_auto_converge(void)
27861e8a1faeSThomas Huth {
2787ff7b9b56SPeter Maydell     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
278819da6edfSDaniel P. Berrangé     MigrateStart args = {};
27891e8a1faeSThomas Huth     QTestState *from, *to;
2790219044b8SPeter Xu     int64_t percentage;
27911e8a1faeSThomas Huth 
27921e8a1faeSThomas Huth     /*
27931e8a1faeSThomas Huth      * We want the test to be stable and as fast as possible.
279496420a30SMichael Tokarev      * E.g., with 1Gb/s bandwidth migration may pass without throttling,
27951e8a1faeSThomas Huth      * so we need to decrease a bandwidth.
27961e8a1faeSThomas Huth      */
27971bfc8ddeSDr. David Alan Gilbert     const int64_t init_pct = 5, inc_pct = 25, max_pct = 95;
2798bfd66ccbSHyman Huang     uint64_t prev_dirty_sync_cnt, dirty_sync_cnt;
2799bfd66ccbSHyman Huang     int max_try_count, hit = 0;
28001e8a1faeSThomas Huth 
28013ff57401SPeter Xu     if (test_migrate_start(&from, &to, uri, &args)) {
28021e8a1faeSThomas Huth         return;
28031e8a1faeSThomas Huth     }
28041e8a1faeSThomas Huth 
28051e8a1faeSThomas Huth     migrate_set_capability(from, "auto-converge", true);
28061e8a1faeSThomas Huth     migrate_set_parameter_int(from, "cpu-throttle-initial", init_pct);
28071e8a1faeSThomas Huth     migrate_set_parameter_int(from, "cpu-throttle-increment", inc_pct);
28081e8a1faeSThomas Huth     migrate_set_parameter_int(from, "max-cpu-throttle", max_pct);
28091e8a1faeSThomas Huth 
28101e8a1faeSThomas Huth     /*
28111e8a1faeSThomas Huth      * Set the initial parameters so that the migration could not converge
28121e8a1faeSThomas Huth      * without throttling.
28131e8a1faeSThomas Huth      */
2814886dfe9dSDaniel P. Berrangé     migrate_ensure_non_converge(from);
28151e8a1faeSThomas Huth 
28161e8a1faeSThomas Huth     /* To check remaining size after precopy */
28171e8a1faeSThomas Huth     migrate_set_capability(from, "pause-before-switchover", true);
28181e8a1faeSThomas Huth 
28191e8a1faeSThomas Huth     /* Wait for the first serial output from the source */
28201e8a1faeSThomas Huth     wait_for_serial("src_serial");
28211e8a1faeSThomas Huth 
2822d5ee387dSHet Gala     migrate_qmp(from, to, uri, NULL, "{}");
28231e8a1faeSThomas Huth 
28241e8a1faeSThomas Huth     /* Wait for throttling begins */
28251e8a1faeSThomas Huth     percentage = 0;
28261bfc8ddeSDr. David Alan Gilbert     do {
28271e8a1faeSThomas Huth         percentage = read_migrate_property_int(from, "cpu-throttle-percentage");
28281bfc8ddeSDr. David Alan Gilbert         if (percentage != 0) {
28291bfc8ddeSDr. David Alan Gilbert             break;
28301e8a1faeSThomas Huth         }
28311bfc8ddeSDr. David Alan Gilbert         usleep(20);
2832f0649758SSteve Sistare         g_assert_false(src_state.stop_seen);
28331bfc8ddeSDr. David Alan Gilbert     } while (true);
28341bfc8ddeSDr. David Alan Gilbert     /* The first percentage of throttling should be at least init_pct */
28351bfc8ddeSDr. David Alan Gilbert     g_assert_cmpint(percentage, >=, init_pct);
2836bfd66ccbSHyman Huang 
2837bfd66ccbSHyman Huang     /*
2838bfd66ccbSHyman Huang      * End the loop when the dirty sync count greater than 1.
2839bfd66ccbSHyman Huang      */
2840bfd66ccbSHyman Huang     while ((dirty_sync_cnt = get_migration_pass(from)) < 2) {
2841bfd66ccbSHyman Huang         usleep(1000 * 1000);
2842bfd66ccbSHyman Huang     }
2843bfd66ccbSHyman Huang 
2844bfd66ccbSHyman Huang     prev_dirty_sync_cnt = dirty_sync_cnt;
2845bfd66ccbSHyman Huang 
2846bfd66ccbSHyman Huang     /*
2847bfd66ccbSHyman Huang      * The RAMBlock dirty sync count must changes in 5 seconds, here we set
2848bfd66ccbSHyman Huang      * the timeout to 10 seconds to ensure it changes.
2849bfd66ccbSHyman Huang      *
2850bfd66ccbSHyman Huang      * Note that migrate_ensure_non_converge set the max-bandwidth to 3MB/s,
2851bfd66ccbSHyman Huang      * while the qtest mem is >= 100MB, one iteration takes at least 33s (100/3)
2852bfd66ccbSHyman Huang      * to complete; this ensures that the RAMBlock dirty sync occurs.
2853bfd66ccbSHyman Huang      */
2854bfd66ccbSHyman Huang     max_try_count = 10;
2855bfd66ccbSHyman Huang     while (--max_try_count) {
2856bfd66ccbSHyman Huang         dirty_sync_cnt = get_migration_pass(from);
2857bfd66ccbSHyman Huang         if (dirty_sync_cnt != prev_dirty_sync_cnt) {
2858bfd66ccbSHyman Huang             hit = 1;
2859bfd66ccbSHyman Huang             break;
2860bfd66ccbSHyman Huang         }
2861bfd66ccbSHyman Huang         prev_dirty_sync_cnt = dirty_sync_cnt;
2862bfd66ccbSHyman Huang         sleep(1);
2863bfd66ccbSHyman Huang     }
2864bfd66ccbSHyman Huang     g_assert_cmpint(hit, ==, 1);
2865bfd66ccbSHyman Huang 
28661e8a1faeSThomas Huth     /* Now, when we tested that throttling works, let it converge */
2867219044b8SPeter Xu     migrate_ensure_converge(from);
28681e8a1faeSThomas Huth 
28691e8a1faeSThomas Huth     /*
28701e8a1faeSThomas Huth      * Wait for pre-switchover status to check last throttle percentage
28711e8a1faeSThomas Huth      * and remaining. These values will be zeroed later
28721e8a1faeSThomas Huth      */
28731e8a1faeSThomas Huth     wait_for_migration_status(from, "pre-switchover", NULL);
28741e8a1faeSThomas Huth 
28751e8a1faeSThomas Huth     /* The final percentage of throttling shouldn't be greater than max_pct */
28761e8a1faeSThomas Huth     percentage = read_migrate_property_int(from, "cpu-throttle-percentage");
28771e8a1faeSThomas Huth     g_assert_cmpint(percentage, <=, max_pct);
28781e8a1faeSThomas Huth     migrate_continue(from, "pre-switchover");
28791e8a1faeSThomas Huth 
28801e8a1faeSThomas Huth     qtest_qmp_eventwait(to, "RESUME");
28811e8a1faeSThomas Huth 
28821e8a1faeSThomas Huth     wait_for_serial("dest_serial");
28831e8a1faeSThomas Huth     wait_for_migration_complete(from);
28841e8a1faeSThomas Huth 
28851e8a1faeSThomas Huth     test_migrate_end(from, to, true);
28861e8a1faeSThomas Huth }
28871e8a1faeSThomas Huth 
2888490facffSDaniel P. Berrangé static void *
test_migrate_precopy_tcp_multifd_start_common(QTestState * from,QTestState * to,const char * method)2889490facffSDaniel P. Berrangé test_migrate_precopy_tcp_multifd_start_common(QTestState *from,
2890490facffSDaniel P. Berrangé                                               QTestState *to,
2891490facffSDaniel P. Berrangé                                               const char *method)
2892b99784efSJuan Quintela {
2893b99784efSJuan Quintela     migrate_set_parameter_int(from, "multifd-channels", 16);
2894b99784efSJuan Quintela     migrate_set_parameter_int(to, "multifd-channels", 16);
2895b99784efSJuan Quintela 
289696eef042SJuan Quintela     migrate_set_parameter_str(from, "multifd-compression", method);
289796eef042SJuan Quintela     migrate_set_parameter_str(to, "multifd-compression", method);
289896eef042SJuan Quintela 
2899a1209bb7SDr. David Alan Gilbert     migrate_set_capability(from, "multifd", true);
2900a1209bb7SDr. David Alan Gilbert     migrate_set_capability(to, "multifd", true);
2901b99784efSJuan Quintela 
2902b99784efSJuan Quintela     /* Start incoming migration from the 1st socket */
29036830e53bSFabiano Rosas     migrate_incoming_qmp(to, "tcp:127.0.0.1:0", "{}");
2904b99784efSJuan Quintela 
2905490facffSDaniel P. Berrangé     return NULL;
2906b99784efSJuan Quintela }
2907b99784efSJuan Quintela 
2908490facffSDaniel P. Berrangé static void *
test_migrate_precopy_tcp_multifd_start(QTestState * from,QTestState * to)2909490facffSDaniel P. Berrangé test_migrate_precopy_tcp_multifd_start(QTestState *from,
2910490facffSDaniel P. Berrangé                                        QTestState *to)
2911490facffSDaniel P. Berrangé {
2912490facffSDaniel P. Berrangé     return test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
2913b99784efSJuan Quintela }
2914b99784efSJuan Quintela 
2915490facffSDaniel P. Berrangé static void *
test_migrate_precopy_tcp_multifd_start_zero_page_legacy(QTestState * from,QTestState * to)29161815338dSHao Xiang test_migrate_precopy_tcp_multifd_start_zero_page_legacy(QTestState *from,
29171815338dSHao Xiang                                                         QTestState *to)
29181815338dSHao Xiang {
29191815338dSHao Xiang     test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
29201815338dSHao Xiang     migrate_set_parameter_str(from, "zero-page-detection", "legacy");
29211815338dSHao Xiang     return NULL;
29221815338dSHao Xiang }
29231815338dSHao Xiang 
29241815338dSHao Xiang static void *
test_migration_precopy_tcp_multifd_start_no_zero_page(QTestState * from,QTestState * to)29251815338dSHao Xiang test_migration_precopy_tcp_multifd_start_no_zero_page(QTestState *from,
29261815338dSHao Xiang                                                       QTestState *to)
29271815338dSHao Xiang {
29281815338dSHao Xiang     test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
29291815338dSHao Xiang     migrate_set_parameter_str(from, "zero-page-detection", "none");
29301815338dSHao Xiang     return NULL;
29311815338dSHao Xiang }
29321815338dSHao Xiang 
29331815338dSHao Xiang static void *
test_migrate_precopy_tcp_multifd_zlib_start(QTestState * from,QTestState * to)2934490facffSDaniel P. Berrangé test_migrate_precopy_tcp_multifd_zlib_start(QTestState *from,
2935490facffSDaniel P. Berrangé                                             QTestState *to)
2936490facffSDaniel P. Berrangé {
29372b571432SBryan Zhang     /*
29382b571432SBryan Zhang      * Overloading this test to also check that set_parameter does not error.
29392b571432SBryan Zhang      * This is also done in the tests for the other compression methods.
29402b571432SBryan Zhang      */
29412b571432SBryan Zhang     migrate_set_parameter_int(from, "multifd-zlib-level", 2);
29422b571432SBryan Zhang     migrate_set_parameter_int(to, "multifd-zlib-level", 2);
29432b571432SBryan Zhang 
2944490facffSDaniel P. Berrangé     return test_migrate_precopy_tcp_multifd_start_common(from, to, "zlib");
2945490facffSDaniel P. Berrangé }
2946490facffSDaniel P. Berrangé 
2947490facffSDaniel P. Berrangé #ifdef CONFIG_ZSTD
2948490facffSDaniel P. Berrangé static void *
test_migrate_precopy_tcp_multifd_zstd_start(QTestState * from,QTestState * to)2949490facffSDaniel P. Berrangé test_migrate_precopy_tcp_multifd_zstd_start(QTestState *from,
2950490facffSDaniel P. Berrangé                                             QTestState *to)
2951490facffSDaniel P. Berrangé {
29522b571432SBryan Zhang     migrate_set_parameter_int(from, "multifd-zstd-level", 2);
29532b571432SBryan Zhang     migrate_set_parameter_int(to, "multifd-zstd-level", 2);
29542b571432SBryan Zhang 
2955490facffSDaniel P. Berrangé     return test_migrate_precopy_tcp_multifd_start_common(from, to, "zstd");
2956490facffSDaniel P. Berrangé }
2957490facffSDaniel P. Berrangé #endif /* CONFIG_ZSTD */
2958490facffSDaniel P. Berrangé 
2959afe166d4SBryan Zhang #ifdef CONFIG_QATZIP
2960afe166d4SBryan Zhang static void *
test_migrate_precopy_tcp_multifd_qatzip_start(QTestState * from,QTestState * to)2961afe166d4SBryan Zhang test_migrate_precopy_tcp_multifd_qatzip_start(QTestState *from,
2962afe166d4SBryan Zhang                                               QTestState *to)
2963afe166d4SBryan Zhang {
2964afe166d4SBryan Zhang     migrate_set_parameter_int(from, "multifd-qatzip-level", 2);
2965afe166d4SBryan Zhang     migrate_set_parameter_int(to, "multifd-qatzip-level", 2);
2966afe166d4SBryan Zhang 
2967afe166d4SBryan Zhang     return test_migrate_precopy_tcp_multifd_start_common(from, to, "qatzip");
2968afe166d4SBryan Zhang }
2969afe166d4SBryan Zhang #endif
2970afe166d4SBryan Zhang 
297108b82d20SYuan Liu #ifdef CONFIG_QPL
297208b82d20SYuan Liu static void *
test_migrate_precopy_tcp_multifd_qpl_start(QTestState * from,QTestState * to)297308b82d20SYuan Liu test_migrate_precopy_tcp_multifd_qpl_start(QTestState *from,
297408b82d20SYuan Liu                                            QTestState *to)
297508b82d20SYuan Liu {
297608b82d20SYuan Liu     return test_migrate_precopy_tcp_multifd_start_common(from, to, "qpl");
297708b82d20SYuan Liu }
297808b82d20SYuan Liu #endif /* CONFIG_QPL */
2979c519caa8SShameer Kolothum #ifdef CONFIG_UADK
2980c519caa8SShameer Kolothum static void *
test_migrate_precopy_tcp_multifd_uadk_start(QTestState * from,QTestState * to)2981c519caa8SShameer Kolothum test_migrate_precopy_tcp_multifd_uadk_start(QTestState *from,
2982c519caa8SShameer Kolothum                                             QTestState *to)
2983c519caa8SShameer Kolothum {
2984c519caa8SShameer Kolothum     return test_migrate_precopy_tcp_multifd_start_common(from, to, "uadk");
2985c519caa8SShameer Kolothum }
2986c519caa8SShameer Kolothum #endif /* CONFIG_UADK */
298708b82d20SYuan Liu 
test_multifd_tcp_uri_none(void)29889d36d62cSHet Gala static void test_multifd_tcp_uri_none(void)
298996eef042SJuan Quintela {
2990490facffSDaniel P. Berrangé     MigrateCommon args = {
2991490facffSDaniel P. Berrangé         .listen_uri = "defer",
2992490facffSDaniel P. Berrangé         .start_hook = test_migrate_precopy_tcp_multifd_start,
2993b861383cSPeter Xu         /*
2994b861383cSPeter Xu          * Multifd is more complicated than most of the features, it
2995b861383cSPeter Xu          * directly takes guest page buffers when sending, make sure
2996b861383cSPeter Xu          * everything will work alright even if guest page is changing.
2997b861383cSPeter Xu          */
29983c4fb177SDaniel P. Berrangé         .live = true,
2999490facffSDaniel P. Berrangé     };
3000490facffSDaniel P. Berrangé     test_precopy_common(&args);
300196eef042SJuan Quintela }
300296eef042SJuan Quintela 
test_multifd_tcp_zero_page_legacy(void)30031815338dSHao Xiang static void test_multifd_tcp_zero_page_legacy(void)
30041815338dSHao Xiang {
30051815338dSHao Xiang     MigrateCommon args = {
30061815338dSHao Xiang         .listen_uri = "defer",
30071815338dSHao Xiang         .start_hook = test_migrate_precopy_tcp_multifd_start_zero_page_legacy,
30081815338dSHao Xiang         /*
30091815338dSHao Xiang          * Multifd is more complicated than most of the features, it
30101815338dSHao Xiang          * directly takes guest page buffers when sending, make sure
30111815338dSHao Xiang          * everything will work alright even if guest page is changing.
30121815338dSHao Xiang          */
30131815338dSHao Xiang         .live = true,
30141815338dSHao Xiang     };
30151815338dSHao Xiang     test_precopy_common(&args);
30161815338dSHao Xiang }
30171815338dSHao Xiang 
test_multifd_tcp_no_zero_page(void)30181815338dSHao Xiang static void test_multifd_tcp_no_zero_page(void)
30191815338dSHao Xiang {
30201815338dSHao Xiang     MigrateCommon args = {
30211815338dSHao Xiang         .listen_uri = "defer",
30221815338dSHao Xiang         .start_hook = test_migration_precopy_tcp_multifd_start_no_zero_page,
30231815338dSHao Xiang         /*
30241815338dSHao Xiang          * Multifd is more complicated than most of the features, it
30251815338dSHao Xiang          * directly takes guest page buffers when sending, make sure
30261815338dSHao Xiang          * everything will work alright even if guest page is changing.
30271815338dSHao Xiang          */
30281815338dSHao Xiang         .live = true,
30291815338dSHao Xiang     };
30301815338dSHao Xiang     test_precopy_common(&args);
30311815338dSHao Xiang }
30321815338dSHao Xiang 
test_multifd_tcp_channels_none(void)30339d36d62cSHet Gala static void test_multifd_tcp_channels_none(void)
30349d36d62cSHet Gala {
30359d36d62cSHet Gala     MigrateCommon args = {
30369d36d62cSHet Gala         .listen_uri = "defer",
30379d36d62cSHet Gala         .start_hook = test_migrate_precopy_tcp_multifd_start,
30389d36d62cSHet Gala         .live = true,
3039*19e56616SFabiano Rosas         .connect_channels = ("[ { 'channel-type': 'main',"
30409d36d62cSHet Gala                              "    'addr': { 'transport': 'socket',"
30419d36d62cSHet Gala                              "              'type': 'inet',"
30429d36d62cSHet Gala                              "              'host': '127.0.0.1',"
3043*19e56616SFabiano Rosas                              "              'port': '0' } } ]"),
30449d36d62cSHet Gala     };
30459d36d62cSHet Gala     test_precopy_common(&args);
30469d36d62cSHet Gala }
30479d36d62cSHet Gala 
test_multifd_tcp_zlib(void)30487ec2c2b3SJuan Quintela static void test_multifd_tcp_zlib(void)
30497ec2c2b3SJuan Quintela {
3050490facffSDaniel P. Berrangé     MigrateCommon args = {
3051490facffSDaniel P. Berrangé         .listen_uri = "defer",
3052490facffSDaniel P. Berrangé         .start_hook = test_migrate_precopy_tcp_multifd_zlib_start,
3053490facffSDaniel P. Berrangé     };
3054490facffSDaniel P. Berrangé     test_precopy_common(&args);
30557ec2c2b3SJuan Quintela }
30567ec2c2b3SJuan Quintela 
305787dc6f5fSJuan Quintela #ifdef CONFIG_ZSTD
test_multifd_tcp_zstd(void)305887dc6f5fSJuan Quintela static void test_multifd_tcp_zstd(void)
305987dc6f5fSJuan Quintela {
3060490facffSDaniel P. Berrangé     MigrateCommon args = {
3061490facffSDaniel P. Berrangé         .listen_uri = "defer",
3062490facffSDaniel P. Berrangé         .start_hook = test_migrate_precopy_tcp_multifd_zstd_start,
3063490facffSDaniel P. Berrangé     };
3064490facffSDaniel P. Berrangé     test_precopy_common(&args);
306587dc6f5fSJuan Quintela }
306687dc6f5fSJuan Quintela #endif
306787dc6f5fSJuan Quintela 
3068afe166d4SBryan Zhang #ifdef CONFIG_QATZIP
test_multifd_tcp_qatzip(void)3069afe166d4SBryan Zhang static void test_multifd_tcp_qatzip(void)
3070afe166d4SBryan Zhang {
3071afe166d4SBryan Zhang     MigrateCommon args = {
3072afe166d4SBryan Zhang         .listen_uri = "defer",
3073afe166d4SBryan Zhang         .start_hook = test_migrate_precopy_tcp_multifd_qatzip_start,
3074afe166d4SBryan Zhang     };
3075afe166d4SBryan Zhang     test_precopy_common(&args);
3076afe166d4SBryan Zhang }
3077afe166d4SBryan Zhang #endif
3078afe166d4SBryan Zhang 
307908b82d20SYuan Liu #ifdef CONFIG_QPL
test_multifd_tcp_qpl(void)308008b82d20SYuan Liu static void test_multifd_tcp_qpl(void)
308108b82d20SYuan Liu {
308208b82d20SYuan Liu     MigrateCommon args = {
308308b82d20SYuan Liu         .listen_uri = "defer",
308408b82d20SYuan Liu         .start_hook = test_migrate_precopy_tcp_multifd_qpl_start,
308508b82d20SYuan Liu     };
308608b82d20SYuan Liu     test_precopy_common(&args);
308708b82d20SYuan Liu }
308808b82d20SYuan Liu #endif
308908b82d20SYuan Liu 
3090c519caa8SShameer Kolothum #ifdef CONFIG_UADK
test_multifd_tcp_uadk(void)3091c519caa8SShameer Kolothum static void test_multifd_tcp_uadk(void)
3092c519caa8SShameer Kolothum {
3093c519caa8SShameer Kolothum     MigrateCommon args = {
3094c519caa8SShameer Kolothum         .listen_uri = "defer",
3095c519caa8SShameer Kolothum         .start_hook = test_migrate_precopy_tcp_multifd_uadk_start,
3096c519caa8SShameer Kolothum     };
3097c519caa8SShameer Kolothum     test_precopy_common(&args);
3098c519caa8SShameer Kolothum }
3099c519caa8SShameer Kolothum #endif
3100c519caa8SShameer Kolothum 
31014d6d2e87SDaniel P. Berrangé #ifdef CONFIG_GNUTLS
31024d6d2e87SDaniel P. Berrangé static void *
test_migrate_multifd_tcp_tls_psk_start_match(QTestState * from,QTestState * to)31034d6d2e87SDaniel P. Berrangé test_migrate_multifd_tcp_tls_psk_start_match(QTestState *from,
31044d6d2e87SDaniel P. Berrangé                                              QTestState *to)
31054d6d2e87SDaniel P. Berrangé {
31064d6d2e87SDaniel P. Berrangé     test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
31074d6d2e87SDaniel P. Berrangé     return test_migrate_tls_psk_start_match(from, to);
31084d6d2e87SDaniel P. Berrangé }
31094d6d2e87SDaniel P. Berrangé 
31104d6d2e87SDaniel P. Berrangé static void *
test_migrate_multifd_tcp_tls_psk_start_mismatch(QTestState * from,QTestState * to)31114d6d2e87SDaniel P. Berrangé test_migrate_multifd_tcp_tls_psk_start_mismatch(QTestState *from,
31124d6d2e87SDaniel P. Berrangé                                                 QTestState *to)
31134d6d2e87SDaniel P. Berrangé {
31144d6d2e87SDaniel P. Berrangé     test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
31154d6d2e87SDaniel P. Berrangé     return test_migrate_tls_psk_start_mismatch(from, to);
31164d6d2e87SDaniel P. Berrangé }
31174d6d2e87SDaniel P. Berrangé 
3118ff32f1ddSDaniel P. Berrangé #ifdef CONFIG_TASN1
3119ff32f1ddSDaniel P. Berrangé static void *
test_migrate_multifd_tls_x509_start_default_host(QTestState * from,QTestState * to)3120ff32f1ddSDaniel P. Berrangé test_migrate_multifd_tls_x509_start_default_host(QTestState *from,
3121ff32f1ddSDaniel P. Berrangé                                                  QTestState *to)
3122ff32f1ddSDaniel P. Berrangé {
3123ff32f1ddSDaniel P. Berrangé     test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
3124ff32f1ddSDaniel P. Berrangé     return test_migrate_tls_x509_start_default_host(from, to);
3125ff32f1ddSDaniel P. Berrangé }
3126ff32f1ddSDaniel P. Berrangé 
3127ff32f1ddSDaniel P. Berrangé static void *
test_migrate_multifd_tls_x509_start_override_host(QTestState * from,QTestState * to)3128ff32f1ddSDaniel P. Berrangé test_migrate_multifd_tls_x509_start_override_host(QTestState *from,
3129ff32f1ddSDaniel P. Berrangé                                                   QTestState *to)
3130ff32f1ddSDaniel P. Berrangé {
3131ff32f1ddSDaniel P. Berrangé     test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
3132ff32f1ddSDaniel P. Berrangé     return test_migrate_tls_x509_start_override_host(from, to);
3133ff32f1ddSDaniel P. Berrangé }
3134ff32f1ddSDaniel P. Berrangé 
3135ff32f1ddSDaniel P. Berrangé static void *
test_migrate_multifd_tls_x509_start_mismatch_host(QTestState * from,QTestState * to)3136ff32f1ddSDaniel P. Berrangé test_migrate_multifd_tls_x509_start_mismatch_host(QTestState *from,
3137ff32f1ddSDaniel P. Berrangé                                                   QTestState *to)
3138ff32f1ddSDaniel P. Berrangé {
3139ff32f1ddSDaniel P. Berrangé     test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
3140ff32f1ddSDaniel P. Berrangé     return test_migrate_tls_x509_start_mismatch_host(from, to);
3141ff32f1ddSDaniel P. Berrangé }
3142ff32f1ddSDaniel P. Berrangé 
3143ff32f1ddSDaniel P. Berrangé static void *
test_migrate_multifd_tls_x509_start_allow_anon_client(QTestState * from,QTestState * to)3144ff32f1ddSDaniel P. Berrangé test_migrate_multifd_tls_x509_start_allow_anon_client(QTestState *from,
3145ff32f1ddSDaniel P. Berrangé                                                       QTestState *to)
3146ff32f1ddSDaniel P. Berrangé {
3147ff32f1ddSDaniel P. Berrangé     test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
3148ff32f1ddSDaniel P. Berrangé     return test_migrate_tls_x509_start_allow_anon_client(from, to);
3149ff32f1ddSDaniel P. Berrangé }
3150ff32f1ddSDaniel P. Berrangé 
3151ff32f1ddSDaniel P. Berrangé static void *
test_migrate_multifd_tls_x509_start_reject_anon_client(QTestState * from,QTestState * to)3152ff32f1ddSDaniel P. Berrangé test_migrate_multifd_tls_x509_start_reject_anon_client(QTestState *from,
3153ff32f1ddSDaniel P. Berrangé                                                        QTestState *to)
3154ff32f1ddSDaniel P. Berrangé {
3155ff32f1ddSDaniel P. Berrangé     test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
3156ff32f1ddSDaniel P. Berrangé     return test_migrate_tls_x509_start_reject_anon_client(from, to);
3157ff32f1ddSDaniel P. Berrangé }
3158ff32f1ddSDaniel P. Berrangé #endif /* CONFIG_TASN1 */
3159ff32f1ddSDaniel P. Berrangé 
test_multifd_tcp_tls_psk_match(void)31604d6d2e87SDaniel P. Berrangé static void test_multifd_tcp_tls_psk_match(void)
31614d6d2e87SDaniel P. Berrangé {
31624d6d2e87SDaniel P. Berrangé     MigrateCommon args = {
31634d6d2e87SDaniel P. Berrangé         .listen_uri = "defer",
31644d6d2e87SDaniel P. Berrangé         .start_hook = test_migrate_multifd_tcp_tls_psk_start_match,
31654d6d2e87SDaniel P. Berrangé         .finish_hook = test_migrate_tls_psk_finish,
31664d6d2e87SDaniel P. Berrangé     };
31674d6d2e87SDaniel P. Berrangé     test_precopy_common(&args);
31684d6d2e87SDaniel P. Berrangé }
31694d6d2e87SDaniel P. Berrangé 
test_multifd_tcp_tls_psk_mismatch(void)31704d6d2e87SDaniel P. Berrangé static void test_multifd_tcp_tls_psk_mismatch(void)
31714d6d2e87SDaniel P. Berrangé {
31724d6d2e87SDaniel P. Berrangé     MigrateCommon args = {
31734d6d2e87SDaniel P. Berrangé         .start = {
31744d6d2e87SDaniel P. Berrangé             .hide_stderr = true,
31754d6d2e87SDaniel P. Berrangé         },
31764d6d2e87SDaniel P. Berrangé         .listen_uri = "defer",
31774d6d2e87SDaniel P. Berrangé         .start_hook = test_migrate_multifd_tcp_tls_psk_start_mismatch,
31784d6d2e87SDaniel P. Berrangé         .finish_hook = test_migrate_tls_psk_finish,
31794d6d2e87SDaniel P. Berrangé         .result = MIG_TEST_FAIL,
31804d6d2e87SDaniel P. Berrangé     };
31814d6d2e87SDaniel P. Berrangé     test_precopy_common(&args);
31824d6d2e87SDaniel P. Berrangé }
3183ff32f1ddSDaniel P. Berrangé 
3184ff32f1ddSDaniel P. Berrangé #ifdef CONFIG_TASN1
test_multifd_tcp_tls_x509_default_host(void)3185ff32f1ddSDaniel P. Berrangé static void test_multifd_tcp_tls_x509_default_host(void)
3186ff32f1ddSDaniel P. Berrangé {
3187ff32f1ddSDaniel P. Berrangé     MigrateCommon args = {
3188ff32f1ddSDaniel P. Berrangé         .listen_uri = "defer",
3189ff32f1ddSDaniel P. Berrangé         .start_hook = test_migrate_multifd_tls_x509_start_default_host,
3190ff32f1ddSDaniel P. Berrangé         .finish_hook = test_migrate_tls_x509_finish,
3191ff32f1ddSDaniel P. Berrangé     };
3192ff32f1ddSDaniel P. Berrangé     test_precopy_common(&args);
3193ff32f1ddSDaniel P. Berrangé }
3194ff32f1ddSDaniel P. Berrangé 
test_multifd_tcp_tls_x509_override_host(void)3195ff32f1ddSDaniel P. Berrangé static void test_multifd_tcp_tls_x509_override_host(void)
3196ff32f1ddSDaniel P. Berrangé {
3197ff32f1ddSDaniel P. Berrangé     MigrateCommon args = {
3198ff32f1ddSDaniel P. Berrangé         .listen_uri = "defer",
3199ff32f1ddSDaniel P. Berrangé         .start_hook = test_migrate_multifd_tls_x509_start_override_host,
3200ff32f1ddSDaniel P. Berrangé         .finish_hook = test_migrate_tls_x509_finish,
3201ff32f1ddSDaniel P. Berrangé     };
3202ff32f1ddSDaniel P. Berrangé     test_precopy_common(&args);
3203ff32f1ddSDaniel P. Berrangé }
3204ff32f1ddSDaniel P. Berrangé 
test_multifd_tcp_tls_x509_mismatch_host(void)3205ff32f1ddSDaniel P. Berrangé static void test_multifd_tcp_tls_x509_mismatch_host(void)
3206ff32f1ddSDaniel P. Berrangé {
3207ff32f1ddSDaniel P. Berrangé     /*
3208ff32f1ddSDaniel P. Berrangé      * This has different behaviour to the non-multifd case.
3209ff32f1ddSDaniel P. Berrangé      *
3210ff32f1ddSDaniel P. Berrangé      * In non-multifd case when client aborts due to mismatched
3211ff32f1ddSDaniel P. Berrangé      * cert host, the server has already started trying to load
3212ff32f1ddSDaniel P. Berrangé      * migration state, and so it exits with I/O failure.
3213ff32f1ddSDaniel P. Berrangé      *
3214ff32f1ddSDaniel P. Berrangé      * In multifd case when client aborts due to mismatched
3215ff32f1ddSDaniel P. Berrangé      * cert host, the server is still waiting for the other
3216ff32f1ddSDaniel P. Berrangé      * multifd connections to arrive so hasn't started trying
3217ff32f1ddSDaniel P. Berrangé      * to load migration state, and thus just aborts the migration
3218ff32f1ddSDaniel P. Berrangé      * without exiting.
3219ff32f1ddSDaniel P. Berrangé      */
3220ff32f1ddSDaniel P. Berrangé     MigrateCommon args = {
3221ff32f1ddSDaniel P. Berrangé         .start = {
3222ff32f1ddSDaniel P. Berrangé             .hide_stderr = true,
3223ff32f1ddSDaniel P. Berrangé         },
3224ff32f1ddSDaniel P. Berrangé         .listen_uri = "defer",
3225ff32f1ddSDaniel P. Berrangé         .start_hook = test_migrate_multifd_tls_x509_start_mismatch_host,
3226ff32f1ddSDaniel P. Berrangé         .finish_hook = test_migrate_tls_x509_finish,
3227ff32f1ddSDaniel P. Berrangé         .result = MIG_TEST_FAIL,
3228ff32f1ddSDaniel P. Berrangé     };
3229ff32f1ddSDaniel P. Berrangé     test_precopy_common(&args);
3230ff32f1ddSDaniel P. Berrangé }
3231ff32f1ddSDaniel P. Berrangé 
test_multifd_tcp_tls_x509_allow_anon_client(void)3232ff32f1ddSDaniel P. Berrangé static void test_multifd_tcp_tls_x509_allow_anon_client(void)
3233ff32f1ddSDaniel P. Berrangé {
3234ff32f1ddSDaniel P. Berrangé     MigrateCommon args = {
3235ff32f1ddSDaniel P. Berrangé         .listen_uri = "defer",
3236ff32f1ddSDaniel P. Berrangé         .start_hook = test_migrate_multifd_tls_x509_start_allow_anon_client,
3237ff32f1ddSDaniel P. Berrangé         .finish_hook = test_migrate_tls_x509_finish,
3238ff32f1ddSDaniel P. Berrangé     };
3239ff32f1ddSDaniel P. Berrangé     test_precopy_common(&args);
3240ff32f1ddSDaniel P. Berrangé }
3241ff32f1ddSDaniel P. Berrangé 
test_multifd_tcp_tls_x509_reject_anon_client(void)3242ff32f1ddSDaniel P. Berrangé static void test_multifd_tcp_tls_x509_reject_anon_client(void)
3243ff32f1ddSDaniel P. Berrangé {
3244ff32f1ddSDaniel P. Berrangé     MigrateCommon args = {
3245ff32f1ddSDaniel P. Berrangé         .start = {
3246ff32f1ddSDaniel P. Berrangé             .hide_stderr = true,
3247ff32f1ddSDaniel P. Berrangé         },
3248ff32f1ddSDaniel P. Berrangé         .listen_uri = "defer",
3249ff32f1ddSDaniel P. Berrangé         .start_hook = test_migrate_multifd_tls_x509_start_reject_anon_client,
3250ff32f1ddSDaniel P. Berrangé         .finish_hook = test_migrate_tls_x509_finish,
3251ff32f1ddSDaniel P. Berrangé         .result = MIG_TEST_FAIL,
3252ff32f1ddSDaniel P. Berrangé     };
3253ff32f1ddSDaniel P. Berrangé     test_precopy_common(&args);
3254ff32f1ddSDaniel P. Berrangé }
3255ff32f1ddSDaniel P. Berrangé #endif /* CONFIG_TASN1 */
32564d6d2e87SDaniel P. Berrangé #endif /* CONFIG_GNUTLS */
32574d6d2e87SDaniel P. Berrangé 
3258d795f474SJuan Quintela /*
3259d795f474SJuan Quintela  * This test does:
3260d795f474SJuan Quintela  *  source               target
3261d795f474SJuan Quintela  *                       migrate_incoming
3262d795f474SJuan Quintela  *     migrate
3263d795f474SJuan Quintela  *     migrate_cancel
3264d795f474SJuan Quintela  *                       launch another target
3265d795f474SJuan Quintela  *     migrate
3266d795f474SJuan Quintela  *
3267d795f474SJuan Quintela  *  And see that it works
3268d795f474SJuan Quintela  */
test_multifd_tcp_cancel(void)3269d795f474SJuan Quintela static void test_multifd_tcp_cancel(void)
3270d795f474SJuan Quintela {
327119da6edfSDaniel P. Berrangé     MigrateStart args = {
327219da6edfSDaniel P. Berrangé         .hide_stderr = true,
327319da6edfSDaniel P. Berrangé     };
3274d795f474SJuan Quintela     QTestState *from, *to, *to2;
3275d795f474SJuan Quintela 
32763ff57401SPeter Xu     if (test_migrate_start(&from, &to, "defer", &args)) {
3277d795f474SJuan Quintela         return;
3278d795f474SJuan Quintela     }
3279d795f474SJuan Quintela 
3280886dfe9dSDaniel P. Berrangé     migrate_ensure_non_converge(from);
3281e02f56e3SDaniel P. Berrangé     migrate_prepare_for_dirty_mem(from);
3282d795f474SJuan Quintela 
3283d795f474SJuan Quintela     migrate_set_parameter_int(from, "multifd-channels", 16);
3284d795f474SJuan Quintela     migrate_set_parameter_int(to, "multifd-channels", 16);
3285d795f474SJuan Quintela 
3286a1209bb7SDr. David Alan Gilbert     migrate_set_capability(from, "multifd", true);
3287a1209bb7SDr. David Alan Gilbert     migrate_set_capability(to, "multifd", true);
3288d795f474SJuan Quintela 
3289d795f474SJuan Quintela     /* Start incoming migration from the 1st socket */
32906830e53bSFabiano Rosas     migrate_incoming_qmp(to, "tcp:127.0.0.1:0", "{}");
3291d795f474SJuan Quintela 
3292d795f474SJuan Quintela     /* Wait for the first serial output from the source */
3293d795f474SJuan Quintela     wait_for_serial("src_serial");
3294d795f474SJuan Quintela 
3295d5ee387dSHet Gala     migrate_qmp(from, to, NULL, NULL, "{}");
3296d795f474SJuan Quintela 
3297e02f56e3SDaniel P. Berrangé     migrate_wait_for_dirty_mem(from, to);
3298d795f474SJuan Quintela 
3299d795f474SJuan Quintela     migrate_cancel(from);
3300d795f474SJuan Quintela 
3301f2d063e6SXuzhou Cheng     /* Make sure QEMU process "to" exited */
3302f2d063e6SXuzhou Cheng     qtest_set_expected_status(to, EXIT_FAILURE);
3303f2d063e6SXuzhou Cheng     qtest_wait_qemu(to);
3304854f67faSPeter Maydell     qtest_quit(to);
3305f2d063e6SXuzhou Cheng 
33069adcdd49SJuraj Marcin     /*
33079adcdd49SJuraj Marcin      * Ensure the source QEMU finishes its cancellation process before we
33089adcdd49SJuraj Marcin      * proceed with the setup of the next migration. The test_migrate_start()
33099adcdd49SJuraj Marcin      * function and others might want to interact with the source in a way that
33109adcdd49SJuraj Marcin      * is not possible while the migration is not canceled properly. For
33119adcdd49SJuraj Marcin      * example, setting migration capabilities when the migration is still
33129adcdd49SJuraj Marcin      * running leads to an error.
33139adcdd49SJuraj Marcin      */
33149adcdd49SJuraj Marcin     wait_for_migration_status(from, "cancelled", NULL);
33159adcdd49SJuraj Marcin 
331619da6edfSDaniel P. Berrangé     args = (MigrateStart){
331719da6edfSDaniel P. Berrangé         .only_target = true,
331819da6edfSDaniel P. Berrangé     };
3319d795f474SJuan Quintela 
33203ff57401SPeter Xu     if (test_migrate_start(&from, &to2, "defer", &args)) {
3321d795f474SJuan Quintela         return;
3322d795f474SJuan Quintela     }
3323d795f474SJuan Quintela 
3324d795f474SJuan Quintela     migrate_set_parameter_int(to2, "multifd-channels", 16);
3325d795f474SJuan Quintela 
3326a1209bb7SDr. David Alan Gilbert     migrate_set_capability(to2, "multifd", true);
3327d795f474SJuan Quintela 
3328d795f474SJuan Quintela     /* Start incoming migration from the 1st socket */
33296830e53bSFabiano Rosas     migrate_incoming_qmp(to2, "tcp:127.0.0.1:0", "{}");
3330d795f474SJuan Quintela 
3331e02f56e3SDaniel P. Berrangé     migrate_ensure_non_converge(from);
3332d795f474SJuan Quintela 
3333d5ee387dSHet Gala     migrate_qmp(from, to2, NULL, NULL, "{}");
3334d795f474SJuan Quintela 
333594aaf6d8SFabiano Rosas     migrate_wait_for_dirty_mem(from, to2);
3336e02f56e3SDaniel P. Berrangé 
3337e02f56e3SDaniel P. Berrangé     migrate_ensure_converge(from);
3338d795f474SJuan Quintela 
3339f0649758SSteve Sistare     wait_for_stop(from, &src_state);
3340d795f474SJuan Quintela     qtest_qmp_eventwait(to2, "RESUME");
3341d795f474SJuan Quintela 
3342d795f474SJuan Quintela     wait_for_serial("dest_serial");
3343d795f474SJuan Quintela     wait_for_migration_complete(from);
3344d795f474SJuan Quintela     test_migrate_end(from, to2, true);
3345d795f474SJuan Quintela }
3346d795f474SJuan Quintela 
calc_dirty_rate(QTestState * who,uint64_t calc_time)33478aff6f50SHyman Huang(黄勇) static void calc_dirty_rate(QTestState *who, uint64_t calc_time)
33488aff6f50SHyman Huang(黄勇) {
3349ffd47275SDaniel P. Berrangé     qtest_qmp_assert_success(who,
33508aff6f50SHyman Huang(黄勇)                              "{ 'execute': 'calc-dirty-rate',"
33518aff6f50SHyman Huang(黄勇)                              "'arguments': { "
3352d46e6bbaSStefan Weil                              "'calc-time': %" PRIu64 ","
33538aff6f50SHyman Huang(黄勇)                              "'mode': 'dirty-ring' }}",
3354ffd47275SDaniel P. Berrangé                              calc_time);
33558aff6f50SHyman Huang(黄勇) }
33568aff6f50SHyman Huang(黄勇) 
query_dirty_rate(QTestState * who)33578aff6f50SHyman Huang(黄勇) static QDict *query_dirty_rate(QTestState *who)
33588aff6f50SHyman Huang(黄勇) {
3359ffd47275SDaniel P. Berrangé     return qtest_qmp_assert_success_ref(who,
3360ffd47275SDaniel P. Berrangé                                         "{ 'execute': 'query-dirty-rate' }");
33618aff6f50SHyman Huang(黄勇) }
33628aff6f50SHyman Huang(黄勇) 
dirtylimit_set_all(QTestState * who,uint64_t dirtyrate)33638aff6f50SHyman Huang(黄勇) static void dirtylimit_set_all(QTestState *who, uint64_t dirtyrate)
33648aff6f50SHyman Huang(黄勇) {
3365ffd47275SDaniel P. Berrangé     qtest_qmp_assert_success(who,
33668aff6f50SHyman Huang(黄勇)                              "{ 'execute': 'set-vcpu-dirty-limit',"
33678aff6f50SHyman Huang(黄勇)                              "'arguments': { "
3368d46e6bbaSStefan Weil                              "'dirty-rate': %" PRIu64 " } }",
3369ffd47275SDaniel P. Berrangé                              dirtyrate);
33708aff6f50SHyman Huang(黄勇) }
33718aff6f50SHyman Huang(黄勇) 
cancel_vcpu_dirty_limit(QTestState * who)33728aff6f50SHyman Huang(黄勇) static void cancel_vcpu_dirty_limit(QTestState *who)
33738aff6f50SHyman Huang(黄勇) {
3374ffd47275SDaniel P. Berrangé     qtest_qmp_assert_success(who,
3375ffd47275SDaniel P. Berrangé                              "{ 'execute': 'cancel-vcpu-dirty-limit' }");
33768aff6f50SHyman Huang(黄勇) }
33778aff6f50SHyman Huang(黄勇) 
query_vcpu_dirty_limit(QTestState * who)33788aff6f50SHyman Huang(黄勇) static QDict *query_vcpu_dirty_limit(QTestState *who)
33798aff6f50SHyman Huang(黄勇) {
33808aff6f50SHyman Huang(黄勇)     QDict *rsp;
33818aff6f50SHyman Huang(黄勇) 
33828aff6f50SHyman Huang(黄勇)     rsp = qtest_qmp(who, "{ 'execute': 'query-vcpu-dirty-limit' }");
33838aff6f50SHyman Huang(黄勇)     g_assert(!qdict_haskey(rsp, "error"));
33848aff6f50SHyman Huang(黄勇)     g_assert(qdict_haskey(rsp, "return"));
33858aff6f50SHyman Huang(黄勇) 
33868aff6f50SHyman Huang(黄勇)     return rsp;
33878aff6f50SHyman Huang(黄勇) }
33888aff6f50SHyman Huang(黄勇) 
calc_dirtyrate_ready(QTestState * who)33898aff6f50SHyman Huang(黄勇) static bool calc_dirtyrate_ready(QTestState *who)
33908aff6f50SHyman Huang(黄勇) {
33918aff6f50SHyman Huang(黄勇)     QDict *rsp_return;
3392f0d74774SPeter Maydell     const char *status;
3393f0d74774SPeter Maydell     bool ready;
33948aff6f50SHyman Huang(黄勇) 
33958aff6f50SHyman Huang(黄勇)     rsp_return = query_dirty_rate(who);
33968aff6f50SHyman Huang(黄勇)     g_assert(rsp_return);
33978aff6f50SHyman Huang(黄勇) 
3398f0d74774SPeter Maydell     status = qdict_get_str(rsp_return, "status");
33998aff6f50SHyman Huang(黄勇)     g_assert(status);
3400f0d74774SPeter Maydell     ready = g_strcmp0(status, "measuring");
3401f0d74774SPeter Maydell     qobject_unref(rsp_return);
34028aff6f50SHyman Huang(黄勇) 
3403f0d74774SPeter Maydell     return ready;
34048aff6f50SHyman Huang(黄勇) }
34058aff6f50SHyman Huang(黄勇) 
wait_for_calc_dirtyrate_complete(QTestState * who,int64_t time_s)34068aff6f50SHyman Huang(黄勇) static void wait_for_calc_dirtyrate_complete(QTestState *who,
34078aff6f50SHyman Huang(黄勇)                                              int64_t time_s)
34088aff6f50SHyman Huang(黄勇) {
34098aff6f50SHyman Huang(黄勇)     int max_try_count = 10000;
34108aff6f50SHyman Huang(黄勇)     usleep(time_s * 1000000);
34118aff6f50SHyman Huang(黄勇) 
34128aff6f50SHyman Huang(黄勇)     while (!calc_dirtyrate_ready(who) && max_try_count--) {
34138aff6f50SHyman Huang(黄勇)         usleep(1000);
34148aff6f50SHyman Huang(黄勇)     }
34158aff6f50SHyman Huang(黄勇) 
34168aff6f50SHyman Huang(黄勇)     /*
34178aff6f50SHyman Huang(黄勇)      * Set the timeout with 10 s(max_try_count * 1000us),
34188aff6f50SHyman Huang(黄勇)      * if dirtyrate measurement not complete, fail test.
34198aff6f50SHyman Huang(黄勇)      */
34208aff6f50SHyman Huang(黄勇)     g_assert_cmpint(max_try_count, !=, 0);
34218aff6f50SHyman Huang(黄勇) }
34228aff6f50SHyman Huang(黄勇) 
get_dirty_rate(QTestState * who)34238aff6f50SHyman Huang(黄勇) static int64_t get_dirty_rate(QTestState *who)
34248aff6f50SHyman Huang(黄勇) {
34258aff6f50SHyman Huang(黄勇)     QDict *rsp_return;
342678a053bcSPeter Maydell     const char *status;
34278aff6f50SHyman Huang(黄勇)     QList *rates;
34288aff6f50SHyman Huang(黄勇)     const QListEntry *entry;
34298aff6f50SHyman Huang(黄勇)     QDict *rate;
34308aff6f50SHyman Huang(黄勇)     int64_t dirtyrate;
34318aff6f50SHyman Huang(黄勇) 
34328aff6f50SHyman Huang(黄勇)     rsp_return = query_dirty_rate(who);
34338aff6f50SHyman Huang(黄勇)     g_assert(rsp_return);
34348aff6f50SHyman Huang(黄勇) 
343578a053bcSPeter Maydell     status = qdict_get_str(rsp_return, "status");
34368aff6f50SHyman Huang(黄勇)     g_assert(status);
34378aff6f50SHyman Huang(黄勇)     g_assert_cmpstr(status, ==, "measured");
34388aff6f50SHyman Huang(黄勇) 
34398aff6f50SHyman Huang(黄勇)     rates = qdict_get_qlist(rsp_return, "vcpu-dirty-rate");
34408aff6f50SHyman Huang(黄勇)     g_assert(rates && !qlist_empty(rates));
34418aff6f50SHyman Huang(黄勇) 
34428aff6f50SHyman Huang(黄勇)     entry = qlist_first(rates);
34438aff6f50SHyman Huang(黄勇)     g_assert(entry);
34448aff6f50SHyman Huang(黄勇) 
34458aff6f50SHyman Huang(黄勇)     rate = qobject_to(QDict, qlist_entry_obj(entry));
34468aff6f50SHyman Huang(黄勇)     g_assert(rate);
34478aff6f50SHyman Huang(黄勇) 
34488aff6f50SHyman Huang(黄勇)     dirtyrate = qdict_get_try_int(rate, "dirty-rate", -1);
34498aff6f50SHyman Huang(黄勇) 
34508aff6f50SHyman Huang(黄勇)     qobject_unref(rsp_return);
34518aff6f50SHyman Huang(黄勇)     return dirtyrate;
34528aff6f50SHyman Huang(黄勇) }
34538aff6f50SHyman Huang(黄勇) 
get_limit_rate(QTestState * who)34548aff6f50SHyman Huang(黄勇) static int64_t get_limit_rate(QTestState *who)
34558aff6f50SHyman Huang(黄勇) {
34568aff6f50SHyman Huang(黄勇)     QDict *rsp_return;
34578aff6f50SHyman Huang(黄勇)     QList *rates;
34588aff6f50SHyman Huang(黄勇)     const QListEntry *entry;
34598aff6f50SHyman Huang(黄勇)     QDict *rate;
34608aff6f50SHyman Huang(黄勇)     int64_t dirtyrate;
34618aff6f50SHyman Huang(黄勇) 
34628aff6f50SHyman Huang(黄勇)     rsp_return = query_vcpu_dirty_limit(who);
34638aff6f50SHyman Huang(黄勇)     g_assert(rsp_return);
34648aff6f50SHyman Huang(黄勇) 
34658aff6f50SHyman Huang(黄勇)     rates = qdict_get_qlist(rsp_return, "return");
34668aff6f50SHyman Huang(黄勇)     g_assert(rates && !qlist_empty(rates));
34678aff6f50SHyman Huang(黄勇) 
34688aff6f50SHyman Huang(黄勇)     entry = qlist_first(rates);
34698aff6f50SHyman Huang(黄勇)     g_assert(entry);
34708aff6f50SHyman Huang(黄勇) 
34718aff6f50SHyman Huang(黄勇)     rate = qobject_to(QDict, qlist_entry_obj(entry));
34728aff6f50SHyman Huang(黄勇)     g_assert(rate);
34738aff6f50SHyman Huang(黄勇) 
34748aff6f50SHyman Huang(黄勇)     dirtyrate = qdict_get_try_int(rate, "limit-rate", -1);
34758aff6f50SHyman Huang(黄勇) 
34768aff6f50SHyman Huang(黄勇)     qobject_unref(rsp_return);
34778aff6f50SHyman Huang(黄勇)     return dirtyrate;
34788aff6f50SHyman Huang(黄勇) }
34798aff6f50SHyman Huang(黄勇) 
dirtylimit_start_vm(void)34808aff6f50SHyman Huang(黄勇) static QTestState *dirtylimit_start_vm(void)
34818aff6f50SHyman Huang(黄勇) {
34828aff6f50SHyman Huang(黄勇)     QTestState *vm = NULL;
34835014478eSSteve Sistare     g_autofree gchar *cmd = NULL;
34845014478eSSteve Sistare 
34855014478eSSteve Sistare     bootfile_create(tmpfs, false);
34868aff6f50SHyman Huang(黄勇)     cmd = g_strdup_printf("-accel kvm,dirty-ring-size=4096 "
34878aff6f50SHyman Huang(黄勇)                           "-name dirtylimit-test,debug-threads=on "
34888aff6f50SHyman Huang(黄勇)                           "-m 150M -smp 1 "
34898aff6f50SHyman Huang(黄勇)                           "-serial file:%s/vm_serial "
34908aff6f50SHyman Huang(黄勇)                           "-drive file=%s,format=raw ",
34918aff6f50SHyman Huang(黄勇)                           tmpfs, bootpath);
34928aff6f50SHyman Huang(黄勇) 
34938aff6f50SHyman Huang(黄勇)     vm = qtest_init(cmd);
34948aff6f50SHyman Huang(黄勇)     return vm;
34958aff6f50SHyman Huang(黄勇) }
34968aff6f50SHyman Huang(黄勇) 
dirtylimit_stop_vm(QTestState * vm)34978aff6f50SHyman Huang(黄勇) static void dirtylimit_stop_vm(QTestState *vm)
34988aff6f50SHyman Huang(黄勇) {
34998aff6f50SHyman Huang(黄勇)     qtest_quit(vm);
35008aff6f50SHyman Huang(黄勇)     cleanup("vm_serial");
35018aff6f50SHyman Huang(黄勇) }
35028aff6f50SHyman Huang(黄勇) 
test_vcpu_dirty_limit(void)35038aff6f50SHyman Huang(黄勇) static void test_vcpu_dirty_limit(void)
35048aff6f50SHyman Huang(黄勇) {
35058aff6f50SHyman Huang(黄勇)     QTestState *vm;
35068aff6f50SHyman Huang(黄勇)     int64_t origin_rate;
35078aff6f50SHyman Huang(黄勇)     int64_t quota_rate;
35088aff6f50SHyman Huang(黄勇)     int64_t rate ;
35098aff6f50SHyman Huang(黄勇)     int max_try_count = 20;
35108aff6f50SHyman Huang(黄勇)     int hit = 0;
35118aff6f50SHyman Huang(黄勇) 
35128aff6f50SHyman Huang(黄勇)     /* Start vm for vcpu dirtylimit test */
35138aff6f50SHyman Huang(黄勇)     vm = dirtylimit_start_vm();
35148aff6f50SHyman Huang(黄勇) 
35158aff6f50SHyman Huang(黄勇)     /* Wait for the first serial output from the vm*/
35168aff6f50SHyman Huang(黄勇)     wait_for_serial("vm_serial");
35178aff6f50SHyman Huang(黄勇) 
35188aff6f50SHyman Huang(黄勇)     /* Do dirtyrate measurement with calc time equals 1s */
35198aff6f50SHyman Huang(黄勇)     calc_dirty_rate(vm, 1);
35208aff6f50SHyman Huang(黄勇) 
35218aff6f50SHyman Huang(黄勇)     /* Sleep calc time and wait for calc dirtyrate complete */
35228aff6f50SHyman Huang(黄勇)     wait_for_calc_dirtyrate_complete(vm, 1);
35238aff6f50SHyman Huang(黄勇) 
35248aff6f50SHyman Huang(黄勇)     /* Query original dirty page rate */
35258aff6f50SHyman Huang(黄勇)     origin_rate = get_dirty_rate(vm);
35268aff6f50SHyman Huang(黄勇) 
35278aff6f50SHyman Huang(黄勇)     /* VM booted from bootsect should dirty memory steadily */
35288aff6f50SHyman Huang(黄勇)     assert(origin_rate != 0);
35298aff6f50SHyman Huang(黄勇) 
35308aff6f50SHyman Huang(黄勇)     /* Setup quota dirty page rate at half of origin */
35318aff6f50SHyman Huang(黄勇)     quota_rate = origin_rate / 2;
35328aff6f50SHyman Huang(黄勇) 
35338aff6f50SHyman Huang(黄勇)     /* Set dirtylimit */
35348aff6f50SHyman Huang(黄勇)     dirtylimit_set_all(vm, quota_rate);
35358aff6f50SHyman Huang(黄勇) 
35368aff6f50SHyman Huang(黄勇)     /*
35378aff6f50SHyman Huang(黄勇)      * Check if set-vcpu-dirty-limit and query-vcpu-dirty-limit
35388aff6f50SHyman Huang(黄勇)      * works literally
35398aff6f50SHyman Huang(黄勇)      */
35408aff6f50SHyman Huang(黄勇)     g_assert_cmpint(quota_rate, ==, get_limit_rate(vm));
35418aff6f50SHyman Huang(黄勇) 
35428aff6f50SHyman Huang(黄勇)     /* Sleep a bit to check if it take effect */
35438aff6f50SHyman Huang(黄勇)     usleep(2000000);
35448aff6f50SHyman Huang(黄勇) 
35458aff6f50SHyman Huang(黄勇)     /*
35468aff6f50SHyman Huang(黄勇)      * Check if dirtylimit take effect realistically, set the
35478aff6f50SHyman Huang(黄勇)      * timeout with 20 s(max_try_count * 1s), if dirtylimit
35488aff6f50SHyman Huang(黄勇)      * doesn't take effect, fail test.
35498aff6f50SHyman Huang(黄勇)      */
35508aff6f50SHyman Huang(黄勇)     while (--max_try_count) {
35518aff6f50SHyman Huang(黄勇)         calc_dirty_rate(vm, 1);
35528aff6f50SHyman Huang(黄勇)         wait_for_calc_dirtyrate_complete(vm, 1);
35538aff6f50SHyman Huang(黄勇)         rate = get_dirty_rate(vm);
35548aff6f50SHyman Huang(黄勇) 
35558aff6f50SHyman Huang(黄勇)         /*
35568aff6f50SHyman Huang(黄勇)          * Assume hitting if current rate is less
35578aff6f50SHyman Huang(黄勇)          * than quota rate (within accepting error)
35588aff6f50SHyman Huang(黄勇)          */
35598aff6f50SHyman Huang(黄勇)         if (rate < (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) {
35608aff6f50SHyman Huang(黄勇)             hit = 1;
35618aff6f50SHyman Huang(黄勇)             break;
35628aff6f50SHyman Huang(黄勇)         }
35638aff6f50SHyman Huang(黄勇)     }
35648aff6f50SHyman Huang(黄勇) 
35658aff6f50SHyman Huang(黄勇)     g_assert_cmpint(hit, ==, 1);
35668aff6f50SHyman Huang(黄勇) 
35678aff6f50SHyman Huang(黄勇)     hit = 0;
35688aff6f50SHyman Huang(黄勇)     max_try_count = 20;
35698aff6f50SHyman Huang(黄勇) 
35708aff6f50SHyman Huang(黄勇)     /* Check if dirtylimit cancellation take effect */
35718aff6f50SHyman Huang(黄勇)     cancel_vcpu_dirty_limit(vm);
35728aff6f50SHyman Huang(黄勇)     while (--max_try_count) {
35738aff6f50SHyman Huang(黄勇)         calc_dirty_rate(vm, 1);
35748aff6f50SHyman Huang(黄勇)         wait_for_calc_dirtyrate_complete(vm, 1);
35758aff6f50SHyman Huang(黄勇)         rate = get_dirty_rate(vm);
35768aff6f50SHyman Huang(黄勇) 
35778aff6f50SHyman Huang(黄勇)         /*
35788aff6f50SHyman Huang(黄勇)          * Assume dirtylimit be canceled if current rate is
35798aff6f50SHyman Huang(黄勇)          * greater than quota rate (within accepting error)
35808aff6f50SHyman Huang(黄勇)          */
35818aff6f50SHyman Huang(黄勇)         if (rate > (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) {
35828aff6f50SHyman Huang(黄勇)             hit = 1;
35838aff6f50SHyman Huang(黄勇)             break;
35848aff6f50SHyman Huang(黄勇)         }
35858aff6f50SHyman Huang(黄勇)     }
35868aff6f50SHyman Huang(黄勇) 
35878aff6f50SHyman Huang(黄勇)     g_assert_cmpint(hit, ==, 1);
35888aff6f50SHyman Huang(黄勇)     dirtylimit_stop_vm(vm);
35898aff6f50SHyman Huang(黄勇) }
35908aff6f50SHyman Huang(黄勇) 
migrate_dirty_limit_wait_showup(QTestState * from,const int64_t period,const int64_t value)359117257b90SHyman Huang static void migrate_dirty_limit_wait_showup(QTestState *from,
359217257b90SHyman Huang                                             const int64_t period,
359317257b90SHyman Huang                                             const int64_t value)
359417257b90SHyman Huang {
359517257b90SHyman Huang     /* Enable dirty limit capability */
359617257b90SHyman Huang     migrate_set_capability(from, "dirty-limit", true);
359717257b90SHyman Huang 
359817257b90SHyman Huang     /* Set dirty limit parameters */
359917257b90SHyman Huang     migrate_set_parameter_int(from, "x-vcpu-dirty-limit-period", period);
360017257b90SHyman Huang     migrate_set_parameter_int(from, "vcpu-dirty-limit", value);
360117257b90SHyman Huang 
360217257b90SHyman Huang     /* Make sure migrate can't converge */
360317257b90SHyman Huang     migrate_ensure_non_converge(from);
360417257b90SHyman Huang 
360517257b90SHyman Huang     /* To check limit rate after precopy */
360617257b90SHyman Huang     migrate_set_capability(from, "pause-before-switchover", true);
360717257b90SHyman Huang 
360817257b90SHyman Huang     /* Wait for the serial output from the source */
360917257b90SHyman Huang     wait_for_serial("src_serial");
361017257b90SHyman Huang }
361117257b90SHyman Huang 
361217257b90SHyman Huang /*
361317257b90SHyman Huang  * This test does:
361417257b90SHyman Huang  *  source                          destination
361517257b90SHyman Huang  *  start vm
361617257b90SHyman Huang  *                                  start incoming vm
361717257b90SHyman Huang  *  migrate
361817257b90SHyman Huang  *  wait dirty limit to begin
361917257b90SHyman Huang  *  cancel migrate
362017257b90SHyman Huang  *  cancellation check
362117257b90SHyman Huang  *                                  restart incoming vm
362217257b90SHyman Huang  *  migrate
362317257b90SHyman Huang  *  wait dirty limit to begin
362417257b90SHyman Huang  *  wait pre-switchover event
362517257b90SHyman Huang  *  convergence condition check
362617257b90SHyman Huang  *
362717257b90SHyman Huang  * And see if dirty limit migration works correctly.
362817257b90SHyman Huang  * This test case involves many passes, so it runs in slow mode only.
362917257b90SHyman Huang  */
test_migrate_dirty_limit(void)363017257b90SHyman Huang static void test_migrate_dirty_limit(void)
363117257b90SHyman Huang {
363217257b90SHyman Huang     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
363317257b90SHyman Huang     QTestState *from, *to;
363417257b90SHyman Huang     int64_t remaining;
363517257b90SHyman Huang     uint64_t throttle_us_per_full;
363617257b90SHyman Huang     /*
363717257b90SHyman Huang      * We want the test to be stable and as fast as possible.
36388053feaaSMichael Tokarev      * E.g., with 1Gb/s bandwidth migration may pass without dirty limit,
363917257b90SHyman Huang      * so we need to decrease a bandwidth.
364017257b90SHyman Huang      */
364117257b90SHyman Huang     const int64_t dirtylimit_period = 1000, dirtylimit_value = 50;
364217257b90SHyman Huang     const int64_t max_bandwidth = 400000000; /* ~400Mb/s */
364317257b90SHyman Huang     const int64_t downtime_limit = 250; /* 250ms */
364417257b90SHyman Huang     /*
364517257b90SHyman Huang      * We migrate through unix-socket (> 500Mb/s).
364617257b90SHyman Huang      * Thus, expected migration speed ~= bandwidth limit (< 500Mb/s).
364717257b90SHyman Huang      * So, we can predict expected_threshold
364817257b90SHyman Huang      */
364917257b90SHyman Huang     const int64_t expected_threshold = max_bandwidth * downtime_limit / 1000;
365017257b90SHyman Huang     int max_try_count = 10;
365117257b90SHyman Huang     MigrateCommon args = {
365217257b90SHyman Huang         .start = {
365317257b90SHyman Huang             .hide_stderr = true,
365417257b90SHyman Huang             .use_dirty_ring = true,
365517257b90SHyman Huang         },
365617257b90SHyman Huang         .listen_uri = uri,
365717257b90SHyman Huang         .connect_uri = uri,
365817257b90SHyman Huang     };
365917257b90SHyman Huang 
366017257b90SHyman Huang     /* Start src, dst vm */
366117257b90SHyman Huang     if (test_migrate_start(&from, &to, args.listen_uri, &args.start)) {
366217257b90SHyman Huang         return;
366317257b90SHyman Huang     }
366417257b90SHyman Huang 
366517257b90SHyman Huang     /* Prepare for dirty limit migration and wait src vm show up */
366617257b90SHyman Huang     migrate_dirty_limit_wait_showup(from, dirtylimit_period, dirtylimit_value);
366717257b90SHyman Huang 
366817257b90SHyman Huang     /* Start migrate */
3669d5ee387dSHet Gala     migrate_qmp(from, to, args.connect_uri, NULL, "{}");
367017257b90SHyman Huang 
367117257b90SHyman Huang     /* Wait for dirty limit throttle begin */
367217257b90SHyman Huang     throttle_us_per_full = 0;
367317257b90SHyman Huang     while (throttle_us_per_full == 0) {
367417257b90SHyman Huang         throttle_us_per_full =
3675*19e56616SFabiano Rosas             read_migrate_property_int(from,
3676*19e56616SFabiano Rosas                                       "dirty-limit-throttle-time-per-round");
367717257b90SHyman Huang         usleep(100);
3678f0649758SSteve Sistare         g_assert_false(src_state.stop_seen);
367917257b90SHyman Huang     }
368017257b90SHyman Huang 
368117257b90SHyman Huang     /* Now cancel migrate and wait for dirty limit throttle switch off */
368217257b90SHyman Huang     migrate_cancel(from);
368317257b90SHyman Huang     wait_for_migration_status(from, "cancelled", NULL);
368417257b90SHyman Huang 
368517257b90SHyman Huang     /* Check if dirty limit throttle switched off, set timeout 1ms */
368617257b90SHyman Huang     do {
368717257b90SHyman Huang         throttle_us_per_full =
3688*19e56616SFabiano Rosas             read_migrate_property_int(from,
3689*19e56616SFabiano Rosas                                       "dirty-limit-throttle-time-per-round");
369017257b90SHyman Huang         usleep(100);
3691f0649758SSteve Sistare         g_assert_false(src_state.stop_seen);
369217257b90SHyman Huang     } while (throttle_us_per_full != 0 && --max_try_count);
369317257b90SHyman Huang 
369417257b90SHyman Huang     /* Assert dirty limit is not in service */
369517257b90SHyman Huang     g_assert_cmpint(throttle_us_per_full, ==, 0);
369617257b90SHyman Huang 
369717257b90SHyman Huang     args = (MigrateCommon) {
369817257b90SHyman Huang         .start = {
369917257b90SHyman Huang             .only_target = true,
370017257b90SHyman Huang             .use_dirty_ring = true,
370117257b90SHyman Huang         },
370217257b90SHyman Huang         .listen_uri = uri,
370317257b90SHyman Huang         .connect_uri = uri,
370417257b90SHyman Huang     };
370517257b90SHyman Huang 
370617257b90SHyman Huang     /* Restart dst vm, src vm already show up so we needn't wait anymore */
370717257b90SHyman Huang     if (test_migrate_start(&from, &to, args.listen_uri, &args.start)) {
370817257b90SHyman Huang         return;
370917257b90SHyman Huang     }
371017257b90SHyman Huang 
371117257b90SHyman Huang     /* Start migrate */
3712d5ee387dSHet Gala     migrate_qmp(from, to, args.connect_uri, NULL, "{}");
371317257b90SHyman Huang 
371417257b90SHyman Huang     /* Wait for dirty limit throttle begin */
371517257b90SHyman Huang     throttle_us_per_full = 0;
371617257b90SHyman Huang     while (throttle_us_per_full == 0) {
371717257b90SHyman Huang         throttle_us_per_full =
3718*19e56616SFabiano Rosas             read_migrate_property_int(from,
3719*19e56616SFabiano Rosas                                       "dirty-limit-throttle-time-per-round");
372017257b90SHyman Huang         usleep(100);
3721f0649758SSteve Sistare         g_assert_false(src_state.stop_seen);
372217257b90SHyman Huang     }
372317257b90SHyman Huang 
372417257b90SHyman Huang     /*
372517257b90SHyman Huang      * The dirty limit rate should equals the return value of
372617257b90SHyman Huang      * query-vcpu-dirty-limit if dirty limit cap set
372717257b90SHyman Huang      */
372817257b90SHyman Huang     g_assert_cmpint(dirtylimit_value, ==, get_limit_rate(from));
372917257b90SHyman Huang 
373017257b90SHyman Huang     /* Now, we have tested if dirty limit works, let it converge */
373117257b90SHyman Huang     migrate_set_parameter_int(from, "downtime-limit", downtime_limit);
373217257b90SHyman Huang     migrate_set_parameter_int(from, "max-bandwidth", max_bandwidth);
373317257b90SHyman Huang 
373417257b90SHyman Huang     /*
373517257b90SHyman Huang      * Wait for pre-switchover status to check if migration
373617257b90SHyman Huang      * satisfy the convergence condition
373717257b90SHyman Huang      */
373817257b90SHyman Huang     wait_for_migration_status(from, "pre-switchover", NULL);
373917257b90SHyman Huang 
374017257b90SHyman Huang     remaining = read_ram_property_int(from, "remaining");
374117257b90SHyman Huang     g_assert_cmpint(remaining, <,
374217257b90SHyman Huang                     (expected_threshold + expected_threshold / 100));
374317257b90SHyman Huang 
374417257b90SHyman Huang     migrate_continue(from, "pre-switchover");
374517257b90SHyman Huang 
374617257b90SHyman Huang     qtest_qmp_eventwait(to, "RESUME");
374717257b90SHyman Huang 
374817257b90SHyman Huang     wait_for_serial("dest_serial");
374917257b90SHyman Huang     wait_for_migration_complete(from);
375017257b90SHyman Huang 
375117257b90SHyman Huang     test_migrate_end(from, to, true);
375217257b90SHyman Huang }
375317257b90SHyman Huang 
kvm_dirty_ring_supported(void)37541f546b70SPeter Xu static bool kvm_dirty_ring_supported(void)
37551f546b70SPeter Xu {
375661c32485SPeter Xu #if defined(__linux__) && defined(HOST_X86_64)
37571f546b70SPeter Xu     int ret, kvm_fd = open("/dev/kvm", O_RDONLY);
37581f546b70SPeter Xu 
37591f546b70SPeter Xu     if (kvm_fd < 0) {
37601f546b70SPeter Xu         return false;
37611f546b70SPeter Xu     }
37621f546b70SPeter Xu 
37631f546b70SPeter Xu     ret = ioctl(kvm_fd, KVM_CHECK_EXTENSION, KVM_CAP_DIRTY_LOG_RING);
37641f546b70SPeter Xu     close(kvm_fd);
37651f546b70SPeter Xu 
37661f546b70SPeter Xu     /* We test with 4096 slots */
37671f546b70SPeter Xu     if (ret < 4096) {
37681f546b70SPeter Xu         return false;
37691f546b70SPeter Xu     }
37701f546b70SPeter Xu 
37711f546b70SPeter Xu     return true;
37721f546b70SPeter Xu #else
37731f546b70SPeter Xu     return false;
37741f546b70SPeter Xu #endif
37751f546b70SPeter Xu }
37761f546b70SPeter Xu 
main(int argc,char ** argv)37771e8a1faeSThomas Huth int main(int argc, char **argv)
37781e8a1faeSThomas Huth {
37790c1ae3ffSFabiano Rosas     bool has_kvm, has_tcg;
3780b1fdd21eSSteve Sistare     bool has_uffd, is_x86;
3781e35b9a2eSDaniel P. Berrangé     const char *arch;
3782e5553c1bSBin Meng     g_autoptr(GError) err = NULL;
37835050ad2aSFabiano Rosas     const char *qemu_src = getenv(QEMU_ENV_SRC);
37845050ad2aSFabiano Rosas     const char *qemu_dst = getenv(QEMU_ENV_DST);
37851e8a1faeSThomas Huth     int ret;
37861e8a1faeSThomas Huth 
37871e8a1faeSThomas Huth     g_test_init(&argc, &argv, NULL);
37881e8a1faeSThomas Huth 
37895050ad2aSFabiano Rosas     /*
37905050ad2aSFabiano Rosas      * The default QTEST_QEMU_BINARY must always be provided because
37915050ad2aSFabiano Rosas      * that is what helpers use to query the accel type and
37925050ad2aSFabiano Rosas      * architecture.
37935050ad2aSFabiano Rosas      */
37945050ad2aSFabiano Rosas     if (qemu_src && qemu_dst) {
37955050ad2aSFabiano Rosas         g_test_message("Only one of %s, %s is allowed",
37965050ad2aSFabiano Rosas                        QEMU_ENV_SRC, QEMU_ENV_DST);
37975050ad2aSFabiano Rosas         exit(1);
37985050ad2aSFabiano Rosas     }
37995050ad2aSFabiano Rosas 
3800e35b9a2eSDaniel P. Berrangé     has_kvm = qtest_has_accel("kvm");
38010c1ae3ffSFabiano Rosas     has_tcg = qtest_has_accel("tcg");
38020c1ae3ffSFabiano Rosas 
38030c1ae3ffSFabiano Rosas     if (!has_tcg && !has_kvm) {
38040c1ae3ffSFabiano Rosas         g_test_skip("No KVM or TCG accelerator available");
38050c1ae3ffSFabiano Rosas         return 0;
38060c1ae3ffSFabiano Rosas     }
38070c1ae3ffSFabiano Rosas 
3808e35b9a2eSDaniel P. Berrangé     has_uffd = ufd_version_check();
3809e35b9a2eSDaniel P. Berrangé     arch = qtest_get_arch();
3810b1fdd21eSSteve Sistare     is_x86 = !strcmp(arch, "i386") || !strcmp(arch, "x86_64");
3811e35b9a2eSDaniel P. Berrangé 
3812e5553c1bSBin Meng     tmpfs = g_dir_make_tmp("migration-test-XXXXXX", &err);
38131e8a1faeSThomas Huth     if (!tmpfs) {
3814b1f6208cSBin Meng         g_test_message("Can't create temporary directory in %s: %s",
3815b1f6208cSBin Meng                        g_get_tmp_dir(), err->message);
38161e8a1faeSThomas Huth     }
38171e8a1faeSThomas Huth     g_assert(tmpfs);
38181e8a1faeSThomas Huth 
38191e8a1faeSThomas Huth     module_call_init(MODULE_INIT_QOM);
38201e8a1faeSThomas Huth 
382164853655SThomas Huth     migration_test_add("/migration/bad_dest", test_baddest);
382264853655SThomas Huth #ifndef _WIN32
382364853655SThomas Huth     migration_test_add("/migration/analyze-script", test_analyze_script);
382464853655SThomas Huth #endif
382564853655SThomas Huth 
3826b1fdd21eSSteve Sistare     if (is_x86) {
38276f0771deSFabiano Rosas         migration_test_add("/migration/precopy/unix/suspend/live",
3828b1fdd21eSSteve Sistare                            test_precopy_unix_suspend_live);
38296f0771deSFabiano Rosas         migration_test_add("/migration/precopy/unix/suspend/notlive",
3830b1fdd21eSSteve Sistare                            test_precopy_unix_suspend_notlive);
3831b1fdd21eSSteve Sistare     }
3832b1fdd21eSSteve Sistare 
38332649a725SPeter Xu     if (has_uffd) {
38346f0771deSFabiano Rosas         migration_test_add("/migration/postcopy/plain", test_postcopy);
38356f0771deSFabiano Rosas         migration_test_add("/migration/postcopy/recovery/plain",
3836767fa9cfSPeter Xu                            test_postcopy_recovery);
38376f0771deSFabiano Rosas         migration_test_add("/migration/postcopy/preempt/plain",
38386f0771deSFabiano Rosas                            test_postcopy_preempt);
38396f0771deSFabiano Rosas         migration_test_add("/migration/postcopy/preempt/recovery/plain",
38408f6fe915SPeter Xu                            test_postcopy_preempt_recovery);
38416cf56a87SPeter Xu         migration_test_add("/migration/postcopy/recovery/double-failures/handshake",
38426cf56a87SPeter Xu                            test_postcopy_recovery_fail_handshake);
38436cf56a87SPeter Xu         migration_test_add("/migration/postcopy/recovery/double-failures/reconnect",
38446cf56a87SPeter Xu                            test_postcopy_recovery_fail_reconnect);
38452b58a8b9SSteve Sistare         if (is_x86) {
38466f0771deSFabiano Rosas             migration_test_add("/migration/postcopy/suspend",
38472b58a8b9SSteve Sistare                                test_postcopy_suspend);
38482b58a8b9SSteve Sistare         }
38492649a725SPeter Xu     }
3850d1a27b16SPeter Xu 
38516f0771deSFabiano Rosas     migration_test_add("/migration/precopy/unix/plain",
38526f0771deSFabiano Rosas                        test_precopy_unix_plain);
38536abc8f12SFabiano Rosas     if (g_test_slow()) {
38546f0771deSFabiano Rosas         migration_test_add("/migration/precopy/unix/xbzrle",
38556f0771deSFabiano Rosas                            test_precopy_unix_xbzrle);
38566abc8f12SFabiano Rosas     }
38576f0771deSFabiano Rosas     migration_test_add("/migration/precopy/file",
38583dc35470SFabiano Rosas                        test_precopy_file);
38596f0771deSFabiano Rosas     migration_test_add("/migration/precopy/file/offset",
38603dc35470SFabiano Rosas                        test_precopy_file_offset);
3861926554c0SFabiano Rosas #ifndef _WIN32
3862926554c0SFabiano Rosas     migration_test_add("/migration/precopy/file/offset/fdset",
3863926554c0SFabiano Rosas                        test_precopy_file_offset_fdset);
3864926554c0SFabiano Rosas #endif
38656f0771deSFabiano Rosas     migration_test_add("/migration/precopy/file/offset/bad",
38663dc35470SFabiano Rosas                        test_precopy_file_offset_bad);
38673dc35470SFabiano Rosas 
3868e7b428d6SSteve Sistare     /*
3869e7b428d6SSteve Sistare      * Our CI system has problems with shared memory.
3870e7b428d6SSteve Sistare      * Don't run this test until we find a workaround.
3871e7b428d6SSteve Sistare      */
3872e7b428d6SSteve Sistare     if (getenv("QEMU_TEST_FLAKY_TESTS")) {
38736f0771deSFabiano Rosas         migration_test_add("/migration/mode/reboot", test_mode_reboot);
3874e7b428d6SSteve Sistare     }
3875e7b428d6SSteve Sistare 
3876c7076ec3SFabiano Rosas     migration_test_add("/migration/precopy/file/mapped-ram",
3877c7076ec3SFabiano Rosas                        test_precopy_file_mapped_ram);
3878c7076ec3SFabiano Rosas     migration_test_add("/migration/precopy/file/mapped-ram/live",
3879c7076ec3SFabiano Rosas                        test_precopy_file_mapped_ram_live);
3880c7076ec3SFabiano Rosas 
38817a09f092SFabiano Rosas     migration_test_add("/migration/multifd/file/mapped-ram",
38827a09f092SFabiano Rosas                        test_multifd_file_mapped_ram);
38837a09f092SFabiano Rosas     migration_test_add("/migration/multifd/file/mapped-ram/live",
38847a09f092SFabiano Rosas                        test_multifd_file_mapped_ram_live);
38857a09f092SFabiano Rosas 
3886408d295dSFabiano Rosas     migration_test_add("/migration/multifd/file/mapped-ram/dio",
3887408d295dSFabiano Rosas                        test_multifd_file_mapped_ram_dio);
3888408d295dSFabiano Rosas 
388931a5a303SFabiano Rosas #ifndef _WIN32
389031a5a303SFabiano Rosas     migration_test_add("/migration/multifd/file/mapped-ram/fdset",
389131a5a303SFabiano Rosas                        test_multifd_file_mapped_ram_fdset);
389231a5a303SFabiano Rosas     migration_test_add("/migration/multifd/file/mapped-ram/fdset/dio",
389331a5a303SFabiano Rosas                        test_multifd_file_mapped_ram_fdset_dio);
389431a5a303SFabiano Rosas #endif
389531a5a303SFabiano Rosas 
389658d25e97SDaniel P. Berrangé #ifdef CONFIG_GNUTLS
38976f0771deSFabiano Rosas     migration_test_add("/migration/precopy/unix/tls/psk",
389858d25e97SDaniel P. Berrangé                        test_precopy_unix_tls_psk);
38992649a725SPeter Xu 
39002649a725SPeter Xu     if (has_uffd) {
3901d1a27b16SPeter Xu         /*
3902d1a27b16SPeter Xu          * NOTE: psk test is enough for postcopy, as other types of TLS
3903d1a27b16SPeter Xu          * channels are tested under precopy.  Here what we want to test is the
3904d1a27b16SPeter Xu          * general postcopy path that has TLS channel enabled.
3905d1a27b16SPeter Xu          */
39066f0771deSFabiano Rosas         migration_test_add("/migration/postcopy/tls/psk",
39076f0771deSFabiano Rosas                            test_postcopy_tls_psk);
39086f0771deSFabiano Rosas         migration_test_add("/migration/postcopy/recovery/tls/psk",
3909767fa9cfSPeter Xu                            test_postcopy_recovery_tls_psk);
39106f0771deSFabiano Rosas         migration_test_add("/migration/postcopy/preempt/tls/psk",
39118f6fe915SPeter Xu                            test_postcopy_preempt_tls_psk);
39126f0771deSFabiano Rosas         migration_test_add("/migration/postcopy/preempt/recovery/tls/psk",
39138f6fe915SPeter Xu                            test_postcopy_preempt_all);
39142649a725SPeter Xu     }
3915d47b83b1SDaniel P. Berrangé #ifdef CONFIG_TASN1
39166f0771deSFabiano Rosas     migration_test_add("/migration/precopy/unix/tls/x509/default-host",
3917d47b83b1SDaniel P. Berrangé                        test_precopy_unix_tls_x509_default_host);
39186f0771deSFabiano Rosas     migration_test_add("/migration/precopy/unix/tls/x509/override-host",
3919d47b83b1SDaniel P. Berrangé                        test_precopy_unix_tls_x509_override_host);
3920d47b83b1SDaniel P. Berrangé #endif /* CONFIG_TASN1 */
392158d25e97SDaniel P. Berrangé #endif /* CONFIG_GNUTLS */
392258d25e97SDaniel P. Berrangé 
39236f0771deSFabiano Rosas     migration_test_add("/migration/precopy/tcp/plain", test_precopy_tcp_plain);
39247e6a5c73SAvihai Horon 
39256f0771deSFabiano Rosas     migration_test_add("/migration/precopy/tcp/plain/switchover-ack",
39267e6a5c73SAvihai Horon                        test_precopy_tcp_switchover_ack);
39277e6a5c73SAvihai Horon 
392858d25e97SDaniel P. Berrangé #ifdef CONFIG_GNUTLS
39296f0771deSFabiano Rosas     migration_test_add("/migration/precopy/tcp/tls/psk/match",
393058d25e97SDaniel P. Berrangé                        test_precopy_tcp_tls_psk_match);
39316f0771deSFabiano Rosas     migration_test_add("/migration/precopy/tcp/tls/psk/mismatch",
393258d25e97SDaniel P. Berrangé                        test_precopy_tcp_tls_psk_mismatch);
3933d47b83b1SDaniel P. Berrangé #ifdef CONFIG_TASN1
39346f0771deSFabiano Rosas     migration_test_add("/migration/precopy/tcp/tls/x509/default-host",
3935d47b83b1SDaniel P. Berrangé                        test_precopy_tcp_tls_x509_default_host);
39366f0771deSFabiano Rosas     migration_test_add("/migration/precopy/tcp/tls/x509/override-host",
3937d47b83b1SDaniel P. Berrangé                        test_precopy_tcp_tls_x509_override_host);
39386f0771deSFabiano Rosas     migration_test_add("/migration/precopy/tcp/tls/x509/mismatch-host",
3939d47b83b1SDaniel P. Berrangé                        test_precopy_tcp_tls_x509_mismatch_host);
39406f0771deSFabiano Rosas     migration_test_add("/migration/precopy/tcp/tls/x509/friendly-client",
3941d47b83b1SDaniel P. Berrangé                        test_precopy_tcp_tls_x509_friendly_client);
39426f0771deSFabiano Rosas     migration_test_add("/migration/precopy/tcp/tls/x509/hostile-client",
3943d47b83b1SDaniel P. Berrangé                        test_precopy_tcp_tls_x509_hostile_client);
39446f0771deSFabiano Rosas     migration_test_add("/migration/precopy/tcp/tls/x509/allow-anon-client",
3945d47b83b1SDaniel P. Berrangé                        test_precopy_tcp_tls_x509_allow_anon_client);
39466f0771deSFabiano Rosas     migration_test_add("/migration/precopy/tcp/tls/x509/reject-anon-client",
3947d47b83b1SDaniel P. Berrangé                        test_precopy_tcp_tls_x509_reject_anon_client);
3948d47b83b1SDaniel P. Berrangé #endif /* CONFIG_TASN1 */
394958d25e97SDaniel P. Berrangé #endif /* CONFIG_GNUTLS */
395058d25e97SDaniel P. Berrangé 
39516f0771deSFabiano Rosas     /* migration_test_add("/migration/ignore_shared", test_ignore_shared); */
3952d7613ee2SBin Meng #ifndef _WIN32
395385cf9abdSFabiano Rosas     migration_test_add("/migration/precopy/fd/tcp",
395485cf9abdSFabiano Rosas                        test_migrate_precopy_fd_socket);
39556d79bd68SFabiano Rosas     migration_test_add("/migration/precopy/fd/file",
39566d79bd68SFabiano Rosas                        test_migrate_precopy_fd_file);
3957d7613ee2SBin Meng #endif
39586f0771deSFabiano Rosas     migration_test_add("/migration/validate_uuid", test_validate_uuid);
39596f0771deSFabiano Rosas     migration_test_add("/migration/validate_uuid_error",
39606f0771deSFabiano Rosas                        test_validate_uuid_error);
39616f0771deSFabiano Rosas     migration_test_add("/migration/validate_uuid_src_not_set",
39621e8a1faeSThomas Huth                        test_validate_uuid_src_not_set);
39636f0771deSFabiano Rosas     migration_test_add("/migration/validate_uuid_dst_not_set",
39641e8a1faeSThomas Huth                        test_validate_uuid_dst_not_set);
3965bc6307a5SHet Gala     migration_test_add("/migration/validate_uri/channels/both_set",
3966bc6307a5SHet Gala                        test_validate_uri_channels_both_set);
3967bc6307a5SHet Gala     migration_test_add("/migration/validate_uri/channels/none_set",
3968bc6307a5SHet Gala                        test_validate_uri_channels_none_set);
396974902af7SJuan Quintela     /*
397074902af7SJuan Quintela      * See explanation why this test is slow on function definition
397174902af7SJuan Quintela      */
397274902af7SJuan Quintela     if (g_test_slow()) {
39736f0771deSFabiano Rosas         migration_test_add("/migration/auto_converge",
39746f0771deSFabiano Rosas                            test_migrate_auto_converge);
397517257b90SHyman Huang         if (g_str_equal(arch, "x86_64") &&
397617257b90SHyman Huang             has_kvm && kvm_dirty_ring_supported()) {
39776f0771deSFabiano Rosas             migration_test_add("/migration/dirty_limit",
39786f0771deSFabiano Rosas                                test_migrate_dirty_limit);
397917257b90SHyman Huang         }
398074902af7SJuan Quintela     }
39819d36d62cSHet Gala     migration_test_add("/migration/multifd/tcp/uri/plain/none",
39829d36d62cSHet Gala                        test_multifd_tcp_uri_none);
39839d36d62cSHet Gala     migration_test_add("/migration/multifd/tcp/channels/plain/none",
39849d36d62cSHet Gala                        test_multifd_tcp_channels_none);
39851815338dSHao Xiang     migration_test_add("/migration/multifd/tcp/plain/zero-page/legacy",
39861815338dSHao Xiang                        test_multifd_tcp_zero_page_legacy);
39871815338dSHao Xiang     migration_test_add("/migration/multifd/tcp/plain/zero-page/none",
39881815338dSHao Xiang                        test_multifd_tcp_no_zero_page);
39896f0771deSFabiano Rosas     migration_test_add("/migration/multifd/tcp/plain/cancel",
39904d6d2e87SDaniel P. Berrangé                        test_multifd_tcp_cancel);
39916f0771deSFabiano Rosas     migration_test_add("/migration/multifd/tcp/plain/zlib",
39924d6d2e87SDaniel P. Berrangé                        test_multifd_tcp_zlib);
399387dc6f5fSJuan Quintela #ifdef CONFIG_ZSTD
39946f0771deSFabiano Rosas     migration_test_add("/migration/multifd/tcp/plain/zstd",
39954d6d2e87SDaniel P. Berrangé                        test_multifd_tcp_zstd);
399687dc6f5fSJuan Quintela #endif
3997afe166d4SBryan Zhang #ifdef CONFIG_QATZIP
3998afe166d4SBryan Zhang     migration_test_add("/migration/multifd/tcp/plain/qatzip",
3999afe166d4SBryan Zhang                        test_multifd_tcp_qatzip);
4000afe166d4SBryan Zhang #endif
400108b82d20SYuan Liu #ifdef CONFIG_QPL
400208b82d20SYuan Liu     migration_test_add("/migration/multifd/tcp/plain/qpl",
400308b82d20SYuan Liu                        test_multifd_tcp_qpl);
400408b82d20SYuan Liu #endif
4005c519caa8SShameer Kolothum #ifdef CONFIG_UADK
4006c519caa8SShameer Kolothum     migration_test_add("/migration/multifd/tcp/plain/uadk",
4007c519caa8SShameer Kolothum                        test_multifd_tcp_uadk);
4008c519caa8SShameer Kolothum #endif
40094d6d2e87SDaniel P. Berrangé #ifdef CONFIG_GNUTLS
40106f0771deSFabiano Rosas     migration_test_add("/migration/multifd/tcp/tls/psk/match",
40114d6d2e87SDaniel P. Berrangé                        test_multifd_tcp_tls_psk_match);
40126f0771deSFabiano Rosas     migration_test_add("/migration/multifd/tcp/tls/psk/mismatch",
40134d6d2e87SDaniel P. Berrangé                        test_multifd_tcp_tls_psk_mismatch);
4014ff32f1ddSDaniel P. Berrangé #ifdef CONFIG_TASN1
40156f0771deSFabiano Rosas     migration_test_add("/migration/multifd/tcp/tls/x509/default-host",
4016ff32f1ddSDaniel P. Berrangé                        test_multifd_tcp_tls_x509_default_host);
40176f0771deSFabiano Rosas     migration_test_add("/migration/multifd/tcp/tls/x509/override-host",
4018ff32f1ddSDaniel P. Berrangé                        test_multifd_tcp_tls_x509_override_host);
40196f0771deSFabiano Rosas     migration_test_add("/migration/multifd/tcp/tls/x509/mismatch-host",
4020ff32f1ddSDaniel P. Berrangé                        test_multifd_tcp_tls_x509_mismatch_host);
40216f0771deSFabiano Rosas     migration_test_add("/migration/multifd/tcp/tls/x509/allow-anon-client",
4022ff32f1ddSDaniel P. Berrangé                        test_multifd_tcp_tls_x509_allow_anon_client);
40236f0771deSFabiano Rosas     migration_test_add("/migration/multifd/tcp/tls/x509/reject-anon-client",
4024ff32f1ddSDaniel P. Berrangé                        test_multifd_tcp_tls_x509_reject_anon_client);
4025ff32f1ddSDaniel P. Berrangé #endif /* CONFIG_TASN1 */
40264d6d2e87SDaniel P. Berrangé #endif /* CONFIG_GNUTLS */
40271e8a1faeSThomas Huth 
40281bca64a3SThomas Huth     if (g_str_equal(arch, "x86_64") && has_kvm && kvm_dirty_ring_supported()) {
40296f0771deSFabiano Rosas         migration_test_add("/migration/dirty_ring",
40301f546b70SPeter Xu                            test_precopy_unix_dirty_ring);
40316abc8f12SFabiano Rosas         if (qtest_has_machine("pc") && g_test_slow()) {
40326f0771deSFabiano Rosas             migration_test_add("/migration/vcpu_dirty_limit",
40338aff6f50SHyman Huang(黄勇)                                test_vcpu_dirty_limit);
40341f546b70SPeter Xu         }
4035d41c9896SThomas Huth     }
40361f546b70SPeter Xu 
40371e8a1faeSThomas Huth     ret = g_test_run();
40381e8a1faeSThomas Huth 
40391e8a1faeSThomas Huth     g_assert_cmpint(ret, ==, 0);
40401e8a1faeSThomas Huth 
40410c690d3eSJuan Quintela     bootfile_delete();
40421e8a1faeSThomas Huth     ret = rmdir(tmpfs);
40431e8a1faeSThomas Huth     if (ret != 0) {
40441e8a1faeSThomas Huth         g_test_message("unable to rmdir: path (%s): %s",
40451e8a1faeSThomas Huth                        tmpfs, strerror(errno));
40461e8a1faeSThomas Huth     }
4047e5553c1bSBin Meng     g_free(tmpfs);
40481e8a1faeSThomas Huth 
40491e8a1faeSThomas Huth     return ret;
40501e8a1faeSThomas Huth }
4051