[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH V3] libxl: add migration support
Opps, forgot --subject-prefix="PATCH V3" when sending this patch... Regards, Jim 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> > --- > > V3 of patch to add migration support to the libxl driver. V2 is here > > https://www.redhat.com/archives/libvir-list/2014-March/msg00880.html > > Patches 1-12 in the original series have been pushed, leaving only > this patch to complete the migration support. > > This version adds a simple, extensible messaging protocol to coordinate > transfer of migration data between libxl hosts. Michal Privoznik > noted the even simpler protocol in V2 was not extensible, which in the > end was a good point IMO so I've tried to address that with V3. > > Comments welcome. Thanks! > > 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 | 221 +++++++++++ > src/libxl/libxl_migration.c | 920 > ++++++++++++++++++++++++++++++++++++++++++++ > src/libxl/libxl_migration.h | 78 ++++ > 7 files changed, 1229 insertions(+), 1 deletion(-) > > diff --git a/po/POTFILES.in b/po/POTFILES.in > index 122b853..5618631 100644 > --- a/po/POTFILES.in > +++ b/po/POTFILES.in > @@ -73,6 +73,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/node_device/node_device_driver.c > diff --git a/src/Makefile.am b/src/Makefile.am > index 21d56fc..f0dd4ae 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -702,7 +702,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 24e1720..b798567 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 979ce2a..9d48049 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 a6ae8a1..acf68b8 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); > @@ -296,6 +298,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; > > @@ -4120,6 +4129,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; > @@ -4298,6 +4308,212 @@ 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) < 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) > + 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))) { > + virReportError(VIR_ERR_NO_DOMAIN, > + _("no domain with matching name '%s'"), > + NULLSTR(dname)); > + return NULL; > + } > + > + if (virDomainMigrateFinish3ParamsEnsureACL(dconn, vm->def) < 0) { > + 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, > @@ -4388,6 +4604,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..4b74ef4 > --- /dev/null > +++ b/src/libxl/libxl_migration.c > @@ -0,0 +1,920 @@ > +/* > + * 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 "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"); > + > +#define LIBXL_MIGRATION_PROTO_VERSION 1 > + > +typedef struct _libxlMigrateReceiveArgs { > + virConnectPtr conn; > + virDomainObjPtr vm; > + > + /* for freeing listen sockets */ > + virNetSocketPtr *socks; > + size_t nsocks; > +} libxlMigrateReceiveArgs; > + > +/* > + * For future extensibility, a simple messaging protocol used to send > migration > + * data between libxl hosts. The message is encapsulated in json and > currently > + * includes the following entries: > + * > + * {"libvirt-libxl-mig-msg" : > + * {"version" : $ver}, > + * {"state" : $state}, > + * {"status" : $status} > + * } > + * > + * Possible $state values are "negotiate-version", "send-binary-data", > + * "sending-binary-data", "received-binary-data", "done", and "error". > + * > + * Migration between source and destination libxl hosts is performed with the > + * following message exchange: > + * > + * - src->dst: connect > + * - dst->src: state="negotiate-version", > version=LIBXL_MIGRATION_PROTO_VERSION > + * - src->dst: state-"negotiate-version", > + * version=min(dst ver, LIBXL_MIGRATION_PROTO_VERSION) > + * - dst->src: state="send-binary-data", version=negotiatedversion > + * - src->dst: state="sending-binary-data", version=negotiatedversion > + * _ src->dst: binary migration data > + * - dst->src: state="received-binary-data", version=negotiatedversion > + * - src->dst: state="done", version=negotiatedversion > + * > + */ > + > +static virJSONValuePtr > +libxlMigrationMsgNew(const char *state) > +{ > + virJSONValuePtr msg; > + virJSONValuePtr body; > + > + if (!(msg = virJSONValueNewObject())) > + return NULL; > + > + if (!(body = virJSONValueNewObject())) { > + virJSONValueFree(msg); > + return NULL; > + } > + > + virJSONValueObjectAppendNumberInt(body, "version", > + LIBXL_MIGRATION_PROTO_VERSION); > + virJSONValueObjectAppendString(body, "state", state); > + virJSONValueObjectAppendNumberInt(body, "status", 0); > + > + virJSONValueObjectAppend(msg, "libvirt-libxl-mig-msg", body); > + > + return msg; > +} > + > +static bool > +libxlMigrationMsgIsState(virJSONValuePtr message, const char *state) > +{ > + virJSONValuePtr body; > + const char *msg_state; > + > + if (!(body = virJSONValueObjectGet(message, "libvirt-libxl-mig-msg"))) > + return false; > + > + msg_state = virJSONValueObjectGetString(body, "state"); > + if (!msg_state || STRNEQ(msg_state, state)) > + return false; > + > + return true; > +} > + > +static int > +libxlMigrationMsgSetState(virJSONValuePtr message, const char *state) > +{ > + virJSONValuePtr body; > + > + if (!(body = virJSONValueObjectGet(message, "libvirt-libxl-mig-msg"))) > + return -1; > + > + virJSONValueObjectRemoveKey(body, "state", NULL); > + virJSONValueObjectAppendString(body, "state", state); > + > + return 0; > +} > + > + > +static int > +libxlMigrationMsgSend(int fd, virJSONValuePtr message, int status) > +{ > + int ret = -1; > + virJSONValuePtr body; > + int len; > + char *msgstr; > + > + if (!(body = virJSONValueObjectGet(message, "libvirt-libxl-mig-msg"))) > + return -1; > + > + virJSONValueObjectRemoveKey(body, "status", NULL); > + virJSONValueObjectAppendNumberInt(body, "status", status); > + > + if (!(msgstr = virJSONValueToString(message, false))) > + return -1; > + > + VIR_DEBUG("Sending migration message %s", msgstr); > + len = strlen(msgstr) + 1; > + if (safewrite(fd, msgstr, len) != len) { > + virReportError(VIR_ERR_OPERATION_FAILED, "%s", > + _("Failed to send migration message")); > + goto cleanup; > + } > + > + ret = 0; > + > + cleanup: > + VIR_FREE(msgstr); > + return ret; > +} > + > +static virJSONValuePtr > +libxlMigrationMsgReceive(int fd) > +{ > + char buf[512]; > + int ret; > + virJSONValuePtr msg = NULL; > + virJSONValuePtr body; > + int status; > + size_t i; > + > + for (i = 0; i < sizeof(buf);) { > + ret = saferead(fd, &(buf[i]), 1); > + if (ret == -1 && errno != EAGAIN) > + goto error; > + if (ret == 1) { > + if (buf[i] == '\0') > + break; > + i++; > + } > + } > + > + VIR_DEBUG("Received migration message %s", buf); > + if (!(msg = virJSONValueFromString(buf))) > + return NULL; > + > + if (!(body = virJSONValueObjectGet(msg, "libvirt-libxl-mig-msg"))) > + goto error; > + > + if (virJSONValueObjectGetNumberInt(body, "status", &status) < 0) > + goto error; > + > + if (status != 0) > + goto error; > + > + return msg; > + > + error: > + virReportError(VIR_ERR_OPERATION_FAILED, "%s", > + _("Failed to receive migration message")); > + virJSONValueFree(msg); > + return NULL; > +} > + > +static int > +libxlMigrationSrcNegotiate(int fd) > +{ > + int ret = -1; > + virJSONValuePtr msg; > + virJSONValuePtr body; > + int ver; > + > + if (!(msg = libxlMigrationMsgReceive(fd))) > + return -1; > + > + if (!libxlMigrationMsgIsState(msg, "negotiate-version")) > + goto cleanup; > + /* > + * ACK by returning the message, with version set to > + * min(dest ver, src ver) > + */ > + if (!(body = virJSONValueObjectGet(msg, "libvirt-libxl-mig-msg"))) > + goto cleanup; > + > + if (virJSONValueObjectGetNumberInt(body, "version", &ver) < 0) > + goto cleanup; > + if (ver > LIBXL_MIGRATION_PROTO_VERSION) { > + virJSONValueObjectRemoveKey(body, "version", NULL); > + virJSONValueObjectAppendNumberInt(body, > + "version", > + LIBXL_MIGRATION_PROTO_VERSION); > + } > + > + if (libxlMigrationMsgSend(fd, msg, 0) < 0) > + goto cleanup; > + > + ret = 0; > + > + cleanup: > + virJSONValueFree(msg); > + return ret; > +} > + > +static int > +libxlMigrationDstNegotiate(int fd, virJSONValuePtr *message) > +{ > + virJSONValuePtr msg; > + > + if (!(msg = libxlMigrationMsgNew("negotiate-version"))) > + return -1; > + > + if (libxlMigrationMsgSend(fd, msg, 0) < 0) { > + virJSONValueFree(msg); > + return -1; > + } > + > + /* > + * Receive ACK. src set version=min(dst ver, highest src ver), > + * which is the negotiated version. Use this message with > + * negotiated version throughout the transaction. > + */ > + virJSONValueFree(msg); > + if (!(msg = libxlMigrationMsgReceive(fd))) > + return -1; > + > + *message = msg; > + return 0; > +} > + > +static int > +libxlMigrationSrcReady(int fd) > +{ > + int ret = -1; > + virJSONValuePtr msg; > + > + if (!(msg = libxlMigrationMsgReceive(fd))) > + return -1; > + > + if (!libxlMigrationMsgIsState(msg, "send-binary-data")) > + goto cleanup; > + > + /* ACK by returning the message with state sending */ > + libxlMigrationMsgSetState(msg, "sending-binary-data"); > + if (libxlMigrationMsgSend(fd, msg, 0) < 0) > + goto cleanup; > + > + ret = 0; > + > + cleanup: > + virJSONValueFree(msg); > + return ret; > +} > + > +static int > +libxlMigrationDstReady(int fd, virJSONValuePtr msg) > +{ > + int ret = -1; > + virJSONValuePtr tmp = NULL; > + > + libxlMigrationMsgSetState(msg, "send-binary-data"); > + if (libxlMigrationMsgSend(fd, msg, 0) < 0) > + return -1; > + > + /* Receive ACK, state sending */ > + if (!(tmp = libxlMigrationMsgReceive(fd))) > + return -1; > + if (!libxlMigrationMsgIsState(tmp, "sending-binary-data")) > + goto cleanup; > + > + ret = 0; > + > + cleanup: > + virJSONValueFree(tmp); > + return ret; > +} > + > +static int > +libxlMigrationSrcDone(int fd) > +{ > + int ret = -1; > + virJSONValuePtr msg; > + > + if (!(msg = libxlMigrationMsgReceive(fd))) > + return -1; > + > + if (!libxlMigrationMsgIsState(msg, "received-binary-data")) > + goto cleanup; > + > + /* ACK by returning the message with state done */ > + libxlMigrationMsgSetState(msg, "done"); > + if (libxlMigrationMsgSend(fd, msg, 0) < 0) > + goto cleanup; > + > + ret = 0; > + > + cleanup: > + virJSONValueFree(msg); > + return ret; > +} > + > +static int > +libxlMigrationDestDone(int fd, virJSONValuePtr msg) > +{ > + int ret = -1; > + virJSONValuePtr tmp; > + > + libxlMigrationMsgSetState(msg, "received-binary-data"); > + if (libxlMigrationMsgSend(fd, msg, 0) < 0) > + return -1; > + > + /* Receive ACK, state done */ > + if (!(tmp = libxlMigrationMsgReceive(fd))) > + return -1; > + if (!libxlMigrationMsgIsState(tmp, "done")) > + goto cleanup; > + > + ret = 0; > + > + cleanup: > + virJSONValueFree(tmp); > + return ret; > +} > + > +static void > +libxlMigrationSrcFailed(int fd, int status) > +{ > + virJSONValuePtr msg; > + > + if (!(msg = libxlMigrationMsgNew("error"))) > + return; > + libxlMigrationMsgSend(fd, msg, status); > + virJSONValueFree(msg); > +} > + > +static void > +libxlMigrationDstFailed(int fd, virJSONValuePtr msg, int status) > +{ > + libxlMigrationMsgSetState(msg, "error"); > + libxlMigrationMsgSend(fd, msg, status); > +} > + > +static void > +libxlDoMigrateReceive(virNetSocketPtr sock, > + int events ATTRIBUTE_UNUSED, > + void *opaque) > +{ > + libxlMigrateReceiveArgs *data = opaque; > + virConnectPtr conn = data->conn; > + virDomainObjPtr vm = data->vm; > + libxlDomainObjPrivatePtr priv = vm->privateData; > + virNetSocketPtr *socks = data->socks; > + size_t nsocks = data->nsocks; > + libxlDriverPrivatePtr driver = conn->privateData; > + virNetSocketPtr client_sock; > + virJSONValuePtr mig_msg = NULL; > + int recvfd; > + 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); > + > + if (libxlMigrationDstNegotiate(recvfd, &mig_msg) < 0) > + goto cleanup; > + > + if (libxlMigrationDstReady(recvfd, mig_msg) < 0) > + goto cleanup; > + > + virObjectLock(vm); > + ret = libxlDomainStart(driver, vm, false, recvfd); > + virObjectUnlock(vm); > + > + if (ret < 0) { > + libxlMigrationDstFailed(recvfd, mig_msg, ret); > + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", > + _("Failed to restore domain with libxenlight")); > + if (!vm->persistent) > + virDomainObjListRemove(driver->domains, vm); > + goto cleanup; > + } > + > + if (libxlMigrationDestDone(recvfd, mig_msg) < 0) { > + virReportError(VIR_ERR_OPERATION_FAILED, "%s", > + _("Failed to notify sender that migration > completed")); > + goto cleanup_dom; > + } > + > + /* 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]); > + } > + VIR_FREE(socks); > + goto cleanup; > + > + cleanup_dom: > + libxl_domain_destroy(priv->ctx, vm->def->id, NULL); > + vm->def->id = -1; > + if (!vm->persistent) > + virDomainObjListRemove(driver->domains, vm); > + > + cleanup: > + VIR_FORCE_CLOSE(recvfd); > + virJSONValueFree(mig_msg); > + VIR_FREE(opaque); > + return; > +} > + > +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 = -1; > + > + if (flags & VIR_MIGRATE_LIVE) > + xl_flags = LIBXL_SUSPEND_LIVE; > + > + priv = vm->privateData; > + > + if (libxlMigrationSrcNegotiate(sockfd) < 0) > + goto cleanup; > + > + if (libxlMigrationSrcReady(sockfd) < 0) > + goto cleanup; > + > + if (libxl_domain_suspend(priv->ctx, vm->def->id, > + sockfd, xl_flags, NULL) != 0) { > + libxlMigrationSrcFailed(sockfd, ret); > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to save domain '%d' with libxenlight"), > + vm->def->id); > + goto cleanup; > + } > + > + if (libxlMigrationSrcDone(sockfd) < 0) { > + if (libxl_domain_resume(priv->ctx, vm->def->id, 0, 0) != 0) { > + VIR_DEBUG("Failed to resume domain '%d' with libxenlight", > + vm->def->id); > + virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, > + VIR_DOMAIN_PAUSED_MIGRATION); > + event = virDomainEventLifecycleNewFromObj(vm, > VIR_DOMAIN_EVENT_SUSPENDED, > + > VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED); > + if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) > + goto cleanup; > + } > + goto cleanup; > + } > + > + ret = 0; > + > + 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; > + > + 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) > +{ > + 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; > + libxlMigrateReceiveArgs *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 (VIR_ALLOC(args) < 0) > + goto cleanup; > + > + args->conn = dconn; > + args->vm = vm; > + 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], > + 0, > + libxlDoMigrateReceive, > + args, > + NULL) < 0) { > + continue; > + } > + > + virNetSocketUpdateIOCallback(socks[i], VIR_EVENT_HANDLE_READABLE); > + nsocks_listen++; > + } > + > + if (!nsocks_listen) > + goto cleanup; > + > + ret = 0; > + goto done; > + > + cleanup: > + for (i = 0; i < nsocks; i++) { > + virNetSocketClose(socks[i]); > + virObjectUnref(socks[i]); > + } > + VIR_FREE(socks); > + > + 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: > + 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) { > + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", > + _("migration failed, attempting to resume on source > host")); > + 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..63d8bdc > --- /dev/null > +++ b/src/libxl/libxl_migration.h > @@ -0,0 +1,78 @@ > +/* > + * 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); > + > +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 */ > _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |