This patch use ioctl to get bridge settings from kernel. Netlink protocol
can't be used for bridge in linux2.6 kernel.
ioctl is the oldest way to talk to kernel about bridge, so it have some
limit in the ports number and bridge number. Currently they are set to 1024.
Signed-off-by: Wenchao Xia <xiawenc(a)cn.ibm.com>
---
libnetwork/host_network_implement_bridge.c | 224 ++++++++++++++++++++++++++++
libnetwork/host_network_implement_bridge.h | 8 +
2 files changed, 232 insertions(+), 0 deletions(-)
create mode 100644 libnetwork/host_network_implement_bridge.c
create mode 100644 libnetwork/host_network_implement_bridge.h
diff --git a/libnetwork/host_network_implement_bridge.c
b/libnetwork/host_network_implement_bridge.c
new file mode 100644
index 0000000..39c6b13
--- /dev/null
+++ b/libnetwork/host_network_implement_bridge.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright IBM Corp. 2012
+ *
+ * Authors:
+ * Wenchao Xia <xiawenc(a)cn.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <net/if.h>
+#include <linux/if_bridge.h>
+#include <sys/ioctl.h>
+
+#include "host_network_implement_bridge.h"
+#include "host_network_helper.h"
+#include "host_network_error.h"
+
+/* following number can't be changed otherwise ioctl get errors */
+#define BR_NUM_MAX 1024
+#define PORT_NUM_MAX 1024
+#define NAME_BUFF_SIZE 16
+
+static int socket_br = -1;
+
+static int try_socket_init(void)
+{
+ if (socket_br < 0) {
+ if ((socket_br = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
+ return -errno;
+ }
+ return 1;
+}
+
+void try_socket_close(void)
+{
+ if (socket_br > 0) {
+ close(socket_br);
+ socket_br = -1;
+ }
+}
+
+static int get_bridge_ports(EthIface *piface)
+{
+ struct ifreq req;
+ char ifname[NAME_BUFF_SIZE];
+ int if_indexes[PORT_NUM_MAX];
+ unsigned long args[4];
+ int i, ret = ERR_LIBBR;
+ BR_Prop *pbr;
+
+ memset(ifname, 0, sizeof(ifname));
+ memset(&req, 0 ,sizeof(req));
+ memset(if_indexes, 0 ,sizeof(if_indexes));
+ args[0] = BRCTL_GET_PORT_LIST;
+ args[1] = (unsigned long)if_indexes;
+ args[2] = PORT_NUM_MAX;
+ args[3] = 0;
+
+ strncpy(req.ifr_name, piface->name, NAME_BUFF_SIZE);
+ req.ifr_data = (char *) &args;
+
+ if (0 > ioctl(socket_br, SIOCDEVPRIVATE, &req)) {
+ CU_DEBUG("failed in ioctl listing ports of bridge %s,"
+ " errno %d, reason %s.",
+ piface->name, errno, strerror(errno));
+ goto out;
+ }
+
+ if (piface->pbr_prop == NULL) {
+ eth_iface_add_br_prop(piface);
+ }
+ pbr = piface->pbr_prop;
+
+ i = -1;
+ while (i < PORT_NUM_MAX) {
+ i++;
+ if (if_indexes[i] <= 0) {
+ continue;
+ }
+ if (0 == if_indextoname(if_indexes[i], ifname)) {
+ CU_DEBUG("failed to translate if_index %d, skip it.", if_indexes);
+ continue;
+ }
+ /* add the ports to the list */
+ 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!",
piface->name);
+ ret = ERR_DEVICE_EXCEED_MAXNUM;
+ goto out;
+ }
+ pbr->port_names[pbr->port_num] = SAFE_STRDUP(ifname);
+ pbr->port_num++;
+ }
+
+ ret = 1;
+
+ out:
+ return ret;
+}
+
+static int get_bridge_info(EthIface *piface)
+{
+ struct ifreq req;
+ struct __bridge_info binfo;
+ unsigned long args[4];
+ int ret = ERR_LIBBR;
+
+ memset(&req, 0, sizeof(req));
+ memset(&binfo, 0, sizeof(binfo));
+ args[0] = BRCTL_GET_BRIDGE_INFO;
+ args[1] = (unsigned long) &binfo;
+ args[2] = 0;
+ args[3] = 0;
+ req.ifr_data = (char *) &args;
+
+ if (piface->name == NULL) {
+ CU_DEBUG("bridge name not set for ioctl.");
+ goto out;
+ }
+ strncpy(req.ifr_name, piface->name, NAME_BUFF_SIZE);
+ if (ioctl(socket_br, SIOCDEVPRIVATE, &req) < 0) {
+ CU_DEBUG("failed to get info for %s, errno %d, reason %s.",
+ piface->name, errno, strerror(errno));
+ goto out;
+ }
+
+ if (piface->pbr_prop == NULL) {
+ eth_iface_add_br_prop(piface);
+ }
+ piface->pbr_prop->STP = binfo.stp_enabled;
+
+ ret = 1;
+
+ out:
+ return ret;
+}
+
+static int list_bridges(EthIfacesList *plist)
+{
+ int if_indexes[BR_NUM_MAX];
+ unsigned long args[3];
+ int brnum;
+ int i, ret = ERR_LIBBR;
+ EthIface tface;
+
+ eth_iface_init(&tface);
+ SAFE_CALLOC(tface.name, NAME_BUFF_SIZE, 1);
+
+ args[0] = BRCTL_GET_BRIDGES;
+ args[1] = (unsigned long)if_indexes;
+ args[2] = BR_NUM_MAX;
+ memset(if_indexes, 0, sizeof(if_indexes));
+
+ if (0 > try_socket_init()) {
+ CU_DEBUG("failed to init socket for bridge ioctl,"
+ " errno is %d, reason: %s.",
+ errno, strerror(errno));
+ goto out;
+ }
+
+ brnum = ioctl(socket_br, SIOCGIFBR, args);
+ if (brnum < 0) {
+ CU_DEBUG("failed tp get bridge, errno is %d, reason: %s.",
+ errno, strerror(errno));
+ goto out;
+ }
+
+ i = 0;
+ while (i < brnum) {
+ if (!if_indextoname(if_indexes[i], tface.name)) {
+ CU_DEBUG("failed to translate index %d, errno is %d, reason: %s.",
+ if_indexes[i], errno, strerror(errno));
+ goto out;
+ }
+
+ ret = get_bridge_info(&tface);
+ if (ret != 1) {
+ CU_DEBUG("failed to get info for %s.", tface.name);
+ continue;
+ }
+
+ ret = get_bridge_ports(&tface);
+ if (ret != 1) {
+ CU_DEBUG("failed to get info for %s.", tface.name);
+ continue;
+ }
+
+ if (1 != eth_ifaceslist_add(plist, &tface)) {
+ CU_DEBUG("failed to add device to list.");
+ goto out;
+ }
+ eth_iface_uninit(&tface);
+ eth_iface_init(&tface);
+ SAFE_CALLOC(tface.name, NAME_BUFF_SIZE, 1);
+ i++;
+ }
+ ret = 1;
+
+ out:
+ eth_iface_uninit(&tface);
+ try_socket_close();
+ return ret;
+
+}
+
+int get_host_eth_ifaces_osapi_bridge(EthIfacesList *plist)
+{
+ return list_bridges(plist);
+}
diff --git a/libnetwork/host_network_implement_bridge.h
b/libnetwork/host_network_implement_bridge.h
new file mode 100644
index 0000000..ed77195
--- /dev/null
+++ b/libnetwork/host_network_implement_bridge.h
@@ -0,0 +1,8 @@
+#ifndef HOST_NETWORK_IMPLE_BRIDGE_H
+#define HOST_NETWORK_IMPLE_BRIDGE_H
+
+#include "host_network_basic.h"
+
+int get_host_eth_ifaces_osapi_bridge(EthIfacesList *plist);
+
+#endif
--
1.7.1