migration: add migration_host support for IPv6 address without brackets

if specifying migration_host to an Ipv6 address without brackets,
it was resolved to an incorrect address, such as:
    tcp:2001:0DB8::1428:4444,
but the correct address should be:
    tcp:[2001:0DB8::1428]:4444
so we should add brackets when parsing it.

Signed-off-by: Chen Fan <chen.fan.fnst@cn.fujitsu.com>
This commit is contained in:
Chen Fan 2014-10-07 12:07:30 +08:00 committed by Ján Tomko
parent 6c31911a96
commit 69f7b67d55
5 changed files with 51 additions and 53 deletions

View File

@ -1916,11 +1916,11 @@ virSocketAddrGetIpPrefix;
virSocketAddrGetPort; virSocketAddrGetPort;
virSocketAddrGetRange; virSocketAddrGetRange;
virSocketAddrIsNetmask; virSocketAddrIsNetmask;
virSocketAddrIsNumeric;
virSocketAddrIsPrivate; virSocketAddrIsPrivate;
virSocketAddrIsWildcard; virSocketAddrIsWildcard;
virSocketAddrMask; virSocketAddrMask;
virSocketAddrMaskByPrefix; virSocketAddrMaskByPrefix;
virSocketAddrNumericFamily;
virSocketAddrParse; virSocketAddrParse;
virSocketAddrParseIPv4; virSocketAddrParseIPv4;
virSocketAddrParseIPv6; virSocketAddrParseIPv6;

View File

