From 05630cf4e516aad42ae47a69a75f9839bb42ccab Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Thu, 5 Jun 2014 16:14:49 +0200 Subject: [PATCH] virnetdev: Introduce virNetDevGetLinkInfo The purpose of this function is to fetch link state and link speed for given NIC name from the SYSFS. Signed-off-by: Michal Privoznik --- src/libvirt_private.syms | 1 + src/util/virnetdev.c | 94 ++++++++++++++++++++++++++++++++++++++++ src/util/virnetdev.h | 5 +++ 3 files changed, 100 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 7a740abfb1..122c572cd2 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1542,6 +1542,7 @@ virNetDevClearIPv4Address; virNetDevExists; virNetDevGetIndex; virNetDevGetIPv4Address; +virNetDevGetLinkInfo; virNetDevGetMAC; virNetDevGetMTU; virNetDevGetPhysicalFunction; diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index 3a60cf7c43..cbf086e106 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -1832,3 +1832,97 @@ virNetDevRestoreNetConfig(const char *linkdev ATTRIBUTE_UNUSED, } #endif /* defined(__linux__) && defined(HAVE_LIBNL) */ + +#ifdef __linux__ +int +virNetDevGetLinkInfo(const char *ifname, + virInterfaceLinkPtr lnk) +{ + int ret = -1; + char *path = NULL; + char *buf = NULL; + char *tmp; + int tmp_state; + unsigned int tmp_speed; + + if (virNetDevSysfsFile(&path, ifname, "operstate") < 0) + goto cleanup; + + if (virFileReadAll(path, 1024, &buf) < 0) { + virReportSystemError(errno, + _("unable to read: %s"), + path); + goto cleanup; + } + + if (!(tmp = strchr(buf, '\n'))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to parse: %s"), + buf); + goto cleanup; + } + + *tmp = '\0'; + + /* We shouldn't allow 0 here, because + * virInterfaceState enum starts from 1. */ + if ((tmp_state = virInterfaceStateTypeFromString(buf)) <= 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to parse: %s"), + buf); + goto cleanup; + } + + lnk->state = tmp_state; + + VIR_FREE(path); + VIR_FREE(buf); + + if (virNetDevSysfsFile(&path, ifname, "speed") < 0) + goto cleanup; + + if (virFileReadAll(path, 1024, &buf) < 0) { + /* Some devices doesn't report speed, in which case we get EINVAL */ + if (errno == EINVAL) { + ret = 0; + goto cleanup; + } + virReportSystemError(errno, + _("unable to read: %s"), + path); + goto cleanup; + } + + if (virStrToLong_ui(buf, &tmp, 10, &tmp_speed) < 0 || + *tmp != '\n') { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to parse: %s"), + buf); + goto cleanup; + } + + /* Workaround broken kernel API. If the link is unplugged then + * depending on the NIC driver, link speed can be reported as -1. + * However, the value is printed out as unsigned integer instead of + * signed one. Terrifying but true. */ + lnk->speed = (int) tmp_speed == -1 ? 0 : tmp_speed; + + ret = 0; + cleanup: + VIR_FREE(buf); + VIR_FREE(path); + return ret; +} + +#else + +int +virNetDevGetLinkInfo(const char *ifname, + virInterfaceLinkPtr lnk) +{ + /* Port me */ + VIR_DEBUG("Getting link info on %s is not implemented on this platform"); + lnk->speed = lnk->state = 0; + return 0; +} +#endif /* defined(__linux__) */ diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h index 00c82e0d5f..69e365e741 100644 --- a/src/util/virnetdev.h +++ b/src/util/virnetdev.h @@ -29,6 +29,7 @@ # include "virnetlink.h" # include "virmacaddr.h" # include "virpci.h" +# include "device_conf.h" # ifdef HAVE_STRUCT_IFREQ typedef struct ifreq virIfreq; @@ -145,4 +146,8 @@ int virNetDevGetVirtualFunctionInfo(const char *vfname, char **pfname, int *vf) ATTRIBUTE_NONNULL(1); +int virNetDevGetLinkInfo(const char *ifname, + virInterfaceLinkPtr lnk) + ATTRIBUTE_NONNULL(1); + #endif /* __VIR_NETDEV_H__ */