Arch Linux backend
by Jon Nordby
I'm interesting in writing an Arch Linux backend for netcf. I'd need augeas
support for the relevant configurations, but what else? What is the basic
principle, what functions should be implemented etc.? How do I approach
this?
--
Regards Jon Nordby - www.jonnor.com
14 years, 4 months
ANNOUNCE: netcf 0.1.5
by David Lutterkort
I am pleased to announce the release of netcf 0.1.5.
This release fixes a couple of bugs that lead to horrendous memory leaks
in libvirt.
Detailed news:
- fix a couple of memory leaks (BZ 540521 and 540472)
- do not require bridge module for succesful initialization
Tarball: https://fedorahosted.org/released/netcf/netcf-0.1.5.tar.gz
GPG signature[1]: https://fedorahosted.org/released/netcf/netcf-0.1.5.tar.gz.sig
RPM's for Fedora and EPEL are making their way through the build systems
and will be available shortly from the usual repos.
David
[1] To verify the signature, first download both the .sig file and the
corresponding tarball. Then, run a command like this:
gpg --verify netcf-0.1.5.tar.gz.sig
If that command fails because you don't have the required public key,
then run this command to import it:
gpg --keyserver keys.gnupg.net --recv-keys FC6E8A22
and rerun the `gpg --verify' command.
14 years, 4 months
ANNOUNCE: netcf 0.1.4
by David Lutterkort
I am pleased to announce the release of netcf 0.1.3.
This release fixes a couple of bugs that trip up libvirt's unit tests;
Laine was also hard at work to produce more complete XML from
ncf_if_xml_state. Detailed news:
- ncf_if_xml_state: fill in details for bridge, bond, and vlan. The
returned XML will now validate against interface.rng (except bonds,
which are still missing the miimon or arpmon elements)
- ncf_close: allow passing in a NULL ncf, or a partially initialized ncf
- ncf_init: set *ncf to NULL when returning -2
Tarball: https://fedorahosted.org/released/netcf/netcf-0.1.4.tar.gz
GPG signature[1]: https://fedorahosted.org/released/netcf/netcf-0.1.4.tar.gz.sig
RPM's for Fedora and EPEL are making their way through the build systems
and will be available shortly from the usual repos.
David
[1] To verify the signature, first download both the .sig file and the
corresponding tarball. Then, run a command like this:
gpg --verify netcf-0.1.4.tar.gz.sig
If that command fails because you don't have the required public key,
then run this command to import it:
gpg --keyserver keys.gnupg.net --recv-keys FC6E8A22
and rerun the `gpg --verify' command.
14 years, 4 months
Undefining a bridge does not recreate the original interface
by Cole Robinson
Hi all,
Playing with netcf a bit, I'm hitting an issue with undefining a bridge:
the original interface disappears from the ncftool --list output, and
its ifcfg script is completely gone.
$ sudo cat /etc/sysconfig/network-scripts/ifcfg-wlan0
# Networking Interface
DEVICE=wlan0
HWADDR=00:1C:BF:04:29:A4
ONBOOT=no
TYPE=wireless
$ cat netcfbridge.xml
<interface type="bridge" name="testbr0">
<start mode="none"/>
<mtu size="1500"/>
<protocol family="ipv4">
<dhcp/>
</protocol>
<bridge stp="off" delay="0.01">
<interface type="ethernet" name="wlan0">
<mac address="00:1C:BF:04:29:A4"/>
</interface>
</bridge>
</interface>
$ sudo src/ncftool
ncftool> list --all
eth0
lo
wlan0
ncftool> define netcfbridge.xml
Defined interface testbr0
ncftool> list --all
eth0
lo
testbr0
ncftool> dumpxml testbr0
<?xml version="1.0"?>
<interface type="bridge" name="testbr0">
<start mode="none"/>
<mtu size="1500"/>
<protocol family="ipv4">
<dhcp/>
</protocol>
<bridge stp="off" delay="0.01">
<interface type="ethernet" name="wlan0">
<mac address="00:1C:BF:04:29:A4"/>
</interface>
</bridge>
</interface>
ncftool> undefine testbr0
testbr0 undefined
ncftool> list --all
eth0
lo
Maybe netcf could attempt to rebuild ifcfg files for child interfaces
when undefining? Since it is already accessing /sys, it should be
straight forward to build a simple config with at least mac and
interface name.
On an unrelated note, the bridge XML example on the main trac page is
outdated and doesn't match the current XML schema.
Thanks,
Cole
14 years, 4 months
[PATCH] Fill in interface details for bridge, bond, and vlan in ncf_if_xml_state.
by Laine Stump
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
14 years, 4 months
[PATCH] Add required vlan properties to live xml.
by Laine Stump
Grab the vlan id and master interface name during the libnl "link"
cache traversal callback, and add it to the xml for vlans.
This is necessary for the xml to pass libvirt's parsing.
---
src/dutil.c | 127 +++++++++++++++++++++++++++++++++++++++++++++-------------
1 files changed, 98 insertions(+), 29 deletions(-)
diff --git a/src/dutil.c b/src/dutil.c
index d4eea90..93bb597 100644
--- a/src/dutil.c
+++ b/src/dutil.c
@@ -50,6 +50,9 @@
#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 <libxml/parser.h>
#include <libxml/relaxng.h>
@@ -611,6 +614,7 @@ struct nl_callback_data {
xmlNodePtr protov4;
xmlNodePtr protov6;
xmlNodePtr mac;
+ xmlNodePtr vlan;
struct netcf_if *nif;
};
@@ -709,58 +713,123 @@ error:
return;
}
-static void add_mac_cb(struct nl_object *obj, void *arg) {
+static void add_link_info_cb(struct nl_object *obj, void *arg) {
struct nl_callback_data *cb_data = arg;
struct rtnl_link *iflink = (struct rtnl_link *)obj;
struct netcf *ncf = cb_data->nif->ncf;
struct nl_addr *addr;
- char mac_str[64];
+ char *link_type;
xmlNodePtr cur;
xmlAttrPtr prop = NULL;
- if (cb_data->mac != NULL)
- return;
+ /* look for mac address */
+ if ((cb_data->mac == NULL)
+ && ((addr = rtnl_link_get_addr(iflink)) != NULL)
+ && !nl_addr_iszero(addr)) {
- addr = rtnl_link_get_addr(iflink);
- if ((addr == NULL) || nl_addr_iszero(addr))
- return;
+ char mac_str[64];
- nl_addr2str(addr, mac_str, sizeof(mac_str));
+ 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;
+ }
+ }
- 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);
}
- 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);
+ /* If this is a vlan link, get the master interface and vlan id.
+ */
+ if ((cb_data->vlan == NULL)
+ && ((link_type = rtnl_link_get_info_type(iflink)) != NULL)
+ && STREQ(link_type, "vlan")) {
+
+ struct rtnl_link *master_link;
+ char *master_name = NULL;
+ int vlan_id = rtnl_link_vlan_get_id(iflink);
+ int l_link = rtnl_link_get_link(iflink);
+
+ if ((l_link != RTNL_LINK_NOT_FOUND)
+ && ((master_link = rtnl_link_get(nl_object_get_cache(obj),
+ l_link)) != NULL)
+ && ((master_name = rtnl_link_get_name(master_link)) != NULL)) {
+
+ char vlan_id_str[16];
+ xmlNodePtr master;
+
+ for (cur = cb_data->root->children; cur != NULL; cur = cur->next) {
+ if ((cur->type == XML_ELEMENT_NODE) &&
+ xmlStrEqual(cur->name, BAD_CAST "vlan")) {
+ cb_data->vlan = cur;
+ break;
+ }
+ }
- 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;
+ 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;
+ }
+ }
+
+ 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);
+
+ master = xmlNewDocNode(cb_data->doc, NULL,
+ BAD_CAST "interface", NULL);
+ ERR_NOMEM(master == NULL, ncf);
+ cur = xmlAddChild(cb_data->vlan, master);
+ if (cur == NULL) {
+ xmlFreeNode(master);
+ report_error(ncf, NETCF_ENOMEM, NULL);
+ goto error;
+ }
+ prop = xmlSetProp(master, BAD_CAST "name", BAD_CAST master_name);
+ ERR_NOMEM(prop == NULL, ncf);
}
}
- prop = xmlSetProp(cb_data->mac, BAD_CAST "address", BAD_CAST mac_str);
- ERR_NOMEM(prop == NULL, ncf);
-
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 nl_callback_data cb_data
+ = { doc, NULL, NULL, NULL, NULL, NULL, nif };
struct rtnl_addr *filter_addr = NULL;
struct rtnl_link *filter_link = NULL;
int ifindex, code;
@@ -795,7 +864,7 @@ void add_state_to_xml_doc(struct netcf_if *nif, xmlDocPtr doc) {
rtnl_link_set_ifindex(filter_link, ifindex);
nl_cache_foreach_filter(nif->ncf->driver->link_cache,
- OBJ_CAST(filter_link), add_mac_cb,
+ OBJ_CAST(filter_link), add_link_info_cb,
&cb_data);
/* Build an rtnl_addr with the interface name set. This is used by
--
1.6.5.15.gc274d
14 years, 5 months