From 97e7e2660d2507a3e11b6f8958221636a1a6b4ea Mon Sep 17 00:00:00 2001 From: Wang Yufei Date: Fri, 11 Oct 2013 11:27:13 +0800 Subject: [PATCH] qemu: Avoid assigning unavailable migration ports https://bugzilla.redhat.com/show_bug.cgi?id=1019053 When we migrate vms concurrently, there's a chance that libvirtd on destination assigns the same port for different migrations, which will lead to migration failure during prepare phase on destination. So we use virPortAllocator here to solve the problem. Signed-off-by: Wang Yufei Signed-off-by: Jiri Denemark (cherry picked from commit 0196845d3abd0d914cf11f7ad6c19df8b47c32ed) Conflicts: missing support for changing the migration listen address src/qemu/qemu_migration.c --- src/qemu/qemu_command.h | 3 +++ src/qemu/qemu_conf.h | 6 ++--- src/qemu/qemu_domain.h | 1 + src/qemu/qemu_driver.c | 6 +++++ src/qemu/qemu_migration.c | 53 +++++++++++++++++++++++++++------------ 5 files changed, 50 insertions(+), 19 deletions(-) diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 2e2acfb326..3277ba4a8e 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -51,6 +51,9 @@ # define QEMU_WEBSOCKET_PORT_MIN 5700 # define QEMU_WEBSOCKET_PORT_MAX 65535 +# define QEMU_MIGRATION_PORT_MIN 49152 +# define QEMU_MIGRATION_PORT_MAX 49215 + typedef struct _qemuBuildCommandLineCallbacks qemuBuildCommandLineCallbacks; typedef qemuBuildCommandLineCallbacks *qemuBuildCommandLineCallbacksPtr; struct _qemuBuildCommandLineCallbacks { diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index da29a2aa2a..3176085adc 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -221,6 +221,9 @@ struct _virQEMUDriver { /* Immutable pointer, self-locking APIs */ virPortAllocatorPtr webSocketPorts; + /* Immutable pointer, self-locking APIs */ + virPortAllocatorPtr migrationPorts; + /* Immutable pointer, lockless APIs*/ virSysinfoDefPtr hostsysinfo; @@ -242,9 +245,6 @@ struct _qemuDomainCmdlineDef { char **env_value; }; -/* Port numbers used for KVM migration. */ -# define QEMUD_MIGRATION_FIRST_PORT 49152 -# define QEMUD_MIGRATION_NUM_PORTS 64 void qemuDomainCmdlineDefFree(qemuDomainCmdlineDefPtr def); diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 21f116c6d3..04f08a3784 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -160,6 +160,7 @@ struct _qemuDomainObjPrivate { unsigned long migMaxBandwidth; char *origname; int nbdPort; /* Port used for migration with NBD */ + unsigned short migrationPort; virChrdevsPtr devs; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 2585a16bbc..f22106a94e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -687,6 +687,11 @@ qemuStateInitialize(bool privileged, cfg->webSocketPortMax)) == NULL) goto error; + if ((qemu_driver->migrationPorts = + virPortAllocatorNew(QEMU_MIGRATION_PORT_MIN, + QEMU_MIGRATION_PORT_MAX)) == NULL) + goto error; + if (qemuSecurityInit(qemu_driver) < 0) goto error; @@ -992,6 +997,7 @@ qemuStateCleanup(void) { virObjectUnref(qemu_driver->domains); virObjectUnref(qemu_driver->remotePorts); virObjectUnref(qemu_driver->webSocketPorts); + virObjectUnref(qemu_driver->migrationPorts); virObjectUnref(qemu_driver->xmlopt); diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index c0b17c3d51..d83293dcfe 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -2151,6 +2151,9 @@ qemuMigrationPrepareCleanup(virQEMUDriverPtr driver, qemuDomainJobTypeToString(priv->job.active), qemuDomainAsyncJobTypeToString(priv->job.asyncJob)); + virPortAllocatorRelease(driver->migrationPorts, priv->migrationPort); + priv->migrationPort = 0; + if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_IN)) return; qemuDomainObjDiscardAsyncJob(driver, vm); @@ -2166,7 +2169,8 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, virDomainDefPtr *def, const char *origname, virStreamPtr st, - unsigned int port, + unsigned short port, + bool autoPort, unsigned long flags) { virDomainObjPtr vm = NULL; @@ -2412,6 +2416,8 @@ done: goto cleanup; } + if (autoPort) + priv->migrationPort = port; ret = 0; cleanup: @@ -2479,7 +2485,7 @@ qemuMigrationPrepareTunnel(virQEMUDriverPtr driver, ret = qemuMigrationPrepareAny(driver, dconn, cookiein, cookieinlen, cookieout, cookieoutlen, def, origname, - st, 0, flags); + st, 0, false, flags); return ret; } @@ -2497,8 +2503,8 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver, const char *origname, unsigned long flags) { - static int port = 0; - int this_port; + unsigned short port = 0; + bool autoPort = true; char *hostname = NULL; const char *p; char *uri_str = NULL; @@ -2525,10 +2531,15 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver, * to be a correct hostname which refers to the target machine). */ if (uri_in == NULL) { - this_port = QEMUD_MIGRATION_FIRST_PORT + port++; - if (port == QEMUD_MIGRATION_NUM_PORTS) port = 0; + if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0) { + goto cleanup; + } else if (!port) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("No migration port available within the " + "configured range")); + goto cleanup; + } - /* Get hostname */ if ((hostname = virGetHostname()) == NULL) goto cleanup; @@ -2545,7 +2556,7 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver, * new targets accept both syntaxes though. */ /* Caller frees */ - if (virAsprintf(uri_out, "tcp:%s:%d", hostname, this_port) < 0) + if (virAsprintf(uri_out, "tcp:%s:%d", hostname, port) < 0) goto cleanup; } else { /* Check the URI starts with "tcp:". We will escape the @@ -2581,17 +2592,22 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver, } if (uri->port == 0) { - /* Generate a port */ - this_port = QEMUD_MIGRATION_FIRST_PORT + port++; - if (port == QEMUD_MIGRATION_NUM_PORTS) - port = 0; + if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0) { + goto cleanup; + } else if (!port) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("No migration port available within the " + "configured range")); + goto cleanup; + } /* Caller frees */ - if (virAsprintf(uri_out, "%s:%d", uri_in, this_port) < 0) + if (virAsprintf(uri_out, "%s:%d", uri_in, port) < 0) goto cleanup; } else { - this_port = uri->port; + port = uri->port; + autoPort = false; } } @@ -2600,12 +2616,15 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver, ret = qemuMigrationPrepareAny(driver, dconn, cookiein, cookieinlen, cookieout, cookieoutlen, def, origname, - NULL, this_port, flags); + NULL, port, autoPort, flags); cleanup: virURIFree(uri); VIR_FREE(hostname); - if (ret != 0) + if (ret != 0) { VIR_FREE(*uri_out); + if (autoPort) + virPortAllocatorRelease(driver->migrationPorts, port); + } return ret; } @@ -4374,6 +4393,8 @@ qemuMigrationFinish(virQEMUDriverPtr driver, } qemuMigrationStopNBDServer(driver, vm, mig); + virPortAllocatorRelease(driver->migrationPorts, priv->migrationPort); + priv->migrationPort = 0; if (flags & VIR_MIGRATE_PERSIST_DEST) { virDomainDefPtr vmdef; -- GitLab