interface: add virInterfaceGetXMLDesc() in udev

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.
This commit is contained in:
Doug Goldstein 2012-10-14 17:02:33 -05:00 committed by Michal Privoznik
parent 740225a1cb
commit 1e7ec88d9a

View File

@ -19,6 +19,8 @@
*/
#include <config.h>
#include <errno.h>
#include <dirent.h>
#include <libudev.h>
#include "virterror_internal.h"
@ -489,6 +491,256 @@ 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++) {
udevIfaceFreeIfaceDef(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 = NULL;
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 */
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;
}
udev_device_unref(dev);
return ifacedef;
cleanup:
udev_device_unref(dev);
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)
{
@ -530,6 +782,7 @@ static virInterfaceDriver udevIfaceDriver = {
.interfaceLookupByName = udevIfaceLookupByName, /* 1.0.0 */
.interfaceLookupByMACString = udevIfaceLookupByMACString, /* 1.0.0 */
.interfaceIsActive = udevIfaceIsActive, /* 1.0.0 */
.interfaceGetXMLDesc = udevIfaceGetXMLDesc, /* 1.0.0 */
};
int