The udev backend now supports bond interfaces. --- The result of an iface-dumpxml bond0 is as follows: <interface type='bond' name='bond0'> <mtu size='1500'/> <bond mode='balance-rr'> <interface type='ethernet' name='eth2'> <mac address='d0:67:e5:fa:88:95'/> <mtu size='1500'/> </interface> <interface type='ethernet' name='eth3'> <mac address='d0:67:e5:fa:88:95'/> <mtu size='1500'/> </interface> </bond> </interface> --- src/interface/interface_backend_udev.c | 195 +++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) diff --git a/src/interface/interface_backend_udev.c b/src/interface/interface_backend_udev.c index 73494a6..bba02d1 100644 --- a/src/interface/interface_backend_udev.c +++ b/src/interface/interface_backend_udev.c @@ -494,6 +494,22 @@ 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) +{ + 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 +538,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++) { @@ -541,6 +565,168 @@ udevIfaceFreeIfaceDef(virInterfaceDef *ifacedef) } static int +udevIfaceGetIfaceDefBond(struct udev *udev ATTRIBUTE_UNUSED, + struct udev_device *dev ATTRIBUTE_UNUSED, + const char *name, + virInterfaceDef *ifacedef) + ATTRIBUTE_NONNULL(1) + ATTRIBUTE_NONNULL(2) + ATTRIBUTE_NONNULL(3) + ATTRIBUTE_NONNULL(4) + ATTRIBUTE_RETURN_CHECK; +static int +udevIfaceGetIfaceDefBond(struct udev *udev ATTRIBUTE_UNUSED, + 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 (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 (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 (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 (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 (virStrToLong_i(strchr(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 (virStrToLong_i(strchr(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 (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; + + ifacedef->data.bond.target = + strdup(udev_device_get_sysattr_value(dev, "bonding/arp_ip_target")); + 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); + 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 udevIfaceGetIfaceDefBridge(struct udev *udev, struct udev_device *dev, const char *name, @@ -752,6 +938,11 @@ udevIfaceGetIfaceDef(struct udev *udev, const char *name) 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)) @@ -761,6 +952,10 @@ udevIfaceGetIfaceDef(struct udev *udev, const char *name) if (udevIfaceGetIfaceDefBridge(udev, dev, name, ifacedef)) goto cleanup; break; + case VIR_INTERFACE_TYPE_BOND: + if (udevIfaceGetIfaceDefBond(udev, dev, name, ifacedef)) + goto cleanup; + break; case VIR_INTERFACE_TYPE_ETHERNET: break; } -- 1.7.12.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list