[libvirt] [PATCH 1/2] virsocket: Introduce virSocketAddrIsAny

This internal API checks, if passed address is ANYCAST address. --- src/libvirt_private.syms | 1 + src/util/virsocketaddr.c | 22 ++++++++++++++++++++++ src/util/virsocketaddr.h | 1 + tests/sockettest.c | 38 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index b93629f..0b2ce42 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1780,6 +1780,7 @@ virSocketAddrFormatFull; virSocketAddrGetIpPrefix; virSocketAddrGetPort; virSocketAddrGetRange; +virSocketAddrIsAny; virSocketAddrIsNetmask; virSocketAddrIsPrivate; virSocketAddrMask; diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c index 1071b00..4bfc86d 100644 --- a/src/util/virsocketaddr.c +++ b/src/util/virsocketaddr.c @@ -227,6 +227,28 @@ virSocketAddrIsPrivate(const virSocketAddrPtr addr) } /* + * virSocketAddrIsAny: + * @addr: address to check + * + * Check if passed address is a variant of ANYCAST address. + */ +bool +virSocketAddrIsAny(const virSocketAddrPtr addr) +{ + unsigned long tmp; + switch (addr->data.stor.ss_family) { + case AF_INET: + tmp = INADDR_ANY; + return memcmp(&addr->data.inet4.sin_addr.s_addr, &tmp, + sizeof(addr->data.inet4.sin_addr.s_addr)) == 0; + case AF_INET6: + return memcmp(addr->data.inet6.sin6_addr.s6_addr, &in6addr_any, + sizeof(addr->data.inet6.sin6_addr.s6_addr)) == 0; + } + return false; +} + +/* * virSocketAddrFormat: * @addr: an initialized virSocketAddrPtr * diff --git a/src/util/virsocketaddr.h b/src/util/virsocketaddr.h index 1c9e54a..d4d7ccf 100644 --- a/src/util/virsocketaddr.h +++ b/src/util/virsocketaddr.h @@ -123,4 +123,5 @@ bool virSocketAddrEqual(const virSocketAddrPtr s1, const virSocketAddrPtr s2); bool virSocketAddrIsPrivate(const virSocketAddrPtr addr); +bool virSocketAddrIsAny(const virSocketAddrPtr addr); #endif /* __VIR_SOCKETADDR_H__ */ diff --git a/tests/sockettest.c b/tests/sockettest.c index 5b36a6c..e4a998b 100644 --- a/tests/sockettest.c +++ b/tests/sockettest.c @@ -157,6 +157,28 @@ static int testNetmaskHelper(const void *opaque) return testNetmask(data->addr1, data->addr2, data->netmask, data->pass); } +static int testAnycast(const char *addrstr, + bool pass) +{ + virSocketAddr addr; + + if (virSocketAddrParse(&addr, addrstr, AF_UNSPEC) < 0) + return -1; + + if (virSocketAddrIsAny(&addr)) + return pass ? 0 : -1; + return pass ? -1 : 0; +} + +struct testAnycastData { + const char *addr; + bool pass; +}; +static int testAnycastHelper(const void *opaque) +{ + const struct testAnycastData *data = opaque; + return testAnycast(data->addr, data->pass); +} static int mymain(void) @@ -223,6 +245,14 @@ mymain(void) ret = -1; \ } while (0) +#define DO_TEST_ANYCAST(addr, pass) \ + do { \ + struct testAnycastData data = { addr, pass}; \ + if (virtTestRun("Test anycast " addr, 1, \ + testAnycastHelper, &data) < 0) \ + ret = -1; \ + } while (0) + DO_TEST_PARSE_AND_FORMAT("127.0.0.1", AF_UNSPEC, true); DO_TEST_PARSE_AND_FORMAT("127.0.0.1", AF_INET, true); @@ -276,6 +306,14 @@ mymain(void) DO_TEST_NETMASK("2000::1:1", "9000::1:1", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0", false); + DO_TEST_ANYCAST("0.0.0.0", true); + DO_TEST_ANYCAST("::", true); + DO_TEST_ANYCAST("0", true); + DO_TEST_ANYCAST("0.0", true); + DO_TEST_ANYCAST("0.0.0", true); + DO_TEST_ANYCAST("1", false); + DO_TEST_ANYCAST("0.1", false); + return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE; } -- 1.8.2.1

