mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-22 11:22:23 +00:00
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:
parent
740225a1cb
commit
1e7ec88d9a
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user