[Libvirt-cim] [V4 PATCH 4/8] vlan library - add host network implemention

Wenchao Xia xiawenc at linux.vnet.ibm.com
Wed Jan 18 09:42:12 UTC 2012


    This patch use libnl-1.1 and ioctl bridge functions in patch 3.

Signed-off-by: Wenchao Xia <xiawenc at 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 at cn.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <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, &param);
+    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 at cn.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ */
+
+#ifndef 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





More information about the Libvirt-cim mailing list