This patch add function libarary and test program with libvirt API.
Limit:
It have only DHCP property about IP settings. Other settings such IP
and mask are ignored, in most cases ip are got by DHCP.
V7: Add codes of writing about network configuration. Codes such as iface
comparing and duplication are removed comparing to V2, which brings some
limit to the usage of API and structure, but make things more simple.
V6: Code changes according to comments.
V5: Calling libvirt API instead of implement my own.
Signed-off-by: Wenchao Xia <xiawenc(a)linux.vnet.ibm.com>
---
libxkutil/Makefile.am | 14 +-
libxkutil/misc_util.c | 48 ++
libxkutil/misc_util.h | 3 +
libxkutil/network_parsing.c | 1309 ++++++++++++++++++++++++++++++++++++++
libxkutil/network_parsing.h | 217 +++++++
libxkutil/network_parsing_test.c | 184 ++++++
libxkutil/xmlgen.c | 4 +-
libxkutil/xmlgen.h | 4 +
8 files changed, 1778 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 8d436ad..d154ef6 100644
--- a/libxkutil/Makefile.am
+++ b/libxkutil/Makefile.am
@@ -11,7 +11,9 @@ noinst_HEADERS = \
infostore.h \
pool_parsing.h \
acl_parsing.h \
- list_util.h
+ list_util.h \
+ network_parsing.h \
+ network_model_helper.h
lib_LTLIBRARIES = \
libxkutil.la
@@ -24,7 +26,9 @@ libxkutil_la_SOURCES = \
infostore.c \
pool_parsing.c \
acl_parsing.c \
- list_util.c
+ list_util.c \
+ network_parsing.c \
+ network_model_helper.c
libxkutil_la_LDFLAGS = \
-version-info @VERSION_INFO@
@@ -42,3 +46,9 @@ xml_parse_test_SOURCES = \
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..b043b40
--- /dev/null
+++ b/libxkutil/network_parsing.c
@@ -0,0 +1,1309 @@
+/*
+ * Copyright IBM Corp. 2012
+ *
+ * Authors:
+ * Wenchao Xia <xiawenc(a)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);
+}
+
+static void eth_iface_add_br_prop_attached_iface(struct EthIface *pbridge,
+ const char *iface_name)
+{
+ char **ppchar = NULL;
+
+ if (pbridge->pbr_prop->port_names == NULL) {
+ CU_CALLOC(pbridge->pbr_prop->port_names,
+ MAX_IFACE_NUM, sizeof(char *));
+ pbridge->pbr_prop->port_num = 0;
+ }
+
+ ppchar = pbridge->pbr_prop->port_names +
+ (pbridge->pbr_prop->port_num)++;
+ *ppchar = CU_STRDUP(iface_name);
+}
+
+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;
+}
+
+static void vlan_prop_merge(struct VLAN_Prop *pdest, struct VLAN_Prop *psrc)
+{
+ struct VLAN_Prop_8021q *pd_8021q, *ps_8021q;
+
+ NUM_MERGE(pdest->vlan_type, psrc->vlan_type, VLAN_TYPE_NOT_GOT);
+
+ if (psrc->vlan_type == VLAN_TYPE_802_1_Q) {
+ pd_8021q = &(pdest->props.prop_8021q);
+ ps_8021q = &(psrc->props.prop_8021q);
+ NUM_MERGE(pd_8021q->vlan_id, ps_8021q->vlan_id, NUM_NONE);
+ CHARS_MERGE(pd_8021q->parent, ps_8021q->parent);
+ }
+}
+
+static void br_prop_merge(struct BR_Prop *pdest, struct BR_Prop *psrc)
+{
+ int i;
+
+ /*merge it when dest have not been set */
+ if ((pdest->port_names == NULL) && (psrc->port_names != NULL)){
+ CU_PSTR_ARRAY_DUP(pdest->port_names, pdest->port_num,
+ psrc->port_names, psrc->port_num, i);
+ }
+
+ NUM_MERGE(pdest->STP, psrc->STP, NUM_NONE);
+ NUM_MERGE(pdest->delay, psrc->delay, NUM_NONE);
+}
+
+static void eth_iface_merge(struct EthIface *dest, struct EthIface *src)
+{
+ CHARS_MERGE(dest->name, src->name);
+ CHARS_MERGE(dest->dep_ifname, src->dep_ifname);
+ CHARS_MERGE(dest->attach_bridge, src->attach_bridge);
+ CHARS_MERGE(dest->mac, src->mac);
+ NUM_MERGE(dest->eth_type, src->eth_type, NUM_NONE);
+
+ NUM_MERGE(dest->run_prop.status, src->run_prop.status,
+ NUM_NONE);
+ NUM_MERGE(dest->run_prop.boot_mode, src->run_prop.boot_mode,
+ BOOT_MODE_NOT_GOT);
+ NUM_MERGE(dest->protocol_prop.ipv4_prop.DHCP,
+ src->protocol_prop.ipv4_prop.DHCP,
+ NUM_NONE);
+ if (src->pbr_prop != NULL) {
+ if (dest->pbr_prop == NULL) {
+ CU_MALLOC(dest->pbr_prop, sizeof(struct BR_Prop));
+ br_prop_init(dest->pbr_prop);
+ }
+ br_prop_merge(dest->pbr_prop, src->pbr_prop);
+ }
+
+ if (src->pvlan_prop != NULL) {
+ if (dest->pvlan_prop == NULL) {
+ CU_MALLOC(dest->pvlan_prop, sizeof(struct VLAN_Prop));
+ vlan_prop_init(dest->pvlan_prop, src->pvlan_prop->vlan_type);
+ }
+ vlan_prop_merge(dest->pvlan_prop, src->pvlan_prop);
+ }
+
+}
+
+/* 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;
+}
+
+int eth_iface_filter_by_name(const struct EthIface *piface, void *name)
+{
+ int comp_ret;
+ comp_ret = strcmp(piface->name, (char *)name);
+ if (comp_ret == 0) {
+ return 1;
+ }
+ return 0;
+}
+
+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;
+
+ case ERR_GENXML_INTERFACE:
+ ret = "Error in generating xml for interfaces.";
+ break;
+
+ case ERR_CALL_LIBVIRT:
+ ret = "Libvirt API returns failure.";
+ break;
+
+ case ERR_DEVICE_EXIST:
+ ret = "Interface already exist.";
+ break;
+
+ case ERR_DEVICE_NOT_EXIST:
+ ret = "Interface do not exist.";
+ break;
+
+ case ERR_NOT_SUPPORT:
+ ret = "Request for interfaces not supported.";
+ 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;
+}
+
+static 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;
+ 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")) {
+ temp = get_attr_value(child2, "name");
+ eth_iface_add_br_prop_attached_iface(piface, temp);
+ CU_FREE(temp);
+ 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;
+
+ 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_OP(3, "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_OP(3, "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:
+ if (conn != NULL) {
+ virConnectClose(conn);
+ }
+ CU_FREE(names);
+ return ret;
+}
+
+int add_host_iface(struct EthIface *piface)
+{
+ struct EthIfacesList list;
+ const char *msg = NULL;
+ char *genxml = NULL;
+ int ret = 0;
+ virConnectPtr conn = NULL;
+ virInterfacePtr iface = NULL;
+
+ /* the list do not need to be uninitilized to keep untouch of piface,
+ because now eth_ifaceslist_add function simply add piface to the
+ list instead of duplication. */
+ eth_ifaceslist_init(&list);
+
+ conn = connect_any();
+ if (conn == NULL) {
+ CU_DEBUG("Connect for network failed.");
+ ret = ERR_CONNECT;
+ goto out;
+ }
+
+ /* Fix me: now virInterfaceLookupByName sometimes return a valid pointer
+ even thought iface with name piface->name is deleted. So here a check
+ for it is skipped. */
+ /*
+ iface = virInterfaceLookupByName(conn, piface->name);
+ if (iface != NULL) {
+ CU_DEBUG("iface %s already exist.", piface->name);
+ ret = ERR_DEVICE_EXIST;
+ goto out;
+ }
+ */
+
+ eth_ifaceslist_add(&list, &piface);
+ msg = EthIfaceListTOXML(&genxml, &list, 0);
+ if (msg != NULL) {
+ CU_DEBUG("Failed in generating xml for iface, msg is %s.", msg);
+ ret = ERR_GENXML_INTERFACE;
+ goto out;
+ }
+
+ CU_DEBUG("Calling InterfaceDefine with XML:\n%s", genxml);
+ iface = virInterfaceDefineXML(conn, genxml, 0);
+ if (iface == NULL) {
+ CU_DEBUG("Failed in create iface, xml is:\n %s.", genxml);
+ ret = ERR_CALL_LIBVIRT;
+ goto out;
+ }
+ ret = 1;
+
+ out:
+ if (conn != NULL) {
+ virConnectClose(conn);
+ }
+ if (iface != NULL) {
+ virInterfaceFree(iface);
+ }
+ CU_FREE(genxml);
+ return ret;
+}
+
+int del_host_iface(struct EthIface *piface)
+{
+ int call_ret = 0;
+ int ret = 0;
+ virConnectPtr conn = NULL;
+ virInterfacePtr iface = NULL;
+
+ conn = connect_any();
+ if (conn == NULL) {
+ CU_DEBUG("Connect for network failed.");
+ ret = ERR_CONNECT;
+ goto out;
+ }
+
+ iface = virInterfaceLookupByName(conn, piface->name);
+ if (iface == NULL) {
+ CU_DEBUG("Failed in find iface %s.", piface->name);
+ ret = ERR_DEVICE_NOT_EXIST;
+ goto out;
+ }
+
+ call_ret = virInterfaceUndefine(iface);
+ if (call_ret != 0) {
+ CU_DEBUG("Failed in undefine iface %s, ret is %d.",
+ piface->name, call_ret);
+ ret = ERR_CALL_LIBVIRT;
+ goto out;
+ }
+ ret = 1;
+
+ out:
+ if (conn != NULL) {
+ virConnectClose(conn);
+ }
+ if (iface != NULL) {
+ virInterfaceFree(iface);
+ }
+ return ret;
+}
+
+/* piface would be changed because of internel merge, in order to save code of
+ struct EthIface duplication */
+int mod_host_iface(struct EthIface *piface)
+{
+ struct EthIfacesList list, list_new;
+ struct EthIface *pprev_iface = NULL;
+ int ret = 0;
+ const char *msg = NULL;
+ char *genxml = NULL;
+ virConnectPtr conn = NULL;
+ virInterfacePtr iface = NULL;
+
+ eth_ifaceslist_init(&list);
+ ret = get_host_ifaces(&list, NULL, NULL);
+ if (ret != 1) {
+ CU_DEBUG("Failed in list host device.");
+ goto out;
+ }
+
+ pprev_iface = eth_ifaceslist_search(&list, piface->name);
+ if (pprev_iface == NULL) {
+ CU_DEBUG("Failed in searching for iface %s",
+ piface->name);
+ ret = ERR_DEVICE_NOT_EXIST;
+ goto out;
+ }
+
+ eth_iface_merge(piface, pprev_iface);
+
+ /* list_new do not need to be uninited */
+ eth_ifaceslist_init(&list_new);
+ eth_ifaceslist_add(&list_new, &piface);
+
+ conn = connect_any();
+ if (conn == NULL) {
+ CU_DEBUG("Connect for network failed.");
+ ret = ERR_CONNECT;
+ goto out;
+ }
+
+ msg = EthIfaceListTOXML(&genxml, &list_new, 0);
+ if (msg != NULL) {
+ CU_DEBUG("Failed in generating xml for iface, msg is %s.", msg);
+ ret = ERR_GENXML_INTERFACE;
+ goto out;
+ }
+
+ CU_DEBUG("Calling InterfaceDefine with XML:\n%s", genxml);
+ iface = virInterfaceDefineXML(conn, genxml, 0);
+ if (iface == NULL) {
+ CU_DEBUG("Failed in create iface, xml is:\n %s.", genxml);
+ ret = ERR_CALL_LIBVIRT;
+ goto out;
+ }
+ ret = 1;
+
+ out:
+ if (conn != NULL) {
+ virConnectClose(conn);
+ }
+ if (iface != NULL) {
+ virInterfaceFree(iface);
+ }
+ CU_FREE(genxml);
+ eth_ifaceslist_uninit(&list);
+ return ret;
+}
+
+/* assuming that pbridge have not added piface in its bridge property,
+ and piface have not set pbridge'name in its attach_bridge property. */
+int connect_two_ifaces(struct EthIface *p1, struct EthIface *p2)
+{
+ struct EthIface *pbridge = NULL, *piface = NULL;
+ struct EthIfacesList list, list_new;
+ struct EthIface *pprev_iface1 = NULL, *pprev_iface2 = NULL,
+ *pexist_port = NULL;
+ int ret = 0;
+ const char* msg = NULL;
+ char *genxml = NULL;
+ virConnectPtr conn = NULL;
+ virInterfacePtr iface = NULL;
+ int i;
+
+ eth_ifaceslist_init(&list);
+ eth_ifaceslist_init(&list_new);
+
+ ret = get_host_ifaces(&list, NULL, NULL);
+ if (ret != 1) {
+ CU_DEBUG("Failed in list host device.");
+ goto out;
+ }
+
+ pprev_iface1 = eth_ifaceslist_search(&list, p1->name);
+ if (pprev_iface1 == NULL) {
+ CU_DEBUG("Failed in searching for iface %s",
+ p1->name);
+ ret = ERR_DEVICE_NOT_EXIST;
+ goto out;
+ }
+
+ pprev_iface2 = eth_ifaceslist_search(&list, p2->name);
+ if (pprev_iface2 == NULL) {
+ CU_DEBUG("Failed in searching for iface %s",
+ p2->name);
+ ret = ERR_DEVICE_NOT_EXIST;
+ goto out;
+ }
+
+ if ((pprev_iface1->eth_type == ETH_TYPE_ETHER_BRIDGE) &&
+ ((pprev_iface2->eth_type == ETH_TYPE_ETHER_VLAN) ||
+ (pprev_iface2->eth_type == ETH_TYPE_ETHER_PHYSICAL))) {
+ pbridge = pprev_iface1;
+ piface = pprev_iface2;
+ }
+ if ((pprev_iface2->eth_type == ETH_TYPE_ETHER_BRIDGE) &&
+ ((pprev_iface1->eth_type == ETH_TYPE_ETHER_VLAN) ||
+ (pprev_iface1->eth_type == ETH_TYPE_ETHER_PHYSICAL))) {
+ pbridge = pprev_iface2;
+ piface = pprev_iface1;
+ }
+
+ if ((pbridge == NULL) || (piface == NULL)) {
+ CU_DEBUG("Cannot connect these devices, one must be bridge.");
+ ret = ERR_NOT_SUPPORT;
+ goto out;
+ }
+
+ if (pbridge->pbr_prop == NULL) {
+ CU_DEBUG("pbridge %s have no bridge props added.", pbridge->name);
+ ret = ERR_NOT_SUPPORT;
+ goto out;
+ }
+
+ /* adding piface to pbridge, list_new do not need uninitlized */
+ eth_iface_add_br_prop_attached_iface(pbridge, piface->name);
+ eth_ifaceslist_add(&list_new, &pbridge);
+ pbridge = list_new.pifaces[0];
+ /* adding existing port to list_new, despite new added port */
+ if (pbridge->pbr_prop->port_num > 1) {
+ for (i = 0;i < (pbridge->pbr_prop->port_num - 1); i++) {
+ pexist_port = eth_ifaceslist_search(&list,
+ pbridge->pbr_prop->port_names[i]);
+ if (pexist_port == NULL) {
+ CU_DEBUG("Fail to find %s.",
pbridge->pbr_prop->port_names[i]);
+ continue;
+ }
+ eth_ifaceslist_add(&list_new, &pexist_port);
+ }
+ }
+ piface->attach_bridge = CU_STRDUP(pbridge->name);
+ eth_ifaceslist_add(&list_new, &piface);
+
+ msg = EthIfaceListTOXML(&genxml, &list_new, 0);
+ if (msg != NULL) {
+ CU_DEBUG("Failed in generating xml for iface, msg is %s.", msg);
+ ret = ERR_GENXML_INTERFACE;
+ goto out;
+ }
+
+ conn = connect_any();
+ if (conn == NULL) {
+ CU_DEBUG("Connect for network failed.");
+ ret = ERR_CONNECT;
+ goto out;
+ }
+
+ CU_DEBUG("Calling InterfaceDefine with XML:\n%s", genxml);
+ iface = virInterfaceDefineXML(conn, genxml, 0);
+ if (iface == NULL) {
+ CU_DEBUG("Failed in create iface, xml is:\n %s.", genxml);
+ ret = ERR_CALL_LIBVIRT;
+ goto out;
+ }
+ ret = 1;
+
+ out:
+ if (conn != NULL) {
+ virConnectClose(conn);
+ }
+ if (iface != NULL) {
+ virInterfaceFree(iface);
+ }
+ eth_ifaceslist_uninit(&list);
+ CU_FREE(genxml);
+ return ret;
+}
+
+int disconnect_two_ifaces(struct EthIface *p1, struct EthIface *p2)
+{
+ struct EthIface *pbridge = NULL, *piface = NULL;
+ struct EthIfacesList list, list_new;
+ struct EthIface *pprev_iface1 = NULL, *pprev_iface2 = NULL;
+ int ret = 0;
+ const char* msg = NULL;
+ char *genxml = NULL;
+ virConnectPtr conn = NULL;
+ virInterfacePtr iface = NULL;
+
+ eth_ifaceslist_init(&list);
+ eth_ifaceslist_init(&list_new);
+
+ ret = get_host_ifaces(&list, NULL, NULL);
+ if (ret != 1) {
+ CU_DEBUG("Failed in list host device.");
+ goto out;
+ }
+
+ pprev_iface1 = eth_ifaceslist_search(&list, p1->name);
+ if (pprev_iface1 == NULL) {
+ CU_DEBUG("Failed in searching for iface %s",
+ p1->name);
+ ret = ERR_DEVICE_NOT_EXIST;
+ goto out;
+ }
+
+ pprev_iface2 = eth_ifaceslist_search(&list, p2->name);
+ if (pprev_iface2 == NULL) {
+ CU_DEBUG("Failed in searching for iface %s",
+ p2->name);
+ ret = ERR_DEVICE_NOT_EXIST;
+ goto out;
+ }
+
+ if ((pprev_iface1->eth_type == ETH_TYPE_ETHER_BRIDGE) &&
+ ((pprev_iface2->eth_type == ETH_TYPE_ETHER_VLAN) ||
+ (pprev_iface2->eth_type == ETH_TYPE_ETHER_PHYSICAL))) {
+ pbridge = pprev_iface1;
+ piface = pprev_iface2;
+ }
+ if ((pprev_iface2->eth_type == ETH_TYPE_ETHER_BRIDGE) &&
+ ((pprev_iface1->eth_type == ETH_TYPE_ETHER_VLAN) ||
+ (pprev_iface1->eth_type == ETH_TYPE_ETHER_PHYSICAL))) {
+ pbridge = pprev_iface2;
+ piface = pprev_iface1;
+ }
+
+ if ((pbridge == NULL) || (piface == NULL)) {
+ CU_DEBUG("Cannot disconnect these devices, one must be bridge.");
+ ret = ERR_NOT_SUPPORT;
+ goto out;
+ }
+
+ /* for libvirt, just remove the attached bridge in piface and redefine it*/
+ CU_FREE(piface->attach_bridge);
+ piface->attach_bridge = NULL;
+ /* for a stand alone piface, libvirt/netcf require it have boot_mode set */
+ if (piface->run_prop.boot_mode == BOOT_MODE_NOT_GOT) {
+ piface->run_prop.boot_mode = BOOT_MODE_NONE;
+ }
+ eth_ifaceslist_add(&list_new, &piface);
+
+ msg = EthIfaceListTOXML(&genxml, &list_new, 0);
+ if (msg != NULL) {
+ CU_DEBUG("Failed in generating xml for iface, msg is %s.", msg);
+ ret = ERR_GENXML_INTERFACE;
+ goto out;
+ }
+
+ conn = connect_any();
+ if (conn == NULL) {
+ CU_DEBUG("Connect for network failed.");
+ ret = ERR_CONNECT;
+ goto out;
+ }
+
+ CU_DEBUG("Calling InterfaceDefine with XML:\n%s", genxml);
+ iface = virInterfaceDefineXML(conn, genxml, 0);
+ if (iface == NULL) {
+ CU_DEBUG("Failed in create iface, xml is:\n %s.", genxml);
+ ret = ERR_CALL_LIBVIRT;
+ goto out;
+ }
+ ret = 1;
+
+ out:
+ if (conn != NULL) {
+ virConnectClose(conn);
+ }
+ if (iface != NULL) {
+ virInterfaceFree(iface);
+ }
+ eth_ifaceslist_uninit(&list);
+ CU_FREE(genxml);
+ return ret;
+}
+
+int change_state_host_iface(struct EthIface *piface, int state)
+{
+ int ret = 0, call_ret = 0;
+ int prev_state = 0;
+ virConnectPtr conn = NULL;
+ virInterfacePtr iface = NULL;
+
+ conn = connect_any();
+ if (conn == NULL) {
+ CU_DEBUG("Connect for network failed.");
+ ret = ERR_CONNECT;
+ goto out;
+ }
+
+ iface = virInterfaceLookupByName(conn, piface->name);
+ if (iface == NULL) {
+ CU_DEBUG("Failed in finding %s.", piface->name);
+ ret = ERR_DEVICE_NOT_EXIST;
+ goto out;
+ }
+
+ prev_state = virInterfaceIsActive(iface);
+ if (prev_state == state) {
+ CU_DEBUG("iface %s already in state %d, request is %d.",
piface->name,
+ prev_state, state);
+ ret = 1;
+ goto out;
+ }
+
+ CU_DEBUG("Calling libvirt API to change state to %d.", state);
+ if (state == 1) {
+ call_ret = virInterfaceCreate(iface, 0);
+ if (call_ret != 0) {
+ CU_DEBUG("Failed to activate %s in libvirt.", piface->name);
+ ret = ERR_CALL_LIBVIRT;
+ goto out;
+ }
+ } else if (state == 0) {
+ call_ret = virInterfaceDestroy(iface, 0);
+ if (call_ret != 0) {
+ CU_DEBUG("Failed to destroy %s in libvirt.", piface->name);
+ ret = ERR_CALL_LIBVIRT;
+ goto out;
+ }
+ }
+
+ ret = 1;
+
+ out:
+ if (conn != NULL) {
+ virConnectClose(conn);
+ }
+ if (iface != NULL) {
+ virInterfaceFree(iface);
+ }
+ 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..c8121a5
--- /dev/null
+++ b/libxkutil/network_parsing.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright IBM Corp. 2012
+ *
+ * Authors:
+ * Wenchao Xia <xiawenc(a)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
+
+#define ERR_CONNECT -1
+#define ERR_LIST_INTERFACE -2
+#define ERR_GENXML_INTERFACE -3
+#define ERR_CALL_LIBVIRT -4
+#define ERR_DEVICE_EXIST -5
+#define ERR_DEVICE_NOT_EXIST -6
+#define ERR_NOT_SUPPORT -7
+
+/* 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; }
+
+/* duplicate char* */
+#define CU_STRDUP(p) (p) == NULL ? NULL : strdup(p);
+
+/* duplicate char* array */
+#define CU_PSTR_ARRAY_DUP(ppdest, dest_num, ppsrc, src_num, iter) do { \
+ (dest_num) = (src_num); \
+ (ppdest) = NULL; \
+ if (((ppsrc) != NULL) && ((src_num) > 0)) { \
+ CU_CALLOC((ppdest), (src_num), sizeof(char *)); \
+ (iter) = 0; \
+ while ((iter) < (src_num)) { \
+ *((ppdest)+(iter)) = CU_STRDUP(*((ppsrc)+(iter))); \
+ (iter)++; \
+ } \
+ } \
+} while (0)
+
+/* merge integer if dest == default */
+#define NUM_MERGE(dest, src, default) do { \
+ if ((dest) == (default)) { \
+ (dest) = (src); \
+ } \
+} while (0)
+
+/* merge char* if dest == NULL */
+#define CHARS_MERGE(dest, src) do { \
+ if (((dest) == NULL) && ((src) != NULL)) { \
+ (dest) = strdup((src)); \
+ } \
+} while (0)
+
+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 {
+ VLANType 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 and it is directly added to list,
+ 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 eth_iface_filter_by_name(const struct EthIface *piface, void *name);
+
+int get_host_ifaces(struct EthIfacesList *plist,
+ eth_iface_filter_func filter_func, void *filter_opaque);
+
+int add_host_iface(struct EthIface *piface);
+int del_host_iface(struct EthIface *piface);
+int mod_host_iface(struct EthIface *piface);
+
+int connect_two_ifaces(struct EthIface *p1, struct EthIface *p2);
+int disconnect_two_ifaces(struct EthIface *p1, struct EthIface *p2);
+
+int change_state_host_iface(struct EthIface *piface, int state);
+
+char *get_host_iface_error_reason(int errno);
+
+#endif
diff --git a/libxkutil/network_parsing_test.c b/libxkutil/network_parsing_test.c
new file mode 100644
index 0000000..4531364
--- /dev/null
+++ b/libxkutil/network_parsing_test.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright IBM Corp. 2012
+ *
+ * Authors:
+ * Wenchao Xia <xiawenc(a)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;
+}
+
+static void check_iface_state(struct EthIface *piface, int expect_state)
+{
+ struct EthIfacesList list;
+ struct EthIface *piface_search;
+
+ eth_ifaceslist_init(&list);
+ get_host_ifaces(&list, NULL, NULL);
+ piface_search = eth_ifaceslist_search(&list, piface->name);
+ if (piface_search != NULL) {
+ if (expect_state == 1) {
+ CU_DEBUG("piface exist, result is:\n");
+ eth_iface_print(piface_search);
+ } else {
+ CU_DEBUG("Error!! piface %s still exist.", piface->name);
+ exit(1);
+ }
+ } else {
+ if (expect_state == 1) {
+ CU_DEBUG("Error!! piface %s do not exist.", piface->name);
+ exit(1);
+ } else {
+ CU_DEBUG("piface %s not exist.", piface->name);
+ }
+ }
+ eth_ifaceslist_uninit(&list);
+}
+
+/* It is a simple test case, autocheck only covers if device exist, other
+ properties need to be checked manually, otherwise more code need to be
+ introduced about property comparation. Output of eth_iface_print() in
+ function check_iface_state() could be used to check the properties. */
+int main(int argc, char **argv)
+{
+ libvirt_cim_init();
+ struct EthIfacesList *plist = NULL;
+ long start_time, end_time;
+ struct EthIface *piface_vlan, *piface_br;
+
+ CU_MALLOC(plist, sizeof(struct EthIfacesList));
+ eth_ifaceslist_init(plist);
+
+ /* test listing the pifaces */
+ 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:\n"
+ "--------------------------------------------------",
+ end_time - start_time);
+ eth_ifaceslist_print(plist);
+ CU_DEBUG("---------------------------------------------");
+ eth_ifaceslist_uninit(plist);
+
+ /* test 802.1.q vlan */
+ CU_MALLOC(piface_vlan, sizeof(struct EthIface));
+ eth_iface_init(piface_vlan);
+ eth_iface_add_vlan_prop(piface_vlan, VLAN_TYPE_802_1_Q);
+
+ piface_vlan->name = CU_STRDUP("eth0.100");
+ piface_vlan->dep_ifname = CU_STRDUP("eth0");
+ piface_vlan->eth_type = ETH_TYPE_ETHER_VLAN;
+ piface_vlan->run_prop.boot_mode = BOOT_MODE_AUTOSTART;
+ piface_vlan->protocol_prop.ipv4_prop.DHCP = 1;
+ piface_vlan->pvlan_prop->vlan_type = VLAN_TYPE_802_1_Q;
+ piface_vlan->pvlan_prop->props.prop_8021q.vlan_id = 100;
+ piface_vlan->pvlan_prop->props.prop_8021q.parent =
CU_STRDUP("eth0");
+ CU_DEBUG("********Adding vlan.");
+ add_host_iface(piface_vlan);
+ check_iface_state(piface_vlan, 1);
+
+ eth_iface_uninit(piface_vlan);
+ eth_iface_init(piface_vlan);
+ piface_vlan->name = CU_STRDUP("eth0.100");
+ piface_vlan->protocol_prop.ipv4_prop.DHCP = 0;
+ piface_vlan->run_prop.boot_mode = BOOT_MODE_NONE;
+ CU_DEBUG("********Modifying vlan.");
+ mod_host_iface(piface_vlan);
+ check_iface_state(piface_vlan, 1);
+
+ /* test bridge */
+ CU_MALLOC(piface_br, sizeof(struct EthIface));
+ eth_iface_init(piface_br);
+ eth_iface_add_br_prop(piface_br);
+ piface_br->name = CU_STRDUP("testbr0");
+ piface_br->eth_type = ETH_TYPE_ETHER_BRIDGE;
+ piface_br->run_prop.boot_mode = BOOT_MODE_AUTOSTART;
+ piface_br->protocol_prop.ipv4_prop.DHCP = 0;
+ piface_br->pbr_prop->STP = 1;
+ piface_br->pbr_prop->delay = 20;
+ CU_DEBUG("********Adding bridge.");
+ add_host_iface(piface_br);
+ check_iface_state(piface_br, 1);
+
+ eth_iface_uninit(piface_br);
+ eth_iface_init(piface_br);
+ eth_iface_add_br_prop(piface_br);
+ piface_br->name = CU_STRDUP("testbr0");
+ piface_br->pbr_prop->STP = 0;
+ piface_br->pbr_prop->delay = 0;
+ CU_DEBUG("********Modifying bridge.");
+ mod_host_iface(piface_br);
+ check_iface_state(piface_br, 1);
+
+ /* test connection */
+ CU_DEBUG("********Connect bridge.");
+ connect_two_ifaces(piface_br, piface_vlan);
+ check_iface_state(piface_br, 1);
+
+ CU_DEBUG("********Disconnect bridge.");
+ disconnect_two_ifaces(piface_br, piface_vlan);
+ check_iface_state(piface_br, 1);
+ check_iface_state(piface_vlan, 1);
+
+ /* test activation */
+ CU_DEBUG("********Activate bridge and vlan");
+ change_state_host_iface(piface_br, 1);
+ change_state_host_iface(piface_vlan, 1);
+ check_iface_state(piface_br, 1);
+ check_iface_state(piface_vlan, 1);
+
+ CU_DEBUG("********Deactivate bridge and vlan");
+ change_state_host_iface(piface_br, 0);
+ change_state_host_iface(piface_vlan, 0);
+ check_iface_state(piface_br, 1);
+ check_iface_state(piface_vlan, 1);
+
+ /* delete them */
+ CU_DEBUG("********Deleting vlan.");
+ del_host_iface(piface_vlan);
+ check_iface_state(piface_vlan, 0);
+ eth_iface_uninit(piface_vlan);
+
+ CU_DEBUG("********Deleting bridge.");
+ del_host_iface(piface_br);
+ check_iface_state(piface_br, 0);
+ eth_iface_uninit(piface_br);
+
+ CU_FREE(piface_br);
+ CU_FREE(piface_vlan);
+ CU_FREE(plist);
+ return 0;
+}
diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c
index 5c16ebe..23d6cc5 100644
--- a/libxkutil/xmlgen.c
+++ b/libxkutil/xmlgen.c
@@ -36,8 +36,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);
@@ -831,7 +829,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