From ecbf7a620fb79456724d37e86069e5a006e45270 Mon Sep 17 00:00:00 2001 Message-Id: From: Michal Privoznik Date: Fri, 11 Oct 2013 11:24:35 +0200 Subject: [PATCH] qemu: Implement support for VIR_MIGRATE_PARAM_LISTEN_ADDRESS https://bugzilla.redhat.com/show_bug.cgi?id=1015215 Signed-off-by: Michal Privoznik (cherry picked from commit c4ac7ef6638081c79ee7e9209bc49a81560a9f25) Signed-off-by: Jiri Denemark --- src/qemu/qemu_driver.c | 26 +++++++---- src/qemu/qemu_migration.c | 112 +++++++++++++++++++++++++++++++--------------- src/qemu/qemu_migration.h | 13 +++--- 3 files changed, 102 insertions(+), 49 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 3d0b56e..91549fb 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -10330,7 +10330,7 @@ qemuDomainMigratePrepare2(virConnectPtr dconn, ret = qemuMigrationPrepareDirect(driver, dconn, NULL, 0, NULL, NULL, /* No cookies */ uri_in, uri_out, - &def, origname, flags); + &def, origname, NULL, flags); cleanup: VIR_FREE(origname); @@ -10381,7 +10381,8 @@ qemuDomainMigratePerform(virDomainPtr dom, * Consume any cookie we were able to decode though */ ret = qemuMigrationPerform(driver, dom->conn, vm, - NULL, dconnuri, uri, NULL, cookie, cookielen, + NULL, dconnuri, uri, NULL, NULL, + cookie, cookielen, NULL, NULL, /* No output cookies in v2 */ flags, dname, resource, false); @@ -10535,7 +10536,7 @@ qemuDomainMigratePrepare3(virConnectPtr dconn, cookiein, cookieinlen, cookieout, cookieoutlen, uri_in, uri_out, - &def, origname, flags); + &def, origname, NULL, flags); cleanup: VIR_FREE(origname); @@ -10559,6 +10560,7 @@ qemuDomainMigratePrepare3Params(virConnectPtr dconn, const char *dom_xml = NULL; const char *dname = NULL; const char *uri_in = NULL; + const char *listenAddress = NULL; char *origname = NULL; int ret = -1; @@ -10574,7 +10576,10 @@ qemuDomainMigratePrepare3Params(virConnectPtr dconn, &dname) < 0 || virTypedParamsGetString(params, nparams, VIR_MIGRATE_PARAM_URI, - &uri_in) < 0) + &uri_in) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_LISTEN_ADDRESS, + &listenAddress) < 0) return -1; if (flags & VIR_MIGRATE_TUNNELLED) { @@ -10597,7 +10602,7 @@ qemuDomainMigratePrepare3Params(virConnectPtr dconn, cookiein, cookieinlen, cookieout, cookieoutlen, uri_in, uri_out, - &def, origname, flags); + &def, origname, listenAddress, flags); cleanup: VIR_FREE(origname); @@ -10729,7 +10734,8 @@ qemuDomainMigratePerform3(virDomainPtr dom, } return qemuMigrationPerform(driver, dom->conn, vm, xmlin, - dconnuri, uri, NULL, cookiein, cookieinlen, + dconnuri, uri, NULL, NULL, + cookiein, cookieinlen, cookieout, cookieoutlen, flags, dname, resource, true); } @@ -10751,6 +10757,7 @@ qemuDomainMigratePerform3Params(virDomainPtr dom, const char *dname = NULL; const char *uri = NULL; const char *graphicsuri = NULL; + const char *listenAddress = NULL; unsigned long long bandwidth = 0; virCheckFlags(QEMU_MIGRATION_FLAGS, -1); @@ -10771,7 +10778,10 @@ qemuDomainMigratePerform3Params(virDomainPtr dom, &bandwidth) < 0 || virTypedParamsGetString(params, nparams, VIR_MIGRATE_PARAM_GRAPHICS_URI, - &graphicsuri) < 0) + &graphicsuri) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_LISTEN_ADDRESS, + &listenAddress) < 0) return -1; if (!(vm = qemuDomObjFromDomain(dom))) @@ -10783,7 +10793,7 @@ qemuDomainMigratePerform3Params(virDomainPtr dom, } return qemuMigrationPerform(driver, dom->conn, vm, dom_xml, - dconnuri, uri, graphicsuri, + dconnuri, uri, graphicsuri, listenAddress, cookiein, cookieinlen, cookieout, cookieoutlen, flags, dname, bandwidth, true); } diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 4f53576..3f07b86 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -1100,12 +1100,6 @@ qemuMigrationStartNBDServer(virQEMUDriverPtr driver, unsigned short port = 0; char *diskAlias = NULL; size_t i; - const char *host; - - if (STREQ(listenAddr, "[::]")) - host = "::"; - else - host = listenAddr; for (i = 0; i < vm->def->ndisks; i++) { virDomainDiskDefPtr disk = vm->def->disks[i]; @@ -1125,7 +1119,7 @@ qemuMigrationStartNBDServer(virQEMUDriverPtr driver, if (!port && ((virPortAllocatorAcquire(driver->remotePorts, &port) < 0) || - (qemuMonitorNBDServerStart(priv->mon, host, port) < 0))) { + (qemuMonitorNBDServerStart(priv->mon, listenAddr, port) < 0))) { qemuDomainObjExitMonitor(driver, vm); goto cleanup; } @@ -2167,6 +2161,7 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, const char *origname, virStreamPtr st, unsigned int port, + const char *listenAddress, unsigned long flags) { virDomainObjPtr vm = NULL; @@ -2180,7 +2175,6 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, char *xmlout = NULL; unsigned int cookieFlags; virCapsPtr caps = NULL; - const char *listenAddr = NULL; char *migrateFrom = NULL; bool abort_on_error = !!(flags & VIR_MIGRATE_ABORT_ON_ERROR); @@ -2264,31 +2258,65 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, if (VIR_STRDUP(migrateFrom, "stdio") < 0) goto cleanup; } else { + virSocketAddr listenAddressSocket; + bool encloseAddress = false; + bool hostIPv6Capable = false; + bool qemuIPv6Capable = false; virQEMUCapsPtr qemuCaps = NULL; struct addrinfo *info = NULL; struct addrinfo hints = { .ai_flags = AI_ADDRCONFIG, .ai_socktype = SOCK_STREAM }; + if (getaddrinfo("::", NULL, &hints, &info) == 0) { + freeaddrinfo(info); + hostIPv6Capable = true; + } if (!(qemuCaps = virQEMUCapsCacheLookupCopy(driver->qemuCapsCache, (*def)->emulator))) goto cleanup; - /* Listen on :: instead of 0.0.0.0 if QEMU understands it - * and there is at least one IPv6 address configured - */ - if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_IPV6_MIGRATION) && - getaddrinfo("::", NULL, &hints, &info) == 0) { - freeaddrinfo(info); - listenAddr = "[::]"; + qemuIPv6Capable = virQEMUCapsGet(qemuCaps, QEMU_CAPS_IPV6_MIGRATION); + virObjectUnref(qemuCaps); + + if (listenAddress) { + if (virSocketAddrIsNumeric(listenAddress)) { + /* listenAddress is numeric IPv4 or IPv6 */ + if (virSocketAddrParse(&listenAddressSocket, listenAddress, AF_UNSPEC) < 0) + goto cleanup; + + /* address parsed successfully */ + if (VIR_SOCKET_ADDR_IS_FAMILY(&listenAddressSocket, AF_INET6)) { + if (!qemuIPv6Capable) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("qemu isn't capable of IPv6")); + goto cleanup; + } + if (!hostIPv6Capable) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("host isn't capable of IPv6")); + goto cleanup; + } + /* IPv6 address must be escaped in brackets on the cmd line */ + encloseAddress = true; + } + } else { + /* listenAddress is a hostname */ + } } else { - listenAddr = "0.0.0.0"; + /* Listen on :: instead of 0.0.0.0 if QEMU understands it + * and there is at least one IPv6 address configured + */ + listenAddress = qemuIPv6Capable && hostIPv6Capable ? + encloseAddress = true, "::" : "0.0.0.0"; } - virObjectUnref(qemuCaps); - /* QEMU will be started with -incoming [::]:port - * or -incoming 0.0.0.0:port + /* QEMU will be started with -incoming []:port, + * -incoming :port or -incoming :port */ - if (virAsprintf(&migrateFrom, "tcp:%s:%d", listenAddr, port) < 0) + if ((encloseAddress && + virAsprintf(&migrateFrom, "tcp:[%s]:%d", listenAddress, port) < 0) || + (!encloseAddress && + virAsprintf(&migrateFrom, "tcp:%s:%d", listenAddress, port) < 0)) goto cleanup; } @@ -2375,7 +2403,7 @@ done: if (mig->nbd && flags & (VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC) && virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NBD_SERVER)) { - if (qemuMigrationStartNBDServer(driver, vm, listenAddr) < 0) { + if (qemuMigrationStartNBDServer(driver, vm, listenAddress) < 0) { /* error already reported */ goto endjob; } @@ -2479,7 +2507,7 @@ qemuMigrationPrepareTunnel(virQEMUDriverPtr driver, ret = qemuMigrationPrepareAny(driver, dconn, cookiein, cookieinlen, cookieout, cookieoutlen, def, origname, - st, 0, flags); + st, 0, NULL, flags); return ret; } @@ -2495,6 +2523,7 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver, char **uri_out, virDomainDefPtr *def, const char *origname, + const char *listenAddress, unsigned long flags) { static int port = 0; @@ -2600,7 +2629,7 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver, ret = qemuMigrationPrepareAny(driver, dconn, cookiein, cookieinlen, cookieout, cookieoutlen, def, origname, - NULL, this_port, flags); + NULL, this_port, listenAddress, flags); cleanup: virURIFree(uri); VIR_FREE(hostname); @@ -3604,6 +3633,7 @@ doPeer2PeerMigrate3(virQEMUDriverPtr driver, const char *dname, const char *uri, const char *graphicsuri, + const char *listenAddress, unsigned long long bandwidth, bool useParams, unsigned long flags) @@ -3625,11 +3655,11 @@ doPeer2PeerMigrate3(virQEMUDriverPtr driver, int maxparams = 0; VIR_DEBUG("driver=%p, sconn=%p, dconn=%p, dconnuri=%s, vm=%p, xmlin=%s, " - "dname=%s, uri=%s, graphicsuri=%s, bandwidth=%llu, " - "useParams=%d, flags=%lx", + "dname=%s, uri=%s, graphicsuri=%s, listenAddress=%s, " + "bandwidth=%llu, useParams=%d, flags=%lx", driver, sconn, dconn, NULLSTR(dconnuri), vm, NULLSTR(xmlin), - NULLSTR(dname), NULLSTR(uri), NULLSTR(graphicsuri), bandwidth, - useParams, flags); + NULLSTR(dname), NULLSTR(uri), NULLSTR(graphicsuri), + NULLSTR(listenAddress), bandwidth, useParams, flags); /* Unlike the virDomainMigrateVersion3 counterpart, we don't need * to worry about auto-setting the VIR_MIGRATE_CHANGE_PROTECTION @@ -3667,6 +3697,11 @@ doPeer2PeerMigrate3(virQEMUDriverPtr driver, VIR_MIGRATE_PARAM_GRAPHICS_URI, graphicsuri) < 0) goto cleanup; + if (listenAddress && + virTypedParamsAddString(¶ms, &nparams, &maxparams, + VIR_MIGRATE_PARAM_LISTEN_ADDRESS, + listenAddress) < 0) + goto cleanup; } if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) @@ -3871,6 +3906,7 @@ static int doPeer2PeerMigrate(virQEMUDriverPtr driver, const char *dconnuri, const char *uri, const char *graphicsuri, + const char *listenAddress, unsigned long flags, const char *dname, unsigned long resource, @@ -3885,10 +3921,11 @@ static int doPeer2PeerMigrate(virQEMUDriverPtr driver, bool useParams; VIR_DEBUG("driver=%p, sconn=%p, vm=%p, xmlin=%s, dconnuri=%s, " - "uri=%s, graphicsuri=%s, flags=%lx, dname=%s, resource=%lu", + "uri=%s, graphicsuri=%s, listenAddress=%s, flags=%lx, " + "dname=%s, resource=%lu", driver, sconn, vm, NULLSTR(xmlin), NULLSTR(dconnuri), - NULLSTR(uri), NULLSTR(graphicsuri), flags, NULLSTR(dname), - resource); + NULLSTR(uri), NULLSTR(graphicsuri), NULLSTR(listenAddress), + flags, NULLSTR(dname), resource); /* the order of operations is important here; we make sure the * destination side is completely setup before we touch the source @@ -3963,8 +4000,8 @@ static int doPeer2PeerMigrate(virQEMUDriverPtr driver, if (*v3proto) { ret = doPeer2PeerMigrate3(driver, sconn, dconn, dconnuri, vm, xmlin, - dname, uri, graphicsuri, resource, - useParams, flags); + dname, uri, graphicsuri, listenAddress, + resource, useParams, flags); } else { ret = doPeer2PeerMigrate2(driver, sconn, dconn, vm, dconnuri, flags, dname, resource); @@ -3998,6 +4035,7 @@ qemuMigrationPerformJob(virQEMUDriverPtr driver, const char *uri, const char *graphicsuri, const char *cookiein, + const char *listenAddress, int cookieinlen, char **cookieout, int *cookieoutlen, @@ -4032,8 +4070,8 @@ qemuMigrationPerformJob(virQEMUDriverPtr driver, if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) { ret = doPeer2PeerMigrate(driver, conn, vm, xmlin, - dconnuri, uri, graphicsuri, flags, dname, - resource, &v3proto); + dconnuri, uri, graphicsuri, listenAddress, + flags, dname, resource, &v3proto); } else { qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_PERFORM2); ret = doNativeMigrate(driver, vm, uri, cookiein, cookieinlen, @@ -4198,6 +4236,7 @@ qemuMigrationPerform(virQEMUDriverPtr driver, const char *dconnuri, const char *uri, const char *graphicsuri, + const char *listenAddress, const char *cookiein, int cookieinlen, char **cookieout, @@ -4224,7 +4263,8 @@ qemuMigrationPerform(virQEMUDriverPtr driver, } return qemuMigrationPerformJob(driver, conn, vm, xmlin, dconnuri, uri, - graphicsuri, cookiein, cookieinlen, + graphicsuri, listenAddress, + cookiein, cookieinlen, cookieout, cookieoutlen, flags, dname, resource, v3proto); } else { @@ -4242,7 +4282,7 @@ qemuMigrationPerform(virQEMUDriverPtr driver, flags, resource); } else { return qemuMigrationPerformJob(driver, conn, vm, xmlin, dconnuri, - uri, graphicsuri, + uri, graphicsuri, listenAddress, cookiein, cookieinlen, cookieout, cookieoutlen, flags, dname, resource, v3proto); diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h index 4af5aed..cafa2a2 100644 --- a/src/qemu/qemu_migration.h +++ b/src/qemu/qemu_migration.h @@ -43,11 +43,12 @@ /* All supported migration parameters and their types. */ # define QEMU_MIGRATION_PARAMETERS \ - VIR_MIGRATE_PARAM_URI, VIR_TYPED_PARAM_STRING, \ - VIR_MIGRATE_PARAM_DEST_NAME, VIR_TYPED_PARAM_STRING, \ - VIR_MIGRATE_PARAM_DEST_XML, VIR_TYPED_PARAM_STRING, \ - VIR_MIGRATE_PARAM_BANDWIDTH, VIR_TYPED_PARAM_ULLONG, \ - VIR_MIGRATE_PARAM_GRAPHICS_URI, VIR_TYPED_PARAM_STRING, \ + VIR_MIGRATE_PARAM_URI, VIR_TYPED_PARAM_STRING, \ + VIR_MIGRATE_PARAM_DEST_NAME, VIR_TYPED_PARAM_STRING, \ + VIR_MIGRATE_PARAM_DEST_XML, VIR_TYPED_PARAM_STRING, \ + VIR_MIGRATE_PARAM_BANDWIDTH, VIR_TYPED_PARAM_ULLONG, \ + VIR_MIGRATE_PARAM_GRAPHICS_URI, VIR_TYPED_PARAM_STRING, \ + VIR_MIGRATE_PARAM_LISTEN_ADDRESS, VIR_TYPED_PARAM_STRING, \ NULL @@ -124,6 +125,7 @@ int qemuMigrationPrepareDirect(virQEMUDriverPtr driver, char **uri_out, virDomainDefPtr *def, const char *origname, + const char *listenAddress, unsigned long flags); int qemuMigrationPerform(virQEMUDriverPtr driver, @@ -133,6 +135,7 @@ int qemuMigrationPerform(virQEMUDriverPtr driver, const char *dconnuri, const char *uri, const char *graphicsuri, + const char *listenAddress, const char *cookiein, int cookieinlen, char **cookieout, -- 1.8.4