
This patch use libnl-1.1 and ioctl bridge functions in patch 3. Signed-off-by: Wenchao Xia <xiawenc@cn.ibm.com> --- libnetwork/host_network_implement_OSAPI.c | 366 +++++++++++++++++++++++++++++ libnetwork/host_network_implement_OSAPI.h | 21 ++ 2 files changed, 387 insertions(+), 0 deletions(-) create mode 100644 libnetwork/host_network_implement_OSAPI.c create mode 100644 libnetwork/host_network_implement_OSAPI.h diff --git a/libnetwork/host_network_implement_OSAPI.c b/libnetwork/host_network_implement_OSAPI.c new file mode 100644 index 0000000..2efcf37 --- /dev/null +++ b/libnetwork/host_network_implement_OSAPI.c @@ -0,0 +1,366 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Wenchao Xia <xiawenc@cn.ibm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + +#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 <netlink/route/link/info-api.h> + +#include "host_network_implement_bridge.h" +#include "host_network_implement_OSAPI.h" +#include "host_network_helper.h" +#include "host_network_error.h" + +/* macro defines */ +#define LN_PRINT_LEVEL 4 + +struct nl_add2list_param { + EthIfacesList *plist; + struct nl_cache *cache; +} ; + +/* libnl1 lackes a way to see if it is vlan8021q, added an implemention here*/ +static int rtnl_link_is_vlan(struct rtnl_link *link) +{ + char* type = rtnl_link_get_info_type(link); + if (type == NULL) { + return 0; + } + return !strcmp(type, "vlan"); +} + +/* 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 (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 void ln_link_print(struct rtnl_link *link) +{ + char *name, *qdisk, *type = NULL; + const char *ifalias = NULL; + 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); + + 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, opstate; + struct vlan_map *egress_map; + EthIfacesList *plist; + EthIface tface; + 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(&tface); + + /* get name */ + tface.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; + } + tface.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)); + tface.mac = SAFE_STRDUP(buf); + } + + /* get main type */ + t = rtnl_link_get_arptype(link); + if (t == ARPHRD_ETHER) { + tface.eth_type = ETH_TYPE_ETHER_ANY; + } else { + tface.eth_type = ETH_TYPE_OTHER; + } + + tface.run_prop.status = rtnl_link_get_operstate(link); + + /* get vlan */ + if (rtnl_link_is_vlan(link)) { + SAFE_MALLOC(tface.pvlan_prop, sizeof(VLAN_Prop)); + vlan_prop_init(tface.pvlan_prop, VLAN_TYPE_802_1_Q); + pprop_8021q = &(tface.pvlan_prop->props.prop_8021q); + tface.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(tface.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 (1 != eth_ifaceslist_add(plist, &tface)) { + CU_DEBUG("failed to add device to list."); + goto out; + } + + out: + eth_iface_uninit(&tface); +} + +static int get_host_eth_ifaces_osapi_netlink(EthIfacesList *plist) +{ + struct nl_handle *nlh = NULL; + struct nl_cache *cache = NULL; + int ret, rtnl_ret; + struct nl_add2list_param param; + + nlh = nl_handle_alloc(); + if (nlh == NULL) { + CU_DEBUG("unable to allocate nl handle."); + ret = ERR_LIBNETLINK; + } + rtnl_ret = nl_connect(nlh, NETLINK_ROUTE); + if (rtnl_ret < 0) { + CU_DEBUG("error in connect to kernel, return %d, err %s.\n", + rtnl_ret, nl_geterror()); + ret = ERR_LIBNETLINK; + } + + cache = rtnl_link_alloc_cache(nlh); + if (cache == NULL) { + CU_DEBUG("error in talking to kernel.\n"); + 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_close(nlh); + nl_handle_destroy(nlh); + + 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..34a261b --- /dev/null +++ b/libnetwork/host_network_implement_OSAPI.h @@ -0,0 +1,21 @@ +/* + * Copyright IBM Corp. 2012 + * + * Authors: + * Wenchao Xia <xiawenc@cn.ibm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +#ifndef 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 -- 1.7.1