[libvirt] [PATCH] interface: add virInterfaceGetXMLDesc() in udev

Doug Goldstein cardoe at cardoe.com
Sun Oct 14 22:02:33 UTC 2012


Added support for retrieving the XML defining a specific interface via
the udev based backend to virInterface. Implement the following APIs
for the udev based backend:
* virInterfaceGetXMLDesc()

Note: Does not support bond devices.
---
 src/interface/interface_backend_udev.c |  251 ++++++++++++++++++++++++++++++++
 1 files changed, 251 insertions(+), 0 deletions(-)

diff --git a/src/interface/interface_backend_udev.c b/src/interface/interface_backend_udev.c
index 1cb6dfe..370f64a 100644
--- a/src/interface/interface_backend_udev.c
+++ b/src/interface/interface_backend_udev.c
@@ -19,6 +19,8 @@
  */
 #include <config.h>
 
+#include <errno.h>
+#include <dirent.h>
 #include <libudev.h>
 
 #include "virterror_internal.h"
@@ -489,6 +491,254 @@ err:
     return ret;
 }
 
+/**
+ * Helper function for our use of scandir()
+ *
+ * @param entry - directory entry passed by scandir()
+ *
+ * @return 1 if we want to add it to scandir's list, 0 if not.
+ */
+static int
+udevIfaceScanDirFilter(const struct dirent *entry)
+{
+    if (STREQ(entry->d_name, ".") || STREQ(entry->d_name, ".."))
+        return 0;
+
+    return 1;
+}
+
+/**
+ * Frees any memory allocated by udevIfaceGetIfaceDef()
+ *
+ * @param ifacedef - interface to free and cleanup
+ */
+static void
+udevIfaceFreeIfaceDef(virInterfaceDef *ifacedef)
+{
+    if (!ifacedef)
+        return;
+
+    if (ifacedef->type == VIR_INTERFACE_TYPE_BRIDGE) {
+        VIR_FREE(ifacedef->data.bridge.delay);
+        for (int i = 0; i < ifacedef->data.bridge.nbItf; i++) {
+            VIR_FREE(ifacedef->data.bridge.itf[i]);
+        }
+        VIR_FREE(ifacedef->data.bridge.itf);
+    }
+
+    if (ifacedef->type == VIR_INTERFACE_TYPE_VLAN) {
+        VIR_FREE(ifacedef->data.vlan.devname);
+    }
+
+    VIR_FREE(ifacedef->mac);
+    VIR_FREE(ifacedef->name);
+
+    VIR_FREE(ifacedef);
+}
+
+
+static virInterfaceDef * ATTRIBUTE_NONNULL(1)
+udevIfaceGetIfaceDef(struct udev *udev, char *name)
+{
+    struct udev_device *dev;
+    virInterfaceDef *ifacedef;
+    unsigned int mtu;
+    const char *mtu_str;
+    char *vlan_parent_dev = NULL;
+    struct dirent **member_list = NULL;
+    int member_count = 0;
+
+    /* Allocate our interface definition structure */
+    if (VIR_ALLOC(ifacedef) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    /* Clear our structure and set safe defaults */
+    memset(ifacedef, 0, sizeof(ifacedef));
+    ifacedef->startmode = VIR_INTERFACE_START_UNSPECIFIED;
+    ifacedef->type = VIR_INTERFACE_TYPE_ETHERNET;
+    ifacedef->name = strdup(name);
+
+    if (!ifacedef->name) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    /* Lookup the device we've been asked about */
+    dev = udev_device_new_from_subsystem_sysname(udev, "net", name);
+    if (!dev) {
+        virReportError(VIR_ERR_NO_INTERFACE,
+                       _("couldn't find interface named '%s'"), name);
+        goto cleanup;
+    }
+
+    /* MAC address */
+    ifacedef->mac = strdup(udev_device_get_sysattr_value(dev, "address"));
+    if (!ifacedef) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    /* MTU */
+    mtu_str = udev_device_get_sysattr_value(dev, "mtu");
+    if (virStrToLong_ui(mtu_str, NULL, 10, &mtu) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                _("Could not parse MTU value '%s'"), mtu_str);
+        goto cleanup;
+    }
+    ifacedef->mtu = mtu;
+
+    /* Number of IP protocols this interface has assigned */
+    /* XXX: Do we want a netlink query or a call out to ip or leave it? */
+    ifacedef->nprotos = 0;
+    ifacedef->protos = NULL;
+
+    /* Check if its a VLAN since we can have a VLAN of any of the
+     * other devices */
+    vlan_parent_dev = strrchr(name, '.');
+    if (vlan_parent_dev) {
+        /* Found the VLAN dot */
+        char *vid;
+
+        vlan_parent_dev = strdup(name);
+        if (!vlan_parent_dev) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        /* Find the DEVICE.VID separator again */
+        vid = strrchr(vlan_parent_dev, '.');
+        if (!vid) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("failed to find the VID for the VLAN device '%s'"),
+                           name);
+            goto cleanup;
+        }
+
+        /* Replace the dot with a NULL so we can have the device and VID */
+        vid[0] = '\0';
+        vid++;
+
+        /* Set our type to VLAN  */
+        ifacedef->type = VIR_INTERFACE_TYPE_VLAN;
+
+        /* Set the VLAN specifics */
+        ifacedef->data.vlan.tag = vid;
+        ifacedef->data.vlan.devname = vlan_parent_dev;
+    } else if (STREQ_NULLABLE(udev_device_get_devtype(dev), "bridge")) {
+        /* Check if its a bridge device */
+        char *member_path;
+        const char *stp_str;
+        int stp;
+
+        /* Set our type to Bridge  */
+        ifacedef->type = VIR_INTERFACE_TYPE_BRIDGE;
+
+        /* Bridge specifics */
+        ifacedef->data.bridge.delay =
+            strdup(udev_device_get_sysattr_value(dev, "bridge/forward_delay"));
+        if (!ifacedef->data.bridge.delay) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        stp_str = udev_device_get_sysattr_value(dev, "bridge/stp_state");
+        if (virStrToLong_i(stp_str, NULL, 10, &stp) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Could not parse STP state '%s'"), stp_str);
+            goto cleanup;
+        }
+        ifacedef->data.bridge.stp = stp;
+
+        /* Members of the bridge */
+        virAsprintf(&member_path, "%s/%s",
+                    udev_device_get_syspath(dev), "brif");
+        if (!member_path) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        /* Get each member of the bridge */
+        member_count = scandir(member_path, &member_list,
+                               udevIfaceScanDirFilter, alphasort);
+
+        /* Don't need the path anymore */
+        VIR_FREE(member_path);
+
+        if (member_count < 0) {
+            virReportSystemError(errno,
+                                 _("Could not get members of bridge '%s'"),
+                                 name);
+            goto cleanup;
+        }
+
+        /* Allocate our list of member devices */
+        if (VIR_ALLOC_N(ifacedef->data.bridge.itf, member_count) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+        ifacedef->data.bridge.nbItf = member_count;
+
+        for (int i= 0; i < member_count; i++) {
+            ifacedef->data.bridge.itf[i] =
+                udevIfaceGetIfaceDef(udev, member_list[i]->d_name);
+            VIR_FREE(member_list[i]);
+        }
+
+        VIR_FREE(member_list);
+
+    } else {
+        /* Set our type to ethernet */
+        ifacedef->type = VIR_INTERFACE_TYPE_ETHERNET;
+    }
+
+    return ifacedef;
+
+cleanup:
+    for (int i = 0; i < member_count; i++) {
+        VIR_FREE(member_list[i]);
+    }
+    VIR_FREE(member_list);
+
+    udevIfaceFreeIfaceDef(ifacedef);
+
+    return NULL;
+}
+
+static char *
+udevIfaceGetXMLDesc(virInterfacePtr ifinfo,
+                    unsigned int flags)
+{
+    struct udev_iface_driver *driverState = ifinfo->conn->interfacePrivateData;
+    struct udev *udev = udev_ref(driverState->udev);
+    virInterfaceDef *ifacedef;
+    char *xmlstr = NULL;
+
+    virCheckFlags(VIR_INTERFACE_XML_INACTIVE, NULL);
+
+    /* Recursively build up the interface XML based on the requested
+     * interface name
+     */
+    ifacedef = udevIfaceGetIfaceDef(udev, ifinfo->name);
+
+    /* We've already printed by it happened */
+    if (!ifacedef)
+        goto err;
+
+    /* Convert our interface to XML */
+    xmlstr = virInterfaceDefFormat(ifacedef);
+
+    /* Recursively free our interface structures and free the children too */
+    udevIfaceFreeIfaceDef(ifacedef);
+
+err:
+    /* decrement our udev ptr */
+    udev_unref(udev);
+
+    return xmlstr;
+}
+
 static int
 udevIfaceIsActive(virInterfacePtr ifinfo)
 {
@@ -529,6 +779,7 @@ static virInterfaceDriver udevIfaceDriver = {
     .listAllInterfaces = udevIfaceListAllInterfaces, /* 0.10.3 */
     .interfaceLookupByName = udevIfaceLookupByName, /* 0.10.3 */
     .interfaceLookupByMACString = udevIfaceLookupByMACString, /* 0.10.3 */
+    .interfaceGetXMLDesc = udevIfaceGetXMLDesc, /* 0.10.3 */
     .interfaceIsActive = udevIfaceIsActive, /* 0.10.3 */
 };
 
-- 
1.7.8.6




More information about the libvir-list mailing list