diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 2e2acfb326ef2e9e06bdd89fbaa6c4cb395366e4..3277ba4a8e98f7ab956efbcf4192f49e3ad49c83 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 da29a2aa2aaf6ca2d6eb5c08529d7c1f6e30377d..3176085adcae50194cc66f75b3312b1291560cfa 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 21f116c6d3b76ebb479b61eab823a33ae1c5ed5b..04f08a3784dfa315afc8a73f77a3f0b52d6370fb 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 2585a16bbc57fe63a01107d1724618f24ae8a088..f22106a94efa176d715d4d4a14e02cb4b70a338a 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 c0b17c3d5193d5b3b19e3df571477fc236bda73e..d83293dcfefd27169245593809cbb6dbdb27838d 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;