diff options
Diffstat (limited to 'libbridge')
-rw-r--r-- | libbridge/config.h.in | 3 | ||||
-rw-r--r-- | libbridge/libbridge_devif.c | 275 | ||||
-rw-r--r-- | libbridge/libbridge_init.c | 104 | ||||
-rw-r--r-- | libbridge/libbridge_private.h | 33 |
4 files changed, 135 insertions, 280 deletions
diff --git a/libbridge/config.h.in b/libbridge/config.h.in index b91185e..12881c4 100644 --- a/libbridge/config.h.in +++ b/libbridge/config.h.in @@ -1,8 +1,5 @@ /* config.h.in. Generated automatically from configure.in by autoheader. */ -/* Define if you have libsysfs */ -#undef HAVE_LIBSYSFS - /* Name of package */ #undef PACKAGE_NAME diff --git a/libbridge/libbridge_devif.c b/libbridge/libbridge_devif.c index 3703f4b..58828c3 100644 --- a/libbridge/libbridge_devif.c +++ b/libbridge/libbridge_devif.c @@ -22,70 +22,52 @@ #include <unistd.h> #include <errno.h> #include <string.h> +#include <dirent.h> #include <sys/fcntl.h> #include "libbridge.h" #include "libbridge_private.h" -#ifdef HAVE_LIBSYSFS -/* Given two two character "0a" convert it to a byte */ -static unsigned char getoctet(const char *cp) +static FILE *fpopen(const char *dir, const char *name) { - char t[3] = { cp[0], cp[1], 0 }; - return strtoul(t, NULL, 16); -} + char path[SYSFS_PATH_MAX]; -#define BRIDGEATTR(_a) SYSFS_BRIDGE_ATTR "/" _a -#define BRPORT(_a) SYSFS_BRIDGE_PORT_ATTR "/" _a + snprintf(path, SYSFS_PATH_MAX, "%s/%s", dir, name); + return fopen(path, "r"); +} -static void fetch_id(struct sysfs_class_device *dev, - const char *name, struct bridge_id *id) +static void fetch_id(const char *dev, const char *name, struct bridge_id *id) { - struct sysfs_attribute *attr; - - attr = sysfs_get_classdev_attr(dev, name); - if (!attr) { - dprintf("Can't find attribute %s/%s\n", dev->path, name); - return; - } + FILE *f = fpopen(dev, name); - if (strlen(attr->value) < 17) - dprintf("Bad format for %s: '%s'\n", name, attr->value); - else { - const char *cp = attr->value; - id->prio[0] = getoctet(cp); cp += 2; - id->prio[1] = getoctet(cp); cp += 3; - id->addr[0] = getoctet(cp); cp += 2; - id->addr[1] = getoctet(cp); cp += 2; - id->addr[2] = getoctet(cp); cp += 2; - id->addr[3] = getoctet(cp); cp += 2; - id->addr[4] = getoctet(cp); cp += 2; - id->addr[5] = getoctet(cp); - } + fscanf(f, "%2hhx%2hhx.%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx", + &id->prio[0], &id->prio[1], + &id->addr[0], &id->addr[1], &id->addr[2], + &id->addr[3], &id->addr[4], &id->addr[5]); + fclose(f); } -/* Get a time value out of sysfs */ -static void fetch_tv(struct sysfs_class_device *dev, - const char *name, - struct timeval *tv) +/* Fetch an integer attribute out of sysfs. */ +static int fetch_int(const char *dev, const char *name) { - struct sysfs_attribute *attr; - - attr = sysfs_get_classdev_attr(dev, name); - if (attr) - __jiffies_to_tv(tv, strtoul(attr->value, NULL, 0)); + FILE *f = fpopen(dev, name); + int value = -1; + if (!f) + fprintf(stderr, "%s: %s\n", dev, strerror(errno)); + else { + fscanf(f, "%d", &value); + fclose(f); + } + return value; } -/* Fetch an integer attribute out of sysfs. */ -static int fetch_int(struct sysfs_class_device *dev, const char *name) +/* Get a time value out of sysfs */ +static void fetch_tv(const char *dev, const char *name, + struct timeval *tv) { - struct sysfs_attribute *attr; - - attr = sysfs_get_classdev_attr(dev, name); - return attr ? strtol(attr->value, NULL, 0) : 0; + __jiffies_to_tv(tv, fetch_int(dev, name)); } -#endif /* * Convert device name to an index in the list of ports in bridge. @@ -172,52 +154,42 @@ static int old_get_bridge_info(const char *bridge, struct bridge_info *info) */ int br_get_bridge_info(const char *bridge, struct bridge_info *info) { -#ifdef HAVE_LIBSYSFS - struct sysfs_class_device *dev; + DIR *dir; char path[SYSFS_PATH_MAX]; - if (!br_class_net) - goto fallback; - - dev = sysfs_get_class_device(br_class_net, bridge); - if (!dev) { - dprintf("get_class_device '%s' failed\n", bridge); - goto fallback; - } - - snprintf(path, SYSFS_PATH_MAX, "%s/bridge", dev->path); - if (sysfs_path_is_dir(path)) { + snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/bridge", bridge); + dir = opendir(path); + if (dir == NULL) { dprintf("path '%s' is not a directory\n", path); goto fallback; } memset(info, 0, sizeof(*info)); - fetch_id(dev, BRIDGEATTR("root_id"), &info->designated_root); - fetch_id(dev, BRIDGEATTR("bridge_id"), &info->bridge_id); - info->root_path_cost = fetch_int(dev, BRIDGEATTR("root_path_cost")); - fetch_tv(dev, BRIDGEATTR("max_age"), &info->max_age); - fetch_tv(dev, BRIDGEATTR("hello_time"), &info->hello_time); - fetch_tv(dev, BRIDGEATTR("forward_delay"), &info->forward_delay); - fetch_tv(dev, BRIDGEATTR("max_age"), &info->bridge_max_age); - fetch_tv(dev, BRIDGEATTR("hello_time"), &info->bridge_hello_time); - fetch_tv(dev, BRIDGEATTR("forward_delay"), &info->bridge_forward_delay); - fetch_tv(dev, BRIDGEATTR("ageing_time"), &info->ageing_time); - fetch_tv(dev, BRIDGEATTR("hello_timer"), &info->hello_timer_value); - fetch_tv(dev, BRIDGEATTR("tcn_timer"), &info->tcn_timer_value); - fetch_tv(dev, BRIDGEATTR("topology_change_timer"), + fetch_id(path, "root_id", &info->designated_root); + fetch_id(path, "bridge_id", &info->bridge_id); + info->root_path_cost = fetch_int(path, "root_path_cost"); + fetch_tv(path, "max_age", &info->max_age); + fetch_tv(path, "hello_time", &info->hello_time); + fetch_tv(path, "forward_delay", &info->forward_delay); + fetch_tv(path, "max_age", &info->bridge_max_age); + fetch_tv(path, "hello_time", &info->bridge_hello_time); + fetch_tv(path, "forward_delay", &info->bridge_forward_delay); + fetch_tv(path, "ageing_time", &info->ageing_time); + fetch_tv(path, "hello_timer", &info->hello_timer_value); + fetch_tv(path, "tcn_timer", &info->tcn_timer_value); + fetch_tv(path, "topology_change_timer", &info->topology_change_timer_value);; - fetch_tv(dev, BRIDGEATTR("gc_timer"), &info->gc_timer_value); + fetch_tv(path, "gc_timer", &info->gc_timer_value); - info->root_port = fetch_int(dev, BRIDGEATTR("root_port")); - info->stp_enabled = fetch_int(dev, BRIDGEATTR("stp_state")); - info->topology_change = fetch_int(dev, BRIDGEATTR("topology_change")); - info->topology_change_detected = fetch_int(dev, - BRIDGEATTR("topology_change_detected")); + info->root_port = fetch_int(path, "root_port"); + info->stp_enabled = fetch_int(path, "stp_state"); + info->topology_change = fetch_int(path, "topology_change"); + info->topology_change_detected = fetch_int(path, "topology_change_detected"); + closedir(dir); return 0; fallback: -#endif return old_get_bridge_info(bridge, info); } @@ -272,44 +244,33 @@ static int old_get_port_info(const char *brname, const char *port, int br_get_port_info(const char *brname, const char *port, struct port_info *info) { -#ifdef HAVE_LIBSYSFS - struct sysfs_class_device *dev; + DIR *d; char path[SYSFS_PATH_MAX]; - if (!br_class_net) + snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brport", port); + d = opendir(path); + if (!d) goto fallback; - dev = sysfs_get_class_device(br_class_net, port); - if (!dev) - goto fallback; - - snprintf(path, SYSFS_PATH_MAX, "%s/brport", dev->path); - if (sysfs_path_is_dir(path)) { - goto fallback; - } - memset(info, 0, sizeof(*info)); - fetch_id(dev, BRPORT("designated_root"), &info->designated_root); - fetch_id(dev, BRPORT("designated_bridge"), &info->designated_bridge); - info->port_no = fetch_int(dev, BRPORT("port_no")); - info->port_id = fetch_int(dev, BRPORT("port_id")); - info->designated_port = fetch_int(dev, BRPORT("designated_port")); - info->path_cost = fetch_int(dev, BRPORT("path_cost")); - info->designated_cost = fetch_int(dev, BRPORT("designated_cost")); - info->state = fetch_int(dev, BRPORT("state")); - info->top_change_ack = fetch_int(dev, BRPORT("change_ack")); - info->config_pending = fetch_int(dev, BRPORT("config_pending")); - fetch_tv(dev, BRPORT("message_age_timer"), - &info->message_age_timer_value); - fetch_tv(dev, BRPORT("forward_delay_timer"), - &info->forward_delay_timer_value); - fetch_tv(dev, BRPORT("hold_timer"), - &info->hold_timer_value); + fetch_id(path, "designated_root", &info->designated_root); + fetch_id(path, "designated_bridge", &info->designated_bridge); + info->port_no = fetch_int(path, "port_no"); + info->port_id = fetch_int(path, "port_id"); + info->designated_port = fetch_int(path, "designated_port"); + info->path_cost = fetch_int(path, "path_cost"); + info->designated_cost = fetch_int(path, "designated_cost"); + info->state = fetch_int(path, "state"); + info->top_change_ack = fetch_int(path, "change_ack"); + info->config_pending = fetch_int(path, "config_pending"); + fetch_tv(path, "message_age_timer", &info->message_age_timer_value); + fetch_tv(path, "forward_delay_timer", &info->forward_delay_timer_value); + fetch_tv(path, "hold_timer", &info->hold_timer_value); + closedir(d); return 0; fallback: -#endif return old_get_port_info(brname, port, info); } @@ -317,27 +278,18 @@ fallback: static int br_set(const char *bridge, const char *name, unsigned long value, unsigned long oldcode) { - int ret = -1; -#ifdef HAVE_LIBSYSFS - struct sysfs_class_device *dev; - - dev = sysfs_get_class_device(br_class_net, bridge); - if (dev) { - struct sysfs_attribute *attr; - char buf[32]; - char path[SYSFS_PATH_MAX]; - - snprintf(buf, sizeof(buf), "%ld\n", value); - snprintf(path, SYSFS_PATH_MAX, "%s/bridge/%s", dev->path, name); - - attr = sysfs_open_attribute(path); - if (attr) { - ret = sysfs_write_attribute(attr, buf, strlen(buf)); - sysfs_close_attribute(attr); - } - } else -#endif - { + int ret; + char path[SYSFS_PATH_MAX]; + FILE *f; + + snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/%s", bridge, name); + + f = fopen(path, "w"); + if (f) { + ret = fprintf(f, "%ld\n", value); + fclose(f); + } else { + /* fallback to old ioctl */ struct ifreq ifr; unsigned long args[4] = { oldcode, value, 0, 0 }; @@ -388,27 +340,16 @@ static int port_set(const char *bridge, const char *ifname, const char *name, unsigned long value, unsigned long oldcode) { - int ret = -1; -#ifdef HAVE_LIBSYSFS - struct sysfs_class_device *dev; - - dev = sysfs_get_class_device(br_class_net, ifname); - if (dev) { - struct sysfs_attribute *attr; - char path[SYSFS_PATH_MAX]; - char buf[32]; - - sprintf(buf, "%ld", value); - snprintf(path, SYSFS_PATH_MAX, "%s/brport/%s", dev->path, name); - - attr = sysfs_open_attribute(path); - if (attr) { - ret = sysfs_write_attribute(attr, buf, strlen(buf)); - sysfs_close_attribute(attr); - } - } else -#endif - { + int ret; + char path[SYSFS_PATH_MAX]; + FILE *f; + + snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brport/%s", ifname, name); + f = fopen(path, "w"); + if (f) { + ret = fprintf(f, "%ld\n", value); + fclose(f); + } else { int index = get_portno(bridge, ifname); if (index < 0) @@ -448,30 +389,19 @@ static inline void __copy_fdb(struct fdb_entry *ent, int br_read_fdb(const char *bridge, struct fdb_entry *fdbs, unsigned long offset, int num) { - int i, fd = -1, n; + FILE *f; + int i, n; struct __fdb_entry fe[num]; -#ifdef HAVE_LIBSYSFS - struct sysfs_class_device *dev; + char path[SYSFS_PATH_MAX]; /* open /sys/class/net/brXXX/brforward */ - if (br_class_net && - (dev = sysfs_get_class_device(br_class_net, (char *) bridge))) { - char path[SYSFS_PATH_MAX]; - - snprintf(path, SYSFS_PATH_MAX, "%s/%s", dev->path, - SYSFS_BRIDGE_FDB); - fd = open(path, O_RDONLY, 0); - } - - if (fd != -1) { - /* read records from file */ - lseek(fd, offset*sizeof(struct __fdb_entry), SEEK_SET); - n = read(fd, fe, num*sizeof(struct __fdb_entry)); - if (n > 0) - n /= sizeof(struct __fdb_entry); - } else -#endif - { + snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brforward", bridge); + f = fopen(path, "r"); + if (f) { + fseek(f, offset*sizeof(struct __fdb_entry), SEEK_SET); + n = fread(fe, sizeof(struct __fdb_entry), num, f); + fclose(f); + } else { /* old kernel, use ioctl */ unsigned long args[4] = { BRCTL_GET_FDB_ENTRIES, (unsigned long) fe, @@ -495,8 +425,5 @@ int br_read_fdb(const char *bridge, struct fdb_entry *fdbs, for (i = 0; i < n; i++) __copy_fdb(fdbs+i, fe+i); - if (fd > 0) - close(fd); - return n; } diff --git a/libbridge/libbridge_init.c b/libbridge/libbridge_init.c index 4c34b31..e2eab77 100644 --- a/libbridge/libbridge_init.c +++ b/libbridge/libbridge_init.c @@ -22,48 +22,35 @@ #include <errno.h> #include <string.h> #include <dirent.h> +#include <sys/types.h> +#include <sys/stat.h> #include "libbridge.h" #include "libbridge_private.h" int br_socket_fd = -1; -struct sysfs_class *br_class_net; int br_init(void) { if ((br_socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) return errno; - - br_class_net = sysfs_open_class("net"); - return 0; -} - -int br_refresh(void) -{ - if (br_class_net) { - sysfs_close_class(br_class_net); - br_class_net = sysfs_open_class("net"); - } - return 0; } void br_shutdown(void) { - sysfs_close_class(br_class_net); - br_class_net = NULL; close(br_socket_fd); br_socket_fd = -1; } -#ifdef HAVE_LIBSYSFS /* If /sys/class/net/XXX/bridge exists then it must be a bridge */ -static int isbridge(const struct sysfs_class_device *dev) +static int isbridge(const struct dirent *entry) { char path[SYSFS_PATH_MAX]; + struct stat st; - snprintf(path, sizeof(path), "%s/bridge", dev->path); - return !sysfs_path_is_dir(path); + snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/bridge", entry->d_name); + return stat(path, &st) == 0 && S_ISDIR(st.st_mode); } /* @@ -72,32 +59,24 @@ static int isbridge(const struct sysfs_class_device *dev) static int new_foreach_bridge(int (*iterator)(const char *name, void *), void *arg) { - struct sysfs_class_device *dev; - struct dlist *devlist; - int count = 0; + struct dirent **namelist; + int i, count = 0; - if (!br_class_net) { - dprintf("no class /sys/class/net\n"); - return -EOPNOTSUPP; - } + count = scandir(SYSFS_CLASS_NET, &namelist, isbridge, alphasort); + if (count < 0) + return -1; - devlist = sysfs_get_class_devices(br_class_net); - if (!devlist) { - dprintf("Can't read devices from sysfs\n"); - return -errno; + for (i = 0; i < count; i++) { + if (iterator(namelist[i]->d_name, arg)) + break; } - dlist_for_each_data(devlist, dev, struct sysfs_class_device) { - if (isbridge(dev)) { - ++count; - if (iterator(dev->name, arg)) - break; - } - } + for (i = 0; i < count; i++) + free(namelist[i]); + free(namelist); return count; } -#endif /* * Old interface uses ioctl @@ -143,11 +122,9 @@ int br_foreach_bridge(int (*iterator)(const char *, void *), void *arg) { int ret; -#ifdef HAVE_LIBSYSFS ret = new_foreach_bridge(iterator, arg); if (ret <= 0) -#endif ret = old_foreach_bridge(iterator, arg); return ret; @@ -205,45 +182,22 @@ int br_foreach_port(const char *brname, int (*iterator)(const char *br, const char *port, void *arg), void *arg) { -#ifdef HAVE_LIBSYSFS - struct sysfs_class_device *dev; - DIR *dir; - struct dirent *dirent; - int err = 0; + int i, count; + struct dirent **namelist; char path[SYSFS_PATH_MAX]; - if (!br_class_net || - !(dev = sysfs_get_class_device(br_class_net, (char *) brname))) - goto old; - - snprintf(path, sizeof(path), "%s/%s", - dev->path, SYSFS_BRIDGE_PORT_SUBDIR); - - - dir = opendir(path); - if (!dir) { - /* no /sys/class/net/ethX/brif subdirectory - * either: old kernel, or not really a bridge - */ - goto old; - } + snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brport", brname); + count = scandir(path, &namelist, 0, alphasort); + if (count < 0) + return old_foreach_port(brname, iterator, arg); - err = 0; - while ((dirent = readdir(dir)) != NULL) { - if (0 == strcmp(dirent->d_name, ".")) - continue; - if (0 == strcmp(dirent->d_name, "..")) - continue; - ++err; - if (iterator(brname, dirent->d_name, arg)) + for (i = 0; i < count; i++) { + if (iterator(brname, namelist[i]->d_name, arg)) break; } - closedir(dir); - - return err; + for (i = 0; i < count; i++) + free(namelist[i]); + free(namelist); - old: -#endif - return old_foreach_port(brname, iterator, arg); - + return count; } diff --git a/libbridge/libbridge_private.h b/libbridge/libbridge_private.h index 8d9ed0c..99a511d 100644 --- a/libbridge/libbridge_private.h +++ b/libbridge/libbridge_private.h @@ -25,39 +25,16 @@ #include <sys/time.h> #include <sys/ioctl.h> #include <linux/if_bridge.h> -#include <asm/param.h> #define MAX_BRIDGES 1024 #define MAX_PORTS 1024 -#define dprintf(fmt,arg...) - -#ifdef HAVE_LIBSYSFS -#include <sysfs/libsysfs.h> - -#ifndef SYSFS_BRIDGE_PORT_ATTR -#error Using wrong kernel headers if_bridge.h is out of date. -#endif - -#ifndef SIOCBRADDBR -#error Using wrong kernel headers sockios.h is out of date. -#endif - -#else -struct sysfs_class { const char *name; }; +#define SYSFS_CLASS_NET "/sys/class/net/" +#define SYSFS_PATH_MAX 256 -static inline struct sysfs_class *sysfs_open_class(const char *name) -{ - return NULL; -} - -static inline void sysfs_close_class(struct sysfs_class *class) -{ -} -#endif +#define dprintf(fmt,arg...) extern int br_socket_fd; -extern struct sysfs_class *br_class_net; static inline unsigned long __tv_to_jiffies(const struct timeval *tv) { @@ -65,14 +42,14 @@ static inline unsigned long __tv_to_jiffies(const struct timeval *tv) jif = 1000000ULL * tv->tv_sec + tv->tv_usec; - return (HZ*jif)/1000000; + return jif/10000; } static inline void __jiffies_to_tv(struct timeval *tv, unsigned long jiffies) { unsigned long long tvusec; - tvusec = (1000000ULL*jiffies)/HZ; + tvusec = 10000ULL*jiffies; tv->tv_sec = tvusec/1000000; tv->tv_usec = tvusec - 1000000 * tv->tv_sec; } |