xref: /openbmc/qemu/migration/options.c (revision 8f9c532756c598c29282a1ec2f11fb615e2fd3c7)
11f0776f1SJuan Quintela /*
21f0776f1SJuan Quintela  * QEMU migration capabilities
31f0776f1SJuan Quintela  *
41f0776f1SJuan Quintela  * Copyright (c) 2012-2023 Red Hat Inc
51f0776f1SJuan Quintela  *
61f0776f1SJuan Quintela  * Authors:
71f0776f1SJuan Quintela  *   Orit Wasserman <owasserm@redhat.com>
81f0776f1SJuan Quintela  *   Juan Quintela <quintela@redhat.com>
91f0776f1SJuan Quintela  *
101f0776f1SJuan Quintela  * This work is licensed under the terms of the GNU GPL, version 2 or later.
111f0776f1SJuan Quintela  * See the COPYING file in the top-level directory.
121f0776f1SJuan Quintela  */
131f0776f1SJuan Quintela 
141f0776f1SJuan Quintela #include "qemu/osdep.h"
1509d6c965SJuan Quintela #include "exec/target_page.h"
169c894df3SJuan Quintela #include "qapi/clone-visitor.h"
1777608706SJuan Quintela #include "qapi/error.h"
184d0c6b69SJuan Quintela #include "qapi/qapi-commands-migration.h"
199c894df3SJuan Quintela #include "qapi/qapi-visit-migration.h"
20f80196b7SJuan Quintela #include "qapi/qmp/qerror.h"
2109d6c965SJuan Quintela #include "qapi/qmp/qnull.h"
2277608706SJuan Quintela #include "sysemu/runstate.h"
2309d6c965SJuan Quintela #include "migration/colo.h"
242682c4eeSJuan Quintela #include "migration/misc.h"
251f0776f1SJuan Quintela #include "migration.h"
2609d6c965SJuan Quintela #include "qemu-file.h"
2777608706SJuan Quintela #include "ram.h"
281f0776f1SJuan Quintela #include "options.h"
291f0776f1SJuan Quintela 
3009d6c965SJuan Quintela /* Maximum migrate downtime set to 2000 seconds */
3109d6c965SJuan Quintela #define MAX_MIGRATE_DOWNTIME_SECONDS 2000
3209d6c965SJuan Quintela #define MAX_MIGRATE_DOWNTIME (MAX_MIGRATE_DOWNTIME_SECONDS * 1000)
3309d6c965SJuan Quintela 
341f0776f1SJuan Quintela bool migrate_auto_converge(void)
351f0776f1SJuan Quintela {
36*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
371f0776f1SJuan Quintela 
381f0776f1SJuan Quintela     return s->capabilities[MIGRATION_CAPABILITY_AUTO_CONVERGE];
391f0776f1SJuan Quintela }
401f0776f1SJuan Quintela 
411f0776f1SJuan Quintela bool migrate_background_snapshot(void)
421f0776f1SJuan Quintela {
43*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
441f0776f1SJuan Quintela 
451f0776f1SJuan Quintela     return s->capabilities[MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT];
461f0776f1SJuan Quintela }
471f0776f1SJuan Quintela 
489d4b1e5fSJuan Quintela bool migrate_block(void)
499d4b1e5fSJuan Quintela {
50*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
519d4b1e5fSJuan Quintela 
529d4b1e5fSJuan Quintela     return s->capabilities[MIGRATION_CAPABILITY_BLOCK];
539d4b1e5fSJuan Quintela }
549d4b1e5fSJuan Quintela 
555e804644SJuan Quintela bool migrate_colo(void)
565e804644SJuan Quintela {
575e804644SJuan Quintela     MigrationState *s = migrate_get_current();
58*8f9c5327SJuan Quintela 
595e804644SJuan Quintela     return s->capabilities[MIGRATION_CAPABILITY_X_COLO];
605e804644SJuan Quintela }
615e804644SJuan Quintela 
62a7a94d14SJuan Quintela bool migrate_compress(void)
63a7a94d14SJuan Quintela {
64*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
65a7a94d14SJuan Quintela 
66a7a94d14SJuan Quintela     return s->capabilities[MIGRATION_CAPABILITY_COMPRESS];
67a7a94d14SJuan Quintela }
68a7a94d14SJuan Quintela 
691f0776f1SJuan Quintela bool migrate_dirty_bitmaps(void)
701f0776f1SJuan Quintela {
71*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
721f0776f1SJuan Quintela 
731f0776f1SJuan Quintela     return s->capabilities[MIGRATION_CAPABILITY_DIRTY_BITMAPS];
741f0776f1SJuan Quintela }
751f0776f1SJuan Quintela 
76b890902cSJuan Quintela bool migrate_events(void)
77b890902cSJuan Quintela {
78*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
79b890902cSJuan Quintela 
80b890902cSJuan Quintela     return s->capabilities[MIGRATION_CAPABILITY_EVENTS];
81b890902cSJuan Quintela }
82b890902cSJuan Quintela 
831f0776f1SJuan Quintela bool migrate_ignore_shared(void)
841f0776f1SJuan Quintela {
85*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
861f0776f1SJuan Quintela 
871f0776f1SJuan Quintela     return s->capabilities[MIGRATION_CAPABILITY_X_IGNORE_SHARED];
881f0776f1SJuan Quintela }
891f0776f1SJuan Quintela 
901f0776f1SJuan Quintela bool migrate_late_block_activate(void)
911f0776f1SJuan Quintela {
92*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
931f0776f1SJuan Quintela 
941f0776f1SJuan Quintela     return s->capabilities[MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE];
951f0776f1SJuan Quintela }
961f0776f1SJuan Quintela 
9751b07548SJuan Quintela bool migrate_multifd(void)
9851b07548SJuan Quintela {
99*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
10051b07548SJuan Quintela 
10151b07548SJuan Quintela     return s->capabilities[MIGRATION_CAPABILITY_MULTIFD];
10251b07548SJuan Quintela }
10351b07548SJuan Quintela 
1041f0776f1SJuan Quintela bool migrate_pause_before_switchover(void)
1051f0776f1SJuan Quintela {
106*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
1071f0776f1SJuan Quintela 
1081f0776f1SJuan Quintela     return s->capabilities[MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER];
1091f0776f1SJuan Quintela }
1101f0776f1SJuan Quintela 
1111f0776f1SJuan Quintela bool migrate_postcopy_blocktime(void)
1121f0776f1SJuan Quintela {
113*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
1141f0776f1SJuan Quintela 
1151f0776f1SJuan Quintela     return s->capabilities[MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME];
1161f0776f1SJuan Quintela }
1171f0776f1SJuan Quintela 
1181f0776f1SJuan Quintela bool migrate_postcopy_preempt(void)
1191f0776f1SJuan Quintela {
120*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
1211f0776f1SJuan Quintela 
1221f0776f1SJuan Quintela     return s->capabilities[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT];
1231f0776f1SJuan Quintela }
1241f0776f1SJuan Quintela 
1251f0776f1SJuan Quintela bool migrate_postcopy_ram(void)
1261f0776f1SJuan Quintela {
127*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
1281f0776f1SJuan Quintela 
1291f0776f1SJuan Quintela     return s->capabilities[MIGRATION_CAPABILITY_POSTCOPY_RAM];
1301f0776f1SJuan Quintela }
1311f0776f1SJuan Quintela 
13217cba690SJuan Quintela bool migrate_rdma_pin_all(void)
13317cba690SJuan Quintela {
13417cba690SJuan Quintela     MigrationState *s = migrate_get_current();
13517cba690SJuan Quintela 
13617cba690SJuan Quintela     return s->capabilities[MIGRATION_CAPABILITY_RDMA_PIN_ALL];
13717cba690SJuan Quintela }
13817cba690SJuan Quintela 
1391f0776f1SJuan Quintela bool migrate_release_ram(void)
1401f0776f1SJuan Quintela {
141*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
1421f0776f1SJuan Quintela 
1431f0776f1SJuan Quintela     return s->capabilities[MIGRATION_CAPABILITY_RELEASE_RAM];
1441f0776f1SJuan Quintela }
1451f0776f1SJuan Quintela 
14638ad1110SJuan Quintela bool migrate_return_path(void)
14738ad1110SJuan Quintela {
148*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
14938ad1110SJuan Quintela 
15038ad1110SJuan Quintela     return s->capabilities[MIGRATION_CAPABILITY_RETURN_PATH];
15138ad1110SJuan Quintela }
15238ad1110SJuan Quintela 
1531f0776f1SJuan Quintela bool migrate_validate_uuid(void)
1541f0776f1SJuan Quintela {
155*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
1561f0776f1SJuan Quintela 
1571f0776f1SJuan Quintela     return s->capabilities[MIGRATION_CAPABILITY_VALIDATE_UUID];
1581f0776f1SJuan Quintela }
1591f0776f1SJuan Quintela 
16087dca0c9SJuan Quintela bool migrate_xbzrle(void)
16187dca0c9SJuan Quintela {
162*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
16387dca0c9SJuan Quintela 
16487dca0c9SJuan Quintela     return s->capabilities[MIGRATION_CAPABILITY_XBZRLE];
16587dca0c9SJuan Quintela }
16687dca0c9SJuan Quintela 
1671f0776f1SJuan Quintela bool migrate_zero_blocks(void)
1681f0776f1SJuan Quintela {
169*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
1701f0776f1SJuan Quintela 
1711f0776f1SJuan Quintela     return s->capabilities[MIGRATION_CAPABILITY_ZERO_BLOCKS];
1721f0776f1SJuan Quintela }
173b4bc342cSJuan Quintela 
174b4bc342cSJuan Quintela bool migrate_zero_copy_send(void)
175b4bc342cSJuan Quintela {
176*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
177b4bc342cSJuan Quintela 
178b4bc342cSJuan Quintela     return s->capabilities[MIGRATION_CAPABILITY_ZERO_COPY_SEND];
179b4bc342cSJuan Quintela }
180f774fde5SJuan Quintela 
181f774fde5SJuan Quintela /* pseudo capabilities */
182f774fde5SJuan Quintela 
183f774fde5SJuan Quintela bool migrate_postcopy(void)
184f774fde5SJuan Quintela {
185f774fde5SJuan Quintela     return migrate_postcopy_ram() || migrate_dirty_bitmaps();
186f774fde5SJuan Quintela }
187f774fde5SJuan Quintela 
18810d4703bSJuan Quintela bool migrate_tls(void)
18910d4703bSJuan Quintela {
190*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
19110d4703bSJuan Quintela 
19210d4703bSJuan Quintela     return s->parameters.tls_creds && *s->parameters.tls_creds;
19310d4703bSJuan Quintela }
19410d4703bSJuan Quintela 
19577608706SJuan Quintela typedef enum WriteTrackingSupport {
19677608706SJuan Quintela     WT_SUPPORT_UNKNOWN = 0,
19777608706SJuan Quintela     WT_SUPPORT_ABSENT,
19877608706SJuan Quintela     WT_SUPPORT_AVAILABLE,
19977608706SJuan Quintela     WT_SUPPORT_COMPATIBLE
20077608706SJuan Quintela } WriteTrackingSupport;
20177608706SJuan Quintela 
20277608706SJuan Quintela static
20377608706SJuan Quintela WriteTrackingSupport migrate_query_write_tracking(void)
20477608706SJuan Quintela {
20577608706SJuan Quintela     /* Check if kernel supports required UFFD features */
20677608706SJuan Quintela     if (!ram_write_tracking_available()) {
20777608706SJuan Quintela         return WT_SUPPORT_ABSENT;
20877608706SJuan Quintela     }
20977608706SJuan Quintela     /*
21077608706SJuan Quintela      * Check if current memory configuration is
21177608706SJuan Quintela      * compatible with required UFFD features.
21277608706SJuan Quintela      */
21377608706SJuan Quintela     if (!ram_write_tracking_compatible()) {
21477608706SJuan Quintela         return WT_SUPPORT_AVAILABLE;
21577608706SJuan Quintela     }
21677608706SJuan Quintela 
21777608706SJuan Quintela     return WT_SUPPORT_COMPATIBLE;
21877608706SJuan Quintela }
21977608706SJuan Quintela 
22077608706SJuan Quintela /* Migration capabilities set */
22177608706SJuan Quintela struct MigrateCapsSet {
22277608706SJuan Quintela     int size;                       /* Capability set size */
22377608706SJuan Quintela     MigrationCapability caps[];     /* Variadic array of capabilities */
22477608706SJuan Quintela };
22577608706SJuan Quintela typedef struct MigrateCapsSet MigrateCapsSet;
22677608706SJuan Quintela 
22777608706SJuan Quintela /* Define and initialize MigrateCapsSet */
22877608706SJuan Quintela #define INITIALIZE_MIGRATE_CAPS_SET(_name, ...)   \
22977608706SJuan Quintela     MigrateCapsSet _name = {    \
23077608706SJuan Quintela         .size = sizeof((int []) { __VA_ARGS__ }) / sizeof(int), \
23177608706SJuan Quintela         .caps = { __VA_ARGS__ } \
23277608706SJuan Quintela     }
23377608706SJuan Quintela 
23477608706SJuan Quintela /* Background-snapshot compatibility check list */
23577608706SJuan Quintela static const
23677608706SJuan Quintela INITIALIZE_MIGRATE_CAPS_SET(check_caps_background_snapshot,
23777608706SJuan Quintela     MIGRATION_CAPABILITY_POSTCOPY_RAM,
23877608706SJuan Quintela     MIGRATION_CAPABILITY_DIRTY_BITMAPS,
23977608706SJuan Quintela     MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME,
24077608706SJuan Quintela     MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE,
24177608706SJuan Quintela     MIGRATION_CAPABILITY_RETURN_PATH,
24277608706SJuan Quintela     MIGRATION_CAPABILITY_MULTIFD,
24377608706SJuan Quintela     MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER,
24477608706SJuan Quintela     MIGRATION_CAPABILITY_AUTO_CONVERGE,
24577608706SJuan Quintela     MIGRATION_CAPABILITY_RELEASE_RAM,
24677608706SJuan Quintela     MIGRATION_CAPABILITY_RDMA_PIN_ALL,
24777608706SJuan Quintela     MIGRATION_CAPABILITY_COMPRESS,
24877608706SJuan Quintela     MIGRATION_CAPABILITY_XBZRLE,
24977608706SJuan Quintela     MIGRATION_CAPABILITY_X_COLO,
25077608706SJuan Quintela     MIGRATION_CAPABILITY_VALIDATE_UUID,
25177608706SJuan Quintela     MIGRATION_CAPABILITY_ZERO_COPY_SEND);
25277608706SJuan Quintela 
25377608706SJuan Quintela /**
25477608706SJuan Quintela  * @migration_caps_check - check capability compatibility
25577608706SJuan Quintela  *
25677608706SJuan Quintela  * @old_caps: old capability list
25777608706SJuan Quintela  * @new_caps: new capability list
25877608706SJuan Quintela  * @errp: set *errp if the check failed, with reason
25977608706SJuan Quintela  *
26077608706SJuan Quintela  * Returns true if check passed, otherwise false.
26177608706SJuan Quintela  */
26277608706SJuan Quintela bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
26377608706SJuan Quintela {
26477608706SJuan Quintela     MigrationIncomingState *mis = migration_incoming_get_current();
26577608706SJuan Quintela 
26674c38cf7SPeter Xu     ERRP_GUARD();
26777608706SJuan Quintela #ifndef CONFIG_LIVE_BLOCK_MIGRATION
26877608706SJuan Quintela     if (new_caps[MIGRATION_CAPABILITY_BLOCK]) {
26977608706SJuan Quintela         error_setg(errp, "QEMU compiled without old-style (blk/-b, inc/-i) "
27077608706SJuan Quintela                    "block migration");
27177608706SJuan Quintela         error_append_hint(errp, "Use drive_mirror+NBD instead.\n");
27277608706SJuan Quintela         return false;
27377608706SJuan Quintela     }
27477608706SJuan Quintela #endif
27577608706SJuan Quintela 
27677608706SJuan Quintela #ifndef CONFIG_REPLICATION
27777608706SJuan Quintela     if (new_caps[MIGRATION_CAPABILITY_X_COLO]) {
27877608706SJuan Quintela         error_setg(errp, "QEMU compiled without replication module"
27977608706SJuan Quintela                    " can't enable COLO");
28077608706SJuan Quintela         error_append_hint(errp, "Please enable replication before COLO.\n");
28177608706SJuan Quintela         return false;
28277608706SJuan Quintela     }
28377608706SJuan Quintela #endif
28477608706SJuan Quintela 
28577608706SJuan Quintela     if (new_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
28677608706SJuan Quintela         /* This check is reasonably expensive, so only when it's being
28777608706SJuan Quintela          * set the first time, also it's only the destination that needs
28877608706SJuan Quintela          * special support.
28977608706SJuan Quintela          */
29077608706SJuan Quintela         if (!old_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] &&
29177608706SJuan Quintela             runstate_check(RUN_STATE_INMIGRATE) &&
29274c38cf7SPeter Xu             !postcopy_ram_supported_by_host(mis, errp)) {
29374c38cf7SPeter Xu             error_prepend(errp, "Postcopy is not supported: ");
29477608706SJuan Quintela             return false;
29577608706SJuan Quintela         }
29677608706SJuan Quintela 
29777608706SJuan Quintela         if (new_caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED]) {
29877608706SJuan Quintela             error_setg(errp, "Postcopy is not compatible with ignore-shared");
29977608706SJuan Quintela             return false;
30077608706SJuan Quintela         }
301b405dfffSLeonardo Bras 
302b405dfffSLeonardo Bras         if (new_caps[MIGRATION_CAPABILITY_MULTIFD]) {
303b405dfffSLeonardo Bras             error_setg(errp, "Postcopy is not yet compatible with multifd");
304b405dfffSLeonardo Bras             return false;
305b405dfffSLeonardo Bras         }
30677608706SJuan Quintela     }
30777608706SJuan Quintela 
30877608706SJuan Quintela     if (new_caps[MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT]) {
30977608706SJuan Quintela         WriteTrackingSupport wt_support;
31077608706SJuan Quintela         int idx;
31177608706SJuan Quintela         /*
31277608706SJuan Quintela          * Check if 'background-snapshot' capability is supported by
31377608706SJuan Quintela          * host kernel and compatible with guest memory configuration.
31477608706SJuan Quintela          */
31577608706SJuan Quintela         wt_support = migrate_query_write_tracking();
31677608706SJuan Quintela         if (wt_support < WT_SUPPORT_AVAILABLE) {
31777608706SJuan Quintela             error_setg(errp, "Background-snapshot is not supported by host kernel");
31877608706SJuan Quintela             return false;
31977608706SJuan Quintela         }
32077608706SJuan Quintela         if (wt_support < WT_SUPPORT_COMPATIBLE) {
32177608706SJuan Quintela             error_setg(errp, "Background-snapshot is not compatible "
32277608706SJuan Quintela                     "with guest memory configuration");
32377608706SJuan Quintela             return false;
32477608706SJuan Quintela         }
32577608706SJuan Quintela 
32677608706SJuan Quintela         /*
32777608706SJuan Quintela          * Check if there are any migration capabilities
32877608706SJuan Quintela          * incompatible with 'background-snapshot'.
32977608706SJuan Quintela          */
33077608706SJuan Quintela         for (idx = 0; idx < check_caps_background_snapshot.size; idx++) {
33177608706SJuan Quintela             int incomp_cap = check_caps_background_snapshot.caps[idx];
33277608706SJuan Quintela             if (new_caps[incomp_cap]) {
33377608706SJuan Quintela                 error_setg(errp,
33477608706SJuan Quintela                         "Background-snapshot is not compatible with %s",
33577608706SJuan Quintela                         MigrationCapability_str(incomp_cap));
33677608706SJuan Quintela                 return false;
33777608706SJuan Quintela             }
33877608706SJuan Quintela         }
33977608706SJuan Quintela     }
34077608706SJuan Quintela 
34177608706SJuan Quintela #ifdef CONFIG_LINUX
34277608706SJuan Quintela     if (new_caps[MIGRATION_CAPABILITY_ZERO_COPY_SEND] &&
34377608706SJuan Quintela         (!new_caps[MIGRATION_CAPABILITY_MULTIFD] ||
34477608706SJuan Quintela          new_caps[MIGRATION_CAPABILITY_COMPRESS] ||
34577608706SJuan Quintela          new_caps[MIGRATION_CAPABILITY_XBZRLE] ||
34677608706SJuan Quintela          migrate_multifd_compression() ||
34710d4703bSJuan Quintela          migrate_tls())) {
34877608706SJuan Quintela         error_setg(errp,
34977608706SJuan Quintela                    "Zero copy only available for non-compressed non-TLS multifd migration");
35077608706SJuan Quintela         return false;
35177608706SJuan Quintela     }
35277608706SJuan Quintela #else
35377608706SJuan Quintela     if (new_caps[MIGRATION_CAPABILITY_ZERO_COPY_SEND]) {
35477608706SJuan Quintela         error_setg(errp,
35577608706SJuan Quintela                    "Zero copy currently only available on Linux");
35677608706SJuan Quintela         return false;
35777608706SJuan Quintela     }
35877608706SJuan Quintela #endif
35977608706SJuan Quintela 
36077608706SJuan Quintela     if (new_caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT]) {
36177608706SJuan Quintela         if (!new_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
36277608706SJuan Quintela             error_setg(errp, "Postcopy preempt requires postcopy-ram");
36377608706SJuan Quintela             return false;
36477608706SJuan Quintela         }
36577608706SJuan Quintela 
36677608706SJuan Quintela         /*
36777608706SJuan Quintela          * Preempt mode requires urgent pages to be sent in separate
36877608706SJuan Quintela          * channel, OTOH compression logic will disorder all pages into
36977608706SJuan Quintela          * different compression channels, which is not compatible with the
37077608706SJuan Quintela          * preempt assumptions on channel assignments.
37177608706SJuan Quintela          */
37277608706SJuan Quintela         if (new_caps[MIGRATION_CAPABILITY_COMPRESS]) {
37377608706SJuan Quintela             error_setg(errp, "Postcopy preempt not compatible with compress");
37477608706SJuan Quintela             return false;
37577608706SJuan Quintela         }
37677608706SJuan Quintela     }
37777608706SJuan Quintela 
37877608706SJuan Quintela     if (new_caps[MIGRATION_CAPABILITY_MULTIFD]) {
37977608706SJuan Quintela         if (new_caps[MIGRATION_CAPABILITY_COMPRESS]) {
38077608706SJuan Quintela             error_setg(errp, "Multifd is not compatible with compress");
38177608706SJuan Quintela             return false;
38277608706SJuan Quintela         }
38377608706SJuan Quintela     }
38477608706SJuan Quintela 
38577608706SJuan Quintela     return true;
38677608706SJuan Quintela }
3874d0c6b69SJuan Quintela 
388f80196b7SJuan Quintela bool migrate_cap_set(int cap, bool value, Error **errp)
389f80196b7SJuan Quintela {
390f80196b7SJuan Quintela     MigrationState *s = migrate_get_current();
391f80196b7SJuan Quintela     bool new_caps[MIGRATION_CAPABILITY__MAX];
392f80196b7SJuan Quintela 
393f80196b7SJuan Quintela     if (migration_is_running(s->state)) {
394f80196b7SJuan Quintela         error_setg(errp, QERR_MIGRATION_ACTIVE);
395f80196b7SJuan Quintela         return false;
396f80196b7SJuan Quintela     }
397f80196b7SJuan Quintela 
398f80196b7SJuan Quintela     memcpy(new_caps, s->capabilities, sizeof(new_caps));
399f80196b7SJuan Quintela     new_caps[cap] = value;
400f80196b7SJuan Quintela 
401f80196b7SJuan Quintela     if (!migrate_caps_check(s->capabilities, new_caps, errp)) {
402f80196b7SJuan Quintela         return false;
403f80196b7SJuan Quintela     }
404f80196b7SJuan Quintela     s->capabilities[cap] = value;
405f80196b7SJuan Quintela     return true;
406f80196b7SJuan Quintela }
407f80196b7SJuan Quintela 
4084d0c6b69SJuan Quintela MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp)
4094d0c6b69SJuan Quintela {
4104d0c6b69SJuan Quintela     MigrationCapabilityStatusList *head = NULL, **tail = &head;
4114d0c6b69SJuan Quintela     MigrationCapabilityStatus *caps;
4124d0c6b69SJuan Quintela     MigrationState *s = migrate_get_current();
4134d0c6b69SJuan Quintela     int i;
4144d0c6b69SJuan Quintela 
4154d0c6b69SJuan Quintela     for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
4164d0c6b69SJuan Quintela #ifndef CONFIG_LIVE_BLOCK_MIGRATION
4174d0c6b69SJuan Quintela         if (i == MIGRATION_CAPABILITY_BLOCK) {
4184d0c6b69SJuan Quintela             continue;
4194d0c6b69SJuan Quintela         }
4204d0c6b69SJuan Quintela #endif
4214d0c6b69SJuan Quintela         caps = g_malloc0(sizeof(*caps));
4224d0c6b69SJuan Quintela         caps->capability = i;
4234d0c6b69SJuan Quintela         caps->state = s->capabilities[i];
4244d0c6b69SJuan Quintela         QAPI_LIST_APPEND(tail, caps);
4254d0c6b69SJuan Quintela     }
4264d0c6b69SJuan Quintela 
4274d0c6b69SJuan Quintela     return head;
4284d0c6b69SJuan Quintela }
42945c1de13SJuan Quintela 
43045c1de13SJuan Quintela void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
43145c1de13SJuan Quintela                                   Error **errp)
43245c1de13SJuan Quintela {
43345c1de13SJuan Quintela     MigrationState *s = migrate_get_current();
43445c1de13SJuan Quintela     MigrationCapabilityStatusList *cap;
43545c1de13SJuan Quintela     bool new_caps[MIGRATION_CAPABILITY__MAX];
43645c1de13SJuan Quintela 
43745c1de13SJuan Quintela     if (migration_is_running(s->state)) {
43845c1de13SJuan Quintela         error_setg(errp, QERR_MIGRATION_ACTIVE);
43945c1de13SJuan Quintela         return;
44045c1de13SJuan Quintela     }
44145c1de13SJuan Quintela 
44245c1de13SJuan Quintela     memcpy(new_caps, s->capabilities, sizeof(new_caps));
44345c1de13SJuan Quintela     for (cap = params; cap; cap = cap->next) {
44445c1de13SJuan Quintela         new_caps[cap->value->capability] = cap->value->state;
44545c1de13SJuan Quintela     }
44645c1de13SJuan Quintela 
44745c1de13SJuan Quintela     if (!migrate_caps_check(s->capabilities, new_caps, errp)) {
44845c1de13SJuan Quintela         return;
44945c1de13SJuan Quintela     }
45045c1de13SJuan Quintela 
45145c1de13SJuan Quintela     for (cap = params; cap; cap = cap->next) {
45245c1de13SJuan Quintela         s->capabilities[cap->value->capability] = cap->value->state;
45345c1de13SJuan Quintela     }
45445c1de13SJuan Quintela }
4551dfc4b9eSJuan Quintela 
4561dfc4b9eSJuan Quintela /* parameters */
4571dfc4b9eSJuan Quintela 
4586f8be708SJuan Quintela bool migrate_block_incremental(void)
4596f8be708SJuan Quintela {
460*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
4616f8be708SJuan Quintela 
4626f8be708SJuan Quintela     return s->parameters.block_incremental;
4636f8be708SJuan Quintela }
4646f8be708SJuan Quintela 
465f94a858fSJuan Quintela uint32_t migrate_checkpoint_delay(void)
466f94a858fSJuan Quintela {
467*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
468f94a858fSJuan Quintela 
469f94a858fSJuan Quintela     return s->parameters.x_checkpoint_delay;
470f94a858fSJuan Quintela }
471f94a858fSJuan Quintela 
4721dfc4b9eSJuan Quintela int migrate_compress_level(void)
4731dfc4b9eSJuan Quintela {
474*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
4751dfc4b9eSJuan Quintela 
4761dfc4b9eSJuan Quintela     return s->parameters.compress_level;
4771dfc4b9eSJuan Quintela }
4781dfc4b9eSJuan Quintela 
4791dfc4b9eSJuan Quintela int migrate_compress_threads(void)
4801dfc4b9eSJuan Quintela {
481*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
4821dfc4b9eSJuan Quintela 
4831dfc4b9eSJuan Quintela     return s->parameters.compress_threads;
4841dfc4b9eSJuan Quintela }
4851dfc4b9eSJuan Quintela 
4861dfc4b9eSJuan Quintela int migrate_compress_wait_thread(void)
4871dfc4b9eSJuan Quintela {
488*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
4891dfc4b9eSJuan Quintela 
4901dfc4b9eSJuan Quintela     return s->parameters.compress_wait_thread;
4911dfc4b9eSJuan Quintela }
4921dfc4b9eSJuan Quintela 
4939605c2acSJuan Quintela uint8_t migrate_cpu_throttle_increment(void)
4949605c2acSJuan Quintela {
495*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
4969605c2acSJuan Quintela 
4979605c2acSJuan Quintela     return s->parameters.cpu_throttle_increment;
4989605c2acSJuan Quintela }
4999605c2acSJuan Quintela 
5002a8ec380SJuan Quintela uint8_t migrate_cpu_throttle_initial(void)
5012a8ec380SJuan Quintela {
502*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
5032a8ec380SJuan Quintela 
5042a8ec380SJuan Quintela     return s->parameters.cpu_throttle_initial;
5052a8ec380SJuan Quintela }
5062a8ec380SJuan Quintela 
507873f674cSJuan Quintela bool migrate_cpu_throttle_tailslow(void)
508873f674cSJuan Quintela {
509*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
510873f674cSJuan Quintela 
511873f674cSJuan Quintela     return s->parameters.cpu_throttle_tailslow;
512873f674cSJuan Quintela }
513873f674cSJuan Quintela 
5141dfc4b9eSJuan Quintela int migrate_decompress_threads(void)
5151dfc4b9eSJuan Quintela {
516*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
5171dfc4b9eSJuan Quintela 
5181dfc4b9eSJuan Quintela     return s->parameters.decompress_threads;
5191dfc4b9eSJuan Quintela }
5201dfc4b9eSJuan Quintela 
52124155bd0SJuan Quintela uint8_t migrate_max_cpu_throttle(void)
52224155bd0SJuan Quintela {
523*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
52424155bd0SJuan Quintela 
52524155bd0SJuan Quintela     return s->parameters.max_cpu_throttle;
52624155bd0SJuan Quintela }
52724155bd0SJuan Quintela 
5289c894df3SJuan Quintela uint64_t migrate_max_bandwidth(void)
5299c894df3SJuan Quintela {
530*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
5319c894df3SJuan Quintela 
5329c894df3SJuan Quintela     return s->parameters.max_bandwidth;
5339c894df3SJuan Quintela }
5349c894df3SJuan Quintela 
5351dfc4b9eSJuan Quintela int64_t migrate_max_postcopy_bandwidth(void)
5361dfc4b9eSJuan Quintela {
537*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
5381dfc4b9eSJuan Quintela 
5391dfc4b9eSJuan Quintela     return s->parameters.max_postcopy_bandwidth;
5401dfc4b9eSJuan Quintela }
5411dfc4b9eSJuan Quintela 
5421dfc4b9eSJuan Quintela int migrate_multifd_channels(void)
5431dfc4b9eSJuan Quintela {
544*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
5451dfc4b9eSJuan Quintela 
5461dfc4b9eSJuan Quintela     return s->parameters.multifd_channels;
5471dfc4b9eSJuan Quintela }
5481dfc4b9eSJuan Quintela 
5491dfc4b9eSJuan Quintela MultiFDCompression migrate_multifd_compression(void)
5501dfc4b9eSJuan Quintela {
551*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
5521dfc4b9eSJuan Quintela 
5531dfc4b9eSJuan Quintela     assert(s->parameters.multifd_compression < MULTIFD_COMPRESSION__MAX);
5541dfc4b9eSJuan Quintela     return s->parameters.multifd_compression;
5551dfc4b9eSJuan Quintela }
5561dfc4b9eSJuan Quintela 
5571dfc4b9eSJuan Quintela int migrate_multifd_zlib_level(void)
5581dfc4b9eSJuan Quintela {
559*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
5601dfc4b9eSJuan Quintela 
5611dfc4b9eSJuan Quintela     return s->parameters.multifd_zlib_level;
5621dfc4b9eSJuan Quintela }
5631dfc4b9eSJuan Quintela 
5641dfc4b9eSJuan Quintela int migrate_multifd_zstd_level(void)
5651dfc4b9eSJuan Quintela {
566*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
5671dfc4b9eSJuan Quintela 
5681dfc4b9eSJuan Quintela     return s->parameters.multifd_zstd_level;
5691dfc4b9eSJuan Quintela }
5701dfc4b9eSJuan Quintela 
5716499efdbSJuan Quintela uint8_t migrate_throttle_trigger_threshold(void)
5726499efdbSJuan Quintela {
573*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
5746499efdbSJuan Quintela 
5756499efdbSJuan Quintela     return s->parameters.throttle_trigger_threshold;
5766499efdbSJuan Quintela }
5776499efdbSJuan Quintela 
5781dfc4b9eSJuan Quintela uint64_t migrate_xbzrle_cache_size(void)
5791dfc4b9eSJuan Quintela {
580*8f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
5811dfc4b9eSJuan Quintela 
5821dfc4b9eSJuan Quintela     return s->parameters.xbzrle_cache_size;
5831dfc4b9eSJuan Quintela }
5842682c4eeSJuan Quintela 
5852682c4eeSJuan Quintela /* parameters helpers */
5862682c4eeSJuan Quintela 
5872682c4eeSJuan Quintela AnnounceParameters *migrate_announce_params(void)
5882682c4eeSJuan Quintela {
5892682c4eeSJuan Quintela     static AnnounceParameters ap;
5902682c4eeSJuan Quintela 
5912682c4eeSJuan Quintela     MigrationState *s = migrate_get_current();
5922682c4eeSJuan Quintela 
5932682c4eeSJuan Quintela     ap.initial = s->parameters.announce_initial;
5942682c4eeSJuan Quintela     ap.max = s->parameters.announce_max;
5952682c4eeSJuan Quintela     ap.rounds = s->parameters.announce_rounds;
5962682c4eeSJuan Quintela     ap.step = s->parameters.announce_step;
5972682c4eeSJuan Quintela 
5982682c4eeSJuan Quintela     return &ap;
5992682c4eeSJuan Quintela }
6009c894df3SJuan Quintela 
6019c894df3SJuan Quintela MigrationParameters *qmp_query_migrate_parameters(Error **errp)
6029c894df3SJuan Quintela {
6039c894df3SJuan Quintela     MigrationParameters *params;
6049c894df3SJuan Quintela     MigrationState *s = migrate_get_current();
6059c894df3SJuan Quintela 
6069c894df3SJuan Quintela     /* TODO use QAPI_CLONE() instead of duplicating it inline */
6079c894df3SJuan Quintela     params = g_malloc0(sizeof(*params));
6089c894df3SJuan Quintela     params->has_compress_level = true;
6099c894df3SJuan Quintela     params->compress_level = s->parameters.compress_level;
6109c894df3SJuan Quintela     params->has_compress_threads = true;
6119c894df3SJuan Quintela     params->compress_threads = s->parameters.compress_threads;
6129c894df3SJuan Quintela     params->has_compress_wait_thread = true;
6139c894df3SJuan Quintela     params->compress_wait_thread = s->parameters.compress_wait_thread;
6149c894df3SJuan Quintela     params->has_decompress_threads = true;
6159c894df3SJuan Quintela     params->decompress_threads = s->parameters.decompress_threads;
6169c894df3SJuan Quintela     params->has_throttle_trigger_threshold = true;
6179c894df3SJuan Quintela     params->throttle_trigger_threshold = s->parameters.throttle_trigger_threshold;
6189c894df3SJuan Quintela     params->has_cpu_throttle_initial = true;
6199c894df3SJuan Quintela     params->cpu_throttle_initial = s->parameters.cpu_throttle_initial;
6209c894df3SJuan Quintela     params->has_cpu_throttle_increment = true;
6219c894df3SJuan Quintela     params->cpu_throttle_increment = s->parameters.cpu_throttle_increment;
6229c894df3SJuan Quintela     params->has_cpu_throttle_tailslow = true;
6239c894df3SJuan Quintela     params->cpu_throttle_tailslow = s->parameters.cpu_throttle_tailslow;
6249c894df3SJuan Quintela     params->tls_creds = g_strdup(s->parameters.tls_creds);
6259c894df3SJuan Quintela     params->tls_hostname = g_strdup(s->parameters.tls_hostname);
6269c894df3SJuan Quintela     params->tls_authz = g_strdup(s->parameters.tls_authz ?
6279c894df3SJuan Quintela                                  s->parameters.tls_authz : "");
6289c894df3SJuan Quintela     params->has_max_bandwidth = true;
6299c894df3SJuan Quintela     params->max_bandwidth = s->parameters.max_bandwidth;
6309c894df3SJuan Quintela     params->has_downtime_limit = true;
6319c894df3SJuan Quintela     params->downtime_limit = s->parameters.downtime_limit;
6329c894df3SJuan Quintela     params->has_x_checkpoint_delay = true;
6339c894df3SJuan Quintela     params->x_checkpoint_delay = s->parameters.x_checkpoint_delay;
6349c894df3SJuan Quintela     params->has_block_incremental = true;
6359c894df3SJuan Quintela     params->block_incremental = s->parameters.block_incremental;
6369c894df3SJuan Quintela     params->has_multifd_channels = true;
6379c894df3SJuan Quintela     params->multifd_channels = s->parameters.multifd_channels;
6389c894df3SJuan Quintela     params->has_multifd_compression = true;
6399c894df3SJuan Quintela     params->multifd_compression = s->parameters.multifd_compression;
6409c894df3SJuan Quintela     params->has_multifd_zlib_level = true;
6419c894df3SJuan Quintela     params->multifd_zlib_level = s->parameters.multifd_zlib_level;
6429c894df3SJuan Quintela     params->has_multifd_zstd_level = true;
6439c894df3SJuan Quintela     params->multifd_zstd_level = s->parameters.multifd_zstd_level;
6449c894df3SJuan Quintela     params->has_xbzrle_cache_size = true;
6459c894df3SJuan Quintela     params->xbzrle_cache_size = s->parameters.xbzrle_cache_size;
6469c894df3SJuan Quintela     params->has_max_postcopy_bandwidth = true;
6479c894df3SJuan Quintela     params->max_postcopy_bandwidth = s->parameters.max_postcopy_bandwidth;
6489c894df3SJuan Quintela     params->has_max_cpu_throttle = true;
6499c894df3SJuan Quintela     params->max_cpu_throttle = s->parameters.max_cpu_throttle;
6509c894df3SJuan Quintela     params->has_announce_initial = true;
6519c894df3SJuan Quintela     params->announce_initial = s->parameters.announce_initial;
6529c894df3SJuan Quintela     params->has_announce_max = true;
6539c894df3SJuan Quintela     params->announce_max = s->parameters.announce_max;
6549c894df3SJuan Quintela     params->has_announce_rounds = true;
6559c894df3SJuan Quintela     params->announce_rounds = s->parameters.announce_rounds;
6569c894df3SJuan Quintela     params->has_announce_step = true;
6579c894df3SJuan Quintela     params->announce_step = s->parameters.announce_step;
6589c894df3SJuan Quintela 
6599c894df3SJuan Quintela     if (s->parameters.has_block_bitmap_mapping) {
6609c894df3SJuan Quintela         params->has_block_bitmap_mapping = true;
6619c894df3SJuan Quintela         params->block_bitmap_mapping =
6629c894df3SJuan Quintela             QAPI_CLONE(BitmapMigrationNodeAliasList,
6639c894df3SJuan Quintela                        s->parameters.block_bitmap_mapping);
6649c894df3SJuan Quintela     }
6659c894df3SJuan Quintela 
6669c894df3SJuan Quintela     return params;
6679c894df3SJuan Quintela }
66809d6c965SJuan Quintela 
66961a174e2SJuan Quintela void migrate_params_init(MigrationParameters *params)
67061a174e2SJuan Quintela {
67161a174e2SJuan Quintela     params->tls_hostname = g_strdup("");
67261a174e2SJuan Quintela     params->tls_creds = g_strdup("");
67361a174e2SJuan Quintela 
67461a174e2SJuan Quintela     /* Set has_* up only for parameter checks */
67561a174e2SJuan Quintela     params->has_compress_level = true;
67661a174e2SJuan Quintela     params->has_compress_threads = true;
67761a174e2SJuan Quintela     params->has_compress_wait_thread = true;
67861a174e2SJuan Quintela     params->has_decompress_threads = true;
67961a174e2SJuan Quintela     params->has_throttle_trigger_threshold = true;
68061a174e2SJuan Quintela     params->has_cpu_throttle_initial = true;
68161a174e2SJuan Quintela     params->has_cpu_throttle_increment = true;
68261a174e2SJuan Quintela     params->has_cpu_throttle_tailslow = true;
68361a174e2SJuan Quintela     params->has_max_bandwidth = true;
68461a174e2SJuan Quintela     params->has_downtime_limit = true;
68561a174e2SJuan Quintela     params->has_x_checkpoint_delay = true;
68661a174e2SJuan Quintela     params->has_block_incremental = true;
68761a174e2SJuan Quintela     params->has_multifd_channels = true;
68861a174e2SJuan Quintela     params->has_multifd_compression = true;
68961a174e2SJuan Quintela     params->has_multifd_zlib_level = true;
69061a174e2SJuan Quintela     params->has_multifd_zstd_level = true;
69161a174e2SJuan Quintela     params->has_xbzrle_cache_size = true;
69261a174e2SJuan Quintela     params->has_max_postcopy_bandwidth = true;
69361a174e2SJuan Quintela     params->has_max_cpu_throttle = true;
69461a174e2SJuan Quintela     params->has_announce_initial = true;
69561a174e2SJuan Quintela     params->has_announce_max = true;
69661a174e2SJuan Quintela     params->has_announce_rounds = true;
69761a174e2SJuan Quintela     params->has_announce_step = true;
69861a174e2SJuan Quintela }
69961a174e2SJuan Quintela 
70009d6c965SJuan Quintela /*
70109d6c965SJuan Quintela  * Check whether the parameters are valid. Error will be put into errp
70209d6c965SJuan Quintela  * (if provided). Return true if valid, otherwise false.
70309d6c965SJuan Quintela  */
70409d6c965SJuan Quintela bool migrate_params_check(MigrationParameters *params, Error **errp)
70509d6c965SJuan Quintela {
70609d6c965SJuan Quintela     if (params->has_compress_level &&
70709d6c965SJuan Quintela         (params->compress_level > 9)) {
70809d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "compress_level",
70909d6c965SJuan Quintela                    "a value between 0 and 9");
71009d6c965SJuan Quintela         return false;
71109d6c965SJuan Quintela     }
71209d6c965SJuan Quintela 
71309d6c965SJuan Quintela     if (params->has_compress_threads && (params->compress_threads < 1)) {
71409d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
71509d6c965SJuan Quintela                    "compress_threads",
71609d6c965SJuan Quintela                    "a value between 1 and 255");
71709d6c965SJuan Quintela         return false;
71809d6c965SJuan Quintela     }
71909d6c965SJuan Quintela 
72009d6c965SJuan Quintela     if (params->has_decompress_threads && (params->decompress_threads < 1)) {
72109d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
72209d6c965SJuan Quintela                    "decompress_threads",
72309d6c965SJuan Quintela                    "a value between 1 and 255");
72409d6c965SJuan Quintela         return false;
72509d6c965SJuan Quintela     }
72609d6c965SJuan Quintela 
72709d6c965SJuan Quintela     if (params->has_throttle_trigger_threshold &&
72809d6c965SJuan Quintela         (params->throttle_trigger_threshold < 1 ||
72909d6c965SJuan Quintela          params->throttle_trigger_threshold > 100)) {
73009d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
73109d6c965SJuan Quintela                    "throttle_trigger_threshold",
73209d6c965SJuan Quintela                    "an integer in the range of 1 to 100");
73309d6c965SJuan Quintela         return false;
73409d6c965SJuan Quintela     }
73509d6c965SJuan Quintela 
73609d6c965SJuan Quintela     if (params->has_cpu_throttle_initial &&
73709d6c965SJuan Quintela         (params->cpu_throttle_initial < 1 ||
73809d6c965SJuan Quintela          params->cpu_throttle_initial > 99)) {
73909d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
74009d6c965SJuan Quintela                    "cpu_throttle_initial",
74109d6c965SJuan Quintela                    "an integer in the range of 1 to 99");
74209d6c965SJuan Quintela         return false;
74309d6c965SJuan Quintela     }
74409d6c965SJuan Quintela 
74509d6c965SJuan Quintela     if (params->has_cpu_throttle_increment &&
74609d6c965SJuan Quintela         (params->cpu_throttle_increment < 1 ||
74709d6c965SJuan Quintela          params->cpu_throttle_increment > 99)) {
74809d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
74909d6c965SJuan Quintela                    "cpu_throttle_increment",
75009d6c965SJuan Quintela                    "an integer in the range of 1 to 99");
75109d6c965SJuan Quintela         return false;
75209d6c965SJuan Quintela     }
75309d6c965SJuan Quintela 
75409d6c965SJuan Quintela     if (params->has_max_bandwidth && (params->max_bandwidth > SIZE_MAX)) {
75509d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
75609d6c965SJuan Quintela                    "max_bandwidth",
75709d6c965SJuan Quintela                    "an integer in the range of 0 to "stringify(SIZE_MAX)
75809d6c965SJuan Quintela                    " bytes/second");
75909d6c965SJuan Quintela         return false;
76009d6c965SJuan Quintela     }
76109d6c965SJuan Quintela 
76209d6c965SJuan Quintela     if (params->has_downtime_limit &&
76309d6c965SJuan Quintela         (params->downtime_limit > MAX_MIGRATE_DOWNTIME)) {
76409d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
76509d6c965SJuan Quintela                    "downtime_limit",
76609d6c965SJuan Quintela                    "an integer in the range of 0 to "
76709d6c965SJuan Quintela                     stringify(MAX_MIGRATE_DOWNTIME)" ms");
76809d6c965SJuan Quintela         return false;
76909d6c965SJuan Quintela     }
77009d6c965SJuan Quintela 
77109d6c965SJuan Quintela     /* x_checkpoint_delay is now always positive */
77209d6c965SJuan Quintela 
77309d6c965SJuan Quintela     if (params->has_multifd_channels && (params->multifd_channels < 1)) {
77409d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
77509d6c965SJuan Quintela                    "multifd_channels",
77609d6c965SJuan Quintela                    "a value between 1 and 255");
77709d6c965SJuan Quintela         return false;
77809d6c965SJuan Quintela     }
77909d6c965SJuan Quintela 
78009d6c965SJuan Quintela     if (params->has_multifd_zlib_level &&
78109d6c965SJuan Quintela         (params->multifd_zlib_level > 9)) {
78209d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_zlib_level",
78309d6c965SJuan Quintela                    "a value between 0 and 9");
78409d6c965SJuan Quintela         return false;
78509d6c965SJuan Quintela     }
78609d6c965SJuan Quintela 
78709d6c965SJuan Quintela     if (params->has_multifd_zstd_level &&
78809d6c965SJuan Quintela         (params->multifd_zstd_level > 20)) {
78909d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_zstd_level",
79009d6c965SJuan Quintela                    "a value between 0 and 20");
79109d6c965SJuan Quintela         return false;
79209d6c965SJuan Quintela     }
79309d6c965SJuan Quintela 
79409d6c965SJuan Quintela     if (params->has_xbzrle_cache_size &&
79509d6c965SJuan Quintela         (params->xbzrle_cache_size < qemu_target_page_size() ||
79609d6c965SJuan Quintela          !is_power_of_2(params->xbzrle_cache_size))) {
79709d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
79809d6c965SJuan Quintela                    "xbzrle_cache_size",
79909d6c965SJuan Quintela                    "a power of two no less than the target page size");
80009d6c965SJuan Quintela         return false;
80109d6c965SJuan Quintela     }
80209d6c965SJuan Quintela 
80309d6c965SJuan Quintela     if (params->has_max_cpu_throttle &&
80409d6c965SJuan Quintela         (params->max_cpu_throttle < params->cpu_throttle_initial ||
80509d6c965SJuan Quintela          params->max_cpu_throttle > 99)) {
80609d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
80709d6c965SJuan Quintela                    "max_cpu_throttle",
80809d6c965SJuan Quintela                    "an integer in the range of cpu_throttle_initial to 99");
80909d6c965SJuan Quintela         return false;
81009d6c965SJuan Quintela     }
81109d6c965SJuan Quintela 
81209d6c965SJuan Quintela     if (params->has_announce_initial &&
81309d6c965SJuan Quintela         params->announce_initial > 100000) {
81409d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
81509d6c965SJuan Quintela                    "announce_initial",
81609d6c965SJuan Quintela                    "a value between 0 and 100000");
81709d6c965SJuan Quintela         return false;
81809d6c965SJuan Quintela     }
81909d6c965SJuan Quintela     if (params->has_announce_max &&
82009d6c965SJuan Quintela         params->announce_max > 100000) {
82109d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
82209d6c965SJuan Quintela                    "announce_max",
82309d6c965SJuan Quintela                    "a value between 0 and 100000");
82409d6c965SJuan Quintela        return false;
82509d6c965SJuan Quintela     }
82609d6c965SJuan Quintela     if (params->has_announce_rounds &&
82709d6c965SJuan Quintela         params->announce_rounds > 1000) {
82809d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
82909d6c965SJuan Quintela                    "announce_rounds",
83009d6c965SJuan Quintela                    "a value between 0 and 1000");
83109d6c965SJuan Quintela        return false;
83209d6c965SJuan Quintela     }
83309d6c965SJuan Quintela     if (params->has_announce_step &&
83409d6c965SJuan Quintela         (params->announce_step < 1 ||
83509d6c965SJuan Quintela         params->announce_step > 10000)) {
83609d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
83709d6c965SJuan Quintela                    "announce_step",
83809d6c965SJuan Quintela                    "a value between 0 and 10000");
83909d6c965SJuan Quintela        return false;
84009d6c965SJuan Quintela     }
84109d6c965SJuan Quintela 
84209d6c965SJuan Quintela     if (params->has_block_bitmap_mapping &&
84309d6c965SJuan Quintela         !check_dirty_bitmap_mig_alias_map(params->block_bitmap_mapping, errp)) {
84409d6c965SJuan Quintela         error_prepend(errp, "Invalid mapping given for block-bitmap-mapping: ");
84509d6c965SJuan Quintela         return false;
84609d6c965SJuan Quintela     }
84709d6c965SJuan Quintela 
84809d6c965SJuan Quintela #ifdef CONFIG_LINUX
84909d6c965SJuan Quintela     if (migrate_zero_copy_send() &&
85009d6c965SJuan Quintela         ((params->has_multifd_compression && params->multifd_compression) ||
85109d6c965SJuan Quintela          (params->tls_creds && *params->tls_creds))) {
85209d6c965SJuan Quintela         error_setg(errp,
85309d6c965SJuan Quintela                    "Zero copy only available for non-compressed non-TLS multifd migration");
85409d6c965SJuan Quintela         return false;
85509d6c965SJuan Quintela     }
85609d6c965SJuan Quintela #endif
85709d6c965SJuan Quintela 
85809d6c965SJuan Quintela     return true;
85909d6c965SJuan Quintela }
86009d6c965SJuan Quintela 
86109d6c965SJuan Quintela static void migrate_params_test_apply(MigrateSetParameters *params,
86209d6c965SJuan Quintela                                       MigrationParameters *dest)
86309d6c965SJuan Quintela {
86409d6c965SJuan Quintela     *dest = migrate_get_current()->parameters;
86509d6c965SJuan Quintela 
86609d6c965SJuan Quintela     /* TODO use QAPI_CLONE() instead of duplicating it inline */
86709d6c965SJuan Quintela 
86809d6c965SJuan Quintela     if (params->has_compress_level) {
86909d6c965SJuan Quintela         dest->compress_level = params->compress_level;
87009d6c965SJuan Quintela     }
87109d6c965SJuan Quintela 
87209d6c965SJuan Quintela     if (params->has_compress_threads) {
87309d6c965SJuan Quintela         dest->compress_threads = params->compress_threads;
87409d6c965SJuan Quintela     }
87509d6c965SJuan Quintela 
87609d6c965SJuan Quintela     if (params->has_compress_wait_thread) {
87709d6c965SJuan Quintela         dest->compress_wait_thread = params->compress_wait_thread;
87809d6c965SJuan Quintela     }
87909d6c965SJuan Quintela 
88009d6c965SJuan Quintela     if (params->has_decompress_threads) {
88109d6c965SJuan Quintela         dest->decompress_threads = params->decompress_threads;
88209d6c965SJuan Quintela     }
88309d6c965SJuan Quintela 
88409d6c965SJuan Quintela     if (params->has_throttle_trigger_threshold) {
88509d6c965SJuan Quintela         dest->throttle_trigger_threshold = params->throttle_trigger_threshold;
88609d6c965SJuan Quintela     }
88709d6c965SJuan Quintela 
88809d6c965SJuan Quintela     if (params->has_cpu_throttle_initial) {
88909d6c965SJuan Quintela         dest->cpu_throttle_initial = params->cpu_throttle_initial;
89009d6c965SJuan Quintela     }
89109d6c965SJuan Quintela 
89209d6c965SJuan Quintela     if (params->has_cpu_throttle_increment) {
89309d6c965SJuan Quintela         dest->cpu_throttle_increment = params->cpu_throttle_increment;
89409d6c965SJuan Quintela     }
89509d6c965SJuan Quintela 
89609d6c965SJuan Quintela     if (params->has_cpu_throttle_tailslow) {
89709d6c965SJuan Quintela         dest->cpu_throttle_tailslow = params->cpu_throttle_tailslow;
89809d6c965SJuan Quintela     }
89909d6c965SJuan Quintela 
90009d6c965SJuan Quintela     if (params->tls_creds) {
90109d6c965SJuan Quintela         assert(params->tls_creds->type == QTYPE_QSTRING);
90209d6c965SJuan Quintela         dest->tls_creds = params->tls_creds->u.s;
90309d6c965SJuan Quintela     }
90409d6c965SJuan Quintela 
90509d6c965SJuan Quintela     if (params->tls_hostname) {
90609d6c965SJuan Quintela         assert(params->tls_hostname->type == QTYPE_QSTRING);
90709d6c965SJuan Quintela         dest->tls_hostname = params->tls_hostname->u.s;
90809d6c965SJuan Quintela     }
90909d6c965SJuan Quintela 
91009d6c965SJuan Quintela     if (params->has_max_bandwidth) {
91109d6c965SJuan Quintela         dest->max_bandwidth = params->max_bandwidth;
91209d6c965SJuan Quintela     }
91309d6c965SJuan Quintela 
91409d6c965SJuan Quintela     if (params->has_downtime_limit) {
91509d6c965SJuan Quintela         dest->downtime_limit = params->downtime_limit;
91609d6c965SJuan Quintela     }
91709d6c965SJuan Quintela 
91809d6c965SJuan Quintela     if (params->has_x_checkpoint_delay) {
91909d6c965SJuan Quintela         dest->x_checkpoint_delay = params->x_checkpoint_delay;
92009d6c965SJuan Quintela     }
92109d6c965SJuan Quintela 
92209d6c965SJuan Quintela     if (params->has_block_incremental) {
92309d6c965SJuan Quintela         dest->block_incremental = params->block_incremental;
92409d6c965SJuan Quintela     }
92509d6c965SJuan Quintela     if (params->has_multifd_channels) {
92609d6c965SJuan Quintela         dest->multifd_channels = params->multifd_channels;
92709d6c965SJuan Quintela     }
92809d6c965SJuan Quintela     if (params->has_multifd_compression) {
92909d6c965SJuan Quintela         dest->multifd_compression = params->multifd_compression;
93009d6c965SJuan Quintela     }
93109d6c965SJuan Quintela     if (params->has_xbzrle_cache_size) {
93209d6c965SJuan Quintela         dest->xbzrle_cache_size = params->xbzrle_cache_size;
93309d6c965SJuan Quintela     }
93409d6c965SJuan Quintela     if (params->has_max_postcopy_bandwidth) {
93509d6c965SJuan Quintela         dest->max_postcopy_bandwidth = params->max_postcopy_bandwidth;
93609d6c965SJuan Quintela     }
93709d6c965SJuan Quintela     if (params->has_max_cpu_throttle) {
93809d6c965SJuan Quintela         dest->max_cpu_throttle = params->max_cpu_throttle;
93909d6c965SJuan Quintela     }
94009d6c965SJuan Quintela     if (params->has_announce_initial) {
94109d6c965SJuan Quintela         dest->announce_initial = params->announce_initial;
94209d6c965SJuan Quintela     }
94309d6c965SJuan Quintela     if (params->has_announce_max) {
94409d6c965SJuan Quintela         dest->announce_max = params->announce_max;
94509d6c965SJuan Quintela     }
94609d6c965SJuan Quintela     if (params->has_announce_rounds) {
94709d6c965SJuan Quintela         dest->announce_rounds = params->announce_rounds;
94809d6c965SJuan Quintela     }
94909d6c965SJuan Quintela     if (params->has_announce_step) {
95009d6c965SJuan Quintela         dest->announce_step = params->announce_step;
95109d6c965SJuan Quintela     }
95209d6c965SJuan Quintela 
95309d6c965SJuan Quintela     if (params->has_block_bitmap_mapping) {
95409d6c965SJuan Quintela         dest->has_block_bitmap_mapping = true;
95509d6c965SJuan Quintela         dest->block_bitmap_mapping = params->block_bitmap_mapping;
95609d6c965SJuan Quintela     }
95709d6c965SJuan Quintela }
95809d6c965SJuan Quintela 
95909d6c965SJuan Quintela static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
96009d6c965SJuan Quintela {
96109d6c965SJuan Quintela     MigrationState *s = migrate_get_current();
96209d6c965SJuan Quintela 
96309d6c965SJuan Quintela     /* TODO use QAPI_CLONE() instead of duplicating it inline */
96409d6c965SJuan Quintela 
96509d6c965SJuan Quintela     if (params->has_compress_level) {
96609d6c965SJuan Quintela         s->parameters.compress_level = params->compress_level;
96709d6c965SJuan Quintela     }
96809d6c965SJuan Quintela 
96909d6c965SJuan Quintela     if (params->has_compress_threads) {
97009d6c965SJuan Quintela         s->parameters.compress_threads = params->compress_threads;
97109d6c965SJuan Quintela     }
97209d6c965SJuan Quintela 
97309d6c965SJuan Quintela     if (params->has_compress_wait_thread) {
97409d6c965SJuan Quintela         s->parameters.compress_wait_thread = params->compress_wait_thread;
97509d6c965SJuan Quintela     }
97609d6c965SJuan Quintela 
97709d6c965SJuan Quintela     if (params->has_decompress_threads) {
97809d6c965SJuan Quintela         s->parameters.decompress_threads = params->decompress_threads;
97909d6c965SJuan Quintela     }
98009d6c965SJuan Quintela 
98109d6c965SJuan Quintela     if (params->has_throttle_trigger_threshold) {
98209d6c965SJuan Quintela         s->parameters.throttle_trigger_threshold = params->throttle_trigger_threshold;
98309d6c965SJuan Quintela     }
98409d6c965SJuan Quintela 
98509d6c965SJuan Quintela     if (params->has_cpu_throttle_initial) {
98609d6c965SJuan Quintela         s->parameters.cpu_throttle_initial = params->cpu_throttle_initial;
98709d6c965SJuan Quintela     }
98809d6c965SJuan Quintela 
98909d6c965SJuan Quintela     if (params->has_cpu_throttle_increment) {
99009d6c965SJuan Quintela         s->parameters.cpu_throttle_increment = params->cpu_throttle_increment;
99109d6c965SJuan Quintela     }
99209d6c965SJuan Quintela 
99309d6c965SJuan Quintela     if (params->has_cpu_throttle_tailslow) {
99409d6c965SJuan Quintela         s->parameters.cpu_throttle_tailslow = params->cpu_throttle_tailslow;
99509d6c965SJuan Quintela     }
99609d6c965SJuan Quintela 
99709d6c965SJuan Quintela     if (params->tls_creds) {
99809d6c965SJuan Quintela         g_free(s->parameters.tls_creds);
99909d6c965SJuan Quintela         assert(params->tls_creds->type == QTYPE_QSTRING);
100009d6c965SJuan Quintela         s->parameters.tls_creds = g_strdup(params->tls_creds->u.s);
100109d6c965SJuan Quintela     }
100209d6c965SJuan Quintela 
100309d6c965SJuan Quintela     if (params->tls_hostname) {
100409d6c965SJuan Quintela         g_free(s->parameters.tls_hostname);
100509d6c965SJuan Quintela         assert(params->tls_hostname->type == QTYPE_QSTRING);
100609d6c965SJuan Quintela         s->parameters.tls_hostname = g_strdup(params->tls_hostname->u.s);
100709d6c965SJuan Quintela     }
100809d6c965SJuan Quintela 
100909d6c965SJuan Quintela     if (params->tls_authz) {
101009d6c965SJuan Quintela         g_free(s->parameters.tls_authz);
101109d6c965SJuan Quintela         assert(params->tls_authz->type == QTYPE_QSTRING);
101209d6c965SJuan Quintela         s->parameters.tls_authz = g_strdup(params->tls_authz->u.s);
101309d6c965SJuan Quintela     }
101409d6c965SJuan Quintela 
101509d6c965SJuan Quintela     if (params->has_max_bandwidth) {
101609d6c965SJuan Quintela         s->parameters.max_bandwidth = params->max_bandwidth;
101709d6c965SJuan Quintela         if (s->to_dst_file && !migration_in_postcopy()) {
101809d6c965SJuan Quintela             qemu_file_set_rate_limit(s->to_dst_file,
101909d6c965SJuan Quintela                                 s->parameters.max_bandwidth / XFER_LIMIT_RATIO);
102009d6c965SJuan Quintela         }
102109d6c965SJuan Quintela     }
102209d6c965SJuan Quintela 
102309d6c965SJuan Quintela     if (params->has_downtime_limit) {
102409d6c965SJuan Quintela         s->parameters.downtime_limit = params->downtime_limit;
102509d6c965SJuan Quintela     }
102609d6c965SJuan Quintela 
102709d6c965SJuan Quintela     if (params->has_x_checkpoint_delay) {
102809d6c965SJuan Quintela         s->parameters.x_checkpoint_delay = params->x_checkpoint_delay;
102909d6c965SJuan Quintela         if (migration_in_colo_state()) {
103009d6c965SJuan Quintela             colo_checkpoint_notify(s);
103109d6c965SJuan Quintela         }
103209d6c965SJuan Quintela     }
103309d6c965SJuan Quintela 
103409d6c965SJuan Quintela     if (params->has_block_incremental) {
103509d6c965SJuan Quintela         s->parameters.block_incremental = params->block_incremental;
103609d6c965SJuan Quintela     }
103709d6c965SJuan Quintela     if (params->has_multifd_channels) {
103809d6c965SJuan Quintela         s->parameters.multifd_channels = params->multifd_channels;
103909d6c965SJuan Quintela     }
104009d6c965SJuan Quintela     if (params->has_multifd_compression) {
104109d6c965SJuan Quintela         s->parameters.multifd_compression = params->multifd_compression;
104209d6c965SJuan Quintela     }
104309d6c965SJuan Quintela     if (params->has_xbzrle_cache_size) {
104409d6c965SJuan Quintela         s->parameters.xbzrle_cache_size = params->xbzrle_cache_size;
104509d6c965SJuan Quintela         xbzrle_cache_resize(params->xbzrle_cache_size, errp);
104609d6c965SJuan Quintela     }
104709d6c965SJuan Quintela     if (params->has_max_postcopy_bandwidth) {
104809d6c965SJuan Quintela         s->parameters.max_postcopy_bandwidth = params->max_postcopy_bandwidth;
104909d6c965SJuan Quintela         if (s->to_dst_file && migration_in_postcopy()) {
105009d6c965SJuan Quintela             qemu_file_set_rate_limit(s->to_dst_file,
105109d6c965SJuan Quintela                     s->parameters.max_postcopy_bandwidth / XFER_LIMIT_RATIO);
105209d6c965SJuan Quintela         }
105309d6c965SJuan Quintela     }
105409d6c965SJuan Quintela     if (params->has_max_cpu_throttle) {
105509d6c965SJuan Quintela         s->parameters.max_cpu_throttle = params->max_cpu_throttle;
105609d6c965SJuan Quintela     }
105709d6c965SJuan Quintela     if (params->has_announce_initial) {
105809d6c965SJuan Quintela         s->parameters.announce_initial = params->announce_initial;
105909d6c965SJuan Quintela     }
106009d6c965SJuan Quintela     if (params->has_announce_max) {
106109d6c965SJuan Quintela         s->parameters.announce_max = params->announce_max;
106209d6c965SJuan Quintela     }
106309d6c965SJuan Quintela     if (params->has_announce_rounds) {
106409d6c965SJuan Quintela         s->parameters.announce_rounds = params->announce_rounds;
106509d6c965SJuan Quintela     }
106609d6c965SJuan Quintela     if (params->has_announce_step) {
106709d6c965SJuan Quintela         s->parameters.announce_step = params->announce_step;
106809d6c965SJuan Quintela     }
106909d6c965SJuan Quintela 
107009d6c965SJuan Quintela     if (params->has_block_bitmap_mapping) {
107109d6c965SJuan Quintela         qapi_free_BitmapMigrationNodeAliasList(
107209d6c965SJuan Quintela             s->parameters.block_bitmap_mapping);
107309d6c965SJuan Quintela 
107409d6c965SJuan Quintela         s->parameters.has_block_bitmap_mapping = true;
107509d6c965SJuan Quintela         s->parameters.block_bitmap_mapping =
107609d6c965SJuan Quintela             QAPI_CLONE(BitmapMigrationNodeAliasList,
107709d6c965SJuan Quintela                        params->block_bitmap_mapping);
107809d6c965SJuan Quintela     }
107909d6c965SJuan Quintela }
108009d6c965SJuan Quintela 
108109d6c965SJuan Quintela void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp)
108209d6c965SJuan Quintela {
108309d6c965SJuan Quintela     MigrationParameters tmp;
108409d6c965SJuan Quintela 
108509d6c965SJuan Quintela     /* TODO Rewrite "" to null instead */
108609d6c965SJuan Quintela     if (params->tls_creds
108709d6c965SJuan Quintela         && params->tls_creds->type == QTYPE_QNULL) {
108809d6c965SJuan Quintela         qobject_unref(params->tls_creds->u.n);
108909d6c965SJuan Quintela         params->tls_creds->type = QTYPE_QSTRING;
109009d6c965SJuan Quintela         params->tls_creds->u.s = strdup("");
109109d6c965SJuan Quintela     }
109209d6c965SJuan Quintela     /* TODO Rewrite "" to null instead */
109309d6c965SJuan Quintela     if (params->tls_hostname
109409d6c965SJuan Quintela         && params->tls_hostname->type == QTYPE_QNULL) {
109509d6c965SJuan Quintela         qobject_unref(params->tls_hostname->u.n);
109609d6c965SJuan Quintela         params->tls_hostname->type = QTYPE_QSTRING;
109709d6c965SJuan Quintela         params->tls_hostname->u.s = strdup("");
109809d6c965SJuan Quintela     }
109909d6c965SJuan Quintela 
110009d6c965SJuan Quintela     migrate_params_test_apply(params, &tmp);
110109d6c965SJuan Quintela 
110209d6c965SJuan Quintela     if (!migrate_params_check(&tmp, errp)) {
110309d6c965SJuan Quintela         /* Invalid parameter */
110409d6c965SJuan Quintela         return;
110509d6c965SJuan Quintela     }
110609d6c965SJuan Quintela 
110709d6c965SJuan Quintela     migrate_params_apply(params, errp);
110809d6c965SJuan Quintela }
1109