master
c 191 lines 6.31 KB
Raw
1 /*
2 * SPDX-License-Identifier: GPL-2.0-or-later
3 *
4 * QTest testcases for COLO migration
5 *
6 * Copyright (c) 2025 Lukas Straub <lukasstraub2@web.de>
7 */
8
9 #include "qemu/osdep.h"
10 #include "libqtest.h"
11 #include "migration/framework.h"
12 #include "migration/migration-qmp.h"
13 #include "migration/migration-util.h"
14 #include "qemu/module.h"
15
16 static int test_colo_common(MigrateCommon *args,
17 bool failover_during_checkpoint,
18 bool primary_failover)
19 {
20 QTestState *from, *to;
21 void *data_hook = NULL;
22
23 /*
24 * For the COLO test, both VMs will run in parallel. Thus both VMs want to
25 * open the image read/write at the same time. Using read-only=on is not
26 * possible here, because ide-hd does not support read-only backing image.
27 *
28 * So use -snapshot, where each qemu instance creates its own writable
29 * snapshot internally while leaving the real image read-only.
30 */
31 args->start.opts_source = "-snapshot";
32 args->start.opts_target = "-snapshot";
33
34 /*
35 * COLO migration code logs many errors when the migration socket
36 * is shut down, these are expected so we hide them here.
37 */
38 args->start.hide_stderr = true;
39
40 /*
41 * Test with yank with out of band capability since that is how it is
42 * used in production.
43 */
44 args->start.oob = true;
45 args->start.caps[MIGRATION_CAPABILITY_RETURN_PATH] = true;
46 args->start.caps[MIGRATION_CAPABILITY_X_COLO] = true;
47
48 if (migrate_start(&from, &to, &args->start)) {
49 return -1;
50 }
51
52 migrate_set_parameter_int(from, "x-checkpoint-delay", 300);
53
54 if (args->start_hook) {
55 data_hook = args->start_hook(from, to);
56 }
57
58 migrate_incoming_qmp(to, args->uri, NULL, "{}");
59
60 migrate_ensure_converge(from);
61 wait_for_serial("src_serial");
62
63 migrate_qmp(from, to, NULL, NULL, "{}");
64
65 wait_for_migration_status(from, "colo", NULL);
66 wait_for_resume(to, get_dst());
67
68 wait_for_serial("src_serial");
69 wait_for_serial("dest_serial");
70
71 /* wait for 3 checkpoints */
72 for (int i = 0; i < 3; i++) {
73 qtest_qmp_eventwait(to, "RESUME");
74 wait_for_serial("src_serial");
75 wait_for_serial("dest_serial");
76 }
77
78 if (failover_during_checkpoint) {
79 qtest_qmp_eventwait(to, "STOP");
80 }
81 if (primary_failover) {
82 qtest_qmp_assert_success(from, "{'exec-oob': 'yank', 'id': 'yank-cmd', "
83 "'arguments': {'instances':"
84 "[{'type': 'migration'}]}}");
85 qtest_qmp_assert_success(from, "{'execute': 'x-colo-lost-heartbeat'}");
86 wait_for_serial("src_serial");
87 } else {
88 qtest_qmp_assert_success(to, "{'exec-oob': 'yank', 'id': 'yank-cmd', "
89 "'arguments': {'instances':"
90 "[{'type': 'migration'}]}}");
91 qtest_qmp_assert_success(to, "{'execute': 'x-colo-lost-heartbeat'}");
92 wait_for_serial("dest_serial");
93 }
94
95 if (args->end_hook) {
96 args->end_hook(from, to, data_hook);
97 }
98
99 migrate_end(from, to, !primary_failover);
100
101 return 0;
102 }
103
104 static void test_colo_plain_common(MigrateCommon *args,
105 bool failover_during_checkpoint,
106 bool primary_failover)
107 {
108 args->uri = "tcp:127.0.0.1:0";
109 test_colo_common(args, failover_during_checkpoint, primary_failover);
110 }
111
112 static void test_colo_multifd_common(MigrateCommon *args,
113 bool failover_during_checkpoint,
114 bool primary_failover)
115 {
116 args->uri = "tcp:127.0.0.1:0";
117 args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true;
118 test_colo_common(args, failover_during_checkpoint, primary_failover);
119 }
120
121 static void test_colo_plain_primary_failover(char *name, MigrateCommon *args)
122 {
123 test_colo_plain_common(args, false, true);
124 }
125
126 static void test_colo_plain_secondary_failover(char *name, MigrateCommon *args)
127 {
128 test_colo_plain_common(args, false, false);
129 }
130
131 static void test_colo_multifd_primary_failover(char *name, MigrateCommon *args)
132 {
133 test_colo_multifd_common(args, false, true);
134 }
135
136 static void test_colo_multifd_secondary_failover(char *name,
137 MigrateCommon *args)
138 {
139 test_colo_multifd_common(args, false, false);
140 }
141
142 static void test_colo_plain_primary_failover_checkpoint(char *name,
143 MigrateCommon *args)
144 {
145 test_colo_plain_common(args, true, true);
146 }
147
148 static void test_colo_plain_secondary_failover_checkpoint(char *name,
149 MigrateCommon *args)
150 {
151 test_colo_plain_common(args, true, false);
152 }
153
154 static void test_colo_multifd_primary_failover_checkpoint(char *name,
155 MigrateCommon *args)
156 {
157 test_colo_multifd_common(args, true, true);
158 }
159
160 static void test_colo_multifd_secondary_failover_checkpoint(char *name,
161 MigrateCommon *args)
162 {
163 test_colo_multifd_common(args, true, false);
164 }
165
166 void migration_test_add_colo(MigrationTestEnv *env)
167 {
168 if (!env->full_set) {
169 return;
170 }
171
172 migration_test_add("/migration/colo/plain/primary_failover",
173 test_colo_plain_primary_failover);
174 migration_test_add("/migration/colo/plain/secondary_failover",
175 test_colo_plain_secondary_failover);
176
177 migration_test_add("/migration/colo/multifd/primary_failover",
178 test_colo_multifd_primary_failover);
179 migration_test_add("/migration/colo/multifd/secondary_failover",
180 test_colo_multifd_secondary_failover);
181
182 migration_test_add("/migration/colo/plain/primary_failover_checkpoint",
183 test_colo_plain_primary_failover_checkpoint);
184 migration_test_add("/migration/colo/plain/secondary_failover_checkpoint",
185 test_colo_plain_secondary_failover_checkpoint);
186
187 migration_test_add("/migration/colo/multifd/primary_failover_checkpoint",
188 test_colo_multifd_primary_failover_checkpoint);
189 migration_test_add("/migration/colo/multifd/secondary_failover_checkpoint",
190 test_colo_multifd_secondary_failover_checkpoint);
191 }