
From: Wenchao Xia <xiawenc@linux.vnet.ibm.com> This patch contain 1 test program and 1 c file doing xml and structure mapping. It expose some API to translate xml to device structure, in a similar way to code in device_parsing.c. Also some other files are changed to let new code use their internal functions. Type following Command in libxkutil directory: sudo CU_DEBUG=stdout .libs/network_parsing_test could see what it have done. v5: calling libvirt API which employ netcf instead of using libnl. From git log these API are available since 0.9.2, and this patch is tested with libvirt 0.9.4. Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com> --- libxkutil/Makefile.am | 12 +- libxkutil/misc_util.c | 10 +- libxkutil/network_parsing.c | 665 ++++++++++++++++++++++++++++++++++++++ libxkutil/network_parsing.h | 160 +++++++++ libxkutil/network_parsing_test.c | 61 ++++ libxkutil/xmlgen.c | 2 +- libxkutil/xmlgen.h | 2 + 7 files changed, 906 insertions(+), 6 deletions(-) create mode 100644 libxkutil/network_parsing.c create mode 100644 libxkutil/network_parsing.h create mode 100644 libxkutil/network_parsing_test.c diff --git a/libxkutil/Makefile.am b/libxkutil/Makefile.am index f1adc03..c0e62eb 100644 --- a/libxkutil/Makefile.am +++ b/libxkutil/Makefile.am @@ -4,12 +4,14 @@ AM_CFLAGS = $(CFLAGS_STRICT) \ -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE@.conf\" noinst_HEADERS = cs_util.h misc_util.h device_parsing.h xmlgen.h infostore.h \ - pool_parsing.h acl_parsing.h + pool_parsing.h acl_parsing.h \ + network_parsing.h lib_LTLIBRARIES = libxkutil.la libxkutil_la_SOURCES = cs_util_instance.c misc_util.c device_parsing.c \ - xmlgen.c infostore.c pool_parsing.c acl_parsing.c + xmlgen.c infostore.c pool_parsing.c acl_parsing.c \ + network_parsing.c libxkutil_la_LDFLAGS = -version-info @VERSION_INFO@ libxkutil_la_LIBADD = @LIBVIRT_LIBS@ \ @LIBUUID_LIBS@ @@ -19,3 +21,9 @@ noinst_PROGRAMS = xml_parse_test xml_parse_test_SOURCES = xml_parse_test.c xml_parse_test_LDADD = libxkutil.la \ @LIBVIRT_LIBS@ + +noinst_PROGRAMS += network_parsing_test + +network_parsing_test_SOURCES = network_parsing_test.c +network_parsing_test_LDADD = libxkutil.la \ + @LIBVIRT_LIBS@ diff --git a/libxkutil/misc_util.c b/libxkutil/misc_util.c index 61893c3..1c18c33 100644 --- a/libxkutil/misc_util.c +++ b/libxkutil/misc_util.c @@ -152,9 +152,13 @@ virConnectPtr connect_by_classname(const CMPIBroker *broker, uri = cn_to_uri(classname); if (!uri) { - cu_statusf(broker, s, - CMPI_RC_ERR_FAILED, - "Unable to generate URI from classname"); + if (broker) { + cu_statusf(broker, s, + CMPI_RC_ERR_FAILED, + "Unable to generate URI from classname"); + } + CU_DEBUG("Unable to generate URI from classname," + " uri is %s.", uri); return NULL; } diff --git a/libxkutil/network_parsing.c b/libxkutil/network_parsing.c new file mode 100644 index 0000000..932000c --- /dev/null +++ b/libxkutil/network_parsing.c @@ -0,0 +1,665 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Wenchao Xia <xiawenc@cn.ibm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdbool.h> +#include <inttypes.h> +#include <sys/stat.h> + +#include <libvirt/libvirt.h> +#include <libxml/tree.h> +#include <libxml/parser.h> +#include <libxml/xpath.h> +#include <libcmpiutil/libcmpiutil.h> + +#include "misc_util.h" +#include "xmlgen.h" +#include "device_parsing.h" +#include "network_parsing.h" + +#define XML_ERROR "Failed to allocate XML memory" + +static void vlan_prop_print(struct VLAN_Prop *pvlan_prop) +{ + struct VLAN_Prop_8021q *p_8021q; + CMD_DEBUG(1, "--VLAN props: type %d.\n", + pvlan_prop->vlan_type); + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q = &(pvlan_prop->props.prop_8021q); + CMD_DEBUG(1, "----IEEE802.1.Q: id %d, parent %s.\n", + p_8021q->vlan_id, p_8021q->parent); + } +} + +static void br_prop_print(struct BR_Prop *pbr_prop) +{ + int i = 0; + CMD_DEBUG(1, "--Bridge props: stp %d, delay %d, port_num %d.\n", + pbr_prop->STP, pbr_prop->delay, pbr_prop->port_num); + if (pbr_prop->port_names != NULL) { + CMD_DEBUG(1, "----Ports attached: "); + while (i < pbr_prop->port_num) { + CMD_DEBUG(1, " %s,", *(pbr_prop->port_names+i)); + i++; + } + CMD_DEBUG(1, "\n"); + } +} + +void eth_iface_print(struct EthIface *piface) +{ + CMD_DEBUG(1, "Iface device: name %s.\n" + "--Main Props: parent %s, attach to %s, mac %s," + " status %d, boot_mode %d, iface type 0x%x.\n", + piface->name, piface->dep_ifname, piface->attach_bridge, + piface->mac, + piface->run_prop.status, piface->run_prop.boot_mode, piface->eth_type); + if (piface->pbr_prop != NULL) { + br_prop_print(piface->pbr_prop); + } + if (piface->pvlan_prop != NULL) { + vlan_prop_print(piface->pvlan_prop); + } + return; +} + +void eth_ifaceslist_print(struct EthIfacesList *plist) +{ + int i = 0; + CMD_DEBUG(1, "Have %d ifaces in the list:\n", plist->count); + while (i < plist->count) { + CMD_DEBUG(1, "%04d ", i); + eth_iface_print(plist->pifaces[i]); + i++; + } +} + +static void vlan_prop_init(struct VLAN_Prop *pvlan_prop, int vlan_type) +{ + struct VLAN_Prop_8021q *p_8021q; + memset(pvlan_prop, 0, sizeof(struct VLAN_Prop)); + pvlan_prop->vlan_type = vlan_type; + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q = &(pvlan_prop->props.prop_8021q); + p_8021q->vlan_id = NUM_NOT_GOT; + } +} + +static void br_prop_init(struct BR_Prop *pbr_prop) +{ + memset(pbr_prop, 0, sizeof(struct BR_Prop)); + pbr_prop->STP = NUM_NOT_GOT; + pbr_prop->delay = NUM_NOT_GOT; + pbr_prop->port_num = NUM_NOT_GOT; +} + +void eth_iface_init(struct EthIface *piface) +{ + memset(piface, 0, sizeof(struct EthIface)); + piface->eth_type = ETH_TYPE_NOT_GOT; + piface->run_prop.status = NUM_NOT_GOT; + piface->run_prop.boot_mode = BOOT_MODE_NOT_GOT; + return; +} + +void eth_iface_add_br_prop(struct EthIface *piface) +{ + if (piface->pbr_prop != NULL) { + return; + } + SAFE_MALLOC(piface->pbr_prop, sizeof(struct BR_Prop)); + br_prop_init(piface->pbr_prop); +} + +void eth_iface_add_vlan_prop(struct EthIface *piface, int vlan_type) +{ + if (piface->pvlan_prop != NULL) { + return; + } + SAFE_MALLOC(piface->pvlan_prop, sizeof(struct VLAN_Prop)); + vlan_prop_init(piface->pvlan_prop, vlan_type); +} + +static void vlan_prop_uninit(struct VLAN_Prop *pvlan_prop) +{ + struct VLAN_Prop_8021q *p_8021q; + if (pvlan_prop == NULL) { + return; + } + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q = &(pvlan_prop->props.prop_8021q); + SAFE_FREE(p_8021q->parent); + } +} + +static void br_prop_uninit(struct BR_Prop *pbr_prop) +{ + int i; + if (pbr_prop == NULL) { + return; + } + i = 0; + if (pbr_prop->port_names != NULL) { + while (i < pbr_prop->port_num) { + SAFE_FREE(pbr_prop->port_names[i]); + i++; + } + SAFE_FREE(pbr_prop->port_names); + } +} + +void eth_iface_uninit(struct EthIface *piface) +{ + if (piface == NULL) { + return; + } + SAFE_FREE(piface->name); + SAFE_FREE(piface->dep_ifname); + SAFE_FREE(piface->attach_bridge); + SAFE_FREE(piface->mac); + br_prop_uninit(piface->pbr_prop); + SAFE_FREE(piface->pbr_prop); + vlan_prop_uninit(piface->pvlan_prop); + SAFE_FREE(piface->pvlan_prop); + return; +} + +void eth_ifaceslist_init(struct EthIfacesList *plist) +{ + plist->count = 0; +} + +void eth_ifaceslist_uninit(struct EthIfacesList *plist) +{ + struct EthIface **t; + int i; + if (plist->count <= 0) { + return; + } + t = plist->pifaces; + i = 0; + while (i < plist->count) { + if (*t != NULL) { + eth_iface_uninit(*t); + SAFE_FREE(*t); + } + t++; + i++; + } + return; +} + +int eth_ifaceslist_add(struct EthIfacesList *plist, struct EthIface **ppiface) +{ + if (plist->count >= MAX_IFACE_NUM) { + CU_DEBUG("too much device found."); + return 0; + } + plist->pifaces[plist->count] = *ppiface; + *ppiface = NULL; + plist->count++; + return 1; +} + +struct EthIface *eth_ifaceslist_search(struct EthIfacesList *plist, + char *name) +{ + int i = 0; + struct EthIface *piface = NULL; + + while (i < plist->count) { + piface = plist->pifaces[i]; + i++; + if (piface != NULL) { + if (0 == strcmp(piface->name, name)) { + return piface; + } + } + } + return NULL; +} + +/* Dummy function to suppress error message from libxml2 */ +static void swallow_err_msg(void *ctx, const char *msg, ...) +{ + /* do nothing, just swallow the message. */ +} + + +static const char *gen_eth_xmlnode_iface(xmlNodePtr root, + struct EthIface *piface, + struct EthIfacesList *plist, + int bridge_port_flag) +{ + const char *msg = NULL; + xmlNodePtr temp_node1 = NULL, temp_node2 = NULL, temp_node3 = NULL; + char *str, buf[16]; + int i; + struct EthIface *pifaceport; + + if (piface->name == NULL) { + msg = "iface have no name.\n"; + goto out; + } + /* netcfg have no xml for iface attatched to bridge */ + if ((piface->attach_bridge != NULL) && (bridge_port_flag != 1)) { + goto out; + } + + temp_node1 = xmlNewChild(root, NULL, BAD_CAST "interface", NULL); + if (temp_node1 == NULL) { + msg = XML_ERROR; + goto out; + } + xmlNewProp(temp_node1, BAD_CAST "name", BAD_CAST piface->name); + if (piface->eth_type & ETH_TYPE_ETHER_ANY) { + if (piface->eth_type & ETH_TYPE_ETHER_SUB_BRIDGE) { + str = "bridge"; + } else if (piface->eth_type & ETH_TYPE_ETHER_SUB_VLAN) { + str = "vlan"; + } else { + str = "ethernet"; + } + xmlNewProp(temp_node1, BAD_CAST "type", BAD_CAST str); + } + + if ((piface->pvlan_prop != NULL) && + (piface->pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q)) { + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "vlan", NULL); + snprintf(buf, sizeof(buf), + "%d", piface->pvlan_prop->props.prop_8021q.vlan_id); + xmlNewProp(temp_node2, BAD_CAST "tag", BAD_CAST buf); + temp_node3 = xmlNewChild(temp_node2, NULL, BAD_CAST "interface", NULL); + xmlNewProp(temp_node3, BAD_CAST "name", + BAD_CAST piface->pvlan_prop->props.prop_8021q.parent); + } + + /* if it is attached to bridge, only above properties could be set */ + if (bridge_port_flag == 1) { + goto out; + } + + if (piface->pbr_prop != NULL) { + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "bridge", NULL); + if (piface->pbr_prop->STP == 1) { + snprintf(buf, sizeof(buf), "on"); + } else { + snprintf(buf, sizeof(buf), "off"); + } + xmlNewProp(temp_node2, BAD_CAST "stp", BAD_CAST buf); + if (piface->pbr_prop->delay >= 0) { + snprintf(buf, sizeof(buf), "%d", piface->pbr_prop->delay); + xmlNewProp(temp_node2, BAD_CAST "delay", BAD_CAST buf); + } + if ((piface->pbr_prop->port_names != NULL) && + (piface->pbr_prop->port_num > 0)) { + for (i = 0; i < piface->pbr_prop->port_num; i++) { + pifaceport = eth_ifaceslist_search(plist, + piface->pbr_prop->port_names[i]); + if (pifaceport == NULL) { + CU_DEBUG("failed to find port %s of bridge %s in list.", + piface->pbr_prop->port_names[i], piface->name); + } else { + gen_eth_xmlnode_iface(temp_node2, pifaceport, plist, 1); + } + } + } + } + + if (piface->run_prop.boot_mode == BOOT_MODE_AUTOSTART) { + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "start", NULL); + xmlNewProp(temp_node2, BAD_CAST "mode", BAD_CAST "onboot"); + } else if (piface->run_prop.boot_mode == BOOT_MODE_NONE) { + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "start", NULL); + xmlNewProp(temp_node2, BAD_CAST "mode", BAD_CAST "none"); + } + if (piface->mac != NULL) { + temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "mac", NULL); + xmlNewProp(temp_node2, BAD_CAST "address", BAD_CAST piface->mac); + } + + out: + return msg; +} + +static const char *gen_eth_xmlnode(xmlNodePtr root, + struct EthIfacesList *plist) +{ + const char *msg = NULL; + int i = 0; + struct EthIface *piface = NULL; + + while (i < plist->count) { + piface = plist->pifaces[i]; + i++; + msg = gen_eth_xmlnode_iface(root, piface, plist, 0); + if (msg != NULL) { + goto out; + } + } + + out: + return msg; +} + +const char *EthIfaceListTOXML(char **ppxml, + struct EthIfacesList *plist, + int dump_all_flag) +{ + const char *msg = NULL; + xmlNodePtr root = NULL; + + root = xmlNewNode(NULL, BAD_CAST "tmp"); + if (root == NULL) { + msg = "failed to create root node."; + goto out; + } + msg = gen_eth_xmlnode(root, plist); + if (msg == NULL) { + if (dump_all_flag == 1) { + *ppxml = tree_to_xml(root); + } else { + *ppxml = tree_to_xml(root->children); + } + } + + out: + xmlFreeNode(root); + return msg; +} + +static int parse_eth_xmlnode(struct EthIfacesList *plist, xmlNode *inode, + int status, char *attached) +{ + struct EthIface *piface = NULL; + xmlNode *child1 = NULL, *child2 = NULL; + char *temp = NULL, **ppchar; + + SAFE_MALLOC(piface, sizeof(struct EthIface)); + eth_iface_init(piface); + + piface->name = get_attr_value(inode, "name"); + piface->run_prop.status = status; + if (attached != NULL) { + piface->attach_bridge = strdup(attached); + } + temp = get_attr_value(inode, "type"); + if (temp != NULL) { + if (0 == strcmp(temp, "ethernet")) { + piface->eth_type = ETH_TYPE_ETHER_ANY; + } + if (0 == strcmp(temp, "bridge")) { + piface->eth_type = ETH_TYPE_ETHER_ANY | ETH_TYPE_ETHER_SUB_BRIDGE; + } + if (0 == strcmp(temp, "vlan")) { + piface->eth_type = ETH_TYPE_ETHER_ANY | ETH_TYPE_ETHER_SUB_VLAN; + } + SAFE_FREE(temp); + } + + for (child1 = inode->children; child1 != NULL; child1 = child1->next) { + if (XSTREQ(child1->name, "start")) { + temp = get_attr_value(child1, "mode"); + if (0 == strcmp(temp, "onboot")) { + piface->run_prop.boot_mode = BOOT_MODE_AUTOSTART; + } + if (0 == strcmp(temp, "none")) { + piface->run_prop.boot_mode = BOOT_MODE_NONE; + } + SAFE_FREE(temp); + } + if (XSTREQ(child1->name, "mac")) { + piface->mac = get_attr_value(child1, "address"); + } + if (XSTREQ(child1->name, "bridge")) { + eth_iface_add_br_prop(piface); + temp = get_attr_value(child1, "stp"); + if (0 == strcmp(temp, "on")) { + piface->pbr_prop->STP = 1; + } + if (0 == strcmp(temp, "off")) { + piface->pbr_prop->STP = 0; + } + SAFE_FREE(temp); + temp = get_attr_value(child1, "delay"); + piface->pbr_prop->delay = strtol(temp, NULL, 10); + SAFE_FREE(temp); + } + if (XSTREQ(child1->name, "bridge")) { + eth_iface_add_br_prop(piface); + temp = get_attr_value(child1, "stp"); + if (0 == strcmp(temp, "on")) { + piface->pbr_prop->STP = 1; + } + if (0 == strcmp(temp, "off")) { + piface->pbr_prop->STP = 0; + } + SAFE_FREE(temp); + temp = get_attr_value(child1, "delay"); + piface->pbr_prop->delay = strtol(temp, NULL, 10); + SAFE_FREE(temp); + for (child2 = child1->children; child2 != NULL; + child2 = child2->next) { + if (XSTREQ(child2->name, "interface")) { + if (piface->pbr_prop->port_names == NULL) { + SAFE_CALLOC(piface->pbr_prop->port_names, + MAX_IFACE_NUM, sizeof(char *)); + piface->pbr_prop->port_num = 0; + } + ppchar = piface->pbr_prop->port_names + + (piface->pbr_prop->port_num)++; + *ppchar = get_attr_value(child2, "name"); + parse_eth_xmlnode(plist, child2, status, piface->name); + } + } + } + if (XSTREQ(child1->name, "vlan")) { + eth_iface_add_vlan_prop(piface, VLAN_TYPE_802_1_Q); + temp = get_attr_value(child1, "tag"); + piface->pvlan_prop->props.prop_8021q.vlan_id = + strtol(temp, NULL, 10); + SAFE_FREE(temp); + for (child2 = child1->children; child2 != NULL; + child2 = child2->next) { + if (XSTREQ(child2->name, "interface")) { + piface->pvlan_prop->props.prop_8021q.parent = + get_attr_value(child2, "name"); + piface->dep_ifname = + get_attr_value(child2, "name"); + } + } + } + } + + eth_ifaceslist_add(plist, &piface); + return 1; +} + +static const char *XMLToEthIfaceList(struct EthIfacesList *plist, + const char *xml, + int status) +{ + xmlDoc *xmldoc; + xmlXPathContext *xpathCtx; + xmlXPathObject *xpathObj; + xmlChar *xpathstr; + xmlNode **dev_nodes = NULL; + xmlNodeSet *nsv = NULL; + int count = 0; + int len, devidx; + const char *msg = NULL; + + len = strlen(xml) + 1; + xpathstr = (xmlChar *)"/interface"; + + xmlSetGenericErrorFunc(NULL, swallow_err_msg); + if ((xmldoc = xmlParseMemory(xml, len)) == NULL) { + msg = "failed to get xmldoc."; + goto err1; + } + + if ((xpathCtx = xmlXPathNewContext(xmldoc)) == NULL) { + msg = "failed to get pathCtx"; + goto err2; + } + + if ((xpathObj = xmlXPathEvalExpression(xpathstr, xpathCtx)) + == NULL) { + msg = "failed to get xpathObj"; + goto err3; + } + + nsv = xpathObj->nodesetval; + if (nsv == NULL) { + msg = "failed to get nodesetval."; + goto out; + } + + dev_nodes = nsv->nodeTab; + count = nsv->nodeNr; + + if (count <= 0) { + msg = "nodesetval have less that 1 values."; + goto out; + } + + for (devidx = 0; devidx < count; devidx++) { + parse_eth_xmlnode(plist, dev_nodes[devidx], status, NULL); + } + + out: + xmlSetGenericErrorFunc(NULL, NULL); + xmlXPathFreeObject(xpathObj); + + err3: + xmlXPathFreeContext(xpathCtx); + err2: + xmlFreeDoc(xmldoc); + err1: + return msg; +} + +CMPIStatus get_host_ifaces(struct EthIfacesList *plist, + const CMPIBroker *broker, char *prefix) +{ + virConnectPtr conn = NULL; + virInterfacePtr iface; + CMPIStatus s = {CMPI_RC_ERR_FAILED, NULL}; + int num, listnum, i; + char **names = NULL; + char *dump = NULL; + int flags = 0; + const char *msg; + + conn = connect_by_classname(broker, prefix, &s); + if (conn == NULL) { + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, "connect failed."); + goto out; + } + + /* list defined interfaces*/ + num = virConnectNumOfDefinedInterfaces(conn); + if (num < 0) { + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, + "failed to find number of defined interfaces."); + goto out; + } + names = malloc(num * sizeof(char *)); + listnum = virConnectListDefinedInterfaces(conn, names, num); + if (listnum < 0) { + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, + "failed to list names of defined interfaces."); + goto out; + } + CU_DEBUG("%d defined ifaces found from libvirt API.\n", listnum); + + flags |= VIR_INTERFACE_XML_INACTIVE; + for (i = 0; i < listnum; i++) { + iface = virInterfaceLookupByName(conn, names[i]); + if (!iface) { + CU_DEBUG("failed to look up %s.\n", names[i]); + SAFE_FREE(names[i]); + continue; + } + SAFE_FREE(names[i]); + dump = virInterfaceGetXMLDesc(iface, flags); + CU_DEBUG("defined interface %d xml:\n%s", i, dump); + msg = XMLToEthIfaceList(plist, dump, 0); + if (msg != NULL) { + CU_DEBUG("failed parsing eth xml, msg is: %s.", msg); + } + SAFE_FREE(dump); + virInterfaceFree(iface); + } + SAFE_FREE(names); + + /* list active interfaces*/ + num = virConnectNumOfInterfaces(conn); + if (num < 0) { + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, + "failed to find number of active interfaces."); + goto out; + } + names = malloc(num * sizeof(char *)); + + listnum = virConnectListInterfaces(conn, names, num); + if (listnum < 0) { + RECORD_MSG(broker, &s, CMPI_RC_ERR_FAILED, + "failed to list names of active interfacess."); + goto out; + } + CU_DEBUG("%d active ifaces found from libvirt API.\n", listnum); + + flags |= VIR_INTERFACE_XML_INACTIVE; + for (i = 0; i < listnum; i++) { + iface = virInterfaceLookupByName(conn, names[i]); + if (!iface) { + CU_DEBUG("failed to look up %s.\n", names[i]); + SAFE_FREE(names[i]); + continue; + } + SAFE_FREE(names[i]); + dump = virInterfaceGetXMLDesc(iface, flags); + CU_DEBUG("active interface %d xml:\n%s", i, dump); + msg = XMLToEthIfaceList(plist, dump, 1); + if (msg != NULL) { + CU_DEBUG("failed parsing eth xml, msg is: %s.", msg); + } + SAFE_FREE(dump); + virInterfaceFree(iface); + } + s.rc = CMPI_RC_OK; + + out: + virConnectClose(conn); + SAFE_FREE(names); + return s; +} +/* + * Local Variables: + * mode: C + * c-set-style: "K&R" + * tab-width: 8 + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/libxkutil/network_parsing.h b/libxkutil/network_parsing.h new file mode 100644 index 0000000..bbfe729 --- /dev/null +++ b/libxkutil/network_parsing.h @@ -0,0 +1,160 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Wenchao Xia <xiawenc@cn.ibm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#ifndef NETWORK_PARSING_H +#define NETWORK_PARSING_H + +#include <cmpidt.h> +#include <cmpift.h> +#include <cmpimacs.h> + +/* value defines */ +#define MAX_IFACE_NUM 4096 + +#define NUM_NOT_GOT -1 + +#define ETH_TYPE_BASE_MASK 0xff00 +#define ETH_TYPE_SUB_MASK 0x00ff + +#define CMD_DEBUG_LEVEL 2 + +/* macro functions */ +#define CMD_DEBUG(lvl, fmt, args...) do { \ + if (CMD_DEBUG_LEVEL && (lvl) <= CMD_DEBUG_LEVEL) { \ + debug_print(fmt, ##args); \ + } \ +} while (0) + +#define SAFE_MALLOC(p, size) \ +{ \ + (p) = malloc((size)); \ + if ((p) == NULL) { \ + CU_DEBUG("malloc failed."); \ + } \ +} + +#define SAFE_CALLOC(p, nmen, size) \ +{ \ + (p) = calloc((nmen), (size)); \ + if ((p) == NULL) { \ + CU_DEBUG("calloc failed."); \ + } \ +} + +#define SAFE_FREE(p) {free(p); (p) = NULL; } + +#define RECORD_MSG(broker, ps, rc, fmt, args...) do { \ + CU_DEBUG(fmt, ##args); \ + if (broker) { \ + cu_statusf((broker), (ps), (rc), fmt, ##args); \ + } \ +} while (0) + +typedef enum { + ETH_TYPE_NOT_GOT = 0x0000, + ETH_TYPE_ETHER_ANY = 0x0100, + ETH_TYPE_ETHER_SUB_PHYSICAL = 0x0001, + ETH_TYPE_ETHER_SUB_BRIDGE = 0x0002, + ETH_TYPE_ETHER_SUB_VLAN = 0x0004 +} EthType; + +typedef enum { + VLAN_TYPE_NOT_GOT = NUM_NOT_GOT, + VLAN_TYPE_802_1_Q = 1, + VLAN_TYPE_802_1_QBG = 2, + VLAN_TYPE_802_1_QBH = 4 +} VLANType; + +typedef enum { + BOOT_MODE_NOT_GOT = NUM_NOT_GOT, + BOOT_MODE_AUTOSTART = 1, + BOOT_MODE_NONE = 2 +} BootMode; + +struct BR_Prop { + int STP; + int delay; + char **port_names; + int port_num; +} ; + +struct Run_Prop { + int status; + BootMode boot_mode; +} ; + +struct VLAN_Prop_8021q { + int vlan_id; + char *parent; +} ; + +/* HP vlan standard, TBD */ +struct VLAN_Prop_8021qbg { + int invalid; +} ; + +/* Cisco and VMware vlan standard, TBD */ +struct VLAN_Prop_8021qbh { + int invalid; +} ; + +struct VLAN_Prop { + int vlan_type; + union { + struct VLAN_Prop_8021q prop_8021q; + struct VLAN_Prop_8021qbg prop_8021qbg; + struct VLAN_Prop_8021qbh prop_8021qbh; + } props; +} ; + +/* EthIface is logical devices include eth ports and bridges */ +struct EthIface { + char *name; + char *dep_ifname; /* parent dev name */ + char *attach_bridge; /* bridge the iface is attached to */ + char *mac; + EthType eth_type; + struct Run_Prop run_prop; + /* optional properties */ + struct BR_Prop *pbr_prop; + struct VLAN_Prop *pvlan_prop; +} ; + +struct EthIfacesList { + struct EthIface *pifaces[MAX_IFACE_NUM]; + int count; +} ; + +void eth_iface_init(struct EthIface *piface); +void eth_iface_add_br_prop(struct EthIface *piface); +void eth_iface_add_vlan_prop(struct EthIface *piface, int vlan_type); +void eth_iface_uninit(struct EthIface *piface); + +void eth_ifaceslist_init(struct EthIfacesList *plist); +void eth_ifaceslist_uninit(struct EthIfacesList *plist); +/* ppiface must be allocated from heap, to save code of struct duplication */ +int eth_ifaceslist_add(struct EthIfacesList *plist, struct EthIface **ppiface); +/* returned pointer is direct reference to a member in plist */ +struct EthIface *eth_ifaceslist_search(struct EthIfacesList *plist, + char *name); + +void eth_iface_print(struct EthIface *piface); +void eth_ifaceslist_print(struct EthIfacesList *plist); + +CMPIStatus get_host_ifaces(struct EthIfacesList *plist, + const CMPIBroker *broker, char *prefix); + +const char *EthIfaceListTOXML(char **ppxml, + struct EthIfacesList *plist, + int dump_all_flag); + +#endif diff --git a/libxkutil/network_parsing_test.c b/libxkutil/network_parsing_test.c new file mode 100644 index 0000000..593bfd0 --- /dev/null +++ b/libxkutil/network_parsing_test.c @@ -0,0 +1,61 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <pthread.h> +#include <unistd.h> +#include <time.h> +#include <assert.h> +#include <sys/time.h> +#include <libvirt/libvirt.h> +#include <libxml/tree.h> +#include <libxml/parser.h> +#include <libxml/xpath.h> + +#include <cmpidt.h> +#include <cmpift.h> +#include <cmpimacs.h> + +#include "misc_util.h" +#include "device_parsing.h" +#include "network_parsing.h" + +static const CMPIBroker *broker; + +static long print_and_ret_time_stamp(void) +{ + struct timeval tv; + long ret; + gettimeofday(&tv, NULL); + ret = tv.tv_sec*1000 + tv.tv_usec/1000; + CU_DEBUG("time is [%ld] ms.", ret); + return ret; +} + +/* try retrieve all information, and then map them back to xml. */ +int main(int argc, char **argv) +{ + libvirt_cim_init(); + struct EthIfacesList *plist = NULL; + const char *msg = NULL; + char *genxml = NULL; + CMPIStatus s; + long start_time, end_time; + + SAFE_MALLOC(plist, sizeof(struct EthIfacesList)); + eth_ifaceslist_init(plist); + + start_time = print_and_ret_time_stamp(); + s = get_host_ifaces(plist, broker, "kvm"); + end_time = print_and_ret_time_stamp(); + CU_DEBUG("cost [%d]ms in discovering host network. Result:", + end_time - start_time); + eth_ifaceslist_print(plist); + + msg = EthIfaceListTOXML(&genxml, plist, 1); + CU_DEBUG("xml gen msg is %s. xml is:\n%s", msg, genxml); + SAFE_FREE(genxml); + + eth_ifaceslist_uninit(plist); + SAFE_FREE(plist); + return 0; +} diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c index 9a2ada9..001246a 100644 --- a/libxkutil/xmlgen.c +++ b/libxkutil/xmlgen.c @@ -830,7 +830,7 @@ static char *features_xml(xmlNodePtr root, struct domain *domain) return NULL; } -static char *tree_to_xml(xmlNodePtr root) +char *tree_to_xml(xmlNodePtr root) { xmlBufferPtr buffer = NULL; xmlSaveCtxtPtr savectx = NULL; diff --git a/libxkutil/xmlgen.h b/libxkutil/xmlgen.h index 743fc82..5d21a94 100644 --- a/libxkutil/xmlgen.h +++ b/libxkutil/xmlgen.h @@ -32,6 +32,8 @@ struct kv { const char *val; }; +char *tree_to_xml(xmlNodePtr root); + char *system_to_xml(struct domain *dominfo); char *device_to_xml(struct virt_device *dev); -- 1.7.1