> --- > src/libxl/libxl_conf.h | 4 + > src/libxl/libxl_driver.c | 641 > ++++++++++++++++++++++++++++++++++++++++++++++ > src/libxl/libxl_driver.h | 5 + > 3 files changed, 650 insertions(+), 0 deletions(-) > > diff --git a/src/libxl/libxl_conf.h b/src/libxl/libxl_conf.h > index 8ba0ee4..2041cc2 100644 > --- a/src/libxl/libxl_conf.h > +++ b/src/libxl/libxl_conf.h > @@ -41,6 +41,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 > + there is a overlap between vnc and migration port. althrought, it will try next port in virPortAllocatorAcquire after bind fail. > # define LIBXL_CONFIG_DIR SYSCONFDIR "/libvirt/libxl" > # define LIBXL_AUTOSTART_DIR LIBXL_CONFIG_DIR "/autostart" > # define LIBXL_STATE_DIR LOCALSTATEDIR "/run/libvirt/libxl" > @@ -109,6 +112,7 @@ struct _libxlDriverPrivate { > > /* Immutable pointer, self-locking APIs */ > virPortAllocatorPtr reservedVNCPorts; > + virPortAllocatorPtr reservedMigPorts; > > /* Immutable pointer, lockless APIs*/ > virSysinfoDefPtr hostsysinfo; > diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c > index e2a6d44..93b7153 100644 > --- a/src/libxl/libxl_driver.c > +++ b/src/libxl/libxl_driver.c > @@ -32,6 +32,12 @@ > #include <libxl_utils.h> > #include <fcntl.h> > #include <regex.h> > +#include <stdlib.h> > +#include <string.h> > +#include <sys/types.h> > +#include <sys/socket.h> > +#include <arpa/inet.h> > +#include <netdb.h> > > #include "internal.h" > #include "virlog.h" > @@ -52,6 +58,7 @@ > #include "virsysinfo.h" > #include "viraccessapicheck.h" > #include "viratomic.h" > +#include "rpc/virnetsocket.h" > > #define VIR_FROM_THIS VIR_FROM_LIBXL > > @@ -69,6 +76,20 @@ > > static libxlDriverPrivatePtr libxl_driver = NULL; > > +typedef struct _libxlMigrateReceiveArgs { > + virConnectPtr conn; > + virDomainObjPtr vm; > + > + /* for freeing listen sockets */ > + virNetSocketPtr *socks; > + size_t nsocks; > +} libxlMigrateReceiveArgs; > + > +static const char libxlMigrateReceiverReady[]= > + "libvirt libxl migration receiver ready, send binary domain data"; > +static const char libxlMigrateReceiverFinish[]= > + "domain received, ready to unpause"; > + > /* Function declarations */ > static int > libxlDomainManagedSaveLoad(virDomainObjPtr vm, > @@ -836,6 +857,12 @@ libxlStateInitialize(bool privileged, > LIBXL_VNC_PORT_MAX))) > goto error; > > + /* Allocate bitmap for migration port reservation */ > + if (!(libxl_driver->reservedMigPorts = > + virPortAllocatorNew(LIBXL_MIGRATION_PORT_MIN, > + LIBXL_MIGRATION_PORT_MAX))) > + goto error; > + > if (!(libxl_driver->domains = virDomainObjListNew())) > goto error; > > @@ -4175,11 +4202,620 @@ libxlConnectSupportsFeature(virConnectPtr conn, > int feature) > switch (feature) { > case VIR_DRV_FEATURE_TYPED_PARAM_STRING: > return 1; > + case VIR_DRV_FEATURE_MIGRATION_V3: > + return 1; > default: > return 0; > } > } > > +static int > +libxlCheckMessageBanner(int fd, const char *banner, int banner_sz) > +{ > + char buf[banner_sz]; > + int ret = 0; > + > + do { > + ret = saferead(fd, buf, banner_sz); > + } while (ret == -1 && errno == EAGAIN); > + > + if (ret != banner_sz || memcmp(buf, banner, banner_sz)) { > + return -1; > + } > + > + return 0; > +} > + > +static char * > +libxlDomainMigrateBegin3(virDomainPtr domain, > + const char *xmlin, > + char **cookieout ATTRIBUTE_UNUSED, > + int *cookieoutlen ATTRIBUTE_UNUSED, > + unsigned long flags, > + const char *dname ATTRIBUTE_UNUSED, > + unsigned long resource ATTRIBUTE_UNUSED) > +{ > + libxlDriverPrivatePtr driver = domain->conn->privateData; > + libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); > + virDomainObjPtr vm; > + virDomainDefPtr def = NULL; > + char *xml = NULL; > + > + virCheckFlags(LIBXL_MIGRATION_FLAGS, NULL); > + > + vm = virDomainObjListFindByUUID(driver->domains, domain->uuid); > + if (!vm) { > + char uuidstr[VIR_UUID_STRING_BUFLEN]; > + virUUIDFormat(domain->uuid, uuidstr); > + virReportError(VIR_ERR_OPERATION_INVALID, > + _("no domain with matching uuid '%s'"), uuidstr); > + goto cleanup; > + } libxlDomObjFromDomain is introduced in commit 0d87fd0aa by Jim. > + > + if (!virDomainObjIsActive(vm)) { > + virReportError(VIR_ERR_OPERATION_INVALID, "%s", > + _("domain is not running")); > + goto cleanup; > + } > + > + if (virDomainMigrateBegin3EnsureACL(domain->conn, vm->def) < 0) > + goto cleanup; > + > + if (xmlin) { > + if (!(def = virDomainDefParseString(xmlin, cfg->caps, > + driver->xmlopt, > + 1 << VIR_DOMAIN_VIRT_XEN, > + VIR_DOMAIN_XML_INACTIVE))) > + goto cleanup; > + > + xml = virDomainDefFormat(def, VIR_DOMAIN_XML_SECURE); > + } else { > + xml = virDomainDefFormat(vm->def, VIR_DOMAIN_XML_SECURE); > + } > + > +cleanup: > + virDomainDefFree(def); > + if (vm) > + virObjectUnlock(vm); > + virObjectUnref(cfg); > + return xml; > +} > + > +static void > +doMigrateReceive(virNetSocketPtr sock, > + int events ATTRIBUTE_UNUSED, > + void *opaque) > +{ > + libxlMigrateReceiveArgs *data = opaque; > + virConnectPtr conn = data->conn; > + virDomainObjPtr vm = data->vm; > + virNetSocketPtr *socks = data->socks; > + size_t nsocks = data->nsocks; > + libxlDriverPrivatePtr driver = conn->privateData; > + virNetSocketPtr client_sock; > + int recv_fd; > + int len; > + 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\n"); > + recv_fd = virNetSocketDupFD(client_sock, true); > + virObjectUnref(client_sock); > + > + len = sizeof(libxlMigrateReceiverReady); > + if (safewrite(recv_fd, libxlMigrateReceiverReady, len) != len) { > + virReportError(VIR_ERR_OPERATION_FAILED, "%s", > + _("Failed to write libxlMigrateReceiverReady")); > + goto cleanup; > + } > + > + virObjectLock(vm); > + ret = libxlVmStart(driver, vm, false, recv_fd); > + virObjectUnlock(vm); > + > + if (ret < 0) { > + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", > + _("Failed to restore domain with libxenlight")); > + if (!vm->persistent) { > + virDomainObjListRemove(driver->domains, vm); > + vm = NULL; > + } > + goto cleanup; > + } > + > + len = sizeof(libxlMigrateReceiverFinish); > + if (safewrite(recv_fd, libxlMigrateReceiverFinish, len) != len) { > + virReportError(VIR_ERR_OPERATION_FAILED, "%s", > + _("Failed to write libxlMigrateReceiverFinish")); > + } > + > + /* Remove all listen socks from event handler, and close them. */ > + if (nsocks) { > + for (i = 0; i < nsocks; i++) { > + virNetSocketUpdateIOCallback(socks[i], 0); > + virNetSocketRemoveIOCallback(socks[i]); > + virNetSocketClose(socks[i]); > + virObjectUnref(socks[i]); > + } > + VIR_FREE(socks); > + } > + > +cleanup: > + VIR_FORCE_CLOSE(recv_fd); > + VIR_FREE(opaque); > + return; > +} > + > +static int > +doMigrateSend(libxlDriverPrivatePtr driver, > + virDomainObjPtr vm, > + unsigned long flags, > + int sockfd) > +{ > + libxlDomainObjPrivatePtr priv; > + libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); > + virDomainEventPtr event = NULL; > + int live = 0; > + int ret = -1; > + > + if (flags & VIR_MIGRATE_LIVE) > + live = LIBXL_SUSPEND_LIVE; > + > + priv = vm->privateData; > + > + /* read fixed message from dest (ready to receive) */ > + if (libxlCheckMessageBanner(sockfd, libxlMigrateReceiverReady, > + sizeof(libxlMigrateReceiverReady))) > + goto cleanup; > + > + if (libxl_domain_suspend(priv->ctx, vm->def->id, sockfd, live, NULL) > != 0) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to save domain '%d' with libxenlight"), > + vm->def->id); > + goto cleanup; > + } > + > + /* read fixed message from dest (receive completed) */ > + if (libxlCheckMessageBanner(sockfd, libxlMigrateReceiverFinish, > + sizeof(libxlMigrateReceiverFinish))) { > + 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 = virDomainEventNewFromObj(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 int > +libxlDomainMigratePrepare3(virConnectPtr dconn, > + const char *cookiein ATTRIBUTE_UNUSED, > + int cookieinlen ATTRIBUTE_UNUSED, > + char **cookieout ATTRIBUTE_UNUSED, > + int *cookieoutlen ATTRIBUTE_UNUSED, > + const char *uri_in, > + char **uri_out, > + unsigned long flags, > + const char *dname, > + unsigned long resource ATTRIBUTE_UNUSED, > + const char *dom_xml) > +{ > + libxlDriverPrivatePtr driver = dconn->privateData; > + libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); > + virDomainDefPtr def = NULL; > + 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; > + > + virCheckFlags(LIBXL_MIGRATION_FLAGS, -1); > + > + libxlDriverLock(driver); > + if (!dom_xml) { > + virReportError(VIR_ERR_OPERATION_INVALID, "%s", > + _("no domain XML passed")); > + goto cleanup; > + } > + def = virDomainDefParseString(dom_xml, cfg->caps, driver->xmlopt, > + 1 << VIR_DOMAIN_VIRT_XEN, > + VIR_DOMAIN_XML_INACTIVE); > + > + /* Target domain name, maybe renamed. */ > + if (dname) { > + if (VIR_STRDUP(def->name, dname) < 0) > + goto cleanup; > + } > + > + if (!(vm = virDomainObjListAdd(driver->domains, def, > + driver->xmlopt, > + VIR_DOMAIN_OBJ_LIST_ADD_LIVE | > + VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE, > + NULL))) > + goto cleanup; > + > + def = NULL; > + > + if (virDomainMigratePrepare3EnsureACL(dconn, vm->def) < 0) > + goto cleanup; > + > + /* Create socket connection to receive migration data */ > + if (!uri_in) { > + hostname = virGetHostname(); > + if (hostname == NULL) > + goto cleanup; > + > + if (virPortAllocatorAcquire(driver->reservedMigPorts, &port) < 0) > + goto cleanup; > + > + if (port == 0) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + "%s", _("Unable to find an unused migrate > port")); > + goto cleanup; > + } > + > + if (virAsprintf(uri_out, "tcp://%s:%d", hostname, port) < 0) > + goto cleanup; > + } else { > + if (!strstr(uri_in, "//")) { > + /* 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->reservedMigPorts, &port) < > 0) > + goto cleanup; > + > + if (port == 0) { > + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", > + _("Unable to find an unused migrate port")); > + 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, > + doMigrateReceive, > + args, > + NULL) < 0) { > + continue; > + } > + > + virNetSocketUpdateIOCallback(socks[i], VIR_EVENT_HANDLE_READABLE); > + nsocks_listen ++; > + } > + > + if (!nsocks_listen) > + goto cleanup; > + > + ret = 0; > + goto end; > + > +cleanup: > + if (nsocks) { > + for (i = 0 ; i < nsocks ; i++) { > + virNetSocketClose(socks[i]); > + virObjectUnref(socks[i]); > + } > + VIR_FREE(socks); > + } > + > +end: > + virURIFree(uri); > + if (vm) > + virObjectUnlock(vm); > + virObjectUnref(cfg); > + libxlDriverUnlock(driver); > + return ret; > +} > + > +static int > +libxlDomainMigratePerform3(virDomainPtr dom, > + const char *xmlin ATTRIBUTE_UNUSED, > + const char *cookiein ATTRIBUTE_UNUSED, > + int cookieinlen ATTRIBUTE_UNUSED, > + char **cookieout ATTRIBUTE_UNUSED, > + int *cookieoutlen ATTRIBUTE_UNUSED, > + const char *dconnuri ATTRIBUTE_UNUSED, > + const char *uri, > + unsigned long flags, > + const char *dname ATTRIBUTE_UNUSED, > + unsigned long resource ATTRIBUTE_UNUSED) > +{ > + libxlDriverPrivatePtr driver = dom->conn->privateData; > + virDomainObjPtr vm; > + char *hostname = NULL; > + unsigned short port = 0; > + char portstr[100]; > + virURIPtr uri_p = NULL; > + virNetSocketPtr sock; > + int sockfd = -1; > + int saved_errno = EINVAL; > + int ret = -1; > + > + virCheckFlags(LIBXL_MIGRATION_FLAGS, -1); > + > + vm = virDomainObjListFindByUUID(driver->domains, dom->uuid); > + if (!vm) { > + char uuidstr[VIR_UUID_STRING_BUFLEN]; > + virUUIDFormat(dom->uuid, uuidstr); > + virReportError(VIR_ERR_OPERATION_INVALID, > + _("no domain with matching uuid '%s'"), uuidstr); > + goto cleanup; > + } same here. > + > + if (virDomainMigratePerform3EnsureACL(dom->conn, vm->def) < 0) > + goto cleanup; > + > + /* parse dst host:port from uri */ > + uri_p = virURIParse(uri); > + if (uri_p == NULL || uri_p->server == NULL || uri_p->port == 0) > + goto cleanup; > + > + hostname = uri_p->server; > + port = uri_p->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 */ > + ret = doMigrateSend(driver, vm, flags, sockfd); > + > +cleanup: > + VIR_FORCE_CLOSE(sockfd); > + virURIFree(uri_p); > + if (vm) > + virObjectUnlock(vm); > + return ret; > +} > + > +static virDomainPtr > +libxlDomainMigrateFinish3(virConnectPtr dconn, > + const char *dname, > + const char *cookiein ATTRIBUTE_UNUSED, > + int cookieinlen ATTRIBUTE_UNUSED, > + char **cookieout ATTRIBUTE_UNUSED, > + int *cookieoutlen ATTRIBUTE_UNUSED, > + const char *dconnuri ATTRIBUTE_UNUSED, > + const char *uri, > + unsigned long flags, > + int cancelled) > +{ > + libxlDriverPrivatePtr driver = dconn->privateData; > + libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); > + unsigned short port = 0; > + virURIPtr uri_p = NULL; > + virDomainObjPtr vm = NULL; > + virDomainPtr dom = NULL; > + libxlDomainObjPrivatePtr priv; > + virDomainEventPtr event = NULL; > + int rc; > + > + virCheckFlags(LIBXL_MIGRATION_FLAGS, NULL); > + > + uri_p = virURIParse(uri); > + if (uri_p == NULL || uri_p->port == 0) > + VIR_DEBUG("Fail to parse port from URI"); > + port = uri_p->port; > + if (LIBXL_MIGRATION_PORT_MIN <= port && port < > LIBXL_MIGRATION_PORT_MAX) { > + if (virPortAllocatorRelease(driver->reservedMigPorts, port) < 0) > + VIR_DEBUG("Could not mark port %d as unused", port); > + } > + > + vm = virDomainObjListFindByName(driver->domains, dname); > + if (!vm) > + goto cleanup; > + > + if (virDomainMigrateFinish3EnsureACL(dconn, vm->def) < 0) > + goto cleanup; > + > + if (!cancelled) { > + if (!(flags & VIR_MIGRATE_PAUSED)) { > + priv = vm->privateData; > + rc = libxl_domain_unpause(priv->ctx, vm->def->id); > + if (rc) { > + virReportError(VIR_ERR_OPERATION_FAILED, "%s", > + _("Failed to unpause domain")); > + goto error; > + } > + > + virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, > VIR_DOMAIN_RUNNING_BOOTED); > + if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) > + goto error; > + } > + > + dom = virGetDomain(dconn, vm->def->name, vm->def->uuid); > + goto cleanup; > + } > + > +error: > + if (libxlVmReap(driver, vm, VIR_DOMAIN_SHUTOFF_SAVED)) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to destroy domain '%d'"), vm->def->id); > + goto cleanup; > + } > + event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED, > + VIR_DOMAIN_EVENT_STOPPED_SAVED); > + if (!vm->persistent) { > + virDomainObjListRemove(driver->domains, vm); > + vm = NULL; > + } > + > +cleanup: > + virURIFree(uri_p); > + if (vm) > + virObjectUnlock(vm); > + if (event) > + libxlDomainEventQueue(driver, event); > + virObjectUnref(cfg); > + return dom; > +} > + > +static int > +libxlDomainMigrateConfirm3(virDomainPtr domain, > + const char *cookiein ATTRIBUTE_UNUSED, > + int cookieinlen ATTRIBUTE_UNUSED, > + unsigned long flags, > + int cancelled) > +{ > + libxlDriverPrivatePtr driver = domain->conn->privateData; > + libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); > + virDomainObjPtr vm; > + libxlDomainObjPrivatePtr priv; > + virDomainEventPtr event = NULL; > + int ret = -1; > + > + virCheckFlags(LIBXL_MIGRATION_FLAGS, -1); > + > + vm = virDomainObjListFindByUUID(driver->domains, domain->uuid); > + if (!vm) { > + char uuidstr[VIR_UUID_STRING_BUFLEN]; > + virUUIDFormat(domain->uuid, uuidstr); > + virReportError(VIR_ERR_NO_DOMAIN, > + _("no domain with matching uuid '%s'"), uuidstr); > + goto cleanup; > + } here. > + > + if (virDomainMigrateConfirm3EnsureACL(domain->conn, vm->def) < 0) > + goto cleanup; > + > + if (cancelled) { > + priv = vm->privateData; > + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", > + _("migration failed, try to resume on our end")); > + if (!libxl_domain_resume(priv->ctx, vm->def->id, 0, 0)) { > + ret = 0; > + } else { > + VIR_DEBUG("Failed to resume domain '%d' with libxenlight", > + vm->def->id); > + virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, > VIR_DOMAIN_PAUSED_MIGRATION); > + event = virDomainEventNewFromObj(vm, > VIR_DOMAIN_EVENT_SUSPENDED, > + > VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED); > + if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) > + goto cleanup; > + } > + > + goto cleanup; > + } > + > + if (libxlVmReap(driver, vm, VIR_DOMAIN_SHUTOFF_SAVED)) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to destroy domain '%d'"), vm->def->id); > + goto cleanup; > + } > + > + event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED, > + VIR_DOMAIN_EVENT_STOPPED_SAVED); > + > + if (flags & VIR_MIGRATE_UNDEFINE_SOURCE) > + virDomainDeleteConfig(cfg->configDir, cfg->autostartDir, vm); > + > + if (!vm->persistent || (flags & VIR_MIGRATE_UNDEFINE_SOURCE)) { > + virDomainObjListRemove(driver->domains, vm); > + vm = NULL; > + } > + > + VIR_DEBUG("Migration successful.\n"); > + ret = 0; > + > +cleanup: > + if (vm) > + virObjectUnlock(vm); > + if (event) > + libxlDomainEventQueue(driver, event); > + virObjectUnref(cfg); > + return ret; > +} > + > > static virDriver libxlDriver = { > .no = VIR_DRV_LIBXL, > @@ -4249,6 +4885,11 @@ static virDriver libxlDriver = { > #ifdef LIBXL_HAVE_DOMAIN_NODEAFFINITY > .domainGetNumaParameters = libxlDomainGetNumaParameters, /* 1.1.1 */ > #endif > + .domainMigrateBegin3 = libxlDomainMigrateBegin3, /* 1.1.3 */ > + .domainMigratePrepare3 = libxlDomainMigratePrepare3, /* 1.1.3 */ > + .domainMigratePerform3 = libxlDomainMigratePerform3, /* 1.1.3 */ > + .domainMigrateFinish3 = libxlDomainMigrateFinish3, /* 1.1.3 */ > + .domainMigrateConfirm3 = libxlDomainMigrateConfirm3, /* 1.1.3 */ > .nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */ > .nodeGetCellsFreeMemory = libxlNodeGetCellsFreeMemory, /* 1.1.1 */ > .connectDomainEventRegister = libxlConnectDomainEventRegister, /* > 0.9.0 */ > diff --git a/src/libxl/libxl_driver.h b/src/libxl/libxl_driver.h > index a33d60c..25ac2b8 100644 > --- a/src/libxl/libxl_driver.h > +++ b/src/libxl/libxl_driver.h > @@ -24,6 +24,11 @@ > #ifndef LIBXL_DRIVER_H > # define LIBXL_DRIVER_H > > +# define LIBXL_MIGRATION_FLAGS \ > + (VIR_MIGRATE_LIVE | \ > + VIR_MIGRATE_UNDEFINE_SOURCE | \ > + VIR_MIGRATE_PAUSED) > + > int libxlRegister(void); > > #endif /* LIBXL_DRIVER_H */ > -- > 1.6.0.2 > > -- > libvir-list mailing list > libvir-list@xxxxxxxxxx > https://www.redhat.com/mailman/listinfo/libvir-list > -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list