xref: /openbmc/qemu/migration/options.c (revision 50795ee051a342c681a9b45671c552fbd6274db8)
1 /*
2  * QEMU migration capabilities
3  *
4  * Copyright (c) 2012-2023 Red Hat Inc
5  *
6  * Authors:
7  *   Orit Wasserman <owasserm@redhat.com>
8  *   Juan Quintela <quintela@redhat.com>
9  *
10  * This work is licensed under the terms of the GNU GPL, version 2 or later.
11  * See the COPYING file in the top-level directory.
12  */
13 
14 #include "qemu/osdep.h"
15 #include "exec/target_page.h"
16 #include "qapi/clone-visitor.h"
17 #include "qapi/error.h"
18 #include "qapi/qapi-commands-migration.h"
19 #include "qapi/qapi-visit-migration.h"
20 #include "qapi/qmp/qerror.h"
21 #include "qapi/qmp/qnull.h"
22 #include "sysemu/runstate.h"
23 #include "migration/colo.h"
24 #include "migration/misc.h"
25 #include "migration.h"
26 #include "qemu-file.h"
27 #include "ram.h"
28 #include "options.h"
29 
30 /* Maximum migrate downtime set to 2000 seconds */
31 #define MAX_MIGRATE_DOWNTIME_SECONDS 2000
32 #define MAX_MIGRATE_DOWNTIME (MAX_MIGRATE_DOWNTIME_SECONDS * 1000)
33 
34 bool migrate_auto_converge(void)
35 {
36     MigrationState *s;
37 
38     s = migrate_get_current();
39 
40     return s->capabilities[MIGRATION_CAPABILITY_AUTO_CONVERGE];
41 }
42 
43 bool migrate_background_snapshot(void)
44 {
45     MigrationState *s;
46 
47     s = migrate_get_current();
48 
49     return s->capabilities[MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT];
50 }
51 
52 bool migrate_block(void)
53 {
54     MigrationState *s;
55 
56     s = migrate_get_current();
57 
58     return s->capabilities[MIGRATION_CAPABILITY_BLOCK];
59 }
60 
61 bool migrate_colo(void)
62 {
63     MigrationState *s = migrate_get_current();
64     return s->capabilities[MIGRATION_CAPABILITY_X_COLO];
65 }
66 
67 bool migrate_compress(void)
68 {
69     MigrationState *s;
70 
71     s = migrate_get_current();
72 
73     return s->capabilities[MIGRATION_CAPABILITY_COMPRESS];
74 }
75 
76 bool migrate_dirty_bitmaps(void)
77 {
78     MigrationState *s;
79 
80     s = migrate_get_current();
81 
82     return s->capabilities[MIGRATION_CAPABILITY_DIRTY_BITMAPS];
83 }
84 
85 bool migrate_events(void)
86 {
87     MigrationState *s;
88 
89     s = migrate_get_current();
90 
91     return s->capabilities[MIGRATION_CAPABILITY_EVENTS];
92 }
93 
94 bool migrate_ignore_shared(void)
95 {
96     MigrationState *s;
97 
98     s = migrate_get_current();
99 
100     return s->capabilities[MIGRATION_CAPABILITY_X_IGNORE_SHARED];
101 }
102 
103 bool migrate_late_block_activate(void)
104 {
105     MigrationState *s;
106 
107     s = migrate_get_current();
108 
109     return s->capabilities[MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE];
110 }
111 
112 bool migrate_multifd(void)
113 {
114     MigrationState *s;
115 
116     s = migrate_get_current();
117 
118     return s->capabilities[MIGRATION_CAPABILITY_MULTIFD];
119 }
120 
121 bool migrate_pause_before_switchover(void)
122 {
123     MigrationState *s;
124 
125     s = migrate_get_current();
126 
127     return s->capabilities[MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER];
128 }
129 
130 bool migrate_postcopy_blocktime(void)
131 {
132     MigrationState *s;
133 
134     s = migrate_get_current();
135 
136     return s->capabilities[MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME];
137 }
138 
139 bool migrate_postcopy_preempt(void)
140 {
141     MigrationState *s;
142 
143     s = migrate_get_current();
144 
145     return s->capabilities[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT];
146 }
147 
148 bool migrate_postcopy_ram(void)
149 {
150     MigrationState *s;
151 
152     s = migrate_get_current();
153 
154     return s->capabilities[MIGRATION_CAPABILITY_POSTCOPY_RAM];
155 }
156 
157 bool migrate_rdma_pin_all(void)
158 {
159     MigrationState *s = migrate_get_current();
160 
161     return s->capabilities[MIGRATION_CAPABILITY_RDMA_PIN_ALL];
162 }
163 
164 bool migrate_release_ram(void)
165 {
166     MigrationState *s;
167 
168     s = migrate_get_current();
169 
170     return s->capabilities[MIGRATION_CAPABILITY_RELEASE_RAM];
171 }
172 
173 bool migrate_return_path(void)
174 {
175     MigrationState *s;
176 
177     s = migrate_get_current();
178 
179     return s->capabilities[MIGRATION_CAPABILITY_RETURN_PATH];
180 }
181 
182 bool migrate_validate_uuid(void)
183 {
184     MigrationState *s;
185 
186     s = migrate_get_current();
187 
188     return s->capabilities[MIGRATION_CAPABILITY_VALIDATE_UUID];
189 }
190 
191 bool migrate_xbzrle(void)
192 {
193     MigrationState *s;
194 
195     s = migrate_get_current();
196 
197     return s->capabilities[MIGRATION_CAPABILITY_XBZRLE];
198 }
199 
200 bool migrate_zero_blocks(void)
201 {
202     MigrationState *s;
203 
204     s = migrate_get_current();
205 
206     return s->capabilities[MIGRATION_CAPABILITY_ZERO_BLOCKS];
207 }
208 
209 bool migrate_zero_copy_send(void)
210 {
211     MigrationState *s;
212 
213     s = migrate_get_current();
214 
215     return s->capabilities[MIGRATION_CAPABILITY_ZERO_COPY_SEND];
216 }
217 
218 /* pseudo capabilities */
219 
220 bool migrate_postcopy(void)
221 {
222     return migrate_postcopy_ram() || migrate_dirty_bitmaps();
223 }
224 
225 bool migrate_tls(void)
226 {
227     MigrationState *s;
228 
229     s = migrate_get_current();
230 
231     return s->parameters.tls_creds && *s->parameters.tls_creds;
232 }
233 
234 typedef enum WriteTrackingSupport {
235     WT_SUPPORT_UNKNOWN = 0,
236     WT_SUPPORT_ABSENT,
237     WT_SUPPORT_AVAILABLE,
238     WT_SUPPORT_COMPATIBLE
239 } WriteTrackingSupport;
240 
241 static
242 WriteTrackingSupport migrate_query_write_tracking(void)
243 {
244     /* Check if kernel supports required UFFD features */
245     if (!ram_write_tracking_available()) {
246         return WT_SUPPORT_ABSENT;
247     }
248     /*
249      * Check if current memory configuration is
250      * compatible with required UFFD features.
251      */
252     if (!ram_write_tracking_compatible()) {
253         return WT_SUPPORT_AVAILABLE;
254     }
255 
256     return WT_SUPPORT_COMPATIBLE;
257 }
258 
259 /* Migration capabilities set */
260 struct MigrateCapsSet {
261     int size;                       /* Capability set size */
262     MigrationCapability caps[];     /* Variadic array of capabilities */
263 };
264 typedef struct MigrateCapsSet MigrateCapsSet;
265 
266 /* Define and initialize MigrateCapsSet */
267 #define INITIALIZE_MIGRATE_CAPS_SET(_name, ...)   \
268     MigrateCapsSet _name = {    \
269         .size = sizeof((int []) { __VA_ARGS__ }) / sizeof(int), \
270         .caps = { __VA_ARGS__ } \
271     }
272 
273 /* Background-snapshot compatibility check list */
274 static const
275 INITIALIZE_MIGRATE_CAPS_SET(check_caps_background_snapshot,
276     MIGRATION_CAPABILITY_POSTCOPY_RAM,
277     MIGRATION_CAPABILITY_DIRTY_BITMAPS,
278     MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME,
279     MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE,
280     MIGRATION_CAPABILITY_RETURN_PATH,
281     MIGRATION_CAPABILITY_MULTIFD,
282     MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER,
283     MIGRATION_CAPABILITY_AUTO_CONVERGE,
284     MIGRATION_CAPABILITY_RELEASE_RAM,
285     MIGRATION_CAPABILITY_RDMA_PIN_ALL,
286     MIGRATION_CAPABILITY_COMPRESS,
287     MIGRATION_CAPABILITY_XBZRLE,
288     MIGRATION_CAPABILITY_X_COLO,
289     MIGRATION_CAPABILITY_VALIDATE_UUID,
290     MIGRATION_CAPABILITY_ZERO_COPY_SEND);
291 
292 /**
293  * @migration_caps_check - check capability compatibility
294  *
295  * @old_caps: old capability list
296  * @new_caps: new capability list
297  * @errp: set *errp if the check failed, with reason
298  *
299  * Returns true if check passed, otherwise false.
300  */
301 bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
302 {
303     MigrationIncomingState *mis = migration_incoming_get_current();
304 
305     ERRP_GUARD();
306 #ifndef CONFIG_LIVE_BLOCK_MIGRATION
307     if (new_caps[MIGRATION_CAPABILITY_BLOCK]) {
308         error_setg(errp, "QEMU compiled without old-style (blk/-b, inc/-i) "
309                    "block migration");
310         error_append_hint(errp, "Use drive_mirror+NBD instead.\n");
311         return false;
312     }
313 #endif
314 
315 #ifndef CONFIG_REPLICATION
316     if (new_caps[MIGRATION_CAPABILITY_X_COLO]) {
317         error_setg(errp, "QEMU compiled without replication module"
318                    " can't enable COLO");
319         error_append_hint(errp, "Please enable replication before COLO.\n");
320         return false;
321     }
322 #endif
323 
324     if (new_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
325         /* This check is reasonably expensive, so only when it's being
326          * set the first time, also it's only the destination that needs
327          * special support.
328          */
329         if (!old_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] &&
330             runstate_check(RUN_STATE_INMIGRATE) &&
331             !postcopy_ram_supported_by_host(mis, errp)) {
332             error_prepend(errp, "Postcopy is not supported: ");
333             return false;
334         }
335 
336         if (new_caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED]) {
337             error_setg(errp, "Postcopy is not compatible with ignore-shared");
338             return false;
339         }
340 
341         if (new_caps[MIGRATION_CAPABILITY_MULTIFD]) {
342             error_setg(errp, "Postcopy is not yet compatible with multifd");
343             return false;
344         }
345     }
346 
347     if (new_caps[MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT]) {
348         WriteTrackingSupport wt_support;
349         int idx;
350         /*
351          * Check if 'background-snapshot' capability is supported by
352          * host kernel and compatible with guest memory configuration.
353          */
354         wt_support = migrate_query_write_tracking();
355         if (wt_support < WT_SUPPORT_AVAILABLE) {
356             error_setg(errp, "Background-snapshot is not supported by host kernel");
357             return false;
358         }
359         if (wt_support < WT_SUPPORT_COMPATIBLE) {
360             error_setg(errp, "Background-snapshot is not compatible "
361                     "with guest memory configuration");
362             return false;
363         }
364 
365         /*
366          * Check if there are any migration capabilities
367          * incompatible with 'background-snapshot'.
368          */
369         for (idx = 0; idx < check_caps_background_snapshot.size; idx++) {
370             int incomp_cap = check_caps_background_snapshot.caps[idx];
371             if (new_caps[incomp_cap]) {
372                 error_setg(errp,
373                         "Background-snapshot is not compatible with %s",
374                         MigrationCapability_str(incomp_cap));
375                 return false;
376             }
377         }
378     }
379 
380 #ifdef CONFIG_LINUX
381     if (new_caps[MIGRATION_CAPABILITY_ZERO_COPY_SEND] &&
382         (!new_caps[MIGRATION_CAPABILITY_MULTIFD] ||
383          new_caps[MIGRATION_CAPABILITY_COMPRESS] ||
384          new_caps[MIGRATION_CAPABILITY_XBZRLE] ||
385          migrate_multifd_compression() ||
386          migrate_tls())) {
387         error_setg(errp,
388                    "Zero copy only available for non-compressed non-TLS multifd migration");
389         return false;
390     }
391 #else
392     if (new_caps[MIGRATION_CAPABILITY_ZERO_COPY_SEND]) {
393         error_setg(errp,
394                    "Zero copy currently only available on Linux");
395         return false;
396     }
397 #endif
398 
399     if (new_caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT]) {
400         if (!new_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
401             error_setg(errp, "Postcopy preempt requires postcopy-ram");
402             return false;
403         }
404 
405         /*
406          * Preempt mode requires urgent pages to be sent in separate
407          * channel, OTOH compression logic will disorder all pages into
408          * different compression channels, which is not compatible with the
409          * preempt assumptions on channel assignments.
410          */
411         if (new_caps[MIGRATION_CAPABILITY_COMPRESS]) {
412             error_setg(errp, "Postcopy preempt not compatible with compress");
413             return false;
414         }
415     }
416 
417     if (new_caps[MIGRATION_CAPABILITY_MULTIFD]) {
418         if (new_caps[MIGRATION_CAPABILITY_COMPRESS]) {
419             error_setg(errp, "Multifd is not compatible with compress");
420             return false;
421         }
422     }
423 
424     return true;
425 }
426 
427 bool migrate_cap_set(int cap, bool value, Error **errp)
428 {
429     MigrationState *s = migrate_get_current();
430     bool new_caps[MIGRATION_CAPABILITY__MAX];
431 
432     if (migration_is_running(s->state)) {
433         error_setg(errp, QERR_MIGRATION_ACTIVE);
434         return false;
435     }
436 
437     memcpy(new_caps, s->capabilities, sizeof(new_caps));
438     new_caps[cap] = value;
439 
440     if (!migrate_caps_check(s->capabilities, new_caps, errp)) {
441         return false;
442     }
443     s->capabilities[cap] = value;
444     return true;
445 }
446 
447 MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp)
448 {
449     MigrationCapabilityStatusList *head = NULL, **tail = &head;
450     MigrationCapabilityStatus *caps;
451     MigrationState *s = migrate_get_current();
452     int i;
453 
454     for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
455 #ifndef CONFIG_LIVE_BLOCK_MIGRATION
456         if (i == MIGRATION_CAPABILITY_BLOCK) {
457             continue;
458         }
459 #endif
460         caps = g_malloc0(sizeof(*caps));
461         caps->capability = i;
462         caps->state = s->capabilities[i];
463         QAPI_LIST_APPEND(tail, caps);
464     }
465 
466     return head;
467 }
468 
469 void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
470                                   Error **errp)
471 {
472     MigrationState *s = migrate_get_current();
473     MigrationCapabilityStatusList *cap;
474     bool new_caps[MIGRATION_CAPABILITY__MAX];
475 
476     if (migration_is_running(s->state)) {
477         error_setg(errp, QERR_MIGRATION_ACTIVE);
478         return;
479     }
480 
481     memcpy(new_caps, s->capabilities, sizeof(new_caps));
482     for (cap = params; cap; cap = cap->next) {
483         new_caps[cap->value->capability] = cap->value->state;
484     }
485 
486     if (!migrate_caps_check(s->capabilities, new_caps, errp)) {
487         return;
488     }
489 
490     for (cap = params; cap; cap = cap->next) {
491         s->capabilities[cap->value->capability] = cap->value->state;
492     }
493 }
494 
495 /* parameters */
496 
497 bool migrate_block_incremental(void)
498 {
499     MigrationState *s;
500 
501     s = migrate_get_current();
502 
503     return s->parameters.block_incremental;
504 }
505 
506 uint32_t migrate_checkpoint_delay(void)
507 {
508     MigrationState *s;
509 
510     s = migrate_get_current();
511 
512     return s->parameters.x_checkpoint_delay;
513 }
514 
515 int migrate_compress_level(void)
516 {
517     MigrationState *s;
518 
519     s = migrate_get_current();
520 
521     return s->parameters.compress_level;
522 }
523 
524 int migrate_compress_threads(void)
525 {
526     MigrationState *s;
527 
528     s = migrate_get_current();
529 
530     return s->parameters.compress_threads;
531 }
532 
533 int migrate_compress_wait_thread(void)
534 {
535     MigrationState *s;
536 
537     s = migrate_get_current();
538 
539     return s->parameters.compress_wait_thread;
540 }
541 
542 uint8_t migrate_cpu_throttle_increment(void)
543 {
544     MigrationState *s;
545 
546     s = migrate_get_current();
547 
548     return s->parameters.cpu_throttle_increment;
549 }
550 
551 uint8_t migrate_cpu_throttle_initial(void)
552 {
553     MigrationState *s;
554 
555     s = migrate_get_current();
556 
557     return s->parameters.cpu_throttle_initial;
558 }
559 
560 bool migrate_cpu_throttle_tailslow(void)
561 {
562     MigrationState *s;
563 
564     s = migrate_get_current();
565 
566     return s->parameters.cpu_throttle_tailslow;
567 }
568 
569 int migrate_decompress_threads(void)
570 {
571     MigrationState *s;
572 
573     s = migrate_get_current();
574 
575     return s->parameters.decompress_threads;
576 }
577 
578 uint8_t migrate_max_cpu_throttle(void)
579 {
580     MigrationState *s;
581 
582     s = migrate_get_current();
583 
584     return s->parameters.max_cpu_throttle;
585 }
586 
587 uint64_t migrate_max_bandwidth(void)
588 {
589     MigrationState *s;
590 
591     s = migrate_get_current();
592 
593     return s->parameters.max_bandwidth;
594 }
595 
596 int64_t migrate_max_postcopy_bandwidth(void)
597 {
598     MigrationState *s;
599 
600     s = migrate_get_current();
601 
602     return s->parameters.max_postcopy_bandwidth;
603 }
604 
605 int migrate_multifd_channels(void)
606 {
607     MigrationState *s;
608 
609     s = migrate_get_current();
610 
611     return s->parameters.multifd_channels;
612 }
613 
614 MultiFDCompression migrate_multifd_compression(void)
615 {
616     MigrationState *s;
617 
618     s = migrate_get_current();
619 
620     assert(s->parameters.multifd_compression < MULTIFD_COMPRESSION__MAX);
621     return s->parameters.multifd_compression;
622 }
623 
624 int migrate_multifd_zlib_level(void)
625 {
626     MigrationState *s;
627 
628     s = migrate_get_current();
629 
630     return s->parameters.multifd_zlib_level;
631 }
632 
633 int migrate_multifd_zstd_level(void)
634 {
635     MigrationState *s;
636 
637     s = migrate_get_current();
638 
639     return s->parameters.multifd_zstd_level;
640 }
641 
642 uint8_t migrate_throttle_trigger_threshold(void)
643 {
644     MigrationState *s;
645 
646     s = migrate_get_current();
647 
648     return s->parameters.throttle_trigger_threshold;
649 }
650 
651 uint64_t migrate_xbzrle_cache_size(void)
652 {
653     MigrationState *s;
654 
655     s = migrate_get_current();
656 
657     return s->parameters.xbzrle_cache_size;
658 }
659 
660 /* parameters helpers */
661 
662 AnnounceParameters *migrate_announce_params(void)
663 {
664     static AnnounceParameters ap;
665 
666     MigrationState *s = migrate_get_current();
667 
668     ap.initial = s->parameters.announce_initial;
669     ap.max = s->parameters.announce_max;
670     ap.rounds = s->parameters.announce_rounds;
671     ap.step = s->parameters.announce_step;
672 
673     return &ap;
674 }
675 
676 MigrationParameters *qmp_query_migrate_parameters(Error **errp)
677 {
678     MigrationParameters *params;
679     MigrationState *s = migrate_get_current();
680 
681     /* TODO use QAPI_CLONE() instead of duplicating it inline */
682     params = g_malloc0(sizeof(*params));
683     params->has_compress_level = true;
684     params->compress_level = s->parameters.compress_level;
685     params->has_compress_threads = true;
686     params->compress_threads = s->parameters.compress_threads;
687     params->has_compress_wait_thread = true;
688     params->compress_wait_thread = s->parameters.compress_wait_thread;
689     params->has_decompress_threads = true;
690     params->decompress_threads = s->parameters.decompress_threads;
691     params->has_throttle_trigger_threshold = true;
692     params->throttle_trigger_threshold = s->parameters.throttle_trigger_threshold;
693     params->has_cpu_throttle_initial = true;
694     params->cpu_throttle_initial = s->parameters.cpu_throttle_initial;
695     params->has_cpu_throttle_increment = true;
696     params->cpu_throttle_increment = s->parameters.cpu_throttle_increment;
697     params->has_cpu_throttle_tailslow = true;
698     params->cpu_throttle_tailslow = s->parameters.cpu_throttle_tailslow;
699     params->tls_creds = g_strdup(s->parameters.tls_creds);
700     params->tls_hostname = g_strdup(s->parameters.tls_hostname);
701     params->tls_authz = g_strdup(s->parameters.tls_authz ?
702                                  s->parameters.tls_authz : "");
703     params->has_max_bandwidth = true;
704     params->max_bandwidth = s->parameters.max_bandwidth;
705     params->has_downtime_limit = true;
706     params->downtime_limit = s->parameters.downtime_limit;
707     params->has_x_checkpoint_delay = true;
708     params->x_checkpoint_delay = s->parameters.x_checkpoint_delay;
709     params->has_block_incremental = true;
710     params->block_incremental = s->parameters.block_incremental;
711     params->has_multifd_channels = true;
712     params->multifd_channels = s->parameters.multifd_channels;
713     params->has_multifd_compression = true;
714     params->multifd_compression = s->parameters.multifd_compression;
715     params->has_multifd_zlib_level = true;
716     params->multifd_zlib_level = s->parameters.multifd_zlib_level;
717     params->has_multifd_zstd_level = true;
718     params->multifd_zstd_level = s->parameters.multifd_zstd_level;
719     params->has_xbzrle_cache_size = true;
720     params->xbzrle_cache_size = s->parameters.xbzrle_cache_size;
721     params->has_max_postcopy_bandwidth = true;
722     params->max_postcopy_bandwidth = s->parameters.max_postcopy_bandwidth;
723     params->has_max_cpu_throttle = true;
724     params->max_cpu_throttle = s->parameters.max_cpu_throttle;
725     params->has_announce_initial = true;
726     params->announce_initial = s->parameters.announce_initial;
727     params->has_announce_max = true;
728     params->announce_max = s->parameters.announce_max;
729     params->has_announce_rounds = true;
730     params->announce_rounds = s->parameters.announce_rounds;
731     params->has_announce_step = true;
732     params->announce_step = s->parameters.announce_step;
733 
734     if (s->parameters.has_block_bitmap_mapping) {
735         params->has_block_bitmap_mapping = true;
736         params->block_bitmap_mapping =
737             QAPI_CLONE(BitmapMigrationNodeAliasList,
738                        s->parameters.block_bitmap_mapping);
739     }
740 
741     return params;
742 }
743 
744 /*
745  * Check whether the parameters are valid. Error will be put into errp
746  * (if provided). Return true if valid, otherwise false.
747  */
748 bool migrate_params_check(MigrationParameters *params, Error **errp)
749 {
750     if (params->has_compress_level &&
751         (params->compress_level > 9)) {
752         error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "compress_level",
753                    "a value between 0 and 9");
754         return false;
755     }
756 
757     if (params->has_compress_threads && (params->compress_threads < 1)) {
758         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
759                    "compress_threads",
760                    "a value between 1 and 255");
761         return false;
762     }
763 
764     if (params->has_decompress_threads && (params->decompress_threads < 1)) {
765         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
766                    "decompress_threads",
767                    "a value between 1 and 255");
768         return false;
769     }
770 
771     if (params->has_throttle_trigger_threshold &&
772         (params->throttle_trigger_threshold < 1 ||
773          params->throttle_trigger_threshold > 100)) {
774         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
775                    "throttle_trigger_threshold",
776                    "an integer in the range of 1 to 100");
777         return false;
778     }
779 
780     if (params->has_cpu_throttle_initial &&
781         (params->cpu_throttle_initial < 1 ||
782          params->cpu_throttle_initial > 99)) {
783         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
784                    "cpu_throttle_initial",
785                    "an integer in the range of 1 to 99");
786         return false;
787     }
788 
789     if (params->has_cpu_throttle_increment &&
790         (params->cpu_throttle_increment < 1 ||
791          params->cpu_throttle_increment > 99)) {
792         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
793                    "cpu_throttle_increment",
794                    "an integer in the range of 1 to 99");
795         return false;
796     }
797 
798     if (params->has_max_bandwidth && (params->max_bandwidth > SIZE_MAX)) {
799         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
800                    "max_bandwidth",
801                    "an integer in the range of 0 to "stringify(SIZE_MAX)
802                    " bytes/second");
803         return false;
804     }
805 
806     if (params->has_downtime_limit &&
807         (params->downtime_limit > MAX_MIGRATE_DOWNTIME)) {
808         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
809                    "downtime_limit",
810                    "an integer in the range of 0 to "
811                     stringify(MAX_MIGRATE_DOWNTIME)" ms");
812         return false;
813     }
814 
815     /* x_checkpoint_delay is now always positive */
816 
817     if (params->has_multifd_channels && (params->multifd_channels < 1)) {
818         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
819                    "multifd_channels",
820                    "a value between 1 and 255");
821         return false;
822     }
823 
824     if (params->has_multifd_zlib_level &&
825         (params->multifd_zlib_level > 9)) {
826         error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_zlib_level",
827                    "a value between 0 and 9");
828         return false;
829     }
830 
831     if (params->has_multifd_zstd_level &&
832         (params->multifd_zstd_level > 20)) {
833         error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_zstd_level",
834                    "a value between 0 and 20");
835         return false;
836     }
837 
838     if (params->has_xbzrle_cache_size &&
839         (params->xbzrle_cache_size < qemu_target_page_size() ||
840          !is_power_of_2(params->xbzrle_cache_size))) {
841         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
842                    "xbzrle_cache_size",
843                    "a power of two no less than the target page size");
844         return false;
845     }
846 
847     if (params->has_max_cpu_throttle &&
848         (params->max_cpu_throttle < params->cpu_throttle_initial ||
849          params->max_cpu_throttle > 99)) {
850         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
851                    "max_cpu_throttle",
852                    "an integer in the range of cpu_throttle_initial to 99");
853         return false;
854     }
855 
856     if (params->has_announce_initial &&
857         params->announce_initial > 100000) {
858         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
859                    "announce_initial",
860                    "a value between 0 and 100000");
861         return false;
862     }
863     if (params->has_announce_max &&
864         params->announce_max > 100000) {
865         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
866                    "announce_max",
867                    "a value between 0 and 100000");
868        return false;
869     }
870     if (params->has_announce_rounds &&
871         params->announce_rounds > 1000) {
872         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
873                    "announce_rounds",
874                    "a value between 0 and 1000");
875        return false;
876     }
877     if (params->has_announce_step &&
878         (params->announce_step < 1 ||
879         params->announce_step > 10000)) {
880         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
881                    "announce_step",
882                    "a value between 0 and 10000");
883        return false;
884     }
885 
886     if (params->has_block_bitmap_mapping &&
887         !check_dirty_bitmap_mig_alias_map(params->block_bitmap_mapping, errp)) {
888         error_prepend(errp, "Invalid mapping given for block-bitmap-mapping: ");
889         return false;
890     }
891 
892 #ifdef CONFIG_LINUX
893     if (migrate_zero_copy_send() &&
894         ((params->has_multifd_compression && params->multifd_compression) ||
895          (params->tls_creds && *params->tls_creds))) {
896         error_setg(errp,
897                    "Zero copy only available for non-compressed non-TLS multifd migration");
898         return false;
899     }
900 #endif
901 
902     return true;
903 }
904 
905 static void migrate_params_test_apply(MigrateSetParameters *params,
906                                       MigrationParameters *dest)
907 {
908     *dest = migrate_get_current()->parameters;
909 
910     /* TODO use QAPI_CLONE() instead of duplicating it inline */
911 
912     if (params->has_compress_level) {
913         dest->compress_level = params->compress_level;
914     }
915 
916     if (params->has_compress_threads) {
917         dest->compress_threads = params->compress_threads;
918     }
919 
920     if (params->has_compress_wait_thread) {
921         dest->compress_wait_thread = params->compress_wait_thread;
922     }
923 
924     if (params->has_decompress_threads) {
925         dest->decompress_threads = params->decompress_threads;
926     }
927 
928     if (params->has_throttle_trigger_threshold) {
929         dest->throttle_trigger_threshold = params->throttle_trigger_threshold;
930     }
931 
932     if (params->has_cpu_throttle_initial) {
933         dest->cpu_throttle_initial = params->cpu_throttle_initial;
934     }
935 
936     if (params->has_cpu_throttle_increment) {
937         dest->cpu_throttle_increment = params->cpu_throttle_increment;
938     }
939 
940     if (params->has_cpu_throttle_tailslow) {
941         dest->cpu_throttle_tailslow = params->cpu_throttle_tailslow;
942     }
943 
944     if (params->tls_creds) {
945         assert(params->tls_creds->type == QTYPE_QSTRING);
946         dest->tls_creds = params->tls_creds->u.s;
947     }
948 
949     if (params->tls_hostname) {
950         assert(params->tls_hostname->type == QTYPE_QSTRING);
951         dest->tls_hostname = params->tls_hostname->u.s;
952     }
953 
954     if (params->has_max_bandwidth) {
955         dest->max_bandwidth = params->max_bandwidth;
956     }
957 
958     if (params->has_downtime_limit) {
959         dest->downtime_limit = params->downtime_limit;
960     }
961 
962     if (params->has_x_checkpoint_delay) {
963         dest->x_checkpoint_delay = params->x_checkpoint_delay;
964     }
965 
966     if (params->has_block_incremental) {
967         dest->block_incremental = params->block_incremental;
968     }
969     if (params->has_multifd_channels) {
970         dest->multifd_channels = params->multifd_channels;
971     }
972     if (params->has_multifd_compression) {
973         dest->multifd_compression = params->multifd_compression;
974     }
975     if (params->has_xbzrle_cache_size) {
976         dest->xbzrle_cache_size = params->xbzrle_cache_size;
977     }
978     if (params->has_max_postcopy_bandwidth) {
979         dest->max_postcopy_bandwidth = params->max_postcopy_bandwidth;
980     }
981     if (params->has_max_cpu_throttle) {
982         dest->max_cpu_throttle = params->max_cpu_throttle;
983     }
984     if (params->has_announce_initial) {
985         dest->announce_initial = params->announce_initial;
986     }
987     if (params->has_announce_max) {
988         dest->announce_max = params->announce_max;
989     }
990     if (params->has_announce_rounds) {
991         dest->announce_rounds = params->announce_rounds;
992     }
993     if (params->has_announce_step) {
994         dest->announce_step = params->announce_step;
995     }
996 
997     if (params->has_block_bitmap_mapping) {
998         dest->has_block_bitmap_mapping = true;
999         dest->block_bitmap_mapping = params->block_bitmap_mapping;
1000     }
1001 }
1002 
1003 static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
1004 {
1005     MigrationState *s = migrate_get_current();
1006 
1007     /* TODO use QAPI_CLONE() instead of duplicating it inline */
1008 
1009     if (params->has_compress_level) {
1010         s->parameters.compress_level = params->compress_level;
1011     }
1012 
1013     if (params->has_compress_threads) {
1014         s->parameters.compress_threads = params->compress_threads;
1015     }
1016 
1017     if (params->has_compress_wait_thread) {
1018         s->parameters.compress_wait_thread = params->compress_wait_thread;
1019     }
1020 
1021     if (params->has_decompress_threads) {
1022         s->parameters.decompress_threads = params->decompress_threads;
1023     }
1024 
1025     if (params->has_throttle_trigger_threshold) {
1026         s->parameters.throttle_trigger_threshold = params->throttle_trigger_threshold;
1027     }
1028 
1029     if (params->has_cpu_throttle_initial) {
1030         s->parameters.cpu_throttle_initial = params->cpu_throttle_initial;
1031     }
1032 
1033     if (params->has_cpu_throttle_increment) {
1034         s->parameters.cpu_throttle_increment = params->cpu_throttle_increment;
1035     }
1036 
1037     if (params->has_cpu_throttle_tailslow) {
1038         s->parameters.cpu_throttle_tailslow = params->cpu_throttle_tailslow;
1039     }
1040 
1041     if (params->tls_creds) {
1042         g_free(s->parameters.tls_creds);
1043         assert(params->tls_creds->type == QTYPE_QSTRING);
1044         s->parameters.tls_creds = g_strdup(params->tls_creds->u.s);
1045     }
1046 
1047     if (params->tls_hostname) {
1048         g_free(s->parameters.tls_hostname);
1049         assert(params->tls_hostname->type == QTYPE_QSTRING);
1050         s->parameters.tls_hostname = g_strdup(params->tls_hostname->u.s);
1051     }
1052 
1053     if (params->tls_authz) {
1054         g_free(s->parameters.tls_authz);
1055         assert(params->tls_authz->type == QTYPE_QSTRING);
1056         s->parameters.tls_authz = g_strdup(params->tls_authz->u.s);
1057     }
1058 
1059     if (params->has_max_bandwidth) {
1060         s->parameters.max_bandwidth = params->max_bandwidth;
1061         if (s->to_dst_file && !migration_in_postcopy()) {
1062             qemu_file_set_rate_limit(s->to_dst_file,
1063                                 s->parameters.max_bandwidth / XFER_LIMIT_RATIO);
1064         }
1065     }
1066 
1067     if (params->has_downtime_limit) {
1068         s->parameters.downtime_limit = params->downtime_limit;
1069     }
1070 
1071     if (params->has_x_checkpoint_delay) {
1072         s->parameters.x_checkpoint_delay = params->x_checkpoint_delay;
1073         if (migration_in_colo_state()) {
1074             colo_checkpoint_notify(s);
1075         }
1076     }
1077 
1078     if (params->has_block_incremental) {
1079         s->parameters.block_incremental = params->block_incremental;
1080     }
1081     if (params->has_multifd_channels) {
1082         s->parameters.multifd_channels = params->multifd_channels;
1083     }
1084     if (params->has_multifd_compression) {
1085         s->parameters.multifd_compression = params->multifd_compression;
1086     }
1087     if (params->has_xbzrle_cache_size) {
1088         s->parameters.xbzrle_cache_size = params->xbzrle_cache_size;
1089         xbzrle_cache_resize(params->xbzrle_cache_size, errp);
1090     }
1091     if (params->has_max_postcopy_bandwidth) {
1092         s->parameters.max_postcopy_bandwidth = params->max_postcopy_bandwidth;
1093         if (s->to_dst_file && migration_in_postcopy()) {
1094             qemu_file_set_rate_limit(s->to_dst_file,
1095                     s->parameters.max_postcopy_bandwidth / XFER_LIMIT_RATIO);
1096         }
1097     }
1098     if (params->has_max_cpu_throttle) {
1099         s->parameters.max_cpu_throttle = params->max_cpu_throttle;
1100     }
1101     if (params->has_announce_initial) {
1102         s->parameters.announce_initial = params->announce_initial;
1103     }
1104     if (params->has_announce_max) {
1105         s->parameters.announce_max = params->announce_max;
1106     }
1107     if (params->has_announce_rounds) {
1108         s->parameters.announce_rounds = params->announce_rounds;
1109     }
1110     if (params->has_announce_step) {
1111         s->parameters.announce_step = params->announce_step;
1112     }
1113 
1114     if (params->has_block_bitmap_mapping) {
1115         qapi_free_BitmapMigrationNodeAliasList(
1116             s->parameters.block_bitmap_mapping);
1117 
1118         s->parameters.has_block_bitmap_mapping = true;
1119         s->parameters.block_bitmap_mapping =
1120             QAPI_CLONE(BitmapMigrationNodeAliasList,
1121                        params->block_bitmap_mapping);
1122     }
1123 }
1124 
1125 void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp)
1126 {
1127     MigrationParameters tmp;
1128 
1129     /* TODO Rewrite "" to null instead */
1130     if (params->tls_creds
1131         && params->tls_creds->type == QTYPE_QNULL) {
1132         qobject_unref(params->tls_creds->u.n);
1133         params->tls_creds->type = QTYPE_QSTRING;
1134         params->tls_creds->u.s = strdup("");
1135     }
1136     /* TODO Rewrite "" to null instead */
1137     if (params->tls_hostname
1138         && params->tls_hostname->type == QTYPE_QNULL) {
1139         qobject_unref(params->tls_hostname->u.n);
1140         params->tls_hostname->type = QTYPE_QSTRING;
1141         params->tls_hostname->u.s = strdup("");
1142     }
1143 
1144     migrate_params_test_apply(params, &tmp);
1145 
1146     if (!migrate_params_check(&tmp, errp)) {
1147         /* Invalid parameter */
1148         return;
1149     }
1150 
1151     migrate_params_apply(params, errp);
1152 }
1153