Please don't apply this patch! I have seriously reorganized, along with
adding reporting of bridge and bond interface details, and will be
posting a new patch soon.
On 10/29/2009 02:26 AM, Laine Stump wrote:
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