[libvirt] [PATCHv4 0/3] Support IPv6 addresses for graphics listening on networks

v1: https://www.redhat.com/archives/libvir-list/2015-February/msg00442.html v2: https://www.redhat.com/archives/libvir-list/2015-February/msg01228.html v3: https://www.redhat.com/archives/libvir-list/2015-March/msg00423.html changes in v4: * remove the family attribute and just return the first IP address * rename virNetDevGetIPv4Address to virNetDevGetIPv4AddressIoctl John Ferlan (1): util: Replace virNetDevGetIPv4Address with virNetDevGetIPAddress Ján Tomko (1): Support IPv6 in networkGetNetworkAddress Luyao Huang (1): util: Update virNetDevGetIPAddress to get IPv6 addresses src/libvirt_private.syms | 2 +- src/network/bridge_driver.c | 11 ++-- src/util/virnetdev.c | 119 +++++++++++++++++++++++++++++++++++++++----- src/util/virnetdev.h | 2 +- 4 files changed, 114 insertions(+), 20 deletions(-) -- 2.0.5

From: John Ferlan <jferlan@redhat.com> Rename it to virNetDevGetIPv4AddressIoctl and make virNetDevGetIPAddress a wrapper around it, allowing other ways of getting the address to be implemented, and still falling back to the old method. Signed-off-by: John Ferlan <jferlan@redhat.com> Signed-off-by: Ján Tomko <jtomko@redhat.com> --- src/libvirt_private.syms | 2 +- src/network/bridge_driver.c | 2 +- src/util/virnetdev.c | 48 +++++++++++++++++++++++++++++++++------------ src/util/virnetdev.h | 2 +- 4 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index a092714..b225707 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1708,7 +1708,7 @@ virNetDevDelMulti; virNetDevExists; virNetDevGetFeatures; virNetDevGetIndex; -virNetDevGetIPv4Address; +virNetDevGetIPAddress; virNetDevGetLinkInfo; virNetDevGetMAC; virNetDevGetMTU; diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index f865adc..6db368b 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -4559,7 +4559,7 @@ networkGetNetworkAddress(const char *netname, char **netaddr) } if (dev_name) { - if (virNetDevGetIPv4Address(dev_name, &addr) < 0) + if (virNetDevGetIPAddress(dev_name, &addr) < 0) goto cleanup; addrptr = &addr; } diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index 54d866e..59593f9 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -1386,7 +1386,7 @@ int virNetDevClearIPAddress(const char *ifname, #endif /* defined(__linux__) && defined(HAVE_LIBNL) */ /** - * virNetDevGetIPv4Address: + * virNetDevGetIPv4AddressIoctl: * @ifname: name of the interface whose IP address we want * @addr: filled with the IPv4 address * @@ -1396,22 +1396,21 @@ int virNetDevClearIPAddress(const char *ifname, * Returns 0 on success, -errno on failure. */ #if defined(SIOCGIFADDR) && defined(HAVE_STRUCT_IFREQ) -int virNetDevGetIPv4Address(const char *ifname, - virSocketAddrPtr addr) +static int +virNetDevGetIPv4AddressIoctl(const char *ifname, + virSocketAddrPtr addr) { int fd = -1; int ret = -1; struct ifreq ifr; - memset(addr, 0, sizeof(*addr)); - addr->data.stor.ss_family = AF_UNSPEC; - if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0) return -1; if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) { virReportSystemError(errno, - _("Unable to get IPv4 address for interface %s"), ifname); + _("Unable to get IPv4 address for interface %s via ioctl"), + ifname); goto cleanup; } @@ -1427,16 +1426,41 @@ int virNetDevGetIPv4Address(const char *ifname, #else /* ! SIOCGIFADDR */ -int virNetDevGetIPv4Address(const char *ifname ATTRIBUTE_UNUSED, - virSocketAddrPtr addr ATTRIBUTE_UNUSED) +static int +virNetDevGetIPv4AddressIoctl(const char *ifname ATTRIBUTE_UNUSED, + virSocketAddrPtr addr ATTRIBUTE_UNUSED) { - virReportSystemError(ENOSYS, "%s", - _("Unable to get IPv4 address on this platform")); - return -1; + return -2; } #endif /* ! SIOCGIFADDR */ +/** + * virNetDevGetIPAddress: + * @ifname: name of the interface whose IP address we want + * @addr: filled with the IPv4 address + * + * This function gets the IPv4 address for the interface @ifname + * and stores it in @addr + * + * Returns 0 on success, -errno on failure. + */ +int +virNetDevGetIPAddress(const char *ifname, + virSocketAddrPtr addr) +{ + int ret; + + memset(addr, 0, sizeof(*addr)); + addr->data.stor.ss_family = AF_UNSPEC; + + if ((ret = virNetDevGetIPv4AddressIoctl(ifname, addr)) != -2) + return ret; + + virReportSystemError(ENOSYS, "%s", + _("Unable to get IP address on this platform")); + return -1; +} /** * virNetDevValidateConfig: diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h index 856127b..fb0fd46 100644 --- a/src/util/virnetdev.h +++ b/src/util/virnetdev.h @@ -103,7 +103,7 @@ int virNetDevClearIPAddress(const char *ifname, virSocketAddr *addr, unsigned int prefix) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; -int virNetDevGetIPv4Address(const char *ifname, virSocketAddrPtr addr) +int virNetDevGetIPAddress(const char *ifname, virSocketAddrPtr addr) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; -- 2.0.5

From: Luyao Huang <lhuang@redhat.com> Add static virNetDevGetifaddrsAddress to attempt to get the interface IP address. If getifaddrs is not supported, fall back to virNetDevGetIPv4AddressIoctl to get the IP address. This allows IPv6 addresses to be used for <listen type='network> with device-backed networks. https://bugzilla.redhat.com/show_bug.cgi?id=1192318 Signed-off-by: Luyao Huang <lhuang@redhat.com> Signed-off-by: John Ferlan <jferlan@redhat.com> Signed-off-by: Ján Tomko <jtomko@redhat.com> --- src/util/virnetdev.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index 59593f9..a7903c3 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -33,6 +33,10 @@ #include "virstring.h" #include "virutil.h" +#if HAVE_GETIFADDRS +# include <ifaddrs.h> +#endif + #include <sys/ioctl.h> #include <net/if.h> #include <fcntl.h> @@ -1436,6 +1440,70 @@ virNetDevGetIPv4AddressIoctl(const char *ifname ATTRIBUTE_UNUSED, #endif /* ! SIOCGIFADDR */ /** + * virNetDevGetifaddrsAddress: + * @ifname: name of the interface whose IP address we want + * @addr: filled with the IP address + * + * This function gets the IP address for the interface @ifname + * and stores it in @addr + * + * Returns 0 on success, -1 on failure, -2 on unsupported. + */ +#if HAVE_GETIFADDRS +static int +virNetDevGetifaddrsAddress(const char *ifname, + virSocketAddrPtr addr) +{ + struct ifaddrs *ifap, *ifa; + int ret = -1; + + if (getifaddrs(&ifap) < 0) { + virReportSystemError(errno, + _("Could not get interface list for '%s'"), + ifname); + return -1; + } + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + int family = ifa->ifa_addr->sa_family; + + if (STRNEQ_NULLABLE(ifa->ifa_name, ifname)) + continue; + if (family != AF_INET6 && family != AF_INET) + continue; + + if (family == AF_INET6) { + addr->len = sizeof(addr->data.inet6); + memcpy(&addr->data.inet6, ifa->ifa_addr, addr->len); + } else { + addr->len = sizeof(addr->data.inet4); + memcpy(&addr->data.inet4, ifa->ifa_addr, addr->len); + } + addr->data.stor.ss_family = family; + ret = 0; + goto cleanup; + } + + virReportError(VIR_ERR_INTERNAL_ERROR, + _("no IP address found for interface '%s'"), + ifname); + cleanup: + freeifaddrs(ifap); + return ret; +} + +#else /* ! HAVE_GETIFADDRS */ + +static int +virNetDevGetifaddrsAddress(const char *ifname ATTRIBUTE_UNUSED, + virSocketAddrPtr addr ATTRIBUTE_UNUSED) +{ + return -2; +} + +#endif + +/** * virNetDevGetIPAddress: * @ifname: name of the interface whose IP address we want * @addr: filled with the IPv4 address @@ -1454,6 +1522,9 @@ virNetDevGetIPAddress(const char *ifname, memset(addr, 0, sizeof(*addr)); addr->data.stor.ss_family = AF_UNSPEC; + if ((ret = virNetDevGetifaddrsAddress(ifname, addr)) != -2) + return ret; + if ((ret = virNetDevGetIPv4AddressIoctl(ifname, addr)) != -2) return ret; -- 2.0.5

We've been explicitly requesting IPv4 for some reason, even if there were only IPv6 addresses in the network definition. https://bugzilla.redhat.com/show_bug.cgi?id=1192318 --- src/network/bridge_driver.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 6db368b..d195085 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -4485,12 +4485,12 @@ networkReleaseActualDevice(virDomainDefPtr dom, * @netname: the name of a network * @netaddr: string representation of IP address for that network. * - * Attempt to return an IP (v4) address associated with the named + * Attempt to return an IP address associated with the named * network. If a libvirt virtual network, that will be provided in the * configuration. For host bridge and direct (macvtap) networks, we * must do an ioctl to learn the address. * - * Note: This function returns the 1st IPv4 address it finds. It might + * Note: This function returns the first IP address it finds. It might * be useful if it was more flexible, but the current use (getting a * listen address for qemu's vnc/spice graphics server) can only use a * single address anyway. @@ -4525,11 +4525,10 @@ networkGetNetworkAddress(const char *netname, char **netaddr) case VIR_NETWORK_FORWARD_NONE: case VIR_NETWORK_FORWARD_NAT: case VIR_NETWORK_FORWARD_ROUTE: - /* if there's an ipv4def, get it's address */ - ipdef = virNetworkDefGetIpByIndex(netdef, AF_INET, 0); + ipdef = virNetworkDefGetIpByIndex(netdef, AF_UNSPEC, 0); if (!ipdef) { virReportError(VIR_ERR_INTERNAL_ERROR, - _("network '%s' doesn't have an IPv4 address"), + _("network '%s' doesn't have an IP address"), netdef->name); goto cleanup; } -- 2.0.5

