2018-02-21 13:18:03 +00:00
|
|
|
/*
|
|
|
|
* qemu_migration_params.c: QEMU migration parameters handling
|
|
|
|
*
|
|
|
|
* Copyright (C) 2006-2018 Red Hat, Inc.
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library. If not, see
|
|
|
|
* <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "virlog.h"
|
|
|
|
#include "virerror.h"
|
|
|
|
#include "virstring.h"
|
|
|
|
|
|
|
|
#include "qemu_alias.h"
|
|
|
|
#include "qemu_hotplug.h"
|
|
|
|
#include "qemu_migration_params.h"
|
2018-12-13 14:53:50 +00:00
|
|
|
#define LIBVIRT_QEMU_MIGRATION_PARAMSPRIV_H_ALLOW
|
2018-03-19 22:44:53 +00:00
|
|
|
#include "qemu_migration_paramspriv.h"
|
2018-03-07 11:38:27 +00:00
|
|
|
#include "qemu_monitor.h"
|
2018-02-21 13:18:03 +00:00
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
|
|
|
|
|
|
|
VIR_LOG_INIT("qemu.qemu_migration_params");
|
|
|
|
|
|
|
|
#define QEMU_MIGRATION_TLS_ALIAS_BASE "libvirt_migrate"
|
|
|
|
|
2018-03-28 16:25:58 +00:00
|
|
|
typedef enum {
|
|
|
|
QEMU_MIGRATION_PARAM_TYPE_INT,
|
|
|
|
QEMU_MIGRATION_PARAM_TYPE_ULL,
|
|
|
|
QEMU_MIGRATION_PARAM_TYPE_BOOL,
|
|
|
|
QEMU_MIGRATION_PARAM_TYPE_STRING,
|
|
|
|
} qemuMigrationParamType;
|
|
|
|
|
2021-12-08 15:16:14 +00:00
|
|
|
typedef enum {
|
|
|
|
QEMU_MIGRATION_FLAG_REQUIRED,
|
|
|
|
QEMU_MIGRATION_FLAG_FORBIDDEN,
|
|
|
|
} qemuMigrationFlagMatch;
|
|
|
|
|
2018-03-28 16:25:58 +00:00
|
|
|
typedef struct _qemuMigrationParamValue qemuMigrationParamValue;
|
|
|
|
struct _qemuMigrationParamValue {
|
|
|
|
bool set;
|
|
|
|
union {
|
|
|
|
int i; /* exempt from syntax-check */
|
|
|
|
unsigned long long ull;
|
|
|
|
bool b;
|
|
|
|
char *s;
|
|
|
|
} value;
|
2018-03-15 19:24:55 +00:00
|
|
|
};
|
|
|
|
|
2018-03-07 11:38:27 +00:00
|
|
|
struct _qemuMigrationParams {
|
2018-03-12 14:50:06 +00:00
|
|
|
unsigned long long compMethods; /* bit-wise OR of qemuMigrationCompressMethod */
|
2021-03-11 07:16:13 +00:00
|
|
|
virBitmap *caps;
|
2018-03-28 16:25:58 +00:00
|
|
|
qemuMigrationParamValue params[QEMU_MIGRATION_PARAM_LAST];
|
2021-03-11 07:16:13 +00:00
|
|
|
virJSONValue *blockDirtyBitmapMapping;
|
2018-03-07 11:38:27 +00:00
|
|
|
};
|
|
|
|
|
2018-03-12 13:19:56 +00:00
|
|
|
typedef enum {
|
|
|
|
QEMU_MIGRATION_COMPRESS_XBZRLE = 0,
|
|
|
|
QEMU_MIGRATION_COMPRESS_MT,
|
2023-02-24 09:27:12 +00:00
|
|
|
QEMU_MIGRATION_COMPRESS_ZLIB,
|
|
|
|
QEMU_MIGRATION_COMPRESS_ZSTD,
|
2018-03-12 13:19:56 +00:00
|
|
|
|
|
|
|
QEMU_MIGRATION_COMPRESS_LAST
|
|
|
|
} qemuMigrationCompressMethod;
|
2019-01-20 16:04:56 +00:00
|
|
|
VIR_ENUM_DECL(qemuMigrationCompressMethod);
|
2019-03-16 18:20:32 +00:00
|
|
|
VIR_ENUM_IMPL(qemuMigrationCompressMethod,
|
|
|
|
QEMU_MIGRATION_COMPRESS_LAST,
|
2018-03-12 13:19:56 +00:00
|
|
|
"xbzrle",
|
|
|
|
"mt",
|
2023-02-24 09:27:12 +00:00
|
|
|
"zlib",
|
|
|
|
"zstd",
|
2018-03-12 13:19:56 +00:00
|
|
|
);
|
|
|
|
|
2019-03-16 18:20:32 +00:00
|
|
|
VIR_ENUM_IMPL(qemuMigrationCapability,
|
|
|
|
QEMU_MIGRATION_CAP_LAST,
|
2018-04-05 20:17:26 +00:00
|
|
|
"xbzrle",
|
|
|
|
"auto-converge",
|
|
|
|
"rdma-pin-all",
|
|
|
|
"events",
|
|
|
|
"postcopy-ram",
|
|
|
|
"compress",
|
|
|
|
"pause-before-switchover",
|
2018-04-17 12:46:29 +00:00
|
|
|
"late-block-activate",
|
2019-02-06 10:53:19 +00:00
|
|
|
"multifd",
|
2021-02-08 09:42:28 +00:00
|
|
|
"dirty-bitmaps",
|
2021-12-08 15:19:26 +00:00
|
|
|
"return-path",
|
2022-06-22 14:37:31 +00:00
|
|
|
"zero-copy-send",
|
2018-04-05 20:17:26 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
2019-01-20 16:04:56 +00:00
|
|
|
VIR_ENUM_DECL(qemuMigrationParam);
|
2019-03-16 18:20:32 +00:00
|
|
|
VIR_ENUM_IMPL(qemuMigrationParam,
|
|
|
|
QEMU_MIGRATION_PARAM_LAST,
|
2018-03-28 16:25:58 +00:00
|
|
|
"compress-level",
|
|
|
|
"compress-threads",
|
|
|
|
"decompress-threads",
|
|
|
|
"cpu-throttle-initial",
|
|
|
|
"cpu-throttle-increment",
|
|
|
|
"tls-creds",
|
|
|
|
"tls-hostname",
|
|
|
|
"max-bandwidth",
|
|
|
|
"downtime-limit",
|
|
|
|
"block-incremental",
|
|
|
|
"xbzrle-cache-size",
|
2019-01-31 09:25:11 +00:00
|
|
|
"max-postcopy-bandwidth",
|
2019-02-06 10:53:19 +00:00
|
|
|
"multifd-channels",
|
2023-02-24 09:27:12 +00:00
|
|
|
"multifd-compression",
|
|
|
|
"multifd-zlib-level",
|
|
|
|
"multifd-zstd-level",
|
2018-03-28 16:25:58 +00:00
|
|
|
);
|
2018-03-12 13:19:56 +00:00
|
|
|
|
2018-03-07 14:59:42 +00:00
|
|
|
typedef struct _qemuMigrationParamsAlwaysOnItem qemuMigrationParamsAlwaysOnItem;
|
|
|
|
struct _qemuMigrationParamsAlwaysOnItem {
|
2018-04-05 20:17:26 +00:00
|
|
|
qemuMigrationCapability cap;
|
2018-03-07 14:59:42 +00:00
|
|
|
int party; /* bit-wise OR of qemuMigrationParty */
|
|
|
|
};
|
|
|
|
|
2018-03-07 20:28:54 +00:00
|
|
|
typedef struct _qemuMigrationParamsFlagMapItem qemuMigrationParamsFlagMapItem;
|
|
|
|
struct _qemuMigrationParamsFlagMapItem {
|
2021-12-08 15:16:14 +00:00
|
|
|
qemuMigrationFlagMatch match;
|
2018-03-07 20:28:54 +00:00
|
|
|
virDomainMigrateFlags flag;
|
2018-04-05 20:17:26 +00:00
|
|
|
qemuMigrationCapability cap;
|
2018-03-07 20:28:54 +00:00
|
|
|
int party; /* bit-wise OR of qemuMigrationParty */
|
|
|
|
};
|
|
|
|
|
2018-03-16 12:05:08 +00:00
|
|
|
typedef struct _qemuMigrationParamsTPMapItem qemuMigrationParamsTPMapItem;
|
|
|
|
struct _qemuMigrationParamsTPMapItem {
|
|
|
|
const char *typedParam;
|
2019-01-31 09:02:17 +00:00
|
|
|
unsigned int unit;
|
2018-03-16 12:05:08 +00:00
|
|
|
qemuMigrationParam param;
|
|
|
|
int party; /* bit-wise OR of qemuMigrationParty */
|
|
|
|
};
|
|
|
|
|
2022-06-29 13:12:20 +00:00
|
|
|
typedef struct _qemuMigrationParamInfoItem qemuMigrationParamInfoItem;
|
|
|
|
struct _qemuMigrationParamInfoItem {
|
|
|
|
qemuMigrationParamType type;
|
2022-06-30 10:52:38 +00:00
|
|
|
bool applyOnPostcopyResume;
|
2022-06-29 13:12:20 +00:00
|
|
|
};
|
|
|
|
|
2018-03-07 14:59:42 +00:00
|
|
|
/* Migration capabilities which should always be enabled as long as they
|
2018-04-06 12:02:04 +00:00
|
|
|
* are supported by QEMU. If the capability is supposed to be enabled on both
|
|
|
|
* sides of migration, it won't be enabled unless both sides support it.
|
|
|
|
*/
|
2018-03-07 14:59:42 +00:00
|
|
|
static const qemuMigrationParamsAlwaysOnItem qemuMigrationParamsAlwaysOn[] = {
|
2018-04-05 20:17:26 +00:00
|
|
|
{QEMU_MIGRATION_CAP_PAUSE_BEFORE_SWITCHOVER,
|
2018-03-07 14:59:42 +00:00
|
|
|
QEMU_MIGRATION_SOURCE},
|
2018-04-17 12:46:29 +00:00
|
|
|
|
|
|
|
{QEMU_MIGRATION_CAP_LATE_BLOCK_ACTIVATE,
|
|
|
|
QEMU_MIGRATION_DESTINATION},
|
2018-03-07 14:59:42 +00:00
|
|
|
};
|
|
|
|
|
2018-04-05 20:17:26 +00:00
|
|
|
/* Translation from virDomainMigrateFlags to qemuMigrationCapability. */
|
2018-03-07 20:28:54 +00:00
|
|
|
static const qemuMigrationParamsFlagMapItem qemuMigrationParamsFlagMap[] = {
|
2021-12-08 15:16:14 +00:00
|
|
|
{QEMU_MIGRATION_FLAG_REQUIRED,
|
|
|
|
VIR_MIGRATE_RDMA_PIN_ALL,
|
2018-04-05 20:17:26 +00:00
|
|
|
QEMU_MIGRATION_CAP_RDMA_PIN_ALL,
|
2018-03-07 20:28:54 +00:00
|
|
|
QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION},
|
|
|
|
|
2021-12-08 15:16:14 +00:00
|
|
|
{QEMU_MIGRATION_FLAG_REQUIRED,
|
|
|
|
VIR_MIGRATE_AUTO_CONVERGE,
|
2018-04-05 20:17:26 +00:00
|
|
|
QEMU_MIGRATION_CAP_AUTO_CONVERGE,
|
2018-03-07 20:28:54 +00:00
|
|
|
QEMU_MIGRATION_SOURCE},
|
|
|
|
|
2021-12-08 15:16:14 +00:00
|
|
|
{QEMU_MIGRATION_FLAG_REQUIRED,
|
|
|
|
VIR_MIGRATE_POSTCOPY,
|
2018-04-05 20:17:26 +00:00
|
|
|
QEMU_MIGRATION_CAP_POSTCOPY,
|
2018-03-07 20:28:54 +00:00
|
|
|
QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION},
|
2019-02-06 10:53:19 +00:00
|
|
|
|
2021-12-08 15:16:14 +00:00
|
|
|
{QEMU_MIGRATION_FLAG_REQUIRED,
|
|
|
|
VIR_MIGRATE_PARALLEL,
|
2019-02-06 10:53:19 +00:00
|
|
|
QEMU_MIGRATION_CAP_MULTIFD,
|
|
|
|
QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION},
|
2021-12-08 15:19:26 +00:00
|
|
|
|
|
|
|
{QEMU_MIGRATION_FLAG_FORBIDDEN,
|
|
|
|
VIR_MIGRATE_TUNNELLED,
|
|
|
|
QEMU_MIGRATION_CAP_RETURN_PATH,
|
|
|
|
QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION},
|
2022-06-22 14:37:31 +00:00
|
|
|
|
|
|
|
{QEMU_MIGRATION_FLAG_REQUIRED,
|
|
|
|
VIR_MIGRATE_ZEROCOPY,
|
|
|
|
QEMU_MIGRATION_CAP_ZERO_COPY_SEND,
|
|
|
|
QEMU_MIGRATION_SOURCE},
|
2018-03-07 20:28:54 +00:00
|
|
|
};
|
|
|
|
|
2018-03-16 12:05:08 +00:00
|
|
|
/* Translation from VIR_MIGRATE_PARAM_* typed parameters to
|
|
|
|
* qemuMigrationParams. */
|
|
|
|
static const qemuMigrationParamsTPMapItem qemuMigrationParamsTPMap[] = {
|
2019-01-31 08:32:42 +00:00
|
|
|
{.typedParam = VIR_MIGRATE_PARAM_AUTO_CONVERGE_INITIAL,
|
|
|
|
.param = QEMU_MIGRATION_PARAM_THROTTLE_INITIAL,
|
|
|
|
.party = QEMU_MIGRATION_SOURCE},
|
2018-03-16 12:05:08 +00:00
|
|
|
|
2019-01-31 08:32:42 +00:00
|
|
|
{.typedParam = VIR_MIGRATE_PARAM_AUTO_CONVERGE_INCREMENT,
|
|
|
|
.param = QEMU_MIGRATION_PARAM_THROTTLE_INCREMENT,
|
|
|
|
.party = QEMU_MIGRATION_SOURCE},
|
2018-03-16 12:05:08 +00:00
|
|
|
|
2019-01-31 08:32:42 +00:00
|
|
|
{.typedParam = VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL,
|
|
|
|
.param = QEMU_MIGRATION_PARAM_COMPRESS_LEVEL,
|
|
|
|
.party = QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION},
|
2018-03-16 12:05:08 +00:00
|
|
|
|
2019-01-31 08:32:42 +00:00
|
|
|
{.typedParam = VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS,
|
|
|
|
.param = QEMU_MIGRATION_PARAM_COMPRESS_THREADS,
|
|
|
|
.party = QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION},
|
2018-03-16 12:05:08 +00:00
|
|
|
|
2019-01-31 08:32:42 +00:00
|
|
|
{.typedParam = VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS,
|
|
|
|
.param = QEMU_MIGRATION_PARAM_DECOMPRESS_THREADS,
|
|
|
|
.party = QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION},
|
2018-03-16 12:05:08 +00:00
|
|
|
|
2019-01-31 08:32:42 +00:00
|
|
|
{.typedParam = VIR_MIGRATE_PARAM_COMPRESSION_XBZRLE_CACHE,
|
|
|
|
.param = QEMU_MIGRATION_PARAM_XBZRLE_CACHE_SIZE,
|
|
|
|
.party = QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION},
|
2019-01-31 09:25:11 +00:00
|
|
|
|
|
|
|
{.typedParam = VIR_MIGRATE_PARAM_BANDWIDTH_POSTCOPY,
|
|
|
|
.unit = 1024 * 1024, /* MiB/s */
|
|
|
|
.param = QEMU_MIGRATION_PARAM_MAX_POSTCOPY_BANDWIDTH,
|
|
|
|
.party = QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION},
|
2019-02-06 10:53:19 +00:00
|
|
|
|
|
|
|
{.typedParam = VIR_MIGRATE_PARAM_PARALLEL_CONNECTIONS,
|
|
|
|
.param = QEMU_MIGRATION_PARAM_MULTIFD_CHANNELS,
|
|
|
|
.party = QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION},
|
2019-12-03 15:20:35 +00:00
|
|
|
|
2023-02-24 09:27:12 +00:00
|
|
|
{.typedParam = VIR_MIGRATE_PARAM_COMPRESSION_ZLIB_LEVEL,
|
|
|
|
.param = QEMU_MIGRATION_PARAM_MULTIFD_ZLIB_LEVEL,
|
|
|
|
.party = QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION},
|
|
|
|
|
|
|
|
{.typedParam = VIR_MIGRATE_PARAM_COMPRESSION_ZSTD_LEVEL,
|
|
|
|
.param = QEMU_MIGRATION_PARAM_MULTIFD_ZSTD_LEVEL,
|
|
|
|
.party = QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION},
|
|
|
|
|
2019-12-03 15:20:35 +00:00
|
|
|
{.typedParam = VIR_MIGRATE_PARAM_TLS_DESTINATION,
|
|
|
|
.param = QEMU_MIGRATION_PARAM_TLS_HOSTNAME,
|
|
|
|
.party = QEMU_MIGRATION_SOURCE},
|
2018-03-16 12:05:08 +00:00
|
|
|
};
|
|
|
|
|
2022-06-29 13:12:20 +00:00
|
|
|
static const qemuMigrationParamInfoItem qemuMigrationParamInfo[] = {
|
|
|
|
[QEMU_MIGRATION_PARAM_COMPRESS_LEVEL] = {
|
|
|
|
.type = QEMU_MIGRATION_PARAM_TYPE_INT,
|
|
|
|
},
|
|
|
|
[QEMU_MIGRATION_PARAM_COMPRESS_THREADS] = {
|
|
|
|
.type = QEMU_MIGRATION_PARAM_TYPE_INT,
|
|
|
|
},
|
|
|
|
[QEMU_MIGRATION_PARAM_DECOMPRESS_THREADS] = {
|
|
|
|
.type = QEMU_MIGRATION_PARAM_TYPE_INT,
|
|
|
|
},
|
|
|
|
[QEMU_MIGRATION_PARAM_THROTTLE_INITIAL] = {
|
|
|
|
.type = QEMU_MIGRATION_PARAM_TYPE_INT,
|
|
|
|
},
|
|
|
|
[QEMU_MIGRATION_PARAM_THROTTLE_INCREMENT] = {
|
|
|
|
.type = QEMU_MIGRATION_PARAM_TYPE_INT,
|
|
|
|
},
|
|
|
|
[QEMU_MIGRATION_PARAM_TLS_CREDS] = {
|
|
|
|
.type = QEMU_MIGRATION_PARAM_TYPE_STRING,
|
|
|
|
},
|
|
|
|
[QEMU_MIGRATION_PARAM_TLS_HOSTNAME] = {
|
|
|
|
.type = QEMU_MIGRATION_PARAM_TYPE_STRING,
|
|
|
|
},
|
|
|
|
[QEMU_MIGRATION_PARAM_MAX_BANDWIDTH] = {
|
|
|
|
.type = QEMU_MIGRATION_PARAM_TYPE_ULL,
|
|
|
|
},
|
|
|
|
[QEMU_MIGRATION_PARAM_DOWNTIME_LIMIT] = {
|
|
|
|
.type = QEMU_MIGRATION_PARAM_TYPE_ULL,
|
|
|
|
},
|
|
|
|
[QEMU_MIGRATION_PARAM_BLOCK_INCREMENTAL] = {
|
|
|
|
.type = QEMU_MIGRATION_PARAM_TYPE_BOOL,
|
|
|
|
},
|
|
|
|
[QEMU_MIGRATION_PARAM_XBZRLE_CACHE_SIZE] = {
|
|
|
|
.type = QEMU_MIGRATION_PARAM_TYPE_ULL,
|
|
|
|
},
|
|
|
|
[QEMU_MIGRATION_PARAM_MAX_POSTCOPY_BANDWIDTH] = {
|
|
|
|
.type = QEMU_MIGRATION_PARAM_TYPE_ULL,
|
2022-06-30 10:52:38 +00:00
|
|
|
.applyOnPostcopyResume = true,
|
2022-06-29 13:12:20 +00:00
|
|
|
},
|
|
|
|
[QEMU_MIGRATION_PARAM_MULTIFD_CHANNELS] = {
|
|
|
|
.type = QEMU_MIGRATION_PARAM_TYPE_INT,
|
|
|
|
},
|
2023-02-24 09:27:12 +00:00
|
|
|
[QEMU_MIGRATION_PARAM_MULTIFD_COMPRESSION] = {
|
|
|
|
.type = QEMU_MIGRATION_PARAM_TYPE_STRING,
|
|
|
|
},
|
|
|
|
[QEMU_MIGRATION_PARAM_MULTIFD_ZLIB_LEVEL] = {
|
|
|
|
.type = QEMU_MIGRATION_PARAM_TYPE_INT,
|
|
|
|
},
|
|
|
|
[QEMU_MIGRATION_PARAM_MULTIFD_ZSTD_LEVEL] = {
|
|
|
|
.type = QEMU_MIGRATION_PARAM_TYPE_INT,
|
|
|
|
},
|
2018-03-28 16:25:58 +00:00
|
|
|
};
|
2022-06-29 13:12:20 +00:00
|
|
|
G_STATIC_ASSERT(G_N_ELEMENTS(qemuMigrationParamInfo) == QEMU_MIGRATION_PARAM_LAST);
|
2018-03-28 16:25:58 +00:00
|
|
|
|
2018-02-21 13:18:03 +00:00
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virBitmap *
|
2018-04-06 08:18:52 +00:00
|
|
|
qemuMigrationParamsGetAlwaysOnCaps(qemuMigrationParty party)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virBitmap *caps = virBitmapNew(QEMU_MIGRATION_CAP_LAST);
|
2018-04-06 08:18:52 +00:00
|
|
|
size_t i;
|
|
|
|
|
2019-10-15 11:55:26 +00:00
|
|
|
for (i = 0; i < G_N_ELEMENTS(qemuMigrationParamsAlwaysOn); i++) {
|
2018-04-06 08:18:52 +00:00
|
|
|
if (!(qemuMigrationParamsAlwaysOn[i].party & party))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ignore_value(virBitmapSetBit(caps, qemuMigrationParamsAlwaysOn[i].cap));
|
|
|
|
}
|
|
|
|
|
|
|
|
return caps;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParams *
|
2018-02-21 15:59:10 +00:00
|
|
|
qemuMigrationParamsNew(void)
|
|
|
|
{
|
2020-08-19 11:13:29 +00:00
|
|
|
g_autoptr(qemuMigrationParams) params = NULL;
|
2018-02-21 15:59:10 +00:00
|
|
|
|
2020-08-19 11:13:29 +00:00
|
|
|
params = g_new0(qemuMigrationParams, 1);
|
2018-02-26 14:47:33 +00:00
|
|
|
|
2020-10-01 15:42:11 +00:00
|
|
|
params->caps = virBitmapNew(QEMU_MIGRATION_CAP_LAST);
|
2018-02-26 14:47:33 +00:00
|
|
|
|
2020-08-19 11:13:29 +00:00
|
|
|
return g_steal_pointer(¶ms);
|
2018-02-21 15:59:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-21 13:18:03 +00:00
|
|
|
void
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParamsFree(qemuMigrationParams *migParams)
|
2018-02-21 13:18:03 +00:00
|
|
|
{
|
2018-03-28 16:25:58 +00:00
|
|
|
size_t i;
|
|
|
|
|
2018-02-21 13:18:03 +00:00
|
|
|
if (!migParams)
|
|
|
|
return;
|
|
|
|
|
2018-03-28 16:25:58 +00:00
|
|
|
for (i = 0; i < QEMU_MIGRATION_PARAM_LAST; i++) {
|
2022-06-29 13:12:20 +00:00
|
|
|
if (qemuMigrationParamInfo[i].type == QEMU_MIGRATION_PARAM_TYPE_STRING)
|
2021-02-03 19:36:01 +00:00
|
|
|
g_free(migParams->params[i].value.s);
|
2018-03-28 16:25:58 +00:00
|
|
|
}
|
|
|
|
|
2018-02-26 14:47:33 +00:00
|
|
|
virBitmapFree(migParams->caps);
|
2021-02-08 09:42:28 +00:00
|
|
|
virJSONValueFree(migParams->blockDirtyBitmapMapping);
|
2021-02-03 19:36:01 +00:00
|
|
|
g_free(migParams);
|
2018-02-21 13:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-28 16:25:58 +00:00
|
|
|
static int
|
|
|
|
qemuMigrationParamsCheckType(qemuMigrationParam param,
|
|
|
|
qemuMigrationParamType type)
|
|
|
|
{
|
2022-06-29 13:12:20 +00:00
|
|
|
if (qemuMigrationParamInfo[param].type != type) {
|
2018-03-28 16:25:58 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2023-03-09 12:15:22 +00:00
|
|
|
_("Type mismatch for '%1$s' migration parameter"),
|
2018-03-28 16:25:58 +00:00
|
|
|
qemuMigrationParamTypeToString(param));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParamsGetTPInt(qemuMigrationParams *migParams,
|
2018-03-28 16:25:58 +00:00
|
|
|
qemuMigrationParam param,
|
|
|
|
virTypedParameterPtr params,
|
|
|
|
int nparams,
|
2019-01-31 09:02:17 +00:00
|
|
|
const char *name,
|
|
|
|
unsigned int unit)
|
2018-03-28 16:25:58 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (qemuMigrationParamsCheckType(param, QEMU_MIGRATION_PARAM_TYPE_INT) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!params)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if ((rc = virTypedParamsGetInt(params, nparams, name,
|
|
|
|
&migParams->params[param].value.i)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2019-01-31 09:02:17 +00:00
|
|
|
if (unit > 0) {
|
|
|
|
unsigned int max = UINT_MAX / unit;
|
|
|
|
if (migParams->params[param].value.i > max) {
|
|
|
|
virReportError(VIR_ERR_OVERFLOW,
|
2023-03-09 12:15:22 +00:00
|
|
|
_("migration parameter '%1$s' must be less than %2$u"),
|
2019-01-31 09:02:17 +00:00
|
|
|
name, max + 1);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
migParams->params[param].value.i *= unit;
|
|
|
|
}
|
|
|
|
|
2018-03-28 16:25:58 +00:00
|
|
|
migParams->params[param].set = !!rc;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParamsSetTPInt(qemuMigrationParams *migParams,
|
2018-03-28 16:25:58 +00:00
|
|
|
qemuMigrationParam param,
|
|
|
|
virTypedParameterPtr *params,
|
|
|
|
int *nparams,
|
|
|
|
int *maxparams,
|
2019-01-31 09:02:17 +00:00
|
|
|
const char *name,
|
|
|
|
unsigned int unit)
|
2018-03-28 16:25:58 +00:00
|
|
|
{
|
2019-01-31 09:02:17 +00:00
|
|
|
int value;
|
|
|
|
|
2018-03-28 16:25:58 +00:00
|
|
|
if (qemuMigrationParamsCheckType(param, QEMU_MIGRATION_PARAM_TYPE_INT) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!migParams->params[param].set)
|
|
|
|
return 0;
|
|
|
|
|
2019-01-31 09:02:17 +00:00
|
|
|
value = migParams->params[param].value.i;
|
|
|
|
if (unit > 0)
|
|
|
|
value /= unit;
|
|
|
|
|
|
|
|
return virTypedParamsAddInt(params, nparams, maxparams, name, value);
|
2018-03-28 16:25:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParamsGetTPULL(qemuMigrationParams *migParams,
|
2018-03-28 16:25:58 +00:00
|
|
|
qemuMigrationParam param,
|
|
|
|
virTypedParameterPtr params,
|
|
|
|
int nparams,
|
2019-01-31 09:02:17 +00:00
|
|
|
const char *name,
|
|
|
|
unsigned int unit)
|
2018-03-28 16:25:58 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (qemuMigrationParamsCheckType(param, QEMU_MIGRATION_PARAM_TYPE_ULL) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!params)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if ((rc = virTypedParamsGetULLong(params, nparams, name,
|
|
|
|
&migParams->params[param].value.ull)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2019-01-31 09:02:17 +00:00
|
|
|
if (unit > 0) {
|
|
|
|
unsigned long long max = ULLONG_MAX / unit;
|
|
|
|
if (migParams->params[param].value.ull > max) {
|
|
|
|
virReportError(VIR_ERR_OVERFLOW,
|
2023-03-09 12:15:22 +00:00
|
|
|
_("migration parameter '%1$s' must be less than %2$llu"),
|
2019-01-31 09:02:17 +00:00
|
|
|
name, max + 1);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
migParams->params[param].value.ull *= unit;
|
|
|
|
}
|
|
|
|
|
2018-03-28 16:25:58 +00:00
|
|
|
migParams->params[param].set = !!rc;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParamsSetTPULL(qemuMigrationParams *migParams,
|
2018-03-28 16:25:58 +00:00
|
|
|
qemuMigrationParam param,
|
|
|
|
virTypedParameterPtr *params,
|
|
|
|
int *nparams,
|
|
|
|
int *maxparams,
|
2019-01-31 09:02:17 +00:00
|
|
|
const char *name,
|
|
|
|
unsigned int unit)
|
2018-03-28 16:25:58 +00:00
|
|
|
{
|
2019-01-31 09:02:17 +00:00
|
|
|
unsigned long long value;
|
|
|
|
|
2018-03-28 16:25:58 +00:00
|
|
|
if (qemuMigrationParamsCheckType(param, QEMU_MIGRATION_PARAM_TYPE_ULL) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!migParams->params[param].set)
|
|
|
|
return 0;
|
|
|
|
|
2019-01-31 09:02:17 +00:00
|
|
|
value = migParams->params[param].value.ull;
|
|
|
|
if (unit > 0)
|
|
|
|
value /= unit;
|
|
|
|
|
|
|
|
return virTypedParamsAddULLong(params, nparams, maxparams, name, value);
|
2018-03-28 16:25:58 +00:00
|
|
|
}
|
2018-03-09 16:17:01 +00:00
|
|
|
|
2018-03-27 21:41:39 +00:00
|
|
|
|
2019-12-03 13:58:32 +00:00
|
|
|
static int
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParamsGetTPString(qemuMigrationParams *migParams,
|
2019-12-03 13:58:32 +00:00
|
|
|
qemuMigrationParam param,
|
|
|
|
virTypedParameterPtr params,
|
|
|
|
int nparams,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
const char *value = NULL;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (qemuMigrationParamsCheckType(param, QEMU_MIGRATION_PARAM_TYPE_STRING) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!params)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if ((rc = virTypedParamsGetString(params, nparams, name, &value)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
migParams->params[param].value.s = g_strdup(value);
|
|
|
|
migParams->params[param].set = !!rc;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParamsSetTPString(qemuMigrationParams *migParams,
|
2019-12-03 13:58:32 +00:00
|
|
|
qemuMigrationParam param,
|
|
|
|
virTypedParameterPtr *params,
|
|
|
|
int *nparams,
|
|
|
|
int *maxparams,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
if (qemuMigrationParamsCheckType(param, QEMU_MIGRATION_PARAM_TYPE_STRING) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!migParams->params[param].set)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return virTypedParamsAddString(params, nparams, maxparams, name,
|
|
|
|
migParams->params[param].value.s);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-03-12 14:20:54 +00:00
|
|
|
static int
|
2018-03-09 16:30:16 +00:00
|
|
|
qemuMigrationParamsSetCompression(virTypedParameterPtr params,
|
|
|
|
int nparams,
|
2022-11-22 10:50:13 +00:00
|
|
|
unsigned int flags,
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParams *migParams)
|
2018-03-27 21:41:39 +00:00
|
|
|
{
|
2018-03-09 16:30:16 +00:00
|
|
|
size_t i;
|
|
|
|
int method;
|
2018-03-27 21:41:39 +00:00
|
|
|
|
2018-03-09 16:30:16 +00:00
|
|
|
for (i = 0; i < nparams; i++) {
|
|
|
|
if (STRNEQ(params[i].field, VIR_MIGRATE_PARAM_COMPRESSION))
|
|
|
|
continue;
|
2018-03-27 21:41:39 +00:00
|
|
|
|
2018-03-09 16:30:16 +00:00
|
|
|
method = qemuMigrationCompressMethodTypeFromString(params[i].value.s);
|
|
|
|
if (method < 0) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
2023-03-09 12:15:22 +00:00
|
|
|
_("Unsupported compression method '%1$s'"),
|
2018-03-09 16:30:16 +00:00
|
|
|
params[i].value.s);
|
2020-01-06 21:57:40 +00:00
|
|
|
return -1;
|
2018-03-09 16:30:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (migParams->compMethods & (1ULL << method)) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
2023-03-09 12:15:22 +00:00
|
|
|
_("Compression method '%1$s' is specified twice"),
|
2018-03-09 16:30:16 +00:00
|
|
|
params[i].value.s);
|
2020-01-06 21:57:40 +00:00
|
|
|
return -1;
|
2018-03-09 16:30:16 +00:00
|
|
|
}
|
2018-03-12 14:50:06 +00:00
|
|
|
|
2023-02-24 09:27:12 +00:00
|
|
|
if ((method == QEMU_MIGRATION_COMPRESS_MT ||
|
|
|
|
method == QEMU_MIGRATION_COMPRESS_XBZRLE) &&
|
|
|
|
flags & VIR_MIGRATE_PARALLEL) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("Compression method '%1$s' isn't supported with parallel migration"),
|
|
|
|
params[i].value.s);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((method == QEMU_MIGRATION_COMPRESS_ZLIB ||
|
|
|
|
method == QEMU_MIGRATION_COMPRESS_ZSTD) &&
|
|
|
|
!(flags & VIR_MIGRATE_PARALLEL)) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("Compression method '%1$s' is only supported with parallel migration"),
|
|
|
|
params[i].value.s);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (migParams->params[QEMU_MIGRATION_PARAM_MULTIFD_COMPRESSION].set) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
|
|
_("Only one compression method could be specified with parallel compression"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-03-09 16:30:16 +00:00
|
|
|
migParams->compMethods |= 1ULL << method;
|
2018-03-27 21:41:39 +00:00
|
|
|
|
2018-03-09 16:30:16 +00:00
|
|
|
switch ((qemuMigrationCompressMethod) method) {
|
|
|
|
case QEMU_MIGRATION_COMPRESS_XBZRLE:
|
2023-02-24 09:27:12 +00:00
|
|
|
ignore_value(virBitmapSetBit(migParams->caps, QEMU_MIGRATION_CAP_XBZRLE));
|
2018-03-09 16:30:16 +00:00
|
|
|
break;
|
2018-03-27 21:41:39 +00:00
|
|
|
|
2018-03-09 16:30:16 +00:00
|
|
|
case QEMU_MIGRATION_COMPRESS_MT:
|
2023-02-24 09:27:12 +00:00
|
|
|
ignore_value(virBitmapSetBit(migParams->caps, QEMU_MIGRATION_CAP_COMPRESS));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMU_MIGRATION_COMPRESS_ZLIB:
|
|
|
|
case QEMU_MIGRATION_COMPRESS_ZSTD:
|
|
|
|
migParams->params[QEMU_MIGRATION_PARAM_MULTIFD_COMPRESSION].value.s = g_strdup(params[i].value.s);
|
|
|
|
migParams->params[QEMU_MIGRATION_PARAM_MULTIFD_COMPRESSION].set = true;
|
2018-03-09 16:30:16 +00:00
|
|
|
break;
|
2018-03-27 21:41:39 +00:00
|
|
|
|
2018-03-09 16:30:16 +00:00
|
|
|
case QEMU_MIGRATION_COMPRESS_LAST:
|
|
|
|
default:
|
2023-02-24 09:27:12 +00:00
|
|
|
break;
|
2018-03-09 16:30:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-28 16:25:58 +00:00
|
|
|
if ((migParams->params[QEMU_MIGRATION_PARAM_COMPRESS_LEVEL].set ||
|
|
|
|
migParams->params[QEMU_MIGRATION_PARAM_COMPRESS_THREADS].set ||
|
|
|
|
migParams->params[QEMU_MIGRATION_PARAM_DECOMPRESS_THREADS].set) &&
|
2018-03-09 16:30:16 +00:00
|
|
|
!(migParams->compMethods & (1ULL << QEMU_MIGRATION_COMPRESS_MT))) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
|
|
_("Turn multithread compression on to tune it"));
|
2020-01-06 21:57:40 +00:00
|
|
|
return -1;
|
2018-03-09 16:30:16 +00:00
|
|
|
}
|
|
|
|
|
2018-03-28 16:25:58 +00:00
|
|
|
if (migParams->params[QEMU_MIGRATION_PARAM_XBZRLE_CACHE_SIZE].set &&
|
2018-03-09 16:30:16 +00:00
|
|
|
!(migParams->compMethods & (1ULL << QEMU_MIGRATION_COMPRESS_XBZRLE))) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
|
|
_("Turn xbzrle compression on to tune it"));
|
2020-01-06 21:57:40 +00:00
|
|
|
return -1;
|
2018-03-09 16:30:16 +00:00
|
|
|
}
|
|
|
|
|
2023-02-24 09:27:12 +00:00
|
|
|
if (migParams->params[QEMU_MIGRATION_PARAM_MULTIFD_ZLIB_LEVEL].set &&
|
|
|
|
!(migParams->compMethods & (1ULL << QEMU_MIGRATION_COMPRESS_ZLIB))) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
|
|
_("Turn zlib compression on to tune it"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (migParams->params[QEMU_MIGRATION_PARAM_MULTIFD_ZSTD_LEVEL].set &&
|
|
|
|
!(migParams->compMethods & (1ULL << QEMU_MIGRATION_COMPRESS_ZSTD))) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
|
|
_("Turn zstd compression on to tune it"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-03-09 16:30:16 +00:00
|
|
|
if (!migParams->compMethods && (flags & VIR_MIGRATE_COMPRESSED)) {
|
2023-02-24 09:27:12 +00:00
|
|
|
if (flags & VIR_MIGRATE_PARALLEL) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
|
|
_("No compression algorithm selected for parallel migration"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-03-09 16:30:16 +00:00
|
|
|
migParams->compMethods = 1ULL << QEMU_MIGRATION_COMPRESS_XBZRLE;
|
|
|
|
ignore_value(virBitmapSetBit(migParams->caps,
|
2018-04-05 20:17:26 +00:00
|
|
|
QEMU_MIGRATION_CAP_XBZRLE));
|
2018-03-09 16:30:16 +00:00
|
|
|
}
|
2018-03-27 21:41:39 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-02-08 09:42:28 +00:00
|
|
|
void
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParamsSetBlockDirtyBitmapMapping(qemuMigrationParams *migParams,
|
|
|
|
virJSONValue **params)
|
2021-02-08 09:42:28 +00:00
|
|
|
{
|
|
|
|
virJSONValueFree(migParams->blockDirtyBitmapMapping);
|
|
|
|
migParams->blockDirtyBitmapMapping = g_steal_pointer(params);
|
|
|
|
|
|
|
|
if (migParams->blockDirtyBitmapMapping)
|
|
|
|
ignore_value(virBitmapSetBit(migParams->caps, QEMU_MIGRATION_CAP_BLOCK_DIRTY_BITMAPS));
|
|
|
|
else
|
|
|
|
ignore_value(virBitmapClearBit(migParams->caps, QEMU_MIGRATION_CAP_BLOCK_DIRTY_BITMAPS));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParams *
|
2018-02-21 13:18:03 +00:00
|
|
|
qemuMigrationParamsFromFlags(virTypedParameterPtr params,
|
|
|
|
int nparams,
|
2022-11-22 10:50:13 +00:00
|
|
|
unsigned int flags,
|
2018-03-09 16:30:16 +00:00
|
|
|
qemuMigrationParty party)
|
2018-02-21 13:18:03 +00:00
|
|
|
{
|
2020-08-19 11:15:35 +00:00
|
|
|
g_autoptr(qemuMigrationParams) migParams = NULL;
|
2018-03-07 20:28:54 +00:00
|
|
|
size_t i;
|
2018-02-21 13:18:03 +00:00
|
|
|
|
2018-02-21 15:59:10 +00:00
|
|
|
if (!(migParams = qemuMigrationParamsNew()))
|
2018-02-21 13:18:03 +00:00
|
|
|
return NULL;
|
|
|
|
|
2019-10-15 11:55:26 +00:00
|
|
|
for (i = 0; i < G_N_ELEMENTS(qemuMigrationParamsFlagMap); i++) {
|
2021-12-08 15:16:14 +00:00
|
|
|
const qemuMigrationParamsFlagMapItem *item = &qemuMigrationParamsFlagMap[i];
|
|
|
|
int match = 0;
|
|
|
|
|
|
|
|
if (item->match == QEMU_MIGRATION_FLAG_REQUIRED)
|
|
|
|
match = item->flag;
|
2018-03-07 20:28:54 +00:00
|
|
|
|
2021-12-08 15:16:14 +00:00
|
|
|
if (item->party & party && (flags & item->flag) == match) {
|
2018-03-07 20:28:54 +00:00
|
|
|
VIR_DEBUG("Enabling migration capability '%s'",
|
2021-12-08 15:16:14 +00:00
|
|
|
qemuMigrationCapabilityTypeToString(item->cap));
|
|
|
|
ignore_value(virBitmapSetBit(migParams->caps, item->cap));
|
2018-03-07 20:28:54 +00:00
|
|
|
}
|
|
|
|
}
|
2018-02-21 13:18:03 +00:00
|
|
|
|
2019-10-15 11:55:26 +00:00
|
|
|
for (i = 0; i < G_N_ELEMENTS(qemuMigrationParamsTPMap); i++) {
|
2018-03-16 12:05:08 +00:00
|
|
|
const qemuMigrationParamsTPMapItem *item = &qemuMigrationParamsTPMap[i];
|
2018-03-28 16:25:58 +00:00
|
|
|
|
2018-03-16 12:05:08 +00:00
|
|
|
if (!(item->party & party))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
VIR_DEBUG("Setting migration parameter '%s' from '%s'",
|
|
|
|
qemuMigrationParamTypeToString(item->param), item->typedParam);
|
|
|
|
|
2022-06-29 13:12:20 +00:00
|
|
|
switch (qemuMigrationParamInfo[item->param].type) {
|
2018-03-16 12:05:08 +00:00
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_INT:
|
|
|
|
if (qemuMigrationParamsGetTPInt(migParams, item->param, params,
|
2019-01-31 09:02:17 +00:00
|
|
|
nparams, item->typedParam,
|
|
|
|
item->unit) < 0)
|
2020-08-19 11:15:35 +00:00
|
|
|
return NULL;
|
2018-03-16 12:05:08 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_ULL:
|
|
|
|
if (qemuMigrationParamsGetTPULL(migParams, item->param, params,
|
2019-01-31 09:02:17 +00:00
|
|
|
nparams, item->typedParam,
|
|
|
|
item->unit) < 0)
|
2020-08-19 11:15:35 +00:00
|
|
|
return NULL;
|
2018-03-16 12:05:08 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_BOOL:
|
2019-12-03 13:58:32 +00:00
|
|
|
break;
|
|
|
|
|
2018-03-16 12:05:08 +00:00
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_STRING:
|
2019-12-03 13:58:32 +00:00
|
|
|
if (qemuMigrationParamsGetTPString(migParams, item->param, params,
|
|
|
|
nparams, item->typedParam) < 0)
|
2020-08-19 11:15:35 +00:00
|
|
|
return NULL;
|
2018-03-16 12:05:08 +00:00
|
|
|
break;
|
|
|
|
}
|
2018-03-09 10:23:49 +00:00
|
|
|
}
|
2018-02-21 13:18:03 +00:00
|
|
|
|
2018-03-28 16:25:58 +00:00
|
|
|
if ((migParams->params[QEMU_MIGRATION_PARAM_THROTTLE_INITIAL].set ||
|
|
|
|
migParams->params[QEMU_MIGRATION_PARAM_THROTTLE_INCREMENT].set) &&
|
2018-02-21 13:18:03 +00:00
|
|
|
!(flags & VIR_MIGRATE_AUTO_CONVERGE)) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
|
|
_("Turn auto convergence on to tune it"));
|
2020-08-19 11:15:35 +00:00
|
|
|
return NULL;
|
2018-02-21 13:18:03 +00:00
|
|
|
}
|
|
|
|
|
2019-02-06 10:53:19 +00:00
|
|
|
if (migParams->params[QEMU_MIGRATION_PARAM_MULTIFD_CHANNELS].set &&
|
|
|
|
!(flags & VIR_MIGRATE_PARALLEL)) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
|
|
_("Turn parallel migration on to tune it"));
|
2020-08-19 11:15:35 +00:00
|
|
|
return NULL;
|
2019-02-06 10:53:19 +00:00
|
|
|
}
|
|
|
|
|
2018-03-09 16:30:16 +00:00
|
|
|
if (qemuMigrationParamsSetCompression(params, nparams, flags, migParams) < 0)
|
2020-08-19 11:15:35 +00:00
|
|
|
return NULL;
|
2018-02-21 13:18:03 +00:00
|
|
|
|
2020-08-19 11:15:35 +00:00
|
|
|
return g_steal_pointer(&migParams);
|
2018-02-21 13:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-12 13:19:56 +00:00
|
|
|
int
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParamsDump(qemuMigrationParams *migParams,
|
2018-03-12 14:50:06 +00:00
|
|
|
virTypedParameterPtr *params,
|
|
|
|
int *nparams,
|
|
|
|
int *maxparams,
|
2022-11-22 10:50:13 +00:00
|
|
|
unsigned int *flags)
|
2018-03-12 13:19:56 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
2018-03-12 14:50:06 +00:00
|
|
|
if (migParams->compMethods == 1ULL << QEMU_MIGRATION_COMPRESS_XBZRLE &&
|
2018-03-28 16:25:58 +00:00
|
|
|
!migParams->params[QEMU_MIGRATION_PARAM_XBZRLE_CACHE_SIZE].set) {
|
2018-03-12 13:19:56 +00:00
|
|
|
*flags |= VIR_MIGRATE_COMPRESSED;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < QEMU_MIGRATION_COMPRESS_LAST; ++i) {
|
2018-03-12 14:50:06 +00:00
|
|
|
if ((migParams->compMethods & (1ULL << i)) &&
|
2018-03-12 13:19:56 +00:00
|
|
|
virTypedParamsAddString(params, nparams, maxparams,
|
|
|
|
VIR_MIGRATE_PARAM_COMPRESSION,
|
|
|
|
qemuMigrationCompressMethodTypeToString(i)) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-10-15 11:55:26 +00:00
|
|
|
for (i = 0; i < G_N_ELEMENTS(qemuMigrationParamsTPMap); i++) {
|
2018-03-16 12:05:08 +00:00
|
|
|
const qemuMigrationParamsTPMapItem *item = &qemuMigrationParamsTPMap[i];
|
2018-03-28 16:25:58 +00:00
|
|
|
|
2018-03-16 12:05:08 +00:00
|
|
|
if (!(item->party & QEMU_MIGRATION_DESTINATION))
|
|
|
|
continue;
|
2018-03-12 13:19:56 +00:00
|
|
|
|
2022-06-29 13:12:20 +00:00
|
|
|
switch (qemuMigrationParamInfo[item->param].type) {
|
2018-03-16 12:05:08 +00:00
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_INT:
|
|
|
|
if (qemuMigrationParamsSetTPInt(migParams, item->param,
|
|
|
|
params, nparams, maxparams,
|
2019-01-31 09:02:17 +00:00
|
|
|
item->typedParam, item->unit) < 0)
|
2018-03-16 12:05:08 +00:00
|
|
|
return -1;
|
|
|
|
break;
|
2018-03-12 13:19:56 +00:00
|
|
|
|
2018-03-16 12:05:08 +00:00
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_ULL:
|
|
|
|
if (qemuMigrationParamsSetTPULL(migParams, item->param,
|
|
|
|
params, nparams, maxparams,
|
2019-01-31 09:02:17 +00:00
|
|
|
item->typedParam, item->unit) < 0)
|
2018-03-16 12:05:08 +00:00
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_BOOL:
|
2019-12-03 13:58:32 +00:00
|
|
|
break;
|
|
|
|
|
2018-03-16 12:05:08 +00:00
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_STRING:
|
2019-12-03 13:58:32 +00:00
|
|
|
if (qemuMigrationParamsSetTPString(migParams, item->param,
|
|
|
|
params, nparams, maxparams,
|
|
|
|
item->typedParam) < 0)
|
|
|
|
return -1;
|
2018-03-16 12:05:08 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-03-12 13:19:56 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParams *
|
|
|
|
qemuMigrationParamsFromJSON(virJSONValue *params)
|
2018-03-15 17:06:01 +00:00
|
|
|
{
|
2020-08-19 11:17:06 +00:00
|
|
|
g_autoptr(qemuMigrationParams) migParams = NULL;
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParamValue *pv;
|
2018-03-28 16:25:58 +00:00
|
|
|
const char *name;
|
|
|
|
const char *str;
|
|
|
|
size_t i;
|
2018-03-15 17:06:01 +00:00
|
|
|
|
|
|
|
if (!(migParams = qemuMigrationParamsNew()))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!params)
|
2020-08-19 11:17:06 +00:00
|
|
|
return g_steal_pointer(&migParams);
|
2018-03-15 17:06:01 +00:00
|
|
|
|
2018-03-28 16:25:58 +00:00
|
|
|
for (i = 0; i < QEMU_MIGRATION_PARAM_LAST; i++) {
|
|
|
|
name = qemuMigrationParamTypeToString(i);
|
|
|
|
pv = &migParams->params[i];
|
|
|
|
|
2022-06-29 13:12:20 +00:00
|
|
|
switch (qemuMigrationParamInfo[i].type) {
|
2018-03-28 16:25:58 +00:00
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_INT:
|
|
|
|
if (virJSONValueObjectGetNumberInt(params, name, &pv->value.i) == 0)
|
|
|
|
pv->set = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_ULL:
|
|
|
|
if (virJSONValueObjectGetNumberUlong(params, name, &pv->value.ull) == 0)
|
|
|
|
pv->set = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_BOOL:
|
|
|
|
if (virJSONValueObjectGetBoolean(params, name, &pv->value.b) == 0)
|
|
|
|
pv->set = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_STRING:
|
|
|
|
if ((str = virJSONValueObjectGetString(params, name))) {
|
2019-10-20 11:49:46 +00:00
|
|
|
pv->value.s = g_strdup(str);
|
2018-03-28 16:25:58 +00:00
|
|
|
pv->set = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-03-15 17:06:01 +00:00
|
|
|
|
2020-08-19 11:17:06 +00:00
|
|
|
return g_steal_pointer(&migParams);
|
2018-03-15 17:06:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virJSONValue *
|
2022-06-30 10:52:38 +00:00
|
|
|
qemuMigrationParamsToJSON(qemuMigrationParams *migParams,
|
|
|
|
bool postcopyResume)
|
2018-03-15 19:24:05 +00:00
|
|
|
{
|
2020-08-19 11:18:31 +00:00
|
|
|
g_autoptr(virJSONValue) params = virJSONValueNewObject();
|
2018-03-28 16:25:58 +00:00
|
|
|
size_t i;
|
2018-03-15 19:24:05 +00:00
|
|
|
|
2018-03-28 16:25:58 +00:00
|
|
|
for (i = 0; i < QEMU_MIGRATION_PARAM_LAST; i++) {
|
2020-08-19 11:18:31 +00:00
|
|
|
const char *name = qemuMigrationParamTypeToString(i);
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParamValue *pv = &migParams->params[i];
|
2020-08-19 11:18:31 +00:00
|
|
|
int rc = 0;
|
2018-03-28 16:25:58 +00:00
|
|
|
|
|
|
|
if (!pv->set)
|
|
|
|
continue;
|
|
|
|
|
2022-06-30 10:52:38 +00:00
|
|
|
if (postcopyResume && !qemuMigrationParamInfo[i].applyOnPostcopyResume)
|
|
|
|
continue;
|
|
|
|
|
2022-06-29 13:12:20 +00:00
|
|
|
switch (qemuMigrationParamInfo[i].type) {
|
2018-03-28 16:25:58 +00:00
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_INT:
|
|
|
|
rc = virJSONValueObjectAppendNumberInt(params, name, pv->value.i);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_ULL:
|
|
|
|
rc = virJSONValueObjectAppendNumberUlong(params, name, pv->value.ull);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_BOOL:
|
|
|
|
rc = virJSONValueObjectAppendBoolean(params, name, pv->value.b);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_STRING:
|
|
|
|
rc = virJSONValueObjectAppendString(params, name, pv->value.s);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc < 0)
|
2020-08-19 11:18:31 +00:00
|
|
|
return NULL;
|
2018-03-28 16:25:58 +00:00
|
|
|
}
|
2018-03-15 19:24:05 +00:00
|
|
|
|
2021-02-08 09:42:28 +00:00
|
|
|
if (migParams->blockDirtyBitmapMapping) {
|
|
|
|
g_autoptr(virJSONValue) mapping = virJSONValueCopy(migParams->blockDirtyBitmapMapping);
|
|
|
|
|
|
|
|
if (!mapping)
|
|
|
|
return NULL;
|
|
|
|
|
2021-02-11 16:57:45 +00:00
|
|
|
if (virJSONValueObjectAppend(params, "block-bitmap-mapping", &mapping) < 0)
|
2021-02-08 09:42:28 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-08-19 11:18:31 +00:00
|
|
|
return g_steal_pointer(¶ms);
|
2018-03-15 19:24:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virJSONValue *
|
|
|
|
qemuMigrationCapsToJSON(virBitmap *caps,
|
|
|
|
virBitmap *states)
|
2018-04-05 18:59:07 +00:00
|
|
|
{
|
2020-08-19 11:20:13 +00:00
|
|
|
g_autoptr(virJSONValue) json = virJSONValueNewArray();
|
2018-04-05 20:17:26 +00:00
|
|
|
qemuMigrationCapability bit;
|
2018-04-05 18:59:07 +00:00
|
|
|
|
2018-04-05 20:17:26 +00:00
|
|
|
for (bit = 0; bit < QEMU_MIGRATION_CAP_LAST; bit++) {
|
2020-08-24 15:00:59 +00:00
|
|
|
g_autoptr(virJSONValue) cap = NULL;
|
2018-04-05 18:59:07 +00:00
|
|
|
|
2020-08-24 15:00:59 +00:00
|
|
|
if (!virBitmapIsBitSet(caps, bit))
|
2018-04-05 18:59:07 +00:00
|
|
|
continue;
|
|
|
|
|
2021-11-08 16:24:50 +00:00
|
|
|
if (virJSONValueObjectAdd(&cap,
|
|
|
|
"s:capability", qemuMigrationCapabilityTypeToString(bit),
|
|
|
|
"b:state", virBitmapIsBitSet(states, bit),
|
|
|
|
NULL) < 0)
|
2020-08-19 11:20:13 +00:00
|
|
|
return NULL;
|
2018-04-05 18:59:07 +00:00
|
|
|
|
2021-02-11 16:57:45 +00:00
|
|
|
if (virJSONValueArrayAppend(json, &cap) < 0)
|
2020-08-19 11:20:13 +00:00
|
|
|
return NULL;
|
2018-04-05 18:59:07 +00:00
|
|
|
}
|
|
|
|
|
2020-08-19 11:20:13 +00:00
|
|
|
return g_steal_pointer(&json);
|
2018-04-05 18:59:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-07-21 13:59:51 +00:00
|
|
|
static int
|
|
|
|
qemuMigrationParamsApplyCaps(virDomainObj *vm,
|
|
|
|
virBitmap *states)
|
|
|
|
{
|
|
|
|
qemuDomainObjPrivate *priv = vm->privateData;
|
|
|
|
g_autoptr(virJSONValue) json = NULL;
|
|
|
|
|
|
|
|
if (!(json = qemuMigrationCapsToJSON(priv->migrationCaps, states)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virJSONValueArraySize(json) > 0 &&
|
|
|
|
qemuMonitorSetMigrationCapabilities(priv->mon, &json) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
qemuMigrationParamsApplyValues(virDomainObj *vm,
|
|
|
|
qemuMigrationParams *params,
|
|
|
|
bool postcopyResume)
|
|
|
|
{
|
|
|
|
qemuDomainObjPrivate *priv = vm->privateData;
|
|
|
|
g_autoptr(virJSONValue) json = NULL;
|
|
|
|
|
|
|
|
if (!(json = qemuMigrationParamsToJSON(params, postcopyResume)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virJSONValueObjectKeysNumber(json) > 0 &&
|
|
|
|
qemuMonitorSetMigrationParams(priv->mon, &json) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-28 13:44:12 +00:00
|
|
|
/**
|
|
|
|
* qemuMigrationParamsApply
|
|
|
|
* @driver: qemu driver
|
|
|
|
* @vm: domain object
|
|
|
|
* @asyncJob: migration job
|
|
|
|
* @migParams: migration parameters to send to QEMU
|
2022-06-29 10:00:03 +00:00
|
|
|
* @apiFlags: migration flags, some of them may affect which parameters are applied
|
2018-02-28 13:44:12 +00:00
|
|
|
*
|
2022-06-29 10:00:03 +00:00
|
|
|
* Send parameters stored in @migParams to QEMU. If @apiFlags is non-zero, some
|
|
|
|
* parameters that do not make sense for the enabled flags will be ignored.
|
2022-06-30 10:52:38 +00:00
|
|
|
* VIR_MIGRATE_POSTCOPY_RESUME is the only flag checked currently.
|
2018-02-28 13:44:12 +00:00
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure.
|
|
|
|
*/
|
2018-02-21 13:18:03 +00:00
|
|
|
int
|
2022-08-10 12:57:02 +00:00
|
|
|
qemuMigrationParamsApply(virDomainObj *vm,
|
2018-02-28 13:44:12 +00:00
|
|
|
int asyncJob,
|
2022-06-29 10:00:03 +00:00
|
|
|
qemuMigrationParams *migParams,
|
2022-10-05 14:54:43 +00:00
|
|
|
unsigned int apiFlags)
|
2018-02-21 13:18:03 +00:00
|
|
|
{
|
2022-06-30 10:52:38 +00:00
|
|
|
bool postcopyResume = !!(apiFlags & VIR_MIGRATE_POSTCOPY_RESUME);
|
2018-02-21 13:18:03 +00:00
|
|
|
int ret = -1;
|
|
|
|
|
2022-08-10 12:57:02 +00:00
|
|
|
if (qemuDomainObjEnterMonitorAsync(vm, asyncJob) < 0)
|
2018-02-21 13:18:03 +00:00
|
|
|
return -1;
|
|
|
|
|
2022-06-30 10:52:38 +00:00
|
|
|
/* Changing capabilities is only allowed before migration starts, we need
|
|
|
|
* to skip them when resuming post-copy migration.
|
|
|
|
*/
|
|
|
|
if (!postcopyResume) {
|
|
|
|
if (asyncJob == VIR_ASYNC_JOB_NONE) {
|
|
|
|
if (!virBitmapIsAllClear(migParams->caps)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2023-08-24 15:03:58 +00:00
|
|
|
_("Migration capabilities can only be set by a migration job"));
|
2022-06-30 10:52:38 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2022-07-21 13:59:51 +00:00
|
|
|
} else if (qemuMigrationParamsApplyCaps(vm, migParams->caps) < 0) {
|
|
|
|
goto cleanup;
|
2022-06-30 10:52:38 +00:00
|
|
|
}
|
2018-04-05 18:59:07 +00:00
|
|
|
}
|
|
|
|
|
2022-07-21 13:59:51 +00:00
|
|
|
if (qemuMigrationParamsApplyValues(vm, migParams, postcopyResume) < 0)
|
2020-11-30 14:17:34 +00:00
|
|
|
goto cleanup;
|
2018-03-15 19:24:05 +00:00
|
|
|
|
2018-02-21 13:18:03 +00:00
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
2022-03-18 10:17:28 +00:00
|
|
|
qemuDomainObjExitMonitor(vm);
|
2018-02-21 13:18:03 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-27 11:17:17 +00:00
|
|
|
/**
|
|
|
|
* qemuMigrationParamsSetString:
|
|
|
|
* @migrParams: migration parameter object
|
|
|
|
* @param: parameter to set
|
|
|
|
* @value: new value
|
|
|
|
*
|
|
|
|
* Enables and sets the migration parameter @param in @migrParams. Returns 0 on
|
|
|
|
* success and -1 on error. Libvirt error is reported.
|
|
|
|
*/
|
2018-04-27 10:59:00 +00:00
|
|
|
static int
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParamsSetString(qemuMigrationParams *migParams,
|
2018-04-27 10:59:00 +00:00
|
|
|
qemuMigrationParam param,
|
|
|
|
const char *value)
|
|
|
|
{
|
|
|
|
if (qemuMigrationParamsCheckType(param, QEMU_MIGRATION_PARAM_TYPE_STRING) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2019-10-20 11:49:46 +00:00
|
|
|
migParams->params[param].value.s = g_strdup(value);
|
2018-04-27 10:59:00 +00:00
|
|
|
|
2018-04-27 11:17:17 +00:00
|
|
|
migParams->params[param].set = true;
|
|
|
|
|
2018-04-27 10:59:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-28 09:45:07 +00:00
|
|
|
/* qemuMigrationParamsEnableTLS
|
2018-02-21 13:18:03 +00:00
|
|
|
* @driver: pointer to qemu driver
|
|
|
|
* @vm: domain object
|
2018-02-27 16:54:54 +00:00
|
|
|
* @tlsListen: server or client
|
|
|
|
* @asyncJob: Migration job to join
|
|
|
|
* @tlsAlias: alias to be generated for TLS object
|
2018-02-28 11:57:19 +00:00
|
|
|
* @hostname: hostname of the migration destination
|
2018-02-27 16:54:54 +00:00
|
|
|
* @migParams: migration parameters to set
|
2018-02-21 13:18:03 +00:00
|
|
|
*
|
2018-02-28 11:57:19 +00:00
|
|
|
* Create the TLS objects for the migration and set the migParams value.
|
|
|
|
* If QEMU itself does not connect to the destination @hostname must be
|
|
|
|
* provided for certificate verification.
|
2018-02-21 13:18:03 +00:00
|
|
|
*
|
2018-02-27 16:54:54 +00:00
|
|
|
* Returns 0 on success, -1 on failure
|
2018-02-21 13:18:03 +00:00
|
|
|
*/
|
|
|
|
int
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParamsEnableTLS(virQEMUDriver *driver,
|
|
|
|
virDomainObj *vm,
|
2018-02-28 09:45:07 +00:00
|
|
|
bool tlsListen,
|
|
|
|
int asyncJob,
|
|
|
|
char **tlsAlias,
|
2018-02-28 11:57:19 +00:00
|
|
|
const char *hostname,
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParams *migParams)
|
2018-02-21 13:18:03 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuDomainObjPrivate *priv = vm->privateData;
|
2022-09-05 13:57:04 +00:00
|
|
|
qemuDomainJobPrivate *jobPriv = vm->job->privateData;
|
2020-07-13 09:49:42 +00:00
|
|
|
g_autoptr(virJSONValue) tlsProps = NULL;
|
|
|
|
g_autoptr(virJSONValue) secProps = NULL;
|
|
|
|
g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
|
2018-05-29 17:56:05 +00:00
|
|
|
const char *secAlias = NULL;
|
2018-02-21 13:18:03 +00:00
|
|
|
|
|
|
|
if (!cfg->migrateTLSx509certdir) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("host migration TLS directory not configured"));
|
2020-07-13 09:49:42 +00:00
|
|
|
return -1;
|
2018-02-21 13:18:03 +00:00
|
|
|
}
|
|
|
|
|
2020-07-16 11:48:34 +00:00
|
|
|
if (!jobPriv->migParams->params[QEMU_MIGRATION_PARAM_TLS_CREDS].set) {
|
2018-02-21 13:18:03 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
|
2023-08-24 15:03:58 +00:00
|
|
|
_("TLS migration is not supported with this QEMU binary"));
|
2020-07-13 09:49:42 +00:00
|
|
|
return -1;
|
2018-02-21 13:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If there's a secret, then grab/store it now using the connection */
|
2018-05-29 17:56:05 +00:00
|
|
|
if (cfg->migrateTLSx509secretUUID) {
|
|
|
|
if (!(priv->migSecinfo =
|
|
|
|
qemuDomainSecretInfoTLSNew(priv, QEMU_MIGRATION_TLS_ALIAS_BASE,
|
|
|
|
cfg->migrateTLSx509secretUUID)))
|
2020-07-13 09:49:42 +00:00
|
|
|
return -1;
|
2021-09-22 07:34:31 +00:00
|
|
|
secAlias = priv->migSecinfo->alias;
|
2018-05-29 17:56:05 +00:00
|
|
|
}
|
2018-02-21 13:18:03 +00:00
|
|
|
|
2018-05-30 07:24:35 +00:00
|
|
|
if (!(*tlsAlias = qemuAliasTLSObjFromSrcAlias(QEMU_MIGRATION_TLS_ALIAS_BASE)))
|
2020-07-13 09:49:42 +00:00
|
|
|
return -1;
|
2018-05-30 07:24:35 +00:00
|
|
|
|
2021-09-23 13:51:21 +00:00
|
|
|
if (qemuDomainGetTLSObjects(priv->migSecinfo,
|
2018-02-21 13:18:03 +00:00
|
|
|
cfg->migrateTLSx509certdir, tlsListen,
|
|
|
|
cfg->migrateTLSx509verify,
|
2018-05-22 05:38:22 +00:00
|
|
|
*tlsAlias, &tlsProps, &secProps) < 0)
|
2020-07-13 09:49:42 +00:00
|
|
|
return -1;
|
2018-02-21 13:18:03 +00:00
|
|
|
|
|
|
|
/* Ensure the domain doesn't already have the TLS objects defined...
|
|
|
|
* This should prevent any issues just in case some cleanup wasn't
|
|
|
|
* properly completed (both src and dst use the same alias) or
|
|
|
|
* some other error path between now and perform . */
|
2022-08-10 12:57:02 +00:00
|
|
|
qemuDomainDelTLSObjects(vm, asyncJob, secAlias, *tlsAlias);
|
2018-02-21 13:18:03 +00:00
|
|
|
|
2022-08-10 12:57:02 +00:00
|
|
|
if (qemuDomainAddTLSObjects(vm, asyncJob, &secProps, &tlsProps) < 0)
|
2020-07-13 09:49:42 +00:00
|
|
|
return -1;
|
2018-02-21 13:18:03 +00:00
|
|
|
|
2018-03-28 16:25:58 +00:00
|
|
|
if (qemuMigrationParamsSetString(migParams,
|
|
|
|
QEMU_MIGRATION_PARAM_TLS_CREDS,
|
2019-12-03 15:20:35 +00:00
|
|
|
*tlsAlias) < 0)
|
2020-07-13 09:49:42 +00:00
|
|
|
return -1;
|
2019-12-03 15:20:35 +00:00
|
|
|
|
|
|
|
if (!migParams->params[QEMU_MIGRATION_PARAM_TLS_HOSTNAME].set &&
|
2018-03-28 16:25:58 +00:00
|
|
|
qemuMigrationParamsSetString(migParams,
|
|
|
|
QEMU_MIGRATION_PARAM_TLS_HOSTNAME,
|
2019-02-12 16:25:06 +00:00
|
|
|
NULLSTR_EMPTY(hostname)) < 0)
|
2020-07-13 09:49:42 +00:00
|
|
|
return -1;
|
2018-02-21 13:18:03 +00:00
|
|
|
|
2020-07-13 09:49:42 +00:00
|
|
|
return 0;
|
2018-02-21 13:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-28 08:35:53 +00:00
|
|
|
/* qemuMigrationParamsDisableTLS
|
2018-02-21 13:18:03 +00:00
|
|
|
* @vm: domain object
|
|
|
|
* @migParams: Pointer to a migration parameters block
|
|
|
|
*
|
|
|
|
* If we support setting the tls-creds, then set both tls-creds and
|
|
|
|
* tls-hostname to the empty string ("") which indicates to not use
|
|
|
|
* TLS on this migration.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure
|
|
|
|
*/
|
|
|
|
int
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParamsDisableTLS(virDomainObj *vm,
|
|
|
|
qemuMigrationParams *migParams)
|
2018-02-21 13:18:03 +00:00
|
|
|
{
|
2022-09-05 13:57:04 +00:00
|
|
|
qemuDomainJobPrivate *jobPriv = vm->job->privateData;
|
2018-02-21 13:18:03 +00:00
|
|
|
|
2020-07-16 11:48:34 +00:00
|
|
|
if (!jobPriv->migParams->params[QEMU_MIGRATION_PARAM_TLS_CREDS].set)
|
2018-03-27 22:23:20 +00:00
|
|
|
return 0;
|
2018-02-21 13:18:03 +00:00
|
|
|
|
2018-03-28 16:25:58 +00:00
|
|
|
if (qemuMigrationParamsSetString(migParams,
|
|
|
|
QEMU_MIGRATION_PARAM_TLS_CREDS, "") < 0 ||
|
|
|
|
qemuMigrationParamsSetString(migParams,
|
|
|
|
QEMU_MIGRATION_PARAM_TLS_HOSTNAME, "") < 0)
|
2018-03-27 22:23:20 +00:00
|
|
|
return -1;
|
2018-02-21 13:18:03 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-02 10:06:12 +00:00
|
|
|
bool
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParamsTLSHostnameIsSet(qemuMigrationParams *migParams)
|
2020-09-02 10:06:12 +00:00
|
|
|
{
|
|
|
|
int param = QEMU_MIGRATION_PARAM_TLS_HOSTNAME;
|
|
|
|
return (migParams->params[param].set &&
|
|
|
|
STRNEQ(migParams->params[param].value.s, ""));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-21 13:18:03 +00:00
|
|
|
/* qemuMigrationParamsResetTLS
|
|
|
|
* @driver: pointer to qemu driver
|
|
|
|
* @vm: domain object
|
|
|
|
* @asyncJob: migration job to join
|
2018-03-21 13:57:44 +00:00
|
|
|
* @apiFlags: API flags used to start the migration
|
2018-02-21 13:18:03 +00:00
|
|
|
*
|
|
|
|
* Deconstruct all the setup possibly done for TLS - delete the TLS and
|
2020-03-09 07:04:54 +00:00
|
|
|
* security objects and free the secinfo
|
2018-02-21 13:18:03 +00:00
|
|
|
*/
|
2018-02-27 16:09:17 +00:00
|
|
|
static void
|
2022-08-10 12:57:02 +00:00
|
|
|
qemuMigrationParamsResetTLS(virDomainObj *vm,
|
2018-02-27 16:09:17 +00:00
|
|
|
int asyncJob,
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParams *origParams,
|
2022-10-05 14:54:43 +00:00
|
|
|
unsigned int apiFlags)
|
2018-02-21 13:18:03 +00:00
|
|
|
{
|
2020-03-09 07:03:49 +00:00
|
|
|
g_autofree char *tlsAlias = NULL;
|
|
|
|
g_autofree char *secAlias = NULL;
|
2018-02-21 13:18:03 +00:00
|
|
|
|
2018-03-21 13:57:44 +00:00
|
|
|
/* There's nothing to do if QEMU does not support TLS migration or we were
|
|
|
|
* not asked to enable it. */
|
|
|
|
if (!origParams->params[QEMU_MIGRATION_PARAM_TLS_CREDS].set ||
|
|
|
|
!(apiFlags & VIR_MIGRATE_TLS))
|
2018-02-27 16:09:17 +00:00
|
|
|
return;
|
2018-02-21 15:59:10 +00:00
|
|
|
|
2018-02-21 13:18:03 +00:00
|
|
|
tlsAlias = qemuAliasTLSObjFromSrcAlias(QEMU_MIGRATION_TLS_ALIAS_BASE);
|
2023-03-13 09:50:18 +00:00
|
|
|
secAlias = qemuAliasForSecret(QEMU_MIGRATION_TLS_ALIAS_BASE, NULL, 0);
|
2018-02-21 13:18:03 +00:00
|
|
|
|
2022-08-10 12:57:02 +00:00
|
|
|
qemuDomainDelTLSObjects(vm, asyncJob, secAlias, tlsAlias);
|
2020-03-06 13:44:43 +00:00
|
|
|
g_clear_pointer(&QEMU_DOMAIN_PRIVATE(vm)->migSecinfo, qemuDomainSecretInfoFree);
|
2018-02-21 13:18:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-15 10:27:07 +00:00
|
|
|
int
|
2022-08-10 12:57:02 +00:00
|
|
|
qemuMigrationParamsFetch(virDomainObj *vm,
|
2018-03-15 10:27:07 +00:00
|
|
|
int asyncJob,
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParams **migParams)
|
2018-03-15 10:27:07 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuDomainObjPrivate *priv = vm->privateData;
|
2020-07-13 09:49:41 +00:00
|
|
|
g_autoptr(virJSONValue) jsonParams = NULL;
|
2018-03-15 10:27:07 +00:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
*migParams = NULL;
|
|
|
|
|
2022-08-10 12:57:02 +00:00
|
|
|
if (qemuDomainObjEnterMonitorAsync(vm, asyncJob) < 0)
|
2020-07-13 09:49:41 +00:00
|
|
|
return -1;
|
2018-03-15 10:27:07 +00:00
|
|
|
|
2018-03-15 17:06:01 +00:00
|
|
|
rc = qemuMonitorGetMigrationParams(priv->mon, &jsonParams);
|
2018-03-15 10:27:07 +00:00
|
|
|
|
2022-03-18 10:17:28 +00:00
|
|
|
qemuDomainObjExitMonitor(vm);
|
2021-11-24 12:11:52 +00:00
|
|
|
if (rc < 0)
|
2020-07-13 09:49:41 +00:00
|
|
|
return -1;
|
2018-03-15 10:27:07 +00:00
|
|
|
|
2018-03-15 17:06:01 +00:00
|
|
|
if (!(*migParams = qemuMigrationParamsFromJSON(jsonParams)))
|
2020-07-13 09:49:41 +00:00
|
|
|
return -1;
|
2018-03-15 10:27:07 +00:00
|
|
|
|
2020-07-13 09:49:41 +00:00
|
|
|
return 0;
|
2018-03-15 10:27:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-02-04 16:11:42 +00:00
|
|
|
int
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParamsSetULL(qemuMigrationParams *migParams,
|
2019-02-04 16:11:42 +00:00
|
|
|
qemuMigrationParam param,
|
|
|
|
unsigned long long value)
|
|
|
|
{
|
|
|
|
if (qemuMigrationParamsCheckType(param, QEMU_MIGRATION_PARAM_TYPE_ULL) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
migParams->params[param].value.ull = value;
|
|
|
|
migParams->params[param].set = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-15 10:39:50 +00:00
|
|
|
/**
|
2018-03-16 10:56:21 +00:00
|
|
|
* Returns -1 on error,
|
|
|
|
* 0 on success,
|
2018-03-15 10:39:50 +00:00
|
|
|
* 1 if the parameter is not supported by QEMU.
|
|
|
|
*/
|
|
|
|
int
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParamsGetULL(qemuMigrationParams *migParams,
|
2018-03-16 10:56:21 +00:00
|
|
|
qemuMigrationParam param,
|
|
|
|
unsigned long long *value)
|
2018-03-15 10:39:50 +00:00
|
|
|
{
|
2018-03-16 10:56:21 +00:00
|
|
|
if (qemuMigrationParamsCheckType(param, QEMU_MIGRATION_PARAM_TYPE_ULL) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!migParams->params[param].set)
|
2018-03-15 10:39:50 +00:00
|
|
|
return 1;
|
|
|
|
|
2018-03-16 10:56:21 +00:00
|
|
|
*value = migParams->params[param].value.ull;
|
2018-03-15 10:39:50 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-27 14:45:52 +00:00
|
|
|
/**
|
|
|
|
* qemuMigrationParamsCheck:
|
|
|
|
*
|
|
|
|
* Check supported migration parameters and keep their original values in
|
2022-07-19 13:48:20 +00:00
|
|
|
* virDomainJobObj so that we can properly reset them at the end of migration.
|
2018-03-07 09:45:18 +00:00
|
|
|
* Reports an error if any of the currently used capabilities in @migParams
|
|
|
|
* are unsupported by QEMU.
|
2018-02-27 14:45:52 +00:00
|
|
|
*/
|
|
|
|
int
|
2022-08-10 12:57:02 +00:00
|
|
|
qemuMigrationParamsCheck(virDomainObj *vm,
|
2018-03-07 09:45:18 +00:00
|
|
|
int asyncJob,
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParams *migParams,
|
|
|
|
virBitmap *remoteCaps)
|
2018-02-27 14:45:52 +00:00
|
|
|
{
|
2022-09-05 13:57:04 +00:00
|
|
|
qemuDomainJobPrivate *jobPriv = vm->job->privateData;
|
2018-04-05 20:17:26 +00:00
|
|
|
qemuMigrationCapability cap;
|
2018-03-07 14:59:42 +00:00
|
|
|
qemuMigrationParty party;
|
|
|
|
size_t i;
|
2018-02-27 14:45:52 +00:00
|
|
|
|
2022-03-24 15:32:42 +00:00
|
|
|
if (asyncJob == VIR_ASYNC_JOB_MIGRATION_OUT)
|
2018-03-07 14:59:42 +00:00
|
|
|
party = QEMU_MIGRATION_SOURCE;
|
|
|
|
else
|
|
|
|
party = QEMU_MIGRATION_DESTINATION;
|
|
|
|
|
2018-04-05 20:17:26 +00:00
|
|
|
for (cap = 0; cap < QEMU_MIGRATION_CAP_LAST; cap++) {
|
2018-03-07 09:45:18 +00:00
|
|
|
bool state = false;
|
|
|
|
|
|
|
|
ignore_value(virBitmapGetBit(migParams->caps, cap, &state));
|
|
|
|
|
|
|
|
if (state && !qemuMigrationCapsGet(vm, cap)) {
|
|
|
|
virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
|
2023-03-09 12:15:22 +00:00
|
|
|
_("Migration option '%1$s' is not supported by QEMU binary"),
|
2018-04-05 20:17:26 +00:00
|
|
|
qemuMigrationCapabilityTypeToString(cap));
|
2018-03-07 09:45:18 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-15 11:55:26 +00:00
|
|
|
for (i = 0; i < G_N_ELEMENTS(qemuMigrationParamsAlwaysOn); i++) {
|
2018-03-07 14:59:42 +00:00
|
|
|
cap = qemuMigrationParamsAlwaysOn[i].cap;
|
|
|
|
|
|
|
|
if (qemuMigrationParamsAlwaysOn[i].party & party &&
|
|
|
|
qemuMigrationCapsGet(vm, cap)) {
|
2018-04-06 12:02:04 +00:00
|
|
|
if (qemuMigrationParamsAlwaysOn[i].party != party) {
|
|
|
|
bool remote = false;
|
|
|
|
|
|
|
|
if (remoteCaps)
|
|
|
|
ignore_value(virBitmapGetBit(remoteCaps, cap, &remote));
|
|
|
|
|
|
|
|
if (!remote) {
|
|
|
|
VIR_DEBUG("Not enabling migration capability '%s'; it is "
|
|
|
|
"not supported or automatically enabled by the "
|
|
|
|
"other side of migration",
|
|
|
|
qemuMigrationCapabilityTypeToString(cap));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-07 14:59:42 +00:00
|
|
|
VIR_DEBUG("Enabling migration capability '%s'",
|
2018-04-05 20:17:26 +00:00
|
|
|
qemuMigrationCapabilityTypeToString(cap));
|
2018-03-07 14:59:42 +00:00
|
|
|
ignore_value(virBitmapSetBit(migParams->caps, cap));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-26 14:47:33 +00:00
|
|
|
/*
|
|
|
|
* We want to disable all migration capabilities after migration, no need
|
|
|
|
* to ask QEMU for their current settings.
|
|
|
|
*/
|
|
|
|
|
2022-08-10 12:57:02 +00:00
|
|
|
return qemuMigrationParamsFetch(vm, asyncJob, &jobPriv->migParams);
|
2018-02-27 14:45:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-21 13:18:03 +00:00
|
|
|
/*
|
|
|
|
* qemuMigrationParamsReset:
|
|
|
|
*
|
|
|
|
* Reset all migration parameters so that the next job which internally uses
|
|
|
|
* migration (save, managedsave, snapshots, dump) will not try to use them.
|
|
|
|
*/
|
|
|
|
void
|
2022-08-10 12:57:02 +00:00
|
|
|
qemuMigrationParamsReset(virDomainObj *vm,
|
2018-02-27 16:09:17 +00:00
|
|
|
int asyncJob,
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParams *origParams,
|
2022-10-05 14:54:43 +00:00
|
|
|
unsigned int apiFlags)
|
2018-02-21 13:18:03 +00:00
|
|
|
{
|
2018-12-06 17:33:04 +00:00
|
|
|
virErrorPtr err;
|
2022-07-21 14:49:09 +00:00
|
|
|
g_autoptr(virBitmap) clearCaps = NULL;
|
2022-07-28 13:35:45 +00:00
|
|
|
int rc;
|
2018-12-06 17:33:04 +00:00
|
|
|
|
|
|
|
virErrorPreserveLast(&err);
|
2018-02-21 13:18:03 +00:00
|
|
|
|
2022-10-05 14:54:43 +00:00
|
|
|
VIR_DEBUG("Resetting migration parameters %p, flags 0x%x",
|
2018-03-21 13:57:44 +00:00
|
|
|
origParams, apiFlags);
|
2018-02-27 16:09:17 +00:00
|
|
|
|
2018-02-26 14:47:33 +00:00
|
|
|
if (!virDomainObjIsActive(vm) || !origParams)
|
2018-02-21 13:18:03 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2022-08-10 12:57:02 +00:00
|
|
|
if (qemuDomainObjEnterMonitorAsync(vm, asyncJob) < 0)
|
2018-02-26 14:47:33 +00:00
|
|
|
goto cleanup;
|
2018-02-21 13:18:03 +00:00
|
|
|
|
2022-07-21 14:49:09 +00:00
|
|
|
clearCaps = virBitmapNew(0);
|
|
|
|
|
2022-07-28 13:35:45 +00:00
|
|
|
rc = 0;
|
|
|
|
if (qemuMigrationParamsApplyCaps(vm, clearCaps) < 0 ||
|
|
|
|
qemuMigrationParamsApplyValues(vm, origParams, false) < 0)
|
|
|
|
rc = -1;
|
2022-07-21 14:49:09 +00:00
|
|
|
|
|
|
|
qemuDomainObjExitMonitor(vm);
|
2022-07-28 13:35:45 +00:00
|
|
|
if (rc < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2022-08-10 12:57:02 +00:00
|
|
|
qemuMigrationParamsResetTLS(vm, asyncJob, origParams, apiFlags);
|
2018-02-21 13:18:03 +00:00
|
|
|
|
|
|
|
cleanup:
|
2018-12-06 17:33:04 +00:00
|
|
|
virErrorRestore(&err);
|
2018-02-21 13:18:03 +00:00
|
|
|
}
|
2018-02-20 15:40:21 +00:00
|
|
|
|
|
|
|
|
2018-03-13 15:08:49 +00:00
|
|
|
void
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParamsFormat(virBuffer *buf,
|
|
|
|
qemuMigrationParams *migParams)
|
2018-03-13 15:08:49 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParamValue *pv;
|
2018-03-13 15:08:49 +00:00
|
|
|
size_t i;
|
|
|
|
|
|
|
|
virBufferAddLit(buf, "<migParams>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
|
|
|
|
for (i = 0; i < QEMU_MIGRATION_PARAM_LAST; i++) {
|
|
|
|
pv = &migParams->params[i];
|
|
|
|
|
|
|
|
if (!pv->set)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
virBufferAsprintf(buf, "<param name='%s' ",
|
|
|
|
qemuMigrationParamTypeToString(i));
|
|
|
|
|
2022-06-29 13:12:20 +00:00
|
|
|
switch (qemuMigrationParamInfo[i].type) {
|
2018-03-13 15:08:49 +00:00
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_INT:
|
|
|
|
virBufferAsprintf(buf, "value='%d'", pv->value.i);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_ULL:
|
|
|
|
virBufferAsprintf(buf, "value='%llu'", pv->value.ull);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_BOOL:
|
|
|
|
virBufferAsprintf(buf, "value='%s'", pv->value.b ? "yes" : "no");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_STRING:
|
|
|
|
virBufferEscapeString(buf, "value='%s'", pv->value.s);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</migParams>\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
qemuMigrationParamsParse(xmlXPathContextPtr ctxt,
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParams **migParams)
|
2018-03-13 15:08:49 +00:00
|
|
|
{
|
2020-08-19 11:20:13 +00:00
|
|
|
g_autoptr(qemuMigrationParams) params = NULL;
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationParamValue *pv;
|
2020-08-19 11:20:13 +00:00
|
|
|
g_autofree xmlNodePtr *nodes = NULL;
|
2018-03-13 15:08:49 +00:00
|
|
|
size_t i;
|
|
|
|
int rc;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
*migParams = NULL;
|
|
|
|
|
|
|
|
if ((rc = virXPathBoolean("boolean(./migParams)", ctxt)) < 0)
|
2020-08-19 11:20:13 +00:00
|
|
|
return -1;
|
2018-03-13 15:08:49 +00:00
|
|
|
|
2020-08-19 11:20:13 +00:00
|
|
|
if (rc == 0)
|
|
|
|
return 0;
|
2018-03-13 15:08:49 +00:00
|
|
|
|
|
|
|
if ((n = virXPathNodeSet("./migParams[1]/param", ctxt, &nodes)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!(params = qemuMigrationParamsNew()))
|
2020-08-19 11:20:13 +00:00
|
|
|
return -1;
|
2018-03-13 15:08:49 +00:00
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
2020-08-19 11:20:13 +00:00
|
|
|
g_autofree char *name = NULL;
|
|
|
|
g_autofree char *value = NULL;
|
|
|
|
int param;
|
|
|
|
|
2018-03-13 15:08:49 +00:00
|
|
|
if (!(name = virXMLPropString(nodes[i], "name"))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("missing migration parameter name"));
|
2020-08-19 11:20:13 +00:00
|
|
|
return -1;
|
2018-03-13 15:08:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((param = qemuMigrationParamTypeFromString(name)) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2023-03-09 12:15:22 +00:00
|
|
|
_("unknown migration parameter '%1$s'"), name);
|
2020-08-19 11:20:13 +00:00
|
|
|
return -1;
|
2018-03-13 15:08:49 +00:00
|
|
|
}
|
|
|
|
pv = ¶ms->params[param];
|
|
|
|
|
|
|
|
if (!(value = virXMLPropString(nodes[i], "value"))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2023-03-09 12:15:22 +00:00
|
|
|
_("missing value for migration parameter '%1$s'"),
|
2018-03-13 15:08:49 +00:00
|
|
|
name);
|
2020-08-19 11:20:13 +00:00
|
|
|
return -1;
|
2018-03-13 15:08:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rc = 0;
|
2022-06-29 13:12:20 +00:00
|
|
|
switch (qemuMigrationParamInfo[param].type) {
|
2018-03-13 15:08:49 +00:00
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_INT:
|
|
|
|
rc = virStrToLong_i(value, NULL, 10, &pv->value.i);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_ULL:
|
|
|
|
rc = virStrToLong_ullp(value, NULL, 10, &pv->value.ull);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_BOOL:
|
2019-10-17 03:19:33 +00:00
|
|
|
rc = virStringParseYesNo(value, &pv->value.b);
|
2018-03-13 15:08:49 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case QEMU_MIGRATION_PARAM_TYPE_STRING:
|
2019-10-16 11:43:18 +00:00
|
|
|
pv->value.s = g_steal_pointer(&value);
|
2018-03-13 15:08:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2023-03-09 12:15:22 +00:00
|
|
|
_("invalid value '%1$s' for migration parameter '%2$s'"),
|
2018-03-13 15:08:49 +00:00
|
|
|
value, name);
|
2020-08-19 11:20:13 +00:00
|
|
|
return -1;
|
2018-03-13 15:08:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pv->set = true;
|
|
|
|
}
|
|
|
|
|
2019-10-16 11:43:18 +00:00
|
|
|
*migParams = g_steal_pointer(¶ms);
|
2018-03-13 15:08:49 +00:00
|
|
|
|
2020-08-19 11:20:13 +00:00
|
|
|
return 0;
|
2018-03-13 15:08:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-20 15:40:21 +00:00
|
|
|
int
|
2022-08-10 12:57:02 +00:00
|
|
|
qemuMigrationCapsCheck(virDomainObj *vm,
|
2022-05-11 13:32:58 +00:00
|
|
|
int asyncJob,
|
|
|
|
bool reconnect)
|
2018-02-20 15:40:21 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuDomainObjPrivate *priv = vm->privateData;
|
2020-08-19 11:20:13 +00:00
|
|
|
g_autoptr(virJSONValue) json = NULL;
|
|
|
|
g_auto(GStrv) caps = NULL;
|
2018-02-20 15:40:21 +00:00
|
|
|
char **capStr;
|
|
|
|
int rc;
|
|
|
|
|
2022-08-10 12:57:02 +00:00
|
|
|
if (qemuDomainObjEnterMonitorAsync(vm, asyncJob) < 0)
|
2018-02-20 15:40:21 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
rc = qemuMonitorGetMigrationCapabilities(priv->mon, &caps);
|
|
|
|
|
2022-03-18 10:17:28 +00:00
|
|
|
qemuDomainObjExitMonitor(vm);
|
2021-11-24 12:11:52 +00:00
|
|
|
if (rc < 0)
|
2020-08-19 11:20:13 +00:00
|
|
|
return -1;
|
2018-02-20 15:40:21 +00:00
|
|
|
|
2020-08-19 11:20:13 +00:00
|
|
|
if (!caps)
|
|
|
|
return 0;
|
2018-02-20 15:40:21 +00:00
|
|
|
|
2018-04-05 20:17:26 +00:00
|
|
|
priv->migrationCaps = virBitmapNew(QEMU_MIGRATION_CAP_LAST);
|
2018-02-20 15:40:21 +00:00
|
|
|
|
|
|
|
for (capStr = caps; *capStr; capStr++) {
|
2018-04-05 20:17:26 +00:00
|
|
|
int cap = qemuMigrationCapabilityTypeFromString(*capStr);
|
2018-02-20 15:40:21 +00:00
|
|
|
|
|
|
|
if (cap < 0) {
|
|
|
|
VIR_DEBUG("Unknown migration capability: '%s'", *capStr);
|
|
|
|
} else {
|
|
|
|
ignore_value(virBitmapSetBit(priv->migrationCaps, cap));
|
|
|
|
VIR_DEBUG("Found migration capability: '%s'", *capStr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-11 13:32:58 +00:00
|
|
|
if (!reconnect) {
|
|
|
|
g_autoptr(virBitmap) migEvent = virBitmapNew(QEMU_MIGRATION_CAP_LAST);
|
2018-03-01 09:51:53 +00:00
|
|
|
|
2022-05-11 13:32:58 +00:00
|
|
|
ignore_value(virBitmapSetBit(migEvent, QEMU_MIGRATION_CAP_EVENTS));
|
2018-03-01 09:51:53 +00:00
|
|
|
|
2022-05-11 13:32:58 +00:00
|
|
|
if (!(json = qemuMigrationCapsToJSON(migEvent, migEvent)))
|
|
|
|
return -1;
|
2018-04-05 18:59:07 +00:00
|
|
|
|
2022-08-10 12:57:02 +00:00
|
|
|
if (qemuDomainObjEnterMonitorAsync(vm, asyncJob) < 0)
|
2022-05-11 13:32:58 +00:00
|
|
|
return -1;
|
2018-02-20 15:40:21 +00:00
|
|
|
|
2022-05-11 13:32:58 +00:00
|
|
|
rc = qemuMonitorSetMigrationCapabilities(priv->mon, &json);
|
2018-02-20 15:40:21 +00:00
|
|
|
|
2022-05-11 13:32:58 +00:00
|
|
|
qemuDomainObjExitMonitor(vm);
|
2018-02-20 15:40:21 +00:00
|
|
|
|
2022-05-11 13:32:58 +00:00
|
|
|
if (rc < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
2018-02-20 15:40:21 +00:00
|
|
|
|
|
|
|
/* Migration events capability must always be enabled, clearing it from
|
|
|
|
* migration capabilities bitmap makes sure it won't be touched anywhere
|
|
|
|
* else.
|
|
|
|
*/
|
|
|
|
ignore_value(virBitmapClearBit(priv->migrationCaps,
|
2018-04-05 20:17:26 +00:00
|
|
|
QEMU_MIGRATION_CAP_EVENTS));
|
2018-02-20 15:40:21 +00:00
|
|
|
|
2020-08-19 11:20:13 +00:00
|
|
|
return 0;
|
2018-02-20 15:40:21 +00:00
|
|
|
}
|
2018-04-06 13:22:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
bool
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuMigrationCapsGet(virDomainObj *vm,
|
2018-04-05 20:17:26 +00:00
|
|
|
qemuMigrationCapability cap)
|
2018-04-06 13:22:51 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
qemuDomainObjPrivate *priv = vm->privateData;
|
2018-04-06 13:22:51 +00:00
|
|
|
bool enabled = false;
|
|
|
|
|
|
|
|
if (priv->migrationCaps)
|
|
|
|
ignore_value(virBitmapGetBit(priv->migrationCaps, cap, &enabled));
|
|
|
|
|
|
|
|
return enabled;
|
|
|
|
}
|
2022-03-10 11:59:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* qemuMigrationParamsGetTLSHostname:
|
|
|
|
* @migParams: Migration params object
|
|
|
|
*
|
|
|
|
* Fetches the value of the QEMU_MIGRATION_PARAM_TLS_HOSTNAME parameter which is
|
|
|
|
* passed from the user as VIR_MIGRATE_PARAM_TLS_DESTINATION
|
|
|
|
*/
|
|
|
|
const char *
|
|
|
|
qemuMigrationParamsGetTLSHostname(qemuMigrationParams *migParams)
|
|
|
|
{
|
|
|
|
if (!migParams->params[QEMU_MIGRATION_PARAM_TLS_HOSTNAME].set)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return migParams->params[QEMU_MIGRATION_PARAM_TLS_HOSTNAME].value.s;
|
|
|
|
}
|