Since we have the new internal API to check for ANYCAST address, we can use it instead of parsing and formatting. --- src/qemu/qemu_migration.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 3ca3f32..320706b 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -1740,7 +1740,6 @@ qemuDomainMigrateGraphicsRelocate(virQEMUDriverPtr driver, int ret; char *listenAddress; virSocketAddr addr; - bool reformatted = false; if (!cookie) return 0; @@ -1756,23 +1755,10 @@ qemuDomainMigrateGraphicsRelocate(virQEMUDriverPtr driver, listenAddress = cookie->graphics->listen; - /* Okay, here's the magic: some mgmt applications set bare '0' as listen - * address. On the other hand, it's a valid IPv4 address. This means, we - * need to reformat the address so the if statement below can check just - * for two ANYCAST addresses and not all their variants. */ - if (listenAddress && - virSocketAddrParse(&addr, listenAddress, AF_UNSPEC) > 0) { - listenAddress = virSocketAddrFormat(&addr); - reformatted = true; - } - if (!listenAddress || - STREQ(listenAddress, "0.0.0.0") || - STREQ(listenAddress, "::")) { - if (reformatted) - VIR_FREE(listenAddress); + (virSocketAddrParse(&addr, listenAddress, AF_UNSPEC) > 0 && + virSocketAddrIsAny(&addr))) listenAddress = cookie->remoteHostname; - } ret = qemuDomainObjEnterMonitorAsync(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT); -- 1.8.2.1

On Thu, Jun 06, 2013 at 16:10:30 +0200, Michal Privoznik wrote:
Since we have the new internal API to check for ANYCAST address, we can use it instead of parsing and formatting. --- src/qemu/qemu_migration.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-)
ACK Jirka

On Thu, Jun 06, 2013 at 16:10:29 +0200, Michal Privoznik wrote:
This internal API checks, if passed address is ANYCAST address. --- src/libvirt_private.syms | 1 + src/util/virsocketaddr.c | 22 ++++++++++++++++++++++ src/util/virsocketaddr.h | 1 + tests/sockettest.c | 38 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index b93629f..0b2ce42 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1780,6 +1780,7 @@ virSocketAddrFormatFull; virSocketAddrGetIpPrefix; virSocketAddrGetPort; virSocketAddrGetRange; +virSocketAddrIsAny; virSocketAddrIsNetmask; virSocketAddrIsPrivate; virSocketAddrMask; diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c index 1071b00..4bfc86d 100644 --- a/src/util/virsocketaddr.c +++ b/src/util/virsocketaddr.c @@ -227,6 +227,28 @@ virSocketAddrIsPrivate(const virSocketAddrPtr addr) }
/* + * virSocketAddrIsAny: + * @addr: address to check + * + * Check if passed address is a variant of ANYCAST address. + */ +bool +virSocketAddrIsAny(const virSocketAddrPtr addr) +{ + unsigned long tmp; + switch (addr->data.stor.ss_family) { + case AF_INET: + tmp = INADDR_ANY; + return memcmp(&addr->data.inet4.sin_addr.s_addr, &tmp, + sizeof(addr->data.inet4.sin_addr.s_addr)) == 0; + case AF_INET6: + return memcmp(addr->data.inet6.sin6_addr.s6_addr, &in6addr_any, + sizeof(addr->data.inet6.sin6_addr.s6_addr)) == 0; + } + return false;
Shouldn't we use in_addr_t (or uint32_t at least) for tmp rather than unsigned long and IN6_IS_ADDR_UNSPECIFIED(&addr->data.inet6.sin6_addr.s6_addr) instead of the second memcmp? However, I'm not sure how portable that would be... in.h(0P) man page says both of them shall be defined in netinet/in.h
+} + +/* * virSocketAddrFormat: * @addr: an initialized virSocketAddrPtr * diff --git a/src/util/virsocketaddr.h b/src/util/virsocketaddr.h index 1c9e54a..d4d7ccf 100644 --- a/src/util/virsocketaddr.h +++ b/src/util/virsocketaddr.h @@ -123,4 +123,5 @@ bool virSocketAddrEqual(const virSocketAddrPtr s1, const virSocketAddrPtr s2); bool virSocketAddrIsPrivate(const virSocketAddrPtr addr);
+bool virSocketAddrIsAny(const virSocketAddrPtr addr); #endif /* __VIR_SOCKETADDR_H__ */ diff --git a/tests/sockettest.c b/tests/sockettest.c index 5b36a6c..e4a998b 100644 --- a/tests/sockettest.c +++ b/tests/sockettest.c @@ -157,6 +157,28 @@ static int testNetmaskHelper(const void *opaque) return testNetmask(data->addr1, data->addr2, data->netmask, data->pass); }
+static int testAnycast(const char *addrstr, + bool pass)
I'd probably use a different name since "anycast" has different meaning in IPv6 world but I don't mind that much as I can't think of a better name :-) Jirka

