While the previous commit was pretty straightforward, things are
different with netcf as it doesn't exposed the bits we need yet.
However, we can work around it by fetching the info we need from
SYSFS.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
Notes:
I know Laine volunteered to contribute patches to netcf so we
don't need this patch then. If that's still the case, we don't
need to bother with this one.
src/interface/interface_backend_netcf.c | 104 ++++++++++++++++++++++++++++++++
1 file changed, 104 insertions(+)
diff --git a/src/interface/interface_backend_netcf.c
b/src/interface/interface_backend_netcf.c
index 1b9ace5..978b3af 100644
--- a/src/interface/interface_backend_netcf.c
+++ b/src/interface/interface_backend_netcf.c
@@ -33,6 +33,7 @@
#include "virlog.h"
#include "virstring.h"
#include "viraccessapicheck.h"
+#include "virfile.h"
#define VIR_FROM_THIS VIR_FROM_INTERFACE
@@ -240,6 +241,103 @@ static struct netcf_if *interfaceDriverGetNetcfIF(struct netcf *ncf,
virInterfac
return iface;
}
+/* Okay, the following two doesn't really belong here as they dump the info
+ * from SYSFS rather than netcf. But netcf is not yet exposing the info we
+ * need, so what. */
+#define SYSFS_PREFIX "/sys/class/net/"
+
+static int
+interfaceGetState(const char *name,
+ virInterfaceState *state)
+{
+ int ret = -1;
+ char *path = NULL;
+ char *buf = NULL;
+ char *tmp;
+
+ if (virAsprintf(&path, SYSFS_PREFIX "%s/operstate", name) < 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 ((*state = virInterfaceStateTypeFromString(buf)) <= 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unable to parse: %s"),
+ buf);
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ VIR_FREE(buf);
+ VIR_FREE(path);
+ return ret;
+}
+
+static int
+interfaceGetSpeed(const char *name,
+ unsigned long *speed)
+{
+ int ret = -1;
+ char *path = NULL;
+ char *buf = NULL;
+ char *tmp;
+
+ if (virAsprintf(&path, SYSFS_PREFIX "%s/speed", name) < 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_ul(buf, &tmp, 10, 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. */
+ if ((int) *speed == -1)
+ *speed = 0;
+
+ ret = 1;
+ cleanup:
+ VIR_FREE(buf);
+ VIR_FREE(path);
+ return ret;
+}
+
+/* Ond of sysfs hacks */
+
static int
netcfInterfaceObjIsActive(struct netcf_if *iface,
bool *active)
@@ -840,6 +938,12 @@ static char *netcfInterfaceGetXMLDesc(virInterfacePtr ifinfo,
if (virInterfaceGetXMLDescEnsureACL(ifinfo->conn, ifacedef) < 0)
goto cleanup;
+ if (interfaceGetState(ifacedef->name, &ifacedef->lnk.state) < 0)
+ goto cleanup;
+
+ if (interfaceGetSpeed(ifacedef->name, &ifacedef->lnk.speed) < 0)
+ goto cleanup;
+
ret = virInterfaceDefFormat(ifacedef);
if (!ret) {
/* error was already reported */
--
2.0.0