xref: /qemu/tests/qtest/migration/precopy-tests.c (revision 8a645544565c14cf1ac1b57ad2ef4f77a9446b7d)
1*8a645544SFabiano Rosas /*
2*8a645544SFabiano Rosas  * QTest testcase for precopy migration
3*8a645544SFabiano Rosas  *
4*8a645544SFabiano Rosas  * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
5*8a645544SFabiano Rosas  *   based on the vhost-user-test.c that is:
6*8a645544SFabiano Rosas  *      Copyright (c) 2014 Virtual Open Systems Sarl.
7*8a645544SFabiano Rosas  *
8*8a645544SFabiano Rosas  * This work is licensed under the terms of the GNU GPL, version 2 or later.
9*8a645544SFabiano Rosas  * See the COPYING file in the top-level directory.
10*8a645544SFabiano Rosas  *
11*8a645544SFabiano Rosas  */
12*8a645544SFabiano Rosas 
13*8a645544SFabiano Rosas #include "qemu/osdep.h"
14*8a645544SFabiano Rosas #include "chardev/char.h"
15*8a645544SFabiano Rosas #include "crypto/tlscredspsk.h"
16*8a645544SFabiano Rosas #include "libqtest.h"
17*8a645544SFabiano Rosas #include "migration/bootfile.h"
18*8a645544SFabiano Rosas #include "migration/framework.h"
19*8a645544SFabiano Rosas #include "migration/migration-qmp.h"
20*8a645544SFabiano Rosas #include "migration/migration-util.h"
21*8a645544SFabiano Rosas #include "ppc-util.h"
22*8a645544SFabiano Rosas #include "qapi/qmp/qlist.h"
23*8a645544SFabiano Rosas #include "qemu/module.h"
24*8a645544SFabiano Rosas #include "qemu/option.h"
25*8a645544SFabiano Rosas #include "qemu/range.h"
26*8a645544SFabiano Rosas #include "qemu/sockets.h"
27*8a645544SFabiano Rosas 
28*8a645544SFabiano Rosas 
29*8a645544SFabiano Rosas /*
30*8a645544SFabiano Rosas  * Dirtylimit stop working if dirty page rate error
31*8a645544SFabiano Rosas  * value less than DIRTYLIMIT_TOLERANCE_RANGE
32*8a645544SFabiano Rosas  */
33*8a645544SFabiano Rosas #define DIRTYLIMIT_TOLERANCE_RANGE  25  /* MB/s */
34*8a645544SFabiano Rosas 
35*8a645544SFabiano Rosas static char *tmpfs;
36*8a645544SFabiano Rosas 
37*8a645544SFabiano Rosas static void test_precopy_unix_plain(void)
38*8a645544SFabiano Rosas {
39*8a645544SFabiano Rosas     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
40*8a645544SFabiano Rosas     MigrateCommon args = {
41*8a645544SFabiano Rosas         .listen_uri = uri,
42*8a645544SFabiano Rosas         .connect_uri = uri,
43*8a645544SFabiano Rosas         /*
44*8a645544SFabiano Rosas          * The simplest use case of precopy, covering smoke tests of
45*8a645544SFabiano Rosas          * get-dirty-log dirty tracking.
46*8a645544SFabiano Rosas          */
47*8a645544SFabiano Rosas         .live = true,
48*8a645544SFabiano Rosas     };
49*8a645544SFabiano Rosas 
50*8a645544SFabiano Rosas     test_precopy_common(&args);
51*8a645544SFabiano Rosas }
52*8a645544SFabiano Rosas 
53*8a645544SFabiano Rosas static void test_precopy_unix_suspend_live(void)
54*8a645544SFabiano Rosas {
55*8a645544SFabiano Rosas     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
56*8a645544SFabiano Rosas     MigrateCommon args = {
57*8a645544SFabiano Rosas         .listen_uri = uri,
58*8a645544SFabiano Rosas         .connect_uri = uri,
59*8a645544SFabiano Rosas         /*
60*8a645544SFabiano Rosas          * despite being live, the test is fast because the src
61*8a645544SFabiano Rosas          * suspends immediately.
62*8a645544SFabiano Rosas          */
63*8a645544SFabiano Rosas         .live = true,
64*8a645544SFabiano Rosas         .start.suspend_me = true,
65*8a645544SFabiano Rosas     };
66*8a645544SFabiano Rosas 
67*8a645544SFabiano Rosas     test_precopy_common(&args);
68*8a645544SFabiano Rosas }
69*8a645544SFabiano Rosas 
70*8a645544SFabiano Rosas static void test_precopy_unix_suspend_notlive(void)
71*8a645544SFabiano Rosas {
72*8a645544SFabiano Rosas     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
73*8a645544SFabiano Rosas     MigrateCommon args = {
74*8a645544SFabiano Rosas         .listen_uri = uri,
75*8a645544SFabiano Rosas         .connect_uri = uri,
76*8a645544SFabiano Rosas         .start.suspend_me = true,
77*8a645544SFabiano Rosas     };
78*8a645544SFabiano Rosas 
79*8a645544SFabiano Rosas     test_precopy_common(&args);
80*8a645544SFabiano Rosas }
81*8a645544SFabiano Rosas 
82*8a645544SFabiano Rosas static void test_precopy_unix_dirty_ring(void)
83*8a645544SFabiano Rosas {
84*8a645544SFabiano Rosas     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
85*8a645544SFabiano Rosas     MigrateCommon args = {
86*8a645544SFabiano Rosas         .start = {
87*8a645544SFabiano Rosas             .use_dirty_ring = true,
88*8a645544SFabiano Rosas         },
89*8a645544SFabiano Rosas         .listen_uri = uri,
90*8a645544SFabiano Rosas         .connect_uri = uri,
91*8a645544SFabiano Rosas         /*
92*8a645544SFabiano Rosas          * Besides the precopy/unix basic test, cover dirty ring interface
93*8a645544SFabiano Rosas          * rather than get-dirty-log.
94*8a645544SFabiano Rosas          */
95*8a645544SFabiano Rosas         .live = true,
96*8a645544SFabiano Rosas     };
97*8a645544SFabiano Rosas 
98*8a645544SFabiano Rosas     test_precopy_common(&args);
99*8a645544SFabiano Rosas }
100*8a645544SFabiano Rosas 
101*8a645544SFabiano Rosas static void test_precopy_tcp_plain(void)
102*8a645544SFabiano Rosas {
103*8a645544SFabiano Rosas     MigrateCommon args = {
104*8a645544SFabiano Rosas         .listen_uri = "tcp:127.0.0.1:0",
105*8a645544SFabiano Rosas     };
106*8a645544SFabiano Rosas 
107*8a645544SFabiano Rosas     test_precopy_common(&args);
108*8a645544SFabiano Rosas }
109*8a645544SFabiano Rosas 
110*8a645544SFabiano Rosas static void *migrate_hook_start_switchover_ack(QTestState *from, QTestState *to)
111*8a645544SFabiano Rosas {
112*8a645544SFabiano Rosas 
113*8a645544SFabiano Rosas     migrate_set_capability(from, "return-path", true);
114*8a645544SFabiano Rosas     migrate_set_capability(to, "return-path", true);
115*8a645544SFabiano Rosas 
116*8a645544SFabiano Rosas     migrate_set_capability(from, "switchover-ack", true);
117*8a645544SFabiano Rosas     migrate_set_capability(to, "switchover-ack", true);
118*8a645544SFabiano Rosas 
119*8a645544SFabiano Rosas     return NULL;
120*8a645544SFabiano Rosas }
121*8a645544SFabiano Rosas 
122*8a645544SFabiano Rosas static void test_precopy_tcp_switchover_ack(void)
123*8a645544SFabiano Rosas {
124*8a645544SFabiano Rosas     MigrateCommon args = {
125*8a645544SFabiano Rosas         .listen_uri = "tcp:127.0.0.1:0",
126*8a645544SFabiano Rosas         .start_hook = migrate_hook_start_switchover_ack,
127*8a645544SFabiano Rosas         /*
128*8a645544SFabiano Rosas          * Source VM must be running in order to consider the switchover ACK
129*8a645544SFabiano Rosas          * when deciding to do switchover or not.
130*8a645544SFabiano Rosas          */
131*8a645544SFabiano Rosas         .live = true,
132*8a645544SFabiano Rosas     };
133*8a645544SFabiano Rosas 
134*8a645544SFabiano Rosas     test_precopy_common(&args);
135*8a645544SFabiano Rosas }
136*8a645544SFabiano Rosas 
137*8a645544SFabiano Rosas #ifndef _WIN32
138*8a645544SFabiano Rosas static void *migrate_hook_start_fd(QTestState *from,
139*8a645544SFabiano Rosas                                    QTestState *to)
140*8a645544SFabiano Rosas {
141*8a645544SFabiano Rosas     int ret;
142*8a645544SFabiano Rosas     int pair[2];
143*8a645544SFabiano Rosas 
144*8a645544SFabiano Rosas     /* Create two connected sockets for migration */
145*8a645544SFabiano Rosas     ret = qemu_socketpair(PF_LOCAL, SOCK_STREAM, 0, pair);
146*8a645544SFabiano Rosas     g_assert_cmpint(ret, ==, 0);
147*8a645544SFabiano Rosas 
148*8a645544SFabiano Rosas     /* Send the 1st socket to the target */
149*8a645544SFabiano Rosas     qtest_qmp_fds_assert_success(to, &pair[0], 1,
150*8a645544SFabiano Rosas                                  "{ 'execute': 'getfd',"
151*8a645544SFabiano Rosas                                  "  'arguments': { 'fdname': 'fd-mig' }}");
152*8a645544SFabiano Rosas     close(pair[0]);
153*8a645544SFabiano Rosas 
154*8a645544SFabiano Rosas     /* Start incoming migration from the 1st socket */
155*8a645544SFabiano Rosas     migrate_incoming_qmp(to, "fd:fd-mig", "{}");
156*8a645544SFabiano Rosas 
157*8a645544SFabiano Rosas     /* Send the 2nd socket to the target */
158*8a645544SFabiano Rosas     qtest_qmp_fds_assert_success(from, &pair[1], 1,
159*8a645544SFabiano Rosas                                  "{ 'execute': 'getfd',"
160*8a645544SFabiano Rosas                                  "  'arguments': { 'fdname': 'fd-mig' }}");
161*8a645544SFabiano Rosas     close(pair[1]);
162*8a645544SFabiano Rosas 
163*8a645544SFabiano Rosas     return NULL;
164*8a645544SFabiano Rosas }
165*8a645544SFabiano Rosas 
166*8a645544SFabiano Rosas static void migrate_hook_end_fd(QTestState *from,
167*8a645544SFabiano Rosas                                 QTestState *to,
168*8a645544SFabiano Rosas                                 void *opaque)
169*8a645544SFabiano Rosas {
170*8a645544SFabiano Rosas     QDict *rsp;
171*8a645544SFabiano Rosas     const char *error_desc;
172*8a645544SFabiano Rosas 
173*8a645544SFabiano Rosas     /* Test closing fds */
174*8a645544SFabiano Rosas     /*
175*8a645544SFabiano Rosas      * We assume, that QEMU removes named fd from its list,
176*8a645544SFabiano Rosas      * so this should fail.
177*8a645544SFabiano Rosas      */
178*8a645544SFabiano Rosas     rsp = qtest_qmp(from,
179*8a645544SFabiano Rosas                     "{ 'execute': 'closefd',"
180*8a645544SFabiano Rosas                     "  'arguments': { 'fdname': 'fd-mig' }}");
181*8a645544SFabiano Rosas     g_assert_true(qdict_haskey(rsp, "error"));
182*8a645544SFabiano Rosas     error_desc = qdict_get_str(qdict_get_qdict(rsp, "error"), "desc");
183*8a645544SFabiano Rosas     g_assert_cmpstr(error_desc, ==, "File descriptor named 'fd-mig' not found");
184*8a645544SFabiano Rosas     qobject_unref(rsp);
185*8a645544SFabiano Rosas 
186*8a645544SFabiano Rosas     rsp = qtest_qmp(to,
187*8a645544SFabiano Rosas                     "{ 'execute': 'closefd',"
188*8a645544SFabiano Rosas                     "  'arguments': { 'fdname': 'fd-mig' }}");
189*8a645544SFabiano Rosas     g_assert_true(qdict_haskey(rsp, "error"));
190*8a645544SFabiano Rosas     error_desc = qdict_get_str(qdict_get_qdict(rsp, "error"), "desc");
191*8a645544SFabiano Rosas     g_assert_cmpstr(error_desc, ==, "File descriptor named 'fd-mig' not found");
192*8a645544SFabiano Rosas     qobject_unref(rsp);
193*8a645544SFabiano Rosas }
194*8a645544SFabiano Rosas 
195*8a645544SFabiano Rosas static void test_precopy_fd_socket(void)
196*8a645544SFabiano Rosas {
197*8a645544SFabiano Rosas     MigrateCommon args = {
198*8a645544SFabiano Rosas         .listen_uri = "defer",
199*8a645544SFabiano Rosas         .connect_uri = "fd:fd-mig",
200*8a645544SFabiano Rosas         .start_hook = migrate_hook_start_fd,
201*8a645544SFabiano Rosas         .end_hook = migrate_hook_end_fd,
202*8a645544SFabiano Rosas     };
203*8a645544SFabiano Rosas     test_precopy_common(&args);
204*8a645544SFabiano Rosas }
205*8a645544SFabiano Rosas 
206*8a645544SFabiano Rosas static void *migrate_hook_start_precopy_fd_file(QTestState *from,
207*8a645544SFabiano Rosas                                                 QTestState *to)
208*8a645544SFabiano Rosas {
209*8a645544SFabiano Rosas     g_autofree char *file = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
210*8a645544SFabiano Rosas     int src_flags = O_CREAT | O_RDWR;
211*8a645544SFabiano Rosas     int dst_flags = O_CREAT | O_RDWR;
212*8a645544SFabiano Rosas     int fds[2];
213*8a645544SFabiano Rosas 
214*8a645544SFabiano Rosas     fds[0] = open(file, src_flags, 0660);
215*8a645544SFabiano Rosas     assert(fds[0] != -1);
216*8a645544SFabiano Rosas 
217*8a645544SFabiano Rosas     fds[1] = open(file, dst_flags, 0660);
218*8a645544SFabiano Rosas     assert(fds[1] != -1);
219*8a645544SFabiano Rosas 
220*8a645544SFabiano Rosas 
221*8a645544SFabiano Rosas     qtest_qmp_fds_assert_success(to, &fds[0], 1,
222*8a645544SFabiano Rosas                                  "{ 'execute': 'getfd',"
223*8a645544SFabiano Rosas                                  "  'arguments': { 'fdname': 'fd-mig' }}");
224*8a645544SFabiano Rosas 
225*8a645544SFabiano Rosas     qtest_qmp_fds_assert_success(from, &fds[1], 1,
226*8a645544SFabiano Rosas                                  "{ 'execute': 'getfd',"
227*8a645544SFabiano Rosas                                  "  'arguments': { 'fdname': 'fd-mig' }}");
228*8a645544SFabiano Rosas 
229*8a645544SFabiano Rosas     close(fds[0]);
230*8a645544SFabiano Rosas     close(fds[1]);
231*8a645544SFabiano Rosas 
232*8a645544SFabiano Rosas     return NULL;
233*8a645544SFabiano Rosas }
234*8a645544SFabiano Rosas 
235*8a645544SFabiano Rosas static void test_precopy_fd_file(void)
236*8a645544SFabiano Rosas {
237*8a645544SFabiano Rosas     MigrateCommon args = {
238*8a645544SFabiano Rosas         .listen_uri = "defer",
239*8a645544SFabiano Rosas         .connect_uri = "fd:fd-mig",
240*8a645544SFabiano Rosas         .start_hook = migrate_hook_start_precopy_fd_file,
241*8a645544SFabiano Rosas         .end_hook = migrate_hook_end_fd,
242*8a645544SFabiano Rosas     };
243*8a645544SFabiano Rosas     test_file_common(&args, true);
244*8a645544SFabiano Rosas }
245*8a645544SFabiano Rosas #endif /* _WIN32 */
246*8a645544SFabiano Rosas 
247*8a645544SFabiano Rosas /*
248*8a645544SFabiano Rosas  * The way auto_converge works, we need to do too many passes to
249*8a645544SFabiano Rosas  * run this test.  Auto_converge logic is only run once every
250*8a645544SFabiano Rosas  * three iterations, so:
251*8a645544SFabiano Rosas  *
252*8a645544SFabiano Rosas  * - 3 iterations without auto_converge enabled
253*8a645544SFabiano Rosas  * - 3 iterations with pct = 5
254*8a645544SFabiano Rosas  * - 3 iterations with pct = 30
255*8a645544SFabiano Rosas  * - 3 iterations with pct = 55
256*8a645544SFabiano Rosas  * - 3 iterations with pct = 80
257*8a645544SFabiano Rosas  * - 3 iterations with pct = 95 (max(95, 80 + 25))
258*8a645544SFabiano Rosas  *
259*8a645544SFabiano Rosas  * To make things even worse, we need to run the initial stage at
260*8a645544SFabiano Rosas  * 3MB/s so we enter autoconverge even when host is (over)loaded.
261*8a645544SFabiano Rosas  */
262*8a645544SFabiano Rosas static void test_auto_converge(void)
263*8a645544SFabiano Rosas {
264*8a645544SFabiano Rosas     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
265*8a645544SFabiano Rosas     MigrateStart args = {};
266*8a645544SFabiano Rosas     QTestState *from, *to;
267*8a645544SFabiano Rosas     int64_t percentage;
268*8a645544SFabiano Rosas 
269*8a645544SFabiano Rosas     /*
270*8a645544SFabiano Rosas      * We want the test to be stable and as fast as possible.
271*8a645544SFabiano Rosas      * E.g., with 1Gb/s bandwidth migration may pass without throttling,
272*8a645544SFabiano Rosas      * so we need to decrease a bandwidth.
273*8a645544SFabiano Rosas      */
274*8a645544SFabiano Rosas     const int64_t init_pct = 5, inc_pct = 25, max_pct = 95;
275*8a645544SFabiano Rosas     uint64_t prev_dirty_sync_cnt, dirty_sync_cnt;
276*8a645544SFabiano Rosas     int max_try_count, hit = 0;
277*8a645544SFabiano Rosas 
278*8a645544SFabiano Rosas     if (migrate_start(&from, &to, uri, &args)) {
279*8a645544SFabiano Rosas         return;
280*8a645544SFabiano Rosas     }
281*8a645544SFabiano Rosas 
282*8a645544SFabiano Rosas     migrate_set_capability(from, "auto-converge", true);
283*8a645544SFabiano Rosas     migrate_set_parameter_int(from, "cpu-throttle-initial", init_pct);
284*8a645544SFabiano Rosas     migrate_set_parameter_int(from, "cpu-throttle-increment", inc_pct);
285*8a645544SFabiano Rosas     migrate_set_parameter_int(from, "max-cpu-throttle", max_pct);
286*8a645544SFabiano Rosas 
287*8a645544SFabiano Rosas     /*
288*8a645544SFabiano Rosas      * Set the initial parameters so that the migration could not converge
289*8a645544SFabiano Rosas      * without throttling.
290*8a645544SFabiano Rosas      */
291*8a645544SFabiano Rosas     migrate_ensure_non_converge(from);
292*8a645544SFabiano Rosas 
293*8a645544SFabiano Rosas     /* To check remaining size after precopy */
294*8a645544SFabiano Rosas     migrate_set_capability(from, "pause-before-switchover", true);
295*8a645544SFabiano Rosas 
296*8a645544SFabiano Rosas     /* Wait for the first serial output from the source */
297*8a645544SFabiano Rosas     wait_for_serial("src_serial");
298*8a645544SFabiano Rosas 
299*8a645544SFabiano Rosas     migrate_qmp(from, to, uri, NULL, "{}");
300*8a645544SFabiano Rosas 
301*8a645544SFabiano Rosas     /* Wait for throttling begins */
302*8a645544SFabiano Rosas     percentage = 0;
303*8a645544SFabiano Rosas     do {
304*8a645544SFabiano Rosas         percentage = read_migrate_property_int(from, "cpu-throttle-percentage");
305*8a645544SFabiano Rosas         if (percentage != 0) {
306*8a645544SFabiano Rosas             break;
307*8a645544SFabiano Rosas         }
308*8a645544SFabiano Rosas         usleep(20);
309*8a645544SFabiano Rosas         g_assert_false(get_src()->stop_seen);
310*8a645544SFabiano Rosas     } while (true);
311*8a645544SFabiano Rosas     /* The first percentage of throttling should be at least init_pct */
312*8a645544SFabiano Rosas     g_assert_cmpint(percentage, >=, init_pct);
313*8a645544SFabiano Rosas 
314*8a645544SFabiano Rosas     /*
315*8a645544SFabiano Rosas      * End the loop when the dirty sync count greater than 1.
316*8a645544SFabiano Rosas      */
317*8a645544SFabiano Rosas     while ((dirty_sync_cnt = get_migration_pass(from)) < 2) {
318*8a645544SFabiano Rosas         usleep(1000 * 1000);
319*8a645544SFabiano Rosas     }
320*8a645544SFabiano Rosas 
321*8a645544SFabiano Rosas     prev_dirty_sync_cnt = dirty_sync_cnt;
322*8a645544SFabiano Rosas 
323*8a645544SFabiano Rosas     /*
324*8a645544SFabiano Rosas      * The RAMBlock dirty sync count must changes in 5 seconds, here we set
325*8a645544SFabiano Rosas      * the timeout to 10 seconds to ensure it changes.
326*8a645544SFabiano Rosas      *
327*8a645544SFabiano Rosas      * Note that migrate_ensure_non_converge set the max-bandwidth to 3MB/s,
328*8a645544SFabiano Rosas      * while the qtest mem is >= 100MB, one iteration takes at least 33s (100/3)
329*8a645544SFabiano Rosas      * to complete; this ensures that the RAMBlock dirty sync occurs.
330*8a645544SFabiano Rosas      */
331*8a645544SFabiano Rosas     max_try_count = 10;
332*8a645544SFabiano Rosas     while (--max_try_count) {
333*8a645544SFabiano Rosas         dirty_sync_cnt = get_migration_pass(from);
334*8a645544SFabiano Rosas         if (dirty_sync_cnt != prev_dirty_sync_cnt) {
335*8a645544SFabiano Rosas             hit = 1;
336*8a645544SFabiano Rosas             break;
337*8a645544SFabiano Rosas         }
338*8a645544SFabiano Rosas         prev_dirty_sync_cnt = dirty_sync_cnt;
339*8a645544SFabiano Rosas         sleep(1);
340*8a645544SFabiano Rosas     }
341*8a645544SFabiano Rosas     g_assert_cmpint(hit, ==, 1);
342*8a645544SFabiano Rosas 
343*8a645544SFabiano Rosas     /* Now, when we tested that throttling works, let it converge */
344*8a645544SFabiano Rosas     migrate_ensure_converge(from);
345*8a645544SFabiano Rosas 
346*8a645544SFabiano Rosas     /*
347*8a645544SFabiano Rosas      * Wait for pre-switchover status to check last throttle percentage
348*8a645544SFabiano Rosas      * and remaining. These values will be zeroed later
349*8a645544SFabiano Rosas      */
350*8a645544SFabiano Rosas     wait_for_migration_status(from, "pre-switchover", NULL);
351*8a645544SFabiano Rosas 
352*8a645544SFabiano Rosas     /* The final percentage of throttling shouldn't be greater than max_pct */
353*8a645544SFabiano Rosas     percentage = read_migrate_property_int(from, "cpu-throttle-percentage");
354*8a645544SFabiano Rosas     g_assert_cmpint(percentage, <=, max_pct);
355*8a645544SFabiano Rosas     migrate_continue(from, "pre-switchover");
356*8a645544SFabiano Rosas 
357*8a645544SFabiano Rosas     qtest_qmp_eventwait(to, "RESUME");
358*8a645544SFabiano Rosas 
359*8a645544SFabiano Rosas     wait_for_serial("dest_serial");
360*8a645544SFabiano Rosas     wait_for_migration_complete(from);
361*8a645544SFabiano Rosas 
362*8a645544SFabiano Rosas     migrate_end(from, to, true);
363*8a645544SFabiano Rosas }
364*8a645544SFabiano Rosas 
365*8a645544SFabiano Rosas static void *
366*8a645544SFabiano Rosas migrate_hook_start_precopy_tcp_multifd(QTestState *from,
367*8a645544SFabiano Rosas                                        QTestState *to)
368*8a645544SFabiano Rosas {
369*8a645544SFabiano Rosas     return migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
370*8a645544SFabiano Rosas }
371*8a645544SFabiano Rosas 
372*8a645544SFabiano Rosas static void *
373*8a645544SFabiano Rosas migrate_hook_start_precopy_tcp_multifd_zero_page_legacy(QTestState *from,
374*8a645544SFabiano Rosas                                                         QTestState *to)
375*8a645544SFabiano Rosas {
376*8a645544SFabiano Rosas     migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
377*8a645544SFabiano Rosas     migrate_set_parameter_str(from, "zero-page-detection", "legacy");
378*8a645544SFabiano Rosas     return NULL;
379*8a645544SFabiano Rosas }
380*8a645544SFabiano Rosas 
381*8a645544SFabiano Rosas static void *
382*8a645544SFabiano Rosas migrate_hook_start_precopy_tcp_multifd_no_zero_page(QTestState *from,
383*8a645544SFabiano Rosas                                                     QTestState *to)
384*8a645544SFabiano Rosas {
385*8a645544SFabiano Rosas     migrate_hook_start_precopy_tcp_multifd_common(from, to, "none");
386*8a645544SFabiano Rosas     migrate_set_parameter_str(from, "zero-page-detection", "none");
387*8a645544SFabiano Rosas     return NULL;
388*8a645544SFabiano Rosas }
389*8a645544SFabiano Rosas 
390*8a645544SFabiano Rosas static void test_multifd_tcp_uri_none(void)
391*8a645544SFabiano Rosas {
392*8a645544SFabiano Rosas     MigrateCommon args = {
393*8a645544SFabiano Rosas         .listen_uri = "defer",
394*8a645544SFabiano Rosas         .start_hook = migrate_hook_start_precopy_tcp_multifd,
395*8a645544SFabiano Rosas         /*
396*8a645544SFabiano Rosas          * Multifd is more complicated than most of the features, it
397*8a645544SFabiano Rosas          * directly takes guest page buffers when sending, make sure
398*8a645544SFabiano Rosas          * everything will work alright even if guest page is changing.
399*8a645544SFabiano Rosas          */
400*8a645544SFabiano Rosas         .live = true,
401*8a645544SFabiano Rosas     };
402*8a645544SFabiano Rosas     test_precopy_common(&args);
403*8a645544SFabiano Rosas }
404*8a645544SFabiano Rosas 
405*8a645544SFabiano Rosas static void test_multifd_tcp_zero_page_legacy(void)
406*8a645544SFabiano Rosas {
407*8a645544SFabiano Rosas     MigrateCommon args = {
408*8a645544SFabiano Rosas         .listen_uri = "defer",
409*8a645544SFabiano Rosas         .start_hook = migrate_hook_start_precopy_tcp_multifd_zero_page_legacy,
410*8a645544SFabiano Rosas         /*
411*8a645544SFabiano Rosas          * Multifd is more complicated than most of the features, it
412*8a645544SFabiano Rosas          * directly takes guest page buffers when sending, make sure
413*8a645544SFabiano Rosas          * everything will work alright even if guest page is changing.
414*8a645544SFabiano Rosas          */
415*8a645544SFabiano Rosas         .live = true,
416*8a645544SFabiano Rosas     };
417*8a645544SFabiano Rosas     test_precopy_common(&args);
418*8a645544SFabiano Rosas }
419*8a645544SFabiano Rosas 
420*8a645544SFabiano Rosas static void test_multifd_tcp_no_zero_page(void)
421*8a645544SFabiano Rosas {
422*8a645544SFabiano Rosas     MigrateCommon args = {
423*8a645544SFabiano Rosas         .listen_uri = "defer",
424*8a645544SFabiano Rosas         .start_hook = migrate_hook_start_precopy_tcp_multifd_no_zero_page,
425*8a645544SFabiano Rosas         /*
426*8a645544SFabiano Rosas          * Multifd is more complicated than most of the features, it
427*8a645544SFabiano Rosas          * directly takes guest page buffers when sending, make sure
428*8a645544SFabiano Rosas          * everything will work alright even if guest page is changing.
429*8a645544SFabiano Rosas          */
430*8a645544SFabiano Rosas         .live = true,
431*8a645544SFabiano Rosas     };
432*8a645544SFabiano Rosas     test_precopy_common(&args);
433*8a645544SFabiano Rosas }
434*8a645544SFabiano Rosas 
435*8a645544SFabiano Rosas static void test_multifd_tcp_channels_none(void)
436*8a645544SFabiano Rosas {
437*8a645544SFabiano Rosas     MigrateCommon args = {
438*8a645544SFabiano Rosas         .listen_uri = "defer",
439*8a645544SFabiano Rosas         .start_hook = migrate_hook_start_precopy_tcp_multifd,
440*8a645544SFabiano Rosas         .live = true,
441*8a645544SFabiano Rosas         .connect_channels = ("[ { 'channel-type': 'main',"
442*8a645544SFabiano Rosas                              "    'addr': { 'transport': 'socket',"
443*8a645544SFabiano Rosas                              "              'type': 'inet',"
444*8a645544SFabiano Rosas                              "              'host': '127.0.0.1',"
445*8a645544SFabiano Rosas                              "              'port': '0' } } ]"),
446*8a645544SFabiano Rosas     };
447*8a645544SFabiano Rosas     test_precopy_common(&args);
448*8a645544SFabiano Rosas }
449*8a645544SFabiano Rosas 
450*8a645544SFabiano Rosas /*
451*8a645544SFabiano Rosas  * This test does:
452*8a645544SFabiano Rosas  *  source               target
453*8a645544SFabiano Rosas  *                       migrate_incoming
454*8a645544SFabiano Rosas  *     migrate
455*8a645544SFabiano Rosas  *     migrate_cancel
456*8a645544SFabiano Rosas  *                       launch another target
457*8a645544SFabiano Rosas  *     migrate
458*8a645544SFabiano Rosas  *
459*8a645544SFabiano Rosas  *  And see that it works
460*8a645544SFabiano Rosas  */
461*8a645544SFabiano Rosas static void test_multifd_tcp_cancel(void)
462*8a645544SFabiano Rosas {
463*8a645544SFabiano Rosas     MigrateStart args = {
464*8a645544SFabiano Rosas         .hide_stderr = true,
465*8a645544SFabiano Rosas     };
466*8a645544SFabiano Rosas     QTestState *from, *to, *to2;
467*8a645544SFabiano Rosas 
468*8a645544SFabiano Rosas     if (migrate_start(&from, &to, "defer", &args)) {
469*8a645544SFabiano Rosas         return;
470*8a645544SFabiano Rosas     }
471*8a645544SFabiano Rosas 
472*8a645544SFabiano Rosas     migrate_ensure_non_converge(from);
473*8a645544SFabiano Rosas     migrate_prepare_for_dirty_mem(from);
474*8a645544SFabiano Rosas 
475*8a645544SFabiano Rosas     migrate_set_parameter_int(from, "multifd-channels", 16);
476*8a645544SFabiano Rosas     migrate_set_parameter_int(to, "multifd-channels", 16);
477*8a645544SFabiano Rosas 
478*8a645544SFabiano Rosas     migrate_set_capability(from, "multifd", true);
479*8a645544SFabiano Rosas     migrate_set_capability(to, "multifd", true);
480*8a645544SFabiano Rosas 
481*8a645544SFabiano Rosas     /* Start incoming migration from the 1st socket */
482*8a645544SFabiano Rosas     migrate_incoming_qmp(to, "tcp:127.0.0.1:0", "{}");
483*8a645544SFabiano Rosas 
484*8a645544SFabiano Rosas     /* Wait for the first serial output from the source */
485*8a645544SFabiano Rosas     wait_for_serial("src_serial");
486*8a645544SFabiano Rosas 
487*8a645544SFabiano Rosas     migrate_qmp(from, to, NULL, NULL, "{}");
488*8a645544SFabiano Rosas 
489*8a645544SFabiano Rosas     migrate_wait_for_dirty_mem(from, to);
490*8a645544SFabiano Rosas 
491*8a645544SFabiano Rosas     migrate_cancel(from);
492*8a645544SFabiano Rosas 
493*8a645544SFabiano Rosas     /* Make sure QEMU process "to" exited */
494*8a645544SFabiano Rosas     qtest_set_expected_status(to, EXIT_FAILURE);
495*8a645544SFabiano Rosas     qtest_wait_qemu(to);
496*8a645544SFabiano Rosas     qtest_quit(to);
497*8a645544SFabiano Rosas 
498*8a645544SFabiano Rosas     /*
499*8a645544SFabiano Rosas      * Ensure the source QEMU finishes its cancellation process before we
500*8a645544SFabiano Rosas      * proceed with the setup of the next migration. The migrate_start()
501*8a645544SFabiano Rosas      * function and others might want to interact with the source in a way that
502*8a645544SFabiano Rosas      * is not possible while the migration is not canceled properly. For
503*8a645544SFabiano Rosas      * example, setting migration capabilities when the migration is still
504*8a645544SFabiano Rosas      * running leads to an error.
505*8a645544SFabiano Rosas      */
506*8a645544SFabiano Rosas     wait_for_migration_status(from, "cancelled", NULL);
507*8a645544SFabiano Rosas 
508*8a645544SFabiano Rosas     args = (MigrateStart){
509*8a645544SFabiano Rosas         .only_target = true,
510*8a645544SFabiano Rosas     };
511*8a645544SFabiano Rosas 
512*8a645544SFabiano Rosas     if (migrate_start(&from, &to2, "defer", &args)) {
513*8a645544SFabiano Rosas         return;
514*8a645544SFabiano Rosas     }
515*8a645544SFabiano Rosas 
516*8a645544SFabiano Rosas     migrate_set_parameter_int(to2, "multifd-channels", 16);
517*8a645544SFabiano Rosas 
518*8a645544SFabiano Rosas     migrate_set_capability(to2, "multifd", true);
519*8a645544SFabiano Rosas 
520*8a645544SFabiano Rosas     /* Start incoming migration from the 1st socket */
521*8a645544SFabiano Rosas     migrate_incoming_qmp(to2, "tcp:127.0.0.1:0", "{}");
522*8a645544SFabiano Rosas 
523*8a645544SFabiano Rosas     migrate_ensure_non_converge(from);
524*8a645544SFabiano Rosas 
525*8a645544SFabiano Rosas     migrate_qmp(from, to2, NULL, NULL, "{}");
526*8a645544SFabiano Rosas 
527*8a645544SFabiano Rosas     migrate_wait_for_dirty_mem(from, to2);
528*8a645544SFabiano Rosas 
529*8a645544SFabiano Rosas     migrate_ensure_converge(from);
530*8a645544SFabiano Rosas 
531*8a645544SFabiano Rosas     wait_for_stop(from, get_src());
532*8a645544SFabiano Rosas     qtest_qmp_eventwait(to2, "RESUME");
533*8a645544SFabiano Rosas 
534*8a645544SFabiano Rosas     wait_for_serial("dest_serial");
535*8a645544SFabiano Rosas     wait_for_migration_complete(from);
536*8a645544SFabiano Rosas     migrate_end(from, to2, true);
537*8a645544SFabiano Rosas }
538*8a645544SFabiano Rosas 
539*8a645544SFabiano Rosas static void calc_dirty_rate(QTestState *who, uint64_t calc_time)
540*8a645544SFabiano Rosas {
541*8a645544SFabiano Rosas     qtest_qmp_assert_success(who,
542*8a645544SFabiano Rosas                              "{ 'execute': 'calc-dirty-rate',"
543*8a645544SFabiano Rosas                              "'arguments': { "
544*8a645544SFabiano Rosas                              "'calc-time': %" PRIu64 ","
545*8a645544SFabiano Rosas                              "'mode': 'dirty-ring' }}",
546*8a645544SFabiano Rosas                              calc_time);
547*8a645544SFabiano Rosas }
548*8a645544SFabiano Rosas 
549*8a645544SFabiano Rosas static QDict *query_dirty_rate(QTestState *who)
550*8a645544SFabiano Rosas {
551*8a645544SFabiano Rosas     return qtest_qmp_assert_success_ref(who,
552*8a645544SFabiano Rosas                                         "{ 'execute': 'query-dirty-rate' }");
553*8a645544SFabiano Rosas }
554*8a645544SFabiano Rosas 
555*8a645544SFabiano Rosas static void dirtylimit_set_all(QTestState *who, uint64_t dirtyrate)
556*8a645544SFabiano Rosas {
557*8a645544SFabiano Rosas     qtest_qmp_assert_success(who,
558*8a645544SFabiano Rosas                              "{ 'execute': 'set-vcpu-dirty-limit',"
559*8a645544SFabiano Rosas                              "'arguments': { "
560*8a645544SFabiano Rosas                              "'dirty-rate': %" PRIu64 " } }",
561*8a645544SFabiano Rosas                              dirtyrate);
562*8a645544SFabiano Rosas }
563*8a645544SFabiano Rosas 
564*8a645544SFabiano Rosas static void cancel_vcpu_dirty_limit(QTestState *who)
565*8a645544SFabiano Rosas {
566*8a645544SFabiano Rosas     qtest_qmp_assert_success(who,
567*8a645544SFabiano Rosas                              "{ 'execute': 'cancel-vcpu-dirty-limit' }");
568*8a645544SFabiano Rosas }
569*8a645544SFabiano Rosas 
570*8a645544SFabiano Rosas static QDict *query_vcpu_dirty_limit(QTestState *who)
571*8a645544SFabiano Rosas {
572*8a645544SFabiano Rosas     QDict *rsp;
573*8a645544SFabiano Rosas 
574*8a645544SFabiano Rosas     rsp = qtest_qmp(who, "{ 'execute': 'query-vcpu-dirty-limit' }");
575*8a645544SFabiano Rosas     g_assert(!qdict_haskey(rsp, "error"));
576*8a645544SFabiano Rosas     g_assert(qdict_haskey(rsp, "return"));
577*8a645544SFabiano Rosas 
578*8a645544SFabiano Rosas     return rsp;
579*8a645544SFabiano Rosas }
580*8a645544SFabiano Rosas 
581*8a645544SFabiano Rosas static bool calc_dirtyrate_ready(QTestState *who)
582*8a645544SFabiano Rosas {
583*8a645544SFabiano Rosas     QDict *rsp_return;
584*8a645544SFabiano Rosas     const char *status;
585*8a645544SFabiano Rosas     bool ready;
586*8a645544SFabiano Rosas 
587*8a645544SFabiano Rosas     rsp_return = query_dirty_rate(who);
588*8a645544SFabiano Rosas     g_assert(rsp_return);
589*8a645544SFabiano Rosas 
590*8a645544SFabiano Rosas     status = qdict_get_str(rsp_return, "status");
591*8a645544SFabiano Rosas     g_assert(status);
592*8a645544SFabiano Rosas     ready = g_strcmp0(status, "measuring");
593*8a645544SFabiano Rosas     qobject_unref(rsp_return);
594*8a645544SFabiano Rosas 
595*8a645544SFabiano Rosas     return ready;
596*8a645544SFabiano Rosas }
597*8a645544SFabiano Rosas 
598*8a645544SFabiano Rosas static void wait_for_calc_dirtyrate_complete(QTestState *who,
599*8a645544SFabiano Rosas                                              int64_t time_s)
600*8a645544SFabiano Rosas {
601*8a645544SFabiano Rosas     int max_try_count = 10000;
602*8a645544SFabiano Rosas     usleep(time_s * 1000000);
603*8a645544SFabiano Rosas 
604*8a645544SFabiano Rosas     while (!calc_dirtyrate_ready(who) && max_try_count--) {
605*8a645544SFabiano Rosas         usleep(1000);
606*8a645544SFabiano Rosas     }
607*8a645544SFabiano Rosas 
608*8a645544SFabiano Rosas     /*
609*8a645544SFabiano Rosas      * Set the timeout with 10 s(max_try_count * 1000us),
610*8a645544SFabiano Rosas      * if dirtyrate measurement not complete, fail test.
611*8a645544SFabiano Rosas      */
612*8a645544SFabiano Rosas     g_assert_cmpint(max_try_count, !=, 0);
613*8a645544SFabiano Rosas }
614*8a645544SFabiano Rosas 
615*8a645544SFabiano Rosas static int64_t get_dirty_rate(QTestState *who)
616*8a645544SFabiano Rosas {
617*8a645544SFabiano Rosas     QDict *rsp_return;
618*8a645544SFabiano Rosas     const char *status;
619*8a645544SFabiano Rosas     QList *rates;
620*8a645544SFabiano Rosas     const QListEntry *entry;
621*8a645544SFabiano Rosas     QDict *rate;
622*8a645544SFabiano Rosas     int64_t dirtyrate;
623*8a645544SFabiano Rosas 
624*8a645544SFabiano Rosas     rsp_return = query_dirty_rate(who);
625*8a645544SFabiano Rosas     g_assert(rsp_return);
626*8a645544SFabiano Rosas 
627*8a645544SFabiano Rosas     status = qdict_get_str(rsp_return, "status");
628*8a645544SFabiano Rosas     g_assert(status);
629*8a645544SFabiano Rosas     g_assert_cmpstr(status, ==, "measured");
630*8a645544SFabiano Rosas 
631*8a645544SFabiano Rosas     rates = qdict_get_qlist(rsp_return, "vcpu-dirty-rate");
632*8a645544SFabiano Rosas     g_assert(rates && !qlist_empty(rates));
633*8a645544SFabiano Rosas 
634*8a645544SFabiano Rosas     entry = qlist_first(rates);
635*8a645544SFabiano Rosas     g_assert(entry);
636*8a645544SFabiano Rosas 
637*8a645544SFabiano Rosas     rate = qobject_to(QDict, qlist_entry_obj(entry));
638*8a645544SFabiano Rosas     g_assert(rate);
639*8a645544SFabiano Rosas 
640*8a645544SFabiano Rosas     dirtyrate = qdict_get_try_int(rate, "dirty-rate", -1);
641*8a645544SFabiano Rosas 
642*8a645544SFabiano Rosas     qobject_unref(rsp_return);
643*8a645544SFabiano Rosas     return dirtyrate;
644*8a645544SFabiano Rosas }
645*8a645544SFabiano Rosas 
646*8a645544SFabiano Rosas static int64_t get_limit_rate(QTestState *who)
647*8a645544SFabiano Rosas {
648*8a645544SFabiano Rosas     QDict *rsp_return;
649*8a645544SFabiano Rosas     QList *rates;
650*8a645544SFabiano Rosas     const QListEntry *entry;
651*8a645544SFabiano Rosas     QDict *rate;
652*8a645544SFabiano Rosas     int64_t dirtyrate;
653*8a645544SFabiano Rosas 
654*8a645544SFabiano Rosas     rsp_return = query_vcpu_dirty_limit(who);
655*8a645544SFabiano Rosas     g_assert(rsp_return);
656*8a645544SFabiano Rosas 
657*8a645544SFabiano Rosas     rates = qdict_get_qlist(rsp_return, "return");
658*8a645544SFabiano Rosas     g_assert(rates && !qlist_empty(rates));
659*8a645544SFabiano Rosas 
660*8a645544SFabiano Rosas     entry = qlist_first(rates);
661*8a645544SFabiano Rosas     g_assert(entry);
662*8a645544SFabiano Rosas 
663*8a645544SFabiano Rosas     rate = qobject_to(QDict, qlist_entry_obj(entry));
664*8a645544SFabiano Rosas     g_assert(rate);
665*8a645544SFabiano Rosas 
666*8a645544SFabiano Rosas     dirtyrate = qdict_get_try_int(rate, "limit-rate", -1);
667*8a645544SFabiano Rosas 
668*8a645544SFabiano Rosas     qobject_unref(rsp_return);
669*8a645544SFabiano Rosas     return dirtyrate;
670*8a645544SFabiano Rosas }
671*8a645544SFabiano Rosas 
672*8a645544SFabiano Rosas static QTestState *dirtylimit_start_vm(void)
673*8a645544SFabiano Rosas {
674*8a645544SFabiano Rosas     QTestState *vm = NULL;
675*8a645544SFabiano Rosas     g_autofree gchar *cmd = NULL;
676*8a645544SFabiano Rosas     const char *bootpath;
677*8a645544SFabiano Rosas 
678*8a645544SFabiano Rosas     bootpath = bootfile_create(qtest_get_arch(), tmpfs, false);
679*8a645544SFabiano Rosas     cmd = g_strdup_printf("-accel kvm,dirty-ring-size=4096 "
680*8a645544SFabiano Rosas                           "-name dirtylimit-test,debug-threads=on "
681*8a645544SFabiano Rosas                           "-m 150M -smp 1 "
682*8a645544SFabiano Rosas                           "-serial file:%s/vm_serial "
683*8a645544SFabiano Rosas                           "-drive file=%s,format=raw ",
684*8a645544SFabiano Rosas                           tmpfs, bootpath);
685*8a645544SFabiano Rosas 
686*8a645544SFabiano Rosas     vm = qtest_init(cmd);
687*8a645544SFabiano Rosas     return vm;
688*8a645544SFabiano Rosas }
689*8a645544SFabiano Rosas 
690*8a645544SFabiano Rosas static void dirtylimit_stop_vm(QTestState *vm)
691*8a645544SFabiano Rosas {
692*8a645544SFabiano Rosas     g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, "vm_serial");
693*8a645544SFabiano Rosas 
694*8a645544SFabiano Rosas     qtest_quit(vm);
695*8a645544SFabiano Rosas     unlink(path);
696*8a645544SFabiano Rosas }
697*8a645544SFabiano Rosas 
698*8a645544SFabiano Rosas static void test_vcpu_dirty_limit(void)
699*8a645544SFabiano Rosas {
700*8a645544SFabiano Rosas     QTestState *vm;
701*8a645544SFabiano Rosas     int64_t origin_rate;
702*8a645544SFabiano Rosas     int64_t quota_rate;
703*8a645544SFabiano Rosas     int64_t rate ;
704*8a645544SFabiano Rosas     int max_try_count = 20;
705*8a645544SFabiano Rosas     int hit = 0;
706*8a645544SFabiano Rosas 
707*8a645544SFabiano Rosas     /* Start vm for vcpu dirtylimit test */
708*8a645544SFabiano Rosas     vm = dirtylimit_start_vm();
709*8a645544SFabiano Rosas 
710*8a645544SFabiano Rosas     /* Wait for the first serial output from the vm*/
711*8a645544SFabiano Rosas     wait_for_serial("vm_serial");
712*8a645544SFabiano Rosas 
713*8a645544SFabiano Rosas     /* Do dirtyrate measurement with calc time equals 1s */
714*8a645544SFabiano Rosas     calc_dirty_rate(vm, 1);
715*8a645544SFabiano Rosas 
716*8a645544SFabiano Rosas     /* Sleep calc time and wait for calc dirtyrate complete */
717*8a645544SFabiano Rosas     wait_for_calc_dirtyrate_complete(vm, 1);
718*8a645544SFabiano Rosas 
719*8a645544SFabiano Rosas     /* Query original dirty page rate */
720*8a645544SFabiano Rosas     origin_rate = get_dirty_rate(vm);
721*8a645544SFabiano Rosas 
722*8a645544SFabiano Rosas     /* VM booted from bootsect should dirty memory steadily */
723*8a645544SFabiano Rosas     assert(origin_rate != 0);
724*8a645544SFabiano Rosas 
725*8a645544SFabiano Rosas     /* Setup quota dirty page rate at half of origin */
726*8a645544SFabiano Rosas     quota_rate = origin_rate / 2;
727*8a645544SFabiano Rosas 
728*8a645544SFabiano Rosas     /* Set dirtylimit */
729*8a645544SFabiano Rosas     dirtylimit_set_all(vm, quota_rate);
730*8a645544SFabiano Rosas 
731*8a645544SFabiano Rosas     /*
732*8a645544SFabiano Rosas      * Check if set-vcpu-dirty-limit and query-vcpu-dirty-limit
733*8a645544SFabiano Rosas      * works literally
734*8a645544SFabiano Rosas      */
735*8a645544SFabiano Rosas     g_assert_cmpint(quota_rate, ==, get_limit_rate(vm));
736*8a645544SFabiano Rosas 
737*8a645544SFabiano Rosas     /* Sleep a bit to check if it take effect */
738*8a645544SFabiano Rosas     usleep(2000000);
739*8a645544SFabiano Rosas 
740*8a645544SFabiano Rosas     /*
741*8a645544SFabiano Rosas      * Check if dirtylimit take effect realistically, set the
742*8a645544SFabiano Rosas      * timeout with 20 s(max_try_count * 1s), if dirtylimit
743*8a645544SFabiano Rosas      * doesn't take effect, fail test.
744*8a645544SFabiano Rosas      */
745*8a645544SFabiano Rosas     while (--max_try_count) {
746*8a645544SFabiano Rosas         calc_dirty_rate(vm, 1);
747*8a645544SFabiano Rosas         wait_for_calc_dirtyrate_complete(vm, 1);
748*8a645544SFabiano Rosas         rate = get_dirty_rate(vm);
749*8a645544SFabiano Rosas 
750*8a645544SFabiano Rosas         /*
751*8a645544SFabiano Rosas          * Assume hitting if current rate is less
752*8a645544SFabiano Rosas          * than quota rate (within accepting error)
753*8a645544SFabiano Rosas          */
754*8a645544SFabiano Rosas         if (rate < (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) {
755*8a645544SFabiano Rosas             hit = 1;
756*8a645544SFabiano Rosas             break;
757*8a645544SFabiano Rosas         }
758*8a645544SFabiano Rosas     }
759*8a645544SFabiano Rosas 
760*8a645544SFabiano Rosas     g_assert_cmpint(hit, ==, 1);
761*8a645544SFabiano Rosas 
762*8a645544SFabiano Rosas     hit = 0;
763*8a645544SFabiano Rosas     max_try_count = 20;
764*8a645544SFabiano Rosas 
765*8a645544SFabiano Rosas     /* Check if dirtylimit cancellation take effect */
766*8a645544SFabiano Rosas     cancel_vcpu_dirty_limit(vm);
767*8a645544SFabiano Rosas     while (--max_try_count) {
768*8a645544SFabiano Rosas         calc_dirty_rate(vm, 1);
769*8a645544SFabiano Rosas         wait_for_calc_dirtyrate_complete(vm, 1);
770*8a645544SFabiano Rosas         rate = get_dirty_rate(vm);
771*8a645544SFabiano Rosas 
772*8a645544SFabiano Rosas         /*
773*8a645544SFabiano Rosas          * Assume dirtylimit be canceled if current rate is
774*8a645544SFabiano Rosas          * greater than quota rate (within accepting error)
775*8a645544SFabiano Rosas          */
776*8a645544SFabiano Rosas         if (rate > (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) {
777*8a645544SFabiano Rosas             hit = 1;
778*8a645544SFabiano Rosas             break;
779*8a645544SFabiano Rosas         }
780*8a645544SFabiano Rosas     }
781*8a645544SFabiano Rosas 
782*8a645544SFabiano Rosas     g_assert_cmpint(hit, ==, 1);
783*8a645544SFabiano Rosas     dirtylimit_stop_vm(vm);
784*8a645544SFabiano Rosas }
785*8a645544SFabiano Rosas 
786*8a645544SFabiano Rosas static void migrate_dirty_limit_wait_showup(QTestState *from,
787*8a645544SFabiano Rosas                                             const int64_t period,
788*8a645544SFabiano Rosas                                             const int64_t value)
789*8a645544SFabiano Rosas {
790*8a645544SFabiano Rosas     /* Enable dirty limit capability */
791*8a645544SFabiano Rosas     migrate_set_capability(from, "dirty-limit", true);
792*8a645544SFabiano Rosas 
793*8a645544SFabiano Rosas     /* Set dirty limit parameters */
794*8a645544SFabiano Rosas     migrate_set_parameter_int(from, "x-vcpu-dirty-limit-period", period);
795*8a645544SFabiano Rosas     migrate_set_parameter_int(from, "vcpu-dirty-limit", value);
796*8a645544SFabiano Rosas 
797*8a645544SFabiano Rosas     /* Make sure migrate can't converge */
798*8a645544SFabiano Rosas     migrate_ensure_non_converge(from);
799*8a645544SFabiano Rosas 
800*8a645544SFabiano Rosas     /* To check limit rate after precopy */
801*8a645544SFabiano Rosas     migrate_set_capability(from, "pause-before-switchover", true);
802*8a645544SFabiano Rosas 
803*8a645544SFabiano Rosas     /* Wait for the serial output from the source */
804*8a645544SFabiano Rosas     wait_for_serial("src_serial");
805*8a645544SFabiano Rosas }
806*8a645544SFabiano Rosas 
807*8a645544SFabiano Rosas /*
808*8a645544SFabiano Rosas  * This test does:
809*8a645544SFabiano Rosas  *  source                          destination
810*8a645544SFabiano Rosas  *  start vm
811*8a645544SFabiano Rosas  *                                  start incoming vm
812*8a645544SFabiano Rosas  *  migrate
813*8a645544SFabiano Rosas  *  wait dirty limit to begin
814*8a645544SFabiano Rosas  *  cancel migrate
815*8a645544SFabiano Rosas  *  cancellation check
816*8a645544SFabiano Rosas  *                                  restart incoming vm
817*8a645544SFabiano Rosas  *  migrate
818*8a645544SFabiano Rosas  *  wait dirty limit to begin
819*8a645544SFabiano Rosas  *  wait pre-switchover event
820*8a645544SFabiano Rosas  *  convergence condition check
821*8a645544SFabiano Rosas  *
822*8a645544SFabiano Rosas  * And see if dirty limit migration works correctly.
823*8a645544SFabiano Rosas  * This test case involves many passes, so it runs in slow mode only.
824*8a645544SFabiano Rosas  */
825*8a645544SFabiano Rosas static void test_dirty_limit(void)
826*8a645544SFabiano Rosas {
827*8a645544SFabiano Rosas     g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
828*8a645544SFabiano Rosas     QTestState *from, *to;
829*8a645544SFabiano Rosas     int64_t remaining;
830*8a645544SFabiano Rosas     uint64_t throttle_us_per_full;
831*8a645544SFabiano Rosas     /*
832*8a645544SFabiano Rosas      * We want the test to be stable and as fast as possible.
833*8a645544SFabiano Rosas      * E.g., with 1Gb/s bandwidth migration may pass without dirty limit,
834*8a645544SFabiano Rosas      * so we need to decrease a bandwidth.
835*8a645544SFabiano Rosas      */
836*8a645544SFabiano Rosas     const int64_t dirtylimit_period = 1000, dirtylimit_value = 50;
837*8a645544SFabiano Rosas     const int64_t max_bandwidth = 400000000; /* ~400Mb/s */
838*8a645544SFabiano Rosas     const int64_t downtime_limit = 250; /* 250ms */
839*8a645544SFabiano Rosas     /*
840*8a645544SFabiano Rosas      * We migrate through unix-socket (> 500Mb/s).
841*8a645544SFabiano Rosas      * Thus, expected migration speed ~= bandwidth limit (< 500Mb/s).
842*8a645544SFabiano Rosas      * So, we can predict expected_threshold
843*8a645544SFabiano Rosas      */
844*8a645544SFabiano Rosas     const int64_t expected_threshold = max_bandwidth * downtime_limit / 1000;
845*8a645544SFabiano Rosas     int max_try_count = 10;
846*8a645544SFabiano Rosas     MigrateCommon args = {
847*8a645544SFabiano Rosas         .start = {
848*8a645544SFabiano Rosas             .hide_stderr = true,
849*8a645544SFabiano Rosas             .use_dirty_ring = true,
850*8a645544SFabiano Rosas         },
851*8a645544SFabiano Rosas         .listen_uri = uri,
852*8a645544SFabiano Rosas         .connect_uri = uri,
853*8a645544SFabiano Rosas     };
854*8a645544SFabiano Rosas 
855*8a645544SFabiano Rosas     /* Start src, dst vm */
856*8a645544SFabiano Rosas     if (migrate_start(&from, &to, args.listen_uri, &args.start)) {
857*8a645544SFabiano Rosas         return;
858*8a645544SFabiano Rosas     }
859*8a645544SFabiano Rosas 
860*8a645544SFabiano Rosas     /* Prepare for dirty limit migration and wait src vm show up */
861*8a645544SFabiano Rosas     migrate_dirty_limit_wait_showup(from, dirtylimit_period, dirtylimit_value);
862*8a645544SFabiano Rosas 
863*8a645544SFabiano Rosas     /* Start migrate */
864*8a645544SFabiano Rosas     migrate_qmp(from, to, args.connect_uri, NULL, "{}");
865*8a645544SFabiano Rosas 
866*8a645544SFabiano Rosas     /* Wait for dirty limit throttle begin */
867*8a645544SFabiano Rosas     throttle_us_per_full = 0;
868*8a645544SFabiano Rosas     while (throttle_us_per_full == 0) {
869*8a645544SFabiano Rosas         throttle_us_per_full =
870*8a645544SFabiano Rosas             read_migrate_property_int(from,
871*8a645544SFabiano Rosas                                       "dirty-limit-throttle-time-per-round");
872*8a645544SFabiano Rosas         usleep(100);
873*8a645544SFabiano Rosas         g_assert_false(get_src()->stop_seen);
874*8a645544SFabiano Rosas     }
875*8a645544SFabiano Rosas 
876*8a645544SFabiano Rosas     /* Now cancel migrate and wait for dirty limit throttle switch off */
877*8a645544SFabiano Rosas     migrate_cancel(from);
878*8a645544SFabiano Rosas     wait_for_migration_status(from, "cancelled", NULL);
879*8a645544SFabiano Rosas 
880*8a645544SFabiano Rosas     /* Check if dirty limit throttle switched off, set timeout 1ms */
881*8a645544SFabiano Rosas     do {
882*8a645544SFabiano Rosas         throttle_us_per_full =
883*8a645544SFabiano Rosas             read_migrate_property_int(from,
884*8a645544SFabiano Rosas                                       "dirty-limit-throttle-time-per-round");
885*8a645544SFabiano Rosas         usleep(100);
886*8a645544SFabiano Rosas         g_assert_false(get_src()->stop_seen);
887*8a645544SFabiano Rosas     } while (throttle_us_per_full != 0 && --max_try_count);
888*8a645544SFabiano Rosas 
889*8a645544SFabiano Rosas     /* Assert dirty limit is not in service */
890*8a645544SFabiano Rosas     g_assert_cmpint(throttle_us_per_full, ==, 0);
891*8a645544SFabiano Rosas 
892*8a645544SFabiano Rosas     args = (MigrateCommon) {
893*8a645544SFabiano Rosas         .start = {
894*8a645544SFabiano Rosas             .only_target = true,
895*8a645544SFabiano Rosas             .use_dirty_ring = true,
896*8a645544SFabiano Rosas         },
897*8a645544SFabiano Rosas         .listen_uri = uri,
898*8a645544SFabiano Rosas         .connect_uri = uri,
899*8a645544SFabiano Rosas     };
900*8a645544SFabiano Rosas 
901*8a645544SFabiano Rosas     /* Restart dst vm, src vm already show up so we needn't wait anymore */
902*8a645544SFabiano Rosas     if (migrate_start(&from, &to, args.listen_uri, &args.start)) {
903*8a645544SFabiano Rosas         return;
904*8a645544SFabiano Rosas     }
905*8a645544SFabiano Rosas 
906*8a645544SFabiano Rosas     /* Start migrate */
907*8a645544SFabiano Rosas     migrate_qmp(from, to, args.connect_uri, NULL, "{}");
908*8a645544SFabiano Rosas 
909*8a645544SFabiano Rosas     /* Wait for dirty limit throttle begin */
910*8a645544SFabiano Rosas     throttle_us_per_full = 0;
911*8a645544SFabiano Rosas     while (throttle_us_per_full == 0) {
912*8a645544SFabiano Rosas         throttle_us_per_full =
913*8a645544SFabiano Rosas             read_migrate_property_int(from,
914*8a645544SFabiano Rosas                                       "dirty-limit-throttle-time-per-round");
915*8a645544SFabiano Rosas         usleep(100);
916*8a645544SFabiano Rosas         g_assert_false(get_src()->stop_seen);
917*8a645544SFabiano Rosas     }
918*8a645544SFabiano Rosas 
919*8a645544SFabiano Rosas     /*
920*8a645544SFabiano Rosas      * The dirty limit rate should equals the return value of
921*8a645544SFabiano Rosas      * query-vcpu-dirty-limit if dirty limit cap set
922*8a645544SFabiano Rosas      */
923*8a645544SFabiano Rosas     g_assert_cmpint(dirtylimit_value, ==, get_limit_rate(from));
924*8a645544SFabiano Rosas 
925*8a645544SFabiano Rosas     /* Now, we have tested if dirty limit works, let it converge */
926*8a645544SFabiano Rosas     migrate_set_parameter_int(from, "downtime-limit", downtime_limit);
927*8a645544SFabiano Rosas     migrate_set_parameter_int(from, "max-bandwidth", max_bandwidth);
928*8a645544SFabiano Rosas 
929*8a645544SFabiano Rosas     /*
930*8a645544SFabiano Rosas      * Wait for pre-switchover status to check if migration
931*8a645544SFabiano Rosas      * satisfy the convergence condition
932*8a645544SFabiano Rosas      */
933*8a645544SFabiano Rosas     wait_for_migration_status(from, "pre-switchover", NULL);
934*8a645544SFabiano Rosas 
935*8a645544SFabiano Rosas     remaining = read_ram_property_int(from, "remaining");
936*8a645544SFabiano Rosas     g_assert_cmpint(remaining, <,
937*8a645544SFabiano Rosas                     (expected_threshold + expected_threshold / 100));
938*8a645544SFabiano Rosas 
939*8a645544SFabiano Rosas     migrate_continue(from, "pre-switchover");
940*8a645544SFabiano Rosas 
941*8a645544SFabiano Rosas     qtest_qmp_eventwait(to, "RESUME");
942*8a645544SFabiano Rosas 
943*8a645544SFabiano Rosas     wait_for_serial("dest_serial");
944*8a645544SFabiano Rosas     wait_for_migration_complete(from);
945*8a645544SFabiano Rosas 
946*8a645544SFabiano Rosas     migrate_end(from, to, true);
947*8a645544SFabiano Rosas }
948*8a645544SFabiano Rosas 
949*8a645544SFabiano Rosas void migration_test_add_precopy(MigrationTestEnv *env)
950*8a645544SFabiano Rosas {
951*8a645544SFabiano Rosas     tmpfs = env->tmpfs;
952*8a645544SFabiano Rosas 
953*8a645544SFabiano Rosas     if (env->is_x86) {
954*8a645544SFabiano Rosas         migration_test_add("/migration/precopy/unix/suspend/live",
955*8a645544SFabiano Rosas                            test_precopy_unix_suspend_live);
956*8a645544SFabiano Rosas         migration_test_add("/migration/precopy/unix/suspend/notlive",
957*8a645544SFabiano Rosas                            test_precopy_unix_suspend_notlive);
958*8a645544SFabiano Rosas     }
959*8a645544SFabiano Rosas 
960*8a645544SFabiano Rosas     migration_test_add("/migration/precopy/unix/plain",
961*8a645544SFabiano Rosas                        test_precopy_unix_plain);
962*8a645544SFabiano Rosas 
963*8a645544SFabiano Rosas     migration_test_add("/migration/precopy/tcp/plain", test_precopy_tcp_plain);
964*8a645544SFabiano Rosas 
965*8a645544SFabiano Rosas     migration_test_add("/migration/precopy/tcp/plain/switchover-ack",
966*8a645544SFabiano Rosas                        test_precopy_tcp_switchover_ack);
967*8a645544SFabiano Rosas 
968*8a645544SFabiano Rosas #ifndef _WIN32
969*8a645544SFabiano Rosas     migration_test_add("/migration/precopy/fd/tcp",
970*8a645544SFabiano Rosas                        test_precopy_fd_socket);
971*8a645544SFabiano Rosas     migration_test_add("/migration/precopy/fd/file",
972*8a645544SFabiano Rosas                        test_precopy_fd_file);
973*8a645544SFabiano Rosas #endif
974*8a645544SFabiano Rosas 
975*8a645544SFabiano Rosas     /*
976*8a645544SFabiano Rosas      * See explanation why this test is slow on function definition
977*8a645544SFabiano Rosas      */
978*8a645544SFabiano Rosas     if (g_test_slow()) {
979*8a645544SFabiano Rosas         migration_test_add("/migration/auto_converge",
980*8a645544SFabiano Rosas                            test_auto_converge);
981*8a645544SFabiano Rosas         if (g_str_equal(env->arch, "x86_64") &&
982*8a645544SFabiano Rosas             env->has_kvm && env->has_dirty_ring) {
983*8a645544SFabiano Rosas             migration_test_add("/dirty_limit",
984*8a645544SFabiano Rosas                                test_dirty_limit);
985*8a645544SFabiano Rosas         }
986*8a645544SFabiano Rosas     }
987*8a645544SFabiano Rosas     migration_test_add("/migration/multifd/tcp/uri/plain/none",
988*8a645544SFabiano Rosas                        test_multifd_tcp_uri_none);
989*8a645544SFabiano Rosas     migration_test_add("/migration/multifd/tcp/channels/plain/none",
990*8a645544SFabiano Rosas                        test_multifd_tcp_channels_none);
991*8a645544SFabiano Rosas     migration_test_add("/migration/multifd/tcp/plain/zero-page/legacy",
992*8a645544SFabiano Rosas                        test_multifd_tcp_zero_page_legacy);
993*8a645544SFabiano Rosas     migration_test_add("/migration/multifd/tcp/plain/zero-page/none",
994*8a645544SFabiano Rosas                        test_multifd_tcp_no_zero_page);
995*8a645544SFabiano Rosas     migration_test_add("/migration/multifd/tcp/plain/cancel",
996*8a645544SFabiano Rosas                        test_multifd_tcp_cancel);
997*8a645544SFabiano Rosas     if (g_str_equal(env->arch, "x86_64")
998*8a645544SFabiano Rosas         && env->has_kvm && env->has_dirty_ring) {
999*8a645544SFabiano Rosas 
1000*8a645544SFabiano Rosas         migration_test_add("/migration/dirty_ring",
1001*8a645544SFabiano Rosas                            test_precopy_unix_dirty_ring);
1002*8a645544SFabiano Rosas         if (qtest_has_machine("pc") && g_test_slow()) {
1003*8a645544SFabiano Rosas             migration_test_add("/migration/vcpu_dirty_limit",
1004*8a645544SFabiano Rosas                                test_vcpu_dirty_limit);
1005*8a645544SFabiano Rosas         }
1006*8a645544SFabiano Rosas     }
1007*8a645544SFabiano Rosas }
1008