[libvirt] [PATCH] add migration APIs to libxl driver

Chunyan Liu cyliu at suse.com
Thu Sep 12 07:01:16 UTC 2013


---
 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
+
 # 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;
+    }
+
+    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;
+    }
+
+    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;
+    }
+
+    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




More information about the libvir-list mailing list