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

Michal Privoznik mprivozn at redhat.com
Wed Oct 17 12:09:33 UTC 2012


On 15.10.2012 00:02, Doug Goldstein wrote:
> 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]);

Shouldn't we call udevIfaceFreeIfaceDef() here instead of VIR_FREE()?
The fact that this is filled by udevIfaceGetIfaceDef() makes my conviction even stronger.

> +        }
> +        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));

This is not needed since VIR_ALLOC uses calloc which is guaranteed to fill allocated memory with zeros.

> +    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);

This call should be followed by udev_device_unref().

> +    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"));

While all NICs should have MAC we are safe here. Otherwise, strdup(NULL) won't play nicely.

> +    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 */
>  };
>  
> 

Yeah, Eric actually went ahead and change these to 1.0.0 so this made a tiny conflict which is easily resolvable.


Otherwise looking good. ACK.

I'm squashing this before pushing:

diff --git a/src/interface/interface_backend_udev.c b/src/interface/interface_backend_udev.c
index 88fa7c7..5a27cc5 100644
--- a/src/interface/interface_backend_udev.c
+++ b/src/interface/interface_backend_udev.c
@@ -521,7 +521,7 @@ udevIfaceFreeIfaceDef(virInterfaceDef *ifacedef)
     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]);
+            udevIfaceFreeIfaceDef(ifacedef->data.bridge.itf[i]);
         }
         VIR_FREE(ifacedef->data.bridge.itf);
     }
@@ -540,7 +540,7 @@ udevIfaceFreeIfaceDef(virInterfaceDef *ifacedef)
 static virInterfaceDef * ATTRIBUTE_NONNULL(1)
 udevIfaceGetIfaceDef(struct udev *udev, char *name)
 {
-    struct udev_device *dev;
+    struct udev_device *dev = NULL;
     virInterfaceDef *ifacedef;
     unsigned int mtu;
     const char *mtu_str;
@@ -555,7 +555,6 @@ udevIfaceGetIfaceDef(struct udev *udev, char *name)
     }
 
     /* 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);
@@ -693,9 +692,12 @@ udevIfaceGetIfaceDef(struct udev *udev, char *name)
         ifacedef->type = VIR_INTERFACE_TYPE_ETHERNET;
     }
 
+    udev_device_unref(dev);
+
     return ifacedef;
 
 cleanup:
+    udev_device_unref(dev);
     for (int i = 0; i < member_count; i++) {
         VIR_FREE(member_list[i]);
     }

---

Michal




More information about the libvir-list mailing list