1
2
3
4
5
6
7
8
9
10
11
12
13#include "qemu/osdep.h"
14
15#include "libqtest.h"
16#include "qapi/qmp/qdict.h"
17#include "qapi/qmp/qjson.h"
18#include "qemu/module.h"
19#include "qemu/option.h"
20#include "qemu/range.h"
21#include "qemu/sockets.h"
22#include "chardev/char.h"
23#include "qapi/qapi-visit-sockets.h"
24#include "qapi/qobject-input-visitor.h"
25#include "qapi/qobject-output-visitor.h"
26
27#include "migration/migration-test.h"
28
29
30#define qtest_qmp_discard_response(...) qobject_unref(qtest_qmp(__VA_ARGS__))
31
32unsigned start_address;
33unsigned end_address;
34bool got_stop;
35static bool uffd_feature_thread_id;
36
37#if defined(__linux__)
38#include <sys/syscall.h>
39#include <sys/vfs.h>
40#endif
41
42#if defined(__linux__) && defined(__NR_userfaultfd) && defined(CONFIG_EVENTFD)
43#include <sys/eventfd.h>
44#include <sys/ioctl.h>
45#include <linux/userfaultfd.h>
46
47static bool ufd_version_check(void)
48{
49 struct uffdio_api api_struct;
50 uint64_t ioctl_mask;
51
52 int ufd = syscall(__NR_userfaultfd, O_CLOEXEC);
53
54 if (ufd == -1) {
55 g_test_message("Skipping test: userfaultfd not available");
56 return false;
57 }
58
59 api_struct.api = UFFD_API;
60 api_struct.features = 0;
61 if (ioctl(ufd, UFFDIO_API, &api_struct)) {
62 g_test_message("Skipping test: UFFDIO_API failed");
63 return false;
64 }
65 uffd_feature_thread_id = api_struct.features & UFFD_FEATURE_THREAD_ID;
66
67 ioctl_mask = (__u64)1 << _UFFDIO_REGISTER |
68 (__u64)1 << _UFFDIO_UNREGISTER;
69 if ((api_struct.ioctls & ioctl_mask) != ioctl_mask) {
70 g_test_message("Skipping test: Missing userfault feature");
71 return false;
72 }
73
74 return true;
75}
76
77#else
78static bool ufd_version_check(void)
79{
80 g_test_message("Skipping test: Userfault not available (builtdtime)");
81 return false;
82}
83
84#endif
85
86static const char *tmpfs;
87
88
89
90
91#include "tests/migration/i386/a-b-bootblock.h"
92#include "tests/migration/aarch64/a-b-kernel.h"
93#include "tests/migration/s390x/a-b-bios.h"
94
95static void init_bootfile(const char *bootpath, void *content, size_t len)
96{
97 FILE *bootfile = fopen(bootpath, "wb");
98
99 g_assert_cmpint(fwrite(content, len, 1, bootfile), ==, 1);
100 fclose(bootfile);
101}
102
103
104
105
106
107
108static void wait_for_serial(const char *side)
109{
110 char *serialpath = g_strdup_printf("%s/%s", tmpfs, side);
111 FILE *serialfile = fopen(serialpath, "r");
112 const char *arch = qtest_get_arch();
113 int started = (strcmp(side, "src_serial") == 0 &&
114 strcmp(arch, "ppc64") == 0) ? 0 : 1;
115
116 g_free(serialpath);
117 do {
118 int readvalue = fgetc(serialfile);
119
120 if (!started) {
121
122
123
124
125 switch (readvalue) {
126 case '_':
127 started = 1;
128 break;
129 case EOF:
130 fseek(serialfile, 0, SEEK_SET);
131 usleep(1000);
132 break;
133 }
134 continue;
135 }
136 switch (readvalue) {
137 case 'A':
138
139 break;
140
141 case 'B':
142
143 fclose(serialfile);
144 return;
145
146 case EOF:
147 started = (strcmp(side, "src_serial") == 0 &&
148 strcmp(arch, "ppc64") == 0) ? 0 : 1;
149 fseek(serialfile, 0, SEEK_SET);
150 usleep(1000);
151 break;
152
153 default:
154 fprintf(stderr, "Unexpected %d on %s serial\n", readvalue, side);
155 g_assert_not_reached();
156 }
157 } while (true);
158}
159
160static void stop_cb(void *opaque, const char *name, QDict *data)
161{
162 if (!strcmp(name, "STOP")) {
163 got_stop = true;
164 }
165}
166
167
168
169
170GCC_FMT_ATTR(3, 4)
171static QDict *wait_command_fd(QTestState *who, int fd, const char *command, ...)
172{
173 va_list ap;
174
175 va_start(ap, command);
176 qtest_qmp_vsend_fds(who, &fd, 1, command, ap);
177 va_end(ap);
178
179 return qtest_qmp_receive_success(who, stop_cb, NULL);
180}
181
182
183
184
185GCC_FMT_ATTR(2, 3)
186static QDict *wait_command(QTestState *who, const char *command, ...)
187{
188 va_list ap;
189
190 va_start(ap, command);
191 qtest_qmp_vsend(who, command, ap);
192 va_end(ap);
193
194 return qtest_qmp_receive_success(who, stop_cb, NULL);
195}
196
197
198
199
200
201static QDict *migrate_query(QTestState *who)
202{
203 return wait_command(who, "{ 'execute': 'query-migrate' }");
204}
205
206
207
208
209
210static gchar *migrate_query_status(QTestState *who)
211{
212 QDict *rsp_return = migrate_query(who);
213 gchar *status = g_strdup(qdict_get_str(rsp_return, "status"));
214
215 g_assert(status);
216 qobject_unref(rsp_return);
217
218 return status;
219}
220
221
222
223
224
225
226static int64_t read_ram_property_int(QTestState *who, const char *property)
227{
228 QDict *rsp_return, *rsp_ram;
229 int64_t result;
230
231 rsp_return = migrate_query(who);
232 if (!qdict_haskey(rsp_return, "ram")) {
233
234 result = 0;
235 } else {
236 rsp_ram = qdict_get_qdict(rsp_return, "ram");
237 result = qdict_get_try_int(rsp_ram, property, 0);
238 }
239 qobject_unref(rsp_return);
240 return result;
241}
242
243static int64_t read_migrate_property_int(QTestState *who, const char *property)
244{
245 QDict *rsp_return;
246 int64_t result;
247
248 rsp_return = migrate_query(who);
249 result = qdict_get_try_int(rsp_return, property, 0);
250 qobject_unref(rsp_return);
251 return result;
252}
253
254static uint64_t get_migration_pass(QTestState *who)
255{
256 return read_ram_property_int(who, "dirty-sync-count");
257}
258
259static void read_blocktime(QTestState *who)
260{
261 QDict *rsp_return;
262
263 rsp_return = migrate_query(who);
264 g_assert(qdict_haskey(rsp_return, "postcopy-blocktime"));
265 qobject_unref(rsp_return);
266}
267
268static bool check_migration_status(QTestState *who, const char *goal,
269 const char **ungoals)
270{
271 bool ready;
272 char *current_status;
273 const char **ungoal;
274
275 current_status = migrate_query_status(who);
276 ready = strcmp(current_status, goal) == 0;
277 if (!ungoals) {
278 g_assert_cmpstr(current_status, !=, "failed");
279
280
281
282
283
284 if (strcmp(goal, "completed") != 0) {
285 g_assert_cmpstr(current_status, !=, "completed");
286 }
287 } else {
288 for (ungoal = ungoals; *ungoal; ungoal++) {
289 g_assert_cmpstr(current_status, !=, *ungoal);
290 }
291 }
292 g_free(current_status);
293 return ready;
294}
295
296static void wait_for_migration_status(QTestState *who,
297 const char *goal,
298 const char **ungoals)
299{
300 while (!check_migration_status(who, goal, ungoals)) {
301 usleep(1000);
302 }
303}
304
305static void wait_for_migration_complete(QTestState *who)
306{
307 wait_for_migration_status(who, "completed", NULL);
308}
309
310static void wait_for_migration_pass(QTestState *who)
311{
312 uint64_t initial_pass = get_migration_pass(who);
313 uint64_t pass;
314
315
316 while (!got_stop && !initial_pass) {
317 usleep(1000);
318 initial_pass = get_migration_pass(who);
319 }
320
321 do {
322 usleep(1000);
323 pass = get_migration_pass(who);
324 } while (pass == initial_pass && !got_stop);
325}
326
327static void check_guests_ram(QTestState *who)
328{
329
330
331
332
333
334
335
336 unsigned address;
337 uint8_t first_byte;
338 uint8_t last_byte;
339 bool hit_edge = false;
340 int bad = 0;
341
342 qtest_memread(who, start_address, &first_byte, 1);
343 last_byte = first_byte;
344
345 for (address = start_address + TEST_MEM_PAGE_SIZE; address < end_address;
346 address += TEST_MEM_PAGE_SIZE)
347 {
348 uint8_t b;
349 qtest_memread(who, address, &b, 1);
350 if (b != last_byte) {
351 if (((b + 1) % 256) == last_byte && !hit_edge) {
352
353
354
355
356 hit_edge = true;
357 last_byte = b;
358 } else {
359 bad++;
360 if (bad <= 10) {
361 fprintf(stderr, "Memory content inconsistency at %x"
362 " first_byte = %x last_byte = %x current = %x"
363 " hit_edge = %x\n",
364 address, first_byte, last_byte, b, hit_edge);
365 }
366 }
367 }
368 }
369 if (bad >= 10) {
370 fprintf(stderr, "and in another %d pages", bad - 10);
371 }
372 g_assert(bad == 0);
373}
374
375static void cleanup(const char *filename)
376{
377 char *path = g_strdup_printf("%s/%s", tmpfs, filename);
378
379 unlink(path);
380 g_free(path);
381}
382
383static char *get_shmem_opts(const char *mem_size, const char *shmem_path)
384{
385 return g_strdup_printf("-object memory-backend-file,id=mem0,size=%s"
386 ",mem-path=%s,share=on -numa node,memdev=mem0",
387 mem_size, shmem_path);
388}
389
390static char *SocketAddress_to_str(SocketAddress *addr)
391{
392 switch (addr->type) {
393 case SOCKET_ADDRESS_TYPE_INET:
394 return g_strdup_printf("tcp:%s:%s",
395 addr->u.inet.host,
396 addr->u.inet.port);
397 case SOCKET_ADDRESS_TYPE_UNIX:
398 return g_strdup_printf("unix:%s",
399 addr->u.q_unix.path);
400 case SOCKET_ADDRESS_TYPE_FD:
401 return g_strdup_printf("fd:%s", addr->u.fd.str);
402 case SOCKET_ADDRESS_TYPE_VSOCK:
403 return g_strdup_printf("tcp:%s:%s",
404 addr->u.vsock.cid,
405 addr->u.vsock.port);
406 default:
407 return g_strdup("unknown address type");
408 }
409}
410
411static char *migrate_get_socket_address(QTestState *who, const char *parameter)
412{
413 QDict *rsp;
414 char *result;
415 Error *local_err = NULL;
416 SocketAddressList *addrs;
417 Visitor *iv = NULL;
418 QObject *object;
419
420 rsp = migrate_query(who);
421 object = qdict_get(rsp, parameter);
422
423 iv = qobject_input_visitor_new(object);
424 visit_type_SocketAddressList(iv, NULL, &addrs, &local_err);
425 visit_free(iv);
426
427
428 result = SocketAddress_to_str(addrs->value);
429
430 qapi_free_SocketAddressList(addrs);
431 qobject_unref(rsp);
432 return result;
433}
434
435static long long migrate_get_parameter_int(QTestState *who,
436 const char *parameter)
437{
438 QDict *rsp;
439 long long result;
440
441 rsp = wait_command(who, "{ 'execute': 'query-migrate-parameters' }");
442 result = qdict_get_int(rsp, parameter);
443 qobject_unref(rsp);
444 return result;
445}
446
447static void migrate_check_parameter_int(QTestState *who, const char *parameter,
448 long long value)
449{
450 long long result;
451
452 result = migrate_get_parameter_int(who, parameter);
453 g_assert_cmpint(result, ==, value);
454}
455
456static void migrate_set_parameter_int(QTestState *who, const char *parameter,
457 long long value)
458{
459 QDict *rsp;
460
461 rsp = qtest_qmp(who,
462 "{ 'execute': 'migrate-set-parameters',"
463 "'arguments': { %s: %lld } }",
464 parameter, value);
465 g_assert(qdict_haskey(rsp, "return"));
466 qobject_unref(rsp);
467 migrate_check_parameter_int(who, parameter, value);
468}
469
470static void migrate_pause(QTestState *who)
471{
472 QDict *rsp;
473
474 rsp = wait_command(who, "{ 'execute': 'migrate-pause' }");
475 qobject_unref(rsp);
476}
477
478static void migrate_continue(QTestState *who, const char *state)
479{
480 QDict *rsp;
481
482 rsp = wait_command(who,
483 "{ 'execute': 'migrate-continue',"
484 " 'arguments': { 'state': %s } }",
485 state);
486 qobject_unref(rsp);
487}
488
489static void migrate_recover(QTestState *who, const char *uri)
490{
491 QDict *rsp;
492
493 rsp = wait_command(who,
494 "{ 'execute': 'migrate-recover', "
495 " 'id': 'recover-cmd', "
496 " 'arguments': { 'uri': %s } }",
497 uri);
498 qobject_unref(rsp);
499}
500
501static void migrate_set_capability(QTestState *who, const char *capability,
502 bool value)
503{
504 QDict *rsp;
505
506 rsp = qtest_qmp(who,
507 "{ 'execute': 'migrate-set-capabilities',"
508 "'arguments': { "
509 "'capabilities': [ { "
510 "'capability': %s, 'state': %i } ] } }",
511 capability, value);
512 g_assert(qdict_haskey(rsp, "return"));
513 qobject_unref(rsp);
514}
515
516
517
518
519
520
521GCC_FMT_ATTR(3, 4)
522static void migrate(QTestState *who, const char *uri, const char *fmt, ...)
523{
524 va_list ap;
525 QDict *args, *rsp;
526
527 va_start(ap, fmt);
528 args = qdict_from_vjsonf_nofail(fmt, ap);
529 va_end(ap);
530
531 g_assert(!qdict_haskey(args, "uri"));
532 qdict_put_str(args, "uri", uri);
533
534 rsp = qtest_qmp(who, "{ 'execute': 'migrate', 'arguments': %p}", args);
535
536 g_assert(qdict_haskey(rsp, "return"));
537 qobject_unref(rsp);
538}
539
540static void migrate_postcopy_start(QTestState *from, QTestState *to)
541{
542 QDict *rsp;
543
544 rsp = wait_command(from, "{ 'execute': 'migrate-start-postcopy' }");
545 qobject_unref(rsp);
546
547 if (!got_stop) {
548 qtest_qmp_eventwait(from, "STOP");
549 }
550
551 qtest_qmp_eventwait(to, "RESUME");
552}
553
554static int test_migrate_start(QTestState **from, QTestState **to,
555 const char *uri, bool hide_stderr,
556 bool use_shmem, const char *opts_src,
557 const char *opts_dst)
558{
559 gchar *cmd_src, *cmd_dst;
560 char *bootpath = NULL;
561 char *extra_opts = NULL;
562 char *shmem_path = NULL;
563 const char *arch = qtest_get_arch();
564 const char *accel = "kvm:tcg";
565
566 opts_src = opts_src ? opts_src : "";
567 opts_dst = opts_dst ? opts_dst : "";
568
569 if (use_shmem) {
570 if (!g_file_test("/dev/shm", G_FILE_TEST_IS_DIR)) {
571 g_test_skip("/dev/shm is not supported");
572 return -1;
573 }
574 shmem_path = g_strdup_printf("/dev/shm/qemu-%d", getpid());
575 }
576
577 got_stop = false;
578 bootpath = g_strdup_printf("%s/bootsect", tmpfs);
579 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
580
581 assert(sizeof(x86_bootsect) == 512);
582 init_bootfile(bootpath, x86_bootsect, sizeof(x86_bootsect));
583 extra_opts = use_shmem ? get_shmem_opts("150M", shmem_path) : NULL;
584 cmd_src = g_strdup_printf("-machine accel=%s -m 150M"
585 " -name source,debug-threads=on"
586 " -serial file:%s/src_serial"
587 " -drive file=%s,format=raw %s %s",
588 accel, tmpfs, bootpath,
589 extra_opts ? extra_opts : "", opts_src);
590 cmd_dst = g_strdup_printf("-machine accel=%s -m 150M"
591 " -name target,debug-threads=on"
592 " -serial file:%s/dest_serial"
593 " -drive file=%s,format=raw"
594 " -incoming %s %s %s",
595 accel, tmpfs, bootpath, uri,
596 extra_opts ? extra_opts : "", opts_dst);
597 start_address = X86_TEST_MEM_START;
598 end_address = X86_TEST_MEM_END;
599 } else if (g_str_equal(arch, "s390x")) {
600 init_bootfile(bootpath, s390x_elf, sizeof(s390x_elf));
601 extra_opts = use_shmem ? get_shmem_opts("128M", shmem_path) : NULL;
602 cmd_src = g_strdup_printf("-machine accel=%s -m 128M"
603 " -name source,debug-threads=on"
604 " -serial file:%s/src_serial -bios %s %s %s",
605 accel, tmpfs, bootpath,
606 extra_opts ? extra_opts : "", opts_src);
607 cmd_dst = g_strdup_printf("-machine accel=%s -m 128M"
608 " -name target,debug-threads=on"
609 " -serial file:%s/dest_serial -bios %s"
610 " -incoming %s %s %s",
611 accel, tmpfs, bootpath, uri,
612 extra_opts ? extra_opts : "", opts_dst);
613 start_address = S390_TEST_MEM_START;
614 end_address = S390_TEST_MEM_END;
615 } else if (strcmp(arch, "ppc64") == 0) {
616 extra_opts = use_shmem ? get_shmem_opts("256M", shmem_path) : NULL;
617 start_address = PPC_TEST_MEM_START;
618 end_address = PPC_TEST_MEM_END;
619 cmd_src = g_strdup_printf("-machine accel=%s,vsmt=8 -m 256M -nodefaults"
620 " -name source,debug-threads=on"
621 " -serial file:%s/src_serial"
622 " -prom-env 'use-nvramrc?=true' -prom-env "
623 "'nvramrc=hex .\" _\" begin %x %x "
624 "do i c@ 1 + i c! 1000 +loop .\" B\" 0 "
625 "until' %s %s", accel, tmpfs, end_address,
626 start_address, extra_opts ? extra_opts : "",
627 opts_src);
628 cmd_dst = g_strdup_printf("-machine accel=%s,vsmt=8 -m 256M"
629 " -name target,debug-threads=on"
630 " -serial file:%s/dest_serial"
631 " -incoming %s %s %s",
632 accel, tmpfs, uri,
633 extra_opts ? extra_opts : "", opts_dst);
634 } else if (strcmp(arch, "aarch64") == 0) {
635 init_bootfile(bootpath, aarch64_kernel, sizeof(aarch64_kernel));
636 extra_opts = use_shmem ? get_shmem_opts("150M", shmem_path) : NULL;
637 cmd_src = g_strdup_printf("-machine virt,accel=%s,gic-version=max "
638 "-name vmsource,debug-threads=on -cpu max "
639 "-m 150M -serial file:%s/src_serial "
640 "-kernel %s %s %s",
641 accel, tmpfs, bootpath,
642 extra_opts ? extra_opts : "", opts_src);
643 cmd_dst = g_strdup_printf("-machine virt,accel=%s,gic-version=max "
644 "-name vmdest,debug-threads=on -cpu max "
645 "-m 150M -serial file:%s/dest_serial "
646 "-kernel %s "
647 "-incoming %s %s %s",
648 accel, tmpfs, bootpath, uri,
649 extra_opts ? extra_opts : "", opts_dst);
650
651 start_address = ARM_TEST_MEM_START;
652 end_address = ARM_TEST_MEM_END;
653
654 g_assert(sizeof(aarch64_kernel) <= ARM_TEST_MAX_KERNEL_SIZE);
655 } else {
656 g_assert_not_reached();
657 }
658
659 g_free(bootpath);
660 g_free(extra_opts);
661
662 if (hide_stderr) {
663 gchar *tmp;
664 tmp = g_strdup_printf("%s 2>/dev/null", cmd_src);
665 g_free(cmd_src);
666 cmd_src = tmp;
667
668 tmp = g_strdup_printf("%s 2>/dev/null", cmd_dst);
669 g_free(cmd_dst);
670 cmd_dst = tmp;
671 }
672
673 *from = qtest_init(cmd_src);
674 g_free(cmd_src);
675
676 *to = qtest_init(cmd_dst);
677 g_free(cmd_dst);
678
679
680
681
682
683 if (use_shmem) {
684 unlink(shmem_path);
685 g_free(shmem_path);
686 }
687
688 return 0;
689}
690
691static void test_migrate_end(QTestState *from, QTestState *to, bool test_dest)
692{
693 unsigned char dest_byte_a, dest_byte_b, dest_byte_c, dest_byte_d;
694
695 qtest_quit(from);
696
697 if (test_dest) {
698 qtest_memread(to, start_address, &dest_byte_a, 1);
699
700
701 do {
702 qtest_memread(to, start_address, &dest_byte_b, 1);
703 usleep(1000 * 10);
704 } while (dest_byte_a == dest_byte_b);
705
706 qtest_qmp_discard_response(to, "{ 'execute' : 'stop'}");
707
708
709 qtest_memread(to, start_address, &dest_byte_c, 1);
710 usleep(1000 * 200);
711 qtest_memread(to, start_address, &dest_byte_d, 1);
712 g_assert_cmpint(dest_byte_c, ==, dest_byte_d);
713
714 check_guests_ram(to);
715 }
716
717 qtest_quit(to);
718
719 cleanup("bootsect");
720 cleanup("migsocket");
721 cleanup("src_serial");
722 cleanup("dest_serial");
723}
724
725static void deprecated_set_downtime(QTestState *who, const double value)
726{
727 QDict *rsp;
728
729 rsp = qtest_qmp(who,
730 "{ 'execute': 'migrate_set_downtime',"
731 " 'arguments': { 'value': %f } }", value);
732 g_assert(qdict_haskey(rsp, "return"));
733 qobject_unref(rsp);
734 migrate_check_parameter_int(who, "downtime-limit", value * 1000);
735}
736
737static void deprecated_set_speed(QTestState *who, long long value)
738{
739 QDict *rsp;
740
741 rsp = qtest_qmp(who, "{ 'execute': 'migrate_set_speed',"
742 "'arguments': { 'value': %lld } }", value);
743 g_assert(qdict_haskey(rsp, "return"));
744 qobject_unref(rsp);
745 migrate_check_parameter_int(who, "max-bandwidth", value);
746}
747
748static void deprecated_set_cache_size(QTestState *who, long long value)
749{
750 QDict *rsp;
751
752 rsp = qtest_qmp(who, "{ 'execute': 'migrate-set-cache-size',"
753 "'arguments': { 'value': %lld } }", value);
754 g_assert(qdict_haskey(rsp, "return"));
755 qobject_unref(rsp);
756 migrate_check_parameter_int(who, "xbzrle-cache-size", value);
757}
758
759static void test_deprecated(void)
760{
761 QTestState *from;
762
763 from = qtest_init("-machine none");
764
765 deprecated_set_downtime(from, 0.12345);
766 deprecated_set_speed(from, 12345);
767 deprecated_set_cache_size(from, 4096);
768
769 qtest_quit(from);
770}
771
772static int migrate_postcopy_prepare(QTestState **from_ptr,
773 QTestState **to_ptr,
774 bool hide_error)
775{
776 char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
777 QTestState *from, *to;
778
779 if (test_migrate_start(&from, &to, uri, hide_error, false, NULL, NULL)) {
780 return -1;
781 }
782
783 migrate_set_capability(from, "postcopy-ram", true);
784 migrate_set_capability(to, "postcopy-ram", true);
785 migrate_set_capability(to, "postcopy-blocktime", true);
786
787
788
789
790
791 migrate_set_parameter_int(from, "max-bandwidth", 30000000);
792 migrate_set_parameter_int(from, "downtime-limit", 1);
793
794
795 wait_for_serial("src_serial");
796
797 migrate(from, uri, "{}");
798 g_free(uri);
799
800 wait_for_migration_pass(from);
801
802 *from_ptr = from;
803 *to_ptr = to;
804
805 return 0;
806}
807
808static void migrate_postcopy_complete(QTestState *from, QTestState *to)
809{
810 wait_for_migration_complete(from);
811
812
813 wait_for_serial("dest_serial");
814
815 if (uffd_feature_thread_id) {
816 read_blocktime(to);
817 }
818
819 test_migrate_end(from, to, true);
820}
821
822static void test_postcopy(void)
823{
824 QTestState *from, *to;
825
826 if (migrate_postcopy_prepare(&from, &to, false)) {
827 return;
828 }
829 migrate_postcopy_start(from, to);
830 migrate_postcopy_complete(from, to);
831}
832
833static void test_postcopy_recovery(void)
834{
835 QTestState *from, *to;
836 char *uri;
837
838 if (migrate_postcopy_prepare(&from, &to, true)) {
839 return;
840 }
841
842
843 migrate_set_parameter_int(from, "max-postcopy-bandwidth", 4096);
844
845
846 migrate_postcopy_start(from, to);
847
848
849
850
851
852 wait_for_migration_status(from, "postcopy-active", NULL);
853
854
855
856
857
858 migrate_pause(from);
859
860
861
862
863
864
865 wait_for_migration_status(to, "postcopy-paused",
866 (const char * []) { "failed", "active",
867 "completed", NULL });
868
869
870
871
872
873
874 uri = g_strdup_printf("unix:%s/migsocket-recover", tmpfs);
875 migrate_recover(to, uri);
876
877
878
879
880
881 wait_for_migration_status(from, "postcopy-paused",
882 (const char * []) { "failed", "active",
883 "completed", NULL });
884 migrate(from, uri, "{'resume': true}");
885 g_free(uri);
886
887
888 migrate_set_parameter_int(from, "max-postcopy-bandwidth", 0);
889
890 migrate_postcopy_complete(from, to);
891}
892
893static void wait_for_migration_fail(QTestState *from, bool allow_active)
894{
895 QDict *rsp_return;
896 char *status;
897 bool failed;
898
899 do {
900 status = migrate_query_status(from);
901 bool result = !strcmp(status, "setup") || !strcmp(status, "failed") ||
902 (allow_active && !strcmp(status, "active"));
903 if (!result) {
904 fprintf(stderr, "%s: unexpected status status=%s allow_active=%d\n",
905 __func__, status, allow_active);
906 }
907 g_assert(result);
908 failed = !strcmp(status, "failed");
909 g_free(status);
910 } while (!failed);
911
912
913 rsp_return = wait_command(from, "{ 'execute': 'query-status' }");
914 g_assert(qdict_haskey(rsp_return, "running"));
915 g_assert(qdict_get_bool(rsp_return, "running"));
916 qobject_unref(rsp_return);
917}
918
919static void test_baddest(void)
920{
921 QTestState *from, *to;
922
923 if (test_migrate_start(&from, &to, "tcp:0:0", true, false, NULL, NULL)) {
924 return;
925 }
926 migrate(from, "tcp:0:0", "{}");
927 wait_for_migration_fail(from, false);
928 test_migrate_end(from, to, false);
929}
930
931static void test_precopy_unix(void)
932{
933 char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
934 QTestState *from, *to;
935
936 if (test_migrate_start(&from, &to, uri, false, false, NULL, NULL)) {
937 return;
938 }
939
940
941
942
943
944
945 migrate_set_parameter_int(from, "downtime-limit", 1);
946
947 migrate_set_parameter_int(from, "max-bandwidth", 1000000000);
948
949
950 wait_for_serial("src_serial");
951
952 migrate(from, uri, "{}");
953
954 wait_for_migration_pass(from);
955
956
957 migrate_set_parameter_int(from, "downtime-limit", 300);
958
959 if (!got_stop) {
960 qtest_qmp_eventwait(from, "STOP");
961 }
962
963 qtest_qmp_eventwait(to, "RESUME");
964
965 wait_for_serial("dest_serial");
966 wait_for_migration_complete(from);
967
968 test_migrate_end(from, to, true);
969 g_free(uri);
970}
971
972#if 0
973
974static void test_ignore_shared(void)
975{
976 char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
977 QTestState *from, *to;
978
979 if (test_migrate_start(&from, &to, uri, false, true, NULL, NULL)) {
980 return;
981 }
982
983 migrate_set_capability(from, "x-ignore-shared", true);
984 migrate_set_capability(to, "x-ignore-shared", true);
985
986
987 wait_for_serial("src_serial");
988
989 migrate(from, uri, "{}");
990
991 wait_for_migration_pass(from);
992
993 if (!got_stop) {
994 qtest_qmp_eventwait(from, "STOP");
995 }
996
997 qtest_qmp_eventwait(to, "RESUME");
998
999 wait_for_serial("dest_serial");
1000 wait_for_migration_complete(from);
1001
1002
1003 g_assert_cmpint(read_ram_property_int(from, "transferred"), <, 1024 * 1024);
1004
1005 test_migrate_end(from, to, true);
1006 g_free(uri);
1007}
1008#endif
1009
1010static void test_xbzrle(const char *uri)
1011{
1012 QTestState *from, *to;
1013
1014 if (test_migrate_start(&from, &to, uri, false, false, NULL, NULL)) {
1015 return;
1016 }
1017
1018
1019
1020
1021
1022
1023
1024 migrate_set_parameter_int(from, "downtime-limit", 1);
1025
1026 migrate_set_parameter_int(from, "max-bandwidth", 1000000000);
1027
1028 migrate_set_parameter_int(from, "xbzrle-cache-size", 33554432);
1029
1030 migrate_set_capability(from, "xbzrle", "true");
1031 migrate_set_capability(to, "xbzrle", "true");
1032
1033 wait_for_serial("src_serial");
1034
1035 migrate(from, uri, "{}");
1036
1037 wait_for_migration_pass(from);
1038
1039
1040 migrate_set_parameter_int(from, "downtime-limit", 300);
1041
1042 if (!got_stop) {
1043 qtest_qmp_eventwait(from, "STOP");
1044 }
1045 qtest_qmp_eventwait(to, "RESUME");
1046
1047 wait_for_serial("dest_serial");
1048 wait_for_migration_complete(from);
1049
1050 test_migrate_end(from, to, true);
1051}
1052
1053static void test_xbzrle_unix(void)
1054{
1055 char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
1056
1057 test_xbzrle(uri);
1058 g_free(uri);
1059}
1060
1061static void test_precopy_tcp(void)
1062{
1063 char *uri;
1064 QTestState *from, *to;
1065
1066 if (test_migrate_start(&from, &to, "tcp:127.0.0.1:0", false, false,
1067 NULL, NULL)) {
1068 return;
1069 }
1070
1071
1072
1073
1074
1075
1076
1077 migrate_set_parameter_int(from, "downtime-limit", 1);
1078
1079 migrate_set_parameter_int(from, "max-bandwidth", 1000000000);
1080
1081
1082 wait_for_serial("src_serial");
1083
1084 uri = migrate_get_socket_address(to, "socket-address");
1085
1086 migrate(from, uri, "{}");
1087
1088 wait_for_migration_pass(from);
1089
1090
1091 migrate_set_parameter_int(from, "downtime-limit", 300);
1092
1093 if (!got_stop) {
1094 qtest_qmp_eventwait(from, "STOP");
1095 }
1096 qtest_qmp_eventwait(to, "RESUME");
1097
1098 wait_for_serial("dest_serial");
1099 wait_for_migration_complete(from);
1100
1101 test_migrate_end(from, to, true);
1102 g_free(uri);
1103}
1104
1105static void test_migrate_fd_proto(void)
1106{
1107 QTestState *from, *to;
1108 int ret;
1109 int pair[2];
1110 QDict *rsp;
1111 const char *error_desc;
1112
1113 if (test_migrate_start(&from, &to, "defer", false, false, NULL, NULL)) {
1114 return;
1115 }
1116
1117
1118
1119
1120
1121
1122
1123 migrate_set_parameter_int(from, "downtime-limit", 1);
1124
1125 migrate_set_parameter_int(from, "max-bandwidth", 1000000000);
1126
1127
1128 wait_for_serial("src_serial");
1129
1130
1131 ret = socketpair(PF_LOCAL, SOCK_STREAM, 0, pair);
1132 g_assert_cmpint(ret, ==, 0);
1133
1134
1135 rsp = wait_command_fd(to, pair[0],
1136 "{ 'execute': 'getfd',"
1137 " 'arguments': { 'fdname': 'fd-mig' }}");
1138 qobject_unref(rsp);
1139 close(pair[0]);
1140
1141
1142 rsp = wait_command(to, "{ 'execute': 'migrate-incoming',"
1143 " 'arguments': { 'uri': 'fd:fd-mig' }}");
1144 qobject_unref(rsp);
1145
1146
1147 rsp = wait_command_fd(from, pair[1],
1148 "{ 'execute': 'getfd',"
1149 " 'arguments': { 'fdname': 'fd-mig' }}");
1150 qobject_unref(rsp);
1151 close(pair[1]);
1152
1153
1154 migrate(from, "fd:fd-mig", "{}");
1155
1156 wait_for_migration_pass(from);
1157
1158
1159 migrate_set_parameter_int(from, "downtime-limit", 300);
1160
1161 if (!got_stop) {
1162 qtest_qmp_eventwait(from, "STOP");
1163 }
1164 qtest_qmp_eventwait(to, "RESUME");
1165
1166
1167
1168
1169 rsp = qtest_qmp(from, "{ 'execute': 'closefd',"
1170 " 'arguments': { 'fdname': 'fd-mig' }}");
1171 g_assert_true(qdict_haskey(rsp, "error"));
1172 error_desc = qdict_get_str(qdict_get_qdict(rsp, "error"), "desc");
1173 g_assert_cmpstr(error_desc, ==, "File descriptor named 'fd-mig' not found");
1174 qobject_unref(rsp);
1175
1176 rsp = qtest_qmp(to, "{ 'execute': 'closefd',"
1177 " 'arguments': { 'fdname': 'fd-mig' }}");
1178 g_assert_true(qdict_haskey(rsp, "error"));
1179 error_desc = qdict_get_str(qdict_get_qdict(rsp, "error"), "desc");
1180 g_assert_cmpstr(error_desc, ==, "File descriptor named 'fd-mig' not found");
1181 qobject_unref(rsp);
1182
1183
1184 wait_for_serial("dest_serial");
1185 wait_for_migration_complete(from);
1186 test_migrate_end(from, to, true);
1187}
1188
1189static void do_test_validate_uuid(const char *uuid_arg_src,
1190 const char *uuid_arg_dst,
1191 bool should_fail, bool hide_stderr)
1192{
1193 char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
1194 QTestState *from, *to;
1195
1196 if (test_migrate_start(&from, &to, uri, hide_stderr, false,
1197 uuid_arg_src, uuid_arg_dst)) {
1198 return;
1199 }
1200
1201
1202
1203
1204
1205
1206 migrate_set_parameter_int(from, "downtime-limit", 1000000);
1207 migrate_set_capability(from, "validate-uuid", true);
1208
1209
1210 wait_for_serial("src_serial");
1211
1212 migrate(from, uri, "{}");
1213
1214 if (should_fail) {
1215 qtest_set_expected_status(to, 1);
1216 wait_for_migration_fail(from, true);
1217 } else {
1218 wait_for_migration_complete(from);
1219 }
1220
1221 test_migrate_end(from, to, false);
1222 g_free(uri);
1223}
1224
1225static void test_validate_uuid(void)
1226{
1227 do_test_validate_uuid("-uuid 11111111-1111-1111-1111-111111111111",
1228 "-uuid 11111111-1111-1111-1111-111111111111",
1229 false, false);
1230}
1231
1232static void test_validate_uuid_error(void)
1233{
1234 do_test_validate_uuid("-uuid 11111111-1111-1111-1111-111111111111",
1235 "-uuid 22222222-2222-2222-2222-222222222222",
1236 true, true);
1237}
1238
1239static void test_validate_uuid_src_not_set(void)
1240{
1241 do_test_validate_uuid(NULL, "-uuid 11111111-1111-1111-1111-111111111111",
1242 false, true);
1243}
1244
1245static void test_validate_uuid_dst_not_set(void)
1246{
1247 do_test_validate_uuid("-uuid 11111111-1111-1111-1111-111111111111", NULL,
1248 false, true);
1249}
1250
1251static void test_migrate_auto_converge(void)
1252{
1253 char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
1254 QTestState *from, *to;
1255 int64_t remaining, percentage;
1256
1257
1258
1259
1260
1261
1262 const int64_t init_pct = 5, inc_pct = 50, max_pct = 95;
1263 const int64_t max_bandwidth = 400000000;
1264 const int64_t downtime_limit = 250;
1265
1266
1267
1268
1269
1270 const int64_t expected_threshold = max_bandwidth * downtime_limit / 1000;
1271
1272 if (test_migrate_start(&from, &to, uri, false, false, NULL, NULL)) {
1273 return;
1274 }
1275
1276 migrate_set_capability(from, "auto-converge", true);
1277 migrate_set_parameter_int(from, "cpu-throttle-initial", init_pct);
1278 migrate_set_parameter_int(from, "cpu-throttle-increment", inc_pct);
1279 migrate_set_parameter_int(from, "max-cpu-throttle", max_pct);
1280
1281
1282
1283
1284
1285 migrate_set_parameter_int(from, "downtime-limit", 1);
1286 migrate_set_parameter_int(from, "max-bandwidth", 100000000);
1287
1288
1289 migrate_set_capability(from, "pause-before-switchover", true);
1290
1291
1292 wait_for_serial("src_serial");
1293
1294 migrate(from, uri, "{}");
1295
1296
1297 percentage = 0;
1298 while (percentage == 0) {
1299 percentage = read_migrate_property_int(from, "cpu-throttle-percentage");
1300 usleep(100);
1301 g_assert_false(got_stop);
1302 }
1303
1304 g_assert_cmpint(percentage, ==, init_pct);
1305
1306 migrate_set_parameter_int(from, "downtime-limit", downtime_limit);
1307 migrate_set_parameter_int(from, "max-bandwidth", max_bandwidth);
1308
1309
1310
1311
1312
1313 wait_for_migration_status(from, "pre-switchover", NULL);
1314
1315
1316 percentage = read_migrate_property_int(from, "cpu-throttle-percentage");
1317 g_assert_cmpint(percentage, <=, max_pct);
1318
1319 remaining = read_ram_property_int(from, "remaining");
1320 g_assert_cmpint(remaining, <, expected_threshold);
1321
1322 migrate_continue(from, "pre-switchover");
1323
1324 qtest_qmp_eventwait(to, "RESUME");
1325
1326 wait_for_serial("dest_serial");
1327 wait_for_migration_complete(from);
1328
1329 g_free(uri);
1330
1331 test_migrate_end(from, to, true);
1332}
1333
1334int main(int argc, char **argv)
1335{
1336 char template[] = "/tmp/migration-test-XXXXXX";
1337 int ret;
1338
1339 g_test_init(&argc, &argv, NULL);
1340
1341 if (!ufd_version_check()) {
1342 return g_test_run();
1343 }
1344
1345
1346
1347
1348
1349
1350 if (g_str_equal(qtest_get_arch(), "ppc64") &&
1351 access("/sys/module/kvm_hv", F_OK)) {
1352 g_test_message("Skipping test: kvm_hv not available");
1353 return g_test_run();
1354 }
1355
1356
1357
1358
1359
1360 if (g_str_equal(qtest_get_arch(), "s390x")) {
1361#if defined(HOST_S390X)
1362 if (access("/dev/kvm", R_OK | W_OK)) {
1363 g_test_message("Skipping test: kvm not available");
1364 return g_test_run();
1365 }
1366#else
1367 g_test_message("Skipping test: Need s390x host to work properly");
1368 return g_test_run();
1369#endif
1370 }
1371
1372 tmpfs = mkdtemp(template);
1373 if (!tmpfs) {
1374 g_test_message("mkdtemp on path (%s): %s", template, strerror(errno));
1375 }
1376 g_assert(tmpfs);
1377
1378 module_call_init(MODULE_INIT_QOM);
1379
1380 qtest_add_func("/migration/postcopy/unix", test_postcopy);
1381 qtest_add_func("/migration/postcopy/recovery", test_postcopy_recovery);
1382 qtest_add_func("/migration/deprecated", test_deprecated);
1383 qtest_add_func("/migration/bad_dest", test_baddest);
1384 qtest_add_func("/migration/precopy/unix", test_precopy_unix);
1385 qtest_add_func("/migration/precopy/tcp", test_precopy_tcp);
1386
1387 qtest_add_func("/migration/xbzrle/unix", test_xbzrle_unix);
1388 qtest_add_func("/migration/fd_proto", test_migrate_fd_proto);
1389 qtest_add_func("/migration/validate_uuid", test_validate_uuid);
1390 qtest_add_func("/migration/validate_uuid_error", test_validate_uuid_error);
1391 qtest_add_func("/migration/validate_uuid_src_not_set",
1392 test_validate_uuid_src_not_set);
1393 qtest_add_func("/migration/validate_uuid_dst_not_set",
1394 test_validate_uuid_dst_not_set);
1395
1396 qtest_add_func("/migration/auto_converge", test_migrate_auto_converge);
1397
1398 ret = g_test_run();
1399
1400 g_assert_cmpint(ret, ==, 0);
1401
1402 ret = rmdir(tmpfs);
1403 if (ret != 0) {
1404 g_test_message("unable to rmdir: path (%s): %s",
1405 tmpfs, strerror(errno));
1406 }
1407
1408 return ret;
1409}
1410