]> git.proxmox.com Git - mirror_qemu.git/blame - tests/migration-test.c
migration: improve documentation of postcopy-ram
[mirror_qemu.git] / tests / migration-test.c
CommitLineData
ea0c6d62 1/*
2656bfd9 2 * QTest testcase for migration
ea0c6d62
DDAG
3 *
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.
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
DDAG
14
15#include "libqtest.h"
452fcdbc 16#include "qapi/qmp/qdict.h"
ea0c6d62
DDAG
17#include "qemu/option.h"
18#include "qemu/range.h"
a9c94277 19#include "qemu/sockets.h"
8228e353 20#include "chardev/char.h"
ea0c6d62 21#include "sysemu/sysemu.h"
ad723fe5 22#include "hw/nvram/chrp_nvram.h"
aaf89c8a 23
24#define MIN_NVRAM_SIZE 8192 /* from spapr_nvram.c */
ea0c6d62 25
ea0c6d62
DDAG
26const unsigned start_address = 1024 * 1024;
27const unsigned end_address = 100 * 1024 * 1024;
28bool got_stop;
29
30#if defined(__linux__)
ea0c6d62
DDAG
31#include <sys/syscall.h>
32#include <sys/vfs.h>
33#endif
34
35#if defined(__linux__) && defined(__NR_userfaultfd) && defined(CONFIG_EVENTFD)
36#include <sys/eventfd.h>
37#include <sys/ioctl.h>
38#include <linux/userfaultfd.h>
39
40static bool ufd_version_check(void)
41{
42 struct uffdio_api api_struct;
43 uint64_t ioctl_mask;
44
e1ae9fb6 45 int ufd = syscall(__NR_userfaultfd, O_CLOEXEC);
ea0c6d62
DDAG
46
47 if (ufd == -1) {
48 g_test_message("Skipping test: userfaultfd not available");
49 return false;
50 }
51
52 api_struct.api = UFFD_API;
53 api_struct.features = 0;
54 if (ioctl(ufd, UFFDIO_API, &api_struct)) {
55 g_test_message("Skipping test: UFFDIO_API failed");
56 return false;
57 }
58
59 ioctl_mask = (__u64)1 << _UFFDIO_REGISTER |
60 (__u64)1 << _UFFDIO_UNREGISTER;
61 if ((api_struct.ioctls & ioctl_mask) != ioctl_mask) {
62 g_test_message("Skipping test: Missing userfault feature");
63 return false;
64 }
65
66 return true;
67}
68
69#else
70static bool ufd_version_check(void)
71{
72 g_test_message("Skipping test: Userfault not available (builtdtime)");
73 return false;
74}
75
76#endif
77
78static const char *tmpfs;
79
80/* A simple PC boot sector that modifies memory (1-100MB) quickly
81 * outputing a 'B' every so often if it's still running.
82 */
83unsigned char bootsect[] = {
84 0xfa, 0x0f, 0x01, 0x16, 0x74, 0x7c, 0x66, 0xb8, 0x01, 0x00, 0x00, 0x00,
85 0x0f, 0x22, 0xc0, 0x66, 0xea, 0x20, 0x7c, 0x00, 0x00, 0x08, 0x00, 0x00,
86 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x92, 0x0c, 0x02,
87 0xe6, 0x92, 0xb8, 0x10, 0x00, 0x00, 0x00, 0x8e, 0xd8, 0x66, 0xb8, 0x41,
88 0x00, 0x66, 0xba, 0xf8, 0x03, 0xee, 0xb3, 0x00, 0xb8, 0x00, 0x00, 0x10,
89 0x00, 0xfe, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x40,
90 0x06, 0x7c, 0xf2, 0xfe, 0xc3, 0x75, 0xe9, 0x66, 0xb8, 0x42, 0x00, 0x66,
91 0xba, 0xf8, 0x03, 0xee, 0xeb, 0xde, 0x66, 0x90, 0x00, 0x00, 0x00, 0x00,
92 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00,
93 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00, 0x27, 0x00, 0x5c, 0x7c,
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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa
127};
128
aaf89c8a 129static void init_bootfile_x86(const char *bootpath)
130{
131 FILE *bootfile = fopen(bootpath, "wb");
132
133 g_assert_cmpint(fwrite(bootsect, 512, 1, bootfile), ==, 1);
134 fclose(bootfile);
135}
136
137static void init_bootfile_ppc(const char *bootpath)
138{
139 FILE *bootfile;
140 char buf[MIN_NVRAM_SIZE];
ad723fe5 141 ChrpNvramPartHdr *header = (ChrpNvramPartHdr *)buf;
aaf89c8a 142
143 memset(buf, 0, MIN_NVRAM_SIZE);
144
145 /* Create a "common" partition in nvram to store boot-command property */
146
ad723fe5 147 header->signature = CHRP_NVPART_SYSTEM;
aaf89c8a 148 memcpy(header->name, "common", 6);
ad723fe5 149 chrp_nvram_finish_partition(header, MIN_NVRAM_SIZE);
aaf89c8a 150
151 /* FW_MAX_SIZE is 4MB, but slof.bin is only 900KB,
152 * so let's modify memory between 1MB and 100MB
153 * to do like PC bootsector
154 */
155
156 sprintf(buf + 16,
157 "boot-command=hex .\" _\" begin %x %x do i c@ 1 + i c! 1000 +loop "
158 ".\" B\" 0 until", end_address, start_address);
159
160 /* Write partition to the NVRAM file */
161
162 bootfile = fopen(bootpath, "wb");
163 g_assert_cmpint(fwrite(buf, MIN_NVRAM_SIZE, 1, bootfile), ==, 1);
164 fclose(bootfile);
165}
166
ea0c6d62
DDAG
167/*
168 * Wait for some output in the serial output file,
169 * we get an 'A' followed by an endless string of 'B's
170 * but on the destination we won't have the A.
171 */
172static void wait_for_serial(const char *side)
173{
174 char *serialpath = g_strdup_printf("%s/%s", tmpfs, side);
175 FILE *serialfile = fopen(serialpath, "r");
aaf89c8a 176 const char *arch = qtest_get_arch();
177 int started = (strcmp(side, "src_serial") == 0 &&
178 strcmp(arch, "ppc64") == 0) ? 0 : 1;
ea0c6d62 179
e2dd21e5 180 g_free(serialpath);
ea0c6d62
DDAG
181 do {
182 int readvalue = fgetc(serialfile);
183
aaf89c8a 184 if (!started) {
185 /* SLOF prints its banner before starting test,
186 * to ignore it, mark the start of the test with '_',
187 * ignore all characters until this marker
188 */
189 switch (readvalue) {
190 case '_':
191 started = 1;
192 break;
193 case EOF:
194 fseek(serialfile, 0, SEEK_SET);
195 usleep(1000);
196 break;
197 }
198 continue;
199 }
ea0c6d62
DDAG
200 switch (readvalue) {
201 case 'A':
202 /* Fine */
203 break;
204
205 case 'B':
206 /* It's alive! */
207 fclose(serialfile);
ea0c6d62
DDAG
208 return;
209
210 case EOF:
aaf89c8a 211 started = (strcmp(side, "src_serial") == 0 &&
212 strcmp(arch, "ppc64") == 0) ? 0 : 1;
ea0c6d62
DDAG
213 fseek(serialfile, 0, SEEK_SET);
214 usleep(1000);
215 break;
216
217 default:
218 fprintf(stderr, "Unexpected %d on %s serial\n", readvalue, side);
219 g_assert_not_reached();
220 }
221 } while (true);
222}
223
224/*
225 * Events can get in the way of responses we are actually waiting for.
226 */
863e27a8 227static QDict *wait_command(QTestState *who, const char *command)
ea0c6d62
DDAG
228{
229 const char *event_string;
863e27a8
JQ
230 QDict *response;
231
232 response = qtest_qmp(who, command);
ea0c6d62 233
863e27a8
JQ
234 while (qdict_haskey(response, "event")) {
235 /* OK, it was an event */
236 event_string = qdict_get_str(response, "event");
237 if (!strcmp(event_string, "STOP")) {
238 got_stop = true;
239 }
240 QDECREF(response);
241 response = qtest_qmp_receive(who);
ea0c6d62 242 }
863e27a8 243 return response;
ea0c6d62
DDAG
244}
245
246
247/*
248 * It's tricky to use qemu's migration event capability with qtest,
249 * events suddenly appearing confuse the qmp()/hmp() responses.
ea0c6d62
DDAG
250 */
251
863e27a8 252static uint64_t get_migration_pass(QTestState *who)
ea0c6d62
DDAG
253{
254 QDict *rsp, *rsp_return, *rsp_ram;
255 uint64_t result;
256
863e27a8 257 rsp = wait_command(who, "{ 'execute': 'query-migrate' }");
ea0c6d62
DDAG
258 rsp_return = qdict_get_qdict(rsp, "return");
259 if (!qdict_haskey(rsp_return, "ram")) {
260 /* Still in setup */
261 result = 0;
262 } else {
263 rsp_ram = qdict_get_qdict(rsp_return, "ram");
264 result = qdict_get_try_int(rsp_ram, "dirty-sync-count", 0);
ea0c6d62 265 }
5b1ded22 266 QDECREF(rsp);
ea0c6d62
DDAG
267 return result;
268}
269
863e27a8 270static void wait_for_migration_complete(QTestState *who)
ea0c6d62 271{
6a7724e9
JQ
272 while (true) {
273 QDict *rsp, *rsp_return;
274 bool completed;
ea0c6d62
DDAG
275 const char *status;
276
863e27a8 277 rsp = wait_command(who, "{ 'execute': 'query-migrate' }");
ea0c6d62
DDAG
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);
6a7724e9
JQ
283 if (completed) {
284 return;
285 }
286 usleep(1000);
287 }
ea0c6d62
DDAG
288}
289
863e27a8 290static void wait_for_migration_pass(QTestState *who)
ea0c6d62 291{
863e27a8 292 uint64_t initial_pass = get_migration_pass(who);
ea0c6d62
DDAG
293 uint64_t pass;
294
295 /* Wait for the 1st sync */
6a7724e9
JQ
296 while (!got_stop && !initial_pass) {
297 usleep(1000);
863e27a8 298 initial_pass = get_migration_pass(who);
6a7724e9 299 }
ea0c6d62
DDAG
300
301 do {
6a7724e9 302 usleep(1000);
863e27a8 303 pass = get_migration_pass(who);
ea0c6d62
DDAG
304 } while (pass == initial_pass && !got_stop);
305}
306
7195a871 307static void check_guests_ram(QTestState *who)
ea0c6d62
DDAG
308{
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).
315 */
316 unsigned address;
317 uint8_t first_byte;
318 uint8_t last_byte;
319 bool hit_edge = false;
320 bool bad = false;
321
7195a871 322 qtest_memread(who, start_address, &first_byte, 1);
ea0c6d62
DDAG
323 last_byte = first_byte;
324
325 for (address = start_address + 4096; address < end_address; address += 4096)
326 {
327 uint8_t b;
7195a871 328 qtest_memread(who, address, &b, 1);
ea0c6d62
DDAG
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.
334 */
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;
342 }
343 }
344 last_byte = b;
345 }
346 g_assert_false(bad);
347}
348
349static void cleanup(const char *filename)
350{
351 char *path = g_strdup_printf("%s/%s", tmpfs, filename);
352
353 unlink(path);
e2dd21e5 354 g_free(path);
ea0c6d62
DDAG
355}
356
56b4a42a
JQ
357static void migrate_check_parameter(QTestState *who, const char *parameter,
358 const char *value)
359{
360 QDict *rsp, *rsp_return;
9c43435d 361 char *result;
56b4a42a
JQ
362
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);
9c43435d 368 g_free(result);
56b4a42a
JQ
369 QDECREF(rsp);
370}
371
1f90d797
JQ
372static void migrate_set_parameter(QTestState *who, const char *parameter,
373 const char *value)
d62fbe60
JQ
374{
375 QDict *rsp;
376 gchar *cmd;
377
1f90d797
JQ
378 cmd = g_strdup_printf("{ 'execute': 'migrate-set-parameters',"
379 "'arguments': { '%s': %s } }",
380 parameter, value);
d62fbe60
JQ
381 rsp = qtest_qmp(who, cmd);
382 g_free(cmd);
383 g_assert(qdict_haskey(rsp, "return"));
384 QDECREF(rsp);
1f90d797 385 migrate_check_parameter(who, parameter, value);
d62fbe60
JQ
386}
387
388static void migrate_set_capability(QTestState *who, const char *capability,
389 const char *value)
390{
391 QDict *rsp;
392 gchar *cmd;
393
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);
403}
404
405static void migrate(QTestState *who, const char *uri)
406{
407 QDict *rsp;
408 gchar *cmd;
409
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);
417}
418
eb665d7d
JQ
419static void migrate_start_postcopy(QTestState *who)
420{
421 QDict *rsp;
422
423 rsp = wait_command(who, "{ 'execute': 'migrate-start-postcopy' }");
424 g_assert(qdict_haskey(rsp, "return"));
425 QDECREF(rsp);
426}
427
7195a871
JQ
428static void test_migrate_start(QTestState **from, QTestState **to,
429 const char *uri)
ea0c6d62 430{
d62fbe60 431 gchar *cmd_src, *cmd_dst;
ea0c6d62 432 char *bootpath = g_strdup_printf("%s/bootsect", tmpfs);
aaf89c8a 433 const char *arch = qtest_get_arch();
63b2d935 434 const char *accel = "kvm:tcg";
ea0c6d62
DDAG
435
436 got_stop = false;
ea0c6d62 437
aaf89c8a 438 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
439 init_bootfile_x86(bootpath);
63b2d935 440 cmd_src = g_strdup_printf("-machine accel=%s -m 150M"
31a6bb74 441 " -name source,debug-threads=on"
aaf89c8a 442 " -serial file:%s/src_serial"
443 " -drive file=%s,format=raw",
63b2d935
JQ
444 accel, tmpfs, bootpath);
445 cmd_dst = g_strdup_printf("-machine accel=%s -m 150M"
31a6bb74 446 " -name target,debug-threads=on"
aaf89c8a 447 " -serial file:%s/dest_serial"
448 " -drive file=%s,format=raw"
449 " -incoming %s",
63b2d935 450 accel, tmpfs, bootpath, uri);
aaf89c8a 451 } else if (strcmp(arch, "ppc64") == 0) {
171da9d5
TH
452
453 /* On ppc64, the test only works with kvm-hv, but not with kvm-pr */
63b2d935
JQ
454 if (access("/sys/module/kvm_hv", F_OK)) {
455 accel = "tcg";
456 }
aaf89c8a 457 init_bootfile_ppc(bootpath);
171da9d5 458 cmd_src = g_strdup_printf("-machine accel=%s -m 256M"
31a6bb74 459 " -name source,debug-threads=on"
aaf89c8a 460 " -serial file:%s/src_serial"
461 " -drive file=%s,if=pflash,format=raw",
171da9d5
TH
462 accel, tmpfs, bootpath);
463 cmd_dst = g_strdup_printf("-machine accel=%s -m 256M"
31a6bb74 464 " -name target,debug-threads=on"
aaf89c8a 465 " -serial file:%s/dest_serial"
466 " -incoming %s",
171da9d5 467 accel, tmpfs, uri);
aaf89c8a 468 } else {
469 g_assert_not_reached();
470 }
471
e2dd21e5
MAL
472 g_free(bootpath);
473
7195a871 474 *from = qtest_start(cmd_src);
aaf89c8a 475 g_free(cmd_src);
476
7195a871 477 *to = qtest_init(cmd_dst);
aaf89c8a 478 g_free(cmd_dst);
7195a871
JQ
479}
480
481static void test_migrate_end(QTestState *from, QTestState *to)
482{
483 unsigned char dest_byte_a, dest_byte_b, dest_byte_c, dest_byte_d;
484
485 qtest_quit(from);
486
487 qtest_memread(to, start_address, &dest_byte_a, 1);
488
489 /* Destination still running, wait for a byte to change */
490 do {
491 qtest_memread(to, start_address, &dest_byte_b, 1);
6a7724e9 492 usleep(1000 * 10);
7195a871
JQ
493 } while (dest_byte_a == dest_byte_b);
494
495 qtest_qmp_discard_response(to, "{ 'execute' : 'stop'}");
496 /* With it stopped, check nothing changes */
497 qtest_memread(to, start_address, &dest_byte_c, 1);
6a7724e9 498 usleep(1000 * 200);
7195a871
JQ
499 qtest_memread(to, start_address, &dest_byte_d, 1);
500 g_assert_cmpint(dest_byte_c, ==, dest_byte_d);
501
502 check_guests_ram(to);
503
504 qtest_quit(to);
505
506 cleanup("bootsect");
507 cleanup("migsocket");
508 cleanup("src_serial");
509 cleanup("dest_serial");
510}
511
4c27486d
JQ
512static void deprecated_set_downtime(QTestState *who, const double value)
513{
514 QDict *rsp;
515 gchar *cmd;
516 char *expected;
517 int64_t result_int;
518
519 cmd = g_strdup_printf("{ 'execute': 'migrate_set_downtime',"
520 "'arguments': { 'value': %g } }", value);
521 rsp = qtest_qmp(who, cmd);
522 g_free(cmd);
523 g_assert(qdict_haskey(rsp, "return"));
524 QDECREF(rsp);
525 result_int = value * 1000L;
526 expected = g_strdup_printf("%" PRId64, result_int);
527 migrate_check_parameter(who, "downtime-limit", expected);
528 g_free(expected);
529}
530
531static void deprecated_set_speed(QTestState *who, const char *value)
532{
533 QDict *rsp;
534 gchar *cmd;
535
536 cmd = g_strdup_printf("{ 'execute': 'migrate_set_speed',"
537 "'arguments': { 'value': %s } }", value);
538 rsp = qtest_qmp(who, cmd);
539 g_free(cmd);
540 g_assert(qdict_haskey(rsp, "return"));
541 QDECREF(rsp);
542 migrate_check_parameter(who, "max-bandwidth", value);
543}
544
545static void test_deprecated(void)
546{
547 QTestState *from;
548
549 from = qtest_start("");
550
551 deprecated_set_downtime(from, 0.12345);
552 deprecated_set_speed(from, "12345");
553
554 qtest_quit(from);
555}
556
7195a871
JQ
557static void test_migrate(void)
558{
559 char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
863e27a8 560 QTestState *from, *to;
7195a871
JQ
561
562 test_migrate_start(&from, &to, uri);
ea0c6d62 563
d62fbe60
JQ
564 migrate_set_capability(from, "postcopy-ram", "true");
565 migrate_set_capability(to, "postcopy-ram", "true");
ea0c6d62
DDAG
566
567 /* We want to pick a speed slow enough that the test completes
568 * quickly, but that it doesn't complete precopy even on a slow
569 * machine, so also set the downtime.
570 */
1f90d797
JQ
571 migrate_set_parameter(from, "max-bandwidth", "100000000");
572 migrate_set_parameter(from, "downtime-limit", "1");
ea0c6d62
DDAG
573
574 /* Wait for the first serial output from the source */
575 wait_for_serial("src_serial");
576
d62fbe60 577 migrate(from, uri);
ea0c6d62 578
863e27a8 579 wait_for_migration_pass(from);
ea0c6d62 580
eb665d7d 581 migrate_start_postcopy(from);
ea0c6d62
DDAG
582
583 if (!got_stop) {
863e27a8 584 qtest_qmp_eventwait(from, "STOP");
ea0c6d62
DDAG
585 }
586
863e27a8 587 qtest_qmp_eventwait(to, "RESUME");
ea0c6d62
DDAG
588
589 wait_for_serial("dest_serial");
863e27a8 590 wait_for_migration_complete(from);
ea0c6d62 591
ea0c6d62 592 g_free(uri);
ea0c6d62 593
7195a871 594 test_migrate_end(from, to);
ea0c6d62
DDAG
595}
596
597int main(int argc, char **argv)
598{
2656bfd9 599 char template[] = "/tmp/migration-test-XXXXXX";
ea0c6d62
DDAG
600 int ret;
601
602 g_test_init(&argc, &argv, NULL);
603
604 if (!ufd_version_check()) {
605 return 0;
606 }
607
608 tmpfs = mkdtemp(template);
609 if (!tmpfs) {
610 g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno));
611 }
612 g_assert(tmpfs);
613
614 module_call_init(MODULE_INIT_QOM);
615
2656bfd9 616 qtest_add_func("/migration/postcopy/unix", test_migrate);
4c27486d 617 qtest_add_func("/migration/deprecated", test_deprecated);
ea0c6d62
DDAG
618
619 ret = g_test_run();
620
621 g_assert_cmpint(ret, ==, 0);
622
623 ret = rmdir(tmpfs);
624 if (ret != 0) {
625 g_test_message("unable to rmdir: path (%s): %s\n",
626 tmpfs, strerror(errno));
627 }
628
629 return ret;
630}