This patch has resulted in a new Coverity warnings (looking at them was just lower on my list of things to do lately)... Anyway - see libxlDoMigrateReceive() and libxlDomainMigrationFinish() for the details... John On 06/04/2014 04:35 PM, Jim Fehlig wrote: > 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@xxxxxxxx> > --- > po/POTFILES.in | 1 + > src/Makefile.am | 3 +- > src/libxl/libxl_conf.h | 6 + > src/libxl/libxl_domain.h | 1 + > src/libxl/libxl_driver.c | 235 ++++++++++++++++++ > src/libxl/libxl_migration.c | 585 ++++++++++++++++++++++++++++++++++++++++++++ > src/libxl/libxl_migration.h | 79 ++++++ > 7 files changed, 909 insertions(+), 1 deletion(-) > > diff --git a/po/POTFILES.in b/po/POTFILES.in > index cff92d9..2ee7225 100644 > --- a/po/POTFILES.in > +++ b/po/POTFILES.in > @@ -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 > diff --git a/src/Makefile.am b/src/Makefile.am > index d82ca26..01af164 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -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 \ > diff --git a/src/libxl/libxl_conf.h b/src/libxl/libxl_conf.h > index 433d6da..6aa36d2 100644 > --- a/src/libxl/libxl_conf.h > +++ b/src/libxl/libxl_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; > }; > diff --git a/src/libxl/libxl_domain.h b/src/libxl/libxl_domain.h > index 6939008..f459fdf 100644 > --- a/src/libxl/libxl_domain.h > +++ b/src/libxl/libxl_domain.h > @@ -69,6 +69,7 @@ struct _libxlDomainObjPrivate { > virChrdevsPtr devs; > libxl_evgen_domain_death *deathW; > libxlDriverPrivatePtr driver; > + unsigned short migrationPort; > > struct libxlDomainJobObj job; > }; > diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c > index 515d5c9..9feacb1 100644 > --- a/src/libxl/libxl_driver.c > +++ b/src/libxl/libxl_driver.c > @@ -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 = { > diff --git a/src/libxl/libxl_migration.c b/src/libxl/libxl_migration.c > new file mode 100644 > index 0000000..9fe904e > --- /dev/null > +++ b/src/libxl/libxl_migration.c > @@ -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@xxxxxxxx> > + * Chunyan Liu <cyliu@xxxxxxxx> > + */ > + > +#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); (1) Event check_return: Calling "virNetSocketAccept" without checking return value (as is done elsewhere 5 out of 6 times). > + 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; The 'vm' is dereferenced here without checking for !vm, although down below in the cleanup: section there is a "if (vm)" done. Coverity throws out the following: (1) Event deref_ptr: Directly dereferencing pointer "vm". > + 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); (2) Event check_after_deref: Null-checking "vm" suggests that it may be null, but it has already been dereferenced on all paths leading to the check. > + 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; > +} > diff --git a/src/libxl/libxl_migration.h b/src/libxl/libxl_migration.h > new file mode 100644 > index 0000000..aab96f5 > --- /dev/null > +++ b/src/libxl/libxl_migration.h > @@ -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@xxxxxxxx> > + */ > + > +#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 */ > -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list