On 04/08/2015 11:35 AM, Ján Tomko wrote:
v1: https://www.redhat.com/archives/libvir-list/2015-February/msg00442.html v2: https://www.redhat.com/archives/libvir-list/2015-February/msg01228.html v3: https://www.redhat.com/archives/libvir-list/2015-March/msg00423.html changes in v4: * remove the family attribute and just return the first IP address * rename virNetDevGetIPv4Address to virNetDevGetIPv4AddressIoctl
John Ferlan (1): util: Replace virNetDevGetIPv4Address with virNetDevGetIPAddress
Ján Tomko (1): Support IPv6 in networkGetNetworkAddress
Luyao Huang (1): util: Update virNetDevGetIPAddress to get IPv6 addresses
src/libvirt_private.syms | 2 +- src/network/bridge_driver.c | 11 ++-- src/util/virnetdev.c | 119 +++++++++++++++++++++++++++++++++++++++----- src/util/virnetdev.h | 2 +- 4 files changed, 114 insertions(+), 20 deletions(-)
ACK series - John Thanks for picking this up - it was in my list but didn't rotate back to it yet...

On 04/08/2015 11:35 PM, Ján Tomko wrote:
v1: https://www.redhat.com/archives/libvir-list/2015-February/msg00442.html v2: https://www.redhat.com/archives/libvir-list/2015-February/msg01228.html v3: https://www.redhat.com/archives/libvir-list/2015-March/msg00423.html changes in v4: * remove the family attribute and just return the first IP address * rename virNetDevGetIPv4Address to virNetDevGetIPv4AddressIoctl
John Ferlan (1): util: Replace virNetDevGetIPv4Address with virNetDevGetIPAddress
Ján Tomko (1): Support IPv6 in networkGetNetworkAddress
Luyao Huang (1): util: Update virNetDevGetIPAddress to get IPv6 addresses
Oh, thanks a lot for your help, i was hesitating if i need give a new version :)
src/libvirt_private.syms | 2 +- src/network/bridge_driver.c | 11 ++-- src/util/virnetdev.c | 119 +++++++++++++++++++++++++++++++++++++++----- src/util/virnetdev.h | 2 +- 4 files changed, 114 insertions(+), 20 deletions(-)
Luyao
participants (3)
-
John Ferlan
-
Ján Tomko
-
lhuang