mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-21 19:02:25 +00:00
libxl: add migration support
This patch adds initial migration support to the libxl driver, using the VIR_DRV_FEATURE_MIGRATION_PARAMS family of migration functions. Signed-off-by: Jim Fehlig <jfehlig@suse.com>
This commit is contained in:
parent
d9a099a4c5
commit
9b8d6e1eef
@ -74,6 +74,7 @@ src/lxc/lxc_process.c
|
||||
src/libxl/libxl_domain.c
|
||||
src/libxl/libxl_driver.c
|
||||
src/libxl/libxl_conf.c
|
||||
src/libxl/libxl_migration.c
|
||||
src/network/bridge_driver.c
|
||||
src/network/bridge_driver_linux.c
|
||||
src/network/leaseshelper.c
|
||||
|
@ -707,7 +707,8 @@ XENAPI_DRIVER_SOURCES = \
|
||||
LIBXL_DRIVER_SOURCES = \
|
||||
libxl/libxl_conf.c libxl/libxl_conf.h \
|
||||
libxl/libxl_domain.c libxl/libxl_domain.h \
|
||||
libxl/libxl_driver.c libxl/libxl_driver.h
|
||||
libxl/libxl_driver.c libxl/libxl_driver.h \
|
||||
libxl/libxl_migration.c libxl/libxl_migration.h
|
||||
|
||||
UML_DRIVER_SOURCES = \
|
||||
uml/uml_conf.c uml/uml_conf.h \
|
||||
|
@ -43,6 +43,9 @@
|
||||
# define LIBXL_VNC_PORT_MIN 5900
|
||||
# define LIBXL_VNC_PORT_MAX 65535
|
||||
|
||||
# define LIBXL_MIGRATION_PORT_MIN 49152
|
||||
# define LIBXL_MIGRATION_PORT_MAX 49216
|
||||
|
||||
# define LIBXL_CONFIG_DIR SYSCONFDIR "/libvirt/libxl"
|
||||
# define LIBXL_AUTOSTART_DIR LIBXL_CONFIG_DIR "/autostart"
|
||||
# define LIBXL_STATE_DIR LOCALSTATEDIR "/run/libvirt/libxl"
|
||||
@ -115,6 +118,9 @@ struct _libxlDriverPrivate {
|
||||
/* Immutable pointer, self-locking APIs */
|
||||
virPortAllocatorPtr reservedVNCPorts;
|
||||
|
||||
/* Immutable pointer, self-locking APIs */
|
||||
virPortAllocatorPtr migrationPorts;
|
||||
|
||||
/* Immutable pointer, lockless APIs*/
|
||||
virSysinfoDefPtr hostsysinfo;
|
||||
};
|
||||
|
@ -69,6 +69,7 @@ struct _libxlDomainObjPrivate {
|
||||
virChrdevsPtr devs;
|
||||
libxl_evgen_domain_death *deathW;
|
||||
libxlDriverPrivatePtr driver;
|
||||
unsigned short migrationPort;
|
||||
|
||||
struct libxlDomainJobObj job;
|
||||
};
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "libxl_domain.h"
|
||||
#include "libxl_driver.h"
|
||||
#include "libxl_conf.h"
|
||||
#include "libxl_migration.h"
|
||||
#include "xen_xm.h"
|
||||
#include "xen_sxpr.h"
|
||||
#include "virtypedparam.h"
|
||||
@ -209,6 +210,7 @@ libxlStateCleanup(void)
|
||||
virObjectUnref(libxl_driver->xmlopt);
|
||||
virObjectUnref(libxl_driver->domains);
|
||||
virObjectUnref(libxl_driver->reservedVNCPorts);
|
||||
virObjectUnref(libxl_driver->migrationPorts);
|
||||
|
||||
virObjectEventStateFree(libxl_driver->domainEventState);
|
||||
virSysinfoDefFree(libxl_driver->hostsysinfo);
|
||||
@ -301,6 +303,13 @@ libxlStateInitialize(bool privileged,
|
||||
LIBXL_VNC_PORT_MAX)))
|
||||
goto error;
|
||||
|
||||
/* Allocate bitmap for migration port reservation */
|
||||
if (!(libxl_driver->migrationPorts =
|
||||
virPortAllocatorNew(_("migration"),
|
||||
LIBXL_MIGRATION_PORT_MIN,
|
||||
LIBXL_MIGRATION_PORT_MAX)))
|
||||
goto error;
|
||||
|
||||
if (!(libxl_driver->domains = virDomainObjListNew()))
|
||||
goto error;
|
||||
|
||||
@ -4153,6 +4162,7 @@ libxlConnectSupportsFeature(virConnectPtr conn, int feature)
|
||||
|
||||
switch (feature) {
|
||||
case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
|
||||
case VIR_DRV_FEATURE_MIGRATION_PARAMS:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
@ -4331,6 +4341,226 @@ libxlNodeDeviceReset(virNodeDevicePtr dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *
|
||||
libxlDomainMigrateBegin3Params(virDomainPtr domain,
|
||||
virTypedParameterPtr params,
|
||||
int nparams,
|
||||
char **cookieout ATTRIBUTE_UNUSED,
|
||||
int *cookieoutlen ATTRIBUTE_UNUSED,
|
||||
unsigned int flags)
|
||||
{
|
||||
const char *xmlin = NULL;
|
||||
virDomainObjPtr vm = NULL;
|
||||
|
||||
virCheckFlags(LIBXL_MIGRATION_FLAGS, NULL);
|
||||
if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0)
|
||||
return NULL;
|
||||
|
||||
if (virTypedParamsGetString(params, nparams,
|
||||
VIR_MIGRATE_PARAM_DEST_XML,
|
||||
&xmlin) < 0)
|
||||
return NULL;
|
||||
|
||||
if (!(vm = libxlDomObjFromDomain(domain)))
|
||||
return NULL;
|
||||
|
||||
if (virDomainMigrateBegin3ParamsEnsureACL(domain->conn, vm->def) < 0) {
|
||||
virObjectUnlock(vm);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!virDomainObjIsActive(vm)) {
|
||||
virReportError(VIR_ERR_OPERATION_INVALID,
|
||||
"%s", _("domain is not running"));
|
||||
virObjectUnlock(vm);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return libxlDomainMigrationBegin(domain->conn, vm, xmlin);
|
||||
}
|
||||
|
||||
static int
|
||||
libxlDomainMigratePrepare3Params(virConnectPtr dconn,
|
||||
virTypedParameterPtr params,
|
||||
int nparams,
|
||||
const char *cookiein ATTRIBUTE_UNUSED,
|
||||
int cookieinlen ATTRIBUTE_UNUSED,
|
||||
char **cookieout ATTRIBUTE_UNUSED,
|
||||
int *cookieoutlen ATTRIBUTE_UNUSED,
|
||||
char **uri_out,
|
||||
unsigned int flags)
|
||||
{
|
||||
libxlDriverPrivatePtr driver = dconn->privateData;
|
||||
virDomainDefPtr def = NULL;
|
||||
const char *dom_xml = NULL;
|
||||
const char *dname = NULL;
|
||||
const char *uri_in = NULL;
|
||||
|
||||
virCheckFlags(LIBXL_MIGRATION_FLAGS, -1);
|
||||
if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0)
|
||||
goto error;
|
||||
|
||||
if (virTypedParamsGetString(params, nparams,
|
||||
VIR_MIGRATE_PARAM_DEST_XML,
|
||||
&dom_xml) < 0 ||
|
||||
virTypedParamsGetString(params, nparams,
|
||||
VIR_MIGRATE_PARAM_DEST_NAME,
|
||||
&dname) < 0 ||
|
||||
virTypedParamsGetString(params, nparams,
|
||||
VIR_MIGRATE_PARAM_URI,
|
||||
&uri_in) < 0)
|
||||
|
||||
goto error;
|
||||
|
||||
if (!(def = libxlDomainMigrationPrepareDef(driver, dom_xml, dname)))
|
||||
goto error;
|
||||
|
||||
if (virDomainMigratePrepare3ParamsEnsureACL(dconn, def) < 0)
|
||||
goto error;
|
||||
|
||||
if (libxlDomainMigrationPrepare(dconn, def, uri_in, uri_out, flags) < 0)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
virDomainDefFree(def);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
libxlDomainMigratePerform3Params(virDomainPtr dom,
|
||||
const char *dconnuri,
|
||||
virTypedParameterPtr params,
|
||||
int nparams,
|
||||
const char *cookiein ATTRIBUTE_UNUSED,
|
||||
int cookieinlen ATTRIBUTE_UNUSED,
|
||||
char **cookieout ATTRIBUTE_UNUSED,
|
||||
int *cookieoutlen ATTRIBUTE_UNUSED,
|
||||
unsigned int flags)
|
||||
{
|
||||
libxlDriverPrivatePtr driver = dom->conn->privateData;
|
||||
virDomainObjPtr vm = NULL;
|
||||
const char *dom_xml = NULL;
|
||||
const char *dname = NULL;
|
||||
const char *uri = NULL;
|
||||
int ret = -1;
|
||||
|
||||
virCheckFlags(LIBXL_MIGRATION_FLAGS, -1);
|
||||
if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (virTypedParamsGetString(params, nparams,
|
||||
VIR_MIGRATE_PARAM_DEST_XML,
|
||||
&dom_xml) < 0 ||
|
||||
virTypedParamsGetString(params, nparams,
|
||||
VIR_MIGRATE_PARAM_DEST_NAME,
|
||||
&dname) < 0 ||
|
||||
virTypedParamsGetString(params, nparams,
|
||||
VIR_MIGRATE_PARAM_URI,
|
||||
&uri) < 0)
|
||||
|
||||
goto cleanup;
|
||||
|
||||
if (!(vm = libxlDomObjFromDomain(dom)))
|
||||
goto cleanup;
|
||||
|
||||
if (virDomainMigratePerform3ParamsEnsureACL(dom->conn, vm->def) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (libxlDomainMigrationPerform(driver, vm, dom_xml, dconnuri,
|
||||
uri, dname, flags) < 0) {
|
||||
/* Job terminated and vm unlocked if MigrationPerform failed */
|
||||
vm = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
if (vm)
|
||||
virObjectUnlock(vm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static virDomainPtr
|
||||
libxlDomainMigrateFinish3Params(virConnectPtr dconn,
|
||||
virTypedParameterPtr params,
|
||||
int nparams,
|
||||
const char *cookiein ATTRIBUTE_UNUSED,
|
||||
int cookieinlen ATTRIBUTE_UNUSED,
|
||||
char **cookieout ATTRIBUTE_UNUSED,
|
||||
int *cookieoutlen ATTRIBUTE_UNUSED,
|
||||
unsigned int flags,
|
||||
int cancelled)
|
||||
{
|
||||
libxlDriverPrivatePtr driver = dconn->privateData;
|
||||
virDomainObjPtr vm = NULL;
|
||||
const char *dname = NULL;
|
||||
|
||||
virCheckFlags(LIBXL_MIGRATION_FLAGS, NULL);
|
||||
if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0)
|
||||
return NULL;
|
||||
|
||||
if (virTypedParamsGetString(params, nparams,
|
||||
VIR_MIGRATE_PARAM_DEST_NAME,
|
||||
&dname) < 0)
|
||||
return NULL;
|
||||
|
||||
if (!dname ||
|
||||
!(vm = virDomainObjListFindByName(driver->domains, dname))) {
|
||||
/* Migration obviously failed if the domain doesn't exist */
|
||||
virReportError(VIR_ERR_OPERATION_FAILED,
|
||||
_("Migration failed. No domain on destination host "
|
||||
"with matching name '%s'"),
|
||||
NULLSTR(dname));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (virDomainMigrateFinish3ParamsEnsureACL(dconn, vm->def) < 0) {
|
||||
virObjectUnlock(vm);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!virDomainObjIsActive(vm)) {
|
||||
/* Migration failed if domain is inactive */
|
||||
virReportError(VIR_ERR_OPERATION_FAILED,
|
||||
"%s", _("Migration failed. Domain is not running "
|
||||
"on destination host"));
|
||||
virObjectUnlock(vm);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return libxlDomainMigrationFinish(dconn, vm, flags, cancelled);
|
||||
}
|
||||
|
||||
static int
|
||||
libxlDomainMigrateConfirm3Params(virDomainPtr domain,
|
||||
virTypedParameterPtr params,
|
||||
int nparams,
|
||||
const char *cookiein ATTRIBUTE_UNUSED,
|
||||
int cookieinlen ATTRIBUTE_UNUSED,
|
||||
unsigned int flags,
|
||||
int cancelled)
|
||||
{
|
||||
libxlDriverPrivatePtr driver = domain->conn->privateData;
|
||||
virDomainObjPtr vm = NULL;
|
||||
|
||||
virCheckFlags(LIBXL_MIGRATION_FLAGS, -1);
|
||||
if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0)
|
||||
return -1;
|
||||
|
||||
if (!(vm = libxlDomObjFromDomain(domain)))
|
||||
return -1;
|
||||
|
||||
if (virDomainMigrateConfirm3ParamsEnsureACL(domain->conn, vm->def) < 0) {
|
||||
virObjectUnlock(vm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return libxlDomainMigrationConfirm(driver, vm, flags, cancelled);
|
||||
}
|
||||
|
||||
|
||||
static virDriver libxlDriver = {
|
||||
.no = VIR_DRV_LIBXL,
|
||||
@ -4421,6 +4651,11 @@ static virDriver libxlDriver = {
|
||||
.nodeDeviceDetachFlags = libxlNodeDeviceDetachFlags, /* 1.2.3 */
|
||||
.nodeDeviceReAttach = libxlNodeDeviceReAttach, /* 1.2.3 */
|
||||
.nodeDeviceReset = libxlNodeDeviceReset, /* 1.2.3 */
|
||||
.domainMigrateBegin3Params = libxlDomainMigrateBegin3Params, /* 1.2.3 */
|
||||
.domainMigratePrepare3Params = libxlDomainMigratePrepare3Params, /* 1.2.3 */
|
||||
.domainMigratePerform3Params = libxlDomainMigratePerform3Params, /* 1.2.3 */
|
||||
.domainMigrateFinish3Params = libxlDomainMigrateFinish3Params, /* 1.2.3 */
|
||||
.domainMigrateConfirm3Params = libxlDomainMigrateConfirm3Params, /* 1.2.3 */
|
||||
};
|
||||
|
||||
static virStateDriver libxlStateDriver = {
|
||||
|
585
src/libxl/libxl_migration.c
Normal file
585
src/libxl/libxl_migration.c
Normal file
@ -0,0 +1,585 @@
|
||||
/*
|
||||
* libxl_migration.c: methods for handling migration with libxenlight
|
||||
*
|
||||
* Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* Authors:
|
||||
* Jim Fehlig <jfehlig@suse.com>
|
||||
* Chunyan Liu <cyliu@suse.com>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "virlog.h"
|
||||
#include "virerror.h"
|
||||
#include "virconf.h"
|
||||
#include "datatypes.h"
|
||||
#include "virfile.h"
|
||||
#include "viralloc.h"
|
||||
#include "viruuid.h"
|
||||
#include "vircommand.h"
|
||||
#include "virstring.h"
|
||||
#include "virobject.h"
|
||||
#include "rpc/virnetsocket.h"
|
||||
#include "libxl_domain.h"
|
||||
#include "libxl_driver.h"
|
||||
#include "libxl_conf.h"
|
||||
#include "libxl_migration.h"
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_LIBXL
|
||||
|
||||
VIR_LOG_INIT("libxl.libxl_migration");
|
||||
|
||||
typedef struct _libxlMigrationDstArgs {
|
||||
virObject parent;
|
||||
|
||||
virConnectPtr conn;
|
||||
virDomainObjPtr vm;
|
||||
unsigned int flags;
|
||||
|
||||
/* for freeing listen sockets */
|
||||
virNetSocketPtr *socks;
|
||||
size_t nsocks;
|
||||
} libxlMigrationDstArgs;
|
||||
|
||||
static virClassPtr libxlMigrationDstArgsClass;
|
||||
|
||||
static void
|
||||
libxlMigrationDstArgsDispose(void *obj)
|
||||
{
|
||||
libxlMigrationDstArgs *args = obj;
|
||||
|
||||
VIR_FREE(args->socks);
|
||||
}
|
||||
|
||||
static int
|
||||
libxlMigrationDstArgsOnceInit(void)
|
||||
{
|
||||
if (!(libxlMigrationDstArgsClass = virClassNew(virClassForObject(),
|
||||
"libxlMigrationDstArgs",
|
||||
sizeof(libxlMigrationDstArgs),
|
||||
libxlMigrationDstArgsDispose)))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
VIR_ONCE_GLOBAL_INIT(libxlMigrationDstArgs)
|
||||
|
||||
static void
|
||||
libxlDoMigrateReceive(virNetSocketPtr sock,
|
||||
int events ATTRIBUTE_UNUSED,
|
||||
void *opaque)
|
||||
{
|
||||
libxlMigrationDstArgs *args = opaque;
|
||||
virConnectPtr conn = args->conn;
|
||||
virDomainObjPtr vm = args->vm;
|
||||
virNetSocketPtr *socks = args->socks;
|
||||
size_t nsocks = args->nsocks;
|
||||
bool paused = args->flags & VIR_MIGRATE_PAUSED;
|
||||
libxlDriverPrivatePtr driver = conn->privateData;
|
||||
virNetSocketPtr client_sock;
|
||||
int recvfd = -1;
|
||||
size_t i;
|
||||
int ret;
|
||||
|
||||
virNetSocketAccept(sock, &client_sock);
|
||||
if (client_sock == NULL) {
|
||||
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
||||
_("Fail to accept migration connection"));
|
||||
goto cleanup;
|
||||
}
|
||||
VIR_DEBUG("Accepted migration connection\n");
|
||||
recvfd = virNetSocketDupFD(client_sock, true);
|
||||
virObjectUnref(client_sock);
|
||||
|
||||
virObjectLock(vm);
|
||||
ret = libxlDomainStart(driver, vm, paused, recvfd);
|
||||
virObjectUnlock(vm);
|
||||
|
||||
if (ret < 0 && !vm->persistent)
|
||||
virDomainObjListRemove(driver->domains, vm);
|
||||
|
||||
cleanup:
|
||||
/* Remove all listen socks from event handler, and close them. */
|
||||
for (i = 0; i < nsocks; i++) {
|
||||
virNetSocketUpdateIOCallback(socks[i], 0);
|
||||
virNetSocketRemoveIOCallback(socks[i]);
|
||||
virNetSocketClose(socks[i]);
|
||||
virObjectUnref(socks[i]);
|
||||
socks[i] = NULL;
|
||||
}
|
||||
args->nsocks = 0;
|
||||
VIR_FORCE_CLOSE(recvfd);
|
||||
}
|
||||
|
||||
static int
|
||||
libxlDoMigrateSend(libxlDriverPrivatePtr driver,
|
||||
virDomainObjPtr vm,
|
||||
unsigned long flags,
|
||||
int sockfd)
|
||||
{
|
||||
libxlDomainObjPrivatePtr priv;
|
||||
libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
|
||||
virObjectEventPtr event = NULL;
|
||||
int xl_flags = 0;
|
||||
int ret;
|
||||
|
||||
if (flags & VIR_MIGRATE_LIVE)
|
||||
xl_flags = LIBXL_SUSPEND_LIVE;
|
||||
|
||||
priv = vm->privateData;
|
||||
ret = libxl_domain_suspend(priv->ctx, vm->def->id, sockfd,
|
||||
xl_flags, NULL);
|
||||
if (ret != 0) {
|
||||
/* attempt to resume the domain on failure */
|
||||
if (libxl_domain_resume(priv->ctx, vm->def->id, 0, 0) != 0) {
|
||||
VIR_DEBUG("Failed to resume domain following failed migration");
|
||||
virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
|
||||
VIR_DOMAIN_PAUSED_MIGRATION);
|
||||
event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED,
|
||||
VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED);
|
||||
ignore_value(virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm));
|
||||
}
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("Failed to send migration data to destination host"));
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (event)
|
||||
libxlDomainEventQueue(driver, event);
|
||||
virObjectUnref(cfg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
libxlDomainMigrationIsAllowed(virDomainDefPtr def)
|
||||
{
|
||||
/* Migration is not allowed if definition contains any hostdevs */
|
||||
if (def->nhostdevs > 0) {
|
||||
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
||||
_("domain has assigned host devices"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
char *
|
||||
libxlDomainMigrationBegin(virConnectPtr conn,
|
||||
virDomainObjPtr vm,
|
||||
const char *xmlin)
|
||||
{
|
||||
libxlDriverPrivatePtr driver = conn->privateData;
|
||||
libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
|
||||
virDomainDefPtr tmpdef = NULL;
|
||||
virDomainDefPtr def;
|
||||
char *xml = NULL;
|
||||
|
||||
if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (xmlin) {
|
||||
if (!(tmpdef = virDomainDefParseString(xmlin, cfg->caps,
|
||||
driver->xmlopt,
|
||||
1 << VIR_DOMAIN_VIRT_XEN,
|
||||
VIR_DOMAIN_XML_INACTIVE)))
|
||||
goto endjob;
|
||||
|
||||
if (!libxlDomainDefCheckABIStability(driver, vm->def, tmpdef))
|
||||
goto endjob;
|
||||
|
||||
def = tmpdef;
|
||||
} else {
|
||||
def = vm->def;
|
||||
}
|
||||
|
||||
if (!libxlDomainMigrationIsAllowed(def))
|
||||
goto endjob;
|
||||
|
||||
xml = virDomainDefFormat(def, VIR_DOMAIN_XML_SECURE);
|
||||
|
||||
cleanup:
|
||||
if (vm)
|
||||
virObjectUnlock(vm);
|
||||
|
||||
virDomainDefFree(tmpdef);
|
||||
virObjectUnref(cfg);
|
||||
return xml;
|
||||
|
||||
endjob:
|
||||
if (!libxlDomainObjEndJob(driver, vm))
|
||||
vm = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
virDomainDefPtr
|
||||
libxlDomainMigrationPrepareDef(libxlDriverPrivatePtr driver,
|
||||
const char *dom_xml,
|
||||
const char *dname)
|
||||
{
|
||||
libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
|
||||
virDomainDefPtr def;
|
||||
char *name = NULL;
|
||||
|
||||
if (!dom_xml) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("no domain XML passed"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(def = virDomainDefParseString(dom_xml, cfg->caps, driver->xmlopt,
|
||||
1 << VIR_DOMAIN_VIRT_XEN,
|
||||
VIR_DOMAIN_XML_INACTIVE)))
|
||||
goto cleanup;
|
||||
|
||||
if (dname) {
|
||||
name = def->name;
|
||||
if (VIR_STRDUP(def->name, dname) < 0) {
|
||||
virDomainDefFree(def);
|
||||
def = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
virObjectUnref(cfg);
|
||||
VIR_FREE(name);
|
||||
return def;
|
||||
}
|
||||
|
||||
int
|
||||
libxlDomainMigrationPrepare(virConnectPtr dconn,
|
||||
virDomainDefPtr def,
|
||||
const char *uri_in,
|
||||
char **uri_out,
|
||||
unsigned int flags)
|
||||
{
|
||||
libxlDriverPrivatePtr driver = dconn->privateData;
|
||||
virDomainObjPtr vm = NULL;
|
||||
char *hostname = NULL;
|
||||
unsigned short port;
|
||||
char portstr[100];
|
||||
virURIPtr uri = NULL;
|
||||
virNetSocketPtr *socks = NULL;
|
||||
size_t nsocks = 0;
|
||||
int nsocks_listen = 0;
|
||||
libxlMigrationDstArgs *args;
|
||||
size_t i;
|
||||
int ret = -1;
|
||||
|
||||
if (!(vm = virDomainObjListAdd(driver->domains, def,
|
||||
driver->xmlopt,
|
||||
VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
|
||||
VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
|
||||
NULL)))
|
||||
goto cleanup;
|
||||
|
||||
/* Create socket connection to receive migration data */
|
||||
if (!uri_in) {
|
||||
if ((hostname = virGetHostname()) == NULL)
|
||||
goto cleanup;
|
||||
|
||||
if (STRPREFIX(hostname, "localhost")) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("hostname on destination resolved to localhost,"
|
||||
" but migration requires an FQDN"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (virAsprintf(uri_out, "tcp://%s:%d", hostname, port) < 0)
|
||||
goto cleanup;
|
||||
} else {
|
||||
if (!(STRPREFIX(uri_in, "tcp://"))) {
|
||||
/* not full URI, add prefix tcp:// */
|
||||
char *tmp;
|
||||
if (virAsprintf(&tmp, "tcp://%s", uri_in) < 0)
|
||||
goto cleanup;
|
||||
uri = virURIParse(tmp);
|
||||
VIR_FREE(tmp);
|
||||
} else {
|
||||
uri = virURIParse(uri_in);
|
||||
}
|
||||
|
||||
if (uri == NULL) {
|
||||
virReportError(VIR_ERR_INVALID_ARG,
|
||||
_("unable to parse URI: %s"),
|
||||
uri_in);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (uri->server == NULL) {
|
||||
virReportError(VIR_ERR_INVALID_ARG,
|
||||
_("missing host in migration URI: %s"),
|
||||
uri_in);
|
||||
goto cleanup;
|
||||
} else {
|
||||
hostname = uri->server;
|
||||
}
|
||||
|
||||
if (uri->port == 0) {
|
||||
if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0)
|
||||
goto cleanup;
|
||||
|
||||
} else {
|
||||
port = uri->port;
|
||||
}
|
||||
|
||||
if (virAsprintf(uri_out, "tcp://%s:%d", hostname, port) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
snprintf(portstr, sizeof(portstr), "%d", port);
|
||||
|
||||
if (virNetSocketNewListenTCP(hostname, portstr, &socks, &nsocks) < 0) {
|
||||
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
||||
_("Fail to create socket for incoming migration"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (libxlMigrationDstArgsInitialize() < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (!(args = virObjectNew(libxlMigrationDstArgsClass)))
|
||||
goto cleanup;
|
||||
|
||||
args->conn = dconn;
|
||||
args->vm = vm;
|
||||
args->flags = flags;
|
||||
args->socks = socks;
|
||||
args->nsocks = nsocks;
|
||||
|
||||
for (i = 0; i < nsocks; i++) {
|
||||
if (virNetSocketSetBlocking(socks[i], true) < 0)
|
||||
continue;
|
||||
|
||||
if (virNetSocketListen(socks[i], 1) < 0)
|
||||
continue;
|
||||
|
||||
if (virNetSocketAddIOCallback(socks[i],
|
||||
VIR_EVENT_HANDLE_READABLE,
|
||||
libxlDoMigrateReceive,
|
||||
args,
|
||||
virObjectFreeCallback) < 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Successfully added sock to event loop. Take a ref on args to
|
||||
* ensure it is not freed until sock is removed from the event loop.
|
||||
* Ref is dropped in virObjectFreeCallback after being removed
|
||||
* from the event loop.
|
||||
*/
|
||||
virObjectRef(args);
|
||||
nsocks_listen++;
|
||||
}
|
||||
|
||||
/* Done with args in this function, drop reference */
|
||||
virObjectUnref(args);
|
||||
|
||||
if (!nsocks_listen)
|
||||
goto cleanup;
|
||||
|
||||
ret = 0;
|
||||
goto done;
|
||||
|
||||
cleanup:
|
||||
for (i = 0; i < nsocks; i++) {
|
||||
virNetSocketClose(socks[i]);
|
||||
virObjectUnref(socks[i]);
|
||||
}
|
||||
|
||||
done:
|
||||
virURIFree(uri);
|
||||
if (vm)
|
||||
virObjectUnlock(vm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
libxlDomainMigrationPerform(libxlDriverPrivatePtr driver,
|
||||
virDomainObjPtr vm,
|
||||
const char *dom_xml ATTRIBUTE_UNUSED,
|
||||
const char *dconnuri ATTRIBUTE_UNUSED,
|
||||
const char *uri_str,
|
||||
const char *dname ATTRIBUTE_UNUSED,
|
||||
unsigned int flags)
|
||||
{
|
||||
char *hostname = NULL;
|
||||
unsigned short port = 0;
|
||||
char portstr[100];
|
||||
virURIPtr uri = NULL;
|
||||
virNetSocketPtr sock;
|
||||
int sockfd = -1;
|
||||
int saved_errno = EINVAL;
|
||||
int ret = -1;
|
||||
|
||||
/* parse dst host:port from uri */
|
||||
uri = virURIParse(uri_str);
|
||||
if (uri == NULL || uri->server == NULL || uri->port == 0)
|
||||
goto cleanup;
|
||||
|
||||
hostname = uri->server;
|
||||
port = uri->port;
|
||||
snprintf(portstr, sizeof(portstr), "%d", port);
|
||||
|
||||
/* socket connect to dst host:port */
|
||||
if (virNetSocketNewConnectTCP(hostname, portstr, &sock) < 0) {
|
||||
virReportSystemError(saved_errno,
|
||||
_("unable to connect to '%s:%s'"),
|
||||
hostname, portstr);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (virNetSocketSetBlocking(sock, true) < 0) {
|
||||
virObjectUnref(sock);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
sockfd = virNetSocketDupFD(sock, true);
|
||||
virObjectUnref(sock);
|
||||
|
||||
/* suspend vm and send saved data to dst through socket fd */
|
||||
virObjectUnlock(vm);
|
||||
ret = libxlDoMigrateSend(driver, vm, flags, sockfd);
|
||||
virObjectLock(vm);
|
||||
|
||||
cleanup:
|
||||
/* If failure, terminate the job started in MigrationBegin */
|
||||
if (ret == -1) {
|
||||
if (libxlDomainObjEndJob(driver, vm))
|
||||
virObjectUnlock(vm);
|
||||
}
|
||||
VIR_FORCE_CLOSE(sockfd);
|
||||
virURIFree(uri);
|
||||
return ret;
|
||||
}
|
||||
|
||||
virDomainPtr
|
||||
libxlDomainMigrationFinish(virConnectPtr dconn,
|
||||
virDomainObjPtr vm,
|
||||
unsigned int flags,
|
||||
int cancelled)
|
||||
{
|
||||
libxlDriverPrivatePtr driver = dconn->privateData;
|
||||
libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
|
||||
libxlDomainObjPrivatePtr priv = vm->privateData;
|
||||
virObjectEventPtr event = NULL;
|
||||
virDomainPtr dom = NULL;
|
||||
|
||||
virPortAllocatorRelease(driver->migrationPorts, priv->migrationPort);
|
||||
priv->migrationPort = 0;
|
||||
|
||||
if (cancelled)
|
||||
goto cleanup;
|
||||
|
||||
if (!(flags & VIR_MIGRATE_PAUSED)) {
|
||||
if (libxl_domain_unpause(priv->ctx, vm->def->id) != 0) {
|
||||
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
||||
_("Failed to unpause domain"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
|
||||
VIR_DOMAIN_RUNNING_MIGRATED);
|
||||
event = virDomainEventLifecycleNewFromObj(vm,
|
||||
VIR_DOMAIN_EVENT_RESUMED,
|
||||
VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
|
||||
} else {
|
||||
virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
|
||||
event = virDomainEventLifecycleNewFromObj(vm,
|
||||
VIR_DOMAIN_EVENT_SUSPENDED,
|
||||
VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
|
||||
}
|
||||
|
||||
if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
|
||||
goto cleanup;
|
||||
|
||||
dom = virGetDomain(dconn, vm->def->name, vm->def->uuid);
|
||||
|
||||
if (dom == NULL) {
|
||||
libxl_domain_destroy(priv->ctx, vm->def->id, NULL);
|
||||
libxlDomainCleanup(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED);
|
||||
event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
|
||||
VIR_DOMAIN_EVENT_STOPPED_FAILED);
|
||||
libxlDomainEventQueue(driver, event);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (event)
|
||||
libxlDomainEventQueue(driver, event);
|
||||
if (vm)
|
||||
virObjectUnlock(vm);
|
||||
virObjectUnref(cfg);
|
||||
return dom;
|
||||
}
|
||||
|
||||
int
|
||||
libxlDomainMigrationConfirm(libxlDriverPrivatePtr driver,
|
||||
virDomainObjPtr vm,
|
||||
unsigned int flags,
|
||||
int cancelled)
|
||||
{
|
||||
libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
|
||||
libxlDomainObjPrivatePtr priv = vm->privateData;
|
||||
virObjectEventPtr event = NULL;
|
||||
int ret = -1;
|
||||
|
||||
if (cancelled) {
|
||||
if (libxl_domain_resume(priv->ctx, vm->def->id, 1, 0) == 0) {
|
||||
ret = 0;
|
||||
} else {
|
||||
VIR_DEBUG("Unable to resume domain '%s' after failed migration",
|
||||
vm->def->name);
|
||||
virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
|
||||
VIR_DOMAIN_PAUSED_MIGRATION);
|
||||
event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED,
|
||||
VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED);
|
||||
ignore_value(virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm));
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
libxl_domain_destroy(priv->ctx, vm->def->id, NULL);
|
||||
libxlDomainCleanup(driver, vm, VIR_DOMAIN_SHUTOFF_MIGRATED);
|
||||
event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
|
||||
VIR_DOMAIN_EVENT_STOPPED_MIGRATED);
|
||||
|
||||
VIR_DEBUG("Domain '%s' successfully migrated", vm->def->name);
|
||||
|
||||
if (flags & VIR_MIGRATE_UNDEFINE_SOURCE)
|
||||
virDomainDeleteConfig(cfg->configDir, cfg->autostartDir, vm);
|
||||
|
||||
if (!vm->persistent || (flags & VIR_MIGRATE_UNDEFINE_SOURCE))
|
||||
virDomainObjListRemove(driver->domains, vm);
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
if (!libxlDomainObjEndJob(driver, vm))
|
||||
vm = NULL;
|
||||
if (event)
|
||||
libxlDomainEventQueue(driver, event);
|
||||
if (vm)
|
||||
virObjectUnlock(vm);
|
||||
virObjectUnref(cfg);
|
||||
return ret;
|
||||
}
|
79
src/libxl/libxl_migration.h
Normal file
79
src/libxl/libxl_migration.h
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* libxl_migration.h: methods for handling migration with libxenlight
|
||||
*
|
||||
* Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* Authors:
|
||||
* Jim Fehlig <jfehlig@suse.com>
|
||||
*/
|
||||
|
||||
#ifndef LIBXL_MIGRATION_H
|
||||
# define LIBXL_MIGRATION_H
|
||||
|
||||
# include "libxl_conf.h"
|
||||
|
||||
# define LIBXL_MIGRATION_FLAGS \
|
||||
(VIR_MIGRATE_LIVE | \
|
||||
VIR_MIGRATE_UNDEFINE_SOURCE | \
|
||||
VIR_MIGRATE_PAUSED)
|
||||
|
||||
/* All supported migration parameters and their types. */
|
||||
# define LIBXL_MIGRATION_PARAMETERS \
|
||||
VIR_MIGRATE_PARAM_URI, VIR_TYPED_PARAM_STRING, \
|
||||
VIR_MIGRATE_PARAM_DEST_NAME, VIR_TYPED_PARAM_STRING, \
|
||||
VIR_MIGRATE_PARAM_DEST_XML, VIR_TYPED_PARAM_STRING, \
|
||||
NULL
|
||||
|
||||
char *
|
||||
libxlDomainMigrationBegin(virConnectPtr conn,
|
||||
virDomainObjPtr vm,
|
||||
const char *xmlin);
|
||||
|
||||
virDomainDefPtr
|
||||
libxlDomainMigrationPrepareDef(libxlDriverPrivatePtr driver,
|
||||
const char *dom_xml,
|
||||
const char *dname);
|
||||
|
||||
int
|
||||
libxlDomainMigrationPrepare(virConnectPtr dconn,
|
||||
virDomainDefPtr def,
|
||||
const char *uri_in,
|
||||
char **uri_out,
|
||||
unsigned int flags);
|
||||
|
||||
int
|
||||
libxlDomainMigrationPerform(libxlDriverPrivatePtr driver,
|
||||
virDomainObjPtr vm,
|
||||
const char *dom_xml,
|
||||
const char *dconnuri,
|
||||
const char *uri_str,
|
||||
const char *dname,
|
||||
unsigned int flags);
|
||||
|
||||
virDomainPtr
|
||||
libxlDomainMigrationFinish(virConnectPtr dconn,
|
||||
virDomainObjPtr vm,
|
||||
unsigned int flags,
|
||||
int cancelled);
|
||||
|
||||
int
|
||||
libxlDomainMigrationConfirm(libxlDriverPrivatePtr driver,
|
||||
virDomainObjPtr vm,
|
||||
unsigned int flags,
|
||||
int cancelled);
|
||||
|
||||
#endif /* LIBXL_DRIVER_H */
|
Loading…
x
Reference in New Issue
Block a user