netcf-devel  

[netcf-devel] [PATCH] Fill in interface details for bridge, bond, and vlan in ncf_if_xml_state.

Laine Stump
Sun, 01 Nov 2009 21:09:27 -0800

Both bridge and vlan now have enough information to pass libvirt xml
parsing. bond interfaces still need either an miimon node or an
arpmode node.
---
 src/drv_initscripts.c |   13 +-
 src/dutil.c           |  508 ++++++++++++++++++++++++++++++++++++++++++-------
 src/dutil.h           |   24 ++-
 3 files changed, 465 insertions(+), 80 deletions(-)

diff --git a/src/drv_initscripts.c b/src/drv_initscripts.c
index 8e082b6..f8099f7 100644
--- a/src/drv_initscripts.c
+++ b/src/drv_initscripts.c
@@ -768,7 +768,7 @@ char *drv_xml_state(struct netcf_if *nif) {
     xmlDocPtr ncf_xml = NULL;
     xmlNodePtr root;
     xmlAttrPtr prop;
-    const char *type;
+    netcf_if_type_t type;
 
     ncf = nif->ncf;
 
@@ -780,17 +780,8 @@ char *drv_xml_state(struct netcf_if *nif) {
     root = xmlNewNode(NULL, BAD_CAST "interface");
     ERR_NOMEM(root == NULL, ncf);
     xmlDocSetRootElement(ncf_xml, root);
-    prop = xmlNewProp(root, BAD_CAST "name", BAD_CAST nif->name);
-    ERR_NOMEM(prop == NULL, ncf);
 
-    type = if_type(ncf, nif->name);
-    ERR_BAIL(ncf);
-    prop = xmlSetProp(root, BAD_CAST "type", BAD_CAST type);
-    ERR_NOMEM(prop == NULL, ncf);
-
-    /* get the current IP address and prefix, and add both to the
-     * document.
-     */
+    /* add all info we can gather from the kernel/sysfs/procfs */
     add_state_to_xml_doc(nif, ncf_xml);
     ERR_BAIL(ncf);
 
diff --git a/src/dutil.c b/src/dutil.c
index d4eea90..d82b3d8 100644
--- a/src/dutil.c
+++ b/src/dutil.c
@@ -50,6 +50,10 @@
 #include <netlink/cache.h>
 #include <netlink/route/addr.h>
 #include <netlink/route/link.h>
+/* For some reason, the headers for libnl vlan functions aren't installed */
+extern int rtnl_link_vlan_get_id(struct rtnl_link *link);
+
+#include <dirent.h>
 
 #include <libxml/parser.h>
 #include <libxml/relaxng.h>
@@ -509,40 +513,94 @@ int if_is_active(struct netcf *ncf, const char *intf) {
     return ((ifr.ifr_flags & IFF_UP) == IFF_UP);
 }
 
-const char *if_type(struct netcf *ncf, const char *intf) {
+netcf_if_type_t if_type(struct netcf *ncf, const char *intf) {
     char *path;
     struct stat stats;
-    const char *ret = NULL;
+    netcf_if_type_t ret = NETCF_IFACE_TYPE_NONE;
 
     xasprintf(&path, "/proc/net/vlan/%s", intf);
     ERR_NOMEM(path == NULL, ncf);
     if ((stat (path, &stats) == 0) && S_ISREG (stats.st_mode)) {
-        ret = "vlan";
+        ret = NETCF_IFACE_TYPE_VLAN;
     }
     FREE(path);
 
-    if (ret == NULL) {
+    if (ret == NETCF_IFACE_TYPE_NONE) {
         xasprintf(&path, "/sys/class/net/%s/bridge", intf);
         ERR_NOMEM(path == NULL, ncf);
         if (stat (path, &stats) == 0 && S_ISDIR (stats.st_mode))
-            ret = "bridge";
+            ret = NETCF_IFACE_TYPE_BRIDGE;
         FREE(path);
     }
-    if (ret == NULL) {
+    if (ret == NETCF_IFACE_TYPE_NONE) {
         xasprintf(&path, "/sys/class/net/%s/bonding", intf);
         ERR_NOMEM(path == NULL, ncf);
         if (stat (path, &stats) == 0 && S_ISDIR (stats.st_mode))
-            ret = "bond";
+            ret = NETCF_IFACE_TYPE_BOND;
         FREE(path);
     }
-    if (ret == NULL)
-        ret = "ethernet";
+    if (ret == NETCF_IFACE_TYPE_NONE)
+        ret = NETCF_IFACE_TYPE_ETHERNET;
 
 error:
     FREE(path);
     return ret;
 }
 
+/* Given a netcf_if_type_t, return a const char * representation */
+const char *if_type_str(netcf_if_type_t type) {
+    switch (type) {
+        case NETCF_IFACE_TYPE_ETHERNET:
+            return "ethernet";
+        case NETCF_IFACE_TYPE_BOND:
+            return "bond";
+        case NETCF_IFACE_TYPE_BRIDGE:
+            return "bridge";
+        case NETCF_IFACE_TYPE_VLAN:
+            return "vlan";
+        default:
+            return NULL;
+    }
+}
+
+char *if_bridge_phys_name(struct netcf *ncf, const char *intf) {
+    /* We can learn the name of the physical interface associated
+     * with this bridge by looking for the name of the one and
+     * only link in /sys/class/net/$ifname/brif.
+     *
+     * The caller of this function must free the string that is
+     * returned.
+     *
+     * For efficiency's sake, this function assumes we've already
+     * checked that this is a bridge interface.
+     */
+    char *ret = NULL;
+    char *dirpath = NULL;
+    DIR *dir = NULL;
+
+    xasprintf(&dirpath, "/sys/class/net/%s/brif", intf);
+    ERR_NOMEM(dirpath == NULL, ncf);
+
+    dir = opendir(dirpath);
+    if (dir != NULL) {
+        struct dirent *d;
+
+        while ((d = readdir (dir)) != NULL) {
+            if (STRNEQ(d->d_name, ".") && STRNEQ(d->d_name, "..")) {
+                xasprintf(&ret, "%s", d->d_name);
+                ERR_NOMEM(ret == NULL, ncf);
+                break;
+            }
+        }
+    }
+
+error:
+    if (dir)
+        closedir (dir);
+    FREE(dirpath);
+    return ret;
+}
+
 /* Create a new netcf if instance for interface NAME */
 struct netcf_if *make_netcf_if(struct netcf *ncf, char *name) {
     int r;
@@ -602,24 +660,28 @@ int dutil_put_aug(struct netcf *ncf, const char *aug_xml, 
char **ncf_xml) {
     return result;
 }
 
+
+static void add_type_specific_info(struct netcf *ncf,
+                                   const char *ifname, int ifindex,
+                                   xmlDocPtr doc, xmlNodePtr root);
+
 /* Data that needs to be preserved between calls to the libnl iterator
  * callback.
  */
-struct nl_callback_data {
+struct nl_ip_callback_data {
     xmlDocPtr doc;
     xmlNodePtr root;
     xmlNodePtr protov4;
     xmlNodePtr protov6;
-    xmlNodePtr mac;
-    struct netcf_if *nif;
+    struct netcf *ncf;
 };
 
 /* add all ip addresses for the given interface to the xml document
 */
-static void add_ips_cb(struct nl_object *obj, void *arg) {
-    struct nl_callback_data *cb_data = arg;
+static void add_ip_info_cb(struct nl_object *obj, void *arg) {
+    struct nl_ip_callback_data *cb_data = arg;
     struct rtnl_addr *addr = (struct rtnl_addr *)obj;
-    struct netcf *ncf = cb_data->nif->ncf;
+    struct netcf *ncf = cb_data->ncf;
 
     struct nl_addr *local_addr;
     int family, prefix;
@@ -709,66 +771,402 @@ error:
     return;
 }
 
-static void add_mac_cb(struct nl_object *obj, void *arg) {
-    struct nl_callback_data *cb_data = arg;
+static void add_ip_info(struct netcf *ncf,
+                        const char *ifname ATTRIBUTE_UNUSED, int ifindex,
+                        xmlDocPtr doc, xmlNodePtr root) {
+    struct nl_ip_callback_data cb_data
+        = { doc, root, NULL, NULL, ncf };
+    struct rtnl_addr *filter_addr = NULL;
+
+    filter_addr = rtnl_addr_alloc();
+    ERR_NOMEM((filter_addr == NULL), ncf);
+
+    rtnl_addr_set_ifindex(filter_addr, ifindex);
+    nl_cache_foreach_filter(ncf->driver->addr_cache,
+                            OBJ_CAST(filter_addr), add_ip_info_cb,
+                            &cb_data);
+error:
+    if (filter_addr)
+        rtnl_addr_put(filter_addr);
+    return;
+}
+
+
+struct nl_ethernet_callback_data {
+    xmlDocPtr doc;
+    xmlNodePtr root;
+    xmlNodePtr mac;
+    struct netcf *ncf;
+};
+
+static void add_ethernet_info_cb(struct nl_object *obj, void *arg) {
+    struct nl_ethernet_callback_data *cb_data = arg;
     struct rtnl_link *iflink = (struct rtnl_link *)obj;
-    struct netcf *ncf = cb_data->nif->ncf;
+    struct netcf *ncf = cb_data->ncf;
 
     struct nl_addr *addr;
-    char mac_str[64];
     xmlNodePtr cur;
     xmlAttrPtr prop = NULL;
 
-    if (cb_data->mac != NULL)
+    /* look for mac address */
+    if ((cb_data->mac == NULL)
+        && ((addr = rtnl_link_get_addr(iflink)) != NULL)
+        && !nl_addr_iszero(addr)) {
+
+        char mac_str[64];
+
+        nl_addr2str(addr, mac_str, sizeof(mac_str));
+
+        for (cur = cb_data->root->children; cur != NULL; cur = cur->next) {
+            if ((cur->type == XML_ELEMENT_NODE) &&
+                xmlStrEqual(cur->name, BAD_CAST "mac")) {
+                cb_data->mac = cur;
+                break;
+            }
+        }
+
+        if (cb_data->mac == NULL) {
+            /* No mac node exists in the document, create a new one.
+             */
+            cb_data->mac = xmlNewDocNode(cb_data->doc, NULL,
+                                         BAD_CAST "mac", NULL);
+            ERR_NOMEM(cb_data->mac == NULL, ncf);
+
+            cur = xmlAddChild(cb_data->root, cb_data->mac);
+            if (cur == NULL) {
+                xmlFreeNode(cb_data->mac);
+                cb_data->mac = NULL;
+                report_error(ncf, NETCF_ENOMEM, NULL);
+                goto error;
+            }
+        }
+
+        prop = xmlSetProp(cb_data->mac, BAD_CAST "address", BAD_CAST mac_str);
+        ERR_NOMEM(prop == NULL, ncf);
+    }
+error:
+    return;
+}
+
+static void add_ethernet_info(struct netcf *ncf,
+                              const char *ifname ATTRIBUTE_UNUSED, int ifindex,
+                              xmlDocPtr doc, xmlNodePtr root) {
+    struct nl_ethernet_callback_data cb_data
+        = { doc, root, NULL, ncf };
+    struct rtnl_link *filter_link = NULL;
+
+    filter_link = rtnl_link_alloc();
+    ERR_NOMEM((filter_link == NULL), ncf);
+
+    rtnl_link_set_ifindex(filter_link, ifindex);
+    nl_cache_foreach_filter(ncf->driver->link_cache,
+                            OBJ_CAST(filter_link), add_ethernet_info_cb,
+                            &cb_data);
+error:
+    if (filter_link)
+        rtnl_link_put(filter_link);
+    return;
+}
+
+struct nl_vlan_callback_data {
+    xmlDocPtr doc;
+    xmlNodePtr root;
+    xmlNodePtr vlan;
+    struct netcf *ncf;
+};
+
+static void add_vlan_info_cb(struct nl_object *obj, void *arg) {
+    struct nl_vlan_callback_data *cb_data = arg;
+    struct rtnl_link *iflink = (struct rtnl_link *)obj;
+    struct netcf *ncf = cb_data->ncf;
+
+    struct rtnl_link *master_link;
+    char *master_name = NULL;
+    int l_link, vlan_id, master_ifindex;
+    char vlan_id_str[16];
+    char *link_type;
+    xmlNodePtr interface_node, cur;
+    xmlAttrPtr prop = NULL;
+
+    /* If this really is a vlan link, get the master interface and vlan id.
+     */
+    if (cb_data->vlan != NULL)
+        return;
+
+    link_type = rtnl_link_get_info_type(iflink);
+    if ((link_type == NULL) || STRNEQ(link_type, "vlan"))
+        return;
+
+    l_link = rtnl_link_get_link(iflink);
+    if (l_link == RTNL_LINK_NOT_FOUND)
         return;
 
-    addr = rtnl_link_get_addr(iflink);
-    if ((addr == NULL) || nl_addr_iszero(addr))
+    master_link = rtnl_link_get(nl_object_get_cache(obj), l_link);
+    if (master_link == NULL)
         return;
 
-    nl_addr2str(addr, mac_str, sizeof(mac_str));
+    master_name = rtnl_link_get_name(master_link);
+    if (master_name == NULL)
+        return;
 
+    /* look for an existing vlan node */
     for (cur = cb_data->root->children; cur != NULL; cur = cur->next) {
         if ((cur->type == XML_ELEMENT_NODE) &&
-            xmlStrEqual(cur->name, BAD_CAST "mac")) {
-            cb_data->mac = cur;
+            xmlStrEqual(cur->name, BAD_CAST "vlan")) {
+            cb_data->vlan = cur;
             break;
         }
     }
+    if (cb_data->vlan == NULL) {
+        /* no vlan node exists in the document, create a new one */
+        cb_data->vlan = xmlNewDocNode(cb_data->doc, NULL,
+                                      BAD_CAST "vlan", NULL);
+        ERR_NOMEM(cb_data->vlan == NULL, ncf);
+
+        cur = xmlAddChild(cb_data->root, cb_data->vlan);
+        if (cur == NULL) {
+            xmlFreeNode(cb_data->vlan);
+            cb_data->vlan = NULL;
+            report_error(ncf, NETCF_ENOMEM, NULL);
+            goto error;
+        }
+    }
+
+    vlan_id = rtnl_link_vlan_get_id(iflink);
+    snprintf(vlan_id_str, sizeof(vlan_id_str), "%d", vlan_id);
+    prop = xmlSetProp(cb_data->vlan, BAD_CAST "tag", BAD_CAST vlan_id_str);
+    ERR_NOMEM(prop == NULL, ncf);
+
+    interface_node = xmlNewDocNode(cb_data->doc, NULL,
+                                   BAD_CAST "interface", NULL);
+    ERR_NOMEM(interface_node == NULL, ncf);
+    cur = xmlAddChild(cb_data->vlan, interface_node);
+    if (cur == NULL) {
+        xmlFreeNode(interface_node);
+        report_error(ncf, NETCF_ENOMEM, NULL);
+        goto error;
+    }
+
+    /* Add in type-specific info of master interface */
+    master_ifindex = rtnl_link_name2i(ncf->driver->link_cache, master_name);
+    ERR_THROW((master_ifindex == RTNL_LINK_NOT_FOUND), ncf, ENETLINK,
+              "couldn't find ifindex for vlan master interface `%s`",
+              master_name);
+    add_type_specific_info(ncf, master_name, master_ifindex,
+                           cb_data->doc, interface_node);
+
+error:
+    return;
+}
+
+static void add_vlan_info(struct netcf *ncf,
+                          const char *ifname ATTRIBUTE_UNUSED, int ifindex,
+                          xmlDocPtr doc, xmlNodePtr root) {
+    struct nl_vlan_callback_data cb_data
+        = { doc, root, NULL, ncf };
+    struct rtnl_link *filter_link = NULL;
 
-    if (cb_data->mac == NULL) {
+    filter_link = rtnl_link_alloc();
+    ERR_NOMEM((filter_link == NULL), ncf);
+
+    rtnl_link_set_ifindex(filter_link, ifindex);
+    nl_cache_foreach_filter(ncf->driver->link_cache,
+                            OBJ_CAST(filter_link), add_vlan_info_cb,
+                            &cb_data);
+    ERR_BAIL(ncf);
+error:
+    if (filter_link)
+        rtnl_link_put(filter_link);
+    return;
+}
+
+static void add_bridge_info(struct netcf *ncf,
+                            const char *ifname, int ifindex ATTRIBUTE_UNUSED,
+                            xmlDocPtr doc, xmlNodePtr root) {
+    char *phys_name;
+    int   phys_ifindex;
+    xmlNodePtr cur, bridge_node = NULL, interface_node = NULL;
+
+    phys_name = if_bridge_phys_name(ncf, ifname);
+    if (phys_name == NULL)
+        return;
+
+    /* look for an existing node of the desired name */
+    for (cur = root->children; cur != NULL; cur = cur->next) {
+        if ((cur->type == XML_ELEMENT_NODE)
+            && xmlStrEqual(cur->name, BAD_CAST "bridge")) {
+            bridge_node = cur;
+            break;
+        }
+    }
+    if (bridge_node == NULL) {
         /* No mac node exists in the document, create a new one.
          */
-        cb_data->mac = xmlNewDocNode(cb_data->doc, NULL, BAD_CAST "mac", NULL);
-        ERR_NOMEM(cb_data->mac == NULL, ncf);
+        bridge_node = xmlNewDocNode(doc, NULL, BAD_CAST "bridge", NULL);
+        ERR_NOMEM(bridge_node == NULL, ncf);
+        cur = xmlAddChild(root, bridge_node);
+        if (cur == NULL) {
+            xmlFreeNode(bridge_node);
+            report_error(ncf, NETCF_ENOMEM, NULL);
+            goto error;
+        }
+    }
+
+    interface_node = xmlNewDocNode(doc, NULL, BAD_CAST "interface", NULL);
+    ERR_NOMEM(interface_node == NULL, ncf);
+    cur = xmlAddChild(bridge_node, interface_node);
+    if (cur == NULL) {
+        xmlFreeNode(interface_node);
+        report_error(ncf, NETCF_ENOMEM, NULL);
+        goto error;
+    }
+
+    /* Add in type-specific info of physical interface */
+    phys_ifindex = rtnl_link_name2i(ncf->driver->link_cache, phys_name);
+    ERR_THROW((phys_ifindex == RTNL_LINK_NOT_FOUND), ncf, ENETLINK,
+              "couldn't find ifindex for physical interface `%s` of bridge %s",
+              phys_name, ifname);
+
+    add_type_specific_info(ncf, phys_name, phys_ifindex, doc, interface_node);
+
+error:
+    FREE(phys_name);
+}
+
+
+struct nl_bond_callback_data {
+    xmlDocPtr doc;
+    xmlNodePtr root;
+    xmlNodePtr bond;
+    int master_ifindex;
+    struct netcf *ncf;
+};
+
+static void add_bond_info_cb(struct nl_object *obj, void *arg 
ATTRIBUTE_UNUSED) {
+    struct nl_bond_callback_data *cb_data = arg;
+    struct rtnl_link *iflink = (struct rtnl_link *)obj;
+    struct netcf *ncf = cb_data->ncf;
+
+    xmlNodePtr interface_node, cur;
+
+    /* If this is a slave link, and the master is master_ifindex, add the 
interface
+     * info to the bond.
+     */
+
+    if (!(rtnl_link_get_flags(iflink) & IFF_SLAVE)
+        || rtnl_link_get_master(iflink) != cb_data->master_ifindex)
+        return;
+
+    if (cb_data->bond == NULL) {
+        /* look for an existing bond node */
+        for (cur = cb_data->root->children; cur != NULL; cur = cur->next) {
+            if ((cur->type == XML_ELEMENT_NODE) &&
+                xmlStrEqual(cur->name, BAD_CAST "bond")) {
+                cb_data->bond = cur;
+                break;
+            }
+        }
+    }
+    if (cb_data->bond == NULL) {
+        /* no bond node exists in the document, create a new one */
+        cb_data->bond = xmlNewDocNode(cb_data->doc, NULL,
+                                      BAD_CAST "bond", NULL);
+        ERR_NOMEM(cb_data->bond == NULL, ncf);
 
-        cur = xmlAddChild(cb_data->root, cb_data->mac);
+        cur = xmlAddChild(cb_data->root, cb_data->bond);
         if (cur == NULL) {
-            xmlFreeNode(cb_data->mac);
-            cb_data->mac = NULL;
+            xmlFreeNode(cb_data->bond);
+            cb_data->bond = NULL;
             report_error(ncf, NETCF_ENOMEM, NULL);
             goto error;
         }
     }
 
-    prop = xmlSetProp(cb_data->mac, BAD_CAST "address", BAD_CAST mac_str);
+    /* XXX - if we learn where to get bridge "mode" property, set it here */
+
+    /* XXX - need to add node like one of these:
+     *
+     *    <miimon freq="100" updelay="10" carrier="ioctl"/>
+     *        or
+     *    <arpmode interval='something' target='something'>
+     */
+
+    /* add a new interface node */
+    interface_node = xmlNewDocNode(cb_data->doc, NULL,
+                                   BAD_CAST "interface", NULL);
+    ERR_NOMEM(interface_node == NULL, ncf);
+    cur = xmlAddChild(cb_data->bond, interface_node);
+    if (cur == NULL) {
+        xmlFreeNode(interface_node);
+        report_error(ncf, NETCF_ENOMEM, NULL);
+        goto error;
+    }
+
+    /* Add in type-specific info of this slave interface */
+    add_type_specific_info(ncf, rtnl_link_get_name(iflink),
+                           rtnl_link_get_ifindex(iflink),
+                           cb_data->doc, interface_node);
+error:
+    return;
+}
+
+static void add_bond_info(struct netcf *ncf,
+                          const char *ifname ATTRIBUTE_UNUSED, int ifindex,
+                          xmlDocPtr doc, xmlNodePtr root) {
+    struct nl_bond_callback_data cb_data
+        = { doc, root, NULL, ifindex, ncf };
+
+    nl_cache_foreach(ncf->driver->link_cache, add_bond_info_cb, &cb_data);
+}
+
+
+static void add_type_specific_info(struct netcf *ncf,
+                                   const char *ifname, int ifindex,
+                                   xmlDocPtr doc, xmlNodePtr root) {
+    xmlAttrPtr prop;
+    netcf_if_type_t iftype;
+    const char *iftype_str;
+
+    prop = xmlNewProp(root, BAD_CAST "name", BAD_CAST ifname);
     ERR_NOMEM(prop == NULL, ncf);
 
+    iftype = if_type(ncf, ifname);
+    ERR_BAIL(ncf);
+    iftype_str = if_type_str(iftype);
+
+    if (iftype_str) {
+        prop = xmlSetProp(root, BAD_CAST "type", BAD_CAST if_type_str(iftype));
+        ERR_NOMEM(prop == NULL, ncf);
+    }
+
+    switch (iftype) {
+        case NETCF_IFACE_TYPE_ETHERNET:
+            add_ethernet_info(ncf, ifname, ifindex, doc, root);
+            break;
+        case NETCF_IFACE_TYPE_BRIDGE:
+            add_bridge_info(ncf, ifname, ifindex, doc, root);
+            break;
+        case NETCF_IFACE_TYPE_VLAN:
+            add_vlan_info(ncf, ifname, ifindex, doc, root);
+            break;
+        case NETCF_IFACE_TYPE_BOND:
+            add_bond_info(ncf, ifname, ifindex, doc, root);
+            break;
+        default:
+            break;
+    }
 error:
     return;
 }
 
 void add_state_to_xml_doc(struct netcf_if *nif, xmlDocPtr doc) {
-
-    struct nl_callback_data cb_data = { doc, NULL, NULL, NULL, NULL, nif };
-    struct rtnl_addr *filter_addr = NULL;
-    struct rtnl_link *filter_link = NULL;
+    xmlNodePtr root;
     int ifindex, code;
 
-    cb_data.root = xmlDocGetRootElement(doc);
-    ERR_THROW((cb_data.root == NULL), nif->ncf, EINTERNAL,
+    root = xmlDocGetRootElement(doc);
+    ERR_THROW((root == NULL), nif->ncf, EINTERNAL,
               "failed to get document root element");
-    ERR_THROW(!xmlStrEqual(cb_data.root->name, BAD_CAST "interface"),
+    ERR_THROW(!xmlStrEqual(root->name, BAD_CAST "interface"),
               nif->ncf, EINTERNAL, "root document is not an interface");
 
     /* Update the caches with any recent changes */
@@ -781,39 +1179,17 @@ void add_state_to_xml_doc(struct netcf_if *nif, 
xmlDocPtr doc) {
     ERR_THROW((code < 0), nif->ncf, ENETLINK,
               "failed to refill interface address cache");
 
-    /* The addr cache only knows about ifindex, not name */
     ifindex = rtnl_link_name2i(nif->ncf->driver->link_cache, nif->name);
     ERR_THROW((ifindex == RTNL_LINK_NOT_FOUND), nif->ncf, ENETLINK,
-              "Could find ifindex for interface `%s`", nif->name);
-
-    /* Build an rtnl_link with the interface index set, and use it to
-     * find the entry for this interface and extract the mac
-     * address.
-     */
-    filter_link = rtnl_link_alloc();
-    ERR_NOMEM((filter_link == NULL), nif->ncf);
-
-    rtnl_link_set_ifindex(filter_link, ifindex);
-    nl_cache_foreach_filter(nif->ncf->driver->link_cache,
-                            OBJ_CAST(filter_link), add_mac_cb,
-                            &cb_data);
+              "couldn't find ifindex for interface `%s`", nif->name);
 
-    /* Build an rtnl_addr with the interface name set. This is used by
-     * the iterator to filter the contents of the address cache.
-     */
-    filter_addr = rtnl_addr_alloc();
-    ERR_NOMEM((filter_addr == NULL), nif->ncf);
+    add_type_specific_info(nif->ncf, nif->name, ifindex, doc, root);
+    ERR_BAIL(nif->ncf);
 
-    rtnl_addr_set_ifindex(filter_addr, ifindex);
+    add_ip_info(nif->ncf, nif->name, ifindex, doc, root);
+    ERR_BAIL(nif->ncf);
 
-    nl_cache_foreach_filter(nif->ncf->driver->addr_cache,
-                            OBJ_CAST(filter_addr), add_ips_cb,
-                            &cb_data);
 error:
-    if (filter_addr)
-        rtnl_addr_put(filter_addr);
-    if (filter_link)
-        rtnl_link_put(filter_link);
     return;
 }
 
diff --git a/src/dutil.h b/src/dutil.h
index 93dae1a..0b72e62 100644
--- a/src/dutil.h
+++ b/src/dutil.h
@@ -122,10 +122,28 @@ int netlink_close(struct netcf *ncf);
 /* Check if the interface INTF is up using an ioctl call */
 int if_is_active(struct netcf *ncf, const char *intf);
 
-/* return the type of the interface - "ethernet" (physical device),
- * "bridge", "bond", or "vlan"
+/* Interface types recognized by netcf. */
+typedef enum {
+    NETCF_IFACE_TYPE_NONE = 0,  /* not yet determined */
+    NETCF_IFACE_TYPE_ETHERNET,  /* any physical device is "ethernet" */
+    NETCF_IFACE_TYPE_BOND,
+    NETCF_IFACE_TYPE_BRIDGE,
+    NETCF_IFACE_TYPE_VLAN,
+} netcf_if_type_t;
+
+/* Return the type of the interface.
  */
-const char *if_type(struct netcf *ncf, const char *intf);
+netcf_if_type_t if_type(struct netcf *ncf, const char *intf);
+
+/* Given a netcf_if_type_t enum value, return a const char *representation
+ * This pointer has an indefinite life, and shouldn't be / can't be free'd.
+ */
+const char *if_type_str(netcf_if_type_t type);
+
+/* Return a newly allocated string containing the name of the physical device
+ * bound to this bridge, if any. Returns NULL if none is found
+*/
+char *if_bridge_phys_name(struct netcf *ncf, const char *intf);
 
 /* Create a new netcf if instance for interface NAME */
 struct netcf_if *make_netcf_if(struct netcf *ncf, char *name);
-- 
1.6.5.15.gc274d

_______________________________________________
netcf-devel mailing list
netcf-devel@lists.fedorahosted.org
https://fedorahosted.org/mailman/listinfo/netcf-devel