On Thu, Jun 06, 2013 at 05:27:46PM +0200, Jiri Denemark wrote:
On Thu, Jun 06, 2013 at 16:10:29 +0200, Michal Privoznik wrote:
This internal API checks, if passed address is ANYCAST address. --- src/libvirt_private.syms | 1 + src/util/virsocketaddr.c | 22 ++++++++++++++++++++++ src/util/virsocketaddr.h | 1 + tests/sockettest.c | 38 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index b93629f..0b2ce42 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1780,6 +1780,7 @@ virSocketAddrFormatFull; virSocketAddrGetIpPrefix; virSocketAddrGetPort; virSocketAddrGetRange; +virSocketAddrIsAny; virSocketAddrIsNetmask; virSocketAddrIsPrivate; virSocketAddrMask; diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c index 1071b00..4bfc86d 100644 --- a/src/util/virsocketaddr.c +++ b/src/util/virsocketaddr.c @@ -227,6 +227,28 @@ virSocketAddrIsPrivate(const virSocketAddrPtr addr) }
/* + * virSocketAddrIsAny: + * @addr: address to check + * + * Check if passed address is a variant of ANYCAST address. + */ +bool +virSocketAddrIsAny(const virSocketAddrPtr addr) +{ + unsigned long tmp; + switch (addr->data.stor.ss_family) { + case AF_INET: + tmp = INADDR_ANY; + return memcmp(&addr->data.inet4.sin_addr.s_addr, &tmp, + sizeof(addr->data.inet4.sin_addr.s_addr)) == 0; + case AF_INET6: + return memcmp(addr->data.inet6.sin6_addr.s6_addr, &in6addr_any, + sizeof(addr->data.inet6.sin6_addr.s6_addr)) == 0; + } + return false;
Or just use 'inaddr_any
Shouldn't we use in_addr_t (or uint32_t at least) for tmp rather than unsigned long and
Yep, 'struct in_addr' is preferrable.
IN6_IS_ADDR_UNSPECIFIED(&addr->data.inet6.sin6_addr.s6_addr)
instead of the second memcmp? However, I'm not sure how portable that would be... in.h(0P) man page says both of them shall be defined in netinet/in.h
It seems to be present in mingw64 headers, so that's a good sign of portability.
diff --git a/tests/sockettest.c b/tests/sockettest.c index 5b36a6c..e4a998b 100644 --- a/tests/sockettest.c +++ b/tests/sockettest.c @@ -157,6 +157,28 @@ static int testNetmaskHelper(const void *opaque) return testNetmask(data->addr1, data->addr2, data->netmask, data->pass); }
+static int testAnycast(const char *addrstr, + bool pass)
I'd probably use a different name since "anycast" has different meaning in IPv6 world but I don't mind that much as I can't think of a better name :-)
Use 'Wildcard' instead of 'Anycast' Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
participants (3)
-
Daniel P. Berrange
-
Jiri Denemark
-
Michal Privoznik