1 /*
2  * qemu_migration_params.c: QEMU migration parameters handling
3  *
4  * Copyright (C) 2006-2018 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library.  If not, see
18  * <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #include <config.h>
23 
24 #include "virlog.h"
25 #include "virerror.h"
26 #include "viralloc.h"
27 #include "virstring.h"
28 
29 #include "qemu_alias.h"
30 #include "qemu_hotplug.h"
31 #include "qemu_migration.h"
32 #include "qemu_migration_params.h"
33 #define LIBVIRT_QEMU_MIGRATION_PARAMSPRIV_H_ALLOW
34 #include "qemu_migration_paramspriv.h"
35 #include "qemu_monitor.h"
36 
37 #define VIR_FROM_THIS VIR_FROM_QEMU
38 
39 VIR_LOG_INIT("qemu.qemu_migration_params");
40 
41 #define QEMU_MIGRATION_TLS_ALIAS_BASE "libvirt_migrate"
42 
43 typedef enum {
44     QEMU_MIGRATION_PARAM_TYPE_INT,
45     QEMU_MIGRATION_PARAM_TYPE_ULL,
46     QEMU_MIGRATION_PARAM_TYPE_BOOL,
47     QEMU_MIGRATION_PARAM_TYPE_STRING,
48 } qemuMigrationParamType;
49 
50 typedef struct _qemuMigrationParamValue qemuMigrationParamValue;
51 struct _qemuMigrationParamValue {
52     bool set;
53     union {
54         int i; /* exempt from syntax-check */
55         unsigned long long ull;
56         bool b;
57         char *s;
58     } value;
59 };
60 
61 struct _qemuMigrationParams {
62     unsigned long long compMethods; /* bit-wise OR of qemuMigrationCompressMethod */
63     virBitmap *caps;
64     qemuMigrationParamValue params[QEMU_MIGRATION_PARAM_LAST];
65     virJSONValue *blockDirtyBitmapMapping;
66 };
67 
68 typedef enum {
69     QEMU_MIGRATION_COMPRESS_XBZRLE = 0,
70     QEMU_MIGRATION_COMPRESS_MT,
71 
72     QEMU_MIGRATION_COMPRESS_LAST
73 } qemuMigrationCompressMethod;
74 VIR_ENUM_DECL(qemuMigrationCompressMethod);
75 VIR_ENUM_IMPL(qemuMigrationCompressMethod,
76               QEMU_MIGRATION_COMPRESS_LAST,
77               "xbzrle",
78               "mt",
79 );
80 
81 VIR_ENUM_IMPL(qemuMigrationCapability,
82               QEMU_MIGRATION_CAP_LAST,
83               "xbzrle",
84               "auto-converge",
85               "rdma-pin-all",
86               "events",
87               "postcopy-ram",
88               "compress",
89               "pause-before-switchover",
90               "late-block-activate",
91               "multifd",
92               "dirty-bitmaps",
93 );
94 
95 
96 VIR_ENUM_DECL(qemuMigrationParam);
97 VIR_ENUM_IMPL(qemuMigrationParam,
98               QEMU_MIGRATION_PARAM_LAST,
99               "compress-level",
100               "compress-threads",
101               "decompress-threads",
102               "cpu-throttle-initial",
103               "cpu-throttle-increment",
104               "tls-creds",
105               "tls-hostname",
106               "max-bandwidth",
107               "downtime-limit",
108               "block-incremental",
109               "xbzrle-cache-size",
110               "max-postcopy-bandwidth",
111               "multifd-channels",
112 );
113 
114 typedef struct _qemuMigrationParamsAlwaysOnItem qemuMigrationParamsAlwaysOnItem;
115 struct _qemuMigrationParamsAlwaysOnItem {
116     qemuMigrationCapability cap;
117     int party; /* bit-wise OR of qemuMigrationParty */
118 };
119 
120 typedef struct _qemuMigrationParamsFlagMapItem qemuMigrationParamsFlagMapItem;
121 struct _qemuMigrationParamsFlagMapItem {
122     virDomainMigrateFlags flag;
123     qemuMigrationCapability cap;
124     int party; /* bit-wise OR of qemuMigrationParty */
125 };
126 
127 typedef struct _qemuMigrationParamsTPMapItem qemuMigrationParamsTPMapItem;
128 struct _qemuMigrationParamsTPMapItem {
129     const char *typedParam;
130     unsigned int unit;
131     qemuMigrationParam param;
132     int party; /* bit-wise OR of qemuMigrationParty */
133 };
134 
135 /* Migration capabilities which should always be enabled as long as they
136  * are supported by QEMU. If the capability is supposed to be enabled on both
137  * sides of migration, it won't be enabled unless both sides support it.
138  */
139 static const qemuMigrationParamsAlwaysOnItem qemuMigrationParamsAlwaysOn[] = {
140     {QEMU_MIGRATION_CAP_PAUSE_BEFORE_SWITCHOVER,
141      QEMU_MIGRATION_SOURCE},
142 
143     {QEMU_MIGRATION_CAP_LATE_BLOCK_ACTIVATE,
144      QEMU_MIGRATION_DESTINATION},
145 };
146 
147 /* Translation from virDomainMigrateFlags to qemuMigrationCapability. */
148 static const qemuMigrationParamsFlagMapItem qemuMigrationParamsFlagMap[] = {
149     {VIR_MIGRATE_RDMA_PIN_ALL,
150      QEMU_MIGRATION_CAP_RDMA_PIN_ALL,
151      QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION},
152 
153     {VIR_MIGRATE_AUTO_CONVERGE,
154      QEMU_MIGRATION_CAP_AUTO_CONVERGE,
155      QEMU_MIGRATION_SOURCE},
156 
157     {VIR_MIGRATE_POSTCOPY,
158      QEMU_MIGRATION_CAP_POSTCOPY,
159      QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION},
160 
161     {VIR_MIGRATE_PARALLEL,
162      QEMU_MIGRATION_CAP_MULTIFD,
163      QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION},
164 };
165 
166 /* Translation from VIR_MIGRATE_PARAM_* typed parameters to
167  * qemuMigrationParams. */
168 static const qemuMigrationParamsTPMapItem qemuMigrationParamsTPMap[] = {
169     {.typedParam = VIR_MIGRATE_PARAM_AUTO_CONVERGE_INITIAL,
170      .param = QEMU_MIGRATION_PARAM_THROTTLE_INITIAL,
171      .party = QEMU_MIGRATION_SOURCE},
172 
173     {.typedParam = VIR_MIGRATE_PARAM_AUTO_CONVERGE_INCREMENT,
174      .param = QEMU_MIGRATION_PARAM_THROTTLE_INCREMENT,
175      .party = QEMU_MIGRATION_SOURCE},
176 
177     {.typedParam = VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL,
178      .param = QEMU_MIGRATION_PARAM_COMPRESS_LEVEL,
179      .party = QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION},
180 
181     {.typedParam = VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS,
182      .param = QEMU_MIGRATION_PARAM_COMPRESS_THREADS,
183      .party = QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION},
184 
185     {.typedParam = VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS,
186      .param = QEMU_MIGRATION_PARAM_DECOMPRESS_THREADS,
187      .party = QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION},
188 
189     {.typedParam = VIR_MIGRATE_PARAM_COMPRESSION_XBZRLE_CACHE,
190      .param = QEMU_MIGRATION_PARAM_XBZRLE_CACHE_SIZE,
191      .party = QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION},
192 
193     {.typedParam = VIR_MIGRATE_PARAM_BANDWIDTH_POSTCOPY,
194      .unit = 1024 * 1024, /* MiB/s */
195      .param = QEMU_MIGRATION_PARAM_MAX_POSTCOPY_BANDWIDTH,
196      .party = QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION},
197 
198     {.typedParam = VIR_MIGRATE_PARAM_PARALLEL_CONNECTIONS,
199      .param = QEMU_MIGRATION_PARAM_MULTIFD_CHANNELS,
200      .party = QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION},
201 
202     {.typedParam = VIR_MIGRATE_PARAM_TLS_DESTINATION,
203      .param = QEMU_MIGRATION_PARAM_TLS_HOSTNAME,
204      .party = QEMU_MIGRATION_SOURCE},
205 };
206 
207 static const qemuMigrationParamType qemuMigrationParamTypes[] = {
208     [QEMU_MIGRATION_PARAM_COMPRESS_LEVEL] = QEMU_MIGRATION_PARAM_TYPE_INT,
209     [QEMU_MIGRATION_PARAM_COMPRESS_THREADS] = QEMU_MIGRATION_PARAM_TYPE_INT,
210     [QEMU_MIGRATION_PARAM_DECOMPRESS_THREADS] = QEMU_MIGRATION_PARAM_TYPE_INT,
211     [QEMU_MIGRATION_PARAM_THROTTLE_INITIAL] = QEMU_MIGRATION_PARAM_TYPE_INT,
212     [QEMU_MIGRATION_PARAM_THROTTLE_INCREMENT] = QEMU_MIGRATION_PARAM_TYPE_INT,
213     [QEMU_MIGRATION_PARAM_TLS_CREDS] = QEMU_MIGRATION_PARAM_TYPE_STRING,
214     [QEMU_MIGRATION_PARAM_TLS_HOSTNAME] = QEMU_MIGRATION_PARAM_TYPE_STRING,
215     [QEMU_MIGRATION_PARAM_MAX_BANDWIDTH] = QEMU_MIGRATION_PARAM_TYPE_ULL,
216     [QEMU_MIGRATION_PARAM_DOWNTIME_LIMIT] = QEMU_MIGRATION_PARAM_TYPE_ULL,
217     [QEMU_MIGRATION_PARAM_BLOCK_INCREMENTAL] = QEMU_MIGRATION_PARAM_TYPE_BOOL,
218     [QEMU_MIGRATION_PARAM_XBZRLE_CACHE_SIZE] = QEMU_MIGRATION_PARAM_TYPE_ULL,
219     [QEMU_MIGRATION_PARAM_MAX_POSTCOPY_BANDWIDTH] = QEMU_MIGRATION_PARAM_TYPE_ULL,
220     [QEMU_MIGRATION_PARAM_MULTIFD_CHANNELS] = QEMU_MIGRATION_PARAM_TYPE_INT,
221 };
222 G_STATIC_ASSERT(G_N_ELEMENTS(qemuMigrationParamTypes) == QEMU_MIGRATION_PARAM_LAST);
223 
224 
225 virBitmap *
qemuMigrationParamsGetAlwaysOnCaps(qemuMigrationParty party)226 qemuMigrationParamsGetAlwaysOnCaps(qemuMigrationParty party)
227 {
228     virBitmap *caps = virBitmapNew(QEMU_MIGRATION_CAP_LAST);
229     size_t i;
230 
231     for (i = 0; i < G_N_ELEMENTS(qemuMigrationParamsAlwaysOn); i++) {
232         if (!(qemuMigrationParamsAlwaysOn[i].party & party))
233             continue;
234 
235         ignore_value(virBitmapSetBit(caps, qemuMigrationParamsAlwaysOn[i].cap));
236     }
237 
238     return caps;
239 }
240 
241 
242 qemuMigrationParams *
qemuMigrationParamsNew(void)243 qemuMigrationParamsNew(void)
244 {
245     g_autoptr(qemuMigrationParams) params = NULL;
246 
247     params = g_new0(qemuMigrationParams, 1);
248 
249     params->caps = virBitmapNew(QEMU_MIGRATION_CAP_LAST);
250 
251     return g_steal_pointer(&params);
252 }
253 
254 
255 void
qemuMigrationParamsFree(qemuMigrationParams * migParams)256 qemuMigrationParamsFree(qemuMigrationParams *migParams)
257 {
258     size_t i;
259 
260     if (!migParams)
261         return;
262 
263     for (i = 0; i < QEMU_MIGRATION_PARAM_LAST; i++) {
264         if (qemuMigrationParamTypes[i] == QEMU_MIGRATION_PARAM_TYPE_STRING)
265             g_free(migParams->params[i].value.s);
266     }
267 
268     virBitmapFree(migParams->caps);
269     virJSONValueFree(migParams->blockDirtyBitmapMapping);
270     g_free(migParams);
271 }
272 
273 
274 static int
qemuMigrationParamsCheckType(qemuMigrationParam param,qemuMigrationParamType type)275 qemuMigrationParamsCheckType(qemuMigrationParam param,
276                              qemuMigrationParamType type)
277 {
278     if (qemuMigrationParamTypes[param] != type) {
279         virReportError(VIR_ERR_INTERNAL_ERROR,
280                        _("Type mismatch for '%s' migration parameter"),
281                        qemuMigrationParamTypeToString(param));
282         return -1;
283     }
284 
285     return 0;
286 }
287 
288 
289 static int
qemuMigrationParamsGetTPInt(qemuMigrationParams * migParams,qemuMigrationParam param,virTypedParameterPtr params,int nparams,const char * name,unsigned int unit)290 qemuMigrationParamsGetTPInt(qemuMigrationParams *migParams,
291                             qemuMigrationParam param,
292                             virTypedParameterPtr params,
293                             int nparams,
294                             const char *name,
295                             unsigned int unit)
296 {
297     int rc;
298 
299     if (qemuMigrationParamsCheckType(param, QEMU_MIGRATION_PARAM_TYPE_INT) < 0)
300         return -1;
301 
302     if (!params)
303         return 0;
304 
305     if ((rc = virTypedParamsGetInt(params, nparams, name,
306                                    &migParams->params[param].value.i)) < 0)
307         return -1;
308 
309     if (unit > 0) {
310         unsigned int max = UINT_MAX / unit;
311         if (migParams->params[param].value.i > max) {
312             virReportError(VIR_ERR_OVERFLOW,
313                            _("migration parameter '%s' must be less than %u"),
314                            name, max + 1);
315             return -1;
316         }
317         migParams->params[param].value.i *= unit;
318     }
319 
320     migParams->params[param].set = !!rc;
321     return 0;
322 }
323 
324 
325 static int
qemuMigrationParamsSetTPInt(qemuMigrationParams * migParams,qemuMigrationParam param,virTypedParameterPtr * params,int * nparams,int * maxparams,const char * name,unsigned int unit)326 qemuMigrationParamsSetTPInt(qemuMigrationParams *migParams,
327                             qemuMigrationParam param,
328                             virTypedParameterPtr *params,
329                             int *nparams,
330                             int *maxparams,
331                             const char *name,
332                             unsigned int unit)
333 {
334     int value;
335 
336     if (qemuMigrationParamsCheckType(param, QEMU_MIGRATION_PARAM_TYPE_INT) < 0)
337         return -1;
338 
339     if (!migParams->params[param].set)
340         return 0;
341 
342     value = migParams->params[param].value.i;
343     if (unit > 0)
344         value /= unit;
345 
346     return virTypedParamsAddInt(params, nparams, maxparams, name, value);
347 }
348 
349 
350 static int
qemuMigrationParamsGetTPULL(qemuMigrationParams * migParams,qemuMigrationParam param,virTypedParameterPtr params,int nparams,const char * name,unsigned int unit)351 qemuMigrationParamsGetTPULL(qemuMigrationParams *migParams,
352                             qemuMigrationParam param,
353                             virTypedParameterPtr params,
354                             int nparams,
355                             const char *name,
356                             unsigned int unit)
357 {
358     int rc;
359 
360     if (qemuMigrationParamsCheckType(param, QEMU_MIGRATION_PARAM_TYPE_ULL) < 0)
361         return -1;
362 
363     if (!params)
364         return 0;
365 
366     if ((rc = virTypedParamsGetULLong(params, nparams, name,
367                                       &migParams->params[param].value.ull)) < 0)
368         return -1;
369 
370     if (unit > 0) {
371         unsigned long long max = ULLONG_MAX / unit;
372         if (migParams->params[param].value.ull > max) {
373             virReportError(VIR_ERR_OVERFLOW,
374                            _("migration parameter '%s' must be less than %llu"),
375                            name, max + 1);
376             return -1;
377         }
378         migParams->params[param].value.ull *= unit;
379     }
380 
381     migParams->params[param].set = !!rc;
382     return 0;
383 }
384 
385 
386 static int
qemuMigrationParamsSetTPULL(qemuMigrationParams * migParams,qemuMigrationParam param,virTypedParameterPtr * params,int * nparams,int * maxparams,const char * name,unsigned int unit)387 qemuMigrationParamsSetTPULL(qemuMigrationParams *migParams,
388                             qemuMigrationParam param,
389                             virTypedParameterPtr *params,
390                             int *nparams,
391                             int *maxparams,
392                             const char *name,
393                             unsigned int unit)
394 {
395     unsigned long long value;
396 
397     if (qemuMigrationParamsCheckType(param, QEMU_MIGRATION_PARAM_TYPE_ULL) < 0)
398         return -1;
399 
400     if (!migParams->params[param].set)
401         return 0;
402 
403     value = migParams->params[param].value.ull;
404     if (unit > 0)
405         value /= unit;
406 
407     return virTypedParamsAddULLong(params, nparams, maxparams, name, value);
408 }
409 
410 
411 static int
qemuMigrationParamsGetTPString(qemuMigrationParams * migParams,qemuMigrationParam param,virTypedParameterPtr params,int nparams,const char * name)412 qemuMigrationParamsGetTPString(qemuMigrationParams *migParams,
413                                qemuMigrationParam param,
414                                virTypedParameterPtr params,
415                                int nparams,
416                                const char *name)
417 {
418     const char *value = NULL;
419     int rc;
420 
421     if (qemuMigrationParamsCheckType(param, QEMU_MIGRATION_PARAM_TYPE_STRING) < 0)
422         return -1;
423 
424     if (!params)
425         return 0;
426 
427     if ((rc = virTypedParamsGetString(params, nparams, name, &value)) < 0)
428         return -1;
429 
430     migParams->params[param].value.s = g_strdup(value);
431     migParams->params[param].set = !!rc;
432     return 0;
433 }
434 
435 
436 static int
qemuMigrationParamsSetTPString(qemuMigrationParams * migParams,qemuMigrationParam param,virTypedParameterPtr * params,int * nparams,int * maxparams,const char * name)437 qemuMigrationParamsSetTPString(qemuMigrationParams *migParams,
438                                qemuMigrationParam param,
439                                virTypedParameterPtr *params,
440                                int *nparams,
441                                int *maxparams,
442                                const char *name)
443 {
444     if (qemuMigrationParamsCheckType(param, QEMU_MIGRATION_PARAM_TYPE_STRING) < 0)
445         return -1;
446 
447     if (!migParams->params[param].set)
448         return 0;
449 
450     return virTypedParamsAddString(params, nparams, maxparams, name,
451                                    migParams->params[param].value.s);
452 }
453 
454 
455 
456 static int
qemuMigrationParamsSetCompression(virTypedParameterPtr params,int nparams,unsigned long flags,qemuMigrationParams * migParams)457 qemuMigrationParamsSetCompression(virTypedParameterPtr params,
458                                   int nparams,
459                                   unsigned long flags,
460                                   qemuMigrationParams *migParams)
461 {
462     size_t i;
463     int method;
464     qemuMigrationCapability cap;
465 
466     for (i = 0; i < nparams; i++) {
467         if (STRNEQ(params[i].field, VIR_MIGRATE_PARAM_COMPRESSION))
468             continue;
469 
470         method = qemuMigrationCompressMethodTypeFromString(params[i].value.s);
471         if (method < 0) {
472             virReportError(VIR_ERR_INVALID_ARG,
473                            _("Unsupported compression method '%s'"),
474                            params[i].value.s);
475             return -1;
476         }
477 
478         if (migParams->compMethods & (1ULL << method)) {
479             virReportError(VIR_ERR_INVALID_ARG,
480                            _("Compression method '%s' is specified twice"),
481                            params[i].value.s);
482             return -1;
483         }
484 
485         migParams->compMethods |= 1ULL << method;
486 
487         switch ((qemuMigrationCompressMethod) method) {
488         case QEMU_MIGRATION_COMPRESS_XBZRLE:
489             cap = QEMU_MIGRATION_CAP_XBZRLE;
490             break;
491 
492         case QEMU_MIGRATION_COMPRESS_MT:
493             cap = QEMU_MIGRATION_CAP_COMPRESS;
494             break;
495 
496         case QEMU_MIGRATION_COMPRESS_LAST:
497         default:
498             continue;
499         }
500         ignore_value(virBitmapSetBit(migParams->caps, cap));
501     }
502 
503     if ((migParams->params[QEMU_MIGRATION_PARAM_COMPRESS_LEVEL].set ||
504          migParams->params[QEMU_MIGRATION_PARAM_COMPRESS_THREADS].set ||
505          migParams->params[QEMU_MIGRATION_PARAM_DECOMPRESS_THREADS].set) &&
506         !(migParams->compMethods & (1ULL << QEMU_MIGRATION_COMPRESS_MT))) {
507         virReportError(VIR_ERR_INVALID_ARG, "%s",
508                        _("Turn multithread compression on to tune it"));
509         return -1;
510     }
511 
512     if (migParams->params[QEMU_MIGRATION_PARAM_XBZRLE_CACHE_SIZE].set &&
513         !(migParams->compMethods & (1ULL << QEMU_MIGRATION_COMPRESS_XBZRLE))) {
514         virReportError(VIR_ERR_INVALID_ARG, "%s",
515                        _("Turn xbzrle compression on to tune it"));
516         return -1;
517     }
518 
519     if (!migParams->compMethods && (flags & VIR_MIGRATE_COMPRESSED)) {
520         migParams->compMethods = 1ULL << QEMU_MIGRATION_COMPRESS_XBZRLE;
521         ignore_value(virBitmapSetBit(migParams->caps,
522                                      QEMU_MIGRATION_CAP_XBZRLE));
523     }
524 
525     return 0;
526 }
527 
528 
529 void
qemuMigrationParamsSetBlockDirtyBitmapMapping(qemuMigrationParams * migParams,virJSONValue ** params)530 qemuMigrationParamsSetBlockDirtyBitmapMapping(qemuMigrationParams *migParams,
531                                               virJSONValue **params)
532 {
533     virJSONValueFree(migParams->blockDirtyBitmapMapping);
534     migParams->blockDirtyBitmapMapping = g_steal_pointer(params);
535 
536     if (migParams->blockDirtyBitmapMapping)
537         ignore_value(virBitmapSetBit(migParams->caps, QEMU_MIGRATION_CAP_BLOCK_DIRTY_BITMAPS));
538     else
539         ignore_value(virBitmapClearBit(migParams->caps, QEMU_MIGRATION_CAP_BLOCK_DIRTY_BITMAPS));
540 }
541 
542 
543 qemuMigrationParams *
qemuMigrationParamsFromFlags(virTypedParameterPtr params,int nparams,unsigned long flags,qemuMigrationParty party)544 qemuMigrationParamsFromFlags(virTypedParameterPtr params,
545                              int nparams,
546                              unsigned long flags,
547                              qemuMigrationParty party)
548 {
549     g_autoptr(qemuMigrationParams) migParams = NULL;
550     size_t i;
551 
552     if (!(migParams = qemuMigrationParamsNew()))
553         return NULL;
554 
555     for (i = 0; i < G_N_ELEMENTS(qemuMigrationParamsFlagMap); i++) {
556         qemuMigrationCapability cap = qemuMigrationParamsFlagMap[i].cap;
557 
558         if (qemuMigrationParamsFlagMap[i].party & party &&
559             flags & qemuMigrationParamsFlagMap[i].flag) {
560             VIR_DEBUG("Enabling migration capability '%s'",
561                       qemuMigrationCapabilityTypeToString(cap));
562             ignore_value(virBitmapSetBit(migParams->caps, cap));
563         }
564     }
565 
566     for (i = 0; i < G_N_ELEMENTS(qemuMigrationParamsTPMap); i++) {
567         const qemuMigrationParamsTPMapItem *item = &qemuMigrationParamsTPMap[i];
568 
569         if (!(item->party & party))
570             continue;
571 
572         VIR_DEBUG("Setting migration parameter '%s' from '%s'",
573                   qemuMigrationParamTypeToString(item->param), item->typedParam);
574 
575         switch (qemuMigrationParamTypes[item->param]) {
576         case QEMU_MIGRATION_PARAM_TYPE_INT:
577             if (qemuMigrationParamsGetTPInt(migParams, item->param, params,
578                                             nparams, item->typedParam,
579                                             item->unit) < 0)
580                 return NULL;
581             break;
582 
583         case QEMU_MIGRATION_PARAM_TYPE_ULL:
584             if (qemuMigrationParamsGetTPULL(migParams, item->param, params,
585                                             nparams, item->typedParam,
586                                             item->unit) < 0)
587                 return NULL;
588             break;
589 
590         case QEMU_MIGRATION_PARAM_TYPE_BOOL:
591             break;
592 
593         case QEMU_MIGRATION_PARAM_TYPE_STRING:
594             if (qemuMigrationParamsGetTPString(migParams, item->param, params,
595                                                nparams, item->typedParam) < 0)
596                 return NULL;
597             break;
598         }
599     }
600 
601     if ((migParams->params[QEMU_MIGRATION_PARAM_THROTTLE_INITIAL].set ||
602          migParams->params[QEMU_MIGRATION_PARAM_THROTTLE_INCREMENT].set) &&
603         !(flags & VIR_MIGRATE_AUTO_CONVERGE)) {
604         virReportError(VIR_ERR_INVALID_ARG, "%s",
605                        _("Turn auto convergence on to tune it"));
606         return NULL;
607     }
608 
609     if (migParams->params[QEMU_MIGRATION_PARAM_MULTIFD_CHANNELS].set &&
610         !(flags & VIR_MIGRATE_PARALLEL)) {
611         virReportError(VIR_ERR_INVALID_ARG, "%s",
612                        _("Turn parallel migration on to tune it"));
613         return NULL;
614     }
615 
616     if (qemuMigrationParamsSetCompression(params, nparams, flags, migParams) < 0)
617         return NULL;
618 
619     return g_steal_pointer(&migParams);
620 }
621 
622 
623 int
qemuMigrationParamsDump(qemuMigrationParams * migParams,virTypedParameterPtr * params,int * nparams,int * maxparams,unsigned long * flags)624 qemuMigrationParamsDump(qemuMigrationParams *migParams,
625                         virTypedParameterPtr *params,
626                         int *nparams,
627                         int *maxparams,
628                         unsigned long *flags)
629 {
630     size_t i;
631 
632     if (migParams->compMethods == 1ULL << QEMU_MIGRATION_COMPRESS_XBZRLE &&
633         !migParams->params[QEMU_MIGRATION_PARAM_XBZRLE_CACHE_SIZE].set) {
634         *flags |= VIR_MIGRATE_COMPRESSED;
635     }
636 
637     for (i = 0; i < QEMU_MIGRATION_COMPRESS_LAST; ++i) {
638         if ((migParams->compMethods & (1ULL << i)) &&
639             virTypedParamsAddString(params, nparams, maxparams,
640                                     VIR_MIGRATE_PARAM_COMPRESSION,
641                                     qemuMigrationCompressMethodTypeToString(i)) < 0)
642             return -1;
643     }
644 
645     for (i = 0; i < G_N_ELEMENTS(qemuMigrationParamsTPMap); i++) {
646         const qemuMigrationParamsTPMapItem *item = &qemuMigrationParamsTPMap[i];
647 
648         if (!(item->party & QEMU_MIGRATION_DESTINATION))
649             continue;
650 
651         switch (qemuMigrationParamTypes[item->param]) {
652         case QEMU_MIGRATION_PARAM_TYPE_INT:
653             if (qemuMigrationParamsSetTPInt(migParams, item->param,
654                                             params, nparams, maxparams,
655                                             item->typedParam, item->unit) < 0)
656                 return -1;
657             break;
658 
659         case QEMU_MIGRATION_PARAM_TYPE_ULL:
660             if (qemuMigrationParamsSetTPULL(migParams, item->param,
661                                             params, nparams, maxparams,
662                                             item->typedParam, item->unit) < 0)
663                 return -1;
664             break;
665 
666         case QEMU_MIGRATION_PARAM_TYPE_BOOL:
667             break;
668 
669         case QEMU_MIGRATION_PARAM_TYPE_STRING:
670             if (qemuMigrationParamsSetTPString(migParams, item->param,
671                                                params, nparams, maxparams,
672                                                item->typedParam) < 0)
673                 return -1;
674             break;
675         }
676     }
677 
678     return 0;
679 }
680 
681 
682 qemuMigrationParams *
qemuMigrationParamsFromJSON(virJSONValue * params)683 qemuMigrationParamsFromJSON(virJSONValue *params)
684 {
685     g_autoptr(qemuMigrationParams) migParams = NULL;
686     qemuMigrationParamValue *pv;
687     const char *name;
688     const char *str;
689     size_t i;
690 
691     if (!(migParams = qemuMigrationParamsNew()))
692         return NULL;
693 
694     if (!params)
695         return g_steal_pointer(&migParams);
696 
697     for (i = 0; i < QEMU_MIGRATION_PARAM_LAST; i++) {
698         name = qemuMigrationParamTypeToString(i);
699         pv = &migParams->params[i];
700 
701         switch (qemuMigrationParamTypes[i]) {
702         case QEMU_MIGRATION_PARAM_TYPE_INT:
703             if (virJSONValueObjectGetNumberInt(params, name, &pv->value.i) == 0)
704                 pv->set = true;
705             break;
706 
707         case QEMU_MIGRATION_PARAM_TYPE_ULL:
708             if (virJSONValueObjectGetNumberUlong(params, name, &pv->value.ull) == 0)
709                 pv->set = true;
710             break;
711 
712         case QEMU_MIGRATION_PARAM_TYPE_BOOL:
713             if (virJSONValueObjectGetBoolean(params, name, &pv->value.b) == 0)
714                 pv->set = true;
715             break;
716 
717         case QEMU_MIGRATION_PARAM_TYPE_STRING:
718             if ((str = virJSONValueObjectGetString(params, name))) {
719                 pv->value.s = g_strdup(str);
720                 pv->set = true;
721             }
722             break;
723         }
724     }
725 
726     return g_steal_pointer(&migParams);
727 }
728 
729 
730 virJSONValue *
qemuMigrationParamsToJSON(qemuMigrationParams * migParams)731 qemuMigrationParamsToJSON(qemuMigrationParams *migParams)
732 {
733     g_autoptr(virJSONValue) params = virJSONValueNewObject();
734     size_t i;
735 
736     for (i = 0; i < QEMU_MIGRATION_PARAM_LAST; i++) {
737         const char *name = qemuMigrationParamTypeToString(i);
738         qemuMigrationParamValue *pv = &migParams->params[i];
739         int rc = 0;
740 
741         if (!pv->set)
742             continue;
743 
744         switch (qemuMigrationParamTypes[i]) {
745         case QEMU_MIGRATION_PARAM_TYPE_INT:
746             rc = virJSONValueObjectAppendNumberInt(params, name, pv->value.i);
747             break;
748 
749         case QEMU_MIGRATION_PARAM_TYPE_ULL:
750             rc = virJSONValueObjectAppendNumberUlong(params, name, pv->value.ull);
751             break;
752 
753         case QEMU_MIGRATION_PARAM_TYPE_BOOL:
754             rc = virJSONValueObjectAppendBoolean(params, name, pv->value.b);
755             break;
756 
757         case QEMU_MIGRATION_PARAM_TYPE_STRING:
758             rc = virJSONValueObjectAppendString(params, name, pv->value.s);
759             break;
760         }
761 
762         if (rc < 0)
763             return NULL;
764     }
765 
766     if (migParams->blockDirtyBitmapMapping) {
767         g_autoptr(virJSONValue) mapping = virJSONValueCopy(migParams->blockDirtyBitmapMapping);
768 
769         if (!mapping)
770             return NULL;
771 
772         if (virJSONValueObjectAppend(params, "block-bitmap-mapping", &mapping) < 0)
773             return NULL;
774     }
775 
776     return g_steal_pointer(&params);
777 }
778 
779 
780 virJSONValue *
qemuMigrationCapsToJSON(virBitmap * caps,virBitmap * states)781 qemuMigrationCapsToJSON(virBitmap *caps,
782                         virBitmap *states)
783 {
784     g_autoptr(virJSONValue) json = virJSONValueNewArray();
785     qemuMigrationCapability bit;
786 
787     for (bit = 0; bit < QEMU_MIGRATION_CAP_LAST; bit++) {
788         g_autoptr(virJSONValue) cap = NULL;
789 
790         if (!virBitmapIsBitSet(caps, bit))
791             continue;
792 
793         if (virJSONValueObjectAdd(&cap,
794                                   "s:capability", qemuMigrationCapabilityTypeToString(bit),
795                                   "b:state", virBitmapIsBitSet(states, bit),
796                                   NULL) < 0)
797             return NULL;
798 
799         if (virJSONValueArrayAppend(json, &cap) < 0)
800             return NULL;
801     }
802 
803     return g_steal_pointer(&json);
804 }
805 
806 
807 /**
808  * qemuMigrationParamsApply
809  * @driver: qemu driver
810  * @vm: domain object
811  * @asyncJob: migration job
812  * @migParams: migration parameters to send to QEMU
813  *
814  * Send all parameters stored in @migParams to QEMU.
815  *
816  * Returns 0 on success, -1 on failure.
817  */
818 int
qemuMigrationParamsApply(virQEMUDriver * driver,virDomainObj * vm,int asyncJob,qemuMigrationParams * migParams)819 qemuMigrationParamsApply(virQEMUDriver *driver,
820                          virDomainObj *vm,
821                          int asyncJob,
822                          qemuMigrationParams *migParams)
823 {
824     qemuDomainObjPrivate *priv = vm->privateData;
825     bool xbzrleCacheSize_old = false;
826     g_autoptr(virJSONValue) params = NULL;
827     g_autoptr(virJSONValue) caps = NULL;
828     qemuMigrationParam xbzrle = QEMU_MIGRATION_PARAM_XBZRLE_CACHE_SIZE;
829     int ret = -1;
830 
831     if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
832         return -1;
833 
834     if (asyncJob == QEMU_ASYNC_JOB_NONE) {
835         if (!virBitmapIsAllClear(migParams->caps)) {
836             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
837                            _("Migration capabilities can only be set by "
838                              "a migration job"));
839             goto cleanup;
840         }
841     } else {
842         if (!(caps = qemuMigrationCapsToJSON(priv->migrationCaps, migParams->caps)))
843             goto cleanup;
844 
845         if (virJSONValueArraySize(caps) > 0 &&
846             qemuMonitorSetMigrationCapabilities(priv->mon, &caps) < 0)
847             goto cleanup;
848     }
849 
850     /* If QEMU is too old to support xbzrle-cache-size migration parameter,
851      * we need to set it via migrate-set-cache-size and tell
852      * qemuMonitorSetMigrationParams to ignore this parameter.
853      */
854     if (migParams->params[xbzrle].set &&
855         !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATION_PARAM_XBZRLE_CACHE_SIZE)) {
856         if (qemuMonitorSetMigrationCacheSize(priv->mon,
857                                              migParams->params[xbzrle].value.ull) < 0)
858             goto cleanup;
859         xbzrleCacheSize_old = true;
860         migParams->params[xbzrle].set = false;
861     }
862 
863     if (!(params = qemuMigrationParamsToJSON(migParams)))
864         goto cleanup;
865 
866     if (virJSONValueObjectKeysNumber(params) > 0 &&
867         qemuMonitorSetMigrationParams(priv->mon, &params) < 0)
868         goto cleanup;
869 
870     ret = 0;
871 
872  cleanup:
873     if (qemuDomainObjExitMonitor(driver, vm) < 0)
874         ret = -1;
875 
876     if (xbzrleCacheSize_old)
877         migParams->params[xbzrle].set = true;
878 
879     return ret;
880 }
881 
882 
883 /**
884  * qemuMigrationParamsSetString:
885  * @migrParams: migration parameter object
886  * @param: parameter to set
887  * @value: new value
888  *
889  * Enables and sets the migration parameter @param in @migrParams. Returns 0 on
890  * success and -1 on error. Libvirt error is reported.
891  */
892 static int
qemuMigrationParamsSetString(qemuMigrationParams * migParams,qemuMigrationParam param,const char * value)893 qemuMigrationParamsSetString(qemuMigrationParams *migParams,
894                              qemuMigrationParam param,
895                              const char *value)
896 {
897     if (qemuMigrationParamsCheckType(param, QEMU_MIGRATION_PARAM_TYPE_STRING) < 0)
898         return -1;
899 
900     migParams->params[param].value.s = g_strdup(value);
901 
902     migParams->params[param].set = true;
903 
904     return 0;
905 }
906 
907 
908 /* qemuMigrationParamsEnableTLS
909  * @driver: pointer to qemu driver
910  * @vm: domain object
911  * @tlsListen: server or client
912  * @asyncJob: Migration job to join
913  * @tlsAlias: alias to be generated for TLS object
914  * @hostname: hostname of the migration destination
915  * @migParams: migration parameters to set
916  *
917  * Create the TLS objects for the migration and set the migParams value.
918  * If QEMU itself does not connect to the destination @hostname must be
919  * provided for certificate verification.
920  *
921  * Returns 0 on success, -1 on failure
922  */
923 int
qemuMigrationParamsEnableTLS(virQEMUDriver * driver,virDomainObj * vm,bool tlsListen,int asyncJob,char ** tlsAlias,const char * hostname,qemuMigrationParams * migParams)924 qemuMigrationParamsEnableTLS(virQEMUDriver *driver,
925                              virDomainObj *vm,
926                              bool tlsListen,
927                              int asyncJob,
928                              char **tlsAlias,
929                              const char *hostname,
930                              qemuMigrationParams *migParams)
931 {
932     qemuDomainObjPrivate *priv = vm->privateData;
933     qemuDomainJobPrivate *jobPriv = priv->job.privateData;
934     g_autoptr(virJSONValue) tlsProps = NULL;
935     g_autoptr(virJSONValue) secProps = NULL;
936     g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
937     const char *secAlias = NULL;
938 
939     if (!cfg->migrateTLSx509certdir) {
940         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
941                        _("host migration TLS directory not configured"));
942         return -1;
943     }
944 
945     if (!jobPriv->migParams->params[QEMU_MIGRATION_PARAM_TLS_CREDS].set) {
946         virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
947                        _("TLS migration is not supported with this "
948                          "QEMU binary"));
949         return -1;
950     }
951 
952     /* If there's a secret, then grab/store it now using the connection */
953     if (cfg->migrateTLSx509secretUUID) {
954         if (!(priv->migSecinfo =
955               qemuDomainSecretInfoTLSNew(priv, QEMU_MIGRATION_TLS_ALIAS_BASE,
956                                          cfg->migrateTLSx509secretUUID)))
957             return -1;
958         secAlias = priv->migSecinfo->alias;
959     }
960 
961     if (!(*tlsAlias = qemuAliasTLSObjFromSrcAlias(QEMU_MIGRATION_TLS_ALIAS_BASE)))
962         return -1;
963 
964     if (qemuDomainGetTLSObjects(priv->migSecinfo,
965                                 cfg->migrateTLSx509certdir, tlsListen,
966                                 cfg->migrateTLSx509verify,
967                                 *tlsAlias, &tlsProps, &secProps) < 0)
968         return -1;
969 
970     /* Ensure the domain doesn't already have the TLS objects defined...
971      * This should prevent any issues just in case some cleanup wasn't
972      * properly completed (both src and dst use the same alias) or
973      * some other error path between now and perform . */
974     qemuDomainDelTLSObjects(driver, vm, asyncJob, secAlias, *tlsAlias);
975 
976     if (qemuDomainAddTLSObjects(driver, vm, asyncJob, &secProps, &tlsProps) < 0)
977         return -1;
978 
979     if (qemuMigrationParamsSetString(migParams,
980                                      QEMU_MIGRATION_PARAM_TLS_CREDS,
981                                      *tlsAlias) < 0)
982         return -1;
983 
984     if (!migParams->params[QEMU_MIGRATION_PARAM_TLS_HOSTNAME].set &&
985         qemuMigrationParamsSetString(migParams,
986                                      QEMU_MIGRATION_PARAM_TLS_HOSTNAME,
987                                      NULLSTR_EMPTY(hostname)) < 0)
988         return -1;
989 
990     return 0;
991 }
992 
993 
994 /* qemuMigrationParamsDisableTLS
995  * @vm: domain object
996  * @migParams: Pointer to a migration parameters block
997  *
998  * If we support setting the tls-creds, then set both tls-creds and
999  * tls-hostname to the empty string ("") which indicates to not use
1000  * TLS on this migration.
1001  *
1002  * Returns 0 on success, -1 on failure
1003  */
1004 int
qemuMigrationParamsDisableTLS(virDomainObj * vm,qemuMigrationParams * migParams)1005 qemuMigrationParamsDisableTLS(virDomainObj *vm,
1006                               qemuMigrationParams *migParams)
1007 {
1008     qemuDomainObjPrivate *priv = vm->privateData;
1009     qemuDomainJobPrivate *jobPriv = priv->job.privateData;
1010 
1011     if (!jobPriv->migParams->params[QEMU_MIGRATION_PARAM_TLS_CREDS].set)
1012         return 0;
1013 
1014     if (qemuMigrationParamsSetString(migParams,
1015                                      QEMU_MIGRATION_PARAM_TLS_CREDS, "") < 0 ||
1016         qemuMigrationParamsSetString(migParams,
1017                                      QEMU_MIGRATION_PARAM_TLS_HOSTNAME, "") < 0)
1018         return -1;
1019 
1020     return 0;
1021 }
1022 
1023 
1024 bool
qemuMigrationParamsTLSHostnameIsSet(qemuMigrationParams * migParams)1025 qemuMigrationParamsTLSHostnameIsSet(qemuMigrationParams *migParams)
1026 {
1027     int param = QEMU_MIGRATION_PARAM_TLS_HOSTNAME;
1028     return (migParams->params[param].set &&
1029             STRNEQ(migParams->params[param].value.s, ""));
1030 }
1031 
1032 
1033 /* qemuMigrationParamsResetTLS
1034  * @driver: pointer to qemu driver
1035  * @vm: domain object
1036  * @asyncJob: migration job to join
1037  * @apiFlags: API flags used to start the migration
1038  *
1039  * Deconstruct all the setup possibly done for TLS - delete the TLS and
1040  * security objects and free the secinfo
1041  */
1042 static void
qemuMigrationParamsResetTLS(virQEMUDriver * driver,virDomainObj * vm,int asyncJob,qemuMigrationParams * origParams,unsigned long apiFlags)1043 qemuMigrationParamsResetTLS(virQEMUDriver *driver,
1044                             virDomainObj *vm,
1045                             int asyncJob,
1046                             qemuMigrationParams *origParams,
1047                             unsigned long apiFlags)
1048 {
1049     g_autofree char *tlsAlias = NULL;
1050     g_autofree char *secAlias = NULL;
1051 
1052     /* There's nothing to do if QEMU does not support TLS migration or we were
1053      * not asked to enable it. */
1054     if (!origParams->params[QEMU_MIGRATION_PARAM_TLS_CREDS].set ||
1055         !(apiFlags & VIR_MIGRATE_TLS))
1056         return;
1057 
1058     tlsAlias = qemuAliasTLSObjFromSrcAlias(QEMU_MIGRATION_TLS_ALIAS_BASE);
1059     secAlias = qemuAliasForSecret(QEMU_MIGRATION_TLS_ALIAS_BASE, NULL);
1060 
1061     qemuDomainDelTLSObjects(driver, vm, asyncJob, secAlias, tlsAlias);
1062     g_clear_pointer(&QEMU_DOMAIN_PRIVATE(vm)->migSecinfo, qemuDomainSecretInfoFree);
1063 }
1064 
1065 
1066 int
qemuMigrationParamsFetch(virQEMUDriver * driver,virDomainObj * vm,int asyncJob,qemuMigrationParams ** migParams)1067 qemuMigrationParamsFetch(virQEMUDriver *driver,
1068                          virDomainObj *vm,
1069                          int asyncJob,
1070                          qemuMigrationParams **migParams)
1071 {
1072     qemuDomainObjPrivate *priv = vm->privateData;
1073     g_autoptr(virJSONValue) jsonParams = NULL;
1074     int rc;
1075 
1076     *migParams = NULL;
1077 
1078     if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
1079         return -1;
1080 
1081     rc = qemuMonitorGetMigrationParams(priv->mon, &jsonParams);
1082 
1083     if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
1084         return -1;
1085 
1086     if (!(*migParams = qemuMigrationParamsFromJSON(jsonParams)))
1087         return -1;
1088 
1089     return 0;
1090 }
1091 
1092 
1093 int
qemuMigrationParamsSetULL(qemuMigrationParams * migParams,qemuMigrationParam param,unsigned long long value)1094 qemuMigrationParamsSetULL(qemuMigrationParams *migParams,
1095                           qemuMigrationParam param,
1096                           unsigned long long value)
1097 {
1098     if (qemuMigrationParamsCheckType(param, QEMU_MIGRATION_PARAM_TYPE_ULL) < 0)
1099         return -1;
1100 
1101     migParams->params[param].value.ull = value;
1102     migParams->params[param].set = true;
1103     return 0;
1104 }
1105 
1106 
1107 /**
1108  * Returns -1 on error,
1109  *          0 on success,
1110  *          1 if the parameter is not supported by QEMU.
1111  */
1112 int
qemuMigrationParamsGetULL(qemuMigrationParams * migParams,qemuMigrationParam param,unsigned long long * value)1113 qemuMigrationParamsGetULL(qemuMigrationParams *migParams,
1114                           qemuMigrationParam param,
1115                           unsigned long long *value)
1116 {
1117     if (qemuMigrationParamsCheckType(param, QEMU_MIGRATION_PARAM_TYPE_ULL) < 0)
1118         return -1;
1119 
1120     if (!migParams->params[param].set)
1121         return 1;
1122 
1123     *value = migParams->params[param].value.ull;
1124     return 0;
1125 }
1126 
1127 
1128 /**
1129  * qemuMigrationParamsCheck:
1130  *
1131  * Check supported migration parameters and keep their original values in
1132  * qemuDomainJobObj so that we can properly reset them at the end of migration.
1133  * Reports an error if any of the currently used capabilities in @migParams
1134  * are unsupported by QEMU.
1135  */
1136 int
qemuMigrationParamsCheck(virQEMUDriver * driver,virDomainObj * vm,int asyncJob,qemuMigrationParams * migParams,virBitmap * remoteCaps)1137 qemuMigrationParamsCheck(virQEMUDriver *driver,
1138                          virDomainObj *vm,
1139                          int asyncJob,
1140                          qemuMigrationParams *migParams,
1141                          virBitmap *remoteCaps)
1142 {
1143     qemuDomainObjPrivate *priv = vm->privateData;
1144     qemuDomainJobPrivate *jobPriv = priv->job.privateData;
1145     qemuMigrationCapability cap;
1146     qemuMigrationParty party;
1147     size_t i;
1148 
1149     if (asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT)
1150         party = QEMU_MIGRATION_SOURCE;
1151     else
1152         party = QEMU_MIGRATION_DESTINATION;
1153 
1154     for (cap = 0; cap < QEMU_MIGRATION_CAP_LAST; cap++) {
1155         bool state = false;
1156 
1157         ignore_value(virBitmapGetBit(migParams->caps, cap, &state));
1158 
1159         if (state && !qemuMigrationCapsGet(vm, cap)) {
1160             virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
1161                            _("Migration option '%s' is not supported by QEMU binary"),
1162                            qemuMigrationCapabilityTypeToString(cap));
1163             return -1;
1164         }
1165     }
1166 
1167     for (i = 0; i < G_N_ELEMENTS(qemuMigrationParamsAlwaysOn); i++) {
1168         cap = qemuMigrationParamsAlwaysOn[i].cap;
1169 
1170         if (qemuMigrationParamsAlwaysOn[i].party & party &&
1171             qemuMigrationCapsGet(vm, cap)) {
1172             if (qemuMigrationParamsAlwaysOn[i].party != party) {
1173                 bool remote = false;
1174 
1175                 if (remoteCaps)
1176                     ignore_value(virBitmapGetBit(remoteCaps, cap, &remote));
1177 
1178                 if (!remote) {
1179                     VIR_DEBUG("Not enabling migration capability '%s'; it is "
1180                               "not supported or automatically enabled by the "
1181                               "other side of migration",
1182                               qemuMigrationCapabilityTypeToString(cap));
1183                     continue;
1184                 }
1185             }
1186 
1187             VIR_DEBUG("Enabling migration capability '%s'",
1188                       qemuMigrationCapabilityTypeToString(cap));
1189             ignore_value(virBitmapSetBit(migParams->caps, cap));
1190         }
1191     }
1192 
1193     /*
1194      * We want to disable all migration capabilities after migration, no need
1195      * to ask QEMU for their current settings.
1196      */
1197 
1198     return qemuMigrationParamsFetch(driver, vm, asyncJob, &jobPriv->migParams);
1199 }
1200 
1201 
1202 /*
1203  * qemuMigrationParamsReset:
1204  *
1205  * Reset all migration parameters so that the next job which internally uses
1206  * migration (save, managedsave, snapshots, dump) will not try to use them.
1207  */
1208 void
qemuMigrationParamsReset(virQEMUDriver * driver,virDomainObj * vm,int asyncJob,qemuMigrationParams * origParams,unsigned long apiFlags)1209 qemuMigrationParamsReset(virQEMUDriver *driver,
1210                          virDomainObj *vm,
1211                          int asyncJob,
1212                          qemuMigrationParams *origParams,
1213                          unsigned long apiFlags)
1214 {
1215     virErrorPtr err;
1216 
1217     virErrorPreserveLast(&err);
1218 
1219     VIR_DEBUG("Resetting migration parameters %p, flags 0x%lx",
1220               origParams, apiFlags);
1221 
1222     if (!virDomainObjIsActive(vm) || !origParams)
1223         goto cleanup;
1224 
1225     if (qemuMigrationParamsApply(driver, vm, asyncJob, origParams) < 0)
1226         goto cleanup;
1227 
1228     qemuMigrationParamsResetTLS(driver, vm, asyncJob, origParams, apiFlags);
1229     /* We don't reset 'block-bitmap-mapping' as it can't be unset */
1230 
1231  cleanup:
1232     virErrorRestore(&err);
1233 }
1234 
1235 
1236 void
qemuMigrationParamsFormat(virBuffer * buf,qemuMigrationParams * migParams)1237 qemuMigrationParamsFormat(virBuffer *buf,
1238                           qemuMigrationParams *migParams)
1239 {
1240     qemuMigrationParamValue *pv;
1241     size_t i;
1242 
1243     virBufferAddLit(buf, "<migParams>\n");
1244     virBufferAdjustIndent(buf, 2);
1245 
1246     for (i = 0; i < QEMU_MIGRATION_PARAM_LAST; i++) {
1247         pv = &migParams->params[i];
1248 
1249         if (!pv->set)
1250             continue;
1251 
1252         virBufferAsprintf(buf, "<param name='%s' ",
1253                           qemuMigrationParamTypeToString(i));
1254 
1255         switch (qemuMigrationParamTypes[i]) {
1256         case QEMU_MIGRATION_PARAM_TYPE_INT:
1257             virBufferAsprintf(buf, "value='%d'", pv->value.i);
1258             break;
1259 
1260         case QEMU_MIGRATION_PARAM_TYPE_ULL:
1261             virBufferAsprintf(buf, "value='%llu'", pv->value.ull);
1262             break;
1263 
1264         case QEMU_MIGRATION_PARAM_TYPE_BOOL:
1265             virBufferAsprintf(buf, "value='%s'", pv->value.b ? "yes" : "no");
1266             break;
1267 
1268         case QEMU_MIGRATION_PARAM_TYPE_STRING:
1269             virBufferEscapeString(buf, "value='%s'", pv->value.s);
1270             break;
1271         }
1272 
1273         virBufferAddLit(buf, "/>\n");
1274     }
1275 
1276     virBufferAdjustIndent(buf, -2);
1277     virBufferAddLit(buf, "</migParams>\n");
1278 }
1279 
1280 
1281 int
qemuMigrationParamsParse(xmlXPathContextPtr ctxt,qemuMigrationParams ** migParams)1282 qemuMigrationParamsParse(xmlXPathContextPtr ctxt,
1283                          qemuMigrationParams **migParams)
1284 {
1285     g_autoptr(qemuMigrationParams) params = NULL;
1286     qemuMigrationParamValue *pv;
1287     g_autofree xmlNodePtr *nodes = NULL;
1288     size_t i;
1289     int rc;
1290     int n;
1291 
1292     *migParams = NULL;
1293 
1294     if ((rc = virXPathBoolean("boolean(./migParams)", ctxt)) < 0)
1295         return -1;
1296 
1297     if (rc == 0)
1298         return 0;
1299 
1300     if ((n = virXPathNodeSet("./migParams[1]/param", ctxt, &nodes)) < 0)
1301         return -1;
1302 
1303     if (!(params = qemuMigrationParamsNew()))
1304         return -1;
1305 
1306     for (i = 0; i < n; i++) {
1307         g_autofree char *name = NULL;
1308         g_autofree char *value = NULL;
1309         int param;
1310 
1311         if (!(name = virXMLPropString(nodes[i], "name"))) {
1312             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1313                            _("missing migration parameter name"));
1314             return -1;
1315         }
1316 
1317         if ((param = qemuMigrationParamTypeFromString(name)) < 0) {
1318             virReportError(VIR_ERR_INTERNAL_ERROR,
1319                            _("unknown migration parameter '%s'"), name);
1320             return -1;
1321         }
1322         pv = &params->params[param];
1323 
1324         if (!(value = virXMLPropString(nodes[i], "value"))) {
1325             virReportError(VIR_ERR_INTERNAL_ERROR,
1326                            _("missing value for migration parameter '%s'"),
1327                            name);
1328             return -1;
1329         }
1330 
1331         rc = 0;
1332         switch (qemuMigrationParamTypes[param]) {
1333         case QEMU_MIGRATION_PARAM_TYPE_INT:
1334             rc = virStrToLong_i(value, NULL, 10, &pv->value.i);
1335             break;
1336 
1337         case QEMU_MIGRATION_PARAM_TYPE_ULL:
1338             rc = virStrToLong_ullp(value, NULL, 10, &pv->value.ull);
1339             break;
1340 
1341         case QEMU_MIGRATION_PARAM_TYPE_BOOL:
1342             rc = virStringParseYesNo(value, &pv->value.b);
1343             break;
1344 
1345         case QEMU_MIGRATION_PARAM_TYPE_STRING:
1346             pv->value.s = g_steal_pointer(&value);
1347             break;
1348         }
1349 
1350         if (rc < 0) {
1351             virReportError(VIR_ERR_INTERNAL_ERROR,
1352                            _("invalid value '%s' for migration parameter '%s'"),
1353                            value, name);
1354             return -1;
1355         }
1356 
1357         pv->set = true;
1358     }
1359 
1360     *migParams = g_steal_pointer(&params);
1361 
1362     return 0;
1363 }
1364 
1365 
1366 int
qemuMigrationCapsCheck(virQEMUDriver * driver,virDomainObj * vm,int asyncJob)1367 qemuMigrationCapsCheck(virQEMUDriver *driver,
1368                        virDomainObj *vm,
1369                        int asyncJob)
1370 {
1371     qemuDomainObjPrivate *priv = vm->privateData;
1372     g_autoptr(virBitmap) migEvent = NULL;
1373     g_autoptr(virJSONValue) json = NULL;
1374     g_auto(GStrv) caps = NULL;
1375     char **capStr;
1376     int rc;
1377 
1378     if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
1379         return -1;
1380 
1381     rc = qemuMonitorGetMigrationCapabilities(priv->mon, &caps);
1382 
1383     if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
1384         return -1;
1385 
1386     if (!caps)
1387         return 0;
1388 
1389     priv->migrationCaps = virBitmapNew(QEMU_MIGRATION_CAP_LAST);
1390 
1391     for (capStr = caps; *capStr; capStr++) {
1392         int cap = qemuMigrationCapabilityTypeFromString(*capStr);
1393 
1394         if (cap < 0) {
1395             VIR_DEBUG("Unknown migration capability: '%s'", *capStr);
1396         } else {
1397             ignore_value(virBitmapSetBit(priv->migrationCaps, cap));
1398             VIR_DEBUG("Found migration capability: '%s'", *capStr);
1399         }
1400     }
1401 
1402     if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATION_EVENT)) {
1403         migEvent = virBitmapNew(QEMU_MIGRATION_CAP_LAST);
1404 
1405         ignore_value(virBitmapSetBit(migEvent, QEMU_MIGRATION_CAP_EVENTS));
1406 
1407         if (!(json = qemuMigrationCapsToJSON(migEvent, migEvent)))
1408             return -1;
1409 
1410         if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
1411             return -1;
1412 
1413         rc = qemuMonitorSetMigrationCapabilities(priv->mon, &json);
1414 
1415         if (qemuDomainObjExitMonitor(driver, vm) < 0)
1416             return -1;
1417 
1418         if (rc < 0) {
1419             virResetLastError();
1420             VIR_DEBUG("Cannot enable migration events; clearing capability");
1421             virQEMUCapsClear(priv->qemuCaps, QEMU_CAPS_MIGRATION_EVENT);
1422         }
1423     }
1424 
1425     /* Migration events capability must always be enabled, clearing it from
1426      * migration capabilities bitmap makes sure it won't be touched anywhere
1427      * else.
1428      */
1429     ignore_value(virBitmapClearBit(priv->migrationCaps,
1430                                    QEMU_MIGRATION_CAP_EVENTS));
1431 
1432     return 0;
1433 }
1434 
1435 
1436 bool
qemuMigrationCapsGet(virDomainObj * vm,qemuMigrationCapability cap)1437 qemuMigrationCapsGet(virDomainObj *vm,
1438                      qemuMigrationCapability cap)
1439 {
1440     qemuDomainObjPrivate *priv = vm->privateData;
1441     bool enabled = false;
1442 
1443     if (priv->migrationCaps)
1444         ignore_value(virBitmapGetBit(priv->migrationCaps, cap, &enabled));
1445 
1446     return enabled;
1447 }
1448