Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx> --- src/qemu/qemu_driver.c | 26 +++++++---- src/qemu/qemu_migration.c | 113 +++++++++++++++++++++++++++++++--------------- src/qemu/qemu_migration.h | 13 ++++-- 3 files changed, 103 insertions(+), 49 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index c71aecc..e12a1de 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -10038,7 +10038,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); @@ -10089,7 +10089,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); @@ -10243,7 +10244,7 @@ qemuDomainMigratePrepare3(virConnectPtr dconn, cookiein, cookieinlen, cookieout, cookieoutlen, uri_in, uri_out, - &def, origname, flags); + &def, origname, NULL, flags); cleanup: VIR_FREE(origname); @@ -10267,6 +10268,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; @@ -10282,7 +10284,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) { @@ -10305,7 +10310,7 @@ qemuDomainMigratePrepare3Params(virConnectPtr dconn, cookiein, cookieinlen, cookieout, cookieoutlen, uri_in, uri_out, - &def, origname, flags); + &def, origname, listenAddress, flags); cleanup: VIR_FREE(origname); @@ -10437,7 +10442,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); } @@ -10459,6 +10465,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); @@ -10479,7 +10486,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))) @@ -10491,7 +10501,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 3a1aab7..2140073 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -1097,12 +1097,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]; @@ -1122,7 +1116,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; } @@ -2163,6 +2157,7 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, const char *origname, virStreamPtr st, unsigned int port, + const char *listenAddress, unsigned long flags) { virDomainObjPtr vm = NULL; @@ -2176,7 +2171,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); @@ -2260,31 +2254,66 @@ 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 enclosed in angle 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 [<IPv6 addr>]:port, + * -incoming <IPv4 addr>:port or -incoming <hostname>: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; } @@ -2371,7 +2400,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; } @@ -2475,7 +2504,7 @@ qemuMigrationPrepareTunnel(virQEMUDriverPtr driver, ret = qemuMigrationPrepareAny(driver, dconn, cookiein, cookieinlen, cookieout, cookieoutlen, def, origname, - st, 0, flags); + st, 0, NULL, flags); return ret; } @@ -2491,6 +2520,7 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver, char **uri_out, virDomainDefPtr *def, const char *origname, + const char *listenAddress, unsigned long flags) { static int port = 0; @@ -2596,7 +2626,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); @@ -3600,6 +3630,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) @@ -3621,11 +3652,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 @@ -3663,6 +3694,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) @@ -3867,6 +3903,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, @@ -3881,10 +3918,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 @@ -3959,8 +3997,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); @@ -3994,6 +4032,7 @@ qemuMigrationPerformJob(virQEMUDriverPtr driver, const char *uri, const char *graphicsuri, const char *cookiein, + const char *listenAddress, int cookieinlen, char **cookieout, int *cookieoutlen, @@ -4028,8 +4067,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, @@ -4194,6 +4233,7 @@ qemuMigrationPerform(virQEMUDriverPtr driver, const char *dconnuri, const char *uri, const char *graphicsuri, + const char *listenAddress, const char *cookiein, int cookieinlen, char **cookieout, @@ -4220,7 +4260,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 { @@ -4238,7 +4279,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.1.5 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list