mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-27 11:01:19 +00:00
Introduce migration cookies to QEMU driver
The migration protocol has support for a 'cookie' parameter which is an opaque array of bytes as far as libvirt is concerned. Drivers may use this for passing around arbitrary extra data they might need during migration. The QEMU driver needs to do a few things: - Pass hostname/uuid to allow strict protection against localhost migration attempts - Pass SPICE/VNC server port from the target back to the source to allow seamless relocation of client sessions - Pass lock driver state from source to destination This patch introduces the basic glue for handling cookies but only includes the host/guest UUID & name. * src/libvirt_private.syms: Export virXMLParseStrHelper * src/qemu/qemu_migration.c, src/qemu/qemu_migration.h: Parsing and formatting of migration cookies * src/qemu/qemu_driver.c: Pass in cookie parameters where possible * src/remote/remote_protocol.h, src/remote/remote_protocol.x: Change cookie max length to 16384 bytes
This commit is contained in:
parent
9ab245585b
commit
8654175c5b
1
cfg.mk
1
cfg.mk
@ -80,6 +80,7 @@ VC_LIST_ALWAYS_EXCLUDE_REGEX = ^(HACKING|docs/news\.html\.in)$$
|
|||||||
useless_free_options = \
|
useless_free_options = \
|
||||||
--name=VIR_FREE \
|
--name=VIR_FREE \
|
||||||
--name=qemuCapsFree \
|
--name=qemuCapsFree \
|
||||||
|
--name=qemuMigrationCookieFree \
|
||||||
--name=sexpr_free \
|
--name=sexpr_free \
|
||||||
--name=virBitmapFree \
|
--name=virBitmapFree \
|
||||||
--name=virCPUDefFree \
|
--name=virCPUDefFree \
|
||||||
|
@ -1016,6 +1016,7 @@ virStrerror;
|
|||||||
|
|
||||||
|
|
||||||
# xml.h
|
# xml.h
|
||||||
|
virXMLParseStrHelper;
|
||||||
virXMLPropString;
|
virXMLPropString;
|
||||||
virXPathBoolean;
|
virXPathBoolean;
|
||||||
virXPathInt;
|
virXPathInt;
|
||||||
|
@ -5785,8 +5785,9 @@ qemudDomainMigratePrepareTunnel(virConnectPtr dconn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
qemuDriverLock(driver);
|
qemuDriverLock(driver);
|
||||||
ret = qemuMigrationPrepareTunnel(driver, dconn, st,
|
ret = qemuMigrationPrepareTunnel(driver, dconn,
|
||||||
dname, dom_xml);
|
NULL, 0, NULL, NULL, /* No cookies in v2 */
|
||||||
|
st, dname, dom_xml);
|
||||||
qemuDriverUnlock(driver);
|
qemuDriverUnlock(driver);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
@ -5799,8 +5800,8 @@ cleanup:
|
|||||||
*/
|
*/
|
||||||
static int ATTRIBUTE_NONNULL (5)
|
static int ATTRIBUTE_NONNULL (5)
|
||||||
qemudDomainMigratePrepare2 (virConnectPtr dconn,
|
qemudDomainMigratePrepare2 (virConnectPtr dconn,
|
||||||
char **cookie ATTRIBUTE_UNUSED,
|
char **cookie,
|
||||||
int *cookielen ATTRIBUTE_UNUSED,
|
int *cookielen,
|
||||||
const char *uri_in,
|
const char *uri_in,
|
||||||
char **uri_out,
|
char **uri_out,
|
||||||
unsigned long flags,
|
unsigned long flags,
|
||||||
@ -5839,6 +5840,8 @@ qemudDomainMigratePrepare2 (virConnectPtr dconn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = qemuMigrationPrepareDirect(driver, dconn,
|
ret = qemuMigrationPrepareDirect(driver, dconn,
|
||||||
|
NULL, 0, /* No input cookies in v2 */
|
||||||
|
cookie, cookielen,
|
||||||
uri_in, uri_out,
|
uri_in, uri_out,
|
||||||
dname, dom_xml);
|
dname, dom_xml);
|
||||||
|
|
||||||
@ -5882,8 +5885,9 @@ qemudDomainMigratePerform (virDomainPtr dom,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = qemuMigrationPerform(driver, dom->conn, vm,
|
ret = qemuMigrationPerform(driver, dom->conn, vm,
|
||||||
uri, flags,
|
uri, cookie, cookielen,
|
||||||
dname, resource);
|
NULL, NULL, /* No output cookies in v2 */
|
||||||
|
flags, dname, resource);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
qemuDriverUnlock(driver);
|
qemuDriverUnlock(driver);
|
||||||
@ -5926,7 +5930,9 @@ qemudDomainMigrateFinish2 (virConnectPtr dconn,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
dom = qemuMigrationFinish(driver, dconn, vm, flags, retcode);
|
dom = qemuMigrationFinish(driver, dconn, vm,
|
||||||
|
NULL, 0, NULL, NULL, /* No cookies in v2 */
|
||||||
|
flags, retcode);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
if (orig_err) {
|
if (orig_err) {
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
#include <gnutls/gnutls.h>
|
||||||
|
#include <gnutls/x509.h>
|
||||||
|
|
||||||
#include "qemu_migration.h"
|
#include "qemu_migration.h"
|
||||||
#include "qemu_monitor.h"
|
#include "qemu_monitor.h"
|
||||||
@ -38,11 +40,271 @@
|
|||||||
#include "files.h"
|
#include "files.h"
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
#include "fdstream.h"
|
#include "fdstream.h"
|
||||||
|
#include "uuid.h"
|
||||||
|
|
||||||
|
|
||||||
#define VIR_FROM_THIS VIR_FROM_QEMU
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
||||||
|
|
||||||
#define timeval_to_ms(tv) (((tv).tv_sec * 1000ull) + ((tv).tv_usec / 1000))
|
#define timeval_to_ms(tv) (((tv).tv_sec * 1000ull) + ((tv).tv_usec / 1000))
|
||||||
|
|
||||||
|
typedef struct _qemuMigrationCookie qemuMigrationCookie;
|
||||||
|
typedef qemuMigrationCookie *qemuMigrationCookiePtr;
|
||||||
|
struct _qemuMigrationCookie {
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
/* Host properties */
|
||||||
|
unsigned char hostuuid[VIR_UUID_BUFLEN];
|
||||||
|
char *hostname;
|
||||||
|
|
||||||
|
/* Guest properties */
|
||||||
|
unsigned char uuid[VIR_UUID_BUFLEN];
|
||||||
|
char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void qemuMigrationCookieFree(qemuMigrationCookiePtr mig)
|
||||||
|
{
|
||||||
|
if (!mig)
|
||||||
|
return;
|
||||||
|
|
||||||
|
VIR_FREE(mig->hostname);
|
||||||
|
VIR_FREE(mig->name);
|
||||||
|
VIR_FREE(mig);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static qemuMigrationCookiePtr
|
||||||
|
qemuMigrationCookieNew(virDomainObjPtr dom)
|
||||||
|
{
|
||||||
|
qemuMigrationCookiePtr mig = NULL;
|
||||||
|
|
||||||
|
if (VIR_ALLOC(mig) < 0)
|
||||||
|
goto no_memory;
|
||||||
|
|
||||||
|
if (!(mig->name = strdup(dom->def->name)))
|
||||||
|
goto no_memory;
|
||||||
|
memcpy(mig->uuid, dom->def->uuid, VIR_UUID_BUFLEN);
|
||||||
|
|
||||||
|
if (!(mig->hostname = virGetHostname(NULL)))
|
||||||
|
goto no_memory;
|
||||||
|
if (virGetHostUUID(mig->hostuuid) < 0) {
|
||||||
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||||
|
_("Unable to obtain host UUID"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mig;
|
||||||
|
|
||||||
|
no_memory:
|
||||||
|
virReportOOMError();
|
||||||
|
error:
|
||||||
|
qemuMigrationCookieFree(mig);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void qemuMigrationCookieXMLFormat(virBufferPtr buf,
|
||||||
|
qemuMigrationCookiePtr mig)
|
||||||
|
{
|
||||||
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
||||||
|
char hostuuidstr[VIR_UUID_STRING_BUFLEN];
|
||||||
|
|
||||||
|
virUUIDFormat(mig->uuid, uuidstr);
|
||||||
|
virUUIDFormat(mig->hostuuid, hostuuidstr);
|
||||||
|
|
||||||
|
virBufferAsprintf(buf, "<qemu-migration>\n");
|
||||||
|
virBufferEscapeString(buf, " <name>%s</name>\n", mig->name);
|
||||||
|
virBufferAsprintf(buf, " <uuid>%s</uuid>\n", uuidstr);
|
||||||
|
virBufferEscapeString(buf, " <hostname>%s</hostname>\n", mig->hostname);
|
||||||
|
virBufferAsprintf(buf, " <hostuuid>%s</hostuuid>\n", hostuuidstr);
|
||||||
|
virBufferAddLit(buf, "</qemu-migration>\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static char *qemuMigrationCookieXMLFormatStr(qemuMigrationCookiePtr mig)
|
||||||
|
{
|
||||||
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||||
|
|
||||||
|
qemuMigrationCookieXMLFormat(&buf, mig);
|
||||||
|
|
||||||
|
if (virBufferError(&buf)) {
|
||||||
|
virReportOOMError();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return virBufferContentAndReset(&buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig,
|
||||||
|
xmlXPathContextPtr ctxt,
|
||||||
|
int flags ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
||||||
|
char *tmp;
|
||||||
|
|
||||||
|
/* We don't store the uuid, name, hostname, or hostuuid
|
||||||
|
* values. We just compare them to local data to do some
|
||||||
|
* sanity checking on migration operation
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Extract domain name */
|
||||||
|
if (!(tmp = virXPathString("string(./name[1])", ctxt))) {
|
||||||
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"%s", _("missing name element in migration data"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (STRNEQ(tmp, mig->name)) {
|
||||||
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("Incoming cookie data had unexpected name %s vs %s"),
|
||||||
|
tmp, mig->name);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
VIR_FREE(tmp);
|
||||||
|
|
||||||
|
/* Extract domain uuid */
|
||||||
|
tmp = virXPathString("string(./uuid[1])", ctxt);
|
||||||
|
if (!tmp) {
|
||||||
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"%s", _("missing uuid element in migration data"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
virUUIDFormat(mig->uuid, uuidstr);
|
||||||
|
if (STRNEQ(tmp, uuidstr)) {
|
||||||
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("Incoming cookie data had unexpected UUID %s vs %s"),
|
||||||
|
tmp, uuidstr);
|
||||||
|
}
|
||||||
|
VIR_FREE(tmp);
|
||||||
|
|
||||||
|
/* Check & forbid "localhost" migration */
|
||||||
|
if (!(tmp = virXPathString("string(./hostname[1])", ctxt))) {
|
||||||
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"%s", _("missing hostname element in migration data"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (STREQ(tmp, mig->hostname)) {
|
||||||
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("Attempt to migrate guest to the same host %s"),
|
||||||
|
tmp);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
VIR_FREE(tmp);
|
||||||
|
|
||||||
|
if (!(tmp = virXPathString("string(./hostuuid[1])", ctxt))) {
|
||||||
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"%s", _("missing hostuuid element in migration data"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
virUUIDFormat(mig->hostuuid, uuidstr);
|
||||||
|
if (STREQ(tmp, uuidstr)) {
|
||||||
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("Attempt to migrate guest to the same host %s"),
|
||||||
|
tmp);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
VIR_FREE(tmp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
VIR_FREE(tmp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
qemuMigrationCookieXMLParseStr(qemuMigrationCookiePtr mig,
|
||||||
|
const char *xml,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
xmlDocPtr doc = NULL;
|
||||||
|
xmlXPathContextPtr ctxt = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
VIR_DEBUG("xml=%s", NULLSTR(xml));
|
||||||
|
|
||||||
|
if (!(doc = virXMLParseString(xml, "qemumigration.xml")))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if ((ctxt = xmlXPathNewContext(doc)) == NULL) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctxt->node = xmlDocGetRootElement(doc);
|
||||||
|
|
||||||
|
ret = qemuMigrationCookieXMLParse(mig, ctxt, flags);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
xmlXPathFreeContext(ctxt);
|
||||||
|
xmlFreeDoc(doc);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
qemuMigrationBakeCookie(qemuMigrationCookiePtr mig,
|
||||||
|
struct qemud_driver *driver ATTRIBUTE_UNUSED,
|
||||||
|
virDomainObjPtr dom ATTRIBUTE_UNUSED,
|
||||||
|
char **cookieout,
|
||||||
|
int *cookieoutlen,
|
||||||
|
int flags ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
if (!cookieout || !cookieoutlen) {
|
||||||
|
qemuReportError(VIR_ERR_INVALID_ARG, "%s",
|
||||||
|
_("missing migration cookie data"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*cookieoutlen = 0;
|
||||||
|
|
||||||
|
if (!(*cookieout = qemuMigrationCookieXMLFormatStr(mig)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
*cookieoutlen = strlen(*cookieout) + 1;
|
||||||
|
|
||||||
|
VIR_DEBUG("cookielen=%d cookie=%s", *cookieoutlen, *cookieout);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static qemuMigrationCookiePtr
|
||||||
|
qemuMigrationEatCookie(virDomainObjPtr dom,
|
||||||
|
const char *cookiein,
|
||||||
|
int cookieinlen,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
qemuMigrationCookiePtr mig = NULL;
|
||||||
|
|
||||||
|
/* Parse & validate incoming cookie (if any) */
|
||||||
|
if (cookiein && cookieinlen &&
|
||||||
|
cookiein[cookieinlen-1] != '\0') {
|
||||||
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||||
|
_("Migration cookie was not NULL terminated"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
VIR_DEBUG("cookielen=%d cookie='%s'", cookieinlen, NULLSTR(cookiein));
|
||||||
|
|
||||||
|
if (!(mig = qemuMigrationCookieNew(dom)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (cookiein && cookieinlen &&
|
||||||
|
qemuMigrationCookieXMLParseStr(mig,
|
||||||
|
cookiein,
|
||||||
|
flags) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
return mig;
|
||||||
|
|
||||||
|
error:
|
||||||
|
qemuMigrationCookieFree(mig);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
qemuMigrationIsAllowed(virDomainDefPtr def)
|
qemuMigrationIsAllowed(virDomainDefPtr def)
|
||||||
@ -245,6 +507,10 @@ cleanup:
|
|||||||
int
|
int
|
||||||
qemuMigrationPrepareTunnel(struct qemud_driver *driver,
|
qemuMigrationPrepareTunnel(struct qemud_driver *driver,
|
||||||
virConnectPtr dconn,
|
virConnectPtr dconn,
|
||||||
|
const char *cookiein,
|
||||||
|
int cookieinlen,
|
||||||
|
char **cookieout,
|
||||||
|
int *cookieoutlen,
|
||||||
virStreamPtr st,
|
virStreamPtr st,
|
||||||
const char *dname,
|
const char *dname,
|
||||||
const char *dom_xml)
|
const char *dom_xml)
|
||||||
@ -257,6 +523,7 @@ qemuMigrationPrepareTunnel(struct qemud_driver *driver,
|
|||||||
int dataFD[2] = { -1, -1 };
|
int dataFD[2] = { -1, -1 };
|
||||||
qemuDomainObjPrivatePtr priv = NULL;
|
qemuDomainObjPrivatePtr priv = NULL;
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
|
qemuMigrationCookiePtr mig = NULL;
|
||||||
|
|
||||||
if (gettimeofday(&now, NULL) < 0) {
|
if (gettimeofday(&now, NULL) < 0) {
|
||||||
virReportSystemError(errno, "%s",
|
virReportSystemError(errno, "%s",
|
||||||
@ -292,6 +559,9 @@ qemuMigrationPrepareTunnel(struct qemud_driver *driver,
|
|||||||
def = NULL;
|
def = NULL;
|
||||||
priv = vm->privateData;
|
priv = vm->privateData;
|
||||||
|
|
||||||
|
if (!(mig = qemuMigrationEatCookie(vm, cookiein, cookieinlen, 0)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
|
if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
priv->jobActive = QEMU_JOB_MIGRATION_OUT;
|
priv->jobActive = QEMU_JOB_MIGRATION_OUT;
|
||||||
@ -342,6 +612,15 @@ qemuMigrationPrepareTunnel(struct qemud_driver *driver,
|
|||||||
event = virDomainEventNewFromObj(vm,
|
event = virDomainEventNewFromObj(vm,
|
||||||
VIR_DOMAIN_EVENT_STARTED,
|
VIR_DOMAIN_EVENT_STARTED,
|
||||||
VIR_DOMAIN_EVENT_STARTED_MIGRATED);
|
VIR_DOMAIN_EVENT_STARTED_MIGRATED);
|
||||||
|
|
||||||
|
if (qemuMigrationBakeCookie(mig, driver, vm, cookieout, cookieoutlen, 0) < 0) {
|
||||||
|
/* We could tear down the whole guest here, but
|
||||||
|
* cookie data is (so far) non-critical, so that
|
||||||
|
* seems a little harsh. We'll just warn for now.
|
||||||
|
*/
|
||||||
|
VIR_WARN("Unable to encode migration cookie");
|
||||||
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
endjob:
|
endjob:
|
||||||
@ -369,6 +648,7 @@ cleanup:
|
|||||||
virDomainObjUnlock(vm);
|
virDomainObjUnlock(vm);
|
||||||
if (event)
|
if (event)
|
||||||
qemuDomainEventQueue(driver, event);
|
qemuDomainEventQueue(driver, event);
|
||||||
|
qemuMigrationCookieFree(mig);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,6 +656,10 @@ cleanup:
|
|||||||
int
|
int
|
||||||
qemuMigrationPrepareDirect(struct qemud_driver *driver,
|
qemuMigrationPrepareDirect(struct qemud_driver *driver,
|
||||||
virConnectPtr dconn,
|
virConnectPtr dconn,
|
||||||
|
const char *cookiein,
|
||||||
|
int cookieinlen,
|
||||||
|
char **cookieout,
|
||||||
|
int *cookieoutlen,
|
||||||
const char *uri_in,
|
const char *uri_in,
|
||||||
char **uri_out,
|
char **uri_out,
|
||||||
const char *dname,
|
const char *dname,
|
||||||
@ -393,6 +677,7 @@ qemuMigrationPrepareDirect(struct qemud_driver *driver,
|
|||||||
int internalret;
|
int internalret;
|
||||||
qemuDomainObjPrivatePtr priv = NULL;
|
qemuDomainObjPrivatePtr priv = NULL;
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
|
qemuMigrationCookiePtr mig = NULL;
|
||||||
|
|
||||||
if (gettimeofday(&now, NULL) < 0) {
|
if (gettimeofday(&now, NULL) < 0) {
|
||||||
virReportSystemError(errno, "%s",
|
virReportSystemError(errno, "%s",
|
||||||
@ -502,6 +787,9 @@ qemuMigrationPrepareDirect(struct qemud_driver *driver,
|
|||||||
def = NULL;
|
def = NULL;
|
||||||
priv = vm->privateData;
|
priv = vm->privateData;
|
||||||
|
|
||||||
|
if (!(mig = qemuMigrationEatCookie(vm, cookiein, cookieinlen, 0)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
|
if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
priv->jobActive = QEMU_JOB_MIGRATION_OUT;
|
priv->jobActive = QEMU_JOB_MIGRATION_OUT;
|
||||||
@ -527,6 +815,14 @@ qemuMigrationPrepareDirect(struct qemud_driver *driver,
|
|||||||
goto endjob;
|
goto endjob;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (qemuMigrationBakeCookie(mig, driver, vm, cookieout, cookieoutlen, 0) < 0) {
|
||||||
|
/* We could tear down the whole guest here, but
|
||||||
|
* cookie data is (so far) non-critical, so that
|
||||||
|
* seems a little harsh. We'll just warn for now.
|
||||||
|
*/
|
||||||
|
VIR_WARN("Unable to encode migration cookie");
|
||||||
|
}
|
||||||
|
|
||||||
qemuAuditDomainStart(vm, "migrated", true);
|
qemuAuditDomainStart(vm, "migrated", true);
|
||||||
event = virDomainEventNewFromObj(vm,
|
event = virDomainEventNewFromObj(vm,
|
||||||
VIR_DOMAIN_EVENT_STARTED,
|
VIR_DOMAIN_EVENT_STARTED,
|
||||||
@ -559,6 +855,7 @@ cleanup:
|
|||||||
virDomainObjUnlock(vm);
|
virDomainObjUnlock(vm);
|
||||||
if (event)
|
if (event)
|
||||||
qemuDomainEventQueue(driver, event);
|
qemuDomainEventQueue(driver, event);
|
||||||
|
qemuMigrationCookieFree(mig);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -569,6 +866,10 @@ cleanup:
|
|||||||
static int doNativeMigrate(struct qemud_driver *driver,
|
static int doNativeMigrate(struct qemud_driver *driver,
|
||||||
virDomainObjPtr vm,
|
virDomainObjPtr vm,
|
||||||
const char *uri,
|
const char *uri,
|
||||||
|
const char *cookiein,
|
||||||
|
int cookieinlen,
|
||||||
|
char **cookieout,
|
||||||
|
int *cookieoutlen,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
const char *dname ATTRIBUTE_UNUSED,
|
const char *dname ATTRIBUTE_UNUSED,
|
||||||
unsigned long resource)
|
unsigned long resource)
|
||||||
@ -577,6 +878,10 @@ static int doNativeMigrate(struct qemud_driver *driver,
|
|||||||
xmlURIPtr uribits = NULL;
|
xmlURIPtr uribits = NULL;
|
||||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
unsigned int background_flags = QEMU_MONITOR_MIGRATE_BACKGROUND;
|
unsigned int background_flags = QEMU_MONITOR_MIGRATE_BACKGROUND;
|
||||||
|
qemuMigrationCookiePtr mig = NULL;
|
||||||
|
|
||||||
|
if (!(mig = qemuMigrationEatCookie(vm, cookiein, cookieinlen, 0)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
/* Issue the migrate command. */
|
/* Issue the migrate command. */
|
||||||
if (STRPREFIX(uri, "tcp:") && !STRPREFIX(uri, "tcp://")) {
|
if (STRPREFIX(uri, "tcp:") && !STRPREFIX(uri, "tcp://")) {
|
||||||
@ -620,9 +925,13 @@ static int doNativeMigrate(struct qemud_driver *driver,
|
|||||||
if (qemuMigrationWaitForCompletion(driver, vm) < 0)
|
if (qemuMigrationWaitForCompletion(driver, vm) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
if (qemuMigrationBakeCookie(mig, driver, vm, cookieout, cookieoutlen, 0) < 0)
|
||||||
|
VIR_WARN("Unable to encode migration cookie");
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
qemuMigrationCookieFree(mig);
|
||||||
xmlFreeURI(uribits);
|
xmlFreeURI(uribits);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -901,14 +1210,16 @@ static int doNonTunnelMigrate(struct qemud_driver *driver,
|
|||||||
virDomainPtr ddomain = NULL;
|
virDomainPtr ddomain = NULL;
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *uri_out = NULL;
|
char *uri_out = NULL;
|
||||||
|
char *cookie = NULL;
|
||||||
|
int cookielen = 0;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
qemuDomainObjEnterRemoteWithDriver(driver, vm);
|
qemuDomainObjEnterRemoteWithDriver(driver, vm);
|
||||||
/* NB we don't pass 'uri' into this, since that's the libvirtd
|
/* NB we don't pass 'uri' into this, since that's the libvirtd
|
||||||
* URI in this context - so we let dest pick it */
|
* URI in this context - so we let dest pick it */
|
||||||
rc = dconn->driver->domainMigratePrepare2(dconn,
|
rc = dconn->driver->domainMigratePrepare2(dconn,
|
||||||
NULL, /* cookie */
|
&cookie,
|
||||||
0, /* cookielen */
|
&cookielen,
|
||||||
NULL, /* uri */
|
NULL, /* uri */
|
||||||
&uri_out,
|
&uri_out,
|
||||||
flags, dname,
|
flags, dname,
|
||||||
@ -933,7 +1244,10 @@ static int doNonTunnelMigrate(struct qemud_driver *driver,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doNativeMigrate(driver, vm, uri_out, flags, dname, resource) < 0)
|
if (doNativeMigrate(driver, vm, uri_out,
|
||||||
|
cookie, cookielen,
|
||||||
|
NULL, NULL, /* No out cookie with v2 migration */
|
||||||
|
flags, dname, resource) < 0)
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
@ -942,13 +1256,14 @@ finish:
|
|||||||
dname = dname ? dname : vm->def->name;
|
dname = dname ? dname : vm->def->name;
|
||||||
qemuDomainObjEnterRemoteWithDriver(driver, vm);
|
qemuDomainObjEnterRemoteWithDriver(driver, vm);
|
||||||
ddomain = dconn->driver->domainMigrateFinish2
|
ddomain = dconn->driver->domainMigrateFinish2
|
||||||
(dconn, dname, NULL, 0, uri_out, flags, retval);
|
(dconn, dname, cookie, cookielen, uri_out, flags, retval);
|
||||||
qemuDomainObjExitRemoteWithDriver(driver, vm);
|
qemuDomainObjExitRemoteWithDriver(driver, vm);
|
||||||
|
|
||||||
if (ddomain)
|
if (ddomain)
|
||||||
virUnrefDomain(ddomain);
|
virUnrefDomain(ddomain);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
VIR_FREE(cookie);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1024,6 +1339,10 @@ int qemuMigrationPerform(struct qemud_driver *driver,
|
|||||||
virConnectPtr conn,
|
virConnectPtr conn,
|
||||||
virDomainObjPtr vm,
|
virDomainObjPtr vm,
|
||||||
const char *uri,
|
const char *uri,
|
||||||
|
const char *cookiein,
|
||||||
|
int cookieinlen,
|
||||||
|
char **cookieout,
|
||||||
|
int *cookieoutlen,
|
||||||
unsigned long flags,
|
unsigned long flags,
|
||||||
const char *dname,
|
const char *dname,
|
||||||
unsigned long resource)
|
unsigned long resource)
|
||||||
@ -1054,11 +1373,19 @@ int qemuMigrationPerform(struct qemud_driver *driver,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) {
|
if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) {
|
||||||
|
if (cookieinlen) {
|
||||||
|
qemuReportError(VIR_ERR_OPERATION_INVALID,
|
||||||
|
"%s", _("received unexpected cookie with P2P migration"));
|
||||||
|
goto endjob;
|
||||||
|
}
|
||||||
|
|
||||||
if (doPeer2PeerMigrate(driver, vm, uri, flags, dname, resource) < 0)
|
if (doPeer2PeerMigrate(driver, vm, uri, flags, dname, resource) < 0)
|
||||||
/* doPeer2PeerMigrate already set the error, so just get out */
|
/* doPeer2PeerMigrate already set the error, so just get out */
|
||||||
goto endjob;
|
goto endjob;
|
||||||
} else {
|
} else {
|
||||||
if (doNativeMigrate(driver, vm, uri, flags, dname, resource) < 0)
|
if (doNativeMigrate(driver, vm, uri, cookiein, cookieinlen,
|
||||||
|
cookieout, cookieoutlen,
|
||||||
|
flags, dname, resource) < 0)
|
||||||
goto endjob;
|
goto endjob;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1076,6 +1403,7 @@ int qemuMigrationPerform(struct qemud_driver *driver,
|
|||||||
virDomainRemoveInactive(&driver->domains, vm);
|
virDomainRemoveInactive(&driver->domains, vm);
|
||||||
vm = NULL;
|
vm = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
endjob:
|
endjob:
|
||||||
@ -1153,6 +1481,10 @@ virDomainPtr
|
|||||||
qemuMigrationFinish(struct qemud_driver *driver,
|
qemuMigrationFinish(struct qemud_driver *driver,
|
||||||
virConnectPtr dconn,
|
virConnectPtr dconn,
|
||||||
virDomainObjPtr vm,
|
virDomainObjPtr vm,
|
||||||
|
const char *cookiein,
|
||||||
|
int cookieinlen,
|
||||||
|
char **cookieout,
|
||||||
|
int *cookieoutlen,
|
||||||
unsigned long flags,
|
unsigned long flags,
|
||||||
int retcode)
|
int retcode)
|
||||||
{
|
{
|
||||||
@ -1160,6 +1492,7 @@ qemuMigrationFinish(struct qemud_driver *driver,
|
|||||||
virDomainEventPtr event = NULL;
|
virDomainEventPtr event = NULL;
|
||||||
int newVM = 1;
|
int newVM = 1;
|
||||||
qemuDomainObjPrivatePtr priv = NULL;
|
qemuDomainObjPrivatePtr priv = NULL;
|
||||||
|
qemuMigrationCookiePtr mig = NULL;
|
||||||
|
|
||||||
priv = vm->privateData;
|
priv = vm->privateData;
|
||||||
if (priv->jobActive != QEMU_JOB_MIGRATION_IN) {
|
if (priv->jobActive != QEMU_JOB_MIGRATION_IN) {
|
||||||
@ -1170,6 +1503,9 @@ qemuMigrationFinish(struct qemud_driver *driver,
|
|||||||
priv->jobActive = QEMU_JOB_NONE;
|
priv->jobActive = QEMU_JOB_NONE;
|
||||||
memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
|
memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
|
||||||
|
|
||||||
|
if (!(mig = qemuMigrationEatCookie(vm, cookiein, cookieinlen, 0)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
|
if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
@ -1257,6 +1593,9 @@ qemuMigrationFinish(struct qemud_driver *driver,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (qemuMigrationBakeCookie(mig, driver, vm, cookieout, cookieoutlen, 0) < 0)
|
||||||
|
VIR_WARN("Unable to encode migration cookie");
|
||||||
|
|
||||||
endjob:
|
endjob:
|
||||||
if (vm &&
|
if (vm &&
|
||||||
qemuDomainObjEndJob(vm) == 0)
|
qemuDomainObjEndJob(vm) == 0)
|
||||||
@ -1267,6 +1606,7 @@ cleanup:
|
|||||||
virDomainObjUnlock(vm);
|
virDomainObjUnlock(vm);
|
||||||
if (event)
|
if (event)
|
||||||
qemuDomainEventQueue(driver, event);
|
qemuDomainEventQueue(driver, event);
|
||||||
|
qemuMigrationCookieFree(mig);
|
||||||
return dom;
|
return dom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,12 +34,20 @@ int qemuMigrationWaitForCompletion(struct qemud_driver *driver, virDomainObjPtr
|
|||||||
|
|
||||||
int qemuMigrationPrepareTunnel(struct qemud_driver *driver,
|
int qemuMigrationPrepareTunnel(struct qemud_driver *driver,
|
||||||
virConnectPtr dconn,
|
virConnectPtr dconn,
|
||||||
|
const char *cookiein,
|
||||||
|
int cookieinlen,
|
||||||
|
char **cookieout,
|
||||||
|
int *cookieoutlen,
|
||||||
virStreamPtr st,
|
virStreamPtr st,
|
||||||
const char *dname,
|
const char *dname,
|
||||||
const char *dom_xml);
|
const char *dom_xml);
|
||||||
|
|
||||||
int qemuMigrationPrepareDirect(struct qemud_driver *driver,
|
int qemuMigrationPrepareDirect(struct qemud_driver *driver,
|
||||||
virConnectPtr dconn,
|
virConnectPtr dconn,
|
||||||
|
const char *cookiein,
|
||||||
|
int cookieinlen,
|
||||||
|
char **cookieout,
|
||||||
|
int *cookieoutlen,
|
||||||
const char *uri_in,
|
const char *uri_in,
|
||||||
char **uri_out,
|
char **uri_out,
|
||||||
const char *dname,
|
const char *dname,
|
||||||
@ -49,6 +57,10 @@ int qemuMigrationPerform(struct qemud_driver *driver,
|
|||||||
virConnectPtr conn,
|
virConnectPtr conn,
|
||||||
virDomainObjPtr vm,
|
virDomainObjPtr vm,
|
||||||
const char *uri,
|
const char *uri,
|
||||||
|
const char *cookiein,
|
||||||
|
int cookieinlen,
|
||||||
|
char **cookieout,
|
||||||
|
int *cookieoutlen,
|
||||||
unsigned long flags,
|
unsigned long flags,
|
||||||
const char *dname,
|
const char *dname,
|
||||||
unsigned long resource);
|
unsigned long resource);
|
||||||
@ -56,6 +68,10 @@ int qemuMigrationPerform(struct qemud_driver *driver,
|
|||||||
virDomainPtr qemuMigrationFinish(struct qemud_driver *driver,
|
virDomainPtr qemuMigrationFinish(struct qemud_driver *driver,
|
||||||
virConnectPtr dconn,
|
virConnectPtr dconn,
|
||||||
virDomainObjPtr vm,
|
virDomainObjPtr vm,
|
||||||
|
const char *cookiein,
|
||||||
|
int cookieinlen,
|
||||||
|
char **cookieout,
|
||||||
|
int *cookieoutlen,
|
||||||
unsigned long flags,
|
unsigned long flags,
|
||||||
int retcode);
|
int retcode);
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ const REMOTE_VCPUINFO_MAX = 2048;
|
|||||||
const REMOTE_CPUMAPS_MAX = 16384;
|
const REMOTE_CPUMAPS_MAX = 16384;
|
||||||
|
|
||||||
/* Upper limit on migrate cookie. */
|
/* Upper limit on migrate cookie. */
|
||||||
const REMOTE_MIGRATE_COOKIE_MAX = 256;
|
const REMOTE_MIGRATE_COOKIE_MAX = 16384;
|
||||||
|
|
||||||
/* Upper limit on lists of network names. */
|
/* Upper limit on lists of network names. */
|
||||||
const REMOTE_NETWORK_NAME_LIST_MAX = 256;
|
const REMOTE_NETWORK_NAME_LIST_MAX = 256;
|
||||||
|
Loading…
Reference in New Issue
Block a user