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); } sysfs_close_class_device(dev); } else #endif { struct ifreq ifr; unsigned long args[4] = { oldcode, value, 0, 0 }; strncpy(ifr.ifr_name, bridge, IFNAMSIZ); ifr.ifr_data = (char *)&args; ret = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr); } return ret < 0 ? errno : 0; }
static struct sysfs_directory *bridge_sysfs_directory(const char *devname, const char *subname) { struct sysfs_directory *sdir; struct sysfs_class_device *dev; char path[SYSFS_PATH_MAX]; if (!devname) return NULL; if (!br_class_net) { dprintf("can't find class_net\n"); return NULL; } dev = sysfs_get_class_device(br_class_net, (char *) devname); if (!dev) { dprintf("can't find device %s in %s\n", devname, br_class_net->path); return NULL; } snprintf(path, SYSFS_PATH_MAX, "%s/%s", dev->path, subname); sdir = sysfs_open_directory(path); if (!sdir) dprintf("can't open directory: %s\n", path); return sdir; }
int br_read_fdb(const char *bridge, struct fdb_entry *fdbs, unsigned long offset, int num) { int i, fd = -1, n; struct __fdb_entry fe[num]; #ifdef HAVE_LIBSYSFS struct sysfs_class_device *dev; /* 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 { /* old kernel, use ioctl */ unsigned long args[4] = { BRCTL_GET_FDB_ENTRIES, (unsigned long) fe, num, offset }; struct ifreq ifr; int retries = 0; strncpy(ifr.ifr_name, bridge, IFNAMSIZ); ifr.ifr_data = (char *) args; retry: n = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr); /* table can change during ioctl processing */ if (n < 0 && errno == EAGAIN && ++retries < 10) { sleep(0); goto retry; } } for (i = 0; i < n; i++) __copy_fdb(fdbs+i, fe+i); if (fd > 0) close(fd); return n; }
/* * Get bridge parameters using either sysfs or old * ioctl. */ static int br_get_bridge_info(const char *bridge, struct bridge_info *info) { #ifdef HAVE_LIBSYSFS struct sysfs_class_device *dev; 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)) { dprintf("path '%s' is not a directory\n", path); sysfs_close_class_device(dev); 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"), &info->topology_change_timer_value);; fetch_tv(dev, BRIDGEATTR("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")); sysfs_close_class_device(dev); return 0; fallback: #endif return old_get_bridge_info(bridge, info); }
/* * Iterate over all ports in bridge (using sysfs). */ 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; 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; } 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)) break; } closedir(dir); return err; old: #endif return old_foreach_port(brname, iterator, arg); }
/* * Iterate over all ports in bridge (using sysfs). */ 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; struct sysfs_directory *dir; struct sysfs_link *plink; struct dlist *links; int err = 0; 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); dprintf("path=%s\n", path); dir = sysfs_open_directory(path); if (!dir) { /* no /sys/class/net/ethX/brif subdirectory * either: old kernel, or not really a bridge */ goto old; } links = sysfs_get_dir_links(dir); if (!links) { err = -ENOSYS; goto out; } err = 0; dlist_for_each_data(links, plink, struct sysfs_link) { ++err; if (iterator(brname, plink->name, arg)) break; }