[Libvirt-cim] [PATCH V6 1/7] vlan extention - readonly function libarary

xiaxia347work at 163.com xiaxia347work at 163.com
Tue Jan 31 13:18:30 UTC 2012


From: Wenchao Xia <xiawenc at linux.vnet.ibm.com>

    This patch add function libarary and test program with libvirt API.

Signed-off-by: Wenchao Xia <xiawenc at linux.vnet.ibm.com>
---
 libxkutil/Makefile.am            |   12 +-
 libxkutil/misc_util.c            |   48 +++
 libxkutil/misc_util.h            |    3 +
 libxkutil/network_parsing.c      |  762 ++++++++++++++++++++++++++++++++++++++
 libxkutil/network_parsing.h      |  176 +++++++++
 libxkutil/network_parsing_test.c |   70 ++++
 libxkutil/xmlgen.c               |    4 +-
 libxkutil/xmlgen.h               |    4 +
 8 files changed, 1074 insertions(+), 5 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..a1fc0b3 100644
--- a/libxkutil/Makefile.am
+++ b/libxkutil/Makefile.am
@@ -4,12 +4,14 @@ AM_CFLAGS = $(CFLAGS_STRICT) \
             -DLIBVIRTCIM_CONF=\"@sysconfdir@/@PACKAGE at .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 network_model_helper.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 network_model_helper.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..564c6f2 100644
--- a/libxkutil/misc_util.c
+++ b/libxkutil/misc_util.c
@@ -184,6 +184,54 @@ virConnectPtr connect_by_classname(const CMPIBroker *broker,
         return conn;
 }
 
