[libvirt] [PATCHv2 5/6] interface: add bond support to udev backend
Laine Stump
laine at laine.org
Thu Feb 21 21:07:41 UTC 2013
On 02/20/2013 02:56 PM, Doug Goldstein wrote:
> The udev backend now supports bond interfaces.
> ---
> src/interface/interface_backend_udev.c | 264 ++++++++++++++++++++++++++++++++-
> 1 file changed, 263 insertions(+), 1 deletion(-)
>
> diff --git a/src/interface/interface_backend_udev.c b/src/interface/interface_backend_udev.c
> index db4e7d1..9f1570c 100644
> --- a/src/interface/interface_backend_udev.c
> +++ b/src/interface/interface_backend_udev.c
> @@ -494,6 +494,27 @@ err:
> }
>
> /**
> + * Helper function for finding bond slaves using 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
> +udevIfaceBondScanDirFilter(const struct dirent *entry)
> +{
> + /* This is ugly so if anyone has a better suggestion, please improve
> + * this. Unfortunately the kernel stores everything in the top level
> + * interface sysfs entry and references the slaves as slave_eth0 for
> + * example.
> + */
> + if (STRPREFIX(entry->d_name, "slave_"))
> + return 1;
> +
> + return 0;
> +}
> +
> +/**
> * Helper function for finding bridge members using scandir()
> *
> * @param entry - directory entry passed by scandir()
> @@ -522,6 +543,14 @@ udevIfaceFreeIfaceDef(virInterfaceDef *ifacedef)
> if (!ifacedef)
> return;
>
> + if (ifacedef->type == VIR_INTERFACE_TYPE_BOND) {
> + VIR_FREE(ifacedef->data.bond.target);
> + for (i = 0; i < ifacedef->data.bond.nbItf; i++) {
> + udevIfaceFreeIfaceDef(ifacedef->data.bond.itf[i]);
> + }
> + VIR_FREE(ifacedef->data.bond.itf);
> + }
> +
> if (ifacedef->type == VIR_INTERFACE_TYPE_BRIDGE) {
> VIR_FREE(ifacedef->data.bridge.delay);
> for (i = 0; i < ifacedef->data.bridge.nbItf; i++) {
> @@ -543,6 +572,230 @@ udevIfaceFreeIfaceDef(virInterfaceDef *ifacedef)
> static int
> ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
> ATTRIBUTE_NONNULL(4) ATTRIBUTE_RETURN_CHECK
> +udevIfaceGetIfaceDefBond(struct udev *udev,
> + struct udev_device *dev,
> + const char *name,
> + virInterfaceDef *ifacedef)
> +{
> + struct dirent **slave_list = NULL;
> + int slave_count = 0;
> + int i;
> + const char *tmp_str;
> + int tmp_int;
> +
> + /* Initial defaults */
> + ifacedef->data.bond.target = NULL;
> + ifacedef->data.bond.nbItf = 0;
> + ifacedef->data.bond.itf = NULL;
> +
> + /* Set the bond specifics */
> + tmp_str = udev_device_get_sysattr_value(dev, "bonding/downdelay");
> + if (!tmp_str) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Could not retrieve 'bonding/downdelay' for '%s'"), name);
> + goto cleanup;
> + }
> + if (virStrToLong_i(tmp_str, NULL, 10, &tmp_int) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Could not parse 'bonding/downdelay' '%s' for '%s'"),
> + tmp_str, name);
> + goto cleanup;
> + }
> + ifacedef->data.bond.downdelay = tmp_int;
> +
> + tmp_str = udev_device_get_sysattr_value(dev, "bonding/updelay");
> + if (!tmp_str) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Could not retrieve 'bonding/updelay' for '%s'"), name);
> + goto cleanup;
> + }
> + if (virStrToLong_i(tmp_str, NULL, 10, &tmp_int) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Could not parse 'bonding/updelay' '%s' for '%s'"),
> + tmp_str, name);
> + goto cleanup;
> + }
> + ifacedef->data.bond.updelay = tmp_int;
> +
> + tmp_str = udev_device_get_sysattr_value(dev, "bonding/miimon");
> + if (!tmp_str) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Could not retrieve 'bonding/miimon' for '%s'"), name);
> + goto cleanup;
> + }
> + if (virStrToLong_i(tmp_str, NULL, 10, &tmp_int) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Could not parse 'bonding/miimon' '%s' for '%s'"),
> + tmp_str, name);
> + goto cleanup;
> + }
> + ifacedef->data.bond.frequency = tmp_int;
> +
> + tmp_str = udev_device_get_sysattr_value(dev, "bonding/arp_interval");
> + if (!tmp_str) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Could not retrieve 'bonding/arp_interval' for '%s'"), name);
> + goto cleanup;
> + }
> + if (virStrToLong_i(tmp_str, NULL, 10, &tmp_int) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Could not parse 'bonding/arp_interval' '%s' for '%s'"),
> + tmp_str, name);
> + goto cleanup;
> + }
> + ifacedef->data.bond.interval = tmp_int;
> +
> + /* bonding/mode is in the format: "balance-rr 0" so we find the
> + * space and increment the pointer to get the number and convert
> + * it to an interger. libvirt uses 1 through 7 while the raw
> + * number is 0 through 6 so increment it by 1.
> + */
> + tmp_str = udev_device_get_sysattr_value(dev, "bonding/mode");
> + if (!tmp_str) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Could not retrieve 'bonding/mode' for '%s'"), name);
> + goto cleanup;
> + }
> + tmp_str = strchr(tmp_str, ' ');
> + if (!tmp_str) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Invalid format for 'bonding/mode' for '%s'"), name);
> + goto cleanup;
> + }
> + if (strlen(tmp_str) < 2) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Unable to find correct value in 'bonding/mode' for '%s'"),
> + name);
> + goto cleanup;
> + }
> + if (virStrToLong_i(tmp_str + 1, NULL, 10, &tmp_int) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Could not parse 'bonding/mode' '%s' for '%s'"),
> + tmp_str, name);
> + goto cleanup;
> + }
> + ifacedef->data.bond.mode = tmp_int + 1;
> +
> + /* bonding/arp_validate is in the format: "none 0" so we find the
> + * space and increment the pointer to get the number and convert
> + * it to an interger.
> + */
> + tmp_str = udev_device_get_sysattr_value(dev, "bonding/arp_validate");
> + if (!tmp_str) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Could not retrieve 'bonding/arp_validate' for '%s'"), name);
> + goto cleanup;
> + }
> + tmp_str = strchr(tmp_str, ' ');
> + if (!tmp_str) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Invalid format for 'bonding/arp_validate' for '%s'"), name);
> + goto cleanup;
> + }
> + if (strlen(tmp_str) < 2) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Unable to find correct value in 'bonding/arp_validate' "
> + "for '%s'"), name);
> + goto cleanup;
> + }
> + if (virStrToLong_i(tmp_str + 1, NULL, 10, &tmp_int) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Could not parse 'bonding/arp_validate' '%s' for '%s'"),
> + tmp_str, name);
> + goto cleanup;
> + }
> + ifacedef->data.bond.validate = tmp_int;
> +
> + /* bonding/use_carrier is 0 or 1 and libvirt stores it as 1 or 2. */
> + tmp_str = udev_device_get_sysattr_value(dev, "bonding/use_carrier");
> + if (!tmp_str) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Could not retrieve 'bonding/use_carrier' for '%s'"), name);
> + goto cleanup;
> + }
> + if (virStrToLong_i(tmp_str, NULL, 10, &tmp_int) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Could not parse 'bonding/use_carrier' '%s' for '%s'"),
> + tmp_str, name);
> + goto cleanup;
> + }
> + ifacedef->data.bond.carrier = tmp_int + 1;
> +
> + /* MII or ARP Monitoring is based on arp_interval and miimon.
> + * if arp_interval > 0 then ARP monitoring is in play, if
> + * miimon > 0 then MII monitoring is in play.
> + */
> + if (ifacedef->data.bond.interval > 0)
> + ifacedef->data.bond.monit = VIR_INTERFACE_BOND_MONIT_ARP;
> + else if (ifacedef->data.bond.frequency > 0)
> + ifacedef->data.bond.monit = VIR_INTERFACE_BOND_MONIT_MII;
> + else
> + ifacedef->data.bond.monit = VIR_INTERFACE_BOND_MONIT_NONE;
> +
> + tmp_str = udev_device_get_sysattr_value(dev, "bonding/arp_ip_target");
> + if (!tmp_str) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Could not retrieve 'bonding/arp_ip_target' for '%s'"), name);
> + goto cleanup;
> + }
> + ifacedef->data.bond.target = strdup(tmp_str);
> + if (!ifacedef->data.bond.target) {
> + virReportOOMError();
> + goto cleanup;
> + }
> +
> + /* Slaves of the bond */
> + /* Get each slave in the bond */
> + slave_count = scandir(udev_device_get_syspath(dev), &slave_list,
> + udevIfaceBondScanDirFilter, alphasort);
> +
> + if (slave_count < 0) {
> + virReportSystemError(errno,
> + _("Could not get slaves of bond '%s'"), name);
> + goto cleanup;
> + }
> +
> + /* Allocate our list of slave devices */
> + if (VIR_ALLOC_N(ifacedef->data.bond.itf, slave_count) < 0) {
> + virReportOOMError();
> + goto cleanup;
> + }
> + ifacedef->data.bond.nbItf = slave_count;
> +
> + for (i = 0; i < slave_count; i++) {
> + /* Names are slave_interface. e.g. slave_eth0
> + * so we use the part after the _
> + */
> + tmp_str = strchr(slave_list[i]->d_name, '_');
> + tmp_str++;
> +
> + ifacedef->data.bond.itf[i] =
> + udevIfaceGetIfaceDef(udev, tmp_str);
> + if (!ifacedef->data.bond.itf[i]) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Could not get interface information for '%s', which is "
> + "a enslaved in bond '%s'"), slave_list[i]->d_name, name);
> + goto cleanup;
> + }
> + VIR_FREE(slave_list[i]);
> + }
> +
> + VIR_FREE(slave_list);
> +
> + return 0;
> +
> +cleanup:
> + for (i = 0; i < slave_count; i++) {
> + VIR_FREE(slave_list[i]);
> + }
> + VIR_FREE(slave_list);
> +
> + return -1;
> +}
> +
> +static int
> +ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
> +ATTRIBUTE_NONNULL(4) ATTRIBUTE_RETURN_CHECK
> udevIfaceGetIfaceDefBridge(struct udev *udev,
> struct udev_device *dev,
> const char *name,
> @@ -774,17 +1027,26 @@ udevIfaceGetIfaceDef(struct udev *udev, const char *name)
> if (vlan_parent_dev) {
> ifacedef->type = VIR_INTERFACE_TYPE_VLAN;
> }
> +
> + /* Fallback check to see if this is a bond device */
> + if (udev_device_get_sysattr_value(dev, "bonding/mode")) {
> + ifacedef->type = VIR_INTERFACE_TYPE_BOND;
> + }
> }
>
> switch (ifacedef->type) {
> case VIR_INTERFACE_TYPE_VLAN:
> - if (udevIfaceGetIfaceDefVlan(udev, dev, name, ifacedef))
> + if (udevIfaceGetIfaceDefVlan(udev, dev, name, ifacedef) < 0)
> goto cleanup;
> break;
> case VIR_INTERFACE_TYPE_BRIDGE:
> if (udevIfaceGetIfaceDefBridge(udev, dev, name, ifacedef) < 0)
> goto cleanup;
> break;
> + case VIR_INTERFACE_TYPE_BOND:
> + if (udevIfaceGetIfaceDefBond(udev, dev, name, ifacedef) < 0)
> + goto cleanup;
> + break;
> case VIR_INTERFACE_TYPE_ETHERNET:
> break;
> }
ACK.
More information about the libvir-list
mailing list