]>
Commit | Line | Data |
---|---|---|
ea0c6d62 | 1 | /* |
2656bfd9 | 2 | * QTest testcase for migration |
ea0c6d62 | 3 | * |
17ca7746 | 4 | * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates |
ea0c6d62 DDAG |
5 | * based on the vhost-user-test.c that is: |
6 | * Copyright (c) 2014 Virtual Open Systems Sarl. | |
7 | * | |
8 | * This work is licensed under the terms of the GNU GPL, version 2 or later. | |
9 | * See the COPYING file in the top-level directory. | |
10 | * | |
11 | */ | |
12 | ||
13 | #include "qemu/osdep.h" | |
ea0c6d62 | 14 | |
907b5105 | 15 | #include "libqtest.h" |
d0112758 | 16 | #include "qapi/error.h" |
452fcdbc | 17 | #include "qapi/qmp/qdict.h" |
0b8fa32f | 18 | #include "qemu/module.h" |
ea0c6d62 DDAG |
19 | #include "qemu/option.h" |
20 | #include "qemu/range.h" | |
a9c94277 | 21 | #include "qemu/sockets.h" |
8228e353 | 22 | #include "chardev/char.h" |
609d3844 JQ |
23 | #include "qapi/qapi-visit-sockets.h" |
24 | #include "qapi/qobject-input-visitor.h" | |
25 | #include "qapi/qobject-output-visitor.h" | |
58d25e97 | 26 | #include "crypto/tlscredspsk.h" |
8aff6f50 | 27 | #include "qapi/qmp/qlist.h" |
ea0c6d62 | 28 | |
d77799cc | 29 | #include "migration-helpers.h" |
a2ce7dbd | 30 | #include "tests/migration/migration-test.h" |
58d25e97 DB |
31 | #ifdef CONFIG_GNUTLS |
32 | # include "tests/unit/crypto-tls-psk-helpers.h" | |
d47b83b1 DB |
33 | # ifdef CONFIG_TASN1 |
34 | # include "tests/unit/crypto-tls-x509-helpers.h" | |
35 | # endif /* CONFIG_TASN1 */ | |
58d25e97 | 36 | #endif /* CONFIG_GNUTLS */ |
e51e711b | 37 | |
61c32485 PX |
38 | /* For dirty ring test; so far only x86_64 is supported */ |
39 | #if defined(__linux__) && defined(HOST_X86_64) | |
1f546b70 PX |
40 | #include "linux/kvm.h" |
41 | #endif | |
42 | ||
e51e711b WH |
43 | unsigned start_address; |
44 | unsigned end_address; | |
346f3dab | 45 | static bool uffd_feature_thread_id; |
95014994 DB |
46 | static bool got_src_stop; |
47 | static bool got_dst_resume; | |
ea0c6d62 | 48 | |
e02f56e3 DB |
49 | /* |
50 | * An initial 3 MB offset is used as that corresponds | |
51 | * to ~1 sec of data transfer with our bandwidth setting. | |
52 | */ | |
53 | #define MAGIC_OFFSET_BASE (3 * 1024 * 1024) | |
54 | /* | |
55 | * A further 1k is added to ensure we're not a multiple | |
56 | * of TEST_MEM_PAGE_SIZE, thus avoid clash with writes | |
57 | * from the migration guest workload. | |
58 | */ | |
59 | #define MAGIC_OFFSET_SHUFFLE 1024 | |
60 | #define MAGIC_OFFSET (MAGIC_OFFSET_BASE + MAGIC_OFFSET_SHUFFLE) | |
61 | #define MAGIC_MARKER 0xFEED12345678CAFEULL | |
62 | ||
8aff6f50 HH |
63 | /* |
64 | * Dirtylimit stop working if dirty page rate error | |
65 | * value less than DIRTYLIMIT_TOLERANCE_RANGE | |
66 | */ | |
67 | #define DIRTYLIMIT_TOLERANCE_RANGE 25 /* MB/s */ | |
68 | ||
d864756e FR |
69 | #define ANALYZE_SCRIPT "scripts/analyze-migration.py" |
70 | ||
3dc35470 FR |
71 | #define QEMU_VM_FILE_MAGIC 0x5145564d |
72 | #define FILE_TEST_FILENAME "migfile" | |
73 | #define FILE_TEST_OFFSET 0x1000 | |
5050ad2a FR |
74 | #define QEMU_ENV_SRC "QTEST_QEMU_BINARY_SRC" |
75 | #define QEMU_ENV_DST "QTEST_QEMU_BINARY_DST" | |
3dc35470 | 76 | |
ea0c6d62 | 77 | #if defined(__linux__) |
ea0c6d62 DDAG |
78 | #include <sys/syscall.h> |
79 | #include <sys/vfs.h> | |
80 | #endif | |
81 | ||
82 | #if defined(__linux__) && defined(__NR_userfaultfd) && defined(CONFIG_EVENTFD) | |
83 | #include <sys/eventfd.h> | |
84 | #include <sys/ioctl.h> | |
d5890ea0 | 85 | #include "qemu/userfaultfd.h" |
ea0c6d62 DDAG |
86 | |
87 | static bool ufd_version_check(void) | |
88 | { | |
89 | struct uffdio_api api_struct; | |
90 | uint64_t ioctl_mask; | |
91 | ||
d5890ea0 | 92 | int ufd = uffd_open(O_CLOEXEC); |
ea0c6d62 DDAG |
93 | |
94 | if (ufd == -1) { | |
95 | g_test_message("Skipping test: userfaultfd not available"); | |
96 | return false; | |
97 | } | |
98 | ||
99 | api_struct.api = UFFD_API; | |
100 | api_struct.features = 0; | |
101 | if (ioctl(ufd, UFFDIO_API, &api_struct)) { | |
102 | g_test_message("Skipping test: UFFDIO_API failed"); | |
103 | return false; | |
104 | } | |
346f3dab | 105 | uffd_feature_thread_id = api_struct.features & UFFD_FEATURE_THREAD_ID; |
ea0c6d62 DDAG |
106 | |
107 | ioctl_mask = (__u64)1 << _UFFDIO_REGISTER | | |
108 | (__u64)1 << _UFFDIO_UNREGISTER; | |
109 | if ((api_struct.ioctls & ioctl_mask) != ioctl_mask) { | |
110 | g_test_message("Skipping test: Missing userfault feature"); | |
111 | return false; | |
112 | } | |
113 | ||
114 | return true; | |
115 | } | |
116 | ||
117 | #else | |
118 | static bool ufd_version_check(void) | |
119 | { | |
120 | g_test_message("Skipping test: Userfault not available (builtdtime)"); | |
121 | return false; | |
122 | } | |
123 | ||
124 | #endif | |
125 | ||
e5553c1b | 126 | static char *tmpfs; |
877cec63 | 127 | static char *bootpath; |
ea0c6d62 | 128 | |
e51e711b WH |
129 | /* The boot file modifies memory area in [start_address, end_address) |
130 | * repeatedly. It outputs a 'B' at a fixed rate while it's still running. | |
ea0c6d62 | 131 | */ |
d54927ef | 132 | #include "tests/migration/i386/a-b-bootblock.h" |
c02b3781 | 133 | #include "tests/migration/aarch64/a-b-kernel.h" |
5571dc82 TH |
134 | #include "tests/migration/s390x/a-b-bios.h" |
135 | ||
0c690d3e | 136 | static void bootfile_create(char *dir) |
5571dc82 | 137 | { |
0c690d3e JQ |
138 | const char *arch = qtest_get_arch(); |
139 | unsigned char *content; | |
140 | size_t len; | |
141 | ||
142 | bootpath = g_strdup_printf("%s/bootsect", dir); | |
143 | if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { | |
144 | /* the assembled x86 boot sector should be exactly one sector large */ | |
145 | g_assert(sizeof(x86_bootsect) == 512); | |
146 | content = x86_bootsect; | |
147 | len = sizeof(x86_bootsect); | |
148 | } else if (g_str_equal(arch, "s390x")) { | |
149 | content = s390x_elf; | |
150 | len = sizeof(s390x_elf); | |
151 | } else if (strcmp(arch, "ppc64") == 0) { | |
152 | /* | |
153 | * sane architectures can be programmed at the boot prompt | |
154 | */ | |
155 | return; | |
156 | } else if (strcmp(arch, "aarch64") == 0) { | |
157 | content = aarch64_kernel; | |
158 | len = sizeof(aarch64_kernel); | |
159 | g_assert(sizeof(aarch64_kernel) <= ARM_TEST_MAX_KERNEL_SIZE); | |
160 | } else { | |
161 | g_assert_not_reached(); | |
162 | } | |
163 | ||
5571dc82 | 164 | FILE *bootfile = fopen(bootpath, "wb"); |
5571dc82 | 165 | |
2785f196 | 166 | g_assert_cmpint(fwrite(content, len, 1, bootfile), ==, 1); |
5571dc82 TH |
167 | fclose(bootfile); |
168 | } | |
169 | ||
0c690d3e JQ |
170 | static void bootfile_delete(void) |
171 | { | |
172 | unlink(bootpath); | |
173 | g_free(bootpath); | |
174 | bootpath = NULL; | |
175 | } | |
176 | ||
ea0c6d62 DDAG |
177 | /* |
178 | * Wait for some output in the serial output file, | |
179 | * we get an 'A' followed by an endless string of 'B's | |
180 | * but on the destination we won't have the A. | |
181 | */ | |
182 | static void wait_for_serial(const char *side) | |
183 | { | |
ff7b9b56 | 184 | g_autofree char *serialpath = g_strdup_printf("%s/%s", tmpfs, side); |
ea0c6d62 | 185 | FILE *serialfile = fopen(serialpath, "r"); |
aaf89c8a | 186 | const char *arch = qtest_get_arch(); |
187 | int started = (strcmp(side, "src_serial") == 0 && | |
188 | strcmp(arch, "ppc64") == 0) ? 0 : 1; | |
ea0c6d62 DDAG |
189 | |
190 | do { | |
191 | int readvalue = fgetc(serialfile); | |
192 | ||
aaf89c8a | 193 | if (!started) { |
194 | /* SLOF prints its banner before starting test, | |
195 | * to ignore it, mark the start of the test with '_', | |
196 | * ignore all characters until this marker | |
197 | */ | |
198 | switch (readvalue) { | |
199 | case '_': | |
200 | started = 1; | |
201 | break; | |
202 | case EOF: | |
203 | fseek(serialfile, 0, SEEK_SET); | |
204 | usleep(1000); | |
205 | break; | |
206 | } | |
207 | continue; | |
208 | } | |
ea0c6d62 DDAG |
209 | switch (readvalue) { |
210 | case 'A': | |
211 | /* Fine */ | |
212 | break; | |
213 | ||
214 | case 'B': | |
215 | /* It's alive! */ | |
216 | fclose(serialfile); | |
ea0c6d62 DDAG |
217 | return; |
218 | ||
219 | case EOF: | |
aaf89c8a | 220 | started = (strcmp(side, "src_serial") == 0 && |
221 | strcmp(arch, "ppc64") == 0) ? 0 : 1; | |
ea0c6d62 DDAG |
222 | fseek(serialfile, 0, SEEK_SET); |
223 | usleep(1000); | |
224 | break; | |
225 | ||
226 | default: | |
227 | fprintf(stderr, "Unexpected %d on %s serial\n", readvalue, side); | |
228 | g_assert_not_reached(); | |
229 | } | |
230 | } while (true); | |
231 | } | |
232 | ||
ea0c6d62 DDAG |
233 | /* |
234 | * It's tricky to use qemu's migration event capability with qtest, | |
235 | * events suddenly appearing confuse the qmp()/hmp() responses. | |
ea0c6d62 DDAG |
236 | */ |
237 | ||
660a9b68 | 238 | static int64_t read_ram_property_int(QTestState *who, const char *property) |
ea0c6d62 | 239 | { |
2f7074c6 | 240 | QDict *rsp_return, *rsp_ram; |
660a9b68 | 241 | int64_t result; |
ea0c6d62 | 242 | |
fd3540ad | 243 | rsp_return = migrate_query_not_failed(who); |
ea0c6d62 DDAG |
244 | if (!qdict_haskey(rsp_return, "ram")) { |
245 | /* Still in setup */ | |
246 | result = 0; | |
247 | } else { | |
248 | rsp_ram = qdict_get_qdict(rsp_return, "ram"); | |
660a9b68 | 249 | result = qdict_get_try_int(rsp_ram, property, 0); |
ea0c6d62 | 250 | } |
2f7074c6 | 251 | qobject_unref(rsp_return); |
ea0c6d62 DDAG |
252 | return result; |
253 | } | |
254 | ||
8c51642b YK |
255 | static int64_t read_migrate_property_int(QTestState *who, const char *property) |
256 | { | |
257 | QDict *rsp_return; | |
258 | int64_t result; | |
259 | ||
fd3540ad | 260 | rsp_return = migrate_query_not_failed(who); |
8c51642b YK |
261 | result = qdict_get_try_int(rsp_return, property, 0); |
262 | qobject_unref(rsp_return); | |
263 | return result; | |
264 | } | |
265 | ||
660a9b68 YK |
266 | static uint64_t get_migration_pass(QTestState *who) |
267 | { | |
268 | return read_ram_property_int(who, "dirty-sync-count"); | |
269 | } | |
270 | ||
346f3dab AP |
271 | static void read_blocktime(QTestState *who) |
272 | { | |
2f7074c6 | 273 | QDict *rsp_return; |
346f3dab | 274 | |
fd3540ad | 275 | rsp_return = migrate_query_not_failed(who); |
346f3dab | 276 | g_assert(qdict_haskey(rsp_return, "postcopy-blocktime")); |
2f7074c6 | 277 | qobject_unref(rsp_return); |
346f3dab AP |
278 | } |
279 | ||
863e27a8 | 280 | static void wait_for_migration_pass(QTestState *who) |
ea0c6d62 | 281 | { |
863e27a8 | 282 | uint64_t initial_pass = get_migration_pass(who); |
ea0c6d62 DDAG |
283 | uint64_t pass; |
284 | ||
285 | /* Wait for the 1st sync */ | |
95014994 | 286 | while (!got_src_stop && !initial_pass) { |
6a7724e9 | 287 | usleep(1000); |
863e27a8 | 288 | initial_pass = get_migration_pass(who); |
6a7724e9 | 289 | } |
ea0c6d62 DDAG |
290 | |
291 | do { | |
6a7724e9 | 292 | usleep(1000); |
863e27a8 | 293 | pass = get_migration_pass(who); |
95014994 | 294 | } while (pass == initial_pass && !got_src_stop); |
ea0c6d62 DDAG |
295 | } |
296 | ||
7195a871 | 297 | static void check_guests_ram(QTestState *who) |
ea0c6d62 DDAG |
298 | { |
299 | /* Our ASM test will have been incrementing one byte from each page from | |
e51e711b WH |
300 | * start_address to < end_address in order. This gives us a constraint |
301 | * that any page's byte should be equal or less than the previous pages | |
302 | * byte (mod 256); and they should all be equal except for one transition | |
303 | * at the point where we meet the incrementer. (We're running this with | |
304 | * the guest stopped). | |
ea0c6d62 DDAG |
305 | */ |
306 | unsigned address; | |
307 | uint8_t first_byte; | |
308 | uint8_t last_byte; | |
309 | bool hit_edge = false; | |
601b5575 | 310 | int bad = 0; |
ea0c6d62 | 311 | |
7195a871 | 312 | qtest_memread(who, start_address, &first_byte, 1); |
ea0c6d62 DDAG |
313 | last_byte = first_byte; |
314 | ||
e51e711b WH |
315 | for (address = start_address + TEST_MEM_PAGE_SIZE; address < end_address; |
316 | address += TEST_MEM_PAGE_SIZE) | |
ea0c6d62 DDAG |
317 | { |
318 | uint8_t b; | |
7195a871 | 319 | qtest_memread(who, address, &b, 1); |
ea0c6d62 DDAG |
320 | if (b != last_byte) { |
321 | if (((b + 1) % 256) == last_byte && !hit_edge) { | |
322 | /* This is OK, the guest stopped at the point of | |
323 | * incrementing the previous page but didn't get | |
324 | * to us yet. | |
325 | */ | |
326 | hit_edge = true; | |
829db8b4 | 327 | last_byte = b; |
ea0c6d62 | 328 | } else { |
601b5575 AB |
329 | bad++; |
330 | if (bad <= 10) { | |
331 | fprintf(stderr, "Memory content inconsistency at %x" | |
332 | " first_byte = %x last_byte = %x current = %x" | |
333 | " hit_edge = %x\n", | |
334 | address, first_byte, last_byte, b, hit_edge); | |
335 | } | |
ea0c6d62 DDAG |
336 | } |
337 | } | |
ea0c6d62 | 338 | } |
601b5575 AB |
339 | if (bad >= 10) { |
340 | fprintf(stderr, "and in another %d pages", bad - 10); | |
341 | } | |
342 | g_assert(bad == 0); | |
ea0c6d62 DDAG |
343 | } |
344 | ||
345 | static void cleanup(const char *filename) | |
346 | { | |
ff7b9b56 | 347 | g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, filename); |
ea0c6d62 DDAG |
348 | |
349 | unlink(path); | |
350 | } | |
351 | ||
609d3844 JQ |
352 | static char *SocketAddress_to_str(SocketAddress *addr) |
353 | { | |
354 | switch (addr->type) { | |
355 | case SOCKET_ADDRESS_TYPE_INET: | |
356 | return g_strdup_printf("tcp:%s:%s", | |
357 | addr->u.inet.host, | |
358 | addr->u.inet.port); | |
359 | case SOCKET_ADDRESS_TYPE_UNIX: | |
360 | return g_strdup_printf("unix:%s", | |
361 | addr->u.q_unix.path); | |
362 | case SOCKET_ADDRESS_TYPE_FD: | |
363 | return g_strdup_printf("fd:%s", addr->u.fd.str); | |
364 | case SOCKET_ADDRESS_TYPE_VSOCK: | |
365 | return g_strdup_printf("tcp:%s:%s", | |
366 | addr->u.vsock.cid, | |
367 | addr->u.vsock.port); | |
368 | default: | |
369 | return g_strdup("unknown address type"); | |
370 | } | |
371 | } | |
372 | ||
373 | static char *migrate_get_socket_address(QTestState *who, const char *parameter) | |
374 | { | |
375 | QDict *rsp; | |
376 | char *result; | |
609d3844 JQ |
377 | SocketAddressList *addrs; |
378 | Visitor *iv = NULL; | |
379 | QObject *object; | |
380 | ||
381 | rsp = migrate_query(who); | |
382 | object = qdict_get(rsp, parameter); | |
383 | ||
384 | iv = qobject_input_visitor_new(object); | |
d0112758 | 385 | visit_type_SocketAddressList(iv, NULL, &addrs, &error_abort); |
1e25879e | 386 | visit_free(iv); |
609d3844 JQ |
387 | |
388 | /* we are only using a single address */ | |
1e25879e | 389 | result = SocketAddress_to_str(addrs->value); |
609d3844 JQ |
390 | |
391 | qapi_free_SocketAddressList(addrs); | |
392 | qobject_unref(rsp); | |
393 | return result; | |
394 | } | |
395 | ||
8f7798f1 JQ |
396 | static long long migrate_get_parameter_int(QTestState *who, |
397 | const char *parameter) | |
609d3844 JQ |
398 | { |
399 | QDict *rsp; | |
400 | long long result; | |
401 | ||
aca04069 DB |
402 | rsp = qtest_qmp_assert_success_ref( |
403 | who, "{ 'execute': 'query-migrate-parameters' }"); | |
609d3844 JQ |
404 | result = qdict_get_int(rsp, parameter); |
405 | qobject_unref(rsp); | |
406 | return result; | |
407 | } | |
408 | ||
8f7798f1 JQ |
409 | static void migrate_check_parameter_int(QTestState *who, const char *parameter, |
410 | long long value) | |
56b4a42a | 411 | { |
609d3844 | 412 | long long result; |
56b4a42a | 413 | |
8f7798f1 | 414 | result = migrate_get_parameter_int(who, parameter); |
609d3844 | 415 | g_assert_cmpint(result, ==, value); |
56b4a42a JQ |
416 | } |
417 | ||
8f7798f1 JQ |
418 | static void migrate_set_parameter_int(QTestState *who, const char *parameter, |
419 | long long value) | |
d62fbe60 | 420 | { |
11936f0e DB |
421 | qtest_qmp_assert_success(who, |
422 | "{ 'execute': 'migrate-set-parameters'," | |
423 | "'arguments': { %s: %lld } }", | |
424 | parameter, value); | |
8f7798f1 | 425 | migrate_check_parameter_int(who, parameter, value); |
d62fbe60 JQ |
426 | } |
427 | ||
6a22c544 JQ |
428 | static char *migrate_get_parameter_str(QTestState *who, |
429 | const char *parameter) | |
430 | { | |
431 | QDict *rsp; | |
432 | char *result; | |
433 | ||
aca04069 DB |
434 | rsp = qtest_qmp_assert_success_ref( |
435 | who, "{ 'execute': 'query-migrate-parameters' }"); | |
6a22c544 JQ |
436 | result = g_strdup(qdict_get_str(rsp, parameter)); |
437 | qobject_unref(rsp); | |
438 | return result; | |
439 | } | |
440 | ||
441 | static void migrate_check_parameter_str(QTestState *who, const char *parameter, | |
442 | const char *value) | |
443 | { | |
ff7b9b56 | 444 | g_autofree char *result = migrate_get_parameter_str(who, parameter); |
6a22c544 | 445 | g_assert_cmpstr(result, ==, value); |
6a22c544 JQ |
446 | } |
447 | ||
6a22c544 JQ |
448 | static void migrate_set_parameter_str(QTestState *who, const char *parameter, |
449 | const char *value) | |
450 | { | |
11936f0e DB |
451 | qtest_qmp_assert_success(who, |
452 | "{ 'execute': 'migrate-set-parameters'," | |
453 | "'arguments': { %s: %s } }", | |
454 | parameter, value); | |
6a22c544 JQ |
455 | migrate_check_parameter_str(who, parameter, value); |
456 | } | |
457 | ||
1536d1da LS |
458 | static long long migrate_get_parameter_bool(QTestState *who, |
459 | const char *parameter) | |
460 | { | |
461 | QDict *rsp; | |
462 | int result; | |
463 | ||
aca04069 DB |
464 | rsp = qtest_qmp_assert_success_ref( |
465 | who, "{ 'execute': 'query-migrate-parameters' }"); | |
1536d1da LS |
466 | result = qdict_get_bool(rsp, parameter); |
467 | qobject_unref(rsp); | |
468 | return !!result; | |
469 | } | |
470 | ||
471 | static void migrate_check_parameter_bool(QTestState *who, const char *parameter, | |
472 | int value) | |
473 | { | |
474 | int result; | |
475 | ||
476 | result = migrate_get_parameter_bool(who, parameter); | |
477 | g_assert_cmpint(result, ==, value); | |
478 | } | |
479 | ||
480 | static void migrate_set_parameter_bool(QTestState *who, const char *parameter, | |
481 | int value) | |
482 | { | |
11936f0e DB |
483 | qtest_qmp_assert_success(who, |
484 | "{ 'execute': 'migrate-set-parameters'," | |
485 | "'arguments': { %s: %i } }", | |
486 | parameter, value); | |
1536d1da LS |
487 | migrate_check_parameter_bool(who, parameter, value); |
488 | } | |
489 | ||
886dfe9d DB |
490 | static void migrate_ensure_non_converge(QTestState *who) |
491 | { | |
1bfc8dde DDAG |
492 | /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */ |
493 | migrate_set_parameter_int(who, "max-bandwidth", 3 * 1000 * 1000); | |
886dfe9d DB |
494 | migrate_set_parameter_int(who, "downtime-limit", 1); |
495 | } | |
496 | ||
497 | static void migrate_ensure_converge(QTestState *who) | |
498 | { | |
499 | /* Should converge with 30s downtime + 1 gbs bandwidth limit */ | |
500 | migrate_set_parameter_int(who, "max-bandwidth", 1 * 1000 * 1000 * 1000); | |
501 | migrate_set_parameter_int(who, "downtime-limit", 30 * 1000); | |
502 | } | |
503 | ||
e02f56e3 DB |
504 | /* |
505 | * Our goal is to ensure that we run a single full migration | |
506 | * iteration, and also dirty memory, ensuring that at least | |
507 | * one further iteration is required. | |
508 | * | |
509 | * We can't directly synchronize with the start of a migration | |
510 | * so we have to apply some tricks monitoring memory that is | |
511 | * transferred. | |
512 | * | |
513 | * Initially we set the migration bandwidth to an insanely | |
514 | * low value, with tiny max downtime too. This basically | |
515 | * guarantees migration will never complete. | |
516 | * | |
517 | * This will result in a test that is unacceptably slow though, | |
518 | * so we can't let the entire migration pass run at this speed. | |
519 | * Our intent is to let it run just long enough that we can | |
520 | * prove data prior to the marker has been transferred *AND* | |
521 | * also prove this transferred data is dirty again. | |
522 | * | |
523 | * Before migration starts, we write a 64-bit magic marker | |
524 | * into a fixed location in the src VM RAM. | |
525 | * | |
526 | * Then watch dst memory until the marker appears. This is | |
527 | * proof that start_address -> MAGIC_OFFSET_BASE has been | |
528 | * transferred. | |
529 | * | |
530 | * Finally we go back to the source and read a byte just | |
96420a30 | 531 | * before the marker until we see it flip in value. This |
e02f56e3 DB |
532 | * is proof that start_address -> MAGIC_OFFSET_BASE |
533 | * is now dirty again. | |
534 | * | |
535 | * IOW, we're guaranteed at least a 2nd migration pass | |
536 | * at this point. | |
537 | * | |
538 | * We can now let migration run at full speed to finish | |
539 | * the test | |
540 | */ | |
541 | static void migrate_prepare_for_dirty_mem(QTestState *from) | |
542 | { | |
543 | /* | |
544 | * The guest workflow iterates from start_address to | |
545 | * end_address, writing 1 byte every TEST_MEM_PAGE_SIZE | |
546 | * bytes. | |
547 | * | |
548 | * IOW, if we write to mem at a point which is NOT | |
549 | * a multiple of TEST_MEM_PAGE_SIZE, our write won't | |
550 | * conflict with the migration workflow. | |
551 | * | |
552 | * We put in a marker here, that we'll use to determine | |
553 | * when the data has been transferred to the dst. | |
554 | */ | |
555 | qtest_writeq(from, start_address + MAGIC_OFFSET, MAGIC_MARKER); | |
556 | } | |
557 | ||
558 | static void migrate_wait_for_dirty_mem(QTestState *from, | |
559 | QTestState *to) | |
560 | { | |
561 | uint64_t watch_address = start_address + MAGIC_OFFSET_BASE; | |
562 | uint64_t marker_address = start_address + MAGIC_OFFSET; | |
563 | uint8_t watch_byte; | |
564 | ||
565 | /* | |
566 | * Wait for the MAGIC_MARKER to get transferred, as an | |
567 | * indicator that a migration pass has made some known | |
568 | * amount of progress. | |
569 | */ | |
570 | do { | |
571 | usleep(1000 * 10); | |
572 | } while (qtest_readq(to, marker_address) != MAGIC_MARKER); | |
573 | ||
574 | /* | |
575 | * Now ensure that already transferred bytes are | |
576 | * dirty again from the guest workload. Note the | |
577 | * guest byte value will wrap around and by chance | |
578 | * match the original watch_byte. This is harmless | |
579 | * as we'll eventually see a different value if we | |
580 | * keep watching | |
581 | */ | |
582 | watch_byte = qtest_readb(from, watch_address); | |
583 | do { | |
584 | usleep(1000 * 10); | |
585 | } while (qtest_readb(from, watch_address) == watch_byte); | |
586 | } | |
587 | ||
588 | ||
d5f49640 PX |
589 | static void migrate_pause(QTestState *who) |
590 | { | |
aca04069 | 591 | qtest_qmp_assert_success(who, "{ 'execute': 'migrate-pause' }"); |
d5f49640 PX |
592 | } |
593 | ||
8c51642b YK |
594 | static void migrate_continue(QTestState *who, const char *state) |
595 | { | |
aca04069 DB |
596 | qtest_qmp_assert_success(who, |
597 | "{ 'execute': 'migrate-continue'," | |
598 | " 'arguments': { 'state': %s } }", | |
599 | state); | |
8c51642b YK |
600 | } |
601 | ||
d5f49640 PX |
602 | static void migrate_recover(QTestState *who, const char *uri) |
603 | { | |
aca04069 DB |
604 | qtest_qmp_assert_success(who, |
605 | "{ 'execute': 'migrate-recover', " | |
606 | " 'id': 'recover-cmd', " | |
607 | " 'arguments': { 'uri': %s } }", | |
608 | uri); | |
d5f49640 PX |
609 | } |
610 | ||
d795f474 JQ |
611 | static void migrate_cancel(QTestState *who) |
612 | { | |
aca04069 | 613 | qtest_qmp_assert_success(who, "{ 'execute': 'migrate_cancel' }"); |
d795f474 JQ |
614 | } |
615 | ||
d131662a | 616 | static void migrate_postcopy_start(QTestState *from, QTestState *to) |
eb665d7d | 617 | { |
aca04069 | 618 | qtest_qmp_assert_success(from, "{ 'execute': 'migrate-start-postcopy' }"); |
d131662a | 619 | |
95014994 | 620 | if (!got_src_stop) { |
d131662a PX |
621 | qtest_qmp_eventwait(from, "STOP"); |
622 | } | |
623 | ||
624 | qtest_qmp_eventwait(to, "RESUME"); | |
eb665d7d JQ |
625 | } |
626 | ||
5d3b575d | 627 | typedef struct { |
a4729501 PX |
628 | /* |
629 | * QTEST_LOG=1 may override this. When QTEST_LOG=1, we always dump errors | |
630 | * unconditionally, because it means the user would like to be verbose. | |
631 | */ | |
5d3b575d JQ |
632 | bool hide_stderr; |
633 | bool use_shmem; | |
d795f474 JQ |
634 | /* only launch the target process */ |
635 | bool only_target; | |
1f546b70 PX |
636 | /* Use dirty ring if true; dirty logging otherwise */ |
637 | bool use_dirty_ring; | |
19da6edf DB |
638 | const char *opts_source; |
639 | const char *opts_target; | |
5d3b575d JQ |
640 | } MigrateStart; |
641 | ||
312e9dd0 PX |
642 | /* |
643 | * A hook that runs after the src and dst QEMUs have been | |
644 | * created, but before the migration is started. This can | |
645 | * be used to set migration parameters and capabilities. | |
646 | * | |
647 | * Returns: NULL, or a pointer to opaque state to be | |
648 | * later passed to the TestMigrateFinishHook | |
649 | */ | |
650 | typedef void * (*TestMigrateStartHook)(QTestState *from, | |
651 | QTestState *to); | |
652 | ||
653 | /* | |
654 | * A hook that runs after the migration has finished, | |
655 | * regardless of whether it succeeded or failed, but | |
656 | * before QEMU has terminated (unless it self-terminated | |
657 | * due to migration error) | |
658 | * | |
659 | * @opaque is a pointer to state previously returned | |
660 | * by the TestMigrateStartHook if any, or NULL. | |
661 | */ | |
662 | typedef void (*TestMigrateFinishHook)(QTestState *from, | |
663 | QTestState *to, | |
664 | void *opaque); | |
665 | ||
666 | typedef struct { | |
667 | /* Optional: fine tune start parameters */ | |
668 | MigrateStart start; | |
669 | ||
670 | /* Required: the URI for the dst QEMU to listen on */ | |
671 | const char *listen_uri; | |
672 | ||
673 | /* | |
674 | * Optional: the URI for the src QEMU to connect to | |
675 | * If NULL, then it will query the dst QEMU for its actual | |
676 | * listening address and use that as the connect address. | |
677 | * This allows for dynamically picking a free TCP port. | |
678 | */ | |
679 | const char *connect_uri; | |
680 | ||
681 | /* Optional: callback to run at start to set migration parameters */ | |
682 | TestMigrateStartHook start_hook; | |
683 | /* Optional: callback to run at finish to cleanup */ | |
684 | TestMigrateFinishHook finish_hook; | |
685 | ||
686 | /* | |
687 | * Optional: normally we expect the migration process to complete. | |
688 | * | |
689 | * There can be a variety of reasons and stages in which failure | |
690 | * can happen during tests. | |
691 | * | |
692 | * If a failure is expected to happen at time of establishing | |
693 | * the connection, then MIG_TEST_FAIL will indicate that the dst | |
694 | * QEMU is expected to stay running and accept future migration | |
695 | * connections. | |
696 | * | |
697 | * If a failure is expected to happen while processing the | |
698 | * migration stream, then MIG_TEST_FAIL_DEST_QUIT_ERR will indicate | |
699 | * that the dst QEMU is expected to quit with non-zero exit status | |
700 | */ | |
701 | enum { | |
702 | /* This test should succeed, the default */ | |
703 | MIG_TEST_SUCCEED = 0, | |
704 | /* This test should fail, dest qemu should keep alive */ | |
705 | MIG_TEST_FAIL, | |
706 | /* This test should fail, dest qemu should fail with abnormal status */ | |
707 | MIG_TEST_FAIL_DEST_QUIT_ERR, | |
5274274c FR |
708 | /* The QMP command for this migration should fail with an error */ |
709 | MIG_TEST_QMP_ERROR, | |
312e9dd0 PX |
710 | } result; |
711 | ||
e02f56e3 DB |
712 | /* |
713 | * Optional: set number of migration passes to wait for, if live==true. | |
714 | * If zero, then merely wait for a few MB of dirty data | |
715 | */ | |
312e9dd0 | 716 | unsigned int iterations; |
d1a27b16 | 717 | |
b861383c PX |
718 | /* |
719 | * Optional: whether the guest CPUs should be running during a precopy | |
720 | * migration test. We used to always run with live but it took much | |
721 | * longer so we reduced live tests to only the ones that have solid | |
722 | * reason to be tested live-only. For each of the new test cases for | |
723 | * precopy please provide justifications to use live explicitly (please | |
724 | * refer to existing ones with live=true), or use live=off by default. | |
725 | */ | |
3c4fb177 DB |
726 | bool live; |
727 | ||
d1a27b16 PX |
728 | /* Postcopy specific fields */ |
729 | void *postcopy_data; | |
8f6fe915 | 730 | bool postcopy_preempt; |
7bca2bb7 | 731 | bool postcopy_recovery_test_fail; |
312e9dd0 PX |
732 | } MigrateCommon; |
733 | ||
5fd4a9c9 | 734 | static int test_migrate_start(QTestState **from, QTestState **to, |
19da6edf | 735 | const char *uri, MigrateStart *args) |
ea0c6d62 | 736 | { |
ff7b9b56 PM |
737 | g_autofree gchar *arch_source = NULL; |
738 | g_autofree gchar *arch_target = NULL; | |
832c732c JQ |
739 | /* options for source and target */ |
740 | g_autofree gchar *arch_opts = NULL; | |
ff7b9b56 PM |
741 | g_autofree gchar *cmd_source = NULL; |
742 | g_autofree gchar *cmd_target = NULL; | |
1b023718 | 743 | const gchar *ignore_stderr; |
ff7b9b56 PM |
744 | g_autofree char *shmem_opts = NULL; |
745 | g_autofree char *shmem_path = NULL; | |
71d36124 | 746 | const char *kvm_opts = NULL; |
aaf89c8a | 747 | const char *arch = qtest_get_arch(); |
7b6d44cb | 748 | const char *memory_size; |
c9961391 | 749 | const char *machine_alias, *machine_opts = ""; |
5050ad2a | 750 | g_autofree char *machine = NULL; |
ea0c6d62 | 751 | |
5d3b575d | 752 | if (args->use_shmem) { |
660a9b68 YK |
753 | if (!g_file_test("/dev/shm", G_FILE_TEST_IS_DIR)) { |
754 | g_test_skip("/dev/shm is not supported"); | |
19da6edf | 755 | return -1; |
660a9b68 | 756 | } |
660a9b68 | 757 | } |
ea0c6d62 | 758 | |
95014994 DB |
759 | got_src_stop = false; |
760 | got_dst_resume = false; | |
aaf89c8a | 761 | if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { |
7b6d44cb | 762 | memory_size = "150M"; |
fa35b0cb FR |
763 | |
764 | if (g_str_equal(arch, "i386")) { | |
765 | machine_alias = "pc"; | |
766 | } else { | |
767 | machine_alias = "q35"; | |
768 | } | |
3cb9c655 FR |
769 | arch_opts = g_strdup_printf( |
770 | "-drive if=none,id=d0,file=%s,format=raw " | |
771 | "-device ide-hd,drive=d0,secs=1,cyls=1,heads=1", bootpath); | |
e51e711b WH |
772 | start_address = X86_TEST_MEM_START; |
773 | end_address = X86_TEST_MEM_END; | |
5571dc82 | 774 | } else if (g_str_equal(arch, "s390x")) { |
7b6d44cb | 775 | memory_size = "128M"; |
c9961391 | 776 | machine_alias = "s390-ccw-virtio"; |
832c732c | 777 | arch_opts = g_strdup_printf("-bios %s", bootpath); |
5571dc82 TH |
778 | start_address = S390_TEST_MEM_START; |
779 | end_address = S390_TEST_MEM_END; | |
aaf89c8a | 780 | } else if (strcmp(arch, "ppc64") == 0) { |
7b6d44cb | 781 | memory_size = "256M"; |
16c5c692 LV |
782 | start_address = PPC_TEST_MEM_START; |
783 | end_address = PPC_TEST_MEM_END; | |
832c732c | 784 | arch_source = g_strdup_printf("-prom-env 'use-nvramrc?=true' -prom-env " |
68d95609 JQ |
785 | "'nvramrc=hex .\" _\" begin %x %x " |
786 | "do i c@ 1 + i c! 1000 +loop .\" B\" 0 " | |
787 | "until'", end_address, start_address); | |
c9961391 FR |
788 | machine_alias = "pseries"; |
789 | machine_opts = "vsmt=8"; | |
790 | arch_opts = g_strdup("-nodefaults"); | |
c02b3781 | 791 | } else if (strcmp(arch, "aarch64") == 0) { |
7b6d44cb | 792 | memory_size = "150M"; |
c9961391 FR |
793 | machine_alias = "virt"; |
794 | machine_opts = "gic-version=max"; | |
795 | arch_opts = g_strdup_printf("-cpu max -kernel %s", bootpath); | |
c02b3781 WH |
796 | start_address = ARM_TEST_MEM_START; |
797 | end_address = ARM_TEST_MEM_END; | |
aaf89c8a | 798 | } else { |
799 | g_assert_not_reached(); | |
800 | } | |
801 | ||
a4729501 | 802 | if (!getenv("QTEST_LOG") && args->hide_stderr) { |
4dc8be38 | 803 | #ifndef _WIN32 |
1b023718 | 804 | ignore_stderr = "2>/dev/null"; |
4dc8be38 BM |
805 | #else |
806 | /* | |
807 | * On Windows the QEMU executable is created via CreateProcess() and | |
808 | * IO redirection does not work, so don't bother adding IO redirection | |
809 | * to the command line. | |
810 | */ | |
811 | ignore_stderr = ""; | |
812 | #endif | |
1b023718 JQ |
813 | } else { |
814 | ignore_stderr = ""; | |
f96d6651 DDAG |
815 | } |
816 | ||
5d3b575d | 817 | if (args->use_shmem) { |
3ed375e7 JQ |
818 | shmem_path = g_strdup_printf("/dev/shm/qemu-%d", getpid()); |
819 | shmem_opts = g_strdup_printf( | |
820 | "-object memory-backend-file,id=mem0,size=%s" | |
821 | ",mem-path=%s,share=on -numa node,memdev=mem0", | |
822 | memory_size, shmem_path); | |
3ed375e7 JQ |
823 | } |
824 | ||
71d36124 JQ |
825 | if (args->use_dirty_ring) { |
826 | kvm_opts = ",dirty-ring-size=4096"; | |
827 | } | |
828 | ||
6c6d2330 FR |
829 | machine = resolve_machine_version(machine_alias, QEMU_ENV_SRC, |
830 | QEMU_ENV_DST); | |
831 | ||
5050ad2a FR |
832 | g_test_message("Using machine type: %s", machine); |
833 | ||
bc28a611 | 834 | cmd_source = g_strdup_printf("-accel kvm%s -accel tcg " |
c9961391 | 835 | "-machine %s,%s " |
d6b43267 | 836 | "-name source,debug-threads=on " |
7b6d44cb | 837 | "-m %s " |
cd496731 | 838 | "-serial file:%s/src_serial " |
832c732c | 839 | "%s %s %s %s %s", |
71d36124 | 840 | kvm_opts ? kvm_opts : "", |
5050ad2a | 841 | machine, machine_opts, |
cd496731 | 842 | memory_size, tmpfs, |
832c732c JQ |
843 | arch_opts ? arch_opts : "", |
844 | arch_source ? arch_source : "", | |
0368ace8 | 845 | shmem_opts ? shmem_opts : "", |
19da6edf | 846 | args->opts_source ? args->opts_source : "", |
68d95609 | 847 | ignore_stderr); |
d795f474 | 848 | if (!args->only_target) { |
5050ad2a | 849 | *from = qtest_init_with_env(QEMU_ENV_SRC, cmd_source); |
cdf5ab55 DB |
850 | qtest_qmp_set_event_callback(*from, |
851 | migrate_watch_for_stop, | |
95014994 | 852 | &got_src_stop); |
d795f474 | 853 | } |
aaf89c8a | 854 | |
bc28a611 | 855 | cmd_target = g_strdup_printf("-accel kvm%s -accel tcg " |
c9961391 | 856 | "-machine %s,%s " |
d6b43267 | 857 | "-name target,debug-threads=on " |
7b6d44cb | 858 | "-m %s " |
c5f40ff9 | 859 | "-serial file:%s/dest_serial " |
cd496731 | 860 | "-incoming %s " |
832c732c | 861 | "%s %s %s %s %s", |
71d36124 | 862 | kvm_opts ? kvm_opts : "", |
5050ad2a | 863 | machine, machine_opts, |
cd496731 | 864 | memory_size, tmpfs, uri, |
832c732c JQ |
865 | arch_opts ? arch_opts : "", |
866 | arch_target ? arch_target : "", | |
0368ace8 | 867 | shmem_opts ? shmem_opts : "", |
19da6edf DB |
868 | args->opts_target ? args->opts_target : "", |
869 | ignore_stderr); | |
5050ad2a | 870 | *to = qtest_init_with_env(QEMU_ENV_DST, cmd_target); |
266ea334 DB |
871 | qtest_qmp_set_event_callback(*to, |
872 | migrate_watch_for_resume, | |
95014994 | 873 | &got_dst_resume); |
660a9b68 YK |
874 | |
875 | /* | |
876 | * Remove shmem file immediately to avoid memory leak in test failed case. | |
96420a30 | 877 | * It's valid because QEMU has already opened this file |
660a9b68 | 878 | */ |
5d3b575d | 879 | if (args->use_shmem) { |
660a9b68 | 880 | unlink(shmem_path); |
660a9b68 YK |
881 | } |
882 | ||
19da6edf | 883 | return 0; |
7195a871 JQ |
884 | } |
885 | ||
2c9bb297 | 886 | static void test_migrate_end(QTestState *from, QTestState *to, bool test_dest) |
7195a871 JQ |
887 | { |
888 | unsigned char dest_byte_a, dest_byte_b, dest_byte_c, dest_byte_d; | |
889 | ||
890 | qtest_quit(from); | |
891 | ||
2c9bb297 DDAG |
892 | if (test_dest) { |
893 | qtest_memread(to, start_address, &dest_byte_a, 1); | |
7195a871 | 894 | |
2c9bb297 DDAG |
895 | /* Destination still running, wait for a byte to change */ |
896 | do { | |
897 | qtest_memread(to, start_address, &dest_byte_b, 1); | |
898 | usleep(1000 * 10); | |
899 | } while (dest_byte_a == dest_byte_b); | |
900 | ||
855436db | 901 | qtest_qmp_assert_success(to, "{ 'execute' : 'stop'}"); |
7195a871 | 902 | |
2c9bb297 DDAG |
903 | /* With it stopped, check nothing changes */ |
904 | qtest_memread(to, start_address, &dest_byte_c, 1); | |
905 | usleep(1000 * 200); | |
906 | qtest_memread(to, start_address, &dest_byte_d, 1); | |
907 | g_assert_cmpint(dest_byte_c, ==, dest_byte_d); | |
7195a871 | 908 | |
2c9bb297 DDAG |
909 | check_guests_ram(to); |
910 | } | |
7195a871 JQ |
911 | |
912 | qtest_quit(to); | |
913 | ||
7195a871 JQ |
914 | cleanup("migsocket"); |
915 | cleanup("src_serial"); | |
916 | cleanup("dest_serial"); | |
3dc35470 | 917 | cleanup(FILE_TEST_FILENAME); |
7195a871 JQ |
918 | } |
919 | ||
58d25e97 DB |
920 | #ifdef CONFIG_GNUTLS |
921 | struct TestMigrateTLSPSKData { | |
922 | char *workdir; | |
923 | char *workdiralt; | |
924 | char *pskfile; | |
925 | char *pskfilealt; | |
926 | }; | |
927 | ||
928 | static void * | |
929 | test_migrate_tls_psk_start_common(QTestState *from, | |
930 | QTestState *to, | |
931 | bool mismatch) | |
932 | { | |
933 | struct TestMigrateTLSPSKData *data = | |
934 | g_new0(struct TestMigrateTLSPSKData, 1); | |
58d25e97 DB |
935 | |
936 | data->workdir = g_strdup_printf("%s/tlscredspsk0", tmpfs); | |
937 | data->pskfile = g_strdup_printf("%s/%s", data->workdir, | |
938 | QCRYPTO_TLS_CREDS_PSKFILE); | |
413bebc0 | 939 | g_mkdir_with_parents(data->workdir, 0700); |
58d25e97 DB |
940 | test_tls_psk_init(data->pskfile); |
941 | ||
942 | if (mismatch) { | |
943 | data->workdiralt = g_strdup_printf("%s/tlscredspskalt0", tmpfs); | |
944 | data->pskfilealt = g_strdup_printf("%s/%s", data->workdiralt, | |
945 | QCRYPTO_TLS_CREDS_PSKFILE); | |
413bebc0 | 946 | g_mkdir_with_parents(data->workdiralt, 0700); |
58d25e97 DB |
947 | test_tls_psk_init_alt(data->pskfilealt); |
948 | } | |
949 | ||
aca04069 DB |
950 | qtest_qmp_assert_success(from, |
951 | "{ 'execute': 'object-add'," | |
952 | " 'arguments': { 'qom-type': 'tls-creds-psk'," | |
953 | " 'id': 'tlscredspsk0'," | |
954 | " 'endpoint': 'client'," | |
955 | " 'dir': %s," | |
956 | " 'username': 'qemu'} }", | |
957 | data->workdir); | |
958 | ||
959 | qtest_qmp_assert_success(to, | |
960 | "{ 'execute': 'object-add'," | |
961 | " 'arguments': { 'qom-type': 'tls-creds-psk'," | |
962 | " 'id': 'tlscredspsk0'," | |
963 | " 'endpoint': 'server'," | |
964 | " 'dir': %s } }", | |
965 | mismatch ? data->workdiralt : data->workdir); | |
58d25e97 DB |
966 | |
967 | migrate_set_parameter_str(from, "tls-creds", "tlscredspsk0"); | |
968 | migrate_set_parameter_str(to, "tls-creds", "tlscredspsk0"); | |
969 | ||
970 | return data; | |
971 | } | |
972 | ||
973 | static void * | |
974 | test_migrate_tls_psk_start_match(QTestState *from, | |
975 | QTestState *to) | |
976 | { | |
977 | return test_migrate_tls_psk_start_common(from, to, false); | |
978 | } | |
979 | ||
980 | static void * | |
981 | test_migrate_tls_psk_start_mismatch(QTestState *from, | |
982 | QTestState *to) | |
983 | { | |
984 | return test_migrate_tls_psk_start_common(from, to, true); | |
985 | } | |
986 | ||
987 | static void | |
988 | test_migrate_tls_psk_finish(QTestState *from, | |
989 | QTestState *to, | |
990 | void *opaque) | |
991 | { | |
992 | struct TestMigrateTLSPSKData *data = opaque; | |
993 | ||
994 | test_tls_psk_cleanup(data->pskfile); | |
995 | if (data->pskfilealt) { | |
996 | test_tls_psk_cleanup(data->pskfilealt); | |
997 | } | |
998 | rmdir(data->workdir); | |
999 | if (data->workdiralt) { | |
1000 | rmdir(data->workdiralt); | |
1001 | } | |
1002 | ||
1003 | g_free(data->workdiralt); | |
1004 | g_free(data->pskfilealt); | |
1005 | g_free(data->workdir); | |
1006 | g_free(data->pskfile); | |
1007 | g_free(data); | |
1008 | } | |
d47b83b1 DB |
1009 | |
1010 | #ifdef CONFIG_TASN1 | |
1011 | typedef struct { | |
1012 | char *workdir; | |
1013 | char *keyfile; | |
1014 | char *cacert; | |
1015 | char *servercert; | |
1016 | char *serverkey; | |
1017 | char *clientcert; | |
1018 | char *clientkey; | |
1019 | } TestMigrateTLSX509Data; | |
1020 | ||
1021 | typedef struct { | |
1022 | bool verifyclient; | |
1023 | bool clientcert; | |
1024 | bool hostileclient; | |
1025 | bool authzclient; | |
1026 | const char *certhostname; | |
1027 | const char *certipaddr; | |
1028 | } TestMigrateTLSX509; | |
1029 | ||
1030 | static void * | |
1031 | test_migrate_tls_x509_start_common(QTestState *from, | |
1032 | QTestState *to, | |
1033 | TestMigrateTLSX509 *args) | |
1034 | { | |
1035 | TestMigrateTLSX509Data *data = g_new0(TestMigrateTLSX509Data, 1); | |
d47b83b1 DB |
1036 | |
1037 | data->workdir = g_strdup_printf("%s/tlscredsx5090", tmpfs); | |
1038 | data->keyfile = g_strdup_printf("%s/key.pem", data->workdir); | |
1039 | ||
1040 | data->cacert = g_strdup_printf("%s/ca-cert.pem", data->workdir); | |
1041 | data->serverkey = g_strdup_printf("%s/server-key.pem", data->workdir); | |
1042 | data->servercert = g_strdup_printf("%s/server-cert.pem", data->workdir); | |
1043 | if (args->clientcert) { | |
1044 | data->clientkey = g_strdup_printf("%s/client-key.pem", data->workdir); | |
1045 | data->clientcert = g_strdup_printf("%s/client-cert.pem", data->workdir); | |
1046 | } | |
1047 | ||
413bebc0 | 1048 | g_mkdir_with_parents(data->workdir, 0700); |
d47b83b1 DB |
1049 | |
1050 | test_tls_init(data->keyfile); | |
2549f610 | 1051 | #ifndef _WIN32 |
d47b83b1 | 1052 | g_assert(link(data->keyfile, data->serverkey) == 0); |
2549f610 BM |
1053 | #else |
1054 | g_assert(CreateHardLink(data->serverkey, data->keyfile, NULL) != 0); | |
1055 | #endif | |
d47b83b1 | 1056 | if (args->clientcert) { |
2549f610 | 1057 | #ifndef _WIN32 |
d47b83b1 | 1058 | g_assert(link(data->keyfile, data->clientkey) == 0); |
2549f610 BM |
1059 | #else |
1060 | g_assert(CreateHardLink(data->clientkey, data->keyfile, NULL) != 0); | |
1061 | #endif | |
d47b83b1 DB |
1062 | } |
1063 | ||
1064 | TLS_ROOT_REQ_SIMPLE(cacertreq, data->cacert); | |
1065 | if (args->clientcert) { | |
1066 | TLS_CERT_REQ_SIMPLE_CLIENT(servercertreq, cacertreq, | |
1067 | args->hostileclient ? | |
1068 | QCRYPTO_TLS_TEST_CLIENT_HOSTILE_NAME : | |
1069 | QCRYPTO_TLS_TEST_CLIENT_NAME, | |
1070 | data->clientcert); | |
1071 | } | |
1072 | ||
1073 | TLS_CERT_REQ_SIMPLE_SERVER(clientcertreq, cacertreq, | |
1074 | data->servercert, | |
1075 | args->certhostname, | |
1076 | args->certipaddr); | |
1077 | ||
aca04069 DB |
1078 | qtest_qmp_assert_success(from, |
1079 | "{ 'execute': 'object-add'," | |
1080 | " 'arguments': { 'qom-type': 'tls-creds-x509'," | |
1081 | " 'id': 'tlscredsx509client0'," | |
1082 | " 'endpoint': 'client'," | |
1083 | " 'dir': %s," | |
1084 | " 'sanity-check': true," | |
1085 | " 'verify-peer': true} }", | |
1086 | data->workdir); | |
d47b83b1 DB |
1087 | migrate_set_parameter_str(from, "tls-creds", "tlscredsx509client0"); |
1088 | if (args->certhostname) { | |
1089 | migrate_set_parameter_str(from, "tls-hostname", args->certhostname); | |
1090 | } | |
1091 | ||
aca04069 DB |
1092 | qtest_qmp_assert_success(to, |
1093 | "{ 'execute': 'object-add'," | |
1094 | " 'arguments': { 'qom-type': 'tls-creds-x509'," | |
1095 | " 'id': 'tlscredsx509server0'," | |
1096 | " 'endpoint': 'server'," | |
1097 | " 'dir': %s," | |
1098 | " 'sanity-check': true," | |
1099 | " 'verify-peer': %i} }", | |
1100 | data->workdir, args->verifyclient); | |
d47b83b1 DB |
1101 | migrate_set_parameter_str(to, "tls-creds", "tlscredsx509server0"); |
1102 | ||
1103 | if (args->authzclient) { | |
aca04069 DB |
1104 | qtest_qmp_assert_success(to, |
1105 | "{ 'execute': 'object-add'," | |
1106 | " 'arguments': { 'qom-type': 'authz-simple'," | |
1107 | " 'id': 'tlsauthz0'," | |
1108 | " 'identity': %s} }", | |
1109 | "CN=" QCRYPTO_TLS_TEST_CLIENT_NAME); | |
d47b83b1 DB |
1110 | migrate_set_parameter_str(to, "tls-authz", "tlsauthz0"); |
1111 | } | |
1112 | ||
1113 | return data; | |
1114 | } | |
1115 | ||
1116 | /* | |
1117 | * The normal case: match server's cert hostname against | |
1118 | * whatever host we were telling QEMU to connect to (if any) | |
1119 | */ | |
1120 | static void * | |
1121 | test_migrate_tls_x509_start_default_host(QTestState *from, | |
1122 | QTestState *to) | |
1123 | { | |
1124 | TestMigrateTLSX509 args = { | |
1125 | .verifyclient = true, | |
1126 | .clientcert = true, | |
1127 | .certipaddr = "127.0.0.1" | |
1128 | }; | |
1129 | return test_migrate_tls_x509_start_common(from, to, &args); | |
1130 | } | |
1131 | ||
1132 | /* | |
1133 | * The unusual case: the server's cert is different from | |
1134 | * the address we're telling QEMU to connect to (if any), | |
1135 | * so we must give QEMU an explicit hostname to validate | |
1136 | */ | |
1137 | static void * | |
1138 | test_migrate_tls_x509_start_override_host(QTestState *from, | |
1139 | QTestState *to) | |
1140 | { | |
1141 | TestMigrateTLSX509 args = { | |
1142 | .verifyclient = true, | |
1143 | .clientcert = true, | |
1144 | .certhostname = "qemu.org", | |
1145 | }; | |
1146 | return test_migrate_tls_x509_start_common(from, to, &args); | |
1147 | } | |
1148 | ||
1149 | /* | |
1150 | * The unusual case: the server's cert is different from | |
1151 | * the address we're telling QEMU to connect to, and so we | |
1152 | * expect the client to reject the server | |
1153 | */ | |
1154 | static void * | |
1155 | test_migrate_tls_x509_start_mismatch_host(QTestState *from, | |
1156 | QTestState *to) | |
1157 | { | |
1158 | TestMigrateTLSX509 args = { | |
1159 | .verifyclient = true, | |
1160 | .clientcert = true, | |
1161 | .certipaddr = "10.0.0.1", | |
1162 | }; | |
1163 | return test_migrate_tls_x509_start_common(from, to, &args); | |
1164 | } | |
1165 | ||
1166 | static void * | |
1167 | test_migrate_tls_x509_start_friendly_client(QTestState *from, | |
1168 | QTestState *to) | |
1169 | { | |
1170 | TestMigrateTLSX509 args = { | |
1171 | .verifyclient = true, | |
1172 | .clientcert = true, | |
1173 | .authzclient = true, | |
1174 | .certipaddr = "127.0.0.1", | |
1175 | }; | |
1176 | return test_migrate_tls_x509_start_common(from, to, &args); | |
1177 | } | |
1178 | ||
1179 | static void * | |
1180 | test_migrate_tls_x509_start_hostile_client(QTestState *from, | |
1181 | QTestState *to) | |
1182 | { | |
1183 | TestMigrateTLSX509 args = { | |
1184 | .verifyclient = true, | |
1185 | .clientcert = true, | |
1186 | .hostileclient = true, | |
1187 | .authzclient = true, | |
1188 | .certipaddr = "127.0.0.1", | |
1189 | }; | |
1190 | return test_migrate_tls_x509_start_common(from, to, &args); | |
1191 | } | |
1192 | ||
1193 | /* | |
1194 | * The case with no client certificate presented, | |
1195 | * and no server verification | |
1196 | */ | |
1197 | static void * | |
1198 | test_migrate_tls_x509_start_allow_anon_client(QTestState *from, | |
1199 | QTestState *to) | |
1200 | { | |
1201 | TestMigrateTLSX509 args = { | |
1202 | .certipaddr = "127.0.0.1", | |
1203 | }; | |
1204 | return test_migrate_tls_x509_start_common(from, to, &args); | |
1205 | } | |
1206 | ||
1207 | /* | |
1208 | * The case with no client certificate presented, | |
1209 | * and server verification rejecting | |
1210 | */ | |
1211 | static void * | |
1212 | test_migrate_tls_x509_start_reject_anon_client(QTestState *from, | |
1213 | QTestState *to) | |
1214 | { | |
1215 | TestMigrateTLSX509 args = { | |
1216 | .verifyclient = true, | |
1217 | .certipaddr = "127.0.0.1", | |
1218 | }; | |
1219 | return test_migrate_tls_x509_start_common(from, to, &args); | |
1220 | } | |
1221 | ||
1222 | static void | |
1223 | test_migrate_tls_x509_finish(QTestState *from, | |
1224 | QTestState *to, | |
1225 | void *opaque) | |
1226 | { | |
1227 | TestMigrateTLSX509Data *data = opaque; | |
1228 | ||
1229 | test_tls_cleanup(data->keyfile); | |
0f0a9e4e TH |
1230 | g_free(data->keyfile); |
1231 | ||
d47b83b1 | 1232 | unlink(data->cacert); |
0f0a9e4e | 1233 | g_free(data->cacert); |
d47b83b1 | 1234 | unlink(data->servercert); |
0f0a9e4e | 1235 | g_free(data->servercert); |
d47b83b1 | 1236 | unlink(data->serverkey); |
0f0a9e4e | 1237 | g_free(data->serverkey); |
d47b83b1 | 1238 | |
0f0a9e4e TH |
1239 | if (data->clientcert) { |
1240 | unlink(data->clientcert); | |
1241 | g_free(data->clientcert); | |
1242 | } | |
1243 | if (data->clientkey) { | |
1244 | unlink(data->clientkey); | |
1245 | g_free(data->clientkey); | |
1246 | } | |
1247 | ||
1248 | rmdir(data->workdir); | |
d47b83b1 | 1249 | g_free(data->workdir); |
0f0a9e4e | 1250 | |
d47b83b1 DB |
1251 | g_free(data); |
1252 | } | |
1253 | #endif /* CONFIG_TASN1 */ | |
58d25e97 DB |
1254 | #endif /* CONFIG_GNUTLS */ |
1255 | ||
dc066da8 LS |
1256 | static void * |
1257 | test_migrate_compress_start(QTestState *from, | |
1258 | QTestState *to) | |
1259 | { | |
1260 | migrate_set_parameter_int(from, "compress-level", 1); | |
1261 | migrate_set_parameter_int(from, "compress-threads", 4); | |
1262 | migrate_set_parameter_bool(from, "compress-wait-thread", true); | |
1263 | migrate_set_parameter_int(to, "decompress-threads", 4); | |
1264 | ||
1265 | migrate_set_capability(from, "compress", true); | |
1266 | migrate_set_capability(to, "compress", true); | |
1267 | ||
1268 | return NULL; | |
1269 | } | |
1270 | ||
1271 | static void * | |
1272 | test_migrate_compress_nowait_start(QTestState *from, | |
1273 | QTestState *to) | |
1274 | { | |
1275 | migrate_set_parameter_int(from, "compress-level", 9); | |
1276 | migrate_set_parameter_int(from, "compress-threads", 1); | |
1277 | migrate_set_parameter_bool(from, "compress-wait-thread", false); | |
1278 | migrate_set_parameter_int(to, "decompress-threads", 1); | |
1279 | ||
1280 | migrate_set_capability(from, "compress", true); | |
1281 | migrate_set_capability(to, "compress", true); | |
1282 | ||
1283 | return NULL; | |
1284 | } | |
1285 | ||
d131662a | 1286 | static int migrate_postcopy_prepare(QTestState **from_ptr, |
5d3b575d | 1287 | QTestState **to_ptr, |
d1a27b16 | 1288 | MigrateCommon *args) |
7195a871 | 1289 | { |
863e27a8 | 1290 | QTestState *from, *to; |
7195a871 | 1291 | |
06c48d6b | 1292 | if (test_migrate_start(&from, &to, "defer", &args->start)) { |
d131662a | 1293 | return -1; |
5fd4a9c9 | 1294 | } |
ea0c6d62 | 1295 | |
d1a27b16 PX |
1296 | if (args->start_hook) { |
1297 | args->postcopy_data = args->start_hook(from, to); | |
1298 | } | |
1299 | ||
c44a56d8 MA |
1300 | migrate_set_capability(from, "postcopy-ram", true); |
1301 | migrate_set_capability(to, "postcopy-ram", true); | |
1302 | migrate_set_capability(to, "postcopy-blocktime", true); | |
ea0c6d62 | 1303 | |
8f6fe915 PX |
1304 | if (args->postcopy_preempt) { |
1305 | migrate_set_capability(from, "postcopy-preempt", true); | |
1306 | migrate_set_capability(to, "postcopy-preempt", true); | |
1307 | } | |
1308 | ||
886dfe9d | 1309 | migrate_ensure_non_converge(from); |
ea0c6d62 | 1310 | |
e02f56e3 | 1311 | migrate_prepare_for_dirty_mem(from); |
06c48d6b | 1312 | qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming'," |
8e3766ee HG |
1313 | " 'arguments': { " |
1314 | " 'channels': [ { 'channel-type': 'main'," | |
1315 | " 'addr': { 'transport': 'socket'," | |
1316 | " 'type': 'inet'," | |
1317 | " 'host': '127.0.0.1'," | |
1318 | " 'port': '0' } } ] } }"); | |
e02f56e3 | 1319 | |
ea0c6d62 DDAG |
1320 | /* Wait for the first serial output from the source */ |
1321 | wait_for_serial("src_serial"); | |
1322 | ||
06c48d6b | 1323 | g_autofree char *uri = migrate_get_socket_address(to, "socket-address"); |
d77799cc | 1324 | migrate_qmp(from, uri, "{}"); |
ea0c6d62 | 1325 | |
e02f56e3 | 1326 | migrate_wait_for_dirty_mem(from, to); |
ea0c6d62 | 1327 | |
d131662a PX |
1328 | *from_ptr = from; |
1329 | *to_ptr = to; | |
ea0c6d62 | 1330 | |
d131662a PX |
1331 | return 0; |
1332 | } | |
ea0c6d62 | 1333 | |
d1a27b16 PX |
1334 | static void migrate_postcopy_complete(QTestState *from, QTestState *to, |
1335 | MigrateCommon *args) | |
d131662a PX |
1336 | { |
1337 | wait_for_migration_complete(from); | |
ea0c6d62 | 1338 | |
d131662a | 1339 | /* Make sure we get at least one "B" on destination */ |
ea0c6d62 | 1340 | wait_for_serial("dest_serial"); |
ea0c6d62 | 1341 | |
346f3dab AP |
1342 | if (uffd_feature_thread_id) { |
1343 | read_blocktime(to); | |
1344 | } | |
ea0c6d62 | 1345 | |
d1a27b16 PX |
1346 | if (args->finish_hook) { |
1347 | args->finish_hook(from, to, args->postcopy_data); | |
1348 | args->postcopy_data = NULL; | |
1349 | } | |
1350 | ||
2c9bb297 DDAG |
1351 | test_migrate_end(from, to, true); |
1352 | } | |
1353 | ||
d1a27b16 | 1354 | static void test_postcopy_common(MigrateCommon *args) |
d131662a PX |
1355 | { |
1356 | QTestState *from, *to; | |
1357 | ||
d1a27b16 | 1358 | if (migrate_postcopy_prepare(&from, &to, args)) { |
d131662a PX |
1359 | return; |
1360 | } | |
1361 | migrate_postcopy_start(from, to); | |
d1a27b16 | 1362 | migrate_postcopy_complete(from, to, args); |
d131662a PX |
1363 | } |
1364 | ||
d1a27b16 PX |
1365 | static void test_postcopy(void) |
1366 | { | |
1367 | MigrateCommon args = { }; | |
1368 | ||
1369 | test_postcopy_common(&args); | |
1370 | } | |
1371 | ||
dc066da8 LS |
1372 | static void test_postcopy_compress(void) |
1373 | { | |
1374 | MigrateCommon args = { | |
1375 | .start_hook = test_migrate_compress_start | |
1376 | }; | |
1377 | ||
1378 | test_postcopy_common(&args); | |
1379 | } | |
1380 | ||
8f6fe915 PX |
1381 | static void test_postcopy_preempt(void) |
1382 | { | |
1383 | MigrateCommon args = { | |
1384 | .postcopy_preempt = true, | |
1385 | }; | |
1386 | ||
1387 | test_postcopy_common(&args); | |
1388 | } | |
1389 | ||
d1a27b16 PX |
1390 | #ifdef CONFIG_GNUTLS |
1391 | static void test_postcopy_tls_psk(void) | |
1392 | { | |
1393 | MigrateCommon args = { | |
1394 | .start_hook = test_migrate_tls_psk_start_match, | |
1395 | .finish_hook = test_migrate_tls_psk_finish, | |
1396 | }; | |
1397 | ||
1398 | test_postcopy_common(&args); | |
1399 | } | |
8f6fe915 PX |
1400 | |
1401 | static void test_postcopy_preempt_tls_psk(void) | |
1402 | { | |
1403 | MigrateCommon args = { | |
1404 | .postcopy_preempt = true, | |
1405 | .start_hook = test_migrate_tls_psk_start_match, | |
1406 | .finish_hook = test_migrate_tls_psk_finish, | |
1407 | }; | |
1408 | ||
1409 | test_postcopy_common(&args); | |
1410 | } | |
d1a27b16 PX |
1411 | #endif |
1412 | ||
7bca2bb7 FR |
1413 | static void wait_for_postcopy_status(QTestState *one, const char *status) |
1414 | { | |
1415 | wait_for_migration_status(one, status, | |
1416 | (const char * []) { "failed", "active", | |
1417 | "completed", NULL }); | |
1418 | } | |
1419 | ||
1420 | #ifndef _WIN32 | |
1421 | static void postcopy_recover_fail(QTestState *from, QTestState *to) | |
1422 | { | |
1423 | int ret, pair1[2], pair2[2]; | |
1424 | char c; | |
1425 | ||
1426 | /* Create two unrelated socketpairs */ | |
1427 | ret = qemu_socketpair(PF_LOCAL, SOCK_STREAM, 0, pair1); | |
1428 | g_assert_cmpint(ret, ==, 0); | |
1429 | ||
1430 | ret = qemu_socketpair(PF_LOCAL, SOCK_STREAM, 0, pair2); | |
1431 | g_assert_cmpint(ret, ==, 0); | |
1432 | ||
1433 | /* | |
1434 | * Give the guests unpaired ends of the sockets, so they'll all blocked | |
1435 | * at reading. This mimics a wrong channel established. | |
1436 | */ | |
1437 | qtest_qmp_fds_assert_success(from, &pair1[0], 1, | |
1438 | "{ 'execute': 'getfd'," | |
1439 | " 'arguments': { 'fdname': 'fd-mig' }}"); | |
1440 | qtest_qmp_fds_assert_success(to, &pair2[0], 1, | |
1441 | "{ 'execute': 'getfd'," | |
1442 | " 'arguments': { 'fdname': 'fd-mig' }}"); | |
1443 | ||
1444 | /* | |
1445 | * Write the 1st byte as QEMU_VM_COMMAND (0x8) for the dest socket, to | |
1446 | * emulate the 1st byte of a real recovery, but stops from there to | |
1447 | * keep dest QEMU in RECOVER. This is needed so that we can kick off | |
1448 | * the recover process on dest QEMU (by triggering the G_IO_IN event). | |
1449 | * | |
1450 | * NOTE: this trick is not needed on src QEMUs, because src doesn't | |
1451 | * rely on an pre-existing G_IO_IN event, so it will always trigger the | |
1452 | * upcoming recovery anyway even if it can read nothing. | |
1453 | */ | |
1454 | #define QEMU_VM_COMMAND 0x08 | |
1455 | c = QEMU_VM_COMMAND; | |
1456 | ret = send(pair2[1], &c, 1, 0); | |
1457 | g_assert_cmpint(ret, ==, 1); | |
1458 | ||
1459 | migrate_recover(to, "fd:fd-mig"); | |
1460 | migrate_qmp(from, "fd:fd-mig", "{'resume': true}"); | |
1461 | ||
1462 | /* | |
1463 | * Make sure both QEMU instances will go into RECOVER stage, then test | |
1464 | * kicking them out using migrate-pause. | |
1465 | */ | |
1466 | wait_for_postcopy_status(from, "postcopy-recover"); | |
1467 | wait_for_postcopy_status(to, "postcopy-recover"); | |
1468 | ||
1469 | /* | |
1470 | * This would be issued by the admin upon noticing the hang, we should | |
1471 | * make sure we're able to kick this out. | |
1472 | */ | |
1473 | migrate_pause(from); | |
1474 | wait_for_postcopy_status(from, "postcopy-paused"); | |
1475 | ||
1476 | /* Do the same test on dest */ | |
1477 | migrate_pause(to); | |
1478 | wait_for_postcopy_status(to, "postcopy-paused"); | |
1479 | ||
1480 | close(pair1[0]); | |
1481 | close(pair1[1]); | |
1482 | close(pair2[0]); | |
1483 | close(pair2[1]); | |
1484 | } | |
1485 | #endif /* _WIN32 */ | |
1486 | ||
767fa9cf | 1487 | static void test_postcopy_recovery_common(MigrateCommon *args) |
d5f49640 PX |
1488 | { |
1489 | QTestState *from, *to; | |
ff7b9b56 | 1490 | g_autofree char *uri = NULL; |
d5f49640 | 1491 | |
767fa9cf PX |
1492 | /* Always hide errors for postcopy recover tests since they're expected */ |
1493 | args->start.hide_stderr = true; | |
1494 | ||
1495 | if (migrate_postcopy_prepare(&from, &to, args)) { | |
d5f49640 PX |
1496 | return; |
1497 | } | |
1498 | ||
1499 | /* Turn postcopy speed down, 4K/s is slow enough on any machines */ | |
8f7798f1 | 1500 | migrate_set_parameter_int(from, "max-postcopy-bandwidth", 4096); |
d5f49640 PX |
1501 | |
1502 | /* Now we start the postcopy */ | |
1503 | migrate_postcopy_start(from, to); | |
1504 | ||
1505 | /* | |
1506 | * Wait until postcopy is really started; we can only run the | |
1507 | * migrate-pause command during a postcopy | |
1508 | */ | |
8c51642b | 1509 | wait_for_migration_status(from, "postcopy-active", NULL); |
d5f49640 PX |
1510 | |
1511 | /* | |
1512 | * Manually stop the postcopy migration. This emulates a network | |
1513 | * failure with the migration socket | |
1514 | */ | |
1515 | migrate_pause(from); | |
1516 | ||
1517 | /* | |
1518 | * Wait for destination side to reach postcopy-paused state. The | |
1519 | * migrate-recover command can only succeed if destination machine | |
1520 | * is in the paused state | |
1521 | */ | |
7bca2bb7 FR |
1522 | wait_for_postcopy_status(to, "postcopy-paused"); |
1523 | wait_for_postcopy_status(from, "postcopy-paused"); | |
1524 | ||
1525 | #ifndef _WIN32 | |
1526 | if (args->postcopy_recovery_test_fail) { | |
1527 | /* | |
1528 | * Test when a wrong socket specified for recover, and then the | |
1529 | * ability to kick it out, and continue with a correct socket. | |
1530 | */ | |
1531 | postcopy_recover_fail(from, to); | |
1532 | /* continue with a good recovery */ | |
1533 | } | |
1534 | #endif /* _WIN32 */ | |
d5f49640 PX |
1535 | |
1536 | /* | |
1537 | * Create a new socket to emulate a new channel that is different | |
1538 | * from the broken migration channel; tell the destination to | |
1539 | * listen to the new port | |
1540 | */ | |
1541 | uri = g_strdup_printf("unix:%s/migsocket-recover", tmpfs); | |
1542 | migrate_recover(to, uri); | |
1543 | ||
1544 | /* | |
1545 | * Try to rebuild the migration channel using the resume flag and | |
1546 | * the newly created channel | |
1547 | */ | |
d77799cc | 1548 | migrate_qmp(from, uri, "{'resume': true}"); |
d5f49640 PX |
1549 | |
1550 | /* Restore the postcopy bandwidth to unlimited */ | |
8f7798f1 | 1551 | migrate_set_parameter_int(from, "max-postcopy-bandwidth", 0); |
d5f49640 | 1552 | |
767fa9cf PX |
1553 | migrate_postcopy_complete(from, to, args); |
1554 | } | |
1555 | ||
1556 | static void test_postcopy_recovery(void) | |
1557 | { | |
1558 | MigrateCommon args = { }; | |
1559 | ||
1560 | test_postcopy_recovery_common(&args); | |
d5f49640 PX |
1561 | } |
1562 | ||
dc066da8 LS |
1563 | static void test_postcopy_recovery_compress(void) |
1564 | { | |
1565 | MigrateCommon args = { | |
1566 | .start_hook = test_migrate_compress_start | |
1567 | }; | |
1568 | ||
1569 | test_postcopy_recovery_common(&args); | |
1570 | } | |
1571 | ||
7bca2bb7 FR |
1572 | #ifndef _WIN32 |
1573 | static void test_postcopy_recovery_double_fail(void) | |
1574 | { | |
1575 | MigrateCommon args = { | |
1576 | .postcopy_recovery_test_fail = true, | |
1577 | }; | |
1578 | ||
1579 | test_postcopy_recovery_common(&args); | |
1580 | } | |
1581 | #endif /* _WIN32 */ | |
1582 | ||
767fa9cf PX |
1583 | #ifdef CONFIG_GNUTLS |
1584 | static void test_postcopy_recovery_tls_psk(void) | |
1585 | { | |
1586 | MigrateCommon args = { | |
1587 | .start_hook = test_migrate_tls_psk_start_match, | |
1588 | .finish_hook = test_migrate_tls_psk_finish, | |
1589 | }; | |
1590 | ||
1591 | test_postcopy_recovery_common(&args); | |
1592 | } | |
1593 | #endif | |
1594 | ||
8f6fe915 PX |
1595 | static void test_postcopy_preempt_recovery(void) |
1596 | { | |
1597 | MigrateCommon args = { | |
1598 | .postcopy_preempt = true, | |
1599 | }; | |
1600 | ||
1601 | test_postcopy_recovery_common(&args); | |
1602 | } | |
1603 | ||
1604 | #ifdef CONFIG_GNUTLS | |
1605 | /* This contains preempt+recovery+tls test altogether */ | |
1606 | static void test_postcopy_preempt_all(void) | |
1607 | { | |
1608 | MigrateCommon args = { | |
1609 | .postcopy_preempt = true, | |
1610 | .start_hook = test_migrate_tls_psk_start_match, | |
1611 | .finish_hook = test_migrate_tls_psk_finish, | |
1612 | }; | |
1613 | ||
1614 | test_postcopy_recovery_common(&args); | |
1615 | } | |
dc066da8 | 1616 | |
8f6fe915 PX |
1617 | #endif |
1618 | ||
3af31a34 YK |
1619 | static void test_baddest(void) |
1620 | { | |
19da6edf DB |
1621 | MigrateStart args = { |
1622 | .hide_stderr = true | |
1623 | }; | |
3af31a34 | 1624 | QTestState *from, *to; |
2c9bb297 | 1625 | |
3ff57401 | 1626 | if (test_migrate_start(&from, &to, "tcp:127.0.0.1:0", &args)) { |
3af31a34 YK |
1627 | return; |
1628 | } | |
5e32ffd3 | 1629 | migrate_qmp(from, "tcp:127.0.0.1:0", "{}"); |
3af31a34 | 1630 | wait_for_migration_fail(from, false); |
2c9bb297 | 1631 | test_migrate_end(from, to, false); |
ea0c6d62 DDAG |
1632 | } |
1633 | ||
d864756e FR |
1634 | #ifndef _WIN32 |
1635 | static void test_analyze_script(void) | |
1636 | { | |
1637 | MigrateStart args = { | |
1638 | .opts_source = "-uuid 11111111-1111-1111-1111-111111111111", | |
1639 | }; | |
1640 | QTestState *from, *to; | |
1641 | g_autofree char *uri = NULL; | |
1642 | g_autofree char *file = NULL; | |
1643 | int pid, wstatus; | |
1644 | const char *python = g_getenv("PYTHON"); | |
1645 | ||
1646 | if (!python) { | |
1647 | g_test_skip("PYTHON variable not set"); | |
1648 | return; | |
1649 | } | |
1650 | ||
1651 | /* dummy url */ | |
1652 | if (test_migrate_start(&from, &to, "tcp:127.0.0.1:0", &args)) { | |
1653 | return; | |
1654 | } | |
1655 | ||
1656 | /* | |
1657 | * Setting these two capabilities causes the "configuration" | |
1658 | * vmstate to include subsections for them. The script needs to | |
1659 | * parse those subsections properly. | |
1660 | */ | |
1661 | migrate_set_capability(from, "validate-uuid", true); | |
1662 | migrate_set_capability(from, "x-ignore-shared", true); | |
1663 | ||
1664 | file = g_strdup_printf("%s/migfile", tmpfs); | |
1665 | uri = g_strdup_printf("exec:cat > %s", file); | |
1666 | ||
1667 | migrate_ensure_converge(from); | |
1668 | migrate_qmp(from, uri, "{}"); | |
1669 | wait_for_migration_complete(from); | |
1670 | ||
1671 | pid = fork(); | |
1672 | if (!pid) { | |
1673 | close(1); | |
1674 | open("/dev/null", O_WRONLY); | |
1675 | execl(python, python, ANALYZE_SCRIPT, "-f", file, NULL); | |
1676 | g_assert_not_reached(); | |
1677 | } | |
1678 | ||
1679 | g_assert(waitpid(pid, &wstatus, 0) == pid); | |
1680 | if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) != 0) { | |
1681 | g_test_message("Failed to analyze the migration stream"); | |
1682 | g_test_fail(); | |
1683 | } | |
1684 | test_migrate_end(from, to, false); | |
1685 | cleanup("migfile"); | |
1686 | } | |
1687 | #endif | |
1688 | ||
ffed54f6 | 1689 | static void test_precopy_common(MigrateCommon *args) |
2884100c | 1690 | { |
2884100c | 1691 | QTestState *from, *to; |
b3caa7b5 | 1692 | void *data_hook = NULL; |
5274274c | 1693 | g_autofree char *connect_uri = NULL; |
2884100c | 1694 | |
ffed54f6 | 1695 | if (test_migrate_start(&from, &to, args->listen_uri, &args->start)) { |
5fd4a9c9 DDAG |
1696 | return; |
1697 | } | |
2884100c | 1698 | |
b3caa7b5 DB |
1699 | if (args->start_hook) { |
1700 | data_hook = args->start_hook(from, to); | |
1701 | } | |
1702 | ||
2884100c | 1703 | /* Wait for the first serial output from the source */ |
e25636a1 TH |
1704 | if (args->result == MIG_TEST_SUCCEED) { |
1705 | wait_for_serial("src_serial"); | |
1706 | } | |
2884100c | 1707 | |
3c4fb177 | 1708 | if (args->live) { |
3c4fb177 | 1709 | migrate_ensure_non_converge(from); |
e02f56e3 | 1710 | migrate_prepare_for_dirty_mem(from); |
3c4fb177 DB |
1711 | } else { |
1712 | /* | |
1713 | * Testing non-live migration, we allow it to run at | |
1714 | * full speed to ensure short test case duration. | |
1715 | * For tests expected to fail, we don't need to | |
1716 | * change anything. | |
1717 | */ | |
1718 | if (args->result == MIG_TEST_SUCCEED) { | |
1719 | qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}"); | |
1720 | if (!got_src_stop) { | |
1721 | qtest_qmp_eventwait(from, "STOP"); | |
1722 | } | |
1723 | migrate_ensure_converge(from); | |
1724 | } | |
1725 | } | |
1726 | ||
ffed54f6 | 1727 | if (!args->connect_uri) { |
5274274c | 1728 | connect_uri = migrate_get_socket_address(to, "socket-address"); |
ffed54f6 | 1729 | } else { |
5274274c | 1730 | connect_uri = g_strdup(args->connect_uri); |
ffed54f6 DB |
1731 | } |
1732 | ||
5274274c FR |
1733 | if (args->result == MIG_TEST_QMP_ERROR) { |
1734 | migrate_qmp_fail(from, connect_uri, "{}"); | |
1735 | goto finish; | |
1736 | } | |
1737 | ||
1738 | migrate_qmp(from, connect_uri, "{}"); | |
2884100c | 1739 | |
00fbe7f6 DB |
1740 | if (args->result != MIG_TEST_SUCCEED) { |
1741 | bool allow_active = args->result == MIG_TEST_FAIL; | |
1742 | wait_for_migration_fail(from, allow_active); | |
2884100c | 1743 | |
00fbe7f6 | 1744 | if (args->result == MIG_TEST_FAIL_DEST_QUIT_ERR) { |
1b0f1b14 | 1745 | qtest_set_expected_status(to, EXIT_FAILURE); |
00fbe7f6 DB |
1746 | } |
1747 | } else { | |
3c4fb177 | 1748 | if (args->live) { |
e02f56e3 DB |
1749 | /* |
1750 | * For initial iteration(s) we must do a full pass, | |
1751 | * but for the final iteration, we need only wait | |
1752 | * for some dirty mem before switching to converge | |
1753 | */ | |
1754 | while (args->iterations > 1) { | |
83bcba1e | 1755 | wait_for_migration_pass(from); |
e02f56e3 | 1756 | args->iterations--; |
83bcba1e | 1757 | } |
e02f56e3 | 1758 | migrate_wait_for_dirty_mem(from, to); |
2884100c | 1759 | |
3c4fb177 | 1760 | migrate_ensure_converge(from); |
2884100c | 1761 | |
3c4fb177 DB |
1762 | /* |
1763 | * We do this first, as it has a timeout to stop us | |
1764 | * hanging forever if migration didn't converge | |
1765 | */ | |
1766 | wait_for_migration_complete(from); | |
8d4e897a | 1767 | |
3c4fb177 DB |
1768 | if (!got_src_stop) { |
1769 | qtest_qmp_eventwait(from, "STOP"); | |
1770 | } | |
1771 | } else { | |
1772 | wait_for_migration_complete(from); | |
1773 | /* | |
1774 | * Must wait for dst to finish reading all incoming | |
1775 | * data on the socket before issuing 'cont' otherwise | |
1776 | * it'll be ignored | |
1777 | */ | |
1778 | wait_for_migration_complete(to); | |
1779 | ||
1780 | qtest_qmp_assert_success(to, "{ 'execute' : 'cont'}"); | |
00fbe7f6 | 1781 | } |
2884100c | 1782 | |
3c4fb177 DB |
1783 | if (!got_dst_resume) { |
1784 | qtest_qmp_eventwait(to, "RESUME"); | |
1785 | } | |
00fbe7f6 DB |
1786 | |
1787 | wait_for_serial("dest_serial"); | |
00fbe7f6 | 1788 | } |
2884100c | 1789 | |
5274274c | 1790 | finish: |
b3caa7b5 DB |
1791 | if (args->finish_hook) { |
1792 | args->finish_hook(from, to, data_hook); | |
1793 | } | |
1794 | ||
00fbe7f6 | 1795 | test_migrate_end(from, to, args->result == MIG_TEST_SUCCEED); |
2884100c JQ |
1796 | } |
1797 | ||
3dc35470 FR |
1798 | static void test_file_common(MigrateCommon *args, bool stop_src) |
1799 | { | |
1800 | QTestState *from, *to; | |
1801 | void *data_hook = NULL; | |
1802 | g_autofree char *connect_uri = g_strdup(args->connect_uri); | |
1803 | ||
1804 | if (test_migrate_start(&from, &to, args->listen_uri, &args->start)) { | |
1805 | return; | |
1806 | } | |
1807 | ||
1808 | /* | |
1809 | * File migration is never live. We can keep the source VM running | |
1810 | * during migration, but the destination will not be running | |
1811 | * concurrently. | |
1812 | */ | |
1813 | g_assert_false(args->live); | |
1814 | ||
1815 | if (args->start_hook) { | |
1816 | data_hook = args->start_hook(from, to); | |
1817 | } | |
1818 | ||
1819 | migrate_ensure_converge(from); | |
1820 | wait_for_serial("src_serial"); | |
1821 | ||
1822 | if (stop_src) { | |
1823 | qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}"); | |
1824 | if (!got_src_stop) { | |
1825 | qtest_qmp_eventwait(from, "STOP"); | |
1826 | } | |
1827 | } | |
1828 | ||
1829 | if (args->result == MIG_TEST_QMP_ERROR) { | |
1830 | migrate_qmp_fail(from, connect_uri, "{}"); | |
1831 | goto finish; | |
1832 | } | |
1833 | ||
1834 | migrate_qmp(from, connect_uri, "{}"); | |
1835 | wait_for_migration_complete(from); | |
1836 | ||
1837 | /* | |
1838 | * We need to wait for the source to finish before starting the | |
1839 | * destination. | |
1840 | */ | |
1841 | migrate_incoming_qmp(to, connect_uri, "{}"); | |
1842 | wait_for_migration_complete(to); | |
1843 | ||
1844 | if (stop_src) { | |
1845 | qtest_qmp_assert_success(to, "{ 'execute' : 'cont'}"); | |
1846 | } | |
1847 | ||
1848 | if (!got_dst_resume) { | |
1849 | qtest_qmp_eventwait(to, "RESUME"); | |
1850 | } | |
1851 | ||
1852 | wait_for_serial("dest_serial"); | |
1853 | ||
1854 | finish: | |
1855 | if (args->finish_hook) { | |
1856 | args->finish_hook(from, to, data_hook); | |
1857 | } | |
1858 | ||
1859 | test_migrate_end(from, to, args->result == MIG_TEST_SUCCEED); | |
1860 | } | |
1861 | ||
58d25e97 | 1862 | static void test_precopy_unix_plain(void) |
1f546b70 | 1863 | { |
ffed54f6 DB |
1864 | g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); |
1865 | MigrateCommon args = { | |
1866 | .listen_uri = uri, | |
1867 | .connect_uri = uri, | |
b861383c PX |
1868 | /* |
1869 | * The simplest use case of precopy, covering smoke tests of | |
1870 | * get-dirty-log dirty tracking. | |
1871 | */ | |
3c4fb177 | 1872 | .live = true, |
ffed54f6 DB |
1873 | }; |
1874 | ||
1875 | test_precopy_common(&args); | |
1f546b70 PX |
1876 | } |
1877 | ||
d47b83b1 DB |
1878 | |
1879 | static void test_precopy_unix_dirty_ring(void) | |
1880 | { | |
1881 | g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); | |
1882 | MigrateCommon args = { | |
1883 | .start = { | |
1884 | .use_dirty_ring = true, | |
1885 | }, | |
1886 | .listen_uri = uri, | |
1887 | .connect_uri = uri, | |
b861383c PX |
1888 | /* |
1889 | * Besides the precopy/unix basic test, cover dirty ring interface | |
1890 | * rather than get-dirty-log. | |
1891 | */ | |
3c4fb177 | 1892 | .live = true, |
d47b83b1 DB |
1893 | }; |
1894 | ||
1895 | test_precopy_common(&args); | |
1896 | } | |
1897 | ||
58d25e97 DB |
1898 | #ifdef CONFIG_GNUTLS |
1899 | static void test_precopy_unix_tls_psk(void) | |
1900 | { | |
1901 | g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); | |
1902 | MigrateCommon args = { | |
1903 | .connect_uri = uri, | |
1904 | .listen_uri = uri, | |
1905 | .start_hook = test_migrate_tls_psk_start_match, | |
1906 | .finish_hook = test_migrate_tls_psk_finish, | |
1907 | }; | |
1908 | ||
1909 | test_precopy_common(&args); | |
1910 | } | |
58d25e97 | 1911 | |
d47b83b1 DB |
1912 | #ifdef CONFIG_TASN1 |
1913 | static void test_precopy_unix_tls_x509_default_host(void) | |
1f546b70 | 1914 | { |
ffed54f6 DB |
1915 | g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); |
1916 | MigrateCommon args = { | |
1917 | .start = { | |
d47b83b1 | 1918 | .hide_stderr = true, |
ffed54f6 | 1919 | }, |
d47b83b1 | 1920 | .connect_uri = uri, |
ffed54f6 | 1921 | .listen_uri = uri, |
d47b83b1 DB |
1922 | .start_hook = test_migrate_tls_x509_start_default_host, |
1923 | .finish_hook = test_migrate_tls_x509_finish, | |
1924 | .result = MIG_TEST_FAIL_DEST_QUIT_ERR, | |
1925 | }; | |
1926 | ||
1927 | test_precopy_common(&args); | |
1928 | } | |
1929 | ||
1930 | static void test_precopy_unix_tls_x509_override_host(void) | |
1931 | { | |
1932 | g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); | |
1933 | MigrateCommon args = { | |
ffed54f6 | 1934 | .connect_uri = uri, |
d47b83b1 DB |
1935 | .listen_uri = uri, |
1936 | .start_hook = test_migrate_tls_x509_start_override_host, | |
1937 | .finish_hook = test_migrate_tls_x509_finish, | |
ffed54f6 DB |
1938 | }; |
1939 | ||
1940 | test_precopy_common(&args); | |
1f546b70 | 1941 | } |
d47b83b1 DB |
1942 | #endif /* CONFIG_TASN1 */ |
1943 | #endif /* CONFIG_GNUTLS */ | |
1f546b70 | 1944 | |
660a9b68 YK |
1945 | #if 0 |
1946 | /* Currently upset on aarch64 TCG */ | |
1947 | static void test_ignore_shared(void) | |
1948 | { | |
ff7b9b56 | 1949 | g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); |
660a9b68 YK |
1950 | QTestState *from, *to; |
1951 | ||
3af31a34 | 1952 | if (test_migrate_start(&from, &to, uri, false, true, NULL, NULL)) { |
660a9b68 YK |
1953 | return; |
1954 | } | |
1955 | ||
e02f56e3 DB |
1956 | migrate_ensure_non_converge(from); |
1957 | migrate_prepare_for_dirty_mem(from); | |
1958 | ||
660a9b68 YK |
1959 | migrate_set_capability(from, "x-ignore-shared", true); |
1960 | migrate_set_capability(to, "x-ignore-shared", true); | |
1961 | ||
1962 | /* Wait for the first serial output from the source */ | |
1963 | wait_for_serial("src_serial"); | |
1964 | ||
d77799cc | 1965 | migrate_qmp(from, uri, "{}"); |
660a9b68 | 1966 | |
e02f56e3 | 1967 | migrate_wait_for_dirty_mem(from, to); |
660a9b68 | 1968 | |
95014994 | 1969 | if (!got_src_stop) { |
660a9b68 YK |
1970 | qtest_qmp_eventwait(from, "STOP"); |
1971 | } | |
1972 | ||
1973 | qtest_qmp_eventwait(to, "RESUME"); | |
1974 | ||
1975 | wait_for_serial("dest_serial"); | |
1976 | wait_for_migration_complete(from); | |
1977 | ||
1978 | /* Check whether shared RAM has been really skipped */ | |
1979 | g_assert_cmpint(read_ram_property_int(from, "transferred"), <, 1024 * 1024); | |
1980 | ||
1981 | test_migrate_end(from, to, true); | |
660a9b68 YK |
1982 | } |
1983 | #endif | |
1984 | ||
83bcba1e DB |
1985 | static void * |
1986 | test_migrate_xbzrle_start(QTestState *from, | |
1987 | QTestState *to) | |
cdf84229 | 1988 | { |
8f7798f1 | 1989 | migrate_set_parameter_int(from, "xbzrle-cache-size", 33554432); |
cdf84229 | 1990 | |
a1209bb7 DDAG |
1991 | migrate_set_capability(from, "xbzrle", true); |
1992 | migrate_set_capability(to, "xbzrle", true); | |
cdf84229 | 1993 | |
83bcba1e | 1994 | return NULL; |
cdf84229 JQ |
1995 | } |
1996 | ||
83bcba1e | 1997 | static void test_precopy_unix_xbzrle(void) |
cdf84229 | 1998 | { |
ff7b9b56 | 1999 | g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); |
83bcba1e DB |
2000 | MigrateCommon args = { |
2001 | .connect_uri = uri, | |
2002 | .listen_uri = uri, | |
83bcba1e | 2003 | .start_hook = test_migrate_xbzrle_start, |
83bcba1e | 2004 | .iterations = 2, |
b861383c PX |
2005 | /* |
2006 | * XBZRLE needs pages to be modified when doing the 2nd+ round | |
2007 | * iteration to have real data pushed to the stream. | |
2008 | */ | |
3c4fb177 | 2009 | .live = true, |
83bcba1e DB |
2010 | }; |
2011 | ||
2012 | test_precopy_common(&args); | |
cdf84229 JQ |
2013 | } |
2014 | ||
1536d1da LS |
2015 | static void test_precopy_unix_compress(void) |
2016 | { | |
2017 | g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); | |
2018 | MigrateCommon args = { | |
2019 | .connect_uri = uri, | |
2020 | .listen_uri = uri, | |
2021 | .start_hook = test_migrate_compress_start, | |
2022 | /* | |
2023 | * Test that no invalid thread state is left over from | |
2024 | * the previous iteration. | |
2025 | */ | |
2026 | .iterations = 2, | |
b861383c PX |
2027 | /* |
2028 | * We make sure the compressor can always work well even if guest | |
2029 | * memory is changing. See commit 34ab9e9743 where we used to fix | |
2030 | * a bug when only trigger-able with guest memory changing. | |
2031 | */ | |
3c4fb177 | 2032 | .live = true, |
1536d1da LS |
2033 | }; |
2034 | ||
2035 | test_precopy_common(&args); | |
2036 | } | |
2037 | ||
1536d1da LS |
2038 | static void test_precopy_unix_compress_nowait(void) |
2039 | { | |
2040 | g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); | |
2041 | MigrateCommon args = { | |
2042 | .connect_uri = uri, | |
2043 | .listen_uri = uri, | |
2044 | .start_hook = test_migrate_compress_nowait_start, | |
2045 | /* | |
2046 | * Test that no invalid thread state is left over from | |
2047 | * the previous iteration. | |
2048 | */ | |
2049 | .iterations = 2, | |
b861383c | 2050 | /* Same reason for the wait version of precopy compress test */ |
3c4fb177 | 2051 | .live = true, |
1536d1da LS |
2052 | }; |
2053 | ||
2054 | test_precopy_common(&args); | |
2055 | } | |
2056 | ||
3dc35470 FR |
2057 | static void test_precopy_file(void) |
2058 | { | |
2059 | g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, | |
2060 | FILE_TEST_FILENAME); | |
2061 | MigrateCommon args = { | |
2062 | .connect_uri = uri, | |
2063 | .listen_uri = "defer", | |
2064 | }; | |
2065 | ||
2066 | test_file_common(&args, true); | |
2067 | } | |
2068 | ||
2069 | static void file_offset_finish_hook(QTestState *from, QTestState *to, | |
2070 | void *opaque) | |
2071 | { | |
2072 | #if defined(__linux__) | |
2073 | g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME); | |
2074 | size_t size = FILE_TEST_OFFSET + sizeof(QEMU_VM_FILE_MAGIC); | |
2075 | uintptr_t *addr, *p; | |
2076 | int fd; | |
2077 | ||
2078 | fd = open(path, O_RDONLY); | |
2079 | g_assert(fd != -1); | |
2080 | addr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); | |
2081 | g_assert(addr != MAP_FAILED); | |
2082 | ||
2083 | /* | |
2084 | * Ensure the skipped offset contains zeros and the migration | |
2085 | * stream starts at the right place. | |
2086 | */ | |
2087 | p = addr; | |
2088 | while (p < addr + FILE_TEST_OFFSET / sizeof(uintptr_t)) { | |
2089 | g_assert(*p == 0); | |
2090 | p++; | |
2091 | } | |
2092 | g_assert_cmpint(cpu_to_be64(*p) >> 32, ==, QEMU_VM_FILE_MAGIC); | |
2093 | ||
2094 | munmap(addr, size); | |
2095 | close(fd); | |
2096 | #endif | |
2097 | } | |
2098 | ||
2099 | static void test_precopy_file_offset(void) | |
2100 | { | |
2101 | g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=%d", tmpfs, | |
2102 | FILE_TEST_FILENAME, | |
2103 | FILE_TEST_OFFSET); | |
2104 | MigrateCommon args = { | |
2105 | .connect_uri = uri, | |
2106 | .listen_uri = "defer", | |
2107 | .finish_hook = file_offset_finish_hook, | |
2108 | }; | |
2109 | ||
2110 | test_file_common(&args, false); | |
2111 | } | |
2112 | ||
2113 | static void test_precopy_file_offset_bad(void) | |
2114 | { | |
2115 | /* using a value not supported by qemu_strtosz() */ | |
2116 | g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=0x20M", | |
2117 | tmpfs, FILE_TEST_FILENAME); | |
2118 | MigrateCommon args = { | |
2119 | .connect_uri = uri, | |
2120 | .listen_uri = "defer", | |
2121 | .result = MIG_TEST_QMP_ERROR, | |
2122 | }; | |
2123 | ||
2124 | test_file_common(&args, false); | |
2125 | } | |
2126 | ||
e7b428d6 SS |
2127 | static void *test_mode_reboot_start(QTestState *from, QTestState *to) |
2128 | { | |
2129 | migrate_set_parameter_str(from, "mode", "cpr-reboot"); | |
2130 | migrate_set_parameter_str(to, "mode", "cpr-reboot"); | |
2131 | ||
2132 | migrate_set_capability(from, "x-ignore-shared", true); | |
2133 | migrate_set_capability(to, "x-ignore-shared", true); | |
2134 | ||
2135 | return NULL; | |
2136 | } | |
2137 | ||
2138 | static void test_mode_reboot(void) | |
2139 | { | |
2140 | g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, | |
2141 | FILE_TEST_FILENAME); | |
2142 | MigrateCommon args = { | |
2143 | .start.use_shmem = true, | |
2144 | .connect_uri = uri, | |
2145 | .listen_uri = "defer", | |
2146 | .start_hook = test_mode_reboot_start | |
2147 | }; | |
2148 | ||
2149 | test_file_common(&args, true); | |
2150 | } | |
2151 | ||
58d25e97 | 2152 | static void test_precopy_tcp_plain(void) |
609d3844 | 2153 | { |
ffed54f6 DB |
2154 | MigrateCommon args = { |
2155 | .listen_uri = "tcp:127.0.0.1:0", | |
2156 | }; | |
609d3844 | 2157 | |
ffed54f6 | 2158 | test_precopy_common(&args); |
609d3844 JQ |
2159 | } |
2160 | ||
7e6a5c73 AH |
2161 | static void *test_migrate_switchover_ack_start(QTestState *from, QTestState *to) |
2162 | { | |
2163 | ||
2164 | migrate_set_capability(from, "return-path", true); | |
2165 | migrate_set_capability(to, "return-path", true); | |
2166 | ||
2167 | migrate_set_capability(from, "switchover-ack", true); | |
2168 | migrate_set_capability(to, "switchover-ack", true); | |
2169 | ||
2170 | return NULL; | |
2171 | } | |
2172 | ||
2173 | static void test_precopy_tcp_switchover_ack(void) | |
2174 | { | |
2175 | MigrateCommon args = { | |
2176 | .listen_uri = "tcp:127.0.0.1:0", | |
2177 | .start_hook = test_migrate_switchover_ack_start, | |
2178 | /* | |
2179 | * Source VM must be running in order to consider the switchover ACK | |
2180 | * when deciding to do switchover or not. | |
2181 | */ | |
2182 | .live = true, | |
2183 | }; | |
2184 | ||
2185 | test_precopy_common(&args); | |
2186 | } | |
2187 | ||
58d25e97 DB |
2188 | #ifdef CONFIG_GNUTLS |
2189 | static void test_precopy_tcp_tls_psk_match(void) | |
2190 | { | |
2191 | MigrateCommon args = { | |
2192 | .listen_uri = "tcp:127.0.0.1:0", | |
2193 | .start_hook = test_migrate_tls_psk_start_match, | |
2194 | .finish_hook = test_migrate_tls_psk_finish, | |
2195 | }; | |
2196 | ||
2197 | test_precopy_common(&args); | |
2198 | } | |
2199 | ||
2200 | static void test_precopy_tcp_tls_psk_mismatch(void) | |
2201 | { | |
2202 | MigrateCommon args = { | |
2203 | .start = { | |
2204 | .hide_stderr = true, | |
2205 | }, | |
2206 | .listen_uri = "tcp:127.0.0.1:0", | |
2207 | .start_hook = test_migrate_tls_psk_start_mismatch, | |
2208 | .finish_hook = test_migrate_tls_psk_finish, | |
2209 | .result = MIG_TEST_FAIL, | |
2210 | }; | |
2211 | ||
2212 | test_precopy_common(&args); | |
2213 | } | |
d47b83b1 DB |
2214 | |
2215 | #ifdef CONFIG_TASN1 | |
2216 | static void test_precopy_tcp_tls_x509_default_host(void) | |
2217 | { | |
2218 | MigrateCommon args = { | |
2219 | .listen_uri = "tcp:127.0.0.1:0", | |
2220 | .start_hook = test_migrate_tls_x509_start_default_host, | |
2221 | .finish_hook = test_migrate_tls_x509_finish, | |
2222 | }; | |
2223 | ||
2224 | test_precopy_common(&args); | |
2225 | } | |
2226 | ||
2227 | static void test_precopy_tcp_tls_x509_override_host(void) | |
2228 | { | |
2229 | MigrateCommon args = { | |
2230 | .listen_uri = "tcp:127.0.0.1:0", | |
2231 | .start_hook = test_migrate_tls_x509_start_override_host, | |
2232 | .finish_hook = test_migrate_tls_x509_finish, | |
2233 | }; | |
2234 | ||
2235 | test_precopy_common(&args); | |
2236 | } | |
2237 | ||
2238 | static void test_precopy_tcp_tls_x509_mismatch_host(void) | |
2239 | { | |
2240 | MigrateCommon args = { | |
2241 | .start = { | |
2242 | .hide_stderr = true, | |
2243 | }, | |
2244 | .listen_uri = "tcp:127.0.0.1:0", | |
2245 | .start_hook = test_migrate_tls_x509_start_mismatch_host, | |
2246 | .finish_hook = test_migrate_tls_x509_finish, | |
2247 | .result = MIG_TEST_FAIL_DEST_QUIT_ERR, | |
2248 | }; | |
2249 | ||
2250 | test_precopy_common(&args); | |
2251 | } | |
2252 | ||
2253 | static void test_precopy_tcp_tls_x509_friendly_client(void) | |
2254 | { | |
2255 | MigrateCommon args = { | |
2256 | .listen_uri = "tcp:127.0.0.1:0", | |
2257 | .start_hook = test_migrate_tls_x509_start_friendly_client, | |
2258 | .finish_hook = test_migrate_tls_x509_finish, | |
2259 | }; | |
2260 | ||
2261 | test_precopy_common(&args); | |
2262 | } | |
2263 | ||
2264 | static void test_precopy_tcp_tls_x509_hostile_client(void) | |
2265 | { | |
2266 | MigrateCommon args = { | |
2267 | .start = { | |
2268 | .hide_stderr = true, | |
2269 | }, | |
2270 | .listen_uri = "tcp:127.0.0.1:0", | |
2271 | .start_hook = test_migrate_tls_x509_start_hostile_client, | |
2272 | .finish_hook = test_migrate_tls_x509_finish, | |
2273 | .result = MIG_TEST_FAIL, | |
2274 | }; | |
2275 | ||
2276 | test_precopy_common(&args); | |
2277 | } | |
2278 | ||
2279 | static void test_precopy_tcp_tls_x509_allow_anon_client(void) | |
2280 | { | |
2281 | MigrateCommon args = { | |
2282 | .listen_uri = "tcp:127.0.0.1:0", | |
2283 | .start_hook = test_migrate_tls_x509_start_allow_anon_client, | |
2284 | .finish_hook = test_migrate_tls_x509_finish, | |
2285 | }; | |
2286 | ||
2287 | test_precopy_common(&args); | |
2288 | } | |
2289 | ||
2290 | static void test_precopy_tcp_tls_x509_reject_anon_client(void) | |
2291 | { | |
2292 | MigrateCommon args = { | |
2293 | .start = { | |
2294 | .hide_stderr = true, | |
2295 | }, | |
2296 | .listen_uri = "tcp:127.0.0.1:0", | |
2297 | .start_hook = test_migrate_tls_x509_start_reject_anon_client, | |
2298 | .finish_hook = test_migrate_tls_x509_finish, | |
2299 | .result = MIG_TEST_FAIL, | |
2300 | }; | |
2301 | ||
2302 | test_precopy_common(&args); | |
2303 | } | |
2304 | #endif /* CONFIG_TASN1 */ | |
58d25e97 DB |
2305 | #endif /* CONFIG_GNUTLS */ |
2306 | ||
d7613ee2 | 2307 | #ifndef _WIN32 |
243e0066 DB |
2308 | static void *test_migrate_fd_start_hook(QTestState *from, |
2309 | QTestState *to) | |
24d5588c | 2310 | { |
24d5588c YK |
2311 | int ret; |
2312 | int pair[2]; | |
24d5588c YK |
2313 | |
2314 | /* Create two connected sockets for migration */ | |
0038e9a2 | 2315 | ret = qemu_socketpair(PF_LOCAL, SOCK_STREAM, 0, pair); |
24d5588c YK |
2316 | g_assert_cmpint(ret, ==, 0); |
2317 | ||
2318 | /* Send the 1st socket to the target */ | |
aca04069 DB |
2319 | qtest_qmp_fds_assert_success(to, &pair[0], 1, |
2320 | "{ 'execute': 'getfd'," | |
2321 | " 'arguments': { 'fdname': 'fd-mig' }}"); | |
24d5588c YK |
2322 | close(pair[0]); |
2323 | ||
2324 | /* Start incoming migration from the 1st socket */ | |
6830e53b | 2325 | migrate_incoming_qmp(to, "fd:fd-mig", "{}"); |
24d5588c YK |
2326 | |
2327 | /* Send the 2nd socket to the target */ | |
aca04069 DB |
2328 | qtest_qmp_fds_assert_success(from, &pair[1], 1, |
2329 | "{ 'execute': 'getfd'," | |
2330 | " 'arguments': { 'fdname': 'fd-mig' }}"); | |
24d5588c YK |
2331 | close(pair[1]); |
2332 | ||
243e0066 DB |
2333 | return NULL; |
2334 | } | |
24d5588c | 2335 | |
243e0066 DB |
2336 | static void test_migrate_fd_finish_hook(QTestState *from, |
2337 | QTestState *to, | |
2338 | void *opaque) | |
2339 | { | |
2340 | QDict *rsp; | |
2341 | const char *error_desc; | |
24d5588c YK |
2342 | |
2343 | /* Test closing fds */ | |
2344 | /* We assume, that QEMU removes named fd from its list, | |
2345 | * so this should fail */ | |
2346 | rsp = qtest_qmp(from, "{ 'execute': 'closefd'," | |
2347 | " 'arguments': { 'fdname': 'fd-mig' }}"); | |
2348 | g_assert_true(qdict_haskey(rsp, "error")); | |
2349 | error_desc = qdict_get_str(qdict_get_qdict(rsp, "error"), "desc"); | |
2350 | g_assert_cmpstr(error_desc, ==, "File descriptor named 'fd-mig' not found"); | |
2351 | qobject_unref(rsp); | |
2352 | ||
2353 | rsp = qtest_qmp(to, "{ 'execute': 'closefd'," | |
2354 | " 'arguments': { 'fdname': 'fd-mig' }}"); | |
2355 | g_assert_true(qdict_haskey(rsp, "error")); | |
2356 | error_desc = qdict_get_str(qdict_get_qdict(rsp, "error"), "desc"); | |
2357 | g_assert_cmpstr(error_desc, ==, "File descriptor named 'fd-mig' not found"); | |
2358 | qobject_unref(rsp); | |
243e0066 | 2359 | } |
24d5588c | 2360 | |
243e0066 DB |
2361 | static void test_migrate_fd_proto(void) |
2362 | { | |
2363 | MigrateCommon args = { | |
2364 | .listen_uri = "defer", | |
2365 | .connect_uri = "fd:fd-mig", | |
2366 | .start_hook = test_migrate_fd_start_hook, | |
2367 | .finish_hook = test_migrate_fd_finish_hook | |
2368 | }; | |
2369 | test_precopy_common(&args); | |
24d5588c | 2370 | } |
d7613ee2 | 2371 | #endif /* _WIN32 */ |
24d5588c | 2372 | |
5d3b575d | 2373 | static void do_test_validate_uuid(MigrateStart *args, bool should_fail) |
3af31a34 | 2374 | { |
ff7b9b56 | 2375 | g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); |
3af31a34 YK |
2376 | QTestState *from, *to; |
2377 | ||
19da6edf | 2378 | if (test_migrate_start(&from, &to, uri, args)) { |
3af31a34 YK |
2379 | return; |
2380 | } | |
2381 | ||
2382 | /* | |
2383 | * UUID validation is at the begin of migration. So, the main process of | |
2384 | * migration is not interesting for us here. Thus, set huge downtime for | |
2385 | * very fast migration. | |
2386 | */ | |
2387 | migrate_set_parameter_int(from, "downtime-limit", 1000000); | |
2388 | migrate_set_capability(from, "validate-uuid", true); | |
2389 | ||
2390 | /* Wait for the first serial output from the source */ | |
2391 | wait_for_serial("src_serial"); | |
2392 | ||
d77799cc | 2393 | migrate_qmp(from, uri, "{}"); |
3af31a34 YK |
2394 | |
2395 | if (should_fail) { | |
1b0f1b14 | 2396 | qtest_set_expected_status(to, EXIT_FAILURE); |
3af31a34 YK |
2397 | wait_for_migration_fail(from, true); |
2398 | } else { | |
2399 | wait_for_migration_complete(from); | |
2400 | } | |
2401 | ||
2402 | test_migrate_end(from, to, false); | |
3af31a34 YK |
2403 | } |
2404 | ||
2405 | static void test_validate_uuid(void) | |
2406 | { | |
19da6edf DB |
2407 | MigrateStart args = { |
2408 | .opts_source = "-uuid 11111111-1111-1111-1111-111111111111", | |
2409 | .opts_target = "-uuid 11111111-1111-1111-1111-111111111111", | |
2410 | }; | |
5d3b575d | 2411 | |
19da6edf | 2412 | do_test_validate_uuid(&args, false); |
3af31a34 YK |
2413 | } |
2414 | ||
2415 | static void test_validate_uuid_error(void) | |
2416 | { | |
19da6edf DB |
2417 | MigrateStart args = { |
2418 | .opts_source = "-uuid 11111111-1111-1111-1111-111111111111", | |
2419 | .opts_target = "-uuid 22222222-2222-2222-2222-222222222222", | |
2420 | .hide_stderr = true, | |
2421 | }; | |
2422 | ||
2423 | do_test_validate_uuid(&args, true); | |
3af31a34 YK |
2424 | } |
2425 | ||
2426 | static void test_validate_uuid_src_not_set(void) | |
2427 | { | |
19da6edf DB |
2428 | MigrateStart args = { |
2429 | .opts_target = "-uuid 22222222-2222-2222-2222-222222222222", | |
2430 | .hide_stderr = true, | |
2431 | }; | |
5d3b575d | 2432 | |
19da6edf | 2433 | do_test_validate_uuid(&args, false); |
3af31a34 YK |
2434 | } |
2435 | ||
2436 | static void test_validate_uuid_dst_not_set(void) | |
2437 | { | |
19da6edf DB |
2438 | MigrateStart args = { |
2439 | .opts_source = "-uuid 11111111-1111-1111-1111-111111111111", | |
2440 | .hide_stderr = true, | |
2441 | }; | |
5d3b575d | 2442 | |
19da6edf | 2443 | do_test_validate_uuid(&args, false); |
3af31a34 YK |
2444 | } |
2445 | ||
74902af7 JQ |
2446 | /* |
2447 | * The way auto_converge works, we need to do too many passes to | |
2448 | * run this test. Auto_converge logic is only run once every | |
2449 | * three iterations, so: | |
2450 | * | |
2451 | * - 3 iterations without auto_converge enabled | |
2452 | * - 3 iterations with pct = 5 | |
2453 | * - 3 iterations with pct = 30 | |
2454 | * - 3 iterations with pct = 55 | |
2455 | * - 3 iterations with pct = 80 | |
2456 | * - 3 iterations with pct = 95 (max(95, 80 + 25)) | |
2457 | * | |
2458 | * To make things even worse, we need to run the initial stage at | |
2459 | * 3MB/s so we enter autoconverge even when host is (over)loaded. | |
2460 | */ | |
8c51642b YK |
2461 | static void test_migrate_auto_converge(void) |
2462 | { | |
ff7b9b56 | 2463 | g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); |
19da6edf | 2464 | MigrateStart args = {}; |
8c51642b | 2465 | QTestState *from, *to; |
219044b8 | 2466 | int64_t percentage; |
8c51642b YK |
2467 | |
2468 | /* | |
2469 | * We want the test to be stable and as fast as possible. | |
96420a30 | 2470 | * E.g., with 1Gb/s bandwidth migration may pass without throttling, |
8c51642b YK |
2471 | * so we need to decrease a bandwidth. |
2472 | */ | |
1bfc8dde | 2473 | const int64_t init_pct = 5, inc_pct = 25, max_pct = 95; |
8c51642b | 2474 | |
3ff57401 | 2475 | if (test_migrate_start(&from, &to, uri, &args)) { |
8c51642b YK |
2476 | return; |
2477 | } | |
2478 | ||
2479 | migrate_set_capability(from, "auto-converge", true); | |
2480 | migrate_set_parameter_int(from, "cpu-throttle-initial", init_pct); | |
2481 | migrate_set_parameter_int(from, "cpu-throttle-increment", inc_pct); | |
2482 | migrate_set_parameter_int(from, "max-cpu-throttle", max_pct); | |
2483 | ||
2484 | /* | |
2485 | * Set the initial parameters so that the migration could not converge | |
2486 | * without throttling. | |
2487 | */ | |
886dfe9d | 2488 | migrate_ensure_non_converge(from); |
8c51642b YK |
2489 | |
2490 | /* To check remaining size after precopy */ | |
2491 | migrate_set_capability(from, "pause-before-switchover", true); | |
2492 | ||
2493 | /* Wait for the first serial output from the source */ | |
2494 | wait_for_serial("src_serial"); | |
2495 | ||
d77799cc | 2496 | migrate_qmp(from, uri, "{}"); |
8c51642b YK |
2497 | |
2498 | /* Wait for throttling begins */ | |
2499 | percentage = 0; | |
1bfc8dde | 2500 | do { |
8c51642b | 2501 | percentage = read_migrate_property_int(from, "cpu-throttle-percentage"); |
1bfc8dde DDAG |
2502 | if (percentage != 0) { |
2503 | break; | |
2504 | } | |
2505 | usleep(20); | |
95014994 | 2506 | g_assert_false(got_src_stop); |
1bfc8dde DDAG |
2507 | } while (true); |
2508 | /* The first percentage of throttling should be at least init_pct */ | |
2509 | g_assert_cmpint(percentage, >=, init_pct); | |
8c51642b | 2510 | /* Now, when we tested that throttling works, let it converge */ |
219044b8 | 2511 | migrate_ensure_converge(from); |
8c51642b YK |
2512 | |
2513 | /* | |
2514 | * Wait for pre-switchover status to check last throttle percentage | |
2515 | * and remaining. These values will be zeroed later | |
2516 | */ | |
2517 | wait_for_migration_status(from, "pre-switchover", NULL); | |
2518 | ||
2519 | /* The final percentage of throttling shouldn't be greater than max_pct */ | |
2520 | percentage = read_migrate_property_int(from, "cpu-throttle-percentage"); | |
2521 | g_assert_cmpint(percentage, <=, max_pct); | |
8c51642b YK |
2522 | migrate_continue(from, "pre-switchover"); |
2523 | ||
2524 | qtest_qmp_eventwait(to, "RESUME"); | |
2525 | ||
2526 | wait_for_serial("dest_serial"); | |
2527 | wait_for_migration_complete(from); | |
2528 | ||
8c51642b YK |
2529 | test_migrate_end(from, to, true); |
2530 | } | |
2531 | ||
490facff DB |
2532 | static void * |
2533 | test_migrate_precopy_tcp_multifd_start_common(QTestState *from, | |
2534 | QTestState *to, | |
2535 | const char *method) | |
b99784ef | 2536 | { |
b99784ef JQ |
2537 | migrate_set_parameter_int(from, "multifd-channels", 16); |
2538 | migrate_set_parameter_int(to, "multifd-channels", 16); | |
2539 | ||
96eef042 JQ |
2540 | migrate_set_parameter_str(from, "multifd-compression", method); |
2541 | migrate_set_parameter_str(to, "multifd-compression", method); | |
2542 | ||
a1209bb7 DDAG |
2543 | migrate_set_capability(from, "multifd", true); |
2544 | migrate_set_capability(to, "multifd", true); | |
b99784ef JQ |
2545 | |
2546 | /* Start incoming migration from the 1st socket */ | |
6830e53b | 2547 | migrate_incoming_qmp(to, "tcp:127.0.0.1:0", "{}"); |
b99784ef | 2548 | |
490facff DB |
2549 | return NULL; |
2550 | } | |
b99784ef | 2551 | |
490facff DB |
2552 | static void * |
2553 | test_migrate_precopy_tcp_multifd_start(QTestState *from, | |
2554 | QTestState *to) | |
2555 | { | |
2556 | return test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); | |
2557 | } | |
b99784ef | 2558 | |
490facff DB |
2559 | static void * |
2560 | test_migrate_precopy_tcp_multifd_zlib_start(QTestState *from, | |
2561 | QTestState *to) | |
2562 | { | |
2563 | return test_migrate_precopy_tcp_multifd_start_common(from, to, "zlib"); | |
2564 | } | |
b99784ef | 2565 | |
490facff DB |
2566 | #ifdef CONFIG_ZSTD |
2567 | static void * | |
2568 | test_migrate_precopy_tcp_multifd_zstd_start(QTestState *from, | |
2569 | QTestState *to) | |
2570 | { | |
2571 | return test_migrate_precopy_tcp_multifd_start_common(from, to, "zstd"); | |
b99784ef | 2572 | } |
490facff | 2573 | #endif /* CONFIG_ZSTD */ |
b99784ef | 2574 | |
96eef042 JQ |
2575 | static void test_multifd_tcp_none(void) |
2576 | { | |
490facff DB |
2577 | MigrateCommon args = { |
2578 | .listen_uri = "defer", | |
2579 | .start_hook = test_migrate_precopy_tcp_multifd_start, | |
b861383c PX |
2580 | /* |
2581 | * Multifd is more complicated than most of the features, it | |
2582 | * directly takes guest page buffers when sending, make sure | |
2583 | * everything will work alright even if guest page is changing. | |
2584 | */ | |
3c4fb177 | 2585 | .live = true, |
490facff DB |
2586 | }; |
2587 | test_precopy_common(&args); | |
96eef042 JQ |
2588 | } |
2589 | ||
7ec2c2b3 JQ |
2590 | static void test_multifd_tcp_zlib(void) |
2591 | { | |
490facff DB |
2592 | MigrateCommon args = { |
2593 | .listen_uri = "defer", | |
2594 | .start_hook = test_migrate_precopy_tcp_multifd_zlib_start, | |
2595 | }; | |
2596 | test_precopy_common(&args); | |
7ec2c2b3 JQ |
2597 | } |
2598 | ||
87dc6f5f JQ |
2599 | #ifdef CONFIG_ZSTD |
2600 | static void test_multifd_tcp_zstd(void) | |
2601 | { | |
490facff DB |
2602 | MigrateCommon args = { |
2603 | .listen_uri = "defer", | |
2604 | .start_hook = test_migrate_precopy_tcp_multifd_zstd_start, | |
2605 | }; | |
2606 | test_precopy_common(&args); | |
87dc6f5f JQ |
2607 | } |
2608 | #endif | |
2609 | ||
4d6d2e87 DB |
2610 | #ifdef CONFIG_GNUTLS |
2611 | static void * | |
2612 | test_migrate_multifd_tcp_tls_psk_start_match(QTestState *from, | |
2613 | QTestState *to) | |
2614 | { | |
2615 | test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); | |
2616 | return test_migrate_tls_psk_start_match(from, to); | |
2617 | } | |
2618 | ||
2619 | static void * | |
2620 | test_migrate_multifd_tcp_tls_psk_start_mismatch(QTestState *from, | |
2621 | QTestState *to) | |
2622 | { | |
2623 | test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); | |
2624 | return test_migrate_tls_psk_start_mismatch(from, to); | |
2625 | } | |
2626 | ||
ff32f1dd DB |
2627 | #ifdef CONFIG_TASN1 |
2628 | static void * | |
2629 | test_migrate_multifd_tls_x509_start_default_host(QTestState *from, | |
2630 | QTestState *to) | |
2631 | { | |
2632 | test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); | |
2633 | return test_migrate_tls_x509_start_default_host(from, to); | |
2634 | } | |
2635 | ||
2636 | static void * | |
2637 | test_migrate_multifd_tls_x509_start_override_host(QTestState *from, | |
2638 | QTestState *to) | |
2639 | { | |
2640 | test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); | |
2641 | return test_migrate_tls_x509_start_override_host(from, to); | |
2642 | } | |
2643 | ||
2644 | static void * | |
2645 | test_migrate_multifd_tls_x509_start_mismatch_host(QTestState *from, | |
2646 | QTestState *to) | |
2647 | { | |
2648 | test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); | |
2649 | return test_migrate_tls_x509_start_mismatch_host(from, to); | |
2650 | } | |
2651 | ||
2652 | static void * | |
2653 | test_migrate_multifd_tls_x509_start_allow_anon_client(QTestState *from, | |
2654 | QTestState *to) | |
2655 | { | |
2656 | test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); | |
2657 | return test_migrate_tls_x509_start_allow_anon_client(from, to); | |
2658 | } | |
2659 | ||
2660 | static void * | |
2661 | test_migrate_multifd_tls_x509_start_reject_anon_client(QTestState *from, | |
2662 | QTestState *to) | |
2663 | { | |
2664 | test_migrate_precopy_tcp_multifd_start_common(from, to, "none"); | |
2665 | return test_migrate_tls_x509_start_reject_anon_client(from, to); | |
2666 | } | |
2667 | #endif /* CONFIG_TASN1 */ | |
2668 | ||
4d6d2e87 DB |
2669 | static void test_multifd_tcp_tls_psk_match(void) |
2670 | { | |
2671 | MigrateCommon args = { | |
2672 | .listen_uri = "defer", | |
2673 | .start_hook = test_migrate_multifd_tcp_tls_psk_start_match, | |
2674 | .finish_hook = test_migrate_tls_psk_finish, | |
2675 | }; | |
2676 | test_precopy_common(&args); | |
2677 | } | |
2678 | ||
2679 | static void test_multifd_tcp_tls_psk_mismatch(void) | |
2680 | { | |
2681 | MigrateCommon args = { | |
2682 | .start = { | |
2683 | .hide_stderr = true, | |
2684 | }, | |
2685 | .listen_uri = "defer", | |
2686 | .start_hook = test_migrate_multifd_tcp_tls_psk_start_mismatch, | |
2687 | .finish_hook = test_migrate_tls_psk_finish, | |
2688 | .result = MIG_TEST_FAIL, | |
2689 | }; | |
2690 | test_precopy_common(&args); | |
2691 | } | |
ff32f1dd DB |
2692 | |
2693 | #ifdef CONFIG_TASN1 | |
2694 | static void test_multifd_tcp_tls_x509_default_host(void) | |
2695 | { | |
2696 | MigrateCommon args = { | |
2697 | .listen_uri = "defer", | |
2698 | .start_hook = test_migrate_multifd_tls_x509_start_default_host, | |
2699 | .finish_hook = test_migrate_tls_x509_finish, | |
2700 | }; | |
2701 | test_precopy_common(&args); | |
2702 | } | |
2703 | ||
2704 | static void test_multifd_tcp_tls_x509_override_host(void) | |
2705 | { | |
2706 | MigrateCommon args = { | |
2707 | .listen_uri = "defer", | |
2708 | .start_hook = test_migrate_multifd_tls_x509_start_override_host, | |
2709 | .finish_hook = test_migrate_tls_x509_finish, | |
2710 | }; | |
2711 | test_precopy_common(&args); | |
2712 | } | |
2713 | ||
2714 | static void test_multifd_tcp_tls_x509_mismatch_host(void) | |
2715 | { | |
2716 | /* | |
2717 | * This has different behaviour to the non-multifd case. | |
2718 | * | |
2719 | * In non-multifd case when client aborts due to mismatched | |
2720 | * cert host, the server has already started trying to load | |
2721 | * migration state, and so it exits with I/O failure. | |
2722 | * | |
2723 | * In multifd case when client aborts due to mismatched | |
2724 | * cert host, the server is still waiting for the other | |
2725 | * multifd connections to arrive so hasn't started trying | |
2726 | * to load migration state, and thus just aborts the migration | |
2727 | * without exiting. | |
2728 | */ | |
2729 | MigrateCommon args = { | |
2730 | .start = { | |
2731 | .hide_stderr = true, | |
2732 | }, | |
2733 | .listen_uri = "defer", | |
2734 | .start_hook = test_migrate_multifd_tls_x509_start_mismatch_host, | |
2735 | .finish_hook = test_migrate_tls_x509_finish, | |
2736 | .result = MIG_TEST_FAIL, | |
2737 | }; | |
2738 | test_precopy_common(&args); | |
2739 | } | |
2740 | ||
2741 | static void test_multifd_tcp_tls_x509_allow_anon_client(void) | |
2742 | { | |
2743 | MigrateCommon args = { | |
2744 | .listen_uri = "defer", | |
2745 | .start_hook = test_migrate_multifd_tls_x509_start_allow_anon_client, | |
2746 | .finish_hook = test_migrate_tls_x509_finish, | |
2747 | }; | |
2748 | test_precopy_common(&args); | |
2749 | } | |
2750 | ||
2751 | static void test_multifd_tcp_tls_x509_reject_anon_client(void) | |
2752 | { | |
2753 | MigrateCommon args = { | |
2754 | .start = { | |
2755 | .hide_stderr = true, | |
2756 | }, | |
2757 | .listen_uri = "defer", | |
2758 | .start_hook = test_migrate_multifd_tls_x509_start_reject_anon_client, | |
2759 | .finish_hook = test_migrate_tls_x509_finish, | |
2760 | .result = MIG_TEST_FAIL, | |
2761 | }; | |
2762 | test_precopy_common(&args); | |
2763 | } | |
2764 | #endif /* CONFIG_TASN1 */ | |
4d6d2e87 DB |
2765 | #endif /* CONFIG_GNUTLS */ |
2766 | ||
d795f474 JQ |
2767 | /* |
2768 | * This test does: | |
2769 | * source target | |
2770 | * migrate_incoming | |
2771 | * migrate | |
2772 | * migrate_cancel | |
2773 | * launch another target | |
2774 | * migrate | |
2775 | * | |
2776 | * And see that it works | |
2777 | */ | |
d795f474 JQ |
2778 | static void test_multifd_tcp_cancel(void) |
2779 | { | |
19da6edf DB |
2780 | MigrateStart args = { |
2781 | .hide_stderr = true, | |
2782 | }; | |
d795f474 | 2783 | QTestState *from, *to, *to2; |
ff7b9b56 | 2784 | g_autofree char *uri = NULL; |
d795f474 | 2785 | |
3ff57401 | 2786 | if (test_migrate_start(&from, &to, "defer", &args)) { |
d795f474 JQ |
2787 | return; |
2788 | } | |
2789 | ||
886dfe9d | 2790 | migrate_ensure_non_converge(from); |
e02f56e3 | 2791 | migrate_prepare_for_dirty_mem(from); |
d795f474 JQ |
2792 | |
2793 | migrate_set_parameter_int(from, "multifd-channels", 16); | |
2794 | migrate_set_parameter_int(to, "multifd-channels", 16); | |
2795 | ||
a1209bb7 DDAG |
2796 | migrate_set_capability(from, "multifd", true); |
2797 | migrate_set_capability(to, "multifd", true); | |
d795f474 JQ |
2798 | |
2799 | /* Start incoming migration from the 1st socket */ | |
6830e53b | 2800 | migrate_incoming_qmp(to, "tcp:127.0.0.1:0", "{}"); |
d795f474 JQ |
2801 | |
2802 | /* Wait for the first serial output from the source */ | |
2803 | wait_for_serial("src_serial"); | |
2804 | ||
2805 | uri = migrate_get_socket_address(to, "socket-address"); | |
2806 | ||
2807 | migrate_qmp(from, uri, "{}"); | |
2808 | ||
e02f56e3 | 2809 | migrate_wait_for_dirty_mem(from, to); |
d795f474 JQ |
2810 | |
2811 | migrate_cancel(from); | |
2812 | ||
f2d063e6 XC |
2813 | /* Make sure QEMU process "to" exited */ |
2814 | qtest_set_expected_status(to, EXIT_FAILURE); | |
2815 | qtest_wait_qemu(to); | |
2816 | ||
19da6edf DB |
2817 | args = (MigrateStart){ |
2818 | .only_target = true, | |
2819 | }; | |
d795f474 | 2820 | |
3ff57401 | 2821 | if (test_migrate_start(&from, &to2, "defer", &args)) { |
d795f474 JQ |
2822 | return; |
2823 | } | |
2824 | ||
2825 | migrate_set_parameter_int(to2, "multifd-channels", 16); | |
2826 | ||
a1209bb7 | 2827 | migrate_set_capability(to2, "multifd", true); |
d795f474 JQ |
2828 | |
2829 | /* Start incoming migration from the 1st socket */ | |
6830e53b | 2830 | migrate_incoming_qmp(to2, "tcp:127.0.0.1:0", "{}"); |
d795f474 | 2831 | |
e022d473 | 2832 | g_free(uri); |
d795f474 JQ |
2833 | uri = migrate_get_socket_address(to2, "socket-address"); |
2834 | ||
2835 | wait_for_migration_status(from, "cancelled", NULL); | |
2836 | ||
e02f56e3 | 2837 | migrate_ensure_non_converge(from); |
d795f474 JQ |
2838 | |
2839 | migrate_qmp(from, uri, "{}"); | |
2840 | ||
94aaf6d8 | 2841 | migrate_wait_for_dirty_mem(from, to2); |
e02f56e3 DB |
2842 | |
2843 | migrate_ensure_converge(from); | |
d795f474 | 2844 | |
95014994 | 2845 | if (!got_src_stop) { |
d795f474 JQ |
2846 | qtest_qmp_eventwait(from, "STOP"); |
2847 | } | |
2848 | qtest_qmp_eventwait(to2, "RESUME"); | |
2849 | ||
2850 | wait_for_serial("dest_serial"); | |
2851 | wait_for_migration_complete(from); | |
2852 | test_migrate_end(from, to2, true); | |
d795f474 JQ |
2853 | } |
2854 | ||
8aff6f50 HH |
2855 | static void calc_dirty_rate(QTestState *who, uint64_t calc_time) |
2856 | { | |
ffd47275 DB |
2857 | qtest_qmp_assert_success(who, |
2858 | "{ 'execute': 'calc-dirty-rate'," | |
2859 | "'arguments': { " | |
2860 | "'calc-time': %" PRIu64 "," | |
2861 | "'mode': 'dirty-ring' }}", | |
2862 | calc_time); | |
8aff6f50 HH |
2863 | } |
2864 | ||
2865 | static QDict *query_dirty_rate(QTestState *who) | |
2866 | { | |
ffd47275 DB |
2867 | return qtest_qmp_assert_success_ref(who, |
2868 | "{ 'execute': 'query-dirty-rate' }"); | |
8aff6f50 HH |
2869 | } |
2870 | ||
2871 | static void dirtylimit_set_all(QTestState *who, uint64_t dirtyrate) | |
2872 | { | |
ffd47275 DB |
2873 | qtest_qmp_assert_success(who, |
2874 | "{ 'execute': 'set-vcpu-dirty-limit'," | |
2875 | "'arguments': { " | |
2876 | "'dirty-rate': %" PRIu64 " } }", | |
2877 | dirtyrate); | |
8aff6f50 HH |
2878 | } |
2879 | ||
2880 | static void cancel_vcpu_dirty_limit(QTestState *who) | |
2881 | { | |
ffd47275 DB |
2882 | qtest_qmp_assert_success(who, |
2883 | "{ 'execute': 'cancel-vcpu-dirty-limit' }"); | |
8aff6f50 HH |
2884 | } |
2885 | ||
2886 | static QDict *query_vcpu_dirty_limit(QTestState *who) | |
2887 | { | |
2888 | QDict *rsp; | |
2889 | ||
2890 | rsp = qtest_qmp(who, "{ 'execute': 'query-vcpu-dirty-limit' }"); | |
2891 | g_assert(!qdict_haskey(rsp, "error")); | |
2892 | g_assert(qdict_haskey(rsp, "return")); | |
2893 | ||
2894 | return rsp; | |
2895 | } | |
2896 | ||
2897 | static bool calc_dirtyrate_ready(QTestState *who) | |
2898 | { | |
2899 | QDict *rsp_return; | |
2900 | gchar *status; | |
2901 | ||
2902 | rsp_return = query_dirty_rate(who); | |
2903 | g_assert(rsp_return); | |
2904 | ||
2905 | status = g_strdup(qdict_get_str(rsp_return, "status")); | |
2906 | g_assert(status); | |
2907 | ||
2908 | return g_strcmp0(status, "measuring"); | |
2909 | } | |
2910 | ||
2911 | static void wait_for_calc_dirtyrate_complete(QTestState *who, | |
2912 | int64_t time_s) | |
2913 | { | |
2914 | int max_try_count = 10000; | |
2915 | usleep(time_s * 1000000); | |
2916 | ||
2917 | while (!calc_dirtyrate_ready(who) && max_try_count--) { | |
2918 | usleep(1000); | |
2919 | } | |
2920 | ||
2921 | /* | |
2922 | * Set the timeout with 10 s(max_try_count * 1000us), | |
2923 | * if dirtyrate measurement not complete, fail test. | |
2924 | */ | |
2925 | g_assert_cmpint(max_try_count, !=, 0); | |
2926 | } | |
2927 | ||
2928 | static int64_t get_dirty_rate(QTestState *who) | |
2929 | { | |
2930 | QDict *rsp_return; | |
2931 | gchar *status; | |
2932 | QList *rates; | |
2933 | const QListEntry *entry; | |
2934 | QDict *rate; | |
2935 | int64_t dirtyrate; | |
2936 | ||
2937 | rsp_return = query_dirty_rate(who); | |
2938 | g_assert(rsp_return); | |
2939 | ||
2940 | status = g_strdup(qdict_get_str(rsp_return, "status")); | |
2941 | g_assert(status); | |
2942 | g_assert_cmpstr(status, ==, "measured"); | |
2943 | ||
2944 | rates = qdict_get_qlist(rsp_return, "vcpu-dirty-rate"); | |
2945 | g_assert(rates && !qlist_empty(rates)); | |
2946 | ||
2947 | entry = qlist_first(rates); | |
2948 | g_assert(entry); | |
2949 | ||
2950 | rate = qobject_to(QDict, qlist_entry_obj(entry)); | |
2951 | g_assert(rate); | |
2952 | ||
2953 | dirtyrate = qdict_get_try_int(rate, "dirty-rate", -1); | |
2954 | ||
2955 | qobject_unref(rsp_return); | |
2956 | return dirtyrate; | |
2957 | } | |
2958 | ||
2959 | static int64_t get_limit_rate(QTestState *who) | |
2960 | { | |
2961 | QDict *rsp_return; | |
2962 | QList *rates; | |
2963 | const QListEntry *entry; | |
2964 | QDict *rate; | |
2965 | int64_t dirtyrate; | |
2966 | ||
2967 | rsp_return = query_vcpu_dirty_limit(who); | |
2968 | g_assert(rsp_return); | |
2969 | ||
2970 | rates = qdict_get_qlist(rsp_return, "return"); | |
2971 | g_assert(rates && !qlist_empty(rates)); | |
2972 | ||
2973 | entry = qlist_first(rates); | |
2974 | g_assert(entry); | |
2975 | ||
2976 | rate = qobject_to(QDict, qlist_entry_obj(entry)); | |
2977 | g_assert(rate); | |
2978 | ||
2979 | dirtyrate = qdict_get_try_int(rate, "limit-rate", -1); | |
2980 | ||
2981 | qobject_unref(rsp_return); | |
2982 | return dirtyrate; | |
2983 | } | |
2984 | ||
2985 | static QTestState *dirtylimit_start_vm(void) | |
2986 | { | |
2987 | QTestState *vm = NULL; | |
22d3c6e1 | 2988 | g_autofree gchar * |
8aff6f50 HH |
2989 | cmd = g_strdup_printf("-accel kvm,dirty-ring-size=4096 " |
2990 | "-name dirtylimit-test,debug-threads=on " | |
2991 | "-m 150M -smp 1 " | |
2992 | "-serial file:%s/vm_serial " | |
2993 | "-drive file=%s,format=raw ", | |
2994 | tmpfs, bootpath); | |
2995 | ||
2996 | vm = qtest_init(cmd); | |
2997 | return vm; | |
2998 | } | |
2999 | ||
3000 | static void dirtylimit_stop_vm(QTestState *vm) | |
3001 | { | |
3002 | qtest_quit(vm); | |
8aff6f50 HH |
3003 | cleanup("vm_serial"); |
3004 | } | |
3005 | ||
3006 | static void test_vcpu_dirty_limit(void) | |
3007 | { | |
3008 | QTestState *vm; | |
3009 | int64_t origin_rate; | |
3010 | int64_t quota_rate; | |
3011 | int64_t rate ; | |
3012 | int max_try_count = 20; | |
3013 | int hit = 0; | |
3014 | ||
3015 | /* Start vm for vcpu dirtylimit test */ | |
3016 | vm = dirtylimit_start_vm(); | |
3017 | ||
3018 | /* Wait for the first serial output from the vm*/ | |
3019 | wait_for_serial("vm_serial"); | |
3020 | ||
3021 | /* Do dirtyrate measurement with calc time equals 1s */ | |
3022 | calc_dirty_rate(vm, 1); | |
3023 | ||
3024 | /* Sleep calc time and wait for calc dirtyrate complete */ | |
3025 | wait_for_calc_dirtyrate_complete(vm, 1); | |
3026 | ||
3027 | /* Query original dirty page rate */ | |
3028 | origin_rate = get_dirty_rate(vm); | |
3029 | ||
3030 | /* VM booted from bootsect should dirty memory steadily */ | |
3031 | assert(origin_rate != 0); | |
3032 | ||
3033 | /* Setup quota dirty page rate at half of origin */ | |
3034 | quota_rate = origin_rate / 2; | |
3035 | ||
3036 | /* Set dirtylimit */ | |
3037 | dirtylimit_set_all(vm, quota_rate); | |
3038 | ||
3039 | /* | |
3040 | * Check if set-vcpu-dirty-limit and query-vcpu-dirty-limit | |
3041 | * works literally | |
3042 | */ | |
3043 | g_assert_cmpint(quota_rate, ==, get_limit_rate(vm)); | |
3044 | ||
3045 | /* Sleep a bit to check if it take effect */ | |
3046 | usleep(2000000); | |
3047 | ||
3048 | /* | |
3049 | * Check if dirtylimit take effect realistically, set the | |
3050 | * timeout with 20 s(max_try_count * 1s), if dirtylimit | |
3051 | * doesn't take effect, fail test. | |
3052 | */ | |
3053 | while (--max_try_count) { | |
3054 | calc_dirty_rate(vm, 1); | |
3055 | wait_for_calc_dirtyrate_complete(vm, 1); | |
3056 | rate = get_dirty_rate(vm); | |
3057 | ||
3058 | /* | |
3059 | * Assume hitting if current rate is less | |
3060 | * than quota rate (within accepting error) | |
3061 | */ | |
3062 | if (rate < (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) { | |
3063 | hit = 1; | |
3064 | break; | |
3065 | } | |
3066 | } | |
3067 | ||
3068 | g_assert_cmpint(hit, ==, 1); | |
3069 | ||
3070 | hit = 0; | |
3071 | max_try_count = 20; | |
3072 | ||
3073 | /* Check if dirtylimit cancellation take effect */ | |
3074 | cancel_vcpu_dirty_limit(vm); | |
3075 | while (--max_try_count) { | |
3076 | calc_dirty_rate(vm, 1); | |
3077 | wait_for_calc_dirtyrate_complete(vm, 1); | |
3078 | rate = get_dirty_rate(vm); | |
3079 | ||
3080 | /* | |
3081 | * Assume dirtylimit be canceled if current rate is | |
3082 | * greater than quota rate (within accepting error) | |
3083 | */ | |
3084 | if (rate > (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) { | |
3085 | hit = 1; | |
3086 | break; | |
3087 | } | |
3088 | } | |
3089 | ||
3090 | g_assert_cmpint(hit, ==, 1); | |
3091 | dirtylimit_stop_vm(vm); | |
3092 | } | |
3093 | ||
17257b90 HH |
3094 | static void migrate_dirty_limit_wait_showup(QTestState *from, |
3095 | const int64_t period, | |
3096 | const int64_t value) | |
3097 | { | |
3098 | /* Enable dirty limit capability */ | |
3099 | migrate_set_capability(from, "dirty-limit", true); | |
3100 | ||
3101 | /* Set dirty limit parameters */ | |
3102 | migrate_set_parameter_int(from, "x-vcpu-dirty-limit-period", period); | |
3103 | migrate_set_parameter_int(from, "vcpu-dirty-limit", value); | |
3104 | ||
3105 | /* Make sure migrate can't converge */ | |
3106 | migrate_ensure_non_converge(from); | |
3107 | ||
3108 | /* To check limit rate after precopy */ | |
3109 | migrate_set_capability(from, "pause-before-switchover", true); | |
3110 | ||
3111 | /* Wait for the serial output from the source */ | |
3112 | wait_for_serial("src_serial"); | |
3113 | } | |
3114 | ||
3115 | /* | |
3116 | * This test does: | |
3117 | * source destination | |
3118 | * start vm | |
3119 | * start incoming vm | |
3120 | * migrate | |
3121 | * wait dirty limit to begin | |
3122 | * cancel migrate | |
3123 | * cancellation check | |
3124 | * restart incoming vm | |
3125 | * migrate | |
3126 | * wait dirty limit to begin | |
3127 | * wait pre-switchover event | |
3128 | * convergence condition check | |
3129 | * | |
3130 | * And see if dirty limit migration works correctly. | |
3131 | * This test case involves many passes, so it runs in slow mode only. | |
3132 | */ | |
3133 | static void test_migrate_dirty_limit(void) | |
3134 | { | |
3135 | g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); | |
3136 | QTestState *from, *to; | |
3137 | int64_t remaining; | |
3138 | uint64_t throttle_us_per_full; | |
3139 | /* | |
3140 | * We want the test to be stable and as fast as possible. | |
8053feaa | 3141 | * E.g., with 1Gb/s bandwidth migration may pass without dirty limit, |
17257b90 HH |
3142 | * so we need to decrease a bandwidth. |
3143 | */ | |
3144 | const int64_t dirtylimit_period = 1000, dirtylimit_value = 50; | |
3145 | const int64_t max_bandwidth = 400000000; /* ~400Mb/s */ | |
3146 | const int64_t downtime_limit = 250; /* 250ms */ | |
3147 | /* | |
3148 | * We migrate through unix-socket (> 500Mb/s). | |
3149 | * Thus, expected migration speed ~= bandwidth limit (< 500Mb/s). | |
3150 | * So, we can predict expected_threshold | |
3151 | */ | |
3152 | const int64_t expected_threshold = max_bandwidth * downtime_limit / 1000; | |
3153 | int max_try_count = 10; | |
3154 | MigrateCommon args = { | |
3155 | .start = { | |
3156 | .hide_stderr = true, | |
3157 | .use_dirty_ring = true, | |
3158 | }, | |
3159 | .listen_uri = uri, | |
3160 | .connect_uri = uri, | |
3161 | }; | |
3162 | ||
3163 | /* Start src, dst vm */ | |
3164 | if (test_migrate_start(&from, &to, args.listen_uri, &args.start)) { | |
3165 | return; | |
3166 | } | |
3167 | ||
3168 | /* Prepare for dirty limit migration and wait src vm show up */ | |
3169 | migrate_dirty_limit_wait_showup(from, dirtylimit_period, dirtylimit_value); | |
3170 | ||
3171 | /* Start migrate */ | |
3172 | migrate_qmp(from, uri, "{}"); | |
3173 | ||
3174 | /* Wait for dirty limit throttle begin */ | |
3175 | throttle_us_per_full = 0; | |
3176 | while (throttle_us_per_full == 0) { | |
3177 | throttle_us_per_full = | |
3178 | read_migrate_property_int(from, "dirty-limit-throttle-time-per-round"); | |
3179 | usleep(100); | |
3180 | g_assert_false(got_src_stop); | |
3181 | } | |
3182 | ||
3183 | /* Now cancel migrate and wait for dirty limit throttle switch off */ | |
3184 | migrate_cancel(from); | |
3185 | wait_for_migration_status(from, "cancelled", NULL); | |
3186 | ||
3187 | /* Check if dirty limit throttle switched off, set timeout 1ms */ | |
3188 | do { | |
3189 | throttle_us_per_full = | |
3190 | read_migrate_property_int(from, "dirty-limit-throttle-time-per-round"); | |
3191 | usleep(100); | |
3192 | g_assert_false(got_src_stop); | |
3193 | } while (throttle_us_per_full != 0 && --max_try_count); | |
3194 | ||
3195 | /* Assert dirty limit is not in service */ | |
3196 | g_assert_cmpint(throttle_us_per_full, ==, 0); | |
3197 | ||
3198 | args = (MigrateCommon) { | |
3199 | .start = { | |
3200 | .only_target = true, | |
3201 | .use_dirty_ring = true, | |
3202 | }, | |
3203 | .listen_uri = uri, | |
3204 | .connect_uri = uri, | |
3205 | }; | |
3206 | ||
3207 | /* Restart dst vm, src vm already show up so we needn't wait anymore */ | |
3208 | if (test_migrate_start(&from, &to, args.listen_uri, &args.start)) { | |
3209 | return; | |
3210 | } | |
3211 | ||
3212 | /* Start migrate */ | |
3213 | migrate_qmp(from, uri, "{}"); | |
3214 | ||
3215 | /* Wait for dirty limit throttle begin */ | |
3216 | throttle_us_per_full = 0; | |
3217 | while (throttle_us_per_full == 0) { | |
3218 | throttle_us_per_full = | |
3219 | read_migrate_property_int(from, "dirty-limit-throttle-time-per-round"); | |
3220 | usleep(100); | |
3221 | g_assert_false(got_src_stop); | |
3222 | } | |
3223 | ||
3224 | /* | |
3225 | * The dirty limit rate should equals the return value of | |
3226 | * query-vcpu-dirty-limit if dirty limit cap set | |
3227 | */ | |
3228 | g_assert_cmpint(dirtylimit_value, ==, get_limit_rate(from)); | |
3229 | ||
3230 | /* Now, we have tested if dirty limit works, let it converge */ | |
3231 | migrate_set_parameter_int(from, "downtime-limit", downtime_limit); | |
3232 | migrate_set_parameter_int(from, "max-bandwidth", max_bandwidth); | |
3233 | ||
3234 | /* | |
3235 | * Wait for pre-switchover status to check if migration | |
3236 | * satisfy the convergence condition | |
3237 | */ | |
3238 | wait_for_migration_status(from, "pre-switchover", NULL); | |
3239 | ||
3240 | remaining = read_ram_property_int(from, "remaining"); | |
3241 | g_assert_cmpint(remaining, <, | |
3242 | (expected_threshold + expected_threshold / 100)); | |
3243 | ||
3244 | migrate_continue(from, "pre-switchover"); | |
3245 | ||
3246 | qtest_qmp_eventwait(to, "RESUME"); | |
3247 | ||
3248 | wait_for_serial("dest_serial"); | |
3249 | wait_for_migration_complete(from); | |
3250 | ||
3251 | test_migrate_end(from, to, true); | |
3252 | } | |
3253 | ||
1f546b70 PX |
3254 | static bool kvm_dirty_ring_supported(void) |
3255 | { | |
61c32485 | 3256 | #if defined(__linux__) && defined(HOST_X86_64) |
1f546b70 PX |
3257 | int ret, kvm_fd = open("/dev/kvm", O_RDONLY); |
3258 | ||
3259 | if (kvm_fd < 0) { | |
3260 | return false; | |
3261 | } | |
3262 | ||
3263 | ret = ioctl(kvm_fd, KVM_CHECK_EXTENSION, KVM_CAP_DIRTY_LOG_RING); | |
3264 | close(kvm_fd); | |
3265 | ||
3266 | /* We test with 4096 slots */ | |
3267 | if (ret < 4096) { | |
3268 | return false; | |
3269 | } | |
3270 | ||
3271 | return true; | |
3272 | #else | |
3273 | return false; | |
3274 | #endif | |
3275 | } | |
3276 | ||
ea0c6d62 DDAG |
3277 | int main(int argc, char **argv) |
3278 | { | |
0c1ae3ff | 3279 | bool has_kvm, has_tcg; |
e35b9a2e DB |
3280 | bool has_uffd; |
3281 | const char *arch; | |
e5553c1b | 3282 | g_autoptr(GError) err = NULL; |
5050ad2a FR |
3283 | const char *qemu_src = getenv(QEMU_ENV_SRC); |
3284 | const char *qemu_dst = getenv(QEMU_ENV_DST); | |
ea0c6d62 DDAG |
3285 | int ret; |
3286 | ||
3287 | g_test_init(&argc, &argv, NULL); | |
3288 | ||
5050ad2a FR |
3289 | /* |
3290 | * The default QTEST_QEMU_BINARY must always be provided because | |
3291 | * that is what helpers use to query the accel type and | |
3292 | * architecture. | |
3293 | */ | |
3294 | if (qemu_src && qemu_dst) { | |
3295 | g_test_message("Only one of %s, %s is allowed", | |
3296 | QEMU_ENV_SRC, QEMU_ENV_DST); | |
3297 | exit(1); | |
3298 | } | |
3299 | ||
e35b9a2e | 3300 | has_kvm = qtest_has_accel("kvm"); |
0c1ae3ff FR |
3301 | has_tcg = qtest_has_accel("tcg"); |
3302 | ||
3303 | if (!has_tcg && !has_kvm) { | |
3304 | g_test_skip("No KVM or TCG accelerator available"); | |
3305 | return 0; | |
3306 | } | |
3307 | ||
e35b9a2e DB |
3308 | has_uffd = ufd_version_check(); |
3309 | arch = qtest_get_arch(); | |
3310 | ||
880b169a TH |
3311 | /* |
3312 | * On ppc64, the test only works with kvm-hv, but not with kvm-pr and TCG | |
3313 | * is touchy due to race conditions on dirty bits (especially on PPC for | |
3314 | * some reason) | |
3315 | */ | |
1bca64a3 | 3316 | if (g_str_equal(arch, "ppc64") && |
b72c7603 | 3317 | (!has_kvm || access("/sys/module/kvm_hv", F_OK))) { |
880b169a | 3318 | g_test_message("Skipping test: kvm_hv not available"); |
4848cb3d | 3319 | return g_test_run(); |
880b169a TH |
3320 | } |
3321 | ||
d254b392 TH |
3322 | /* |
3323 | * Similar to ppc64, s390x seems to be touchy with TCG, so disable it | |
3324 | * there until the problems are resolved | |
3325 | */ | |
1bca64a3 | 3326 | if (g_str_equal(arch, "s390x") && !has_kvm) { |
b72c7603 | 3327 | g_test_message("Skipping test: s390x host with KVM is required"); |
4848cb3d | 3328 | return g_test_run(); |
d254b392 TH |
3329 | } |
3330 | ||
e5553c1b | 3331 | tmpfs = g_dir_make_tmp("migration-test-XXXXXX", &err); |
ea0c6d62 | 3332 | if (!tmpfs) { |
b1f6208c BM |
3333 | g_test_message("Can't create temporary directory in %s: %s", |
3334 | g_get_tmp_dir(), err->message); | |
ea0c6d62 DDAG |
3335 | } |
3336 | g_assert(tmpfs); | |
0c690d3e | 3337 | bootfile_create(tmpfs); |
ea0c6d62 DDAG |
3338 | |
3339 | module_call_init(MODULE_INIT_QOM); | |
3340 | ||
2649a725 | 3341 | if (has_uffd) { |
2649a725 PX |
3342 | qtest_add_func("/migration/postcopy/plain", test_postcopy); |
3343 | qtest_add_func("/migration/postcopy/recovery/plain", | |
3344 | test_postcopy_recovery); | |
3345 | qtest_add_func("/migration/postcopy/preempt/plain", test_postcopy_preempt); | |
3346 | qtest_add_func("/migration/postcopy/preempt/recovery/plain", | |
3347 | test_postcopy_preempt_recovery); | |
dc066da8 LS |
3348 | if (getenv("QEMU_TEST_FLAKY_TESTS")) { |
3349 | qtest_add_func("/migration/postcopy/compress/plain", | |
3350 | test_postcopy_compress); | |
3351 | qtest_add_func("/migration/postcopy/recovery/compress/plain", | |
3352 | test_postcopy_recovery_compress); | |
3353 | } | |
7bca2bb7 FR |
3354 | #ifndef _WIN32 |
3355 | qtest_add_func("/migration/postcopy/recovery/double-failures", | |
3356 | test_postcopy_recovery_double_fail); | |
3357 | #endif /* _WIN32 */ | |
3358 | ||
2649a725 | 3359 | } |
d1a27b16 | 3360 | |
2c9bb297 | 3361 | qtest_add_func("/migration/bad_dest", test_baddest); |
d864756e | 3362 | #ifndef _WIN32 |
04131e00 TH |
3363 | if (!g_str_equal(arch, "s390x")) { |
3364 | qtest_add_func("/migration/analyze-script", test_analyze_script); | |
3365 | } | |
d864756e | 3366 | #endif |
58d25e97 | 3367 | qtest_add_func("/migration/precopy/unix/plain", test_precopy_unix_plain); |
83bcba1e | 3368 | qtest_add_func("/migration/precopy/unix/xbzrle", test_precopy_unix_xbzrle); |
1536d1da LS |
3369 | /* |
3370 | * Compression fails from time to time. | |
3371 | * Put test here but don't enable it until everything is fixed. | |
3372 | */ | |
3373 | if (getenv("QEMU_TEST_FLAKY_TESTS")) { | |
3374 | qtest_add_func("/migration/precopy/unix/compress/wait", | |
3375 | test_precopy_unix_compress); | |
3376 | qtest_add_func("/migration/precopy/unix/compress/nowait", | |
3377 | test_precopy_unix_compress_nowait); | |
3378 | } | |
3dc35470 FR |
3379 | |
3380 | qtest_add_func("/migration/precopy/file", | |
3381 | test_precopy_file); | |
3382 | qtest_add_func("/migration/precopy/file/offset", | |
3383 | test_precopy_file_offset); | |
3384 | qtest_add_func("/migration/precopy/file/offset/bad", | |
3385 | test_precopy_file_offset_bad); | |
3386 | ||
e7b428d6 SS |
3387 | /* |
3388 | * Our CI system has problems with shared memory. | |
3389 | * Don't run this test until we find a workaround. | |
3390 | */ | |
3391 | if (getenv("QEMU_TEST_FLAKY_TESTS")) { | |
3392 | qtest_add_func("/migration/mode/reboot", test_mode_reboot); | |
3393 | } | |
3394 | ||
58d25e97 DB |
3395 | #ifdef CONFIG_GNUTLS |
3396 | qtest_add_func("/migration/precopy/unix/tls/psk", | |
3397 | test_precopy_unix_tls_psk); | |
2649a725 PX |
3398 | |
3399 | if (has_uffd) { | |
3400 | /* | |
3401 | * NOTE: psk test is enough for postcopy, as other types of TLS | |
3402 | * channels are tested under precopy. Here what we want to test is the | |
3403 | * general postcopy path that has TLS channel enabled. | |
3404 | */ | |
3405 | qtest_add_func("/migration/postcopy/tls/psk", test_postcopy_tls_psk); | |
3406 | qtest_add_func("/migration/postcopy/recovery/tls/psk", | |
3407 | test_postcopy_recovery_tls_psk); | |
3408 | qtest_add_func("/migration/postcopy/preempt/tls/psk", | |
3409 | test_postcopy_preempt_tls_psk); | |
3410 | qtest_add_func("/migration/postcopy/preempt/recovery/tls/psk", | |
3411 | test_postcopy_preempt_all); | |
3412 | } | |
d47b83b1 DB |
3413 | #ifdef CONFIG_TASN1 |
3414 | qtest_add_func("/migration/precopy/unix/tls/x509/default-host", | |
3415 | test_precopy_unix_tls_x509_default_host); | |
3416 | qtest_add_func("/migration/precopy/unix/tls/x509/override-host", | |
3417 | test_precopy_unix_tls_x509_override_host); | |
3418 | #endif /* CONFIG_TASN1 */ | |
58d25e97 DB |
3419 | #endif /* CONFIG_GNUTLS */ |
3420 | ||
3421 | qtest_add_func("/migration/precopy/tcp/plain", test_precopy_tcp_plain); | |
7e6a5c73 AH |
3422 | |
3423 | qtest_add_func("/migration/precopy/tcp/plain/switchover-ack", | |
3424 | test_precopy_tcp_switchover_ack); | |
3425 | ||
58d25e97 DB |
3426 | #ifdef CONFIG_GNUTLS |
3427 | qtest_add_func("/migration/precopy/tcp/tls/psk/match", | |
3428 | test_precopy_tcp_tls_psk_match); | |
3429 | qtest_add_func("/migration/precopy/tcp/tls/psk/mismatch", | |
3430 | test_precopy_tcp_tls_psk_mismatch); | |
d47b83b1 DB |
3431 | #ifdef CONFIG_TASN1 |
3432 | qtest_add_func("/migration/precopy/tcp/tls/x509/default-host", | |
3433 | test_precopy_tcp_tls_x509_default_host); | |
3434 | qtest_add_func("/migration/precopy/tcp/tls/x509/override-host", | |
3435 | test_precopy_tcp_tls_x509_override_host); | |
3436 | qtest_add_func("/migration/precopy/tcp/tls/x509/mismatch-host", | |
3437 | test_precopy_tcp_tls_x509_mismatch_host); | |
3438 | qtest_add_func("/migration/precopy/tcp/tls/x509/friendly-client", | |
3439 | test_precopy_tcp_tls_x509_friendly_client); | |
3440 | qtest_add_func("/migration/precopy/tcp/tls/x509/hostile-client", | |
3441 | test_precopy_tcp_tls_x509_hostile_client); | |
3442 | qtest_add_func("/migration/precopy/tcp/tls/x509/allow-anon-client", | |
3443 | test_precopy_tcp_tls_x509_allow_anon_client); | |
3444 | qtest_add_func("/migration/precopy/tcp/tls/x509/reject-anon-client", | |
3445 | test_precopy_tcp_tls_x509_reject_anon_client); | |
3446 | #endif /* CONFIG_TASN1 */ | |
58d25e97 DB |
3447 | #endif /* CONFIG_GNUTLS */ |
3448 | ||
660a9b68 | 3449 | /* qtest_add_func("/migration/ignore_shared", test_ignore_shared); */ |
d7613ee2 | 3450 | #ifndef _WIN32 |
24d5588c | 3451 | qtest_add_func("/migration/fd_proto", test_migrate_fd_proto); |
d7613ee2 | 3452 | #endif |
3af31a34 YK |
3453 | qtest_add_func("/migration/validate_uuid", test_validate_uuid); |
3454 | qtest_add_func("/migration/validate_uuid_error", test_validate_uuid_error); | |
3455 | qtest_add_func("/migration/validate_uuid_src_not_set", | |
3456 | test_validate_uuid_src_not_set); | |
3457 | qtest_add_func("/migration/validate_uuid_dst_not_set", | |
3458 | test_validate_uuid_dst_not_set); | |
74902af7 JQ |
3459 | /* |
3460 | * See explanation why this test is slow on function definition | |
3461 | */ | |
3462 | if (g_test_slow()) { | |
3463 | qtest_add_func("/migration/auto_converge", test_migrate_auto_converge); | |
17257b90 HH |
3464 | if (g_str_equal(arch, "x86_64") && |
3465 | has_kvm && kvm_dirty_ring_supported()) { | |
3466 | qtest_add_func("/migration/dirty_limit", test_migrate_dirty_limit); | |
3467 | } | |
74902af7 | 3468 | } |
4d6d2e87 DB |
3469 | qtest_add_func("/migration/multifd/tcp/plain/none", |
3470 | test_multifd_tcp_none); | |
c15d9e23 PM |
3471 | /* |
3472 | * This test is flaky and sometimes fails in CI and otherwise: | |
3473 | * don't run unless user opts in via environment variable. | |
3474 | */ | |
3475 | if (getenv("QEMU_TEST_FLAKY_TESTS")) { | |
3476 | qtest_add_func("/migration/multifd/tcp/plain/cancel", | |
3477 | test_multifd_tcp_cancel); | |
3478 | } | |
4d6d2e87 DB |
3479 | qtest_add_func("/migration/multifd/tcp/plain/zlib", |
3480 | test_multifd_tcp_zlib); | |
87dc6f5f | 3481 | #ifdef CONFIG_ZSTD |
4d6d2e87 DB |
3482 | qtest_add_func("/migration/multifd/tcp/plain/zstd", |
3483 | test_multifd_tcp_zstd); | |
87dc6f5f | 3484 | #endif |
4d6d2e87 DB |
3485 | #ifdef CONFIG_GNUTLS |
3486 | qtest_add_func("/migration/multifd/tcp/tls/psk/match", | |
3487 | test_multifd_tcp_tls_psk_match); | |
3488 | qtest_add_func("/migration/multifd/tcp/tls/psk/mismatch", | |
3489 | test_multifd_tcp_tls_psk_mismatch); | |
ff32f1dd DB |
3490 | #ifdef CONFIG_TASN1 |
3491 | qtest_add_func("/migration/multifd/tcp/tls/x509/default-host", | |
3492 | test_multifd_tcp_tls_x509_default_host); | |
3493 | qtest_add_func("/migration/multifd/tcp/tls/x509/override-host", | |
3494 | test_multifd_tcp_tls_x509_override_host); | |
3495 | qtest_add_func("/migration/multifd/tcp/tls/x509/mismatch-host", | |
3496 | test_multifd_tcp_tls_x509_mismatch_host); | |
3497 | qtest_add_func("/migration/multifd/tcp/tls/x509/allow-anon-client", | |
3498 | test_multifd_tcp_tls_x509_allow_anon_client); | |
3499 | qtest_add_func("/migration/multifd/tcp/tls/x509/reject-anon-client", | |
3500 | test_multifd_tcp_tls_x509_reject_anon_client); | |
3501 | #endif /* CONFIG_TASN1 */ | |
4d6d2e87 | 3502 | #endif /* CONFIG_GNUTLS */ |
8c51642b | 3503 | |
1bca64a3 | 3504 | if (g_str_equal(arch, "x86_64") && has_kvm && kvm_dirty_ring_supported()) { |
1f546b70 PX |
3505 | qtest_add_func("/migration/dirty_ring", |
3506 | test_precopy_unix_dirty_ring); | |
8aff6f50 HH |
3507 | qtest_add_func("/migration/vcpu_dirty_limit", |
3508 | test_vcpu_dirty_limit); | |
1f546b70 PX |
3509 | } |
3510 | ||
ea0c6d62 DDAG |
3511 | ret = g_test_run(); |
3512 | ||
3513 | g_assert_cmpint(ret, ==, 0); | |
3514 | ||
0c690d3e | 3515 | bootfile_delete(); |
ea0c6d62 DDAG |
3516 | ret = rmdir(tmpfs); |
3517 | if (ret != 0) { | |
13ee9e30 | 3518 | g_test_message("unable to rmdir: path (%s): %s", |
ea0c6d62 DDAG |
3519 | tmpfs, strerror(errno)); |
3520 | } | |
e5553c1b | 3521 | g_free(tmpfs); |
ea0c6d62 DDAG |
3522 | |
3523 | return ret; | |
3524 | } |