xref: /openbmc/qemu/migration/options.c (revision f5da8ba4777f3ab88bfee82bbf8261d6295a26a2)
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 {
368f9c5327SJuan 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 {
438f9c5327SJuan 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 {
508f9c5327SJuan 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();
588f9c5327SJuan Quintela 
595e804644SJuan Quintela     return s->capabilities[MIGRATION_CAPABILITY_X_COLO];
605e804644SJuan Quintela }
615e804644SJuan Quintela 
62a7a94d14SJuan Quintela bool migrate_compress(void)
63a7a94d14SJuan Quintela {
648f9c5327SJuan 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 {
718f9c5327SJuan 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 {
788f9c5327SJuan 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 {
858f9c5327SJuan 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 {
928f9c5327SJuan 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 {
998f9c5327SJuan 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 {
1068f9c5327SJuan 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 {
1138f9c5327SJuan 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 {
1208f9c5327SJuan 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 {
1278f9c5327SJuan 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 {
1418f9c5327SJuan 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 {
1488f9c5327SJuan 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 {
1558f9c5327SJuan 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 {
1628f9c5327SJuan 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 {
1698f9c5327SJuan 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 {
1768f9c5327SJuan 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 {
1908f9c5327SJuan 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 {
4608f9c5327SJuan 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 {
4678f9c5327SJuan 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 {
4748f9c5327SJuan 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 {
4818f9c5327SJuan 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 {
4888f9c5327SJuan 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 {
4958f9c5327SJuan 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 {
5028f9c5327SJuan 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 {
5098f9c5327SJuan 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 {
5168f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
5171dfc4b9eSJuan Quintela 
5181dfc4b9eSJuan Quintela     return s->parameters.decompress_threads;
5191dfc4b9eSJuan Quintela }
5201dfc4b9eSJuan Quintela 
521*f5da8ba4SJuan Quintela uint64_t migrate_downtime_limit(void)
522*f5da8ba4SJuan Quintela {
523*f5da8ba4SJuan Quintela     MigrationState *s = migrate_get_current();
524*f5da8ba4SJuan Quintela 
525*f5da8ba4SJuan Quintela     return s->parameters.downtime_limit;
526*f5da8ba4SJuan Quintela }
527*f5da8ba4SJuan Quintela 
52824155bd0SJuan Quintela uint8_t migrate_max_cpu_throttle(void)
52924155bd0SJuan Quintela {
5308f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
53124155bd0SJuan Quintela 
53224155bd0SJuan Quintela     return s->parameters.max_cpu_throttle;
53324155bd0SJuan Quintela }
53424155bd0SJuan Quintela 
5359c894df3SJuan Quintela uint64_t migrate_max_bandwidth(void)
5369c894df3SJuan Quintela {
5378f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
5389c894df3SJuan Quintela 
5399c894df3SJuan Quintela     return s->parameters.max_bandwidth;
5409c894df3SJuan Quintela }
5419c894df3SJuan Quintela 
5421dfc4b9eSJuan Quintela int64_t migrate_max_postcopy_bandwidth(void)
5431dfc4b9eSJuan Quintela {
5448f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
5451dfc4b9eSJuan Quintela 
5461dfc4b9eSJuan Quintela     return s->parameters.max_postcopy_bandwidth;
5471dfc4b9eSJuan Quintela }
5481dfc4b9eSJuan Quintela 
5491dfc4b9eSJuan Quintela int migrate_multifd_channels(void)
5501dfc4b9eSJuan Quintela {
5518f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
5521dfc4b9eSJuan Quintela 
5531dfc4b9eSJuan Quintela     return s->parameters.multifd_channels;
5541dfc4b9eSJuan Quintela }
5551dfc4b9eSJuan Quintela 
5561dfc4b9eSJuan Quintela MultiFDCompression migrate_multifd_compression(void)
5571dfc4b9eSJuan Quintela {
5588f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
5591dfc4b9eSJuan Quintela 
5601dfc4b9eSJuan Quintela     assert(s->parameters.multifd_compression < MULTIFD_COMPRESSION__MAX);
5611dfc4b9eSJuan Quintela     return s->parameters.multifd_compression;
5621dfc4b9eSJuan Quintela }
5631dfc4b9eSJuan Quintela 
5641dfc4b9eSJuan Quintela int migrate_multifd_zlib_level(void)
5651dfc4b9eSJuan Quintela {
5668f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
5671dfc4b9eSJuan Quintela 
5681dfc4b9eSJuan Quintela     return s->parameters.multifd_zlib_level;
5691dfc4b9eSJuan Quintela }
5701dfc4b9eSJuan Quintela 
5711dfc4b9eSJuan Quintela int migrate_multifd_zstd_level(void)
5721dfc4b9eSJuan Quintela {
5738f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
5741dfc4b9eSJuan Quintela 
5751dfc4b9eSJuan Quintela     return s->parameters.multifd_zstd_level;
5761dfc4b9eSJuan Quintela }
5771dfc4b9eSJuan Quintela 
5786499efdbSJuan Quintela uint8_t migrate_throttle_trigger_threshold(void)
5796499efdbSJuan Quintela {
5808f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
5816499efdbSJuan Quintela 
5826499efdbSJuan Quintela     return s->parameters.throttle_trigger_threshold;
5836499efdbSJuan Quintela }
5846499efdbSJuan Quintela 
5851dfc4b9eSJuan Quintela uint64_t migrate_xbzrle_cache_size(void)
5861dfc4b9eSJuan Quintela {
5878f9c5327SJuan Quintela     MigrationState *s = migrate_get_current();
5881dfc4b9eSJuan Quintela 
5891dfc4b9eSJuan Quintela     return s->parameters.xbzrle_cache_size;
5901dfc4b9eSJuan Quintela }
5912682c4eeSJuan Quintela 
5922682c4eeSJuan Quintela /* parameters helpers */
5932682c4eeSJuan Quintela 
5942682c4eeSJuan Quintela AnnounceParameters *migrate_announce_params(void)
5952682c4eeSJuan Quintela {
5962682c4eeSJuan Quintela     static AnnounceParameters ap;
5972682c4eeSJuan Quintela 
5982682c4eeSJuan Quintela     MigrationState *s = migrate_get_current();
5992682c4eeSJuan Quintela 
6002682c4eeSJuan Quintela     ap.initial = s->parameters.announce_initial;
6012682c4eeSJuan Quintela     ap.max = s->parameters.announce_max;
6022682c4eeSJuan Quintela     ap.rounds = s->parameters.announce_rounds;
6032682c4eeSJuan Quintela     ap.step = s->parameters.announce_step;
6042682c4eeSJuan Quintela 
6052682c4eeSJuan Quintela     return &ap;
6062682c4eeSJuan Quintela }
6079c894df3SJuan Quintela 
6089c894df3SJuan Quintela MigrationParameters *qmp_query_migrate_parameters(Error **errp)
6099c894df3SJuan Quintela {
6109c894df3SJuan Quintela     MigrationParameters *params;
6119c894df3SJuan Quintela     MigrationState *s = migrate_get_current();
6129c894df3SJuan Quintela 
6139c894df3SJuan Quintela     /* TODO use QAPI_CLONE() instead of duplicating it inline */
6149c894df3SJuan Quintela     params = g_malloc0(sizeof(*params));
6159c894df3SJuan Quintela     params->has_compress_level = true;
6169c894df3SJuan Quintela     params->compress_level = s->parameters.compress_level;
6179c894df3SJuan Quintela     params->has_compress_threads = true;
6189c894df3SJuan Quintela     params->compress_threads = s->parameters.compress_threads;
6199c894df3SJuan Quintela     params->has_compress_wait_thread = true;
6209c894df3SJuan Quintela     params->compress_wait_thread = s->parameters.compress_wait_thread;
6219c894df3SJuan Quintela     params->has_decompress_threads = true;
6229c894df3SJuan Quintela     params->decompress_threads = s->parameters.decompress_threads;
6239c894df3SJuan Quintela     params->has_throttle_trigger_threshold = true;
6249c894df3SJuan Quintela     params->throttle_trigger_threshold = s->parameters.throttle_trigger_threshold;
6259c894df3SJuan Quintela     params->has_cpu_throttle_initial = true;
6269c894df3SJuan Quintela     params->cpu_throttle_initial = s->parameters.cpu_throttle_initial;
6279c894df3SJuan Quintela     params->has_cpu_throttle_increment = true;
6289c894df3SJuan Quintela     params->cpu_throttle_increment = s->parameters.cpu_throttle_increment;
6299c894df3SJuan Quintela     params->has_cpu_throttle_tailslow = true;
6309c894df3SJuan Quintela     params->cpu_throttle_tailslow = s->parameters.cpu_throttle_tailslow;
6319c894df3SJuan Quintela     params->tls_creds = g_strdup(s->parameters.tls_creds);
6329c894df3SJuan Quintela     params->tls_hostname = g_strdup(s->parameters.tls_hostname);
6339c894df3SJuan Quintela     params->tls_authz = g_strdup(s->parameters.tls_authz ?
6349c894df3SJuan Quintela                                  s->parameters.tls_authz : "");
6359c894df3SJuan Quintela     params->has_max_bandwidth = true;
6369c894df3SJuan Quintela     params->max_bandwidth = s->parameters.max_bandwidth;
6379c894df3SJuan Quintela     params->has_downtime_limit = true;
6389c894df3SJuan Quintela     params->downtime_limit = s->parameters.downtime_limit;
6399c894df3SJuan Quintela     params->has_x_checkpoint_delay = true;
6409c894df3SJuan Quintela     params->x_checkpoint_delay = s->parameters.x_checkpoint_delay;
6419c894df3SJuan Quintela     params->has_block_incremental = true;
6429c894df3SJuan Quintela     params->block_incremental = s->parameters.block_incremental;
6439c894df3SJuan Quintela     params->has_multifd_channels = true;
6449c894df3SJuan Quintela     params->multifd_channels = s->parameters.multifd_channels;
6459c894df3SJuan Quintela     params->has_multifd_compression = true;
6469c894df3SJuan Quintela     params->multifd_compression = s->parameters.multifd_compression;
6479c894df3SJuan Quintela     params->has_multifd_zlib_level = true;
6489c894df3SJuan Quintela     params->multifd_zlib_level = s->parameters.multifd_zlib_level;
6499c894df3SJuan Quintela     params->has_multifd_zstd_level = true;
6509c894df3SJuan Quintela     params->multifd_zstd_level = s->parameters.multifd_zstd_level;
6519c894df3SJuan Quintela     params->has_xbzrle_cache_size = true;
6529c894df3SJuan Quintela     params->xbzrle_cache_size = s->parameters.xbzrle_cache_size;
6539c894df3SJuan Quintela     params->has_max_postcopy_bandwidth = true;
6549c894df3SJuan Quintela     params->max_postcopy_bandwidth = s->parameters.max_postcopy_bandwidth;
6559c894df3SJuan Quintela     params->has_max_cpu_throttle = true;
6569c894df3SJuan Quintela     params->max_cpu_throttle = s->parameters.max_cpu_throttle;
6579c894df3SJuan Quintela     params->has_announce_initial = true;
6589c894df3SJuan Quintela     params->announce_initial = s->parameters.announce_initial;
6599c894df3SJuan Quintela     params->has_announce_max = true;
6609c894df3SJuan Quintela     params->announce_max = s->parameters.announce_max;
6619c894df3SJuan Quintela     params->has_announce_rounds = true;
6629c894df3SJuan Quintela     params->announce_rounds = s->parameters.announce_rounds;
6639c894df3SJuan Quintela     params->has_announce_step = true;
6649c894df3SJuan Quintela     params->announce_step = s->parameters.announce_step;
6659c894df3SJuan Quintela 
6669c894df3SJuan Quintela     if (s->parameters.has_block_bitmap_mapping) {
6679c894df3SJuan Quintela         params->has_block_bitmap_mapping = true;
6689c894df3SJuan Quintela         params->block_bitmap_mapping =
6699c894df3SJuan Quintela             QAPI_CLONE(BitmapMigrationNodeAliasList,
6709c894df3SJuan Quintela                        s->parameters.block_bitmap_mapping);
6719c894df3SJuan Quintela     }
6729c894df3SJuan Quintela 
6739c894df3SJuan Quintela     return params;
6749c894df3SJuan Quintela }
67509d6c965SJuan Quintela 
67661a174e2SJuan Quintela void migrate_params_init(MigrationParameters *params)
67761a174e2SJuan Quintela {
67861a174e2SJuan Quintela     params->tls_hostname = g_strdup("");
67961a174e2SJuan Quintela     params->tls_creds = g_strdup("");
68061a174e2SJuan Quintela 
68161a174e2SJuan Quintela     /* Set has_* up only for parameter checks */
68261a174e2SJuan Quintela     params->has_compress_level = true;
68361a174e2SJuan Quintela     params->has_compress_threads = true;
68461a174e2SJuan Quintela     params->has_compress_wait_thread = true;
68561a174e2SJuan Quintela     params->has_decompress_threads = true;
68661a174e2SJuan Quintela     params->has_throttle_trigger_threshold = true;
68761a174e2SJuan Quintela     params->has_cpu_throttle_initial = true;
68861a174e2SJuan Quintela     params->has_cpu_throttle_increment = true;
68961a174e2SJuan Quintela     params->has_cpu_throttle_tailslow = true;
69061a174e2SJuan Quintela     params->has_max_bandwidth = true;
69161a174e2SJuan Quintela     params->has_downtime_limit = true;
69261a174e2SJuan Quintela     params->has_x_checkpoint_delay = true;
69361a174e2SJuan Quintela     params->has_block_incremental = true;
69461a174e2SJuan Quintela     params->has_multifd_channels = true;
69561a174e2SJuan Quintela     params->has_multifd_compression = true;
69661a174e2SJuan Quintela     params->has_multifd_zlib_level = true;
69761a174e2SJuan Quintela     params->has_multifd_zstd_level = true;
69861a174e2SJuan Quintela     params->has_xbzrle_cache_size = true;
69961a174e2SJuan Quintela     params->has_max_postcopy_bandwidth = true;
70061a174e2SJuan Quintela     params->has_max_cpu_throttle = true;
70161a174e2SJuan Quintela     params->has_announce_initial = true;
70261a174e2SJuan Quintela     params->has_announce_max = true;
70361a174e2SJuan Quintela     params->has_announce_rounds = true;
70461a174e2SJuan Quintela     params->has_announce_step = true;
70561a174e2SJuan Quintela }
70661a174e2SJuan Quintela 
70709d6c965SJuan Quintela /*
70809d6c965SJuan Quintela  * Check whether the parameters are valid. Error will be put into errp
70909d6c965SJuan Quintela  * (if provided). Return true if valid, otherwise false.
71009d6c965SJuan Quintela  */
71109d6c965SJuan Quintela bool migrate_params_check(MigrationParameters *params, Error **errp)
71209d6c965SJuan Quintela {
71309d6c965SJuan Quintela     if (params->has_compress_level &&
71409d6c965SJuan Quintela         (params->compress_level > 9)) {
71509d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "compress_level",
71609d6c965SJuan Quintela                    "a value between 0 and 9");
71709d6c965SJuan Quintela         return false;
71809d6c965SJuan Quintela     }
71909d6c965SJuan Quintela 
72009d6c965SJuan Quintela     if (params->has_compress_threads && (params->compress_threads < 1)) {
72109d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
72209d6c965SJuan Quintela                    "compress_threads",
72309d6c965SJuan Quintela                    "a value between 1 and 255");
72409d6c965SJuan Quintela         return false;
72509d6c965SJuan Quintela     }
72609d6c965SJuan Quintela 
72709d6c965SJuan Quintela     if (params->has_decompress_threads && (params->decompress_threads < 1)) {
72809d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
72909d6c965SJuan Quintela                    "decompress_threads",
73009d6c965SJuan Quintela                    "a value between 1 and 255");
73109d6c965SJuan Quintela         return false;
73209d6c965SJuan Quintela     }
73309d6c965SJuan Quintela 
73409d6c965SJuan Quintela     if (params->has_throttle_trigger_threshold &&
73509d6c965SJuan Quintela         (params->throttle_trigger_threshold < 1 ||
73609d6c965SJuan Quintela          params->throttle_trigger_threshold > 100)) {
73709d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
73809d6c965SJuan Quintela                    "throttle_trigger_threshold",
73909d6c965SJuan Quintela                    "an integer in the range of 1 to 100");
74009d6c965SJuan Quintela         return false;
74109d6c965SJuan Quintela     }
74209d6c965SJuan Quintela 
74309d6c965SJuan Quintela     if (params->has_cpu_throttle_initial &&
74409d6c965SJuan Quintela         (params->cpu_throttle_initial < 1 ||
74509d6c965SJuan Quintela          params->cpu_throttle_initial > 99)) {
74609d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
74709d6c965SJuan Quintela                    "cpu_throttle_initial",
74809d6c965SJuan Quintela                    "an integer in the range of 1 to 99");
74909d6c965SJuan Quintela         return false;
75009d6c965SJuan Quintela     }
75109d6c965SJuan Quintela 
75209d6c965SJuan Quintela     if (params->has_cpu_throttle_increment &&
75309d6c965SJuan Quintela         (params->cpu_throttle_increment < 1 ||
75409d6c965SJuan Quintela          params->cpu_throttle_increment > 99)) {
75509d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
75609d6c965SJuan Quintela                    "cpu_throttle_increment",
75709d6c965SJuan Quintela                    "an integer in the range of 1 to 99");
75809d6c965SJuan Quintela         return false;
75909d6c965SJuan Quintela     }
76009d6c965SJuan Quintela 
76109d6c965SJuan Quintela     if (params->has_max_bandwidth && (params->max_bandwidth > SIZE_MAX)) {
76209d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
76309d6c965SJuan Quintela                    "max_bandwidth",
76409d6c965SJuan Quintela                    "an integer in the range of 0 to "stringify(SIZE_MAX)
76509d6c965SJuan Quintela                    " bytes/second");
76609d6c965SJuan Quintela         return false;
76709d6c965SJuan Quintela     }
76809d6c965SJuan Quintela 
76909d6c965SJuan Quintela     if (params->has_downtime_limit &&
77009d6c965SJuan Quintela         (params->downtime_limit > MAX_MIGRATE_DOWNTIME)) {
77109d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
77209d6c965SJuan Quintela                    "downtime_limit",
77309d6c965SJuan Quintela                    "an integer in the range of 0 to "
77409d6c965SJuan Quintela                     stringify(MAX_MIGRATE_DOWNTIME)" ms");
77509d6c965SJuan Quintela         return false;
77609d6c965SJuan Quintela     }
77709d6c965SJuan Quintela 
77809d6c965SJuan Quintela     /* x_checkpoint_delay is now always positive */
77909d6c965SJuan Quintela 
78009d6c965SJuan Quintela     if (params->has_multifd_channels && (params->multifd_channels < 1)) {
78109d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
78209d6c965SJuan Quintela                    "multifd_channels",
78309d6c965SJuan Quintela                    "a value between 1 and 255");
78409d6c965SJuan Quintela         return false;
78509d6c965SJuan Quintela     }
78609d6c965SJuan Quintela 
78709d6c965SJuan Quintela     if (params->has_multifd_zlib_level &&
78809d6c965SJuan Quintela         (params->multifd_zlib_level > 9)) {
78909d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_zlib_level",
79009d6c965SJuan Quintela                    "a value between 0 and 9");
79109d6c965SJuan Quintela         return false;
79209d6c965SJuan Quintela     }
79309d6c965SJuan Quintela 
79409d6c965SJuan Quintela     if (params->has_multifd_zstd_level &&
79509d6c965SJuan Quintela         (params->multifd_zstd_level > 20)) {
79609d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_zstd_level",
79709d6c965SJuan Quintela                    "a value between 0 and 20");
79809d6c965SJuan Quintela         return false;
79909d6c965SJuan Quintela     }
80009d6c965SJuan Quintela 
80109d6c965SJuan Quintela     if (params->has_xbzrle_cache_size &&
80209d6c965SJuan Quintela         (params->xbzrle_cache_size < qemu_target_page_size() ||
80309d6c965SJuan Quintela          !is_power_of_2(params->xbzrle_cache_size))) {
80409d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
80509d6c965SJuan Quintela                    "xbzrle_cache_size",
80609d6c965SJuan Quintela                    "a power of two no less than the target page size");
80709d6c965SJuan Quintela         return false;
80809d6c965SJuan Quintela     }
80909d6c965SJuan Quintela 
81009d6c965SJuan Quintela     if (params->has_max_cpu_throttle &&
81109d6c965SJuan Quintela         (params->max_cpu_throttle < params->cpu_throttle_initial ||
81209d6c965SJuan Quintela          params->max_cpu_throttle > 99)) {
81309d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
81409d6c965SJuan Quintela                    "max_cpu_throttle",
81509d6c965SJuan Quintela                    "an integer in the range of cpu_throttle_initial to 99");
81609d6c965SJuan Quintela         return false;
81709d6c965SJuan Quintela     }
81809d6c965SJuan Quintela 
81909d6c965SJuan Quintela     if (params->has_announce_initial &&
82009d6c965SJuan Quintela         params->announce_initial > 100000) {
82109d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
82209d6c965SJuan Quintela                    "announce_initial",
82309d6c965SJuan Quintela                    "a value between 0 and 100000");
82409d6c965SJuan Quintela         return false;
82509d6c965SJuan Quintela     }
82609d6c965SJuan Quintela     if (params->has_announce_max &&
82709d6c965SJuan Quintela         params->announce_max > 100000) {
82809d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
82909d6c965SJuan Quintela                    "announce_max",
83009d6c965SJuan Quintela                    "a value between 0 and 100000");
83109d6c965SJuan Quintela        return false;
83209d6c965SJuan Quintela     }
83309d6c965SJuan Quintela     if (params->has_announce_rounds &&
83409d6c965SJuan Quintela         params->announce_rounds > 1000) {
83509d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
83609d6c965SJuan Quintela                    "announce_rounds",
83709d6c965SJuan Quintela                    "a value between 0 and 1000");
83809d6c965SJuan Quintela        return false;
83909d6c965SJuan Quintela     }
84009d6c965SJuan Quintela     if (params->has_announce_step &&
84109d6c965SJuan Quintela         (params->announce_step < 1 ||
84209d6c965SJuan Quintela         params->announce_step > 10000)) {
84309d6c965SJuan Quintela         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
84409d6c965SJuan Quintela                    "announce_step",
84509d6c965SJuan Quintela                    "a value between 0 and 10000");
84609d6c965SJuan Quintela        return false;
84709d6c965SJuan Quintela     }
84809d6c965SJuan Quintela 
84909d6c965SJuan Quintela     if (params->has_block_bitmap_mapping &&
85009d6c965SJuan Quintela         !check_dirty_bitmap_mig_alias_map(params->block_bitmap_mapping, errp)) {
85109d6c965SJuan Quintela         error_prepend(errp, "Invalid mapping given for block-bitmap-mapping: ");
85209d6c965SJuan Quintela         return false;
85309d6c965SJuan Quintela     }
85409d6c965SJuan Quintela 
85509d6c965SJuan Quintela #ifdef CONFIG_LINUX
85609d6c965SJuan Quintela     if (migrate_zero_copy_send() &&
85709d6c965SJuan Quintela         ((params->has_multifd_compression && params->multifd_compression) ||
85809d6c965SJuan Quintela          (params->tls_creds && *params->tls_creds))) {
85909d6c965SJuan Quintela         error_setg(errp,
86009d6c965SJuan Quintela                    "Zero copy only available for non-compressed non-TLS multifd migration");
86109d6c965SJuan Quintela         return false;
86209d6c965SJuan Quintela     }
86309d6c965SJuan Quintela #endif
86409d6c965SJuan Quintela 
86509d6c965SJuan Quintela     return true;
86609d6c965SJuan Quintela }
86709d6c965SJuan Quintela 
86809d6c965SJuan Quintela static void migrate_params_test_apply(MigrateSetParameters *params,
86909d6c965SJuan Quintela                                       MigrationParameters *dest)
87009d6c965SJuan Quintela {
87109d6c965SJuan Quintela     *dest = migrate_get_current()->parameters;
87209d6c965SJuan Quintela 
87309d6c965SJuan Quintela     /* TODO use QAPI_CLONE() instead of duplicating it inline */
87409d6c965SJuan Quintela 
87509d6c965SJuan Quintela     if (params->has_compress_level) {
87609d6c965SJuan Quintela         dest->compress_level = params->compress_level;
87709d6c965SJuan Quintela     }
87809d6c965SJuan Quintela 
87909d6c965SJuan Quintela     if (params->has_compress_threads) {
88009d6c965SJuan Quintela         dest->compress_threads = params->compress_threads;
88109d6c965SJuan Quintela     }
88209d6c965SJuan Quintela 
88309d6c965SJuan Quintela     if (params->has_compress_wait_thread) {
88409d6c965SJuan Quintela         dest->compress_wait_thread = params->compress_wait_thread;
88509d6c965SJuan Quintela     }
88609d6c965SJuan Quintela 
88709d6c965SJuan Quintela     if (params->has_decompress_threads) {
88809d6c965SJuan Quintela         dest->decompress_threads = params->decompress_threads;
88909d6c965SJuan Quintela     }
89009d6c965SJuan Quintela 
89109d6c965SJuan Quintela     if (params->has_throttle_trigger_threshold) {
89209d6c965SJuan Quintela         dest->throttle_trigger_threshold = params->throttle_trigger_threshold;
89309d6c965SJuan Quintela     }
89409d6c965SJuan Quintela 
89509d6c965SJuan Quintela     if (params->has_cpu_throttle_initial) {
89609d6c965SJuan Quintela         dest->cpu_throttle_initial = params->cpu_throttle_initial;
89709d6c965SJuan Quintela     }
89809d6c965SJuan Quintela 
89909d6c965SJuan Quintela     if (params->has_cpu_throttle_increment) {
90009d6c965SJuan Quintela         dest->cpu_throttle_increment = params->cpu_throttle_increment;
90109d6c965SJuan Quintela     }
90209d6c965SJuan Quintela 
90309d6c965SJuan Quintela     if (params->has_cpu_throttle_tailslow) {
90409d6c965SJuan Quintela         dest->cpu_throttle_tailslow = params->cpu_throttle_tailslow;
90509d6c965SJuan Quintela     }
90609d6c965SJuan Quintela 
90709d6c965SJuan Quintela     if (params->tls_creds) {
90809d6c965SJuan Quintela         assert(params->tls_creds->type == QTYPE_QSTRING);
90909d6c965SJuan Quintela         dest->tls_creds = params->tls_creds->u.s;
91009d6c965SJuan Quintela     }
91109d6c965SJuan Quintela 
91209d6c965SJuan Quintela     if (params->tls_hostname) {
91309d6c965SJuan Quintela         assert(params->tls_hostname->type == QTYPE_QSTRING);
91409d6c965SJuan Quintela         dest->tls_hostname = params->tls_hostname->u.s;
91509d6c965SJuan Quintela     }
91609d6c965SJuan Quintela 
91709d6c965SJuan Quintela     if (params->has_max_bandwidth) {
91809d6c965SJuan Quintela         dest->max_bandwidth = params->max_bandwidth;
91909d6c965SJuan Quintela     }
92009d6c965SJuan Quintela 
92109d6c965SJuan Quintela     if (params->has_downtime_limit) {
92209d6c965SJuan Quintela         dest->downtime_limit = params->downtime_limit;
92309d6c965SJuan Quintela     }
92409d6c965SJuan Quintela 
92509d6c965SJuan Quintela     if (params->has_x_checkpoint_delay) {
92609d6c965SJuan Quintela         dest->x_checkpoint_delay = params->x_checkpoint_delay;
92709d6c965SJuan Quintela     }
92809d6c965SJuan Quintela 
92909d6c965SJuan Quintela     if (params->has_block_incremental) {
93009d6c965SJuan Quintela         dest->block_incremental = params->block_incremental;
93109d6c965SJuan Quintela     }
93209d6c965SJuan Quintela     if (params->has_multifd_channels) {
93309d6c965SJuan Quintela         dest->multifd_channels = params->multifd_channels;
93409d6c965SJuan Quintela     }
93509d6c965SJuan Quintela     if (params->has_multifd_compression) {
93609d6c965SJuan Quintela         dest->multifd_compression = params->multifd_compression;
93709d6c965SJuan Quintela     }
93809d6c965SJuan Quintela     if (params->has_xbzrle_cache_size) {
93909d6c965SJuan Quintela         dest->xbzrle_cache_size = params->xbzrle_cache_size;
94009d6c965SJuan Quintela     }
94109d6c965SJuan Quintela     if (params->has_max_postcopy_bandwidth) {
94209d6c965SJuan Quintela         dest->max_postcopy_bandwidth = params->max_postcopy_bandwidth;
94309d6c965SJuan Quintela     }
94409d6c965SJuan Quintela     if (params->has_max_cpu_throttle) {
94509d6c965SJuan Quintela         dest->max_cpu_throttle = params->max_cpu_throttle;
94609d6c965SJuan Quintela     }
94709d6c965SJuan Quintela     if (params->has_announce_initial) {
94809d6c965SJuan Quintela         dest->announce_initial = params->announce_initial;
94909d6c965SJuan Quintela     }
95009d6c965SJuan Quintela     if (params->has_announce_max) {
95109d6c965SJuan Quintela         dest->announce_max = params->announce_max;
95209d6c965SJuan Quintela     }
95309d6c965SJuan Quintela     if (params->has_announce_rounds) {
95409d6c965SJuan Quintela         dest->announce_rounds = params->announce_rounds;
95509d6c965SJuan Quintela     }
95609d6c965SJuan Quintela     if (params->has_announce_step) {
95709d6c965SJuan Quintela         dest->announce_step = params->announce_step;
95809d6c965SJuan Quintela     }
95909d6c965SJuan Quintela 
96009d6c965SJuan Quintela     if (params->has_block_bitmap_mapping) {
96109d6c965SJuan Quintela         dest->has_block_bitmap_mapping = true;
96209d6c965SJuan Quintela         dest->block_bitmap_mapping = params->block_bitmap_mapping;
96309d6c965SJuan Quintela     }
96409d6c965SJuan Quintela }
96509d6c965SJuan Quintela 
96609d6c965SJuan Quintela static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
96709d6c965SJuan Quintela {
96809d6c965SJuan Quintela     MigrationState *s = migrate_get_current();
96909d6c965SJuan Quintela 
97009d6c965SJuan Quintela     /* TODO use QAPI_CLONE() instead of duplicating it inline */
97109d6c965SJuan Quintela 
97209d6c965SJuan Quintela     if (params->has_compress_level) {
97309d6c965SJuan Quintela         s->parameters.compress_level = params->compress_level;
97409d6c965SJuan Quintela     }
97509d6c965SJuan Quintela 
97609d6c965SJuan Quintela     if (params->has_compress_threads) {
97709d6c965SJuan Quintela         s->parameters.compress_threads = params->compress_threads;
97809d6c965SJuan Quintela     }
97909d6c965SJuan Quintela 
98009d6c965SJuan Quintela     if (params->has_compress_wait_thread) {
98109d6c965SJuan Quintela         s->parameters.compress_wait_thread = params->compress_wait_thread;
98209d6c965SJuan Quintela     }
98309d6c965SJuan Quintela 
98409d6c965SJuan Quintela     if (params->has_decompress_threads) {
98509d6c965SJuan Quintela         s->parameters.decompress_threads = params->decompress_threads;
98609d6c965SJuan Quintela     }
98709d6c965SJuan Quintela 
98809d6c965SJuan Quintela     if (params->has_throttle_trigger_threshold) {
98909d6c965SJuan Quintela         s->parameters.throttle_trigger_threshold = params->throttle_trigger_threshold;
99009d6c965SJuan Quintela     }
99109d6c965SJuan Quintela 
99209d6c965SJuan Quintela     if (params->has_cpu_throttle_initial) {
99309d6c965SJuan Quintela         s->parameters.cpu_throttle_initial = params->cpu_throttle_initial;
99409d6c965SJuan Quintela     }
99509d6c965SJuan Quintela 
99609d6c965SJuan Quintela     if (params->has_cpu_throttle_increment) {
99709d6c965SJuan Quintela         s->parameters.cpu_throttle_increment = params->cpu_throttle_increment;
99809d6c965SJuan Quintela     }
99909d6c965SJuan Quintela 
100009d6c965SJuan Quintela     if (params->has_cpu_throttle_tailslow) {
100109d6c965SJuan Quintela         s->parameters.cpu_throttle_tailslow = params->cpu_throttle_tailslow;
100209d6c965SJuan Quintela     }
100309d6c965SJuan Quintela 
100409d6c965SJuan Quintela     if (params->tls_creds) {
100509d6c965SJuan Quintela         g_free(s->parameters.tls_creds);
100609d6c965SJuan Quintela         assert(params->tls_creds->type == QTYPE_QSTRING);
100709d6c965SJuan Quintela         s->parameters.tls_creds = g_strdup(params->tls_creds->u.s);
100809d6c965SJuan Quintela     }
100909d6c965SJuan Quintela 
101009d6c965SJuan Quintela     if (params->tls_hostname) {
101109d6c965SJuan Quintela         g_free(s->parameters.tls_hostname);
101209d6c965SJuan Quintela         assert(params->tls_hostname->type == QTYPE_QSTRING);
101309d6c965SJuan Quintela         s->parameters.tls_hostname = g_strdup(params->tls_hostname->u.s);
101409d6c965SJuan Quintela     }
101509d6c965SJuan Quintela 
101609d6c965SJuan Quintela     if (params->tls_authz) {
101709d6c965SJuan Quintela         g_free(s->parameters.tls_authz);
101809d6c965SJuan Quintela         assert(params->tls_authz->type == QTYPE_QSTRING);
101909d6c965SJuan Quintela         s->parameters.tls_authz = g_strdup(params->tls_authz->u.s);
102009d6c965SJuan Quintela     }
102109d6c965SJuan Quintela 
102209d6c965SJuan Quintela     if (params->has_max_bandwidth) {
102309d6c965SJuan Quintela         s->parameters.max_bandwidth = params->max_bandwidth;
102409d6c965SJuan Quintela         if (s->to_dst_file && !migration_in_postcopy()) {
102509d6c965SJuan Quintela             qemu_file_set_rate_limit(s->to_dst_file,
102609d6c965SJuan Quintela                                 s->parameters.max_bandwidth / XFER_LIMIT_RATIO);
102709d6c965SJuan Quintela         }
102809d6c965SJuan Quintela     }
102909d6c965SJuan Quintela 
103009d6c965SJuan Quintela     if (params->has_downtime_limit) {
103109d6c965SJuan Quintela         s->parameters.downtime_limit = params->downtime_limit;
103209d6c965SJuan Quintela     }
103309d6c965SJuan Quintela 
103409d6c965SJuan Quintela     if (params->has_x_checkpoint_delay) {
103509d6c965SJuan Quintela         s->parameters.x_checkpoint_delay = params->x_checkpoint_delay;
103609d6c965SJuan Quintela         if (migration_in_colo_state()) {
103709d6c965SJuan Quintela             colo_checkpoint_notify(s);
103809d6c965SJuan Quintela         }
103909d6c965SJuan Quintela     }
104009d6c965SJuan Quintela 
104109d6c965SJuan Quintela     if (params->has_block_incremental) {
104209d6c965SJuan Quintela         s->parameters.block_incremental = params->block_incremental;
104309d6c965SJuan Quintela     }
104409d6c965SJuan Quintela     if (params->has_multifd_channels) {
104509d6c965SJuan Quintela         s->parameters.multifd_channels = params->multifd_channels;
104609d6c965SJuan Quintela     }
104709d6c965SJuan Quintela     if (params->has_multifd_compression) {
104809d6c965SJuan Quintela         s->parameters.multifd_compression = params->multifd_compression;
104909d6c965SJuan Quintela     }
105009d6c965SJuan Quintela     if (params->has_xbzrle_cache_size) {
105109d6c965SJuan Quintela         s->parameters.xbzrle_cache_size = params->xbzrle_cache_size;
105209d6c965SJuan Quintela         xbzrle_cache_resize(params->xbzrle_cache_size, errp);
105309d6c965SJuan Quintela     }
105409d6c965SJuan Quintela     if (params->has_max_postcopy_bandwidth) {
105509d6c965SJuan Quintela         s->parameters.max_postcopy_bandwidth = params->max_postcopy_bandwidth;
105609d6c965SJuan Quintela         if (s->to_dst_file && migration_in_postcopy()) {
105709d6c965SJuan Quintela             qemu_file_set_rate_limit(s->to_dst_file,
105809d6c965SJuan Quintela                     s->parameters.max_postcopy_bandwidth / XFER_LIMIT_RATIO);
105909d6c965SJuan Quintela         }
106009d6c965SJuan Quintela     }
106109d6c965SJuan Quintela     if (params->has_max_cpu_throttle) {
106209d6c965SJuan Quintela         s->parameters.max_cpu_throttle = params->max_cpu_throttle;
106309d6c965SJuan Quintela     }
106409d6c965SJuan Quintela     if (params->has_announce_initial) {
106509d6c965SJuan Quintela         s->parameters.announce_initial = params->announce_initial;
106609d6c965SJuan Quintela     }
106709d6c965SJuan Quintela     if (params->has_announce_max) {
106809d6c965SJuan Quintela         s->parameters.announce_max = params->announce_max;
106909d6c965SJuan Quintela     }
107009d6c965SJuan Quintela     if (params->has_announce_rounds) {
107109d6c965SJuan Quintela         s->parameters.announce_rounds = params->announce_rounds;
107209d6c965SJuan Quintela     }
107309d6c965SJuan Quintela     if (params->has_announce_step) {
107409d6c965SJuan Quintela         s->parameters.announce_step = params->announce_step;
107509d6c965SJuan Quintela     }
107609d6c965SJuan Quintela 
107709d6c965SJuan Quintela     if (params->has_block_bitmap_mapping) {
107809d6c965SJuan Quintela         qapi_free_BitmapMigrationNodeAliasList(
107909d6c965SJuan Quintela             s->parameters.block_bitmap_mapping);
108009d6c965SJuan Quintela 
108109d6c965SJuan Quintela         s->parameters.has_block_bitmap_mapping = true;
108209d6c965SJuan Quintela         s->parameters.block_bitmap_mapping =
108309d6c965SJuan Quintela             QAPI_CLONE(BitmapMigrationNodeAliasList,
108409d6c965SJuan Quintela                        params->block_bitmap_mapping);
108509d6c965SJuan Quintela     }
108609d6c965SJuan Quintela }
108709d6c965SJuan Quintela 
108809d6c965SJuan Quintela void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp)
108909d6c965SJuan Quintela {
109009d6c965SJuan Quintela     MigrationParameters tmp;
109109d6c965SJuan Quintela 
109209d6c965SJuan Quintela     /* TODO Rewrite "" to null instead */
109309d6c965SJuan Quintela     if (params->tls_creds
109409d6c965SJuan Quintela         && params->tls_creds->type == QTYPE_QNULL) {
109509d6c965SJuan Quintela         qobject_unref(params->tls_creds->u.n);
109609d6c965SJuan Quintela         params->tls_creds->type = QTYPE_QSTRING;
109709d6c965SJuan Quintela         params->tls_creds->u.s = strdup("");
109809d6c965SJuan Quintela     }
109909d6c965SJuan Quintela     /* TODO Rewrite "" to null instead */
110009d6c965SJuan Quintela     if (params->tls_hostname
110109d6c965SJuan Quintela         && params->tls_hostname->type == QTYPE_QNULL) {
110209d6c965SJuan Quintela         qobject_unref(params->tls_hostname->u.n);
110309d6c965SJuan Quintela         params->tls_hostname->type = QTYPE_QSTRING;
110409d6c965SJuan Quintela         params->tls_hostname->u.s = strdup("");
110509d6c965SJuan Quintela     }
110609d6c965SJuan Quintela 
110709d6c965SJuan Quintela     migrate_params_test_apply(params, &tmp);
110809d6c965SJuan Quintela 
110909d6c965SJuan Quintela     if (!migrate_params_check(&tmp, errp)) {
111009d6c965SJuan Quintela         /* Invalid parameter */
111109d6c965SJuan Quintela         return;
111209d6c965SJuan Quintela     }
111309d6c965SJuan Quintela 
111409d6c965SJuan Quintela     migrate_params_apply(params, errp);
111509d6c965SJuan Quintela }
1116