From: Luyao Huang <lhuang(a)redhat.com>
Add static virNetDevGetIfaddrsAddress to attempt to get interface IPv6
or IPv4 address. If that fails, if an IPv4 address is desired, then
fall back to try the virNetDevGetIPv4Address to get the IP address.
Signed-off-by: Luyao Huang <lhuang(a)redhat.com>
Signed-off-by: John Ferlan <jferlan(a)redhat.com>
---
src/network/bridge_driver.c | 2 +-
src/util/virnetdev.c | 97 +++++++++++++++++++++++++++++++++++++++++----
src/util/virnetdev.h | 7 ++--
3 files changed, 95 insertions(+), 11 deletions(-)
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 281612a..5186be8 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -4569,7 +4569,7 @@ networkGetNetworkAddress(const char *netname, char **netaddr)
}
if (dev_name) {
- if (virNetDevGetIPAddress(dev_name, &addr) < 0)
+ if (virNetDevGetIPAddress(dev_name, false, &addr) < 0)
goto cleanup;
addrptr = &addr;
}
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
index fd480e9..50f6f0f 100644
--- a/src/util/virnetdev.c
+++ b/src/util/virnetdev.c
@@ -33,6 +33,10 @@
#include "virstring.h"
#include "virutil.h"
+#if defined(HAVE_GETIFADDRS)
+# include <ifaddrs.h>
+#endif
+
#include <sys/ioctl.h>
#include <net/if.h>
#include <fcntl.h>
@@ -1403,9 +1407,6 @@ virNetDevGetIPv4Address(const char *ifname,
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;
@@ -1431,16 +1432,79 @@ static int
virNetDevGetIPv4Address(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 */
/**
+ * virNetDevGetIfaddrsAddress:
+ * @ifname: name of the interface whose IP address we want
+ * @want_ipv6: get IPv4 or IPv6 address
+ * @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 defined(HAVE_GETIFADDRS)
+static int
+virNetDevGetIfaddrsAddress(const char *ifname,
+ bool want_ipv6,
+ 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) {
+ if (STRNEQ_NULLABLE(ifa->ifa_name, ifname))
+ continue;
+ if (ifa->ifa_addr->sa_family == (want_ipv6 ? AF_INET6 : AF_INET)) {
+ if (want_ipv6) {
+ 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 = ifa->ifa_addr->sa_family;
+ ret = 0;
+ goto cleanup;
+ }
+ }
+
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unable to find %s address for interface '%s'"),
+ want_ipv6 ? "IPv6" : "IPv4", ifname);
+ cleanup:
+ freeifaddrs(ifap);
+ return ret;
+}
+
+#else /* ! defined(HAVE_GETIFADDRS) */
+
+static int
+virNetDevGetIfaddrsAddress(const char *ifname ATTRIBUTE_UNUSED,
+ bool want_ipv6 ATTRIBUTE_UNUSED,
+ virSocketAddrPtr addr ATTRIBUTE_UNUSED)
+{
+ return -2;
+}
+
+#endif
+
+/**
* virNetDevGetIPAddress:
* @ifname: name of the interface whose IP address we want
+ * @want_ipv6: get IPv4 or IPv6 address
* @addr: filled with the IPv4 address
*
* This function gets the IPv4 address for the interface @ifname
@@ -1450,9 +1514,28 @@ virNetDevGetIPv4Address(const char *ifname ATTRIBUTE_UNUSED,
*/
int
virNetDevGetIPAddress(const char *ifname,
+ bool want_ipv6,
virSocketAddrPtr addr)
{
- return virNetDevGetIPv4Address(ifname, addr);
+ int ret;
+
+ memset(addr, 0, sizeof(*addr));
+ addr->data.stor.ss_family = AF_UNSPEC;
+
+ ret = virNetDevGetIfaddrsAddress(ifname, want_ipv6, addr);
+ if (ret != -2)
+ return ret;
+
+ if (!want_ipv6)
+ ret = virNetDevGetIPv4Address(ifname, addr);
+
+ if (ret != -2)
+ return ret;
+
+ virReportSystemError(ENOSYS,
+ _("Unable to get %s address on this platform"),
+ want_ipv6 ? "IPv6" : "IPv4");
+ return -1;
}
/**
diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h
index fb0fd46..620db50 100644
--- a/src/util/virnetdev.h
+++ b/src/util/virnetdev.h
@@ -103,9 +103,10 @@ int virNetDevClearIPAddress(const char *ifname,
virSocketAddr *addr,
unsigned int prefix)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
-int virNetDevGetIPAddress(const char *ifname, virSocketAddrPtr addr)
- ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
-
+int virNetDevGetIPAddress(const char *ifname,
+ bool want_ipv6,
+ virSocketAddrPtr addr)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
int virNetDevSetMAC(const char *ifname,
const virMacAddr *macaddr)
--
2.1.0