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