tests: Remove deprecated migration tests commands
[qemu/ar7.git] / tests / migration-test.c
blob0428d450df91704961c9f6346132b87e7f15e5bb
1 /*
2 * QTest testcase for migration
4 * Copyright (c) 2016 Red Hat, Inc. and/or its affiliates
5 * based on the vhost-user-test.c that is:
6 * Copyright (c) 2014 Virtual Open Systems Sarl.
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.
13 #include "qemu/osdep.h"
15 #include "libqtest.h"
16 #include "qemu/option.h"
17 #include "qemu/range.h"
18 #include "qemu/sockets.h"
19 #include "chardev/char.h"
20 #include "sysemu/sysemu.h"
21 #include "hw/nvram/chrp_nvram.h"
23 #define MIN_NVRAM_SIZE 8192 /* from spapr_nvram.c */
25 const unsigned start_address = 1024 * 1024;
26 const unsigned end_address = 100 * 1024 * 1024;
27 bool got_stop;
29 #if defined(__linux__)
30 #include <sys/syscall.h>
31 #include <sys/vfs.h>
32 #endif
34 #if defined(__linux__) && defined(__NR_userfaultfd) && defined(CONFIG_EVENTFD)
35 #include <sys/eventfd.h>
36 #include <sys/ioctl.h>
37 #include <linux/userfaultfd.h>
39 static bool ufd_version_check(void)
41 struct uffdio_api api_struct;
42 uint64_t ioctl_mask;
44 int ufd = syscall(__NR_userfaultfd, O_CLOEXEC);
46 if (ufd == -1) {
47 g_test_message("Skipping test: userfaultfd not available");
48 return false;
51 api_struct.api = UFFD_API;
52 api_struct.features = 0;
53 if (ioctl(ufd, UFFDIO_API, &api_struct)) {
54 g_test_message("Skipping test: UFFDIO_API failed");
55 return false;
58 ioctl_mask = (__u64)1 << _UFFDIO_REGISTER |
59 (__u64)1 << _UFFDIO_UNREGISTER;
60 if ((api_struct.ioctls & ioctl_mask) != ioctl_mask) {
61 g_test_message("Skipping test: Missing userfault feature");
62 return false;
65 return true;
68 #else
69 static bool ufd_version_check(void)
71 g_test_message("Skipping test: Userfault not available (builtdtime)");
72 return false;
75 #endif
77 static const char *tmpfs;
79 /* A simple PC boot sector that modifies memory (1-100MB) quickly
80 * outputing a 'B' every so often if it's still running.
82 unsigned char bootsect[] = {
83 0xfa, 0x0f, 0x01, 0x16, 0x74, 0x7c, 0x66, 0xb8, 0x01, 0x00, 0x00, 0x00,
84 0x0f, 0x22, 0xc0, 0x66, 0xea, 0x20, 0x7c, 0x00, 0x00, 0x08, 0x00, 0x00,
85 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x92, 0x0c, 0x02,
86 0xe6, 0x92, 0xb8, 0x10, 0x00, 0x00, 0x00, 0x8e, 0xd8, 0x66, 0xb8, 0x41,
87 0x00, 0x66, 0xba, 0xf8, 0x03, 0xee, 0xb3, 0x00, 0xb8, 0x00, 0x00, 0x10,
88 0x00, 0xfe, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x40,
89 0x06, 0x7c, 0xf2, 0xfe, 0xc3, 0x75, 0xe9, 0x66, 0xb8, 0x42, 0x00, 0x66,
90 0xba, 0xf8, 0x03, 0xee, 0xeb, 0xde, 0x66, 0x90, 0x00, 0x00, 0x00, 0x00,
91 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00,
92 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00, 0x27, 0x00, 0x5c, 0x7c,
93 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
94 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
95 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
98 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
99 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
108 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
109 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
111 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
113 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
114 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
116 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
120 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
122 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
123 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
124 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa
128 static void init_bootfile_x86(const char *bootpath)
130 FILE *bootfile = fopen(bootpath, "wb");
132 g_assert_cmpint(fwrite(bootsect, 512, 1, bootfile), ==, 1);
133 fclose(bootfile);
136 static void init_bootfile_ppc(const char *bootpath)
138 FILE *bootfile;
139 char buf[MIN_NVRAM_SIZE];
140 ChrpNvramPartHdr *header = (ChrpNvramPartHdr *)buf;
142 memset(buf, 0, MIN_NVRAM_SIZE);
144 /* Create a "common" partition in nvram to store boot-command property */
146 header->signature = CHRP_NVPART_SYSTEM;
147 memcpy(header->name, "common", 6);
148 chrp_nvram_finish_partition(header, MIN_NVRAM_SIZE);
150 /* FW_MAX_SIZE is 4MB, but slof.bin is only 900KB,
151 * so let's modify memory between 1MB and 100MB
152 * to do like PC bootsector
155 sprintf(buf + 16,
156 "boot-command=hex .\" _\" begin %x %x do i c@ 1 + i c! 1000 +loop "
157 ".\" B\" 0 until", end_address, start_address);
159 /* Write partition to the NVRAM file */
161 bootfile = fopen(bootpath, "wb");
162 g_assert_cmpint(fwrite(buf, MIN_NVRAM_SIZE, 1, bootfile), ==, 1);
163 fclose(bootfile);
167 * Wait for some output in the serial output file,
168 * we get an 'A' followed by an endless string of 'B's
169 * but on the destination we won't have the A.
171 static void wait_for_serial(const char *side)
173 char *serialpath = g_strdup_printf("%s/%s", tmpfs, side);
174 FILE *serialfile = fopen(serialpath, "r");
175 const char *arch = qtest_get_arch();
176 int started = (strcmp(side, "src_serial") == 0 &&
177 strcmp(arch, "ppc64") == 0) ? 0 : 1;
179 g_free(serialpath);
180 do {
181 int readvalue = fgetc(serialfile);
183 if (!started) {
184 /* SLOF prints its banner before starting test,
185 * to ignore it, mark the start of the test with '_',
186 * ignore all characters until this marker
188 switch (readvalue) {
189 case '_':
190 started = 1;
191 break;
192 case EOF:
193 fseek(serialfile, 0, SEEK_SET);
194 usleep(1000);
195 break;
197 continue;
199 switch (readvalue) {
200 case 'A':
201 /* Fine */
202 break;
204 case 'B':
205 /* It's alive! */
206 fclose(serialfile);
207 return;
209 case EOF:
210 started = (strcmp(side, "src_serial") == 0 &&
211 strcmp(arch, "ppc64") == 0) ? 0 : 1;
212 fseek(serialfile, 0, SEEK_SET);
213 usleep(1000);
214 break;
216 default:
217 fprintf(stderr, "Unexpected %d on %s serial\n", readvalue, side);
218 g_assert_not_reached();
220 } while (true);
224 * Events can get in the way of responses we are actually waiting for.
226 static QDict *wait_command(QTestState *who, const char *command)
228 const char *event_string;
229 QDict *response;
231 response = qtest_qmp(who, command);
233 while (qdict_haskey(response, "event")) {
234 /* OK, it was an event */
235 event_string = qdict_get_str(response, "event");
236 if (!strcmp(event_string, "STOP")) {
237 got_stop = true;
239 QDECREF(response);
240 response = qtest_qmp_receive(who);
242 return response;
247 * It's tricky to use qemu's migration event capability with qtest,
248 * events suddenly appearing confuse the qmp()/hmp() responses.
251 static uint64_t get_migration_pass(QTestState *who)
253 QDict *rsp, *rsp_return, *rsp_ram;
254 uint64_t result;
256 rsp = wait_command(who, "{ 'execute': 'query-migrate' }");
257 rsp_return = qdict_get_qdict(rsp, "return");
258 if (!qdict_haskey(rsp_return, "ram")) {
259 /* Still in setup */
260 result = 0;
261 } else {
262 rsp_ram = qdict_get_qdict(rsp_return, "ram");
263 result = qdict_get_try_int(rsp_ram, "dirty-sync-count", 0);
265 QDECREF(rsp);
266 return result;
269 static void wait_for_migration_complete(QTestState *who)
271 QDict *rsp, *rsp_return;
272 bool completed;
274 do {
275 const char *status;
277 rsp = wait_command(who, "{ 'execute': 'query-migrate' }");
278 rsp_return = qdict_get_qdict(rsp, "return");
279 status = qdict_get_str(rsp_return, "status");
280 completed = strcmp(status, "completed") == 0;
281 g_assert_cmpstr(status, !=, "failed");
282 QDECREF(rsp);
283 usleep(1000 * 100);
284 } while (!completed);
287 static void wait_for_migration_pass(QTestState *who)
289 uint64_t initial_pass = get_migration_pass(who);
290 uint64_t pass;
292 /* Wait for the 1st sync */
293 do {
294 initial_pass = get_migration_pass(who);
295 if (got_stop || initial_pass) {
296 break;
298 usleep(1000 * 100);
299 } while (true);
301 do {
302 usleep(1000 * 100);
303 pass = get_migration_pass(who);
304 } while (pass == initial_pass && !got_stop);
307 static void check_guests_ram(QTestState *who)
309 /* Our ASM test will have been incrementing one byte from each page from
310 * 1MB to <100MB in order.
311 * This gives us a constraint that any page's byte should be equal or less
312 * than the previous pages byte (mod 256); and they should all be equal
313 * except for one transition at the point where we meet the incrementer.
314 * (We're running this with the guest stopped).
316 unsigned address;
317 uint8_t first_byte;
318 uint8_t last_byte;
319 bool hit_edge = false;
320 bool bad = false;
322 qtest_memread(who, start_address, &first_byte, 1);
323 last_byte = first_byte;
325 for (address = start_address + 4096; address < end_address; address += 4096)
327 uint8_t b;
328 qtest_memread(who, address, &b, 1);
329 if (b != last_byte) {
330 if (((b + 1) % 256) == last_byte && !hit_edge) {
331 /* This is OK, the guest stopped at the point of
332 * incrementing the previous page but didn't get
333 * to us yet.
335 hit_edge = true;
336 } else {
337 fprintf(stderr, "Memory content inconsistency at %x"
338 " first_byte = %x last_byte = %x current = %x"
339 " hit_edge = %x\n",
340 address, first_byte, last_byte, b, hit_edge);
341 bad = true;
344 last_byte = b;
346 g_assert_false(bad);
349 static void cleanup(const char *filename)
351 char *path = g_strdup_printf("%s/%s", tmpfs, filename);
353 unlink(path);
354 g_free(path);
357 static void migrate_check_parameter(QTestState *who, const char *parameter,
358 const char *value)
360 QDict *rsp, *rsp_return;
361 char *result;
363 rsp = wait_command(who, "{ 'execute': 'query-migrate-parameters' }");
364 rsp_return = qdict_get_qdict(rsp, "return");
365 result = g_strdup_printf("%" PRId64,
366 qdict_get_try_int(rsp_return, parameter, -1));
367 g_assert_cmpstr(result, ==, value);
368 g_free(result);
369 QDECREF(rsp);
372 static void migrate_set_parameter(QTestState *who, const char *parameter,
373 const char *value)
375 QDict *rsp;
376 gchar *cmd;
378 cmd = g_strdup_printf("{ 'execute': 'migrate-set-parameters',"
379 "'arguments': { '%s': %s } }",
380 parameter, value);
381 rsp = qtest_qmp(who, cmd);
382 g_free(cmd);
383 g_assert(qdict_haskey(rsp, "return"));
384 QDECREF(rsp);
385 migrate_check_parameter(who, parameter, value);
388 static void migrate_set_capability(QTestState *who, const char *capability,
389 const char *value)
391 QDict *rsp;
392 gchar *cmd;
394 cmd = g_strdup_printf("{ 'execute': 'migrate-set-capabilities',"
395 "'arguments': { "
396 "'capabilities': [ { "
397 "'capability': '%s', 'state': %s } ] } }",
398 capability, value);
399 rsp = qtest_qmp(who, cmd);
400 g_free(cmd);
401 g_assert(qdict_haskey(rsp, "return"));
402 QDECREF(rsp);
405 static void migrate(QTestState *who, const char *uri)
407 QDict *rsp;
408 gchar *cmd;
410 cmd = g_strdup_printf("{ 'execute': 'migrate',"
411 "'arguments': { 'uri': '%s' } }",
412 uri);
413 rsp = qtest_qmp(who, cmd);
414 g_free(cmd);
415 g_assert(qdict_haskey(rsp, "return"));
416 QDECREF(rsp);
419 static void test_migrate_start(QTestState **from, QTestState **to,
420 const char *uri)
422 gchar *cmd_src, *cmd_dst;
423 char *bootpath = g_strdup_printf("%s/bootsect", tmpfs);
424 const char *arch = qtest_get_arch();
426 got_stop = false;
428 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
429 init_bootfile_x86(bootpath);
430 cmd_src = g_strdup_printf("-machine accel=kvm:tcg -m 150M"
431 " -name pcsource,debug-threads=on"
432 " -serial file:%s/src_serial"
433 " -drive file=%s,format=raw",
434 tmpfs, bootpath);
435 cmd_dst = g_strdup_printf("-machine accel=kvm:tcg -m 150M"
436 " -name pcdest,debug-threads=on"
437 " -serial file:%s/dest_serial"
438 " -drive file=%s,format=raw"
439 " -incoming %s",
440 tmpfs, bootpath, uri);
441 } else if (strcmp(arch, "ppc64") == 0) {
442 const char *accel;
444 /* On ppc64, the test only works with kvm-hv, but not with kvm-pr */
445 accel = access("/sys/module/kvm_hv", F_OK) ? "tcg" : "kvm:tcg";
446 init_bootfile_ppc(bootpath);
447 cmd_src = g_strdup_printf("-machine accel=%s -m 256M"
448 " -name pcsource,debug-threads=on"
449 " -serial file:%s/src_serial"
450 " -drive file=%s,if=pflash,format=raw",
451 accel, tmpfs, bootpath);
452 cmd_dst = g_strdup_printf("-machine accel=%s -m 256M"
453 " -name pcdest,debug-threads=on"
454 " -serial file:%s/dest_serial"
455 " -incoming %s",
456 accel, tmpfs, uri);
457 } else {
458 g_assert_not_reached();
461 g_free(bootpath);
463 *from = qtest_start(cmd_src);
464 g_free(cmd_src);
466 *to = qtest_init(cmd_dst);
467 g_free(cmd_dst);
470 static void test_migrate_end(QTestState *from, QTestState *to)
472 unsigned char dest_byte_a, dest_byte_b, dest_byte_c, dest_byte_d;
474 qtest_quit(from);
476 qtest_memread(to, start_address, &dest_byte_a, 1);
478 /* Destination still running, wait for a byte to change */
479 do {
480 qtest_memread(to, start_address, &dest_byte_b, 1);
481 usleep(10 * 1000);
482 } while (dest_byte_a == dest_byte_b);
484 qtest_qmp_discard_response(to, "{ 'execute' : 'stop'}");
485 /* With it stopped, check nothing changes */
486 qtest_memread(to, start_address, &dest_byte_c, 1);
487 sleep(1);
488 qtest_memread(to, start_address, &dest_byte_d, 1);
489 g_assert_cmpint(dest_byte_c, ==, dest_byte_d);
491 check_guests_ram(to);
493 qtest_quit(to);
495 cleanup("bootsect");
496 cleanup("migsocket");
497 cleanup("src_serial");
498 cleanup("dest_serial");
501 static void test_migrate(void)
503 char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
504 QTestState *from, *to;
505 QDict *rsp;
507 test_migrate_start(&from, &to, uri);
509 migrate_set_capability(from, "postcopy-ram", "true");
510 migrate_set_capability(to, "postcopy-ram", "true");
512 /* We want to pick a speed slow enough that the test completes
513 * quickly, but that it doesn't complete precopy even on a slow
514 * machine, so also set the downtime.
516 migrate_set_parameter(from, "max-bandwidth", "100000000");
517 migrate_set_parameter(from, "downtime-limit", "1");
519 /* Wait for the first serial output from the source */
520 wait_for_serial("src_serial");
522 migrate(from, uri);
524 wait_for_migration_pass(from);
526 rsp = wait_command(from, "{ 'execute': 'migrate-start-postcopy' }");
527 g_assert(qdict_haskey(rsp, "return"));
528 QDECREF(rsp);
530 if (!got_stop) {
531 qtest_qmp_eventwait(from, "STOP");
534 qtest_qmp_eventwait(to, "RESUME");
536 wait_for_serial("dest_serial");
537 wait_for_migration_complete(from);
539 g_free(uri);
541 test_migrate_end(from, to);
544 int main(int argc, char **argv)
546 char template[] = "/tmp/migration-test-XXXXXX";
547 int ret;
549 g_test_init(&argc, &argv, NULL);
551 if (!ufd_version_check()) {
552 return 0;
555 tmpfs = mkdtemp(template);
556 if (!tmpfs) {
557 g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno));
559 g_assert(tmpfs);
561 module_call_init(MODULE_INIT_QOM);
563 qtest_add_func("/migration/postcopy/unix", test_migrate);
565 ret = g_test_run();
567 g_assert_cmpint(ret, ==, 0);
569 ret = rmdir(tmpfs);
570 if (ret != 0) {
571 g_test_message("unable to rmdir: path (%s): %s\n",
572 tmpfs, strerror(errno));
575 return ret;