This patch use libnl-1.1 and ioctl bridge functions in patch 3.
Signed-off-by: Wenchao Xia <xiawenc(a)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(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 <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(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 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