| 1 | /* |
| 2 | * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates |
| 3 | * based on the vhost-user-test.c that is: |
| 4 | * Copyright (c) 2014 Virtual Open Systems Sarl. |
| 5 | * |
| 6 | * This work is licensed under the terms of the GNU GPL, version 2 or later. |
| 7 | * See the COPYING file in the top-level directory. |
| 8 | * |
| 9 | */ |
| 10 | |
| 11 | #ifndef TEST_FRAMEWORK_H |
| 12 | #define TEST_FRAMEWORK_H |
| 13 | |
| 14 | #include "libqtest.h" |
| 15 | #include <qapi/qapi-types-migration.h> |
| 16 | |
| 17 | #define FILE_TEST_FILENAME "migfile" |
| 18 | #define FILE_TEST_OFFSET 0x1000 |
| 19 | #define FILE_TEST_MARKER 'X' |
| 20 | |
| 21 | typedef enum { |
| 22 | /* |
| 23 | * Use memory-backend-ram, private mappings |
| 24 | */ |
| 25 | MEM_TYPE_ANON, |
| 26 | /* |
| 27 | * Use shmem file (under /dev/shm), shared mappings |
| 28 | */ |
| 29 | MEM_TYPE_SHMEM, |
| 30 | /* |
| 31 | * Use anonymous memfd, shared mappings. |
| 32 | * |
| 33 | * NOTE: this is internally almost the same as MEM_TYPE_SHMEM on Linux, |
| 34 | * but only anonymously allocated. |
| 35 | */ |
| 36 | MEM_TYPE_MEMFD, |
| 37 | MEM_TYPE_NUM, |
| 38 | } MemType; |
| 39 | |
| 40 | typedef struct MigrationTestEnv { |
| 41 | bool has_kvm; |
| 42 | bool has_hvf; |
| 43 | bool has_tcg; |
| 44 | bool has_uffd; |
| 45 | bool uffd_feature_thread_id; |
| 46 | bool has_dirty_ring; |
| 47 | bool is_x86; |
| 48 | bool full_set; |
| 49 | const char *arch; |
| 50 | const char *qemu_src; |
| 51 | const char *qemu_dst; |
| 52 | char *tmpfs; |
| 53 | } MigrationTestEnv; |
| 54 | |
| 55 | MigrationTestEnv *migration_get_env(void); |
| 56 | int migration_env_clean(MigrationTestEnv *env); |
| 57 | |
| 58 | /* |
| 59 | * A hook that runs after the src and dst QEMUs have been |
| 60 | * created, but before the migration is started. This can |
| 61 | * be used to set migration parameters and capabilities. |
| 62 | * |
| 63 | * Returns: NULL, or a pointer to opaque state to be |
| 64 | * later passed to the TestMigrateEndHook |
| 65 | */ |
| 66 | typedef void * (*TestMigrateStartHook)(QTestState *from, |
| 67 | QTestState *to); |
| 68 | |
| 69 | /* |
| 70 | * A hook that runs after the migration has finished, |
| 71 | * regardless of whether it succeeded or failed, but |
| 72 | * before QEMU has terminated (unless it self-terminated |
| 73 | * due to migration error) |
| 74 | * |
| 75 | * @opaque is a pointer to state previously returned |
| 76 | * by the TestMigrateStartHook if any, or NULL. |
| 77 | */ |
| 78 | typedef void (*TestMigrateEndHook)(QTestState *from, |
| 79 | QTestState *to, |
| 80 | void *opaque); |
| 81 | |
| 82 | /* |
| 83 | * Our goal is to ensure that we run a single full migration |
| 84 | * iteration, and also dirty memory, ensuring that at least |
| 85 | * one further iteration is required. |
| 86 | * |
| 87 | * We can't directly synchronize with the start of a migration |
| 88 | * so we have to apply some tricks monitoring memory that is |
| 89 | * transferred. |
| 90 | * |
| 91 | * Initially we set the migration bandwidth to an insanely |
| 92 | * low value, with tiny max downtime too. This basically |
| 93 | * guarantees migration will never complete. |
| 94 | * |
| 95 | * This will result in a test that is unacceptably slow though, |
| 96 | * so we can't let the entire migration pass run at this speed. |
| 97 | * Our intent is to let it run just long enough that we can |
| 98 | * prove data prior to the marker has been transferred *AND* |
| 99 | * also prove this transferred data is dirty again. |
| 100 | * |
| 101 | * Before migration starts, we write a 64-bit magic marker |
| 102 | * into a fixed location in the src VM RAM. |
| 103 | * |
| 104 | * Then watch dst memory until the marker appears. This is |
| 105 | * proof that start_address -> MAGIC_OFFSET_BASE has been |
| 106 | * transferred. |
| 107 | * |
| 108 | * Finally we go back to the source and read a byte just |
| 109 | * before the marker until we see it flip in value. This |
| 110 | * is proof that start_address -> MAGIC_OFFSET_BASE |
| 111 | * is now dirty again. |
| 112 | * |
| 113 | * IOW, we're guaranteed at least a 2nd migration pass |
| 114 | * at this point. |
| 115 | * |
| 116 | * We can now let migration run at full speed to finish |
| 117 | * the test |
| 118 | */ |
| 119 | typedef struct { |
| 120 | /* |
| 121 | * QTEST_LOG=test may override this in which case we dump errors |
| 122 | * unconditionally, because it means the user would like to be |
| 123 | * verbose. |
| 124 | */ |
| 125 | bool hide_stderr; |
| 126 | MemType mem_type; |
| 127 | /* only launch the source process */ |
| 128 | bool only_source; |
| 129 | /* only launch the target process */ |
| 130 | bool only_target; |
| 131 | /* Use dirty ring if true; dirty logging otherwise */ |
| 132 | bool use_dirty_ring; |
| 133 | const char *opts_source; |
| 134 | const char *opts_target; |
| 135 | /* suspend the src before migrating to dest. */ |
| 136 | bool suspend_me; |
| 137 | /* enable OOB QMP capability */ |
| 138 | bool oob; |
| 139 | |
| 140 | /* Do not connect to target monitor and qtest sockets in qtest_init */ |
| 141 | bool defer_target_connect; |
| 142 | |
| 143 | /* |
| 144 | * Migration capabilities to be set in both source and |
| 145 | * destination. For unilateral capabilities, use |
| 146 | * migration_set_capabilities(). |
| 147 | */ |
| 148 | bool caps[MIGRATION_CAPABILITY__MAX]; |
| 149 | } MigrateStart; |
| 150 | |
| 151 | typedef enum PostcopyRecoveryFailStage { |
| 152 | /* |
| 153 | * "no failure" must be 0 as it's the default. OTOH, real failure |
| 154 | * cases must be >0 to make sure they trigger by a "if" test. |
| 155 | */ |
| 156 | POSTCOPY_FAIL_NONE = 0, |
| 157 | POSTCOPY_FAIL_CHANNEL_ESTABLISH, |
| 158 | POSTCOPY_FAIL_RECOVERY, |
| 159 | POSTCOPY_FAIL_MAX |
| 160 | } PostcopyRecoveryFailStage; |
| 161 | |
| 162 | typedef struct { |
| 163 | /* Optional: fine tune start parameters */ |
| 164 | MigrateStart start; |
| 165 | |
| 166 | /* |
| 167 | * Optional: the migration URI. If NULL, the common code should |
| 168 | * provide a default. For socket migration, the source QEMU may |
| 169 | * query the dst QEMU for the listening address and use that as |
| 170 | * the connection address. This allows for dynamically picking a |
| 171 | * free TCP port. |
| 172 | */ |
| 173 | const char *uri; |
| 174 | |
| 175 | /* |
| 176 | * Optional: JSON-formatted list of src QEMU URIs. If a port is |
| 177 | * defined as '0' in any QDict key a value of '0' will be |
| 178 | * automatically converted to the correct destination port. |
| 179 | */ |
| 180 | const char *connect_channels; |
| 181 | |
| 182 | /* Optional: callback to run at start to set migration parameters */ |
| 183 | TestMigrateStartHook start_hook; |
| 184 | /* Optional: callback to run at finish to cleanup */ |
| 185 | TestMigrateEndHook end_hook; |
| 186 | |
| 187 | /* |
| 188 | * Optional: normally we expect the migration process to complete. |
| 189 | * |
| 190 | * There can be a variety of reasons and stages in which failure |
| 191 | * can happen during tests. |
| 192 | * |
| 193 | * If a failure is expected to happen at time of establishing |
| 194 | * the connection, then MIG_TEST_FAIL will indicate that the dst |
| 195 | * QEMU is expected to stay running and accept future migration |
| 196 | * connections. |
| 197 | * |
| 198 | * If a failure is expected to happen while processing the |
| 199 | * migration stream, then MIG_TEST_FAIL_DEST_QUIT_ERR will indicate |
| 200 | * that the dst QEMU is expected to quit with non-zero exit status |
| 201 | */ |
| 202 | enum { |
| 203 | /* This test should succeed, the default */ |
| 204 | MIG_TEST_SUCCEED = 0, |
| 205 | /* This test should fail, dest qemu should keep alive */ |
| 206 | MIG_TEST_FAIL, |
| 207 | /* The QMP command for this migration should fail with an error */ |
| 208 | MIG_TEST_QMP_ERROR, |
| 209 | } result; |
| 210 | |
| 211 | /* |
| 212 | * Optional: set number of migration passes to wait for, if live==true. |
| 213 | * If zero, then merely wait for a few MB of dirty data |
| 214 | */ |
| 215 | unsigned int iterations; |
| 216 | |
| 217 | /* |
| 218 | * Optional: whether the guest CPUs should be running during a precopy |
| 219 | * migration test. We used to always run with live but it took much |
| 220 | * longer so we reduced live tests to only the ones that have solid |
| 221 | * reason to be tested live-only. For each of the new test cases for |
| 222 | * precopy please provide justifications to use live explicitly (please |
| 223 | * refer to existing ones with live=true), or use live=off by default. |
| 224 | */ |
| 225 | bool live; |
| 226 | } MigrateCommon; |
| 227 | |
| 228 | void wait_for_serial(const char *side); |
| 229 | void migrate_prepare_for_dirty_mem(QTestState *from); |
| 230 | void migrate_wait_for_dirty_mem(QTestState *from, QTestState *to); |
| 231 | |
| 232 | int migrate_args(char **from, char **to, MigrateStart *args); |
| 233 | int migrate_start(QTestState **from, QTestState **to, MigrateStart *args); |
| 234 | void migrate_end(QTestState *from, QTestState *to, bool test_dest); |
| 235 | |
| 236 | void test_postcopy_common(MigrateCommon *args); |
| 237 | void test_postcopy_recovery_common(MigrateCommon *args, |
| 238 | PostcopyRecoveryFailStage fail_stage); |
| 239 | int test_precopy_common(MigrateCommon *args); |
| 240 | void test_precopy_unix_common(MigrateCommon *args); |
| 241 | void test_file_common(MigrateCommon *args, bool stop_src); |
| 242 | |
| 243 | typedef struct QTestMigrationState QTestMigrationState; |
| 244 | QTestMigrationState *get_src(void); |
| 245 | QTestMigrationState *get_dst(void); |
| 246 | |
| 247 | #ifdef CONFIG_GNUTLS |
| 248 | void migration_test_add_tls(MigrationTestEnv *env); |
| 249 | #else |
| 250 | static inline void migration_test_add_tls(MigrationTestEnv *env) {}; |
| 251 | #endif |
| 252 | void migration_test_add_compression(MigrationTestEnv *env); |
| 253 | void migration_test_add_postcopy(MigrationTestEnv *env); |
| 254 | void migration_test_add_file(MigrationTestEnv *env); |
| 255 | void migration_test_add_precopy(MigrationTestEnv *env); |
| 256 | void migration_test_add_cpr(MigrationTestEnv *env); |
| 257 | void migration_test_add_misc(MigrationTestEnv *env); |
| 258 | #ifdef CONFIG_REPLICATION |
| 259 | void migration_test_add_colo(MigrationTestEnv *env); |
| 260 | #else |
| 261 | static inline void migration_test_add_colo(MigrationTestEnv *env) {}; |
| 262 | #endif |
| 263 | |
| 264 | #endif /* TEST_FRAMEWORK_H */ |