@ -2605,7 +2605,6 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver,
if (VIR_STRDUP(migrateFrom, "stdio") < 0) if (VIR_STRDUP(migrateFrom, "stdio") < 0)
goto cleanup; goto cleanup;
} else { } else {
virSocketAddr listenAddressSocket;
bool encloseAddress = false; bool encloseAddress = false;
bool hostIPv6Capable = false; bool hostIPv6Capable = false;
bool qemuIPv6Capable = false; bool qemuIPv6Capable = false;
@ -2627,28 +2626,21 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver,
virObjectUnref(qemuCaps); virObjectUnref(qemuCaps);
if (listenAddress) { if (listenAddress) {
if (virSocketAddrIsNumeric(listenAddress)) { if (virSocketAddrNumericFamily(listenAddress) == AF_INET6) {
/* listenAddress is numeric IPv4 or IPv6 */ if (!qemuIPv6Capable) {
if (virSocketAddrParse(&listenAddressSocket, listenAddress, AF_UNSPEC) < 0) virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
_("qemu isn't capable of IPv6"));
goto cleanup; 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;
} }
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 { } else {
/* listenAddress is a hostname */ /* listenAddress is a hostname or IPv4 */
} }
} else if (qemuIPv6Capable && hostIPv6Capable) { } else if (qemuIPv6Capable && hostIPv6Capable) {
/* Listen on :: instead of 0.0.0.0 if QEMU understands it /* Listen on :: instead of 0.0.0.0 if QEMU understands it
@ -2950,15 +2942,17 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver,
* to be a correct hostname which refers to the target machine). * to be a correct hostname which refers to the target machine).
*/ */
if (uri_in == NULL) { if (uri_in == NULL) {
bool encloseAddress = false;
const char *incFormat;
if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0) if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0)
goto cleanup; goto cleanup;
if (migrateHost != NULL) { if (migrateHost != NULL) {
if (virSocketAddrIsNumeric(migrateHost) && if (virSocketAddrNumericFamily(migrateHost) == AF_INET6)
virSocketAddrParse(NULL, migrateHost, AF_UNSPEC) < 0) encloseAddress = true;
goto cleanup;
if (VIR_STRDUP(hostname, migrateHost) < 0) if (VIR_STRDUP(hostname, migrateHost) < 0)
goto cleanup; goto cleanup;
} else { } else {
if ((hostname = virGetHostname()) == NULL) if ((hostname = virGetHostname()) == NULL)
@ -2977,7 +2971,12 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver,
* compatibility with old targets. We at least make the * compatibility with old targets. We at least make the
* new targets accept both syntaxes though. * new targets accept both syntaxes though.
*/ */
if (virAsprintf(uri_out, "tcp:%s:%d", hostname, port) < 0) if (encloseAddress)
incFormat = "%s:[%s]:%d";
else
incFormat = "%s:%s:%d";
if (virAsprintf(uri_out, incFormat, "tcp", hostname, port) < 0)
goto cleanup; goto cleanup;
} else { } else {
bool well_formed_uri; bool well_formed_uri;

View File

@ -856,26 +856,25 @@ virSocketAddrGetIpPrefix(const virSocketAddr *address,
} }
/** /**
* virSocketAddrIsNumeric: * virSocketAddrNumericFamily:
* @address: address to check * @address: address to check
* *
* Check if passed address is an IP address in numeric format. For * Check if passed address is an IP address in numeric format. and
* instance, for 0.0.0.0 true is returned, for 'examplehost" * return the address family, otherwise return 0.
* false is returned.
* *
* Returns: true if @address is an IP address, * Returns: AF_INET or AF_INET6 if @address is an numeric IP address,
* false otherwise * -1 otherwise.
*/ */
bool int
virSocketAddrIsNumeric(const char *address) virSocketAddrNumericFamily(const char *address)
{ {
struct addrinfo *res; struct addrinfo *res;
unsigned short family; unsigned short family;
if (virSocketAddrParseInternal(&res, address, AF_UNSPEC, false) < 0) if (virSocketAddrParseInternal(&res, address, AF_UNSPEC, false) < 0)
return false; return -1;
family = res->ai_addr->sa_family; family = res->ai_addr->sa_family;
freeaddrinfo(res); freeaddrinfo(res);
return family == AF_INET || family == AF_INET6; return family;
} }

View File

@ -125,5 +125,5 @@ bool virSocketAddrIsPrivate(const virSocketAddr *addr);
bool virSocketAddrIsWildcard(const virSocketAddr *addr); bool virSocketAddrIsWildcard(const virSocketAddr *addr);
bool virSocketAddrIsNumeric(const char *address); int virSocketAddrNumericFamily(const char *address);
#endif /* __VIR_SOCKETADDR_H__ */ #endif /* __VIR_SOCKETADDR_H__ */

View File

@ -219,19 +219,19 @@ static int testWildcardHelper(const void *opaque)
return testWildcard(data->addr, data->pass); return testWildcard(data->addr, data->pass);
} }
struct testIsNumericData { struct testNumericData {
const char *addr; const char *addr;
bool pass; int expected;
}; };
static int static int
testIsNumericHelper(const void *opaque) testNumericHelper(const void *opaque)
{ {
const struct testIsNumericData *data = opaque; const struct testNumericData *data = opaque;
if (virSocketAddrIsNumeric(data->addr)) if (virSocketAddrNumericFamily(data->addr) != data->expected)
return data->pass ? 0 : -1; return -1;
return data->pass ? -1 : 0; return 0;
} }
static int static int
@ -314,11 +314,11 @@ mymain(void)
ret = -1; \ ret = -1; \
} while (0) } while (0)
#define DO_TEST_IS_NUMERIC(addr, pass) \ #define DO_TEST_NUMERIC_FAMILY(addr, pass) \
do { \ do { \
struct testIsNumericData data = { addr, pass}; \ struct testNumericData data = { addr, pass }; \
if (virtTestRun("Test isNumeric " addr, \ if (virtTestRun("Test Numeric Family" addr, \
testIsNumericHelper, &data) < 0) \ testNumericHelper, &data) < 0) \
ret = -1; \ ret = -1; \
} while (0) } while (0)
@ -385,11 +385,11 @@ mymain(void)
DO_TEST_WILDCARD("1", false); DO_TEST_WILDCARD("1", false);
DO_TEST_WILDCARD("0.1", false); DO_TEST_WILDCARD("0.1", false);
DO_TEST_IS_NUMERIC("0.0.0.0", true); DO_TEST_NUMERIC_FAMILY("0.0.0.0", AF_INET);
DO_TEST_IS_NUMERIC("::", true); DO_TEST_NUMERIC_FAMILY("::", AF_INET6);
DO_TEST_IS_NUMERIC("1", true); DO_TEST_NUMERIC_FAMILY("1", AF_INET);
DO_TEST_IS_NUMERIC("::ffff", true); DO_TEST_NUMERIC_FAMILY("::ffff", AF_INET6);
DO_TEST_IS_NUMERIC("examplehost", false); DO_TEST_NUMERIC_FAMILY("examplehost", -1);
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
} }