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

Bamvor Jian Zhang bjzhang at suse.com
Mon Sep 30 06:29:49 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 
> + 
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 at redhat.com 
> https://www.redhat.com/mailman/listinfo/libvir-list 
>  





More information about the libvir-list mailing list