diff options
author | shemminger <shemminger> | 2004-05-21 17:41:48 +0000 |
---|---|---|
committer | shemminger <shemminger> | 2004-05-21 17:41:48 +0000 |
commit | 328f4711bbc369dcccf8f8cfba2adf5dd0f74479 (patch) | |
tree | 8dd07660534f32407d249d0259e2e8f3a62f2ae5 | |
parent | 064717a4d7e47b47ba42e658abfd36acaa4a65d6 (diff) | |
download | android_external_brctl-328f4711bbc369dcccf8f8cfba2adf5dd0f74479.tar.gz android_external_brctl-328f4711bbc369dcccf8f8cfba2adf5dd0f74479.tar.bz2 android_external_brctl-328f4711bbc369dcccf8f8cfba2adf5dd0f74479.zip |
New version of command and library that use sysfs.
Update make system to build with or without sysfs.
-rw-r--r-- | Makefile.in | 4 | ||||
-rw-r--r-- | brctl/Makefile.in | 2 | ||||
-rw-r--r-- | brctl/brctl.c | 62 | ||||
-rw-r--r-- | brctl/brctl.h | 19 | ||||
-rw-r--r-- | brctl/brctl_cmd.c | 367 | ||||
-rw-r--r-- | brctl/brctl_disp.c | 59 | ||||
-rw-r--r-- | configure.in | 3 | ||||
-rw-r--r-- | doc/Makefile | 2 | ||||
-rw-r--r-- | libbridge/libbridge.h | 75 | ||||
-rw-r--r-- | libbridge/libbridge_devif.c | 477 | ||||
-rw-r--r-- | libbridge/libbridge_if.c | 66 | ||||
-rw-r--r-- | libbridge/libbridge_init.c | 353 | ||||
-rw-r--r-- | libbridge/libbridge_misc.c | 59 | ||||
-rw-r--r-- | libbridge/libbridge_private.h | 52 |
14 files changed, 941 insertions, 659 deletions
diff --git a/Makefile.in b/Makefile.in index be1d3ad..6028513 100644 --- a/Makefile.in +++ b/Makefile.in @@ -2,13 +2,14 @@ DESTDIR= KERNEL_HEADERS=-I@KERNEL_HEADERS@ -INSTALL=install -s +INSTALL=@INSTALL@ prefix=@prefix@ exec_prefix=@exec_prefix@ bindir=@bindir@ sbindir=@sbindir@ mandir=@mandir@ +distdir = $(PACKAGE)-$(VERSION) SUBDIRS=libbridge brctl doc @@ -31,3 +32,4 @@ maintainer-clean: distclean install: for x in $(SUBDIRS); do $(MAKE) $(MFLAGS) -C $$x install; done + diff --git a/brctl/Makefile.in b/brctl/Makefile.in index fd66905..f56bd9c 100644 --- a/brctl/Makefile.in +++ b/brctl/Makefile.in @@ -4,7 +4,7 @@ KERNEL_HEADERS=-I@KERNEL_HEADERS@ CC=@CC@ CFLAGS= -Wall -g @CFLAGS@ INCLUDE=-I../libbridge $(KERNEL_HEADERS) -LIBS= -L ../libbridge -lbridge +LIBS= -L ../libbridge -lbridge -lsysfs prefix=@prefix@ exec_prefix=@exec_prefix@ diff --git a/brctl/brctl.c b/brctl/brctl.c index 5ff9ab4..11dc1f3 100644 --- a/brctl/brctl.c +++ b/brctl/brctl.c @@ -21,45 +21,25 @@ #include <string.h> #include <sys/errno.h> #include "libbridge.h" -#include "brctl.h" - -const char *version = "bridge-utils 1.0 (11-May-2004)"; +#include "config.h" -const char *help_message = -"commands:\n" -"\taddbr\t\t<bridge>\t\tadd bridge\n" -"\taddif\t\t<bridge> <device>\tadd interface to bridge\n" -"\tdelbr\t\t<bridge>\t\tdelete bridge\n" -"\tdelif\t\t<bridge> <device>\tdelete interface from bridge\n" -"\tshow\t\t\t\t\tshow a list of bridges\n" -"\tshowmacs\t<bridge>\t\tshow a list of mac addrs\n" -"\tshowstp\t\t<bridge>\t\tshow bridge stp info\n" -"\n" -"\tsetageing\t<bridge> <time>\t\tset ageing time\n" -"\tsetbridgeprio\t<bridge> <prio>\t\tset bridge priority\n" -"\tsetfd\t\t<bridge> <time>\t\tset bridge forward delay\n" -"\tsethello\t<bridge> <time>\t\tset hello time\n" -"\tsetmaxage\t<bridge> <time>\t\tset max message age\n" -"\tsetpathcost\t<bridge> <port> <cost>\tset path cost\n" -"\tsetportprio\t<bridge> <port> <prio>\tset port priority\n" -"\tstp\t\t<bridge> <state>\tturn stp on/off\n"; +#include "brctl.h" -void help() +static void help() { - fprintf(stderr, help_message); + printf("commands:\n"); + command_helpall(); } int main(int argc, char *argv[]) { - int argindex; - struct bridge *br; - struct command *cmd; + const struct command *cmd; if (argc < 2) goto help; if (strcmp(argv[1], "-V") == 0) { - fprintf(stderr, "%s, %s\n", argv[0], version); + printf("%s, %s\n", PACKAGE, VERSION); return 0; } @@ -69,37 +49,17 @@ int main(int argc, char *argv[]) return 1; } - if ((cmd = br_command_lookup(argv[1])) == NULL) { + if ((cmd = command_lookup(argv[1])) == NULL) { fprintf(stderr, "never heard of command [%s]\n", argv[1]); goto help; } - - argindex = 2; - br = NULL; - if (cmd->needs_bridge_argument) { - if (argindex >= argc) { - fprintf(stderr, "this option requires a bridge name as argument\n"); - return 1; - } - - br = br_find_bridge(argv[argindex]); - if (br == NULL) { - fprintf(stderr, "bridge %s doesn't exist?\n", argv[argindex]); - return 1; - } - - argindex++; - } - - if (argc - argindex != cmd->num_string_arguments) { + if (argc < cmd->nargs + 2) { fprintf(stderr, "incorrect number of arguments for command\n"); - return 1; + goto help; } - cmd->func(br, argv[argindex], argv[argindex+1]); - - return 0; + return cmd->func(++argv); help: help(); diff --git a/brctl/brctl.h b/brctl/brctl.h index 901b6ce..8fdd9ef 100644 --- a/brctl/brctl.h +++ b/brctl/brctl.h @@ -21,18 +21,19 @@ struct command { - int needs_bridge_argument; - int num_string_arguments; - char *name; - void (*func)(struct bridge *br, char *arg0, char *arg1); + int nargs; + const char *name; + int (*func)(char **argv); + const char *help; }; -struct command *br_command_lookup(char *cmd); +const struct command *command_lookup(const char *cmd); +void command_help(const struct command *); +void command_helpall(void); + void br_dump_bridge_id(const unsigned char *x); void br_show_timer(const struct timeval *tv); -void br_dump_interface_list(const struct bridge *br); -void br_dump_port_info(const struct port *p); -void br_dump_info(const struct bridge *br, - const struct bridge_info *bri); +void br_dump_interface_list(const char *br); +void br_dump_info(const char *br, const struct bridge_info *bri); #endif diff --git a/brctl/brctl_cmd.c b/brctl/brctl_cmd.c index 99d9725..f9da974 100644 --- a/brctl/brctl_cmd.c +++ b/brctl/brctl_cmd.c @@ -35,280 +35,291 @@ static int strtotimeval(struct timeval *tv, const char *time) return 0; } -void br_cmd_addbr(struct bridge *br, char *brname, char *arg1) +static int br_cmd_addbr(char** argv) { int err; - if ((err = br_add_bridge(brname)) == 0) - return; + switch (err = br_add_bridge(argv[1])) { + case 0: + return 0; - switch (err) { case EEXIST: fprintf(stderr, "device %s already exists; can't create " - "bridge with the same name\n", brname); - break; - + "bridge with the same name\n", argv[1]); + return 1; default: fprintf(stderr, "add bridge failed: %s\n", strerror(err)); - break; + return 1; } } -void br_cmd_delbr(struct bridge *br, char *brname, char *arg1) +static int br_cmd_delbr(char** argv) { int err; - if ((err = br_del_bridge(brname)) == 0) - return; + switch (err = br_del_bridge(argv[1])){ + case 0: + return 0; - switch (err) { case ENXIO: fprintf(stderr, "bridge %s doesn't exist; can't delete it\n", - brname); - break; + argv[1]); + return 1; case EBUSY: fprintf(stderr, "bridge %s is still up; can't delete it\n", - brname); - break; + argv[1]); + return 1; default: fprintf(stderr, "can't delete bridge %s: %s\n", - brname, strerror(err)); - break; + argv[1], strerror(err)); + return 1; } } -void br_cmd_addif(struct bridge *br, char *ifname, char *arg1) +static int br_cmd_addif(char** argv) { int err; - int ifindex; + int ifindex = if_nametoindex(argv[2]); - ifindex = if_nametoindex(ifname); if (!ifindex) { - fprintf(stderr, "interface %s does not exist!\n", ifname); - return; + fprintf(stderr, "interface %s does not exist!\n", argv[2]); + return 1; } - if ((err = br_add_interface(br, ifindex)) == 0) - return; + switch (err = br_add_interface(argv[1], ifindex)) { + case 0: + return 0; - switch (err) { case EBUSY: fprintf(stderr, "device %s is already a member of a bridge; " - "can't enslave it to bridge %s.\n", ifname, - br->ifname); - break; + "can't enslave it to bridge %s.\n", argv[2], + argv[1]); + return 1; case ELOOP: fprintf(stderr, "device %s is a bridge device itself; " "can't enslave a bridge device to a bridge device.\n", - ifname); - break; + argv[2]); + return 1; default: fprintf(stderr, "can't add %s to bridge %s: %s\n", - ifname, br->ifname, strerror(err)); - break; + argv[2], argv[1], strerror(err)); + return 1; } } -void br_cmd_delif(struct bridge *br, char *ifname, char *arg1) +static int br_cmd_delif(char** argv) { int err; - int ifindex; + int ifindex = if_nametoindex(argv[2]); - ifindex = if_nametoindex(ifname); if (!ifindex) { - fprintf(stderr, "interface %s does not exist!\n", ifname); - return; + fprintf(stderr, "interface %s does not exist!\n", argv[2]); + return 1; } - if ((err = br_del_interface(br, ifindex)) == 0) - return; + switch (err = br_del_interface(argv[1], ifindex)) { + case 0: + return 0; - switch (err) { case EINVAL: fprintf(stderr, "device %s is not a slave of %s\n", - ifname, br->ifname); - break; + argv[2], argv[1]); + return 1; default: fprintf(stderr, "can't delete %s from %s: %s\n", - ifname, br->ifname, strerror(err)); - break; + argv[2], argv[1], strerror(err)); + return 1; } } -void br_cmd_setageing(struct bridge *br, char *time, char *arg1) +static int br_cmd_setageing(char** argv) { int err; struct timeval tv; - - if (strtotimeval(&tv, time)) { + + if (strtotimeval(&tv, argv[2])) { fprintf(stderr, "bad ageing time value\n"); - return; + return 1; } - err = br_set_ageing_time(br, &tv); + + err = br_set_ageing_time(argv[1], &tv); if (err) fprintf(stderr, "set ageing time failed: %s\n", strerror(err)); + + return err != 0; } -void br_cmd_setbridgeprio(struct bridge *br, char *_prio, char *arg1) +static int br_cmd_setbridgeprio(char** argv) { int prio; int err; - if (sscanf(_prio, "%i", &prio) != 1) { + if (sscanf(argv[2], "%i", &prio) != 1) { fprintf(stderr,"bad priority\n"); - return; + return 1; } - err = br_set_bridge_priority(br, prio); + + err = br_set_bridge_priority(argv[1], prio); if (err) fprintf(stderr, "set bridge priority failed: %s\n", strerror(err)); + return err != 0; } -void br_cmd_setfd(struct bridge *br, char *time, char *arg1) +static int br_cmd_setfd(char** argv) { struct timeval tv; int err; - if (strtotimeval(&tv, time)) { + if (strtotimeval(&tv, argv[2])) { fprintf(stderr, "bad forward delay value\n"); - return; + return 1; } - err = br_set_bridge_forward_delay(br, &tv); + err = br_set_bridge_forward_delay(argv[1], &tv); if (err) fprintf(stderr, "set forward delay failed: %s\n", strerror(err)); + + return err != 0; } -void br_cmd_sethello(struct bridge *br, char *time, char *arg1) +static int br_cmd_sethello(char** argv) { struct timeval tv; int err; - if (strtotimeval(&tv, time)) { + if (strtotimeval(&tv, argv[2])) { fprintf(stderr, "bad hello timer value\n"); - return; + return 1; } - err = br_set_bridge_hello_time(br, &tv); + err = br_set_bridge_hello_time(argv[1], &tv); if (err) fprintf(stderr, "set hello timer failed: %s\n", strerror(err)); + + return err != 0; } -void br_cmd_setmaxage(struct bridge *br, char *time, char *arg1) +static int br_cmd_setmaxage(char** argv) { struct timeval tv; int err; - if (strtotimeval(&tv, time)) { + if (strtotimeval(&tv, argv[2])) { fprintf(stderr, "bad max age value\n"); - return; + return 1; } - err = br_set_bridge_max_age(br, &tv); + err = br_set_bridge_max_age(argv[1], &tv); if (err) fprintf(stderr, "set max age failed: %s\n", strerror(err)); + + return err != 0; } -void br_cmd_setpathcost(struct bridge *br, char *arg0, char *arg1) +static int br_cmd_setpathcost(char** argv) { int cost, err; - struct port *p; - if (sscanf(arg1, "%i", &cost) != 1) { + if (sscanf(argv[3], "%i", &cost) != 1) { fprintf(stderr, "bad path cost value\n"); - return; - } - - if ((p = br_find_port(br, arg0)) == NULL) { - fprintf(stderr, "can't find port %s in bridge %s\n", arg0, br->ifname); - return; + return 1; } - err = br_set_path_cost(p, cost); + err = br_set_path_cost(argv[1], argv[2], cost); if (err) fprintf(stderr, "set path cost failed: %s\n", strerror(err)); + return err != 0; } -void br_cmd_setportprio(struct bridge *br, char *arg0, char *arg1) +static int br_cmd_setportprio(char** argv) { int cost, err; - struct port *p; - if (sscanf(arg1, "%i", &cost) != 1) { + if (sscanf(argv[3], "%i", &cost) != 1) { fprintf(stderr, "bad path priority value\n"); - return; + return 1; } - if ((p = br_find_port(br, arg0)) == NULL) { - fprintf(stderr, "can't find port %s in bridge %s\n", arg0, br->ifname); - return; - } - err = br_set_port_priority(p, cost); + err = br_set_path_cost(argv[1], argv[2], cost); if (err) fprintf(stderr, "set port priority failed: %s\n", - strerror(err)); + strerror(errno)); + + return err != 0; } -void br_cmd_stp(struct bridge *br, char *arg0, char *arg1) +static int br_cmd_stp(char** argv) { int stp, err; - if (!strcmp(arg0, "on") || !strcmp(arg0, "yes") - || !strcmp(arg0, "1")) + if (!strcmp(argv[2], "on") || !strcmp(argv[2], "yes") + || !strcmp(argv[2], "1")) stp = 1; - else if (!strcmp(arg0, "off") || !strcmp(arg0, "no") - || !strcmp(arg0, "0")) + else if (!strcmp(argv[2], "off") || !strcmp(argv[2], "no") + || !strcmp(argv[2], "0")) stp = 0; else { fprintf(stderr, "expect on/off for argument\n"); - return; + return 1; } - err = br_set_stp_state(br, stp); + err = br_set_stp_state(argv[1], stp); if (err) - fprintf(stderr, "set stp status failed: %d\n", err); + fprintf(stderr, "set stp status failed: %s\n", + strerror(errno)); + return err != 0; } -void br_cmd_showstp(struct bridge *br, char *arg0, char *arg1) +static int br_cmd_showstp(char** argv) { struct bridge_info info; - if (br_get_bridge_info(br, &info)) { - fprintf(stderr, "%s: can't get info %s\n", br->ifname, + if (br_get_bridge_info(argv[1], &info)) { + fprintf(stderr, "%s: can't get info %s\n", argv[1], strerror(errno)); - return; + return 1; } - br_dump_info(br, &info); + + br_dump_info(argv[1], &info); + return 0; } -void br_cmd_show(struct bridge *br, char *arg0, char *arg1) +static int show_bridge(const char *name, void *arg) { struct bridge_info info; - printf("bridge name\tbridge id\t\tSTP enabled\tinterfaces\n"); - for (br = bridge_list; br; br = br->next) { - printf("%s\t\t", br->ifname); - if (br_get_bridge_info(br, &info)) { - fprintf(stderr, "can't get info %s\n", + printf("%s\t\t", name); + fflush(stdout); + + if (br_get_bridge_info(name, &info)) { + fprintf(stderr, "can't get info %s\n", strerror(errno)); - continue; - } + return 1; + } - br_dump_bridge_id((unsigned char *)&info.bridge_id); - printf("\t%s\t\t", info.stp_enabled?"yes":"no"); - br_dump_interface_list(br); + br_dump_bridge_id((unsigned char *)&info.bridge_id); + printf("\t%s\t\t", info.stp_enabled?"yes":"no"); - } + br_dump_interface_list(name); + return 0; +} + +static int br_cmd_show(char** argv) +{ + printf("bridge name\tbridge id\t\tSTP enabled\tinterfaces\n"); + br_foreach_bridge(show_bridge, NULL); + return 0; } static int compare_fdbs(const void *_f0, const void *_f1) @@ -319,75 +330,101 @@ static int compare_fdbs(const void *_f0, const void *_f1) return memcmp(f0->mac_addr, f1->mac_addr, 6); } -static void __dump_fdb_entry(const struct fdb_entry *f) -{ - printf("%3i\t", f->port_no); - printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\t", - f->mac_addr[0], f->mac_addr[1], f->mac_addr[2], - f->mac_addr[3], f->mac_addr[4], f->mac_addr[5]); - printf("%s\t\t", f->is_local?"yes":"no"); - br_show_timer(&f->ageing_timer_value); - printf("\n"); -} - -void br_cmd_showmacs(struct bridge *br, char *arg0, char *arg1) +static int br_cmd_showmacs(char** argv) { - struct fdb_entry fdb[1024]; - int offset; - - printf("port no\tmac addr\t\tis local?\tageing timer\n"); - - offset = 0; - while (1) { - int i; - int num; - - num = br_read_fdb(br, fdb, offset, 1024); - if (num < 0) { - fprintf(stderr, "read of forward table failed\n"); - break; + const char *brname = argv[1]; +#define CHUNK 128 + int i, n; + struct fdb_entry *fdb = NULL; + int offset = 0; + + for(;;) { + fdb = realloc(fdb, (offset + CHUNK) * sizeof(struct fdb_entry)); + if (!fdb) { + fprintf(stderr, "Out of memory\n"); + return 1; } - - if (!num) + + n = br_read_fdb(brname, fdb+offset, offset, CHUNK); + if (n == 0) break; - - qsort(fdb, num, sizeof(struct fdb_entry), compare_fdbs); - for (i=0;i<num;i++) - __dump_fdb_entry(fdb+i); + if (n < 0) { + fprintf(stderr, "read of forward table failed: %s\n", + strerror(errno)); + return 1; + } + + offset += n; + } + + qsort(fdb, offset, sizeof(struct fdb_entry), compare_fdbs); - offset += num; + printf("port no\tmac addr\t\tis local?\tageing timer\n"); + for (i = 0; i < offset; i++) { + const struct fdb_entry *f = fdb + i; + printf("%3i\t", f->port_no); + printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\t", + f->mac_addr[0], f->mac_addr[1], f->mac_addr[2], + f->mac_addr[3], f->mac_addr[4], f->mac_addr[5]); + printf("%s\t\t", f->is_local?"yes":"no"); + br_show_timer(&f->ageing_timer_value); + printf("\n"); } + return 0; } -static struct command commands[] = { - {0, 1, "addbr", br_cmd_addbr}, - {1, 1, "addif", br_cmd_addif}, - {0, 1, "delbr", br_cmd_delbr}, - {1, 1, "delif", br_cmd_delif}, - {1, 1, "setageing", br_cmd_setageing}, - {1, 1, "setbridgeprio", br_cmd_setbridgeprio}, - {1, 1, "setfd", br_cmd_setfd}, - {1, 1, "sethello", br_cmd_sethello}, - {1, 1, "setmaxage", br_cmd_setmaxage}, - {1, 2, "setpathcost", br_cmd_setpathcost}, - {1, 2, "setportprio", br_cmd_setportprio}, - {0, 0, "show", br_cmd_show}, - {1, 0, "showmacs", br_cmd_showmacs}, - {1, 0, "showstp", br_cmd_showstp}, - {1, 1, "stp", br_cmd_stp}, +static const struct command commands[] = { + { 1, "addbr", br_cmd_addbr, "<bridge>\t\tadd bridge" }, + { 1, "delbr", br_cmd_delbr, "<bridge>\t\tdelete bridge" }, + { 2, "addif", br_cmd_addif, + "<bridge> <device>\tadd interface to bridge" }, + { 2, "delif", br_cmd_delif, + "<bridge> <device>\tdelete interface from bridge" }, + { 2, "setageing", br_cmd_setageing, + "<bridge> <time>\t\tset ageing time" }, + { 2, "setbridgeprio", br_cmd_setbridgeprio, + "<bridge> <prio>\t\tset bridge priority" }, + { 2, "setfd", br_cmd_setfd, + "<bridge> <time>\t\tset bridge forward delay" }, + { 2, "sethello", br_cmd_sethello, + "<bridge> <time>\t\tset hello time" }, + { 2, "setmaxage", br_cmd_setmaxage, + "<bridge> <time>\t\tset max message age" }, + { 3, "setpathcost", br_cmd_setpathcost, + "<bridge> <port> <cost>\tset path cost" }, + { 3, "setportprio", br_cmd_setportprio, + "<bridge> <port> <prio>\tset port priority" }, + { 0, "show", br_cmd_show, "\t\t\tshow a list of bridges" }, + { 1, "showmacs", br_cmd_showmacs, + "<bridge>\t\tshow a list of mac addrs"}, + { 1, "showstp", br_cmd_showstp, + "<bridge>\t\tshow bridge stp info"}, + { 1, "stp", br_cmd_stp, + "<bridge> <state>\tturn stp on/off" }, }; -struct command *br_command_lookup(char *cmd) +const struct command *command_lookup(const char *cmd) { int i; - int numcommands; - - numcommands = sizeof(commands)/sizeof(commands[0]); - for (i=0;i<numcommands;i++) + for (i = 0; i < sizeof(commands)/sizeof(commands[0]); i++) { if (!strcmp(cmd, commands[i].name)) return &commands[i]; + } return NULL; } + +void command_help(const struct command *cmd) +{ + printf("\t%-10s\t%s\n", cmd->name, cmd->help); +} + +void command_helpall(void) +{ + int i; + + for (i = 0; i < sizeof(commands)/sizeof(commands[0]); i++) + command_help(commands+i); +} diff --git a/brctl/brctl_disp.c b/brctl/brctl_disp.c index 9849f18..6eb72ca 100644 --- a/brctl/brctl_disp.c +++ b/brctl/brctl_disp.c @@ -33,37 +33,41 @@ void br_show_timer(const struct timeval *tv) printf("%4i.%.2i", (int)tv->tv_sec, (int)tv->tv_usec/10000); } -void br_dump_interface_list(const struct bridge *br) +static int first; + +static int dump_interface(const char *b, const char *p, int ind, void *arg) { - char ifname[IFNAMSIZ]; - struct port *p; - p = br->firstport; - if (p != NULL) { - printf("%s", if_indextoname(p->ifindex, ifname)); - p = p->next; - } - printf("\n"); + if (first) + first = 0; + else + printf("\n\t\t\t\t\t\t\t"); - while (p != NULL) { - printf("\t\t\t\t\t\t\t%s\n", if_indextoname(p->ifindex, ifname)); - p = p->next; - } + printf("%s", p); + + return 0; +} + +void br_dump_interface_list(const char *br) +{ + first = 1; + br_foreach_port(br, dump_interface, NULL); + printf("\n"); } -void br_dump_port_info(const struct port *p) +static int dump_port_info(const char *br, const char *p, int ifindex, + void *arg) { - char ifname[IFNAMSIZ]; struct port_info pinfo; - printf("%s (%i)\n", if_indextoname(p->ifindex, ifname), p->index); - if (br_get_port_info(p, &pinfo)) { + printf("%s (%i)\n", p, if_nametoindex(p)); + if (br_get_port_info(p, ifindex, &pinfo)) { printf(" can't get port info\n"); - return; + return 1; } printf(" port id\t\t%.4x\t\t\t", pinfo.port_id); - printf("state\t\t\t%s\n", br_get_state_name(pinfo.state)); + printf("state\t\t%15s\n", br_get_state_name(pinfo.state)); printf(" designated root\t"); br_dump_bridge_id((unsigned char *)&pinfo.designated_root); printf("\tpath cost\t\t%4i\n", pinfo.path_cost); @@ -85,18 +89,13 @@ void br_dump_port_info(const struct port *p) printf("TOPOLOGY_CHANGE_ACK "); printf("\n"); printf("\n"); + return 0; } -void br_dump_info(const struct bridge *br, const struct bridge_info *bri) +void br_dump_info(const char *br, const struct bridge_info *bri) { - const struct port *p; - - printf("%s\n", br->ifname); - if (!bri->stp_enabled) { - printf(" STP is disabled for this interface\n"); - return; - } + printf("%s\n", br); printf(" bridge id\t\t"); br_dump_bridge_id((unsigned char *)&bri->bridge_id); printf("\n designated root\t"); @@ -134,9 +133,5 @@ void br_dump_info(const struct bridge *br, const struct bridge_info *bri) printf("\n"); printf("\n"); - p = br->firstport; - while (p != NULL) { - br_dump_port_info(p); - p = p->next; - } + br_foreach_port(br, dump_port_info, NULL); } diff --git a/configure.in b/configure.in index 0ed11cc..53c0eac 100644 --- a/configure.in +++ b/configure.in @@ -1,5 +1,7 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT(brctl/brctl.c) +AC_CONFIG_HEADER(libbridge/config.h) +AM_INIT_AUTOMAKE(bridge-utils,1.0) AC_ARG_WITH( linux, [ --with-linux-headers Location of the linux headers to use], KERNEL_HEADERS=$withval, KERNEL_HEADERS="/usr/src/linux/include") @@ -22,6 +24,7 @@ AC_PROG_GCC_TRADITIONAL AC_FUNC_MEMCMP AC_CHECK_FUNCS(gethostname socket strdup uname) AC_CHECK_FUNCS(if_nametoindex if_indextoname) +AC_CHECK_LIB(sysfs, sysfs_open_directory) AC_SUBST(KERNEL_HEADERS) diff --git a/doc/Makefile b/doc/Makefile index 011b86e..8c57ff7 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -1,6 +1,6 @@ DESTDIR= -KERNEL_HEADERS=-I/usr/src/linux/include +KERNEL_HEADERS=-I/home/shemminger/bridge-2.6/include INSTALL=install -s diff --git a/libbridge/libbridge.h b/libbridge/libbridge.h index 503effc..b1e1fb5 100644 --- a/libbridge/libbridge.h +++ b/libbridge/libbridge.h @@ -22,12 +22,6 @@ #include <net/if.h> #include <linux/if_bridge.h> -struct bridge; -struct bridge_info; -struct fdb_entry; -struct port; -struct port_info; - struct bridge_id { unsigned char prio[2]; @@ -56,15 +50,6 @@ struct bridge_info struct timeval gc_timer_value; }; -struct bridge -{ - struct bridge *next; - - int ifindex; - char ifname[IFNAMSIZ]; - struct port *firstport; -}; - struct fdb_entry { u_int8_t mac_addr[6]; @@ -90,37 +75,35 @@ struct port_info struct timeval hold_timer_value; }; -struct port -{ - struct port *next; - int index; - int ifindex; - struct bridge *parent; -}; - -extern struct bridge *bridge_list; +extern int br_init(void); +extern int br_refresh(void); +extern void br_shutdown(void); -int br_init(void); -int br_refresh(void); -struct bridge *br_find_bridge(const char *brname); -struct port *br_find_port(struct bridge *br, const char *portname); -const char *br_get_state_name(int state); +extern int br_foreach_bridge(int (*iterator)(const char *brname, void *), + void *arg); +extern int br_foreach_port(const char *brname, + int (*iterator)(const char *brname, + const char *port, int ifindex, + void *), + void *arg); +extern const char *br_get_state_name(int state); -int br_get_bridge_info(const struct bridge *br, struct bridge_info *); -int br_get_port_info(const struct port *port, struct port_info *); -int br_get_version(void); -int br_add_bridge(const char *brname); -int br_del_bridge(const char *brname); -int br_add_interface(struct bridge *br, int ifindex); -int br_del_interface(struct bridge *br, int ifindex); -int br_set_bridge_forward_delay(struct bridge *br, struct timeval *tv); -int br_set_bridge_hello_time(struct bridge *br, struct timeval *tv); -int br_set_bridge_max_age(struct bridge *br, struct timeval *tv); -int br_set_ageing_time(struct bridge *br, struct timeval *tv); -int br_set_gc_interval(struct bridge *br, struct timeval *tv); -int br_set_stp_state(struct bridge *br, int stp_state); -int br_set_bridge_priority(struct bridge *br, int bridge_priority); -int br_set_port_priority(struct port *p, int port_priority); -int br_set_path_cost(struct port *p, int path_cost); -int br_read_fdb(struct bridge *br, struct fdb_entry *fdbs, int offset, int num); +extern int br_get_bridge_info(const char *br, struct bridge_info *); +extern int br_get_port_info(const char *port, int ifindex, struct port_info *); +extern int br_add_bridge(const char *brname); +extern int br_del_bridge(const char *brname); +extern int br_add_interface(const char *br, int ifindex); +extern int br_del_interface(const char *br, int ifindex); +extern int br_set_bridge_forward_delay(const char *br, struct timeval *tv); +extern int br_set_bridge_hello_time(const char *br, struct timeval *tv); +extern int br_set_bridge_max_age(const char *br, struct timeval *tv); +extern int br_set_ageing_time(const char *br, struct timeval *tv); +extern int br_set_stp_state(const char *br, int stp_state); +extern int br_set_bridge_priority(const char *br, int bridge_priority); +extern int br_set_port_priority(const char *br, const char *p, + int port_priority); +extern int br_set_path_cost(const char *br, const char *p, + int path_cost); +extern int br_read_fdb(const char *br, struct fdb_entry *fdbs, + unsigned long skip, int num); #endif diff --git a/libbridge/libbridge_devif.c b/libbridge/libbridge_devif.c index ef947b6..baf450b 100644 --- a/libbridge/libbridge_devif.c +++ b/libbridge/libbridge_devif.c @@ -16,142 +16,419 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include <stdio.h> #include <stdlib.h> +#include <unistd.h> #include <errno.h> #include <string.h> #include <sys/fcntl.h> -#include <linux/sockios.h> -#include <sys/ioctl.h> -#include <sys/time.h> #include "libbridge.h" #include "libbridge_private.h" -int br_device_ioctl(const struct bridge *br, unsigned long arg0, - unsigned long arg1, unsigned long arg2, unsigned long arg3) +#define dprintf(fmt,arg...) + +#ifdef HAVE_LIBSYSFS +/* Given two two character "0a" convert it to a byte */ +static unsigned char getoctet(const char *cp) { - unsigned long args[4]; - struct ifreq ifr; + char t[3] = { cp[0], cp[1], 0 }; + return strtoul(t, NULL, 16); +} - args[0] = arg0; - args[1] = arg1; - args[2] = arg2; - args[3] = arg3; +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]; - strncpy(ifr.ifr_name, br->ifname, IFNAMSIZ); - ((unsigned long *)(&ifr.ifr_data))[0] = (unsigned long)args; + if (!br_class_net) { + dprintf("can't find class_net\n"); + return NULL; + } -#ifdef SIOCBRDEV - /* New interface which allows 32bit/64 bit compatiability to work. */ - { int err = ioctl(br_socket_fd, SIOCBRDEV, &ifr); - if (err >= 0) - return err; + 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; } -#endif - /* Old fall back */ - return ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr); + + snprintf(path, SYSFS_PATH_MAX, "%s/%s", dev->path, subname); + sdir = sysfs_open_directory(path); + if (!sdir) + fprintf(stderr, "Can't open directory: %s\n", path); + return sdir; } -int br_add_interface(struct bridge *br, int ifindex) +static void fetch_id(struct sysfs_directory *sdir, char *name, + struct bridge_id *id) { - if (br_device_ioctl(br, BRCTL_ADD_IF, ifindex, 0, 0) < 0) - return errno; + struct sysfs_attribute *attr; - return 0; + memset(id, 0, sizeof(id)); + attr = sysfs_get_directory_attribute(sdir, name); + dprintf("fetch_id %s/%s = %s\n", sdir->path, name, + attr ? attr->value : "<null>\n"); + + if (!attr) { + fprintf(stderr, "Can't find attribute %s/%s\n", sdir->path, name); + return; + } + + if (strlen(attr->value) < 17) + fprintf(stderr, "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); + } } -int br_del_interface(struct bridge *br, int ifindex) +static void fetch_tv(struct sysfs_directory *sdir, char *name, + struct timeval *tv) { - if (br_device_ioctl(br, BRCTL_DEL_IF, ifindex, 0, 0) < 0) - return errno; + struct sysfs_attribute *attr + = sysfs_get_directory_attribute(sdir, name); - return 0; + if (!attr) { + fprintf(stderr, "Can't find attribute %s/%s\n", sdir->path, name); + memset(tv, 0, sizeof(tv)); + return; + } + + __jiffies_to_tv(tv, strtoul(attr->value, NULL, 0)); +} + +static int fetch_int(struct sysfs_directory *sdir, char *name) +{ + struct sysfs_attribute *attr + = sysfs_get_directory_attribute(sdir, name); + int val = 0; + + if (!attr) + fprintf(stderr, "Can't find attribute %s/%s\n", sdir->path, name); + else + val = strtol(attr->value, NULL, 0); + return val; } +#endif -int br_set_bridge_forward_delay(struct bridge *br, struct timeval *tv) +/* get information via ioctl */ +static int old_get_bridge_info(const char *bridge, struct bridge_info *info) { - unsigned long jif = __tv_to_jiffies(tv); + struct ifreq ifr; + struct __bridge_info i; + unsigned long args[4] = { BRCTL_GET_BRIDGE_INFO, + (unsigned long) &i, 0, 0 }; + + memset(info, 0, sizeof(*info)); + strncpy(ifr.ifr_name, bridge, IFNAMSIZ); + ifr.ifr_data = (char *) &args; - if (br_device_ioctl(br, BRCTL_SET_BRIDGE_FORWARD_DELAY, - jif, 0, 0) < 0) + if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) { + fprintf(stderr, "%s: can't get info %s\n", + bridge, strerror(errno)); return errno; + } + + memcpy(&info->designated_root, &i.designated_root, 8); + memcpy(&info->bridge_id, &i.bridge_id, 8); + info->root_path_cost = i.root_path_cost; + info->root_port = i.root_port; + info->topology_change = i.topology_change; + info->topology_change_detected = i.topology_change_detected; + info->stp_enabled = i.stp_enabled; + __jiffies_to_tv(&info->max_age, i.max_age); + __jiffies_to_tv(&info->hello_time, i.hello_time); + __jiffies_to_tv(&info->forward_delay, i.forward_delay); + __jiffies_to_tv(&info->bridge_max_age, i.bridge_max_age); + __jiffies_to_tv(&info->bridge_hello_time, i.bridge_hello_time); + __jiffies_to_tv(&info->bridge_forward_delay, i.bridge_forward_delay); + __jiffies_to_tv(&info->ageing_time, i.ageing_time); + __jiffies_to_tv(&info->hello_timer_value, i.hello_timer_value); + __jiffies_to_tv(&info->tcn_timer_value, i.tcn_timer_value); + __jiffies_to_tv(&info->topology_change_timer_value, + i.topology_change_timer_value); + __jiffies_to_tv(&info->gc_timer_value, i.gc_timer_value); return 0; } -int br_set_bridge_hello_time(struct bridge *br, struct timeval *tv) +int br_get_bridge_info(const char *bridge, struct bridge_info *info) { - unsigned long jif = __tv_to_jiffies(tv); - - if (br_device_ioctl(br, BRCTL_SET_BRIDGE_HELLO_TIME, jif, 0, 0) < 0) - return errno; +#ifndef HAVE_LIBSYSFS + return old_get_bridge_info(bridge, info); +#else + struct sysfs_directory *sdir; + + sdir = bridge_sysfs_directory(bridge, SYSFS_BRIDGE_ATTR); + if (!sdir) + return old_get_bridge_info(bridge,info); + + memset(info, 0, sizeof(*info)); + fetch_id(sdir, "root_id", &info->designated_root); + fetch_id(sdir, "bridge_id", &info->bridge_id); + info->root_path_cost = fetch_int(sdir, "root_path_cost"); + fetch_tv(sdir, "max_age", &info->max_age); + fetch_tv(sdir, "hello_time", &info->hello_time); + fetch_tv(sdir, "forward_delay", &info->forward_delay); + fetch_tv(sdir, "max_age", &info->bridge_max_age); + fetch_tv(sdir, "hello_time", &info->bridge_hello_time); + fetch_tv(sdir, "forward_delay", &info->bridge_forward_delay); + fetch_tv(sdir, "ageing_time", &info->ageing_time); + fetch_tv(sdir, "hello_timer", &info->hello_timer_value); + fetch_tv(sdir, "tcn_timer", &info->tcn_timer_value); + fetch_tv(sdir, "topology_change_timer", + &info->topology_change_timer_value);; + fetch_tv(sdir, "gc_timer", &info->gc_timer_value); + + info->root_port = fetch_int(sdir, "root_port"); + info->stp_enabled = fetch_int(sdir, "stp_state"); + info->topology_change = fetch_int(sdir, "topology_change"); + info->topology_change_detected = fetch_int(sdir, "topology_change_detected"); + sysfs_close_directory(sdir); return 0; +#endif } -int br_set_bridge_max_age(struct bridge *br, struct timeval *tv) +static int old_get_port_info(const char *port, int ifindex, struct port_info *info) { - unsigned long jif = __tv_to_jiffies(tv); + struct __port_info i; + struct ifreq ifr; + unsigned long args[4] = { BRCTL_GET_PORT_INFO, + (unsigned long) &i, ifindex, 0 }; + + memset(info, 0, sizeof(*info)); + strncpy(ifr.ifr_name, port, IFNAMSIZ); + ifr.ifr_data = (char *) &args; - if (br_device_ioctl(br, BRCTL_SET_BRIDGE_MAX_AGE, jif, 0, 0) < 0) + if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) { + fprintf(stderr, "can't get port %s(%d) info %s\n", + port, ifindex, strerror(errno)); return errno; + } + + + memcpy(&info->designated_root, &i.designated_root, 8); + memcpy(&info->designated_bridge, &i.designated_bridge, 8); + info->port_id = i.port_id; + info->designated_port = i.designated_port; + info->path_cost = i.path_cost; + info->designated_cost = i.designated_cost; + info->state = i.state; + info->top_change_ack = i.top_change_ack; + info->config_pending = i.config_pending; + __jiffies_to_tv(&info->message_age_timer_value, + i.message_age_timer_value); + __jiffies_to_tv(&info->forward_delay_timer_value, + i.forward_delay_timer_value); + __jiffies_to_tv(&info->hold_timer_value, i.hold_timer_value); + return 0; +} + +int br_get_port_info(const char *port, int ifindex, struct port_info *info) +{ +#ifndef HAVE_LIBSYSFS + return old_get_port_info(port, ifindex, info); +#else + struct sysfs_directory *sdir; + + sdir = bridge_sysfs_directory(port, SYSFS_BRIDGE_PORT_ATTR); + if (!sdir) + return old_get_port_info(port, ifindex, info); + + memset(info, 0, sizeof(*info)); + fetch_id(sdir, "designated_root", &info->designated_root); + fetch_id(sdir, "designated_bridge", &info->designated_bridge); + info->port_id = fetch_int(sdir, "port_id"); + info->designated_port = fetch_int(sdir, "designated_port"); + info->path_cost = fetch_int(sdir, "path_cost"); + info->designated_cost = fetch_int(sdir, "designated_cost"); + info->state = fetch_int(sdir, "state"); + info->top_change_ack = fetch_int(sdir, "change_ack"); + info->config_pending = fetch_int(sdir, "config_pending"); + fetch_tv(sdir, "message_age_timer", + &info->message_age_timer_value); + fetch_tv(sdir, "forward_delay_timer", + &info->forward_delay_timer_value); + fetch_tv(sdir, "hold_timer", + &info->hold_timer_value); + sysfs_close_directory(sdir); return 0; +#endif +} + +int br_add_interface(const char *bridge, int ifindex) +{ + struct ifreq ifr; + int err; + + strncpy(ifr.ifr_name, bridge, IFNAMSIZ); +#ifdef SIOCBRADDIF + ifr.ifr_ifindex = ifindex; + err = ioctl(br_socket_fd, SIOCBRADDIF, &ifr); + if (err < 0 && errno == EOPNOTSUPP) +#endif + { + unsigned long args[4] = { BRCTL_ADD_IF, ifindex, 0, 0 }; + + ifr.ifr_data = (char *) args; + err = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr); + } + + return err < 0 ? errno : 0; } -int br_set_ageing_time(struct bridge *br, struct timeval *tv) +int br_del_interface(const char *bridge, int ifindex) { - unsigned long jif = __tv_to_jiffies(tv); + struct ifreq ifr; + int err; + + strncpy(ifr.ifr_name, bridge, IFNAMSIZ); +#ifdef SIOCBRDELIF + ifr.ifr_ifindex = ifindex; + err = ioctl(br_socket_fd, SIOCBRDELIF, &ifr); + if (err < 0 && errno == EOPNOTSUPP) +#endif + { + unsigned long args[4] = { BRCTL_DEL_IF, ifindex, 0, 0 }; + + ifr.ifr_data = (char *) args; + err = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr); + } - if (br_device_ioctl(br, BRCTL_SET_AGEING_TIME, jif, 0, 0) < 0) - return errno; + return err < 0 ? errno : 0; +} - return 0; +static int br_set(const char *bridge, const char *name, + unsigned long value, unsigned long oldcode) +{ + int ret; +#ifdef HAVE_LIBSYSFS + struct sysfs_directory *sdir; + + sdir = bridge_sysfs_directory(bridge, SYSFS_BRIDGE_ATTR); + if (sdir) { + struct sysfs_attribute *attr; + char buf[32]; + sprintf(buf, "%ld", value); + + attr = sysfs_get_directory_attribute(sdir, (char *) name); + if (attr) + ret = sysfs_write_attribute(attr, buf, strlen(buf)); + else { + ret = -1; + errno = EINVAL; + } + sysfs_close_directory(sdir); + } 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; } -int br_set_gc_interval(struct bridge *br, struct timeval *tv) +int br_set_bridge_forward_delay(const char *br, struct timeval *tv) { - return 0; + return br_set(br, "forward_delay", __tv_to_jiffies(tv), + BRCTL_SET_BRIDGE_FORWARD_DELAY); } -int br_set_stp_state(struct bridge *br, int stp_state) +int br_set_bridge_hello_time(const char *br, struct timeval *tv) { - if (br_device_ioctl(br, BRCTL_SET_BRIDGE_STP_STATE, stp_state, - 0, 0) < 0) - return errno; + return br_set(br, "hello_time", __tv_to_jiffies(tv), + BRCTL_SET_BRIDGE_HELLO_TIME); +} - return 0; +int br_set_bridge_max_age(const char *br, struct timeval *tv) +{ + return br_set(br, "max_age", __tv_to_jiffies(tv), + BRCTL_SET_BRIDGE_MAX_AGE); } -int br_set_bridge_priority(struct bridge *br, int bridge_priority) +int br_set_ageing_time(const char *br, struct timeval *tv) { - if (br_device_ioctl(br, BRCTL_SET_BRIDGE_PRIORITY, bridge_priority, - 0, 0) < 0) - return errno; + return br_set(br, "ageing_time", __tv_to_jiffies(tv), + BRCTL_SET_AGEING_TIME); +} - return 0; +int br_set_stp_state(const char *br, int stp_state) +{ + return br_set(br, "stp_state", stp_state, BRCTL_SET_BRIDGE_STP_STATE); } -int br_set_port_priority(struct port *p, int port_priority) +int br_set_bridge_priority(const char *br, int bridge_priority) { - if (br_device_ioctl(p->parent, BRCTL_SET_PORT_PRIORITY, p->index, - port_priority, 0) < 0) - return errno; + return br_set(br, "priority", bridge_priority, + BRCTL_SET_BRIDGE_PRIORITY); +} - return 0; +static int port_set(const char *bridge, const char *ifname, + const char *name, unsigned long value, + unsigned long oldcode) +{ + int ret; +#ifdef HAVE_LIBSYSFS + struct sysfs_directory *sdir; + + sdir = bridge_sysfs_directory(ifname, SYSFS_BRIDGE_PORT_ATTR); + if (sdir) { + struct sysfs_attribute *attr; + char buf[32]; + + sprintf(buf, "%ld", value); + + attr = sysfs_get_directory_attribute(sdir, (char *) name); + if (attr) + ret = sysfs_write_attribute(attr, buf, strlen(buf)); + else { + ret = -1; + errno = EINVAL; + } + sysfs_close_directory(sdir); + } else +#endif + { + struct ifreq ifr; + int ifindex = if_nametoindex(ifname); + unsigned long args[4] = { oldcode, ifindex, value, 0 }; + + strncpy(ifr.ifr_name, bridge, IFNAMSIZ); + ifr.ifr_data = (char *) &args; + ret = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr); + } + return ret < 0 ? errno : 0; } -int br_set_path_cost(struct port *p, int path_cost) +int br_set_port_priority(const char *bridge, const char *port, int priority) { - if (br_device_ioctl(p->parent, BRCTL_SET_PATH_COST, p->index, - path_cost, 0) < 0) - return errno; + return port_set(bridge, port, "priority", priority, BRCTL_SET_PORT_PRIORITY); +} - return 0; +int br_set_path_cost(const char *bridge, const char *port, int cost) +{ + return port_set(bridge, port, "path_cost", cost, BRCTL_SET_PATH_COST); } -static void __copy_fdb(struct fdb_entry *ent, const struct __fdb_entry *f) +static inline void __copy_fdb(struct fdb_entry *ent, + const struct __fdb_entry *f) { memcpy(ent->mac_addr, f->mac_addr, 6); ent->port_no = f->port_no; @@ -159,25 +436,55 @@ static void __copy_fdb(struct fdb_entry *ent, const struct __fdb_entry *f) __jiffies_to_tv(&ent->ageing_timer_value, f->ageing_timer_value); } -int br_read_fdb(struct bridge *br, struct fdb_entry *fdbs, int offset, int num) +int br_read_fdb(const char *bridge, struct fdb_entry *fdbs, + unsigned long offset, int num) { - struct __fdb_entry f[num]; - int i; - int numread; - - again: - numread = br_device_ioctl(br, BRCTL_GET_FDB_ENTRIES, - (unsigned long)f, num, offset); - if (numread < 0) { - if (errno == EAGAIN) - goto again; + 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); + } - return -errno; + 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); + sleep(0); + if (n < 0 && errno == EAGAIN && ++retries < 10) + goto retry; } - for (i=0;i<numread;i++) - __copy_fdb(fdbs+i, f+i); + for (i = 0; i < n; i++) + __copy_fdb(fdbs+i, fe+i); - return numread; + if (fd > 0) + close(fd); + + return n; } - diff --git a/libbridge/libbridge_if.c b/libbridge/libbridge_if.c index 518d2b4..9eff89b 100644 --- a/libbridge/libbridge_if.c +++ b/libbridge/libbridge_if.c @@ -22,56 +22,46 @@ #include <string.h> #include <sys/fcntl.h> #include <sys/ioctl.h> -#include <sys/time.h> -#include <sys/utsname.h> + #include "libbridge.h" #include "libbridge_private.h" -int br_get_br(unsigned long arg0, unsigned long arg1, unsigned long arg2) -{ - unsigned long arg[3]; - - arg[0] = arg0; - arg[1] = arg1; - arg[2] = arg2; - - return ioctl(br_socket_fd, SIOCGIFBR, arg); -} - -int br_set_br(unsigned long arg0, unsigned long arg1, unsigned long arg2) -{ - unsigned long arg[3]; - - arg[0] = arg0; - arg[1] = arg1; - arg[2] = arg2; - - return ioctl(br_socket_fd, SIOCSIFBR, arg); -} - -int br_get_version(void) -{ - return br_get_br(BRCTL_GET_VERSION, 0, 0); -} int br_add_bridge(const char *brname) { - char _br[IFNAMSIZ]; + int ret; + +#ifdef SIOCBRADDBR + ret = ioctl(br_socket_fd, SIOCBRADDBR, brname); + if (ret < 0 && errno == -EOPNOTSUPP) +#endif + { + char _br[IFNAMSIZ]; + unsigned long arg[3] + = { BRCTL_ADD_BRIDGE, (unsigned long) _br }; - strncpy(_br, brname, IFNAMSIZ); - if (br_set_br(BRCTL_ADD_BRIDGE, (unsigned long)_br, 0) < 0) - return errno; + strncpy(_br, brname, IFNAMSIZ); + ret = ioctl(br_socket_fd, SIOCSIFBR, arg); + } - return 0; + return ret < 0 ? errno : 0; } int br_del_bridge(const char *brname) { - char _br[IFNAMSIZ]; + int ret; - strncpy(_br, brname, IFNAMSIZ); - if (br_set_br(BRCTL_DEL_BRIDGE, (unsigned long)_br, 0) < 0) - return errno; +#ifdef SIOCBRDELBR + ret = ioctl(br_socket_fd, SIOCBRDELBR, brname); + if (ret < 0 && errno == -EOPNOTSUPP) +#endif + { + char _br[IFNAMSIZ]; + unsigned long arg[3] + = { BRCTL_DEL_BRIDGE, (unsigned long) _br }; - return 0; + strncpy(_br, brname, IFNAMSIZ); + ret = ioctl(br_socket_fd, SIOCSIFBR, arg); + } + return ret < 0 ? errno : 0; } diff --git a/libbridge/libbridge_init.c b/libbridge/libbridge_init.c index d401250..2704f32 100644 --- a/libbridge/libbridge_init.c +++ b/libbridge/libbridge_init.c @@ -18,236 +18,245 @@ #include <stdio.h> #include <stdlib.h> +#include <unistd.h> #include <errno.h> #include <string.h> -#include <sys/fcntl.h> -#include <sys/ioctl.h> -#include <sys/time.h> + #include "libbridge.h" #include "libbridge_private.h" -#define MAX_BRIDGES 1024 /* arbitrary */ -#define MAX_PORTS 4096 +#define MAX_BRIDGES 1024 +#define MAX_PORTS 1024 -int br_socket_fd; -struct bridge *bridge_list; +#define dprintf(fmt,arg...) -static void __bridge_info_copy(struct bridge_info *info, - const struct __bridge_info *i) -{ - memcpy(&info->designated_root, &i->designated_root, 8); - memcpy(&info->bridge_id, &i->bridge_id, 8); - info->root_path_cost = i->root_path_cost; - info->topology_change = i->topology_change; - info->topology_change_detected = i->topology_change_detected; - info->root_port = i->root_port; - info->stp_enabled = i->stp_enabled; - __jiffies_to_tv(&info->max_age, i->max_age); - __jiffies_to_tv(&info->hello_time, i->hello_time); - __jiffies_to_tv(&info->forward_delay, i->forward_delay); - __jiffies_to_tv(&info->bridge_max_age, i->bridge_max_age); - __jiffies_to_tv(&info->bridge_hello_time, i->bridge_hello_time); - __jiffies_to_tv(&info->bridge_forward_delay, i->bridge_forward_delay); - __jiffies_to_tv(&info->ageing_time, i->ageing_time); - __jiffies_to_tv(&info->hello_timer_value, i->hello_timer_value); - __jiffies_to_tv(&info->tcn_timer_value, i->tcn_timer_value); - __jiffies_to_tv(&info->topology_change_timer_value, - i->topology_change_timer_value); - __jiffies_to_tv(&info->gc_timer_value, i->gc_timer_value); -} +int br_socket_fd = -1; +struct sysfs_class *br_class_net; - -int br_get_bridge_info(const struct bridge *br, struct bridge_info *info) +int br_init(void) { - struct __bridge_info i; - - if (br_device_ioctl(br, BRCTL_GET_BRIDGE_INFO, - (unsigned long )&i, 0, 0) < 0) { + if ((br_socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) return errno; - } - __bridge_info_copy(info, &i); + br_class_net = sysfs_open_class("net"); return 0; } -static void __port_info_copy(struct port_info *info, - const struct __port_info *i) +int br_refresh(void) { - memcpy(&info->designated_root, &i->designated_root, 8); - memcpy(&info->designated_bridge, &i->designated_bridge, 8); - info->port_id = i->port_id; - info->designated_port = i->designated_port; - info->path_cost = i->path_cost; - info->designated_cost = i->designated_cost; - info->state = i->state; - info->top_change_ack = i->top_change_ack; - info->config_pending = i->config_pending; - __jiffies_to_tv(&info->message_age_timer_value, - i->message_age_timer_value); - __jiffies_to_tv(&info->forward_delay_timer_value, - i->forward_delay_timer_value); - __jiffies_to_tv(&info->hold_timer_value, - i->hold_timer_value); + if (br_class_net) { + sysfs_close_class(br_class_net); + br_class_net = sysfs_open_class("net"); + } + + return 0; } -int br_get_port_info(const struct port *p, struct port_info *info) +void br_shutdown(void) { - struct __port_info i; + sysfs_close_class(br_class_net); + br_class_net = NULL; + close(br_socket_fd); + br_socket_fd = -1; +} - if (br_device_ioctl(p->parent, BRCTL_GET_PORT_INFO, - (unsigned long)&i, p->index, 0) < 0) { - fprintf(stderr, "%s: can't get port %d info %s\n", - p->parent->ifname, p->index, strerror(errno)); - return errno; - } - __port_info_copy(info, &i); +#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) +{ + char path[SYSFS_PATH_MAX]; - return 0; + snprintf(path, sizeof(path), "%s/bridge", dev->path); + return !sysfs_path_is_dir(path); } -static void br_nuke_bridge(struct bridge *b) +/* + * New interface uses sysfs to find bridges + */ +static int new_foreach_bridge(int (*iterator)(const char *name, void *), + void *arg) { - struct port *p, *n; + struct sysfs_class_device *dev; + struct dlist *devlist; + int count = 0; - for (p = b->firstport; p; p = n) { - n = p->next; - free(p); + if (!br_class_net) { + dprintf("no class /sys/class/net\n"); + return -EOPNOTSUPP; } - free(b); -} - -static int br_make_port_list(struct bridge *br) -{ - int i, cnt; - struct port *p, **top; - int *ifindices; - - ifindices = calloc(MAX_PORTS, sizeof(int)); - if (!ifindices) - return -ENOMEM; - - cnt = br_device_ioctl(br, BRCTL_GET_PORT_LIST, - (unsigned long)ifindices, - MAX_PORTS, 0); - if (cnt < 0) - return errno; + devlist = sysfs_get_class_devices(br_class_net); + if (!devlist) { + fprintf(stderr, "Can't read devices from sysfs\n"); + return -errno; + } - if (cnt == 0) - cnt = 256; /* old 2.4 compatiablity */ + dlist_for_each_data(devlist, dev, struct sysfs_class_device) { + if (isbridge(dev)) { + ++count; + if (iterator(dev->name, arg)) + break; + } + } - top = &br->firstport; - for (i = 0; i < cnt; i++) { - if (!ifindices[i]) - continue; + return count; +} +#endif - p = malloc(sizeof(struct port)); - if (!p) - goto nomem; +/* + * Old interface uses ioctl + */ +static int old_foreach_bridge(int (*iterator)(const char *, void *), + void *iarg) +{ + int i, ret=0, num; + char ifname[IFNAMSIZ]; + int ifindices[MAX_BRIDGES]; + unsigned long args[3] = { BRCTL_GET_BRIDGES, + (unsigned long)ifindices, MAX_BRIDGES }; - p->next = NULL; - p->ifindex = ifindices[i]; - p->parent = br; - p->index = i; - *top = p; - top = &p->next; + num = ioctl(br_socket_fd, SIOCGIFBR, args); + dprintf("old_foreach_bridge num=%d\n", num); + if (num < 0) { + fprintf(stderr, "Get bridge indices failed: %s\n", + strerror(errno)); + return -errno; } - free(ifindices); - return 0; + for (i = 0; i < num; i++) { + if (!if_indextoname(ifindices[i], ifname)) { + fprintf(stderr, "get find name for ifindex %d\n", + ifindices[i]); + return -errno; + } - nomem: - p = br->firstport; - while (p) { - struct port *n = p->next; - free(p); - p = n; + ++ret; + if(iterator(ifname, iarg)) + break; + } - br->firstport = NULL; - free(ifindices); - return -ENOMEM; + return ret; + } -static struct bridge *new_bridge(int ifindex, const char *name) +/* + * Go over all bridges and call iterator function. + * if iterator returns non-zero then stop. + */ +int br_foreach_bridge(int (*iterator)(const char *, void *), + void *arg) { - struct bridge *br; - - br = malloc(sizeof(struct bridge)); - if (br) { - memset(br, 0, sizeof(struct bridge)); - br->ifindex = ifindex; - strncpy(br->ifname, name, IFNAMSIZ); - br->firstport = NULL; - } - return br; + int ret; +#ifdef HAVE_LIBSYSFS + + ret = new_foreach_bridge(iterator, arg); + if (ret <= 0) +#endif + ret = old_foreach_bridge(iterator, arg); + + return ret; } -static int br_make_bridge_list(void) +/* + * Only used if sysfs is not available. + */ +static int old_foreach_port(const char *brname, + int (*iterator)(const char *br, + const char *port, int ind, + void *arg), + void *arg) { - struct bridge *br; - int i, num; - int ifindices[MAX_BRIDGES]; + int i, err, count; + struct ifreq ifr; char ifname[IFNAMSIZ]; + int ifindices[MAX_PORTS]; + unsigned long args[4] = { BRCTL_GET_PORT_LIST, + (unsigned long)ifindices, MAX_PORTS, 0 }; - num = br_get_br(BRCTL_GET_BRIDGES, (unsigned long)ifindices, - MAX_BRIDGES); - if (num < 0) { - fprintf(stderr, "Get bridge indices failed: %s\n", - strerror(errno)); - return errno; - } + memset(ifindices, 0, sizeof(ifindices)); + strncpy(ifr.ifr_name, brname, IFNAMSIZ); + ifr.ifr_data = (char *) &args; - bridge_list = NULL; - for (i = 0; i < num; i++) { - if (!if_indextoname(ifindices[i], ifname)) - continue; - br = new_bridge(ifindices[i], ifname); - if (!br) /* ignore the problem could just be a race! */ + err = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr); + if (err < 0) + return -errno; + + count = 0; + for (i = 0; i < MAX_PORTS; i++) { + if (!ifindices[i]) continue; - if ( br_make_port_list(br)) { - free(br); + if (!if_indextoname(ifindices[i], ifname)) continue; - } - br->next = bridge_list; - bridge_list = br; + ++count; + if (iterator(brname, ifname, ifindices[i], arg)) + break; } - return 0; + return count; } + -int br_init() -{ - int err; - if ((br_socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) - return errno; - - if (br_get_version() != BRCTL_VERSION) { - fprintf(stderr, "bridge utilities not compatiable with kernel version\n"); - exit(1); +/* + * Iterate over all ports in bridge (using sysfs). + */ +int br_foreach_port(const char *brname, + int (*iterator)(const char *br, const char *port, + int ind, void *arg), + void *arg) +{ +#ifndef HAVE_LIBSYSFS + return old_foreach_port(brname, iterator, arg); +#else + 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))) + return -ENODEV; + + snprintf(path, sizeof(path), "%s/%s", + dev->path, SYSFS_BRIDGE_PORT_SUBDIR); + + dir = sysfs_open_directory(path); + if (!dir) { + /* no /sys/class/net/ethX/brif subdirectory + * either: old kernel, or not really a bridge + */ + err = old_foreach_port(brname, iterator, arg); + goto out1; } - if ((err = br_make_bridge_list()) != 0) - return err; + links = sysfs_get_dir_links(dir); + if (!links) { + err = -ENOSYS; + goto out2; + } - return 0; -} + err = 0; + dlist_for_each_data(links, plink, struct sysfs_link) { + int ifindex = if_nametoindex(plink->name); -int br_refresh() -{ - struct bridge *b; + if (!ifindex) { + dprintf("can't find ifindex for %s\n", plink->name); + continue; + } - b = bridge_list; - while (b != NULL) { - struct bridge *bnext; + ++err; + if (iterator(brname, plink->name, ifindex, arg)) + break; - bnext = b->next; - br_nuke_bridge(b); - b = bnext; } - - return br_make_bridge_list(); + out2: + sysfs_close_directory(dir); + out1: + return err; +#endif } diff --git a/libbridge/libbridge_misc.c b/libbridge/libbridge_misc.c index c19d2fc..b227185 100644 --- a/libbridge/libbridge_misc.c +++ b/libbridge/libbridge_misc.c @@ -24,26 +24,14 @@ #include "libbridge.h" #include "libbridge_private.h" -unsigned long __tv_to_jiffies(struct timeval *tv) -{ - unsigned long long jif; - - jif = 1000000ULL * tv->tv_sec + tv->tv_usec; - - return (HZ*jif)/1000000; -} -void __jiffies_to_tv(struct timeval *tv, unsigned long jiffies) -{ - unsigned long long tvusec; - - tvusec = (1000000ULL*jiffies)/HZ; - tv->tv_sec = tvusec/1000000; - tv->tv_usec = tvusec - 1000000 * tv->tv_sec; -} - -static const char *state_names[5] -= {"disabled", "listening", "learning", "forwarding", "blocking"}; +static const char *state_names[5] = { + [BR_STATE_DISABLED] = "disabled", + [BR_STATE_LISTENING] = "listening", + [BR_STATE_LEARNING] = "learning", + [BR_STATE_FORWARDING] = "forwarding", + [BR_STATE_BLOCKING] ="blocking", +}; const char *br_get_state_name(int state) { @@ -52,36 +40,3 @@ const char *br_get_state_name(int state) return "<INVALID STATE>"; } - -struct bridge *br_find_bridge(const char *brname) -{ - struct bridge *b; - - b = bridge_list; - while (b != NULL) { - if (!strcmp(b->ifname, brname)) - return b; - - b = b->next; - } - - return NULL; -} - - -struct port *br_find_port(struct bridge *br, const char *portname) -{ - int index; - struct port *p; - - index = if_nametoindex(portname); - if (index <= 0) - return NULL; - - for (p = br->firstport; p; p = p->next) { - if (p->ifindex == index) - return p; - } - - return NULL; -} diff --git a/libbridge/libbridge_private.h b/libbridge/libbridge_private.h index 98ded65..57d0233 100644 --- a/libbridge/libbridge_private.h +++ b/libbridge/libbridge_private.h @@ -19,16 +19,56 @@ #ifndef _LIBBRIDGE_PRIVATE_H #define _LIBBRIDGE_PRIVATE_H +#include "config.h" + +#include <linux/sockios.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <linux/if_bridge.h> #include <asm/param.h> +#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; }; + +static inline struct sysfs_class *sysfs_open_class(const char *name) +{ + return NULL; +} + +static inline void sysfs_close_class(struct sysfs_class *class) +{ +} +#endif + extern int br_socket_fd; +extern struct sysfs_class *br_class_net; + +static inline unsigned long __tv_to_jiffies(const struct timeval *tv) +{ + unsigned long long jif; + + jif = 1000000ULL * tv->tv_sec + tv->tv_usec; -void __jiffies_to_tv(struct timeval *tv, unsigned long jiffies); -unsigned long __tv_to_jiffies(struct timeval *tv); + return (HZ*jif)/1000000; +} -int br_get_br(unsigned long arg0, unsigned long arg1, unsigned long arg2); -int br_set_br(unsigned long arg0, unsigned long arg1, unsigned long arg2); -int br_device_ioctl(const struct bridge *br, unsigned long arg0, - unsigned long arg1, unsigned long arg2, unsigned long arg3); +static inline void __jiffies_to_tv(struct timeval *tv, unsigned long jiffies) +{ + unsigned long long tvusec; + tvusec = (1000000ULL*jiffies)/HZ; + tv->tv_sec = tvusec/1000000; + tv->tv_usec = tvusec - 1000000 * tv->tv_sec; +} #endif |