+virConnectPtr connect_any(void)
+{
+        const char *uri = NULL;
+        virConnectPtr conn = NULL;
+        hypervisor_status_t *h = NULL;
+        const char *classname = NULL;
+
+        for (h = &hypervisor_list[0]; h != NULL; h++) {
+                if (h->enabled) {
+
+                        classname = h->name;
+
+                        uri = cn_to_uri(classname);
+                        if (!uri) {
+                                CU_DEBUG("Unable to gen URI from classname,"
+                                 " uri is %s.", uri);
+                                return NULL;
+                        }
+                        CU_DEBUG("Connecting to libvirt with uri `%s'", uri);
+
+                        pthread_mutex_lock(&libvirt_mutex);
+
+                        if (is_read_only())
+                                conn = virConnectOpenReadOnly(uri);
+                        else
+                                conn = virConnectOpen(uri);
+
+                        pthread_mutex_unlock(&libvirt_mutex);
+
+                        if (!conn) {
+                                virErrorPtr error = virGetLastError();
+                                if (error->code == VIR_ERR_NO_CONNECT)
+                                        set_hypervisor_disabled(classname);
+
+                                CU_DEBUG("Unable to connect to `%s'", uri);
+                                continue;
+                        } else {
+                                break;
+                        }
+                }
+        }
+
+        if (classname == NULL) {
+                CU_DEBUG("Failed to find any hypervisor.");
+        }
+        return conn;
+}
+
 void free_domain_list(virDomainPtr *list, int count)
 {
         int i;
diff --git a/libxkutil/misc_util.h b/libxkutil/misc_util.h
index c7a2122..d1cc081 100644
--- a/libxkutil/misc_util.h
+++ b/libxkutil/misc_util.h
@@ -57,6 +57,9 @@ virConnectPtr connect_by_classname(const CMPIBroker *broker,
                                    const char *classname,
                                    CMPIStatus *s);
 
+/* Try connect to any hypervisor available */
+virConnectPtr connect_any(void);
+
 /* Establish a libvirt connection to the appropriate hypervisor,
  * as determined by the state of the system, or the value of the
  * HYPURI environment variable, if set.
diff --git a/libxkutil/network_parsing.c b/libxkutil/network_parsing.c
new file mode 100644
index 0000000..aa1b2e7
--- /dev/null
+++ b/libxkutil/network_parsing.c
@@ -0,0 +1,762 @@
+/*
+ * Copyright IBM Corp. 2012
+ *
+ * Authors:
+ *  Wenchao Xia <xiawenc at 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 LIST_INACTIVE_IFACE 1
+#define LIST_ACTIVE_IFACE 2
+
+static void vlan_prop_print(struct VLAN_Prop *pvlan_prop)
+{
+    struct VLAN_Prop_8021q *p_8021q;
+    CU_DEBUG_OP(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);
+        CU_DEBUG_OP(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;
+    CU_DEBUG_OP(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) {
+        CU_DEBUG_OP(1, "----Ports attached: ");
+        while (i < pbr_prop->port_num) {
+            CU_DEBUG_OP(1, " %s,", *(pbr_prop->port_names+i));
+            i++;
+        }
+        CU_DEBUG_OP(1, "\n");
+    }
+}
+
+void eth_iface_print(struct EthIface *piface)
+{
+    CU_DEBUG_OP(1, "Iface device: name %s.\n"
+        "--Main Props: parent %s, attach to %s, mac %s, iface type %d,"
+        " status %d, boot_mode %d,"
+        " protocol ipv4 dhcp %d.\n",
+        piface->name,
+        piface->dep_ifname, piface->attach_bridge, piface->mac, piface->eth_type,
+        piface->run_prop.status, piface->run_prop.boot_mode,
+        piface->protocol_prop.ipv4_prop.DHCP);
+    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;
+    CU_DEBUG_OP(1, "Have %d ifaces in the list:\n", plist->count);
+    while (i < plist->count) {
+        CU_DEBUG_OP(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_NONE;
+    }
+}
+
+static void br_prop_init(struct BR_Prop *pbr_prop)
+{
+    memset(pbr_prop, 0, sizeof(struct BR_Prop));
+    pbr_prop->STP = NUM_NONE;
+    pbr_prop->delay = NUM_NONE;
+    pbr_prop->port_num = NUM_NONE;
+}
+
+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_NONE;
+    piface->run_prop.boot_mode = BOOT_MODE_NOT_GOT;
+    piface->protocol_prop.ipv4_prop.DHCP = NUM_NONE;
+    return;
+}
+
+void eth_iface_add_br_prop(struct EthIface *piface)
+{
+    if (piface->pbr_prop != NULL) {
+        return;
+    }
+    CU_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;
+    }
+    CU_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);
+        CU_FREE(p_8021q->parent);
+    }
+}
+
+static void br_prop_uninit(struct BR_Prop *pbr_prop)
+{
+    int i = 0;
+    if (pbr_prop == NULL) {
+        return;
+    }
+    if (pbr_prop->port_names != NULL) {
+        while (i < pbr_prop->port_num) {
+            CU_FREE(pbr_prop->port_names[i]);
+            i++;
+        }
+        CU_FREE(pbr_prop->port_names);
+    }
+}
+
+void eth_iface_uninit(struct EthIface *piface)
+{
+    if (piface == NULL) {
+        return;
+    }
+    CU_FREE(piface->name);
+    CU_FREE(piface->dep_ifname);
+    CU_FREE(piface->attach_bridge);
+    CU_FREE(piface->mac);
+    br_prop_uninit(piface->pbr_prop);
+    CU_FREE(piface->pbr_prop);
+    vlan_prop_uninit(piface->pvlan_prop);
+    CU_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 = NULL;
+    int i = 0;
+    if (plist->count <= 0) {
+        return;
+    }
+    t = plist->pifaces;
+    while (i < plist->count) {
+        if (*t != NULL) {
+            eth_iface_uninit(*t);
+            CU_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 (strcmp(piface->name, name) == 0) {
+                return piface;
+            }
+        }
+    }
+    return NULL;
+}
+
+/* the judgement condition is weak, but I can't find a better way */
+int eth_iface_filter_peths(const struct EthIface *piface, void *nouse)
+{
+    if ((piface->eth_type != ETH_TYPE_ETHER_ANY) &&
+        (piface->eth_type != ETH_TYPE_ETHER_PHYSICAL)) {
+        return 0;
+    }
+    if (piface->dep_ifname != NULL) {
+        return 0;
+    }
+    if (NULL != strstr(piface->name, ".")) {
+        return 0;
+    }
+    /* this filter NetUSB etc */
+    if (NULL == strstr(piface->name, "eth")) {
+        return 0;
+    }
+
+    return 1;
+}
+
+char *get_host_iface_error_reason(int errno)
+{
+    char *ret = NULL;
+    switch (errno) {
+    case ERR_CONNECT:
+        ret = "Error in connect to hypervisor.";
+        break;
+
+    case ERR_LIST_INTERFACE:
+        ret = "Error in listing the interfaces.";
+        break;
+
+    default:
+        ret = "Internal error in calling libvirt API for interfaces.";
+        break;
+    }
+    return ret;
+}
+
+/* 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 = NULL, buf[16] = {0,};
+    int i = 0;
+    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_BRIDGE) {
+        str = "bridge";
+    } else if (piface->eth_type == ETH_TYPE_ETHER_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->protocol_prop.ipv4_prop.DHCP == 1) {
+        temp_node2 = xmlNewChild(temp_node1, NULL, BAD_CAST "protocol", NULL);
+        xmlNewProp(temp_node2, BAD_CAST "family", BAD_CAST "ipv4");
+        temp_node3 = xmlNewChild(temp_node2, NULL, BAD_CAST "dhcp", NULL);
+    }
+
+    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 host_iface_adjust(struct EthIface *piface)
+{
+    if (1 == eth_iface_filter_peths(piface, NULL)) {
+        piface->eth_type = ETH_TYPE_ETHER_PHYSICAL;
+    }
+    return 1;
+}
+
+static int parse_eth_xmlnode(struct EthIfacesList *plist, xmlNode *inode,
+                             int status, char *attached,
+                             eth_iface_filter_func filter_func,
+                             void *filter_opaque)
+{
+    struct EthIface *piface = NULL;
+    xmlNode *child1 = NULL, *child2 = NULL;
+    char *temp = NULL, **ppchar;
+    int filter_ret = 0;
+
+    CU_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 (strcmp(temp, "ethernet") == 0) {
+            piface->eth_type = ETH_TYPE_ETHER_ANY;
+        }
+        if (strcmp(temp, "bridge") == 0) {
+            piface->eth_type = ETH_TYPE_ETHER_BRIDGE;
+        }
+        if (strcmp(temp, "vlan") == 0) {
+            piface->eth_type = ETH_TYPE_ETHER_VLAN;
+        }
+        CU_FREE(temp);
+    }
+
+    for (child1 = inode->children; child1 != NULL; child1 = child1->next) {
+        if (XSTREQ(child1->name, "start")) {
+            temp = get_attr_value(child1, "mode");
+            if (strcmp(temp, "onboot") == 0) {
+                piface->run_prop.boot_mode = BOOT_MODE_AUTOSTART;
+            }
+            if (strcmp(temp, "none") == 0) {
+                piface->run_prop.boot_mode = BOOT_MODE_NONE;
+            }
+            CU_FREE(temp);
+        }
+        if (XSTREQ(child1->name, "mac")) {
+            piface->mac = get_attr_value(child1, "address");
+        }
+        if (XSTREQ(child1->name, "protocol")) {
+            temp = get_attr_value(child1, "family");
+            if (strcmp(temp, "ipv4") == 0) {
+                for (child2 = child1->children; child2 != NULL;
+                                            child2 = child2->next) {
+                    if (XSTREQ(child2->name, "dhcp")) {
+                        piface->protocol_prop.ipv4_prop.DHCP = 1;
+                        break;
+                    }
+                }
+            }
+            CU_FREE(temp);
+        }
+        if (XSTREQ(child1->name, "bridge")) {
+            eth_iface_add_br_prop(piface);
+            temp = get_attr_value(child1, "stp");
+            if (strcmp(temp, "on") == 0) {
+                piface->pbr_prop->STP = 1;
+            }
+            if (strcmp(temp, "off") == 0) {
+                piface->pbr_prop->STP = 0;
+            }
+            CU_FREE(temp);
+            temp = get_attr_value(child1, "delay");
+            piface->pbr_prop->delay = strtol(temp, NULL, 10);
+            CU_FREE(temp);
+        }
+        if (XSTREQ(child1->name, "bridge")) {
+            eth_iface_add_br_prop(piface);
+            temp = get_attr_value(child1, "stp");
+            if (strcmp(temp, "on") == 0) {
+                piface->pbr_prop->STP = 1;
+            }
+            if (strcmp(temp, "off") == 0) {
+                piface->pbr_prop->STP = 0;
+            }
+            CU_FREE(temp);
+            temp = get_attr_value(child1, "delay");
+            piface->pbr_prop->delay = strtol(temp, NULL, 10);
+            CU_FREE(temp);
+            for (child2 = child1->children; child2 != NULL;
+                                            child2 = child2->next) {
+                if (XSTREQ(child2->name, "interface")) {
+                    if (piface->pbr_prop->port_names == NULL) {
+                        CU_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,
+                                      filter_func, filter_opaque);
+                }
+            }
+        }
+        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);
+            CU_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");
+                }
+            }
+        }
+    }
+
+    host_iface_adjust(piface);
+
+    filter_ret = 1;
+    if (filter_func != NULL) {
+        filter_ret = filter_func(piface, filter_opaque);
+    }
+    if (filter_ret == 1) {
+        eth_ifaceslist_add(plist, &piface);
+    }
+    return 1;
+}
+
+static const char *XMLToEthIfaceList(struct EthIfacesList *plist,
+                                     const char *xml,
+                                     int status,
+                                     eth_iface_filter_func filter_func,
+                                     void *filter_opaque)
+{
+    xmlDoc *xmldoc = NULL;
+    xmlXPathContext *xpathCtx = NULL;
+    xmlXPathObject *xpathObj = NULL;
+    xmlChar *xpathstr = NULL;
+    xmlNode **dev_nodes = NULL;
+    xmlNodeSet *nsv = NULL;
+    int count = 0;
+    int len = 0, devidx = 0;
+    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,
+                          filter_func, filter_opaque);
+    }
+
+ out:
+    xmlSetGenericErrorFunc(NULL, NULL);
+    xmlXPathFreeObject(xpathObj);
+
+ err3:
+    xmlXPathFreeContext(xpathCtx);
+ err2:
+    xmlFreeDoc(xmldoc);
+ err1:
+    return msg;
+}
+
+int get_host_ifaces(struct EthIfacesList *plist,
+                    eth_iface_filter_func filter_func, void *filter_opaque)
+{
+    virConnectPtr conn = NULL;
+    virInterfacePtr iface = NULL;
+    int ret = 0;
+    int num = 0, listnum = 0, i = 0;
+    char **names = NULL;
+    char *xml = NULL;
+    int flags = 0;
+    const char *msg = NULL;
+    int list_flag = LIST_INACTIVE_IFACE | LIST_ACTIVE_IFACE;
+    int xml_flag = VIR_INTERFACE_XML_INACTIVE;
+    //CMPIStatus s;
+
+    //conn = connect_by_classname(NULL, "xen", &s);
+    conn = connect_any();
+    if (conn == NULL) {
+        CU_DEBUG("Connect for network failed.");
+        ret = ERR_CONNECT;
+        goto out;
+    }
+
+    /* list defined interfaces*/
+    if ((list_flag & LIST_INACTIVE_IFACE) == 0) {
+        goto list_active;
+    }
+    num = virConnectNumOfDefinedInterfaces(conn);
+    if (num < 0) {
+        CU_DEBUG("Failed to find number of defined interfaces.");
+        ret = ERR_LIST_INTERFACE;
+        goto out;
+    }
+    names = malloc(num * sizeof(char *));
+    listnum = virConnectListDefinedInterfaces(conn, names, num);
+    if (listnum < 0) {
+        CU_DEBUG("Failed to list names of defined interfaces.");
+        ret = ERR_LIST_INTERFACE;
+        goto out;
+    }
+    CU_DEBUG("%d defined ifaces found from libvirt API.\n", listnum);
+
+    flags = xml_flag;
+    for (i = 0; i < listnum; i++) {
+        iface = virInterfaceLookupByName(conn, names[i]);
+        if (!iface) {
+            CU_DEBUG("Failed to look up %s.\n", names[i]);
+            CU_FREE(names[i]);
+            continue;
+        }
+        CU_FREE(names[i]);
+        xml = virInterfaceGetXMLDesc(iface, flags);
+        CU_DEBUG("Defined interface %d xml:\n%s", i, xml);
+        msg = XMLToEthIfaceList(plist, xml, ETH_STATE_INACTIVE,
+                               filter_func, filter_opaque);
+        if (msg != NULL) {
+            CU_DEBUG("Failed parsing eth xml, msg is: %s.", msg);
+        }
+        CU_FREE(xml);
+        virInterfaceFree(iface);
+    }
+    CU_FREE(names);
+
+ list_active:
+    /* list active interfaces*/
+    if ((list_flag & LIST_ACTIVE_IFACE) == 0) {
+        goto out;
+    }
+    num = virConnectNumOfInterfaces(conn);
+    if (num < 0) {
+        CU_DEBUG("Failed to find number of active interfaces.");
+        ret = ERR_LIST_INTERFACE;
+        goto out;
+    }
+    names = malloc(num * sizeof(char *));
+
+    listnum = virConnectListInterfaces(conn, names, num);
+    if (listnum < 0) {
+        CU_DEBUG("Failed to list names of active interfacess.");
+        ret = ERR_LIST_INTERFACE;
+        goto out;
+    }
+    CU_DEBUG("%d active ifaces found from libvirt API.\n", listnum);
+
+    flags = xml_flag;
+    for (i = 0; i < listnum; i++) {
+        iface = virInterfaceLookupByName(conn, names[i]);
+        if (!iface) {
+            CU_DEBUG("Failed to look up %s.\n", names[i]);
+            CU_FREE(names[i]);
+            continue;
+        }
+        CU_FREE(names[i]);
+        xml = virInterfaceGetXMLDesc(iface, flags);
+        CU_DEBUG("Active interface %d xml:\n%s", i, xml);
+        msg = XMLToEthIfaceList(plist, xml, ETH_STATE_ACTIVE,
+                                filter_func, filter_opaque);
+        if (msg != NULL) {
+            CU_DEBUG("Failed parsing eth xml, msg is: %s.", msg);
+        }
+        CU_FREE(xml);
+        virInterfaceFree(iface);
+    }
+    ret = 1;
+
+ out:
+    virConnectClose(conn);
+    CU_FREE(names);
+    return ret;
+}
+/*
+ * 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..5994f78
--- /dev/null
+++ b/libxkutil/network_parsing.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright IBM Corp. 2012
+ *
+ * Authors:
+ *  Wenchao Xia <xiawenc at 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_NONE -1
+
+#define CU_DEBUG_LEVEL 2
+
+/* macro functions */
+#define CU_DEBUG_OP(lvl, fmt, args...) do { \
+    if (CU_DEBUG_LEVEL && (lvl) <= CU_DEBUG_LEVEL) { \
+        debug_print(fmt, ##args); \
+    } \
+} while (0)
+
+#define CU_MALLOC(p, size) \
+{ \
+    (p) = malloc((size)); \
+    if ((p) == NULL) { \
+        CU_DEBUG("malloc failed."); \
+    } \
+}
+
+#define CU_CALLOC(p, nmen, size) \
+{ \
+    (p) = calloc((nmen), (size)); \
+    if ((p) == NULL) { \
+        CU_DEBUG("calloc failed."); \
+    } \
+}
+
+#define CU_FREE(p) {free(p); (p) = NULL; }
+
+#define CU_STRDUP(p) (p) == NULL ? NULL : strdup(p);
+
+#define ERR_CONNECT -1
+#define ERR_LIST_INTERFACE -2
+
+typedef enum {
+    ETH_TYPE_NOT_GOT = NUM_NONE,
+    ETH_TYPE_ETHER_ANY = 0x0001,
+    ETH_TYPE_ETHER_PHYSICAL = 0x0002,
+    ETH_TYPE_ETHER_BRIDGE = 0x0004,
+    ETH_TYPE_ETHER_VLAN = 0x0008
+} EthType;
+
+typedef enum {
+    VLAN_TYPE_NOT_GOT = NUM_NONE,
+    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_NONE,
+    BOOT_MODE_NONE = 0,
+    BOOT_MODE_AUTOSTART = 1
+} BootMode;
+
+typedef enum {
+    ETH_STATE_INACTIVE = 0,
+    ETH_STATE_ACTIVE = 1
+} Status;
+
+struct IPV4_Prop {
+    int DHCP;
+} ;
+
+struct Protocol_Prop {
+    struct IPV4_Prop ipv4_prop;
+} ;
+
+struct BR_Prop {
+    int STP;
+    int delay;
+    char **port_names;
+    int port_num;
+} ;
+
+struct Run_Prop {
+    Status 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;
+    struct Protocol_Prop protocol_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);
+
+typedef int (*eth_iface_filter_func)(const struct EthIface *piface,
+                                     void *opaque);
+
+int eth_iface_filter_peths(const struct EthIface *piface, void *nouse);
+
+int get_host_ifaces(struct EthIfacesList *plist,
+                    eth_iface_filter_func filter_func, void *filter_opaque);
+
+char *get_host_iface_error_reason(int errno);
+
+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..31a1a3b
--- /dev/null
+++ b/libxkutil/network_parsing_test.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright IBM Corp. 2012
+ *
+ * Authors:
+ *  Wenchao Xia <xiawenc at 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.
+ */
+
+#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 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;
+    long start_time, end_time;
+
+    CU_MALLOC(plist, sizeof(struct EthIfacesList));
+    eth_ifaceslist_init(plist);
+
+    start_time = print_and_ret_time_stamp();
+    get_host_ifaces(plist, NULL, NULL);
+    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);
+    CU_FREE(genxml);
+
+    eth_ifaceslist_uninit(plist);
+    CU_FREE(plist);
+    return 0;
+}
diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c
index 9a2ada9..33da52b 100644
--- a/libxkutil/xmlgen.c
+++ b/libxkutil/xmlgen.c
@@ -35,8 +35,6 @@
 #include "cmpimacs.h"
 #endif
 
-#define XML_ERROR "Failed to allocate XML memory"
-
 typedef const char *(*devfn_t)(xmlNodePtr node, struct domain *dominfo);
 typedef const char *(*poolfn_t)(xmlNodePtr node, struct virt_pool *pool);
 typedef const char *(*resfn_t)(xmlNodePtr node, struct virt_pool_res *res);
@@ -830,7 +828,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..9c88986 100644
--- a/libxkutil/xmlgen.h
+++ b/libxkutil/xmlgen.h
@@ -27,11 +27,15 @@
 
 #include "cmpidt.h"
 
+#define XML_ERROR "Failed to allocate XML memory"
+
 struct kv {
 	const char *key;
 	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






More information about the Libvirt-cim mailing list