
source code of libnetwor and test program. Calling stack is: main->host_network_API->host_network_implement_OSAPI->(libnl3 libbridge). dll_magic.h is the file used to distinguish whether the symbol is exported or imported. Signed-off-by: Wayne Xia <xiawenc@linux.vnet.ibm.com> --- libnetwork/dll_magic.h | 13 + libnetwork/host_network_API.c | 30 ++ libnetwork/host_network_API.h | 25 ++ libnetwork/host_network_basic.c | 657 ++++++++++++++++++++++++++++ libnetwork/host_network_basic.h | 170 ++++++++ libnetwork/host_network_error.h | 31 ++ libnetwork/host_network_helper.c | 659 +++++++++++++++++++++++++++++ libnetwork/host_network_helper.h | 202 +++++++++ libnetwork/host_network_implement_OSAPI.c | 453 ++++++++++++++++++++ libnetwork/host_network_implement_OSAPI.h | 21 + libnetwork/libnetwork_test.c | 82 ++++ 11 files changed, 2343 insertions(+), 0 deletions(-) create mode 100644 libnetwork/dll_magic.h create mode 100644 libnetwork/host_network_API.c create mode 100644 libnetwork/host_network_API.h create mode 100644 libnetwork/host_network_basic.c create mode 100644 libnetwork/host_network_basic.h create mode 100644 libnetwork/host_network_error.h create mode 100644 libnetwork/host_network_helper.c create mode 100644 libnetwork/host_network_helper.h create mode 100644 libnetwork/host_network_implement_OSAPI.c create mode 100644 libnetwork/host_network_implement_OSAPI.h create mode 100644 libnetwork/libnetwork_test.c diff --git a/libnetwork/dll_magic.h b/libnetwork/dll_magic.h new file mode 100644 index 0000000..36bca83 --- /dev/null +++ b/libnetwork/dll_magic.h @@ -0,0 +1,13 @@ +#ifndef DLL_MAGIC_H +#define DLL_MAGIC_H + + +#if __GNUC__ >= 4 + #ifdef DLL_BUILD + #define DLL_PUBLIC __attribute__ ((visibility ("default"))) + #else + #define DLL_PUBLIC + #endif +#endif + +#endif diff --git a/libnetwork/host_network_API.c b/libnetwork/host_network_API.c new file mode 100644 index 0000000..d2838ad --- /dev/null +++ b/libnetwork/host_network_API.c @@ -0,0 +1,30 @@ +/* + * Copyright IBM Corp. 2011 + * + * 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. + */ + + +#include "host_network_API.h" +#include "host_network_implement_OSAPI.h" +#include "host_network_error.h" + +/* this layer is added to devide the abstraction and implemention, so that + different implemention could be used and switched */ + +int get_host_ifaces(EthIfacesList *plist, + eth_iface_filter_func filter_func, void *filter_opaque) +{ + return get_host_eth_ifaces_osapi(plist, filter_func, filter_opaque); +} + +char *get_host_iface_error_reason(int errno) +{ + return translate_error_no(errno); +} diff --git a/libnetwork/host_network_API.h b/libnetwork/host_network_API.h new file mode 100644 index 0000000..452aa29 --- /dev/null +++ b/libnetwork/host_network_API.h @@ -0,0 +1,25 @@ +/* + * Copyright IBM Corp. 2011 + * + * 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 HOST_NETWORK_API +#define HOST_NETWORK_API + +#include "dll_magic.h" +#include "host_network_basic.h" +#include "host_network_helper.h" + +DLL_PUBLIC int get_host_ifaces(EthIfacesList *plist, + eth_iface_filter_func filter_func, void *filter_opaque); + +DLL_PUBLIC char *get_host_iface_error_reason(int errno); + +#endif diff --git a/libnetwork/host_network_basic.c b/libnetwork/host_network_basic.c new file mode 100644 index 0000000..e227091 --- /dev/null +++ b/libnetwork/host_network_basic.c @@ -0,0 +1,657 @@ +/* + * Copyright IBM Corp. 2011 + * + * 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. + */ + +#include "host_network_basic.h" +#include "host_network_helper.h" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +static void vlan_prop_print(VLAN_Prop *pvlan_prop) +{ + VLAN_Prop_8021q *p_8021q; + char *ingress = NULL, *egress = NULL; + 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); + vlan_8021q_qos_num_to_str(&ingress, &(p_8021q->ingress)); + vlan_8021q_qos_num_to_str(&egress, &(p_8021q->egress)); + CMD_DEBUG(1, "----IEEE802.1.Q: id %d, reorder %d, priority %d, " + "ingress %s, egress %s, parent %s.\n", + p_8021q->vlan_id, p_8021q->reorder_hdr, p_8021q->priv_flag, + ingress, egress, p_8021q->parent); + } + SAFE_FREE(ingress); + SAFE_FREE(egress); +} + +static void br_prop_print(BR_Prop *pbr_prop) +{ + int i = 0; + CMD_DEBUG(1, "--Bridge props: id %s, stp %d, " + "bridge type %d, port_num %d.\n", + pbr_prop->bridge_id, pbr_prop->STP, + pbr_prop->type, 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(EthIface *piface) +{ + CMD_DEBUG(1, "Iface device: name %s.\n" + "--Main Props: parent %s, attach to %s, mac %s, ip %s, ip_mask %s," + " RX %lld, TX %lld, state %d, iface type 0x%x.\n", + piface->name, piface->dep_ifname, piface->attach_bridge, + piface->mac, piface->ipv4_prop.ip, piface->ipv4_prop.ip_mask, + piface->run_prop.rx_bytes, piface->run_prop.tx_bytes, + piface->run_prop.state, 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(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++; + } +} + +void vlan_prop_init(VLAN_Prop *pvlan_prop, int vlan_type) +{ + VLAN_Prop_8021q *p_8021q; + memset(pvlan_prop, 0, sizeof(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->ingress.count = NUM_NOT_GOT; + p_8021q->egress.count = NUM_NOT_GOT; + p_8021q->vlan_id = NUM_NOT_GOT; + p_8021q->reorder_hdr = NUM_NOT_GOT; + p_8021q->priv_flag = NUM_NOT_GOT; + } +} + +void br_prop_init(BR_Prop *pbr_prop) +{ + memset(pbr_prop, 0, sizeof(BR_Prop)); + pbr_prop->STP = NUM_NOT_GOT; + pbr_prop->type = BR_TYPE_NOT_GOT; + pbr_prop->port_num = NUM_NOT_GOT; +} + +void eth_iface_init(EthIface *piface) +{ + memset(piface, 0, sizeof(EthIface)); + piface->eth_type = ETH_TYPE_NOT_GOT; + piface->run_prop.rx_bytes = NUM_NOT_GOT; + piface->run_prop.tx_bytes = NUM_NOT_GOT; + piface->run_prop.state = ETH_STATE_NOT_GOT; + return; +} + +void eth_iface_add_br_prop(EthIface *piface) +{ + SAFE_MALLOC(piface->pbr_prop, sizeof(BR_Prop)); + br_prop_init(piface->pbr_prop); +} + +void eth_iface_add_vlan_prop(EthIface *piface, int vlan_type) +{ + SAFE_MALLOC(piface->pvlan_prop, sizeof(VLAN_Prop)); + vlan_prop_init(piface->pvlan_prop, vlan_type); +} + +void vlan_prop_uninit(VLAN_Prop *pvlan_prop) +{ + 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); + } +} + +void br_prop_uninit(BR_Prop *pbr_prop) +{ + int i; + if (pbr_prop == NULL) { + return; + } + SAFE_FREE(pbr_prop->bridge_id); + 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(EthIface *piface) +{ + if (piface == NULL) { + return; + } + SAFE_FREE(piface->name); + SAFE_FREE(piface->dep_ifname); + SAFE_FREE(piface->attach_bridge); + SAFE_FREE(piface->mac); + SAFE_FREE(piface->ipv4_prop.ip); + SAFE_FREE(piface->ipv4_prop.ip_mask); + 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_ifaces_clear(EthIface **ppifaces, int num) +{ + EthIface **t; + int i; + if (num <= 0) { + return; + } + t = ppifaces; + i = 0; + while (i < num) { + if (*t != NULL) { + eth_iface_uninit(*t); + SAFE_FREE(*t); + } + t++; + i++; + } + return; +} + +void eth_ifaceslist_init(EthIfacesList *plist) +{ + plist->count = 0; +} + +void eth_ifaceslist_uninit(EthIfacesList *plist) +{ + eth_ifaces_clear(plist->pifaces, plist->count); +} + +static void vlan_prop_dup(VLAN_Prop *dest, const VLAN_Prop *src) +{ + VLAN_Prop_8021q *pd_8021q; + const VLAN_Prop_8021q *ps_8021q; + dest->vlan_type = src->vlan_type; + if (dest->vlan_type == VLAN_TYPE_802_1_Q) { + pd_8021q = &(dest->props.prop_8021q); + ps_8021q = &(src->props.prop_8021q); + pd_8021q->vlan_id = ps_8021q->vlan_id; + pd_8021q->reorder_hdr = ps_8021q->reorder_hdr; + pd_8021q->priv_flag = ps_8021q->priv_flag; + pd_8021q->ingress = ps_8021q->ingress; + pd_8021q->egress = ps_8021q->egress; + pd_8021q->parent = SAFE_STRDUP(ps_8021q->parent); + } +} + +static void br_prop_dup(BR_Prop *dest, const BR_Prop *src) +{ + int i; + dest->bridge_id = SAFE_STRDUP(src->bridge_id); + dest->STP = src->STP; + dest->type = src->type; + SAFE_PSTR_ARRAY_DUP(dest->port_names, dest->port_num, + src->port_names, src->port_num, i); +} + +void eth_iface_dup(EthIface *dest, const EthIface *src) +{ + dest->name = SAFE_STRDUP(src->name); + dest->dep_ifname = SAFE_STRDUP(src->dep_ifname); + dest->attach_bridge = SAFE_STRDUP(src->attach_bridge); + dest->mac = SAFE_STRDUP(src->mac); + dest->eth_type = src->eth_type; + dest->ipv4_prop.ip = SAFE_STRDUP(src->ipv4_prop.ip); + dest->ipv4_prop.ip_mask = SAFE_STRDUP(src->ipv4_prop.ip_mask); + dest->run_prop.rx_bytes = src->run_prop.rx_bytes; + dest->run_prop.tx_bytes = src->run_prop.tx_bytes; + dest->run_prop.state = src->run_prop.state; + + if (src->pbr_prop != NULL) { + SAFE_MALLOC(dest->pbr_prop, sizeof(BR_Prop)); + /* doesn't need init it for that it would be copied at once */ + br_prop_dup(dest->pbr_prop, src->pbr_prop); + } else { + dest->pbr_prop = NULL; + } + + if (src->pvlan_prop != NULL) { + SAFE_MALLOC(dest->pvlan_prop, sizeof(VLAN_Prop)); + /* doesn't need init it for that it would be copied at once */ + vlan_prop_dup(dest->pvlan_prop, src->pvlan_prop); + } else { + dest->pvlan_prop = NULL; + } + +} + +int eth_iface_compare(const EthIface *p1, const EthIface *p2) +{ + int ret = 0; + if ((p1->name != NULL) || (p2->name != NULL)) { + if (0 == strcmp(p1->name, p2->name)) { + ret = 1; + } + } + return ret; +} + +static void vlan_prop_merge(VLAN_Prop *pdest, VLAN_Prop *psrc, int style) +{ + 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_NOT_GOT); + NUM_MERGE(pd_8021q->reorder_hdr, ps_8021q->reorder_hdr, NUM_NOT_GOT); + NUM_MERGE(pd_8021q->priv_flag, ps_8021q->priv_flag, NUM_NOT_GOT); + if (pd_8021q->ingress.count == NUM_NOT_GOT) { + pd_8021q->ingress = ps_8021q->ingress; + } + if (pd_8021q->egress.count == NUM_NOT_GOT) { + pd_8021q->egress = ps_8021q->egress; + } + if (style == 0) { + CHARS_MERGE_NORMAL(pd_8021q->parent, ps_8021q->parent); + } else { + CHARS_MERGE_MOVE(pd_8021q->parent, ps_8021q->parent); + } + } +} + +static void br_prop_merge(BR_Prop *pdest, BR_Prop *psrc, int style) +{ + int i; + + if (style == 0) { + CHARS_MERGE_NORMAL(pdest->bridge_id, psrc->bridge_id); + /*merge it when dest have not been set */ + if (pdest->port_names == NULL) { + SAFE_PSTR_ARRAY_DUP(pdest->port_names, pdest->port_num, + psrc->port_names, psrc->port_num, i); + } + } else { + CHARS_MERGE_MOVE(pdest->bridge_id, psrc->bridge_id); + /*merge it when dest have not been set */ + if (pdest->port_names == NULL) { + pdest->port_names = psrc->port_names; + pdest->port_num = psrc->port_num; + psrc->port_names = NULL; + psrc->port_num = NUM_NOT_GOT; + } + } + NUM_MERGE(pdest->STP, psrc->STP, NUM_NOT_GOT); + NUM_MERGE(pdest->type, psrc->type, BR_TYPE_NOT_GOT); +} + +void eth_iface_merge(EthIface *dest, EthIface *src, int style) +{ + if (style == 0) { + CHARS_MERGE_NORMAL(dest->name, src->name); + CHARS_MERGE_NORMAL(dest->dep_ifname, src->dep_ifname); + CHARS_MERGE_NORMAL(dest->attach_bridge, src->attach_bridge); + CHARS_MERGE_NORMAL(dest->mac, src->mac); + CHARS_MERGE_NORMAL(dest->ipv4_prop.ip, src->ipv4_prop.ip); + CHARS_MERGE_NORMAL(dest->ipv4_prop.ip_mask, src->ipv4_prop.ip_mask); + } else { + CHARS_MERGE_MOVE(dest->name, src->name); + CHARS_MERGE_MOVE(dest->dep_ifname, src->dep_ifname); + CHARS_MERGE_MOVE(dest->attach_bridge, src->attach_bridge); + CHARS_MERGE_MOVE(dest->mac, src->mac); + CHARS_MERGE_MOVE(dest->ipv4_prop.ip, src->ipv4_prop.ip); + CHARS_MERGE_MOVE(dest->ipv4_prop.ip_mask, src->ipv4_prop.ip_mask); + } + + /* special case for eth_type*/ + if (dest->eth_type == ETH_TYPE_NOT_GOT) { + dest->eth_type = src->eth_type; + } else { + if ((src->eth_type & ETH_TYPE_ETHER_ANY) && + (dest->eth_type & ETH_TYPE_ETHER_ANY)) { + dest->eth_type |= (src->eth_type & ETH_TYPE_SUB_MASK); + } + } + + NUM_MERGE(dest->run_prop.rx_bytes, src->run_prop.rx_bytes, + NUM_NOT_GOT); + NUM_MERGE(dest->run_prop.tx_bytes, src->run_prop.tx_bytes, + NUM_NOT_GOT); + NUM_MERGE(dest->run_prop.state, src->run_prop.state, ETH_STATE_NOT_GOT); + + if (src->pbr_prop != NULL) { + if (dest->pbr_prop == NULL) { + SAFE_MALLOC(dest->pbr_prop, sizeof(BR_Prop)); + br_prop_init(dest->pbr_prop); + } + br_prop_merge(dest->pbr_prop, src->pbr_prop, style); + } + + if (src->pvlan_prop != NULL) { + if (dest->pvlan_prop == NULL) { + SAFE_MALLOC(dest->pvlan_prop, sizeof(VLAN_Prop)); + vlan_prop_init(dest->pvlan_prop, src->pvlan_prop->vlan_type); + } + vlan_prop_merge(dest->pvlan_prop, src->pvlan_prop, style); + } + +} + +/* compare qos values */ +static int VLAN_Qos_8021q_compare_by_ref(const VLAN_Qos_8021q *pqos, + const VLAN_Qos_8021q *pref) +{ + int ret = 1; + int i, j; + if (pref->count == NUM_NOT_GOT) { + /* do not need to compare*/ + goto out; + } + if ((pref->count < 0) || (pref->count > 8)) { + ret = 0; + goto out; + } + if ((pqos->count < 0) || (pqos->count > 8)) { + ret = 0; + goto out; + } + + i = 0; + while (i < pref->count) { + j = 0; + while (j < pqos->count) { + if (pref->values[i].from == pqos->values[j].from) { + if (pref->values[i].to != pqos->values[j].to) { + ret = 0; + goto out; + } + break; + } + j++; + } + if (j == pqos->count) { + ret = 0; + goto out; + } + i++; + } + + out: + return ret; +} + +static int vlan_prop_filter_by_ref(const VLAN_Prop *pvlan_prop, void *pref) +{ + int compare_result = 1; + VLAN_Prop *ref = (VLAN_Prop *)pref; + char *p1, *p2; + const VLAN_Prop_8021q *pd_8021q; + VLAN_Prop_8021q *pref_8021q; + + NUM_COMPARE_BY_REF(pvlan_prop->vlan_type, ref->vlan_type, + compare_result, VLAN_TYPE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + if (ref->vlan_type == VLAN_TYPE_802_1_Q) { + pd_8021q = &(pvlan_prop->props.prop_8021q); + pref_8021q = &(ref->props.prop_8021q); + + NUM_COMPARE_BY_REF(pd_8021q->vlan_id, pref_8021q->vlan_id, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pd_8021q->reorder_hdr, pref_8021q->reorder_hdr, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pd_8021q->priv_flag, pref_8021q->priv_flag, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + compare_result = VLAN_Qos_8021q_compare_by_ref(&(pd_8021q->ingress), + &(pref_8021q->ingress)); + if (compare_result == 0) { + goto out; + } + + compare_result = VLAN_Qos_8021q_compare_by_ref(&(pd_8021q->egress), + &(pref_8021q->egress)); + if (compare_result == 0) { + goto out; + } + + p1 = pd_8021q->parent; + p2 = pref_8021q->parent; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + } + + out: + return compare_result; + +} + +static int br_prop_filter_by_ref(const BR_Prop *pbr_prop, void *pref) +{ + int compare_result = 1; + BR_Prop *ref = (BR_Prop *)pref; + char *p1, *p2; + + p1 = pbr_prop->bridge_id; + p2 = ref->bridge_id; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pbr_prop->STP, ref->STP, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pbr_prop->type, ref->type, + compare_result, BR_TYPE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pbr_prop->port_num, ref->port_num, + compare_result, NUM_NOT_GOT); + /* skip the comparation of ports it attached, user can define + a special filter for that */ + out: + return compare_result; +} + +int eth_iface_filter_by_ref(const EthIface *piface, void *pref) +{ + int compare_result = 1; + EthIface *ref = (EthIface *)pref; + char *p1, *p2; + + p1 = piface->name; + p2 = ref->name; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->dep_ifname; + p2 = ref->dep_ifname; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->attach_bridge; + p2 = ref->attach_bridge; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->mac; + p2 = ref->mac; + CHARS_COMPARE_CASE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + /* special case for eth_type */ + NUM_COMPARE_BY_REF((piface->eth_type & ETH_TYPE_BASE_MASK), + (ref->eth_type & ETH_TYPE_BASE_MASK), + compare_result, ETH_TYPE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + NUM_COMPARE_BY_REF((piface->eth_type & ETH_TYPE_SUB_MASK), + (ref->eth_type & ETH_TYPE_SUB_MASK), + compare_result, ETH_TYPE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + p1 = piface->ipv4_prop.ip; + p2 = ref->ipv4_prop.ip; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->ipv4_prop.ip_mask; + p2 = ref->ipv4_prop.ip_mask; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(piface->run_prop.state, ref->run_prop.state, + compare_result, ETH_STATE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + if (ref->pbr_prop != NULL) { + if (piface->pbr_prop != NULL) { + compare_result = br_prop_filter_by_ref(piface->pbr_prop, + ref->pbr_prop); + } else { + compare_result = 0; + } + if (compare_result == 0) { + goto out; + } + } + + if (ref->pvlan_prop != NULL) { + if (piface->pvlan_prop != NULL) { + compare_result = vlan_prop_filter_by_ref(piface->pvlan_prop, + ref->pvlan_prop); + + } else { + compare_result = 0; + } + if (compare_result == 0) { + goto out; + } + } + + out: + return compare_result; +} + +int eth_iface_filter_by_refname(const EthIface *piface, void *pref) +{ + int compare_result = 1; + EthIface *ref = (EthIface *)pref; + char *p1, *p2; + + p1 = piface->name; + p2 = ref->name; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + out: + return compare_result; +} + +int eth_iface_filter_vlans(const EthIface *piface, void *nouse) +{ + if (piface->name == NULL) { + return 0; + } + if (NULL == strstr(piface->name, ".")) { + return 0; + } else { + return 1; + } +} + +/* the judgement condition is weak, but I can't find a better way */ +int eth_iface_filter_peths(const EthIface *piface, void *nouse) +{ + if (piface->name == NULL) { + return 0; + } + if (NULL == strstr(piface->name, ".")) { + if (0 == strncmp(piface->name, "eth", 3)) { + return 1; + } else { + return 0; + } + } else { + return 0; + } +} diff --git a/libnetwork/host_network_basic.h b/libnetwork/host_network_basic.h new file mode 100644 index 0000000..bb92453 --- /dev/null +++ b/libnetwork/host_network_basic.h @@ -0,0 +1,170 @@ +/* + * Copyright IBM Corp. 2011 + * + * 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_BASIC_HOST_H +#define NETWORK_BASIC_HOST_H + +#include "dll_magic.h" + +/* value defines */ +#define MAX_IFACE_NUM 4096 + +#define NUM_NOT_GOT -1 + +typedef enum { + ETH_STATE_NOT_GOT = NUM_NOT_GOT, + ETH_STATE_UNKNOWN = 0, + ETH_STATE_DOWN = 1, + ETH_STATE_UP = 2 +} EthState; + +#define ETH_TYPE_BASE_MASK 0xff00 +#define ETH_TYPE_SUB_MASK 0x00ff +typedef enum { + ETH_TYPE_NOT_GOT = 0x0000, + ETH_TYPE_UNKNOWN = 0x0100, + ETH_TYPE_OTHER = 0x0200, + ETH_TYPE_ETHER_ANY = 0x0400, + ETH_TYPE_ETHER_SUB_PHYSICAL = 0x0001, + ETH_TYPE_ETHER_SUB_BRIDGE = 0x0002, + ETH_TYPE_ETHER_SUB_VLAN = 0x0004 +} EthType; + +typedef enum { + BR_TYPE_NOT_GOT = NUM_NOT_GOT, + BR_TYPE_UNKNOWN = 0, + BR_TYPE_SWITCH = 1, + BR_TYPE_NAT = 2 +} BrType; + +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; + +/* structure defines */ +typedef struct IPV4_Prop { + char *ip; + char *ip_mask; +} IPV4_Prop; + +typedef struct BR_Prop { + char *bridge_id; + int STP; + BrType type; + char **port_names; + int port_num; +} BR_Prop; + +typedef struct Run_Prop { + long long rx_bytes; + long long tx_bytes; + EthState state; +} Run_Prop; + +typedef struct VLAN_Qos_8021q_elem { + int from; + int to; +} VLAN_Qos_8021q_elem; + +typedef struct VLAN_Qos_8021q { + VLAN_Qos_8021q_elem values[8]; + int count; +} VLAN_Qos_8021q; + +typedef struct VLAN_Prop_8021q { + int vlan_id; + int reorder_hdr; + int priv_flag; + VLAN_Qos_8021q ingress; + VLAN_Qos_8021q egress; + char *parent; +} VLAN_Prop_8021q; + +/* HP vlan standard, TBD */ +typedef struct VLAN_Prop_8021qbg { + int invalid; +} VLAN_Prop_8021qbg; + +/* Cisco and VMware vlan standard, TBD */ +typedef struct VLAN_Prop_8021qbh { + int invalid; +} VLAN_Prop_8021qbh; + +typedef struct VLAN_Prop { + int vlan_type; + union { + VLAN_Prop_8021q prop_8021q; + VLAN_Prop_8021qbg prop_8021qbg; + VLAN_Prop_8021qbh prop_8021qbh; + } props; +} VLAN_Prop; + +/* EthIface is logical devices include eth ports and bridges */ +typedef struct EthIface { + char *name; + char *dep_ifname; /* parent dev name */ + char *attach_bridge; /* bridge the iface is attached to */ + char *mac; + EthType eth_type; + Run_Prop run_prop; + IPV4_Prop ipv4_prop; + /* optional properties */ + BR_Prop *pbr_prop; + VLAN_Prop *pvlan_prop; +} EthIface; + +typedef struct EthIfacesList { + EthIface *pifaces[MAX_IFACE_NUM]; + int count; +} EthIfacesList; + +typedef int (*eth_iface_filter_func)(const EthIface *piface, void *opaque); + +/* uninit functions are only called when there is resource malloc */ +DLL_PUBLIC void vlan_prop_init(VLAN_Prop *pvlan_prop, int vlan_type); +DLL_PUBLIC void vlan_prop_uninit(VLAN_Prop *pvlan_prop); + +DLL_PUBLIC void br_prop_init(BR_Prop *pbr_prop); +DLL_PUBLIC void br_prop_uninit(BR_Prop *pbr_prop); + +DLL_PUBLIC void eth_iface_print(EthIface *piface); +DLL_PUBLIC void eth_iface_init(EthIface *piface); +DLL_PUBLIC void eth_iface_add_br_prop(EthIface *piface); +DLL_PUBLIC void eth_iface_add_vlan_prop(EthIface *piface, int vlan_type); +DLL_PUBLIC void eth_iface_uninit(EthIface *piface); +DLL_PUBLIC void eth_ifaces_clear(EthIface **ppifaces, int num); + +DLL_PUBLIC void eth_ifaceslist_init(EthIfacesList *plist); +DLL_PUBLIC void eth_ifaceslist_uninit(EthIfacesList *plist); +DLL_PUBLIC void eth_ifaceslist_print(EthIfacesList *plist); + +/* this function assume dest have been uninited if it was used before*/ +DLL_PUBLIC void eth_iface_dup(EthIface *dest, const EthIface *src); + +/* see if it is refered to the same device */ +DLL_PUBLIC int eth_iface_compare(const EthIface *p1, const EthIface *p2); + +/* merge the properties that dest do not have value set, if style is set to 1, + the char* properties was moved instead of copy, safely reduce the memory + fragments, but src is modified. */ +DLL_PUBLIC void eth_iface_merge(EthIface *dest, EthIface *src, int style); + +DLL_PUBLIC int eth_iface_filter_by_ref(const EthIface *piface, void *pref); +DLL_PUBLIC int eth_iface_filter_by_refname(const EthIface *piface, void *pref); +DLL_PUBLIC int eth_iface_filter_vlans(const EthIface *piface, void *nouse); +DLL_PUBLIC int eth_iface_filter_peths(const EthIface *piface, void *nouse); + + +#endif diff --git a/libnetwork/host_network_error.h b/libnetwork/host_network_error.h new file mode 100644 index 0000000..5c38dde --- /dev/null +++ b/libnetwork/host_network_error.h @@ -0,0 +1,31 @@ +#ifndef HOST_NETWORK_ERROR_H +#define HOST_NETWORK_ERROR_H + +#define ERR_REQUEST_NOT_SUPPORT -1 + +#define ERR_COMMAND_NOT_SET -11 +#define ERR_COMMAND_PIPE_ERR -12 +#define ERR_COMMAND_NOT_SUPPORT -13 +#define ERR_COMMAND_NO_PERMISSION -14 +#define ERR_COMMAND_NO_READY -15 +#define ERR_COMMAND_PARAMETER_WRONG -16 +#define ERR_COMMAND_EXECUTION -17 + +#define ERR_LIBNETLINK -80 +#define ERR_LIBBR -90 + +#define ERR_DEVICE_EXCEED_MAXNUM -100 +#define ERR_DEVICE_EXIST -101 +#define ERR_DEVICE_NOT_EXIST -102 +#define ERR_DEVICE_ALREADY_DONE -103 +#define ERR_DEVICE_CONNECT_OTHER -104 + +#define ERR_FILE_OP_FAIL -125 +#define ERR_FILE_EMPTY -126 +#define ERR_FILE_TOO_LARGE -127 +#define ERR_FILE_CONT_TOO_LARGE -128 +#define ERR_FILE_LOCK_FAIL -129 + +#define ERR_PERSIST_NOT_REDHAT -200 + +#endif diff --git a/libnetwork/host_network_helper.c b/libnetwork/host_network_helper.c new file mode 100644 index 0000000..dc9f775 --- /dev/null +++ b/libnetwork/host_network_helper.c @@ -0,0 +1,659 @@ +/* + * Copyright IBM Corp. 2011 + * + * 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. + */ + + + +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> + +#include "host_network_helper.h" +#include "host_network_error.h" + +#define CONFIGURE_FILE_MAX_SIZE 2048 + +#define PIPE_CMD_SUFFIX " 2>&1" + +static int g_linux_version = LINUX_UNKNOWN; + +static int compare_qos_8021q(const void *p1, const void *p2) +{ + const VLAN_Qos_8021q_elem *qos1 = (VLAN_Qos_8021q_elem *)p1; + const VLAN_Qos_8021q_elem *qos2 = (VLAN_Qos_8021q_elem *)p2; + int ret = 0; + if ((qos1->from) > (qos2->from)) { + ret = 1; + } + return ret; +} + +/* it need to be checked see whether these are the conditions */ +int vlan_8021q_qos_check_valid(VLAN_Qos_8021q *pqos) +{ + int ret = 1; + int i = 0; + int last_num = -1; + if ((pqos->count < 0) || (pqos->count > 8)) { + ret = 0; + goto out; + } else if (pqos->count == 0) { + goto out; + } + qsort((void *)pqos->values, pqos->count, sizeof(VLAN_Qos_8021q_elem), + compare_qos_8021q); + + while (i < pqos->count) { + if (pqos->values[i].from == last_num) { + CU_DEBUG("error: vlan 802.1.q qos setting have same <from> values: " + "last is %d, new is %d", last_num, pqos->values[i].from); + ret = 0; + goto out; + } + last_num = pqos->values[i].from; + if ((pqos->values[i].from < 0) || (pqos->values[i].from >= 8)) { + CU_DEBUG("error: vlan 802.1.q qos setting have outbound value: " + "from is %d.", pqos->values[i].from); + ret = 0; + goto out; + } + if ((pqos->values[i].to < 0) || (pqos->values[i].to >= 8)) { + CU_DEBUG("error: vlan 802.1.q qos setting have outbound value: " + "to is %d.", pqos->values[i].to); + ret = 0; + goto out; + } + i++; + } + + out: + return ret; +} + +int vlan_8021q_qos_str_to_num(VLAN_Qos_8021q *pqos, const char* str) +{ + int ret = 1; + char *str_line = NULL; + char *temp; + char *saveptr = NULL; + char *invalptr1, *invalptr2; + int qos_num1, qos_num2; + VLAN_Qos_8021q qos; + + if (str == NULL) { + ret = 0; + goto out; + } + if (str[0] == '\0') { + ret = 1; + pqos->count = 0; + CU_DEBUG("empty vlan 802.1.q qos string found."); + goto out; + } + str_line = SAFE_STRDUP(str); + qos.count = 0; + + temp = strtok_r(str_line, " ", &saveptr); + while (temp != NULL) { + qos_num1 = strtol(temp, &invalptr1, 10); + if (temp == invalptr1) { + ret = 0; + goto out; + } + if (*invalptr1 != ':') { + ret = 0; + goto out; + } + invalptr1++; + qos_num2 = strtol(invalptr1, &invalptr2, 10); + if (invalptr1 == invalptr2) { + ret = 0; + goto out; + } + if (*invalptr2 != '\0') { + ret = 0; + goto out; + } + if (qos.count >= 8) { + ret = 0; + CU_DEBUG("too many settings found in vlan 802.1.q qos string [%s]", + str); + goto out; + } + qos.values[qos.count].from = qos_num1; + qos.values[qos.count].to = qos_num2; + qos.count++; + temp = strtok_r(NULL, " ", &saveptr); + } + ret = vlan_8021q_qos_check_valid(&qos); + if (ret == 1) { + *pqos = qos; + } + + out: + if (ret != 1) { + CU_DEBUG("vlan 802.1.q qos string [%s] is invalid.", str); + } + SAFE_FREE(str_line); + return ret; +} + +int vlan_8021q_qos_num_to_str(char **str, const VLAN_Qos_8021q *pqos) +{ + char temp[16]; + int i; + VLAN_Qos_8021q qos = *pqos; + int ret = vlan_8021q_qos_check_valid(&qos); + if (ret != 1) { + goto out; + } + SAFE_MALLOC(*str, 64); + *str[0] = '\0'; + if (qos.count == 0) { + goto out; + } + i = 0; + snprintf(temp, sizeof(temp), "%d:%d", + qos.values[i].from, qos.values[i].to); + strcat(*str, temp); + i++; + while (i < qos.count) { + strcat(*str, " "); + snprintf(temp, sizeof(temp), "%d:%d", + qos.values[i].from, qos.values[i].to); + strcat(*str, temp); + i++; + } + + out: + return ret; +} + +int netmask_easy_to_inaddr(struct in_addr *paddr, const char* pmask) +{ + long mask_one_num = -1; + unsigned char *p; + int bitnum; + + mask_one_num = strtol(pmask, NULL, 10); + if ((mask_one_num < 0) || (mask_one_num > 32)) { + return 0; + } + + /* use network byte order */ + p = (unsigned char *)&paddr->s_addr; + memset(p, 0, 4); + while (mask_one_num > 8) { + *(p++) = 255; + mask_one_num -= 8; + } + bitnum = 7; + while (mask_one_num > 0) { + *p = *p + (1<<bitnum); + mask_one_num--; + bitnum--; + } + return 1; +} + +char *strtok_onetime(const char *str, const char *delim) +{ + char *t = strstr(str, delim); + char *ret_char; + int len; + if (t == NULL) { + return NULL; + } + len = t - str; + if (len <= 0) { + return NULL; + } + SAFE_MALLOC(ret_char, len+1); + strncpy(ret_char, str, len); + ret_char[len] = '\0'; + + return ret_char; +} + +char *combine_file_name(const char *prefix, const char *name) +{ + char *ret = NULL; + int size; + size = strlen(prefix) + strlen(name) + 1; + SAFE_CALLOC(ret, size, sizeof(char)); + snprintf(ret, size, "%s%s", prefix, name); + return ret; +} + +/* return the whole content length that need update. The data length keep + unchanged in the head part is returned in *unchanged_len which could be + used to avoid write whole data later. + requriement: cont must contain end character, prefix must be not NULL */ +static int replace_prop_str(char *cont, const int maxsize, const char *prefix, + const char *prop, int *unchanged_len) +{ + int target_len, origin_len; + int cont_len; + int valid_len = 0; + int prefix_len, prop_len = 0; + char *endchar1 = "\n"; + char *pprop_start, *pprop_end; + int head_len; + + cont_len = strlen(cont); + head_len = cont_len; + prefix_len = strlen(prefix); + if ((prop == NULL) || (*prop == '\0')) { + /* want the property removed */ + target_len = 0; + } else { + /* want the property changed */ + prop_len = strlen(prop); + target_len = prefix_len + prop_len; + } + + pprop_start = strstr(cont, prefix); + if (pprop_start == NULL) { + /* the content do not exist in original contents */ + if (target_len > 0) { + /* add the property */ + if ((cont_len + target_len) >= maxsize) { + CU_DEBUG("buffer is too small for the operation."); + valid_len = -1; + goto out; + } + strcat(cont, prefix); + strcat(cont, prop); + valid_len = cont_len + target_len; + } else { + /* remove the property, but it do not exist, so skip */ + } + } else { + /* the content exist in original contents */ + /* locate the end of the property */ + pprop_end = strstr(pprop_start, endchar1); + if (pprop_end == NULL) { + /* last line */ + origin_len = strlen(pprop_start); + pprop_end = cont+cont_len; + } else { + origin_len = pprop_end - pprop_start; + } + if (target_len > 0) { + /* change the property */ + /* check the bound */ + if ((cont_len + target_len - origin_len) >= maxsize) { + CU_DEBUG("buffer is too small for the operation."); + valid_len = -1; + goto out; + } + /* move contents in the tail */ + memmove(pprop_end+target_len-origin_len, pprop_end, + cont+cont_len+1-pprop_end); + /* copy the content of the new string */ + memcpy(pprop_start+prefix_len, prop, prop_len); + head_len = pprop_start - cont + prefix_len; + } else { + /* remove the property */ + /* move contents in the tail to replace original string*/ + memmove(pprop_end+target_len-origin_len, pprop_end, + cont+cont_len+1-pprop_end); + head_len = pprop_start - cont; + } + valid_len = cont_len + target_len - origin_len; + } + + out: + if (unchanged_len != NULL) { + *unchanged_len = head_len; + } + return valid_len; +} + +int configure_file_replace_attr(const char *path, const char *prefix, + const char *prop) +{ + int fd = -1; + int fop_ret; + struct stat s; + struct flock lock; + int lock_state = -1; + char *cont = NULL; + char *pbuff; + int write_len; + int cont_len_update; + int cont_len_unchanged; + int ret = 0; + + if ((prefix == NULL) || (*prefix == '\0')) { + CU_DEBUG("no prefix for property set, could not replace the content."); + goto out; + } + + fd = open(path, O_RDWR, 0644); + if (fd < 0) { + CU_DEBUG("Unable to open [%s], it does not exist.", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + + lock.l_type = F_WRLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + lock_state = fcntl(fd, F_SETLK, &lock); + if (lock_state < 0) { + CU_DEBUG("Failed to lock file [%s], it may be locked by other.", path); + ret = ERR_FILE_LOCK_FAIL; + goto out; + } + + fstat(fd, &s); + if (s.st_size == 0) { + CU_DEBUG("file [%s] is empty, will not replace attr for it.", path); + ret = ERR_FILE_EMPTY; + goto out; + } else if (s.st_size >= CONFIGURE_FILE_MAX_SIZE) { + CU_DEBUG("file [%s] is too large, " + "it have %lld bytes, will not read it.", + path, (long long)s.st_size); + ret = ERR_FILE_TOO_LARGE; + goto out; + } + + SAFE_MALLOC(cont, CONFIGURE_FILE_MAX_SIZE); + lseek(fd, 0, SEEK_SET); + fop_ret = read(fd, cont, s.st_size); + cont[s.st_size] = '\0'; + cont_len_update = replace_prop_str(cont, CONFIGURE_FILE_MAX_SIZE, + prefix, prop, &cont_len_unchanged); + if (cont_len_update < 0) { + CU_DEBUG("file [%s] is too big to expand it with [%s%s].", + path, prefix, prop); + ret = ERR_FILE_TOO_LARGE; + goto out; + } else if (cont_len_update == 0) { + CU_DEBUG("the contents was not changed, do not need update it"); + ret = 1; + goto out; + } else { + if (ftruncate(fd, cont_len_unchanged) != 0) { + CU_DEBUG("file [%s] Unable to truncate it", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + write_len = cont_len_update-cont_len_unchanged; + if (write_len > 0) { + lseek(fd, cont_len_unchanged, SEEK_SET); + CU_DEBUG("writing file [%s] for %d bytes with offset %d," + " cont is :\n%s\n", + path, write_len, cont_len_unchanged, cont); + pbuff = cont+cont_len_unchanged; + fop_ret = write(fd, pbuff, write_len); + } + } + ret = 1; + + out: + if (fd >= 0) { + if (lock_state >= 0) { + lock.l_type = F_UNLCK; + fcntl(fd, F_SETLK, &lock); + } + close(fd); + } + SAFE_FREE(cont); + return ret; +} + +int configure_file_update(const char *path, const char *cont) +{ + int fd = -1; + int fop_ret; + struct flock lock; + int lock_state = -1; + int write_len; + int ret = 0; + + fd = open(path, O_RDWR|O_CREAT, 0644); + if (fd < 0) { + CU_DEBUG("Unable to open [%s], it does not exist.", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + + lock.l_type = F_WRLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + lock_state = fcntl(fd, F_SETLK, &lock); + if (lock_state < 0) { + CU_DEBUG("Failed to lock file [%s], it may be locked by other.", path); + ret = ERR_FILE_LOCK_FAIL; + goto out; + } + + if (ftruncate(fd, 0) != 0) { + CU_DEBUG("file [%s] Unable to truncate it", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + + write_len = strlen(cont); + if (write_len > 0) { + lseek(fd, 0, SEEK_SET); + CU_DEBUG("writing file [%s] for %d bytes with offset 0," + " cont is :\n%s\n", + path, write_len, cont); + fop_ret = write(fd, cont, write_len); + } + ret = 1; + + out: + if (fd >= 0) { + if (lock_state >= 0) { + lock.l_type = F_UNLCK; + fcntl(fd, F_SETLK, &lock); + } + close(fd); + } + return ret; +} + +int configure_file_remove(const char *path) +{ + int fd_ret; + int ret = 0; + if (access(path, F_OK) == 0) { + CU_DEBUG("Deleting %s.", path); + fd_ret = remove(path); + if (fd_ret != 0) { + CU_DEBUG("failed to remove %s.", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + } + + ret = 1; + out: + return ret; +} + +FILE *pipe_excute_command_type_read(char *cmd, const int buf_size, + const char *type, int *errno) +{ + FILE *stream = NULL; + char *suffix = PIPE_CMD_SUFFIX; + if ((strlen(cmd) + strlen(suffix)) >= buf_size) { + CU_DEBUG("cmd [%s] is too long to append the suffix", cmd); + *errno = ERR_COMMAND_NO_READY; + goto out; + } + strcat(cmd, suffix); + CU_DEBUG("excuting readonly cmd [%s].", cmd); + stream = popen(cmd, type); + if (stream == NULL) { + CU_DEBUG("Failed to open pipe to run command"); + *errno = ERR_COMMAND_PIPE_ERR; + } + +out: + return stream; +} + +FILE *pipe_excute_command_type_write(char *cmd, const int buf_size, + const char *type, int *errno) +{ + FILE *stream = NULL; + char *suffix = PIPE_CMD_SUFFIX; + if ((strlen(cmd) + strlen(suffix)) >= buf_size) { + CU_DEBUG("cmd [%s] is too long to append the suffix", cmd); + *errno = ERR_COMMAND_NO_READY; + goto out; + } + strcat(cmd, suffix); + CU_DEBUG("excuting system modification cmd [%s].", cmd); + stream = popen(cmd, type); + if (stream == NULL) { + CU_DEBUG("Failed to open pipe to run command"); + *errno = ERR_COMMAND_PIPE_ERR; + } + usleep(10000); + +out: + return stream; +} + +int get_host_linux_version(void) +{ + FILE *stream = NULL; + char cmd[64]; + char buff[256]; + int linenum; + int errno; + + if (g_linux_version != LINUX_UNKNOWN) { + goto out; + } + + cmd[0] = '\0'; + strcat(cmd, "lsb_release -a"); + stream = pipe_excute_command_type_read(cmd, sizeof(cmd), "r", &errno); + if (stream == NULL) { + goto out; + } + + linenum = -1; + g_linux_version = LINUX_OTHER; + while (fgets(buff, 256, stream) != NULL) { + linenum++; + if (linenum == 0) { + if (NULL == strstr(buff, "LSB")) { + CU_DEBUG("ERR: unable to get linux distribution version."); + g_linux_version = LINUX_FAIL_TO_GET; + } + } + if ((NULL != strstr(buff, "Red Hat")) || + (NULL != strstr(buff, "RedHat"))) { + g_linux_version = LINUX_REDHAT; + break; + } + } + + out: + if (stream != NULL) { + pclose(stream); + } + return g_linux_version; +} + +char *translate_error_no(int errno) +{ + char *ret = NULL; + switch (errno) { + case ERR_REQUEST_NOT_SUPPORT: + ret = "request is not supported now"; + break; + + case ERR_COMMAND_NOT_SET: + ret = "command is not set."; + break; + case ERR_COMMAND_PIPE_ERR: + ret = "failed in creating pipe to execute the command."; + break; + case ERR_COMMAND_NOT_SUPPORT: + ret = "command is not found, check u environment."; + break; + case ERR_COMMAND_NO_PERMISSION: + ret = "not enough authority to execute the command."; + break; + case ERR_COMMAND_NO_READY: + ret = "failed to build up the command line, check your input, " + "maybe it is too long."; + break; + case ERR_COMMAND_PARAMETER_WRONG: + ret = "got invalid paramenter, check your input."; + break; + case ERR_COMMAND_EXECUTION: + ret = "error happened in the excution of command."; + break; + + case ERR_DEVICE_EXCEED_MAXNUM: + ret = "too many devices found or set, check the environment."; + break; + case ERR_DEVICE_EXIST: + ret = "device already exist, can not execute the command."; + break; + case ERR_DEVICE_NOT_EXIST: + ret = "device do not exist, can not execute the command."; + break; + case ERR_DEVICE_ALREADY_DONE: + ret = "the operation you want have been done before, " + "will not do it again."; + break; + case ERR_DEVICE_CONNECT_OTHER: + ret = "the device you want to connect have been connect to another" + " device, can't change it directly."; + break; + + case ERR_FILE_OP_FAIL: + ret = "failed in accessing the file."; + break; + case ERR_FILE_EMPTY: + ret = "the file it want is empty."; + break; + case ERR_FILE_TOO_LARGE: + ret = "the file it want is too large."; + break; + case ERR_FILE_CONT_TOO_LARGE: + ret = "the content it want to combine to file is too large."; + break; + case ERR_FILE_LOCK_FAIL: + ret = "failed in locking the file, " + "check if other process is using it."; + break; + + case ERR_PERSIST_NOT_REDHAT: + ret = "host is not a RedHat distribution, can't persist the " + "configuration, it would not take effect after host is " + "rebooted. Other version would be supported in the future. " + "If you are sure host is RedHat, make sure command " + "<lsb_release -a> could work."; + break; + + default: + ret = "internal error."; + break; + } + return ret; +} diff --git a/libnetwork/host_network_helper.h b/libnetwork/host_network_helper.h new file mode 100644 index 0000000..4170366 --- /dev/null +++ b/libnetwork/host_network_helper.h @@ -0,0 +1,202 @@ +/* + * Copyright IBM Corp. 2011 + * + * 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 HOST_NETWORK_HELPER_H +#define HOST_NETWORK_HELPER_H + +#include <stdio.h> +#include <stdlib.h> +#include <arpa/inet.h> + +#include "dll_magic.h" +#include "host_network_basic.h" + +#ifdef TESTLIB +#include "TestDefines.h" +#else +#include <libcmpiutil/libcmpiutil.h> +#endif + +#define LINUX_FAIL_TO_GET -2 +#define LINUX_UNKNOWN -1 +#define LINUX_OTHER 0 +#define LINUX_REDHAT 1 + +#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; } + + +/* Macro used to compare two char*, it would skip if ref is NULL. It would + only set the result when src != ref, user need to set the result to 1 by + default before use the macro. If not set, the it could be used to do + check multi times in "one fail all die" mode. Empty lines is the place + where result should be set to 1. */ +#define CHARS_COMPARE_BY_REF(src, ref, result) do { \ + if ((ref) == NULL) { \ + ; \ + } else { \ + if ((src) == NULL) { \ + (result) = 0; \ + } else { \ + if (0 == strcmp((src), (ref))) { \ + ; \ + } else { \ + (result) = 0; \ + } \ + } \ + } \ +} while (0) + +/* ignore case version */ +#define CHARS_COMPARE_CASE_BY_REF(src, ref, result) do { \ + if ((ref) == NULL) { \ + ; \ + } else { \ + if ((src) == NULL) { \ + (result) = 0; \ + } else { \ + if (0 == strcasecmp((src), (ref))) { \ + ; \ + } else { \ + (result) = 0; \ + } \ + } \ + } \ +} while (0) + +/* compare the value if ref != default */ +#define NUM_COMPARE_BY_REF(src, ref, result, default) do { \ + if ((ref) == (default)) { \ + ; \ + } else { \ + if ((src) == (ref)) { \ + ; \ + } else { \ + result = 0; \ + } \ + } \ +} while (0) + +/* merge the char* string to dest, only when dest == NULL */ +#define CHARS_MERGE_NORMAL(dest, src) do { \ + if (((dest) == NULL) && ((src) != NULL)) { \ + (dest) = strdup((src)); \ + } \ +} while (0) + +/* merge the char* string to dest, only when dest == NULL, + pointer is moved instead of strdup */ +#define CHARS_MERGE_MOVE(dest, src) do { \ + if (((dest) == NULL) && ((src) != NULL)) { \ + (dest) = (src); \ + (src) = NULL; \ + } \ +} while (0) + +/* merge the value, only when dest == default */ +#define NUM_MERGE(dest, src, default) do { \ + if ((dest) == (default)) { \ + (dest) = (src); \ + } \ +} while (0) + +/* this macro may cause "p" to be excuted twice if it is a function */ +#define SAFE_STRDUP(p) (p) == NULL ? NULL : strdup(p); + +/* this macro make sure "src" to be excuted once if it is function, so it is + safe for functions that have state logged, such as "strtok" */ +#define SAFE_STRDUP_WITH_FUNC(dest, src, iter) do { \ + (iter) = (src); \ + if ((iter) == NULL) { \ + (dest) = NULL; \ + } else { \ + (dest) = strdup((iter)); \ + } \ +} while (0) + +/* array version of SAFE_STRDUP, dest and src are char**. */ +#define SAFE_PSTR_ARRAY_DUP(ppdest, dest_num, ppsrc, src_num, iter) do { \ + (dest_num) = (src_num); \ + (ppdest) = NULL; \ + if (((ppsrc) != NULL) && ((src_num) > 0)) { \ + SAFE_CALLOC((ppdest), (src_num), sizeof(char *)); \ + (iter) = 0; \ + while ((iter) < (src_num)) { \ + *((ppdest)+(iter)) = SAFE_STRDUP(*((ppsrc)+(iter))); \ + (iter)++; \ + } \ + } \ +} while (0) + +/* functions */ +/* this function convert ip mask "24" in "192.1.0.9/24" to real mask num as + 255.255.255.0 */ +int netmask_easy_to_inaddr(struct in_addr *paddr, const char *pmask); + +/* this function would sort the pqos and check its values. */ +int vlan_8021q_qos_check_valid(VLAN_Qos_8021q *pqos); + +/* converting qos string of 802.1.Q, it should be as "0:0 1:0 2:0" */ +DLL_PUBLIC int vlan_8021q_qos_str_to_num(VLAN_Qos_8021q *pqos, const char *str); +DLL_PUBLIC int vlan_8021q_qos_num_to_str(char **str, const VLAN_Qos_8021q *pqos); + +/* following functions would return FILE popened, so it need pclose later, + cmd would be appended so it must be writable. */ +FILE *pipe_excute_command_type_read(char *cmd, const int buf_size, + const char *type, int *errno); +FILE *pipe_excute_command_type_write(char *cmd, const int buf_size, + const char *type, int *errno); + +/* following functions would return string by malloc, so it need free later */ +char *strtok_onetime(const char *str, const char *delim); +char *combine_file_name(const char *prefix, const char *name); + +/* write the configuration file */ +int configure_file_update(const char *path, const char *cont); +/* remove the configuration file */ +int configure_file_remove(const char *path); +/* replace one attribute, the file have format with one line for one propety */ +int configure_file_replace_attr(const char *path, const char *prefix, + const char *prop); + +/* check host linux version */ +int get_host_linux_version(void); + +/* err message number to char* */ +char *translate_error_no(int errno); + +#endif diff --git a/libnetwork/host_network_implement_OSAPI.c b/libnetwork/host_network_implement_OSAPI.c new file mode 100644 index 0000000..24b382e --- /dev/null +++ b/libnetwork/host_network_implement_OSAPI.c @@ -0,0 +1,453 @@ +/* + * Copyright IBM Corp. 2011 + * + * 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. + * + */ + +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <net/if_arp.h> +#include <linux/if_vlan.h> + +#include <netlink/netlink.h> +#include <netlink/socket.h> +#include <netlink/list.h> +#include <netlink/object.h> +#include <netlink/object-api.h> +#include <netlink/route/link.h> +#include <netlink/route/link/vlan.h> + +#include "libbridge/libbridge.h" + +#include "host_network_implement_OSAPI.h" +#include "host_network_helper.h" +#include "host_network_error.h" + +/* macro defines */ +#define LN_PRINT_LEVEL 3 + +struct nl_add2list_param { + EthIfacesList *plist; + struct nl_cache *cache; +} ; + +/* the bridge seems have 0 value when it is up , so adjust the value, + and found out which are physical cards */ +static int host_iface_adjust(EthIface *piface) +{ + if ((piface->eth_type & ETH_TYPE_ETHER_ANY) && + (piface->eth_type & ETH_TYPE_ETHER_SUB_BRIDGE)) { + if (piface->run_prop.state == ETH_STATE_UNKNOWN) { + piface->run_prop.state = ETH_STATE_UP; + } + } + if (1 == eth_iface_filter_peths(piface, NULL)) { + piface->eth_type |= (ETH_TYPE_ETHER_ANY | ETH_TYPE_ETHER_SUB_PHYSICAL); + } + return 1; +} + +static void find_iface_attached_bridge(EthIfacesList *peth_list, EthIface *pbr) +{ + int i, j; + char *name_on_br, *name_iface; + if (pbr->pbr_prop == NULL) { + return; + } + i = 0; + while (i < pbr->pbr_prop->port_num) { + name_on_br = pbr->pbr_prop->port_names[i]; + j = 0; + while (j < peth_list->count) { + name_iface = peth_list->pifaces[j]->name; + if (0 == strcmp(name_on_br, name_iface)) { + if (peth_list->pifaces[j]->attach_bridge == NULL) { + peth_list->pifaces[j]->attach_bridge = + SAFE_STRDUP(pbr->name); + } + break; + } + j++; + } + i++; + } +} + +/* assuming that one peth would be attached to at most 1 bridge */ +static void merge_eth_list_for_bridge(EthIfacesList *peth_list, + EthIfacesList *pbr_list, + int flag) +{ + int i, j; + i = 0; + while (i < pbr_list->count) { + find_iface_attached_bridge(peth_list, pbr_list->pifaces[i]); + j = 0; + while (j < peth_list->count) { + if (1 == eth_iface_compare(peth_list->pifaces[j], + pbr_list->pifaces[i])) { + /* found the matched device, merge them */ + eth_iface_merge(peth_list->pifaces[j], + pbr_list->pifaces[i], flag); + break; + } + j++; + } + i++; + } + return; +} + +static int br_addports_func(const char *brname, const char *port, void *opaque) +{ + BR_Prop *pbr; + int ret = 0; + + pbr = (BR_Prop *)opaque; + + if (port != NULL) { + /* adding the port */ + if (pbr->port_names == NULL) { + SAFE_CALLOC(pbr->port_names, + MAX_IFACE_NUM, sizeof(char *)); + pbr->port_num = 0; + } + if (pbr->port_num >= MAX_IFACE_NUM) { + CU_DEBUG("bridge [%s] have too much eth attached!", brname); + ret = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + + pbr->port_names[pbr->port_num] = SAFE_STRDUP(port); + pbr->port_num++; + } + + out: + return ret; +} + +static int br_add2list_func(const char *name, void *opaque) +{ + int count; + EthIfacesList *plist; + EthIface tcard; + BR_Prop *pbr; + struct bridge_info binfo; + int ret = 0; + + plist = (EthIfacesList *)opaque; + eth_iface_init(&tcard); + + tcard.eth_type = ETH_TYPE_ETHER_ANY | ETH_TYPE_ETHER_SUB_BRIDGE; + tcard.name = SAFE_STRDUP(name); + + SAFE_MALLOC(pbr, sizeof(BR_Prop)); + br_prop_init(pbr); + tcard.pbr_prop = pbr; + + if (0 == br_get_bridge_info(name, &binfo)) { + pbr->STP = binfo.stp_enabled; + } else { + CU_DEBUG("failed to get bridge_info for %s.", name); + } + count = br_foreach_port(name, br_addports_func, pbr); + + /* put result to list */ + if (plist->count >= MAX_IFACE_NUM) { + CU_DEBUG("too much device found."); + ret = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + SAFE_MALLOC(plist->pifaces[plist->count], sizeof(EthIface)); + eth_iface_dup(plist->pifaces[plist->count], &tcard); + plist->count++; + + out: + eth_iface_uninit(&tcard); + return ret; +} + +static int get_host_eth_ifaces_osapi_bridge(EthIfacesList *plist) +{ + int count; + int ret = 0, libret; + + libret = br_init(); + if (libret != 0) { + ret = ERR_LIBBR; + CU_DEBUG("erro in init the libbridge, errno is %d.", libret); + goto out; + } + + count = br_foreach_bridge(br_add2list_func, plist); + + if (plist->count >= MAX_IFACE_NUM) { + CU_DEBUG("too much device found."); + ret = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + + ret = 1; + + out: + br_shutdown(); + return ret; +} + +static void ln_link_print(struct rtnl_link *link) +{ + char *name, *qdisk, *type; + const char *ifalias; + int ifindex, flags, mtu, txqlen, family, arptype, getlink, master, operstate, linkmode; + uint32_t num_vf = 0; + int ret, i; + int vlanid, vlanflag, egress_num = 0; + uint32_t *ingress_map; + struct vlan_map *egress_map; + + qdisk = rtnl_link_get_qdisc(link); + name = rtnl_link_get_name(link); + flags = rtnl_link_get_flags(link); + mtu = rtnl_link_get_mtu(link); + txqlen = rtnl_link_get_txqlen(link); + ifindex = rtnl_link_get_ifindex(link); + family = rtnl_link_get_family(link); + arptype = rtnl_link_get_arptype(link); + getlink = rtnl_link_get_link(link); + master = rtnl_link_get_master(link); + operstate = rtnl_link_get_operstate(link); + linkmode = rtnl_link_get_linkmode(link); + ifalias = rtnl_link_get_ifalias(link); + ret = rtnl_link_get_num_vf(link, &num_vf); + + type = rtnl_link_get_type(link); + CMD_DEBUG(1, "link name %s, alias %s, qdisk %s, type %s,\n" + "--ifindex 0x%x, flags 0x%x, mtu 0x%x, txqlen 0x%x, family 0x%x, arptype 0x%x,\n" + "--getlink 0x%x, master 0x%x, operstate 0x%x, linkmode 0x%x, vf_ret %d with num_vf 0x%x.\n", + name, ifalias, qdisk, type, + ifindex, flags, mtu, txqlen, family, arptype, + getlink, master, operstate, linkmode, ret, num_vf); + + if (rtnl_link_is_vlan(link)) { + vlanid = rtnl_link_vlan_get_id(link); + vlanflag = rtnl_link_vlan_get_flags(link); + ingress_map = rtnl_link_vlan_get_ingress_map(link); + egress_map = rtnl_link_vlan_get_egress_map(link, &egress_num); + CMD_DEBUG(1, "--vlan properties:\n" + "----id %d, vlanflag 0x%x.", + vlanid, vlanflag); + CMD_DEBUG(1, "\n----ingress: "); + if (ingress_map != NULL) { + for (i = 0; i <= VLAN_PRIO_MAX; i++) { + CMD_DEBUG(1, "0x%x, ", ingress_map[i]); + } + } + CMD_DEBUG(1, "\n----egress: "); + if (egress_map != NULL) { + i = 0; + while (i < egress_num) { + CMD_DEBUG(1, "[%d %d], ", egress_map[i].vm_from, egress_map[i].vm_to); + i++; + } + } + CMD_DEBUG(1, "\n"); + } +} + +static void nl_add2list_func(struct nl_object *obj, void *opaque) +{ + struct rtnl_link *link; + struct nl_cache *cache; + struct rtnl_link *ll; + struct nl_addr *addr; + uint32_t *ingress_map; + int egress_num = 0; + struct vlan_map *egress_map; + EthIfacesList *plist; + EthIface tcard; + VLAN_Prop_8021q *pprop_8021q; + char buf[128]; + int t, i; + + struct nl_add2list_param *pparam = (struct nl_add2list_param *)opaque; + plist = pparam->plist; + cache = pparam->cache; + link = (struct rtnl_link *)obj; + + if (CMD_DEBUG_LEVEL && (LN_PRINT_LEVEL) <= CMD_DEBUG_LEVEL) { + ln_link_print(link); + } + + /* get properties */ + eth_iface_init(&tcard); + + /* get name */ + tcard.name = SAFE_STRDUP(rtnl_link_get_name(link)); + + /* get parent */ + t = rtnl_link_get_link(link); + if (t > 0) { + ll = rtnl_link_get(cache, t); + if (ll == NULL) { + CU_DEBUG("failed to find interface with index %d.", t); + goto out; + } + tcard.dep_ifname = SAFE_STRDUP(rtnl_link_get_name(ll)); + rtnl_link_put(ll); + } + + /* get mac */ + addr =rtnl_link_get_addr(link); + if (addr && !nl_addr_iszero(addr)) { + nl_addr2str(addr, buf, sizeof(buf)); + tcard.mac = SAFE_STRDUP(buf); + } + + /* get main type */ + t = rtnl_link_get_arptype(link); + if (t == ARPHRD_ETHER) { + tcard.eth_type = ETH_TYPE_ETHER_ANY; + } else { + tcard.eth_type = ETH_TYPE_OTHER; + } + + /* get vlan */ + if (rtnl_link_is_vlan(link)) { + SAFE_MALLOC(tcard.pvlan_prop, sizeof(VLAN_Prop)); + vlan_prop_init(tcard.pvlan_prop, VLAN_TYPE_802_1_Q); + pprop_8021q = &(tcard.pvlan_prop->props.prop_8021q); + tcard.eth_type |= ETH_TYPE_ETHER_SUB_VLAN; + pprop_8021q->vlan_id = rtnl_link_vlan_get_id(link); + pprop_8021q->reorder_hdr = (rtnl_link_vlan_get_flags(link) & + VLAN_FLAG_REORDER_HDR); + /* at any time parent of vlan8021.q is just what it depends on */ + pprop_8021q->parent = SAFE_STRDUP(tcard.dep_ifname); + ingress_map = rtnl_link_vlan_get_ingress_map(link); + egress_map = rtnl_link_vlan_get_egress_map(link, &egress_num); + if (ingress_map != NULL) { + for (i = 0; i <= VLAN_PRIO_MAX; i++) { + pprop_8021q->ingress.values[i].from = i; + pprop_8021q->ingress.values[i].to = ingress_map[i]; + } + pprop_8021q->ingress.count = VLAN_PRIO_MAX; + i = 0; + while (i < egress_num) { + pprop_8021q->egress.values[i].from = egress_map[i].vm_from; + pprop_8021q->egress.values[i].to = egress_map[i].vm_to; + i++; + } + pprop_8021q->egress.count = egress_num; + } + } + + + /* put result to list */ + if (plist->count >= MAX_IFACE_NUM) { + CU_DEBUG("too much device found."); + goto out; + } + SAFE_MALLOC(plist->pifaces[plist->count], sizeof(EthIface)); + eth_iface_dup(plist->pifaces[plist->count], &tcard); + plist->count++; + + out: + eth_iface_uninit(&tcard); +} + +static int get_host_eth_ifaces_osapi_netlink(EthIfacesList *plist) +{ + struct nl_sock *sk = NULL; + struct nl_cache *cache = NULL; + int ret, rtnl_ret; + struct nl_add2list_param param; + + sk = nl_socket_alloc(); + nl_connect(sk, NETLINK_ROUTE); + + rtnl_ret = rtnl_link_alloc_cache(sk, AF_UNSPEC, &cache); + if (rtnl_ret < 0) { + CU_DEBUG("error in talking to kernel, return %d.\n", rtnl_ret); + ret = ERR_LIBNETLINK; + } + + param.plist = plist; + param.cache = cache; + nl_cache_foreach(cache, nl_add2list_func, ¶m); + if (plist->count >= MAX_IFACE_NUM) { + CU_DEBUG("too much device found."); + ret = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + + ret = 1; + + out: + nl_cache_free(cache); + nl_socket_free(sk); + + return ret; +} + +int get_host_eth_ifaces_osapi(EthIfacesList *plist, + eth_iface_filter_func filter_func, void *filter_opaque) +{ + int retvalue; + EthIfacesList *ifaces1, *ifaces2; + int i; + int filter_ret; + int count = 0; + SAFE_MALLOC(ifaces1, sizeof(EthIfacesList)); + SAFE_MALLOC(ifaces2, sizeof(EthIfacesList)); + eth_ifaceslist_init(ifaces1); + eth_ifaceslist_init(ifaces2); + + retvalue = get_host_eth_ifaces_osapi_netlink(ifaces1); + if (retvalue != 1) { + goto out; + } + + retvalue = get_host_eth_ifaces_osapi_bridge(ifaces2); + if (retvalue != 1) { + goto out; + } + /* merge the information */ + merge_eth_list_for_bridge(ifaces1, ifaces2, 1); + eth_ifaceslist_uninit(ifaces2); + + /* filter the result */ + i = 0; + while (i < ifaces1->count) { + /* see if the result need to be put to the list */ + filter_ret = 1; + if (filter_func != NULL) { + filter_ret = filter_func(ifaces1->pifaces[i], filter_opaque); + } + if (filter_ret == 1) { + if (count >= MAX_IFACE_NUM) { + retvalue = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + host_iface_adjust(ifaces1->pifaces[i]); + plist->pifaces[count] = ifaces1->pifaces[i]; + ifaces1->pifaces[i] = NULL; + count++; + } + i++; + } + + out: + eth_ifaceslist_uninit(ifaces1); + SAFE_FREE(ifaces1); + eth_ifaceslist_uninit(ifaces2); + SAFE_FREE(ifaces2); + plist->count = count; + return retvalue; +} diff --git a/libnetwork/host_network_implement_OSAPI.h b/libnetwork/host_network_implement_OSAPI.h new file mode 100644 index 0000000..f72bf52 --- /dev/null +++ b/libnetwork/host_network_implement_OSAPI.h @@ -0,0 +1,21 @@ +/* + * Copyright IBM Corp. 2011 + * + * 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 HOST_NETWORK_IMPLEMENT_OSAPI_H +#define HOST_NETWORK_IMPLEMENT_OSAPI_H + +#include "host_network_basic.h" + +int get_host_eth_ifaces_osapi(EthIfacesList *plist, + eth_iface_filter_func filter_func, void *filter_opaque); + +#endif diff --git a/libnetwork/libnetwork_test.c b/libnetwork/libnetwork_test.c new file mode 100644 index 0000000..e8168b8 --- /dev/null +++ b/libnetwork/libnetwork_test.c @@ -0,0 +1,82 @@ +#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 "host_network_API.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; + printf("time is [%ld] ms.", ret); + return ret; +} + +int main(int argc, char **argv) +{ + EthIfacesList ifaces_list; + EthIface iface_ref,iface_br,iface_vlan; + int comp_ret = 0; + int persist_flag = 1; + long timestart, timeend; + + + printf("executing the program with persist flag %d.\n", persist_flag); + comp_ret = 0; + + eth_ifaceslist_init(&ifaces_list); + eth_iface_init(&iface_ref); + eth_iface_init(&iface_br); + eth_iface_init(&iface_vlan); + + eth_iface_add_br_prop(&iface_br); + eth_iface_add_vlan_prop(&iface_vlan, VLAN_TYPE_802_1_Q); + iface_br.eth_type = ETH_TYPE_ETHER_SUB_BRIDGE | ETH_TYPE_ETHER_ANY; + iface_vlan.eth_type = ETH_TYPE_ETHER_SUB_VLAN | ETH_TYPE_ETHER_ANY; + + //iface_ref.name = SAFE_STRDUP("eth1.100"); + iface_ref.eth_type = ETH_TYPE_ETHER_SUB_BRIDGE | ETH_TYPE_ETHER_ANY; + + iface_br.name = SAFE_STRDUP("test_br"); + iface_vlan.name = SAFE_STRDUP("eth0.1000"); + + iface_br.pbr_prop->STP = 1; + + iface_vlan.pvlan_prop->vlan_type = VLAN_TYPE_802_1_Q; + iface_vlan.pvlan_prop->props.prop_8021q.parent = SAFE_STRDUP("eth0"); + iface_vlan.pvlan_prop->props.prop_8021q.vlan_id = 1000; + iface_vlan.pvlan_prop->props.prop_8021q.reorder_hdr = 0; + iface_vlan.pvlan_prop->props.prop_8021q.ingress.count = 1; + iface_vlan.pvlan_prop->props.prop_8021q.ingress.values[0].from = 2; + iface_vlan.pvlan_prop->props.prop_8021q.ingress.values[0].to = 3; + iface_vlan.pvlan_prop->props.prop_8021q.egress.count = 1; + iface_vlan.pvlan_prop->props.prop_8021q.egress.values[0].from = 4; + iface_vlan.pvlan_prop->props.prop_8021q.egress.values[0].to = 6; + + timestart = print_and_ret_time_stamp(); + printf(" start list the host ifaces.\n"); + + get_host_ifaces(&ifaces_list, NULL, NULL); + //get_host_ifaces(&ifaces_list, eth_iface_filter_by_ref, &iface_ref); + //get_host_ifaces(&ifaces_list, eth_iface_filter_vlans, NULL); + //get_host_ifaces(&ifaces_list, eth_iface_filter_peths, NULL); + + timeend = print_and_ret_time_stamp(); + printf(" end list the host ifaces, cost [%ld]ms.\n", timeend-timestart); + + eth_ifaceslist_print(&ifaces_list); + eth_ifaceslist_uninit(&ifaces_list); + + eth_iface_uninit(&iface_ref); + eth_iface_uninit(&iface_br); + eth_iface_uninit(&iface_vlan); + + return 0; +} -- 1.7.6