[libvirt] [PATCHv2 4/5] interface: add virInterfaceGetXMLDesc() in udev

Doug Goldstein cardoe at cardoe.com
Sat Oct 6 19:20:28 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.
---
***
* NOTE: I'm aware this is incomplete (e.g. no bond support) and we aren't
*       showing devices in a bridge. This patch can be considered only a RFC
*       or it can be applied and I'll work on further support as I figure
*       out how to implement it. Waiting for feedback from LKML and from
*       the udev ML on some questions or patches.
***

change since v1:
* support vlans
* cleanups for simplifications

 src/interface/interface_backend_udev.c |  128 ++++++++++++++++++++++++++++++++
 1 files changed, 128 insertions(+), 0 deletions(-)

diff --git a/src/interface/interface_backend_udev.c b/src/interface/interface_backend_udev.c
index b001e6e..2f37bed 100644
--- a/src/interface/interface_backend_udev.c
+++ b/src/interface/interface_backend_udev.c
@@ -489,6 +489,133 @@ err:
     return ret;
 }
 
+static char *
+udevIfaceGetXMLDesc(virInterfacePtr ifinfo,
+                    unsigned int flags)
+{
+    struct udev_iface_driver *driverState = ifinfo->conn->interfacePrivateData;
+    struct udev *udev = udev_ref(driverState->udev);
+    struct udev_device *dev;
+    virInterfaceDef ifacedef;
+    unsigned int mtu;
+    const char *mtu_str;
+    char *vlan_parent_dev = NULL;
+    char *xmlstr = NULL;
+
+    virCheckFlags(VIR_INTERFACE_XML_INACTIVE, NULL);
+
+    /* Lookup the device we've been asked about */
+    dev = udev_device_new_from_subsystem_sysname(udev, "net",
+                                                 ifinfo->name);
+    if (!dev) {
+        virReportError(VIR_ERR_NO_INTERFACE,
+                       _("couldn't find interface named '%s'"),
+                       ifinfo->name);
+        goto cleanup;
+    }
+
+    /* Zero it all out */
+    memset(&ifacedef, 0, sizeof(ifacedef));
+
+    /* Common pieces */
+    ifacedef.name = ifinfo->name;
+    ifacedef.mac = ifinfo->mac;
+    ifacedef.startmode = VIR_INTERFACE_START_UNSPECIFIED;
+
+    /* 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(ifinfo->name, '.');
+    if (vlan_parent_dev) {
+        /* Found the VLAN dot */
+        char *vid;
+
+        vlan_parent_dev = strdup(ifinfo->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'"),
+                           ifinfo->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 */
+        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 */
+        /* XXX: Waiting to hear back from the udev/systemd ML how to
+         * successfully query this.
+         */
+        ifacedef.data.bridge.nbItf = 0;
+        ifacedef.data.bridge.itf = NULL;
+    } else {
+        /* Set our type to ethernet */
+        ifacedef.type = VIR_INTERFACE_TYPE_ETHERNET;
+    }
+
+    /* Convert our interface to XML */
+    xmlstr = virInterfaceDefFormat(&ifacedef);
+
+cleanup:
+    if (ifacedef.type == VIR_INTERFACE_TYPE_BRIDGE)
+        VIR_FREE(ifacedef.data.bridge.delay);
+
+    VIR_FREE(vlan_parent_dev);
+
+    udev_unref(udev);
+    return xmlstr;
+}
+
 static virInterfaceDriver udevIfaceDriver = {
     "udev",
     .open = udevIfaceOpenInterface, /* 0.10.3 */
@@ -500,6 +627,7 @@ static virInterfaceDriver udevIfaceDriver = {
     .listAllInterfaces = udevIfaceListAllInterfaces, /* 0.10.3 */
     .interfaceLookupByName = udevIfaceLookupByName, /* 0.10.3 */
     .interfaceLookupByMACString = udevIfaceLookupByMACString, /* 0.10.3 */
+    .interfaceGetXMLDesc = udevIfaceGetXMLDesc, /* 0.10.3 */
 };
 
 int
-- 
1.7.8.6




More information about the libvir-list mailing list