Hi, Jim,
I made some changes to the patch according to your comments:
a. support concurrent migrations, add virBitmapPtr for probing migration ports
b. update doParseURI:
use virAsprintf instead of strdup and snprintf,
support migration URI syntax hostname[:port], remove xlmigr scheme
c. drop lock of driver while doing doMigrateSend
d. fix extra whitespace and parameter alignment and other places mentioned
Not changed:
a. ensure the name provided in xmlin is the same as def->name. Since we support
domain name change, so I think the name could be different. Keep not checked.
b. leaks the original name. It seems the original name won't be used again, so
didn't save original name. Keep it as before.
c. about migrate_receive_args. It's only used in dst side. If send logic and
receive logic still matches, extending the structure won't cause problem.
But if send logic and receive logic cannot match, there will problem. Still
think about how to handle it.
Any further comments will be very appreciated. Thanks for your time!
Signed-off-by: Chunyan Liu <cyliu(a)suse.com>
---
src/libxl/libxl_conf.h | 1 +
src/libxl/libxl_driver.c | 634 ++++++++++++++++++++++++++++++++++++++++++++++
src/libxl/libxl_driver.h | 20 ++-
3 files changed, 653 insertions(+), 2 deletions(-)
diff --git a/src/libxl/libxl_conf.h b/src/libxl/libxl_conf.h
index 2820afb..dd59817 100644
--- a/src/libxl/libxl_conf.h
+++ b/src/libxl/libxl_conf.h
@@ -61,6 +61,7 @@ struct _libxlDriverPrivate {
libxl_ctx ctx;
virBitmapPtr reservedVNCPorts;
+ virBitmapPtr reservedMigPorts; /* reserved migration ports */
virDomainObjList domains;
virDomainEventStatePtr domainEventState;
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index d5fa64a..5dc29a0 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -30,6 +30,12 @@
#include <math.h>
#include <libxl.h>
#include <fcntl.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 "logging.h"
@@ -61,6 +67,12 @@
static libxlDriverPrivatePtr libxl_driver = NULL;
+typedef struct migrate_receive_args {
+ virConnectPtr conn;
+ virDomainObjPtr vm;
+ int sockfd;
+} migrate_receive_args;
+
/* Function declarations */
static int
libxlVmStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm,
@@ -810,6 +822,7 @@ libxlShutdown(void)
VIR_FORCE_FCLOSE(libxl_driver->logger_file);
virBitmapFree(libxl_driver->reservedVNCPorts);
+ virBitmapFree(libxl_driver->reservedMigPorts);
VIR_FREE(libxl_driver->configDir);
VIR_FREE(libxl_driver->autostartDir);
@@ -865,6 +878,10 @@ libxlStartup(int privileged) {
virBitmapAlloc(LIBXL_VNC_PORT_MAX - LIBXL_VNC_PORT_MIN)) == NULL)
goto out_of_memory;
+ if ((libxl_driver->reservedMigPorts =
+ virBitmapAlloc(LIBXL_MIGRATION_MAX_PORT -
LIBXL_MIGRATION_MIN_PORT)) == NULL)
+ goto out_of_memory;
+
if (virDomainObjListInit(&libxl_driver->domains) < 0)
goto out_of_memory;
@@ -1095,6 +1112,17 @@ libxlClose(virConnectPtr conn ATTRIBUTE_UNUSED)
return 0;
}
+static int
+libxlSupportsFeature(virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
+{
+ switch (feature) {
+ case VIR_DRV_FEATURE_MIGRATION_V3:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
static const char *
libxlGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
{
@@ -3842,12 +3870,613 @@ libxlIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
return 1;
}
+static int libxlReadFixedMessage(int fd, const void *msg, int msgsz)
+{
+ char buf[msgsz];
+
+ if (saferead(fd, buf, msgsz) != msgsz || memcmp(buf, msg, msgsz)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int doParseURI(const char *uri, char **p_hostname, int *p_port)
+{
+ char *p, *hostname;
+ int port_nr = 0;
+
+ if (uri == NULL)
+ return -1;
+
+ /* URI passed is a string "hostname[:port]" */
+ if ((p = strrchr(uri, ':')) != NULL) { /* "hostname:port" */
+ int n;
+
+ if (virStrToLong_i(p+1, NULL, 10, &port_nr) < 0) {
+ libxlError(VIR_ERR_INVALID_ARG,
+ _("Invalid port number"));
+ return -1;
+ }
+
+ /* Get the hostname. */
+ n = p - uri; /* n = Length of hostname in bytes. */
+ if (n <= 0) {
+ libxlError(VIR_ERR_INVALID_ARG,
+ _("Hostname must be specified in the URI"));
+ return -1;
+ }
+
+ if (virAsprintf(&hostname, "%s", uri) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ hostname[n] = '\0';
+ }
+ else {/* "hostname" (or IP address) */
+ if (virAsprintf(&hostname, "%s", uri) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+ }
+ *p_hostname = hostname;
+ *p_port = port_nr;
+ 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;
+ virDomainObjPtr vm;
+ virDomainDefPtr def = NULL;
+ char *xml = NULL;
+
+ virCheckFlags(LIBXL_MIGRATION_FLAGS, NULL);
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, domain->uuid);
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(domain->uuid, uuidstr);
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ _("no domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ if (!virDomainObjIsActive(vm)) {
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ _("domain is not running"));
+ goto cleanup;
+ }
+
+ if (xmlin) {
+ if (!(def = virDomainDefParseString(driver->caps, xmlin,
+ 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:
+ if (vm)
+ virDomainObjUnlock(vm);
+ libxlDriverUnlock(driver);
+ return xml;
+}
+
+static void doMigrateReceive(void *opaque)
+{
+ migrate_receive_args *data = opaque;
+ virConnectPtr conn = data->conn;
+ int sockfd = data->sockfd;
+ virDomainObjPtr vm = data->vm;
+ libxlDriverPrivatePtr driver = conn->privateData;
+ int recv_fd;
+ struct sockaddr_in new_addr;
+ socklen_t socklen = sizeof(new_addr);
+ int len;
+
+ do {
+ recv_fd = accept(sockfd, (struct sockaddr *)&new_addr, &socklen);
+ } while(recv_fd < 0 && errno == EINTR);
+
+ if (recv_fd < 0) {
+ libxlError(VIR_ERR_OPERATION_FAILED,
+ _("Could not accept migration connection"));
+ goto cleanup;
+ }
+ VIR_DEBUG("Accepted migration\n");
+
+ len = sizeof(migrate_receiver_banner);
+ if (safewrite(recv_fd, migrate_receiver_banner, len) != len) {
+ libxlError(VIR_ERR_OPERATION_FAILED,
+ _("Failed to write migrate_receiver_banner"));
+ goto cleanup;
+ }
+
+ if (libxlVmStart(driver, vm, false, recv_fd) < 0) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to restore domain with libxenlight"));
+ if (!vm->persistent) {
+ virDomainRemoveInactive(&driver->domains, vm);
+ vm = NULL;
+ }
+ goto cleanup;
+ }
+
+ len = sizeof(migrate_receiver_ready);
+ if (safewrite(recv_fd, migrate_receiver_ready, len) != len) {
+ libxlError(VIR_ERR_OPERATION_FAILED,
+ _("Failed to write migrate_receiver_ready"));
+ }
+
+cleanup:
+ if (VIR_CLOSE(recv_fd) < 0)
+ virReportSystemError(errno, "%s", _("cannot close
recv_fd"));
+ if (VIR_CLOSE(sockfd) < 0)
+ virReportSystemError(errno, "%s", _("cannot close sockfd"));
+ if (vm)
+ virDomainObjUnlock(vm);
+ VIR_FREE(opaque);
+ return;
+}
+
+static int doMigrateSend(virDomainPtr dom, unsigned long flags, int sockfd)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ libxlDomainObjPrivatePtr priv;
+ libxl_domain_suspend_info suspinfo;
+ virDomainEventPtr event = NULL;
+ int live = 0;
+ int ret = -1;
+
+ if (flags & VIR_MIGRATE_LIVE)
+ live = 1;
+
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ _("no domain with matching uuid '%s'"),
uuidstr);
+ goto cleanup;
+ }
+
+ priv = vm->privateData;
+
+ /* read fixed message from dest (ready to receive) */
+ if (libxlReadFixedMessage(sockfd, migrate_receiver_banner,
+ sizeof(migrate_receiver_banner))) {
+ goto cleanup;
+ }
+
+ /* send suspend data */
+ memset(&suspinfo, 0, sizeof(suspinfo));
+ if (live == 1)
+ suspinfo.flags |= XL_SUSPEND_LIVE;
+ if (libxl_domain_suspend(&priv->ctx, &suspinfo, vm->def->id,
sockfd) != 0) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to save domain '%d' with libxenlight"),
+ vm->def->id);
+ goto cleanup;
+ }
+
+ /* read fixed message from dest (receive completed) */
+ if (libxlReadFixedMessage(sockfd, migrate_receiver_ready,
+ sizeof(migrate_receiver_ready))) {
+ /* Src side should be resumed, but for ret < 0, virsh won't
call Src side
+ * Confirm3, handle it here.
+ */
+ libxl_domain_resume(&priv->ctx, vm->def->id);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ if (event)
+ libxlDomainEventQueue(driver, event);
+ return ret;
+}
+
+static int libxlFindFreeMigPort(libxlDriverPrivatePtr driver, int startPort)
+{
+ int i;
+
+ for (i = startPort ; i < LIBXL_MIGRATION_MAX_PORT; i++) {
+ bool used = false;
+ if (virBitmapGetBit(driver->reservedMigPorts,
+ i - LIBXL_MIGRATION_MIN_PORT, &used) < 0)
+ VIR_DEBUG("virBitmapGetBit failed on bit %d", i -
LIBXL_MIGRATION_MIN_PORT);
+
+ if (!used)
+ return i;
+ }
+
+ return -1;
+}
+
+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;
+ virDomainDefPtr def = NULL;
+ virDomainObjPtr vm = NULL;
+ char *hostname = NULL;
+ int port = 0;
+ int sockfd = -1;
+ struct sockaddr_in addr;
+ virThread migrate_receive_thread;
+ migrate_receive_args *args;
+ int ret = -1;
+
+ virCheckFlags(LIBXL_MIGRATION_FLAGS, -1);
+
+ libxlDriverLock(driver);
+ if (!dom_xml) {
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ _("no domain XML passed"));
+ goto cleanup;
+ }
+
+ def = virDomainDefParseString(driver->caps, dom_xml,
+ 1 << VIR_DOMAIN_VIRT_XEN,
+ VIR_DOMAIN_XML_INACTIVE);
+
+ /* Target domain name, maybe renamed. */
+ if (dname) {
+ def->name = strdup(dname);
+ if (def->name == NULL)
+ goto cleanup;
+ }
+
+ if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
+ goto cleanup;
+
+ if (!(vm = virDomainAssignDef(driver->caps, &driver->domains, def, true)))
+ goto cleanup;
+
+ def = NULL;
+
+ /* Create socket connection to receive migration data */
+ if (!uri_in) {
+ hostname = virGetHostname(dconn);
+ if (hostname == NULL)
+ goto cleanup;
+
+ port = libxlFindFreeMigPort(driver, LIBXL_MIGRATION_MIN_PORT);
+ if (port < 0) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Unable to find an unused migration
port"));
+ goto cleanup;
+ }
+
+ if (virAsprintf(uri_out, "%s:%d", hostname, port) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ } else {
+ if (doParseURI(uri_in, &hostname, &port))
+ goto cleanup;
+
+ if (port <= 0) {
+ port = libxlFindFreeMigPort(driver, LIBXL_MIGRATION_MIN_PORT);
+ if (port < 0) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Unable to find an unused migration
port"));
+ goto cleanup;
+ }
+
+ if (virAsprintf(uri_out, "%s:%d", hostname, port) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ }
+ }
+
+ sockfd = socket(AF_INET, SOCK_STREAM, 0);
+ if (sockfd == -1) {
+ libxlError(VIR_ERR_OPERATION_FAILED,
+ _("Failed to create socket for incoming migration"));
+ goto cleanup;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ libxlError(VIR_ERR_OPERATION_FAILED,
+ _("Fail to bind port for incoming migration"));
+ goto cleanup;
+ }
+
+ if (listen(sockfd, MAXCONN_NUM) < 0){
+ libxlError(VIR_ERR_OPERATION_FAILED,
+ _("Fail to listen to incoming migration"));
+ goto cleanup;
+ }
+
+ if (VIR_ALLOC(args) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ args->conn = dconn;
+ args->vm = vm;
+ args->sockfd = sockfd;
+ if (virThreadCreate(&migrate_receive_thread,
+ true,
+ doMigrateReceive, args) < 0 ) {
+ virReportSystemError(errno, "%s",
+ _("Unable to create migration thread"));
+ VIR_FREE(args);
+ goto cleanup;
+ }
+
+ if (LIBXL_MIGRATION_MIN_PORT <= port && port <
LIBXL_MIGRATION_MAX_PORT) {
+ if (virBitmapSetBit(driver->reservedMigPorts,
+ port - LIBXL_MIGRATION_MIN_PORT) < 0)
+ VIR_DEBUG("virBitmapSetBit failed on bit %d",
+ port - LIBXL_MIGRATION_MIN_PORT);
+ }
+ ret = 0;
+ goto end;
+
+cleanup:
+ if (VIR_CLOSE(sockfd) < 0)
+ virReportSystemError(errno, "%s", _("cannot close sockfd"));
+ if (vm)
+ virDomainObjUnlock(vm);
+
+end:
+ VIR_FREE(hostname);
+ 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;
+ char *hostname = NULL;
+ int port = 0;
+ char *servname = NULL;
+ struct addrinfo hints, *res;
+ int sockfd = -1;
+ int ret = -1;
+
+ virCheckFlags(LIBXL_MIGRATION_FLAGS, -1);
+
+ if (doParseURI(uri, &hostname, &port))
+ goto cleanup;
+
+ VIR_DEBUG("hostname = %s, port = %d", hostname, port);
+
+ if (port <= 0)
+ goto cleanup;
+
+ if (virAsprintf(&servname, "%d", port) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ){
+ libxlError(VIR_ERR_OPERATION_FAILED,
+ _("Failed to create socket"));
+ goto cleanup;
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ if (getaddrinfo(hostname, servname, &hints, &res) || res == NULL) {
+ libxlError(VIR_ERR_OPERATION_FAILED,
+ _("IP address lookup failed"));
+ goto cleanup;
+ }
+
+ if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0) {
+ libxlError(VIR_ERR_OPERATION_FAILED,
+ _("Connect error"));
+ goto cleanup;
+ }
+
+ ret = doMigrateSend(dom, flags, sockfd);
+
+cleanup:
+ if (VIR_CLOSE(sockfd) < 0)
+ virReportSystemError(errno, "%s", _("cannot close sockfd"));
+ VIR_FREE(hostname);
+ VIR_FREE(servname);
+ if (res)
+ freeaddrinfo(res);
+ 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;
+ char *hostname = NULL;
+ int port = 0;
+ virDomainObjPtr vm = NULL;
+ virDomainPtr dom = NULL;
+ libxlDomainObjPrivatePtr priv;
+ virDomainEventPtr event = NULL;
+ int rc;
+
+ virCheckFlags(LIBXL_MIGRATION_FLAGS, NULL);
+
+ libxlDriverLock(driver);
+
+ if (doParseURI(uri, &hostname, &port))
+ VIR_DEBUG("Fail to parse port from URI");
+
+ if (LIBXL_MIGRATION_MIN_PORT <= port && port <
LIBXL_MIGRATION_MAX_PORT) {
+ if (virBitmapClearBit(driver->reservedMigPorts,
+ port - LIBXL_MIGRATION_MIN_PORT) < 0)
+ VIR_DEBUG("Could not mark port %d as unused", port);
+ }
+
+ vm = virDomainFindByName(&driver->domains, dname);
+ if (!vm)
+ goto cleanup;
+
+ if (!cancelled) {
+ if (!(flags & VIR_MIGRATE_PAUSED)) {
+ priv = vm->privateData;
+ rc = libxl_domain_unpause(&priv->ctx, vm->def->id);
+ if (rc) {
+ libxlError(VIR_ERR_OPERATION_FAILED,
+ _("Failed to unpause domain"));
+ goto error;
+ }
+
+ virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
VIR_DOMAIN_RUNNING_BOOTED);
+ if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
+ goto error;
+ }
+
+ dom = virGetDomain(dconn, vm->def->name, vm->def->uuid);
+ goto cleanup;
+ }
+
+error:
+ if (libxlVmReap(driver, vm, 1, VIR_DOMAIN_SHUTOFF_SAVED)) {
+ libxlError(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) {
+ virDomainRemoveInactive(&driver->domains, vm);
+ vm = NULL;
+ }
+
+cleanup:
+ VIR_FREE(hostname);
+ if (vm)
+ virDomainObjUnlock(vm);
+ if (event)
+ libxlDomainEventQueue(driver, event);
+ libxlDriverUnlock(driver);
+ 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;
+ virDomainObjPtr vm;
+ libxlDomainObjPrivatePtr priv;
+ virDomainEventPtr event = NULL;
+ int ret = -1;
+
+ virCheckFlags(LIBXL_MIGRATION_FLAGS, -1);
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, domain->uuid);
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(domain->uuid, uuidstr);
+ libxlError(VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ if (cancelled) {
+ priv = vm->privateData;
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("migration failed, try to resume on our end"));
+ if (!libxl_domain_resume(&priv->ctx, vm->def->id))
+ ret = 0;
+
+ goto cleanup;
+ }
+
+ if (libxlVmReap(driver, vm, 1, VIR_DOMAIN_SHUTOFF_SAVED)) {
+ libxlError(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(driver->configDir, driver->autostartDir, vm);
+
+ if (!vm->persistent || (flags & VIR_MIGRATE_UNDEFINE_SOURCE)) {
+ virDomainRemoveInactive(&driver->domains, vm);
+ vm = NULL;
+ }
+
+ VIR_DEBUG("Migration successful.\n");
+ ret = 0;
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ libxlDriverUnlock(driver);
+ return ret;
+}
static virDriver libxlDriver = {
.no = VIR_DRV_LIBXL,
.name = "xenlight",
.open = libxlOpen, /* 0.9.0 */
.close = libxlClose, /* 0.9.0 */
+ .supports_feature = libxlSupportsFeature, /* 0.9.12 */
.type = libxlGetType, /* 0.9.0 */
.version = libxlGetVersion, /* 0.9.0 */
.getHostname = virGetHostname, /* 0.9.0 */
@@ -3906,6 +4535,11 @@ static virDriver libxlDriver = {
.domainGetSchedulerParametersFlags =
libxlDomainGetSchedulerParametersFlags, /* 0.9.2 */
.domainSetSchedulerParameters = libxlDomainSetSchedulerParameters,
/* 0.9.0 */
.domainSetSchedulerParametersFlags =
libxlDomainSetSchedulerParametersFlags, /* 0.9.2 */
+ .domainMigrateBegin3 = libxlDomainMigrateBegin3, /* 0.9.12 */
+ .domainMigratePrepare3 = libxlDomainMigratePrepare3, /* 0.9.12 */
+ .domainMigratePerform3 = libxlDomainMigratePerform3, /* 0.9.12 */
+ .domainMigrateFinish3 = libxlDomainMigrateFinish3, /* 0.9.12 */
+ .domainMigrateConfirm3 = libxlDomainMigrateConfirm3, /* 0.9.12 */
.nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */
.domainEventRegister = libxlDomainEventRegister, /* 0.9.0 */
.domainEventDeregister = libxlDomainEventDeregister, /* 0.9.0 */
diff --git a/src/libxl/libxl_driver.h b/src/libxl/libxl_driver.h
index 4632d33..ad8df1f 100644
--- a/src/libxl/libxl_driver.h
+++ b/src/libxl/libxl_driver.h
@@ -21,9 +21,25 @@
/*---------------------------------------------------------------------------*/
#ifndef LIBXL_DRIVER_H
-# define LIBXL_DRIVER_H
+#define LIBXL_DRIVER_H
-# include <config.h>
+#include <config.h>
+
+#define LIBXL_MIGRATION_FLAGS \
+ (VIR_MIGRATE_LIVE | \
+ VIR_MIGRATE_UNDEFINE_SOURCE | \
+ VIR_MIGRATE_PAUSED)
+
+#define MAXCONN_NUM 10
+#define LIBXL_MIGRATION_MIN_PORT 49512
+#define LIBXL_MIGRATION_NUM_PORTS 64
+#define LIBXL_MIGRATION_MAX_PORT \
+ (LIBXL_MIGRATION_MIN_PORT + LIBXL_MIGRATION_NUM_PORTS)
+
+static const char migrate_receiver_banner[]=
+ "xl migration receiver ready, send binary domain data";
+static const char migrate_receiver_ready[]=
+ "domain received, ready to unpause";
int libxlRegister(void);
--
1.7.3.4