[libvirt] [PATCH 4/4] interface: add bond support to udev backend

Doug Goldstein cardoe at cardoe.com
Mon Feb 18 01:56:03 UTC 2013


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




More information about the libvir-list mailing list