aboutsummaryrefslogtreecommitdiffstats
path: root/brctl
diff options
context:
space:
mode:
Diffstat (limited to 'brctl')
-rw-r--r--brctl/Makefile.in44
-rw-r--r--brctl/brctl.c87
-rw-r--r--brctl/brctl.h39
-rw-r--r--brctl/brctl_cmd.c493
-rw-r--r--brctl/brctl_disp.c148
5 files changed, 811 insertions, 0 deletions
diff --git a/brctl/Makefile.in b/brctl/Makefile.in
new file mode 100644
index 0000000..e1956d6
--- /dev/null
+++ b/brctl/Makefile.in
@@ -0,0 +1,44 @@
+
+KERNEL_HEADERS=-I@KERNEL_HEADERS@
+
+CC=@CC@
+CFLAGS= -Wall @CFLAGS@
+LDFLAGS=@LDFLAGS@
+INCLUDE=-I../libbridge $(KERNEL_HEADERS)
+LIBS= -L ../libbridge -lbridge @LIBS@
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+sbindir=@sbindir@
+mandir=@mandir@
+
+INSTALL=@INSTALL@
+
+
+common_SOURCES= brctl_cmd.c brctl_disp.c
+brctl_SOURCES= brctl.c $(common_SOURCES)
+
+common_OBJECTS= $(common_SOURCES:.c=.o)
+brctl_OBJECTS= $(brctl_SOURCES:.c=.o)
+
+OBJECTS= $(common_OBJECTS) $(brctl_OBJECTS)
+
+PROGRAMS= brctl
+
+
+all: $(PROGRAMS)
+
+install: $(PROGRAMS)
+ mkdir -p $(DESTDIR)$(sbindir)
+ $(INSTALL) -m 755 $(PROGRAMS) $(DESTDIR)$(sbindir)
+
+brctl: $(brctl_OBJECTS) ../libbridge/libbridge.a
+ $(CC) $(LDFLAGS) $(brctl_OBJECTS) $(LIBS) -o brctl
+
+%.o: %.c brctl.h
+ $(CC) $(CFLAGS) $(INCLUDE) -c $<
+
+clean:
+ rm -f *.o brctl core
+
diff --git a/brctl/brctl.c b/brctl/brctl.c
new file mode 100644
index 0000000..46ca352
--- /dev/null
+++ b/brctl/brctl.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/errno.h>
+#include <getopt.h>
+
+#include "libbridge.h"
+#include "config.h"
+
+#include "brctl.h"
+
+static void help()
+{
+ printf("Usage: brctl [commands]\n");
+ printf("commands:\n");
+ command_helpall();
+}
+
+int main(int argc, char *const* argv)
+{
+ const struct command *cmd;
+ int f;
+ static const struct option options[] = {
+ { .name = "help", .val = 'h' },
+ { .name = "version", .val = 'V' },
+ { 0 }
+ };
+
+ while ((f = getopt_long(argc, argv, "Vh", options, NULL)) != EOF)
+ switch(f) {
+ case 'h':
+ help();
+ return 0;
+ case 'V':
+ printf("%s, %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+ return 0;
+ default:
+ fprintf(stderr, "Unknown option '%c'\n", f);
+ goto help;
+ }
+
+ if (argc == optind)
+ goto help;
+
+ if (br_init()) {
+ fprintf(stderr, "can't setup bridge control: %s\n",
+ strerror(errno));
+ return 1;
+ }
+
+ argc -= optind;
+ argv += optind;
+ if ((cmd = command_lookup(*argv)) == NULL) {
+ fprintf(stderr, "never heard of command [%s]\n", *argv);
+ goto help;
+ }
+
+ if (argc < cmd->nargs + 1) {
+ printf("Incorrect number of arguments for command\n");
+ printf("Usage: brctl %s %s\n", cmd->name, cmd->help);
+ return 1;
+ }
+
+ return cmd->func(argc, argv);
+
+help:
+ help();
+ return 1;
+}
diff --git a/brctl/brctl.h b/brctl/brctl.h
new file mode 100644
index 0000000..55b7897
--- /dev/null
+++ b/brctl/brctl.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _BRCTL_H
+#define _BRCTL_H
+
+struct command
+{
+ int nargs;
+ const char *name;
+ int (*func)(int argc, char *const* argv);
+ const char *help;
+};
+
+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 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
new file mode 100644
index 0000000..b4ed104
--- /dev/null
+++ b/brctl/brctl_cmd.c
@@ -0,0 +1,493 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <asm/param.h>
+#include "libbridge.h"
+#include "brctl.h"
+
+static int strtotimeval(struct timeval *tv, const char *time)
+{
+ double secs;
+ if (sscanf(time, "%lf", &secs) != 1)
+ return -1;
+ tv->tv_sec = secs;
+ tv->tv_usec = 1000000 * (secs - tv->tv_sec);
+ return 0;
+}
+
+static int br_cmd_addbr(int argc, char*const* argv)
+{
+ int err;
+
+ switch (err = br_add_bridge(argv[1])) {
+ case 0:
+ return 0;
+
+ case EEXIST:
+ fprintf(stderr, "device %s already exists; can't create "
+ "bridge with the same name\n", argv[1]);
+ return 1;
+ default:
+ fprintf(stderr, "add bridge failed: %s\n",
+ strerror(err));
+ return 1;
+ }
+}
+
+static int br_cmd_delbr(int argc, char*const* argv)
+{
+ int err;
+
+ switch (err = br_del_bridge(argv[1])){
+ case 0:
+ return 0;
+
+ case ENXIO:
+ fprintf(stderr, "bridge %s doesn't exist; can't delete it\n",
+ argv[1]);
+ return 1;
+
+ case EBUSY:
+ fprintf(stderr, "bridge %s is still up; can't delete it\n",
+ argv[1]);
+ return 1;
+
+ default:
+ fprintf(stderr, "can't delete bridge %s: %s\n",
+ argv[1], strerror(err));
+ return 1;
+ }
+}
+
+static int br_cmd_addif(int argc, char *const* argv)
+{
+ const char *brname;
+ int err;
+
+ argc -= 2;
+ brname = *++argv;
+
+ while (argc-- > 0) {
+ const char *ifname = *++argv;
+ err = br_add_interface(brname, ifname);
+
+ switch(err) {
+ case 0:
+ continue;
+
+ case ENODEV:
+ if (if_nametoindex(ifname) == 0)
+ fprintf(stderr, "interface %s does not exist!\n", ifname);
+ else
+ fprintf(stderr, "bridge %s does not exist!\n", brname);
+ break;
+
+ case EBUSY:
+ fprintf(stderr, "device %s is already a member of a bridge; "
+ "can't enslave it to bridge %s.\n", ifname,
+ brname);
+ break;
+
+ case ELOOP:
+ fprintf(stderr, "device %s is a bridge device itself; "
+ "can't enslave a bridge device to a bridge device.\n",
+ ifname);
+ break;
+
+ default:
+ fprintf(stderr, "can't add %s to bridge %s: %s\n",
+ ifname, brname, strerror(err));
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static int br_cmd_delif(int argc, char *const* argv)
+{
+ const char *brname;
+ int err;
+
+ argc -= 2;
+ brname = *++argv;
+
+ while (argc-- > 0) {
+ const char *ifname = *++argv;
+ err = br_del_interface(brname, ifname);
+ switch (err) {
+ case 0:
+ continue;
+
+ case ENODEV:
+ if (if_nametoindex(ifname) == 0)
+ fprintf(stderr, "interface %s does not exist!\n", ifname);
+ else
+ fprintf(stderr, "bridge %s does not exist!\n", brname);
+ break;
+
+ case EINVAL:
+ fprintf(stderr, "device %s is not a slave of %s\n",
+ ifname, brname);
+ break;
+
+ default:
+ fprintf(stderr, "can't delete %s from %s: %s\n",
+ ifname, brname, strerror(err));
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static int br_cmd_setageing(int argc, char *const* argv)
+{
+ int err;
+ struct timeval tv;
+
+ if (strtotimeval(&tv, argv[2])) {
+ fprintf(stderr, "bad ageing time value\n");
+ return 1;
+ }
+
+ err = br_set_ageing_time(argv[1], &tv);
+ if (err)
+ fprintf(stderr, "set ageing time failed: %s\n",
+ strerror(err));
+
+ return err != 0;
+}
+
+static int br_cmd_setbridgeprio(int argc, char *const* argv)
+{
+ int prio;
+ int err;
+
+ if (sscanf(argv[2], "%i", &prio) != 1) {
+ fprintf(stderr,"bad priority\n");
+ return 1;
+ }
+
+ err = br_set_bridge_priority(argv[1], prio);
+ if (err)
+ fprintf(stderr, "set bridge priority failed: %s\n",
+ strerror(err));
+ return err != 0;
+}
+
+static int br_cmd_setfd(int argc, char *const* argv)
+{
+ struct timeval tv;
+ int err;
+
+ if (strtotimeval(&tv, argv[2])) {
+ fprintf(stderr, "bad forward delay value\n");
+ return 1;
+ }
+
+ err = br_set_bridge_forward_delay(argv[1], &tv);
+ if (err)
+ fprintf(stderr, "set forward delay failed: %s\n",
+ strerror(err));
+
+ return err != 0;
+}
+
+static int br_cmd_sethello(int argc, char *const* argv)
+{
+ struct timeval tv;
+ int err;
+
+ if (strtotimeval(&tv, argv[2])) {
+ fprintf(stderr, "bad hello timer value\n");
+ return 1;
+ }
+
+ err = br_set_bridge_hello_time(argv[1], &tv);
+ if (err)
+ fprintf(stderr, "set hello timer failed: %s\n",
+ strerror(err));
+
+ return err != 0;
+}
+
+static int br_cmd_setmaxage(int argc, char *const* argv)
+{
+ struct timeval tv;
+ int err;
+
+ if (strtotimeval(&tv, argv[2])) {
+ fprintf(stderr, "bad max age value\n");
+ return 1;
+ }
+ err = br_set_bridge_max_age(argv[1], &tv);
+ if (err)
+ fprintf(stderr, "set max age failed: %s\n",
+ strerror(err));
+
+ return err != 0;
+}
+
+static int br_cmd_setpathcost(int argc, char *const* argv)
+{
+ int cost, err;
+
+ if (sscanf(argv[3], "%i", &cost) != 1) {
+ fprintf(stderr, "bad path cost value\n");
+ return 1;
+ }
+
+ 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;
+}
+
+static int br_cmd_setportprio(int argc, char *const* argv)
+{
+ int cost, err;
+
+ if (sscanf(argv[3], "%i", &cost) != 1) {
+ fprintf(stderr, "bad path priority value\n");
+ return 1;
+ }
+
+ err = br_set_port_priority(argv[1], argv[2], cost);
+ if (err)
+ fprintf(stderr, "set port priority failed: %s\n",
+ strerror(errno));
+
+ return err != 0;
+}
+
+static int br_cmd_stp(int argc, char *const* argv)
+{
+ int stp, err;
+
+ if (!strcmp(argv[2], "on") || !strcmp(argv[2], "yes")
+ || !strcmp(argv[2], "1"))
+ stp = 1;
+ 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 1;
+ }
+
+ err = br_set_stp_state(argv[1], stp);
+ if (err)
+ fprintf(stderr, "set stp status failed: %s\n",
+ strerror(errno));
+ return err != 0;
+}
+
+static int br_cmd_showstp(int argc, char *const* argv)
+{
+ struct bridge_info info;
+
+ if (br_get_bridge_info(argv[1], &info)) {
+ fprintf(stderr, "%s: can't get info %s\n", argv[1],
+ strerror(errno));
+ return 1;
+ }
+
+ br_dump_info(argv[1], &info);
+ return 0;
+}
+
+static int show_bridge(const char *name, void *arg)
+{
+ struct bridge_info info;
+
+ printf("%s\t\t", name);
+ fflush(stdout);
+
+ if (br_get_bridge_info(name, &info)) {
+ fprintf(stderr, "can't get info %s\n",
+ strerror(errno));
+ 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(name);
+ return 0;
+}
+
+static int br_cmd_show(int argc, char *const* argv)
+{
+ int i;
+
+ printf("bridge name\tbridge id\t\tSTP enabled\tinterfaces\n");
+ if (argc == 1)
+ br_foreach_bridge(show_bridge, NULL);
+ else
+ for(i = 2; i <= argc; i++)
+ show_bridge(argv[i - 1], NULL);
+
+ return 0;
+}
+
+static int compare_fdbs(const void *_f0, const void *_f1)
+{
+ const struct fdb_entry *f0 = _f0;
+ const struct fdb_entry *f1 = _f1;
+
+ return memcmp(f0->mac_addr, f1->mac_addr, 6);
+}
+
+static int br_cmd_showmacs(int argc, char *const* argv)
+{
+ 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;
+ }
+
+ n = br_read_fdb(brname, fdb+offset, offset, CHUNK);
+ if (n == 0)
+ break;
+
+ 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);
+
+ 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 int br_cmd_hairpin(int argc, char *const* argv)
+{
+ int hairpin, err;
+ const char *brname = *++argv;
+ const char *ifname = *++argv;
+ const char *hpmode = *++argv;
+
+ if (!strcmp(hpmode, "on") || !strcmp(hpmode, "yes")
+ || !strcmp(hpmode, "1"))
+ hairpin = 1;
+ else if (!strcmp(hpmode, "off") || !strcmp(hpmode, "no")
+ || !strcmp(hpmode, "0"))
+ hairpin = 0;
+ else {
+ fprintf(stderr, "expect on/off for argument\n");
+ return 1;
+ }
+ if (if_nametoindex(ifname) == 0) {
+ fprintf(stderr, "interface %s does not exist!\n",
+ ifname);
+ return 1;
+ } else if (if_nametoindex(brname) == 0) {
+ fprintf(stderr, "bridge %s does not exist!\n",
+ brname);
+ return 1;
+ }
+
+ err = br_set_hairpin_mode(brname, ifname, hairpin);
+
+ if (err) {
+ fprintf(stderr, "can't set %s to hairpin on bridge %s: %s\n",
+ ifname, brname, strerror(err));
+ }
+ return err != 0;
+}
+
+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" },
+ { 3, "hairpin", br_cmd_hairpin,
+ "<bridge> <port> {on|off}\tturn hairpin on/off" },
+ { 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,
+ "[ <bridge> ]\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"},
+ { 2, "stp", br_cmd_stp,
+ "<bridge> {on|off}\tturn stp on/off" },
+};
+
+const struct command *command_lookup(const char *cmd)
+{
+ int i;
+
+ for (i = 0; i < sizeof(commands)/sizeof(commands[0]); i++) {
+ if (!strcmp(cmd, commands[i].name))
+ return &commands[i];
+ }
+
+ return NULL;
+}
+
+void command_helpall(void)
+{
+ int i;
+
+ for (i = 0; i < sizeof(commands)/sizeof(commands[0]); i++) {
+ printf("\t%-10s\t%s\n", commands[i].name, commands[i].help);
+ }
+}
diff --git a/brctl/brctl_disp.c b/brctl/brctl_disp.c
new file mode 100644
index 0000000..3e81241
--- /dev/null
+++ b/brctl/brctl_disp.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include "libbridge.h"
+#include "brctl.h"
+
+void br_dump_bridge_id(const unsigned char *x)
+{
+ printf("%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x", x[0], x[1], x[2], x[3],
+ x[4], x[5], x[6], x[7]);
+}
+
+void br_show_timer(const struct timeval *tv)
+{
+ printf("%4i.%.2i", (int)tv->tv_sec, (int)tv->tv_usec/10000);
+}
+
+static int first;
+
+static int dump_interface(const char *b, const char *p, void *arg)
+{
+
+ if (first)
+ first = 0;
+ else
+ printf("\n\t\t\t\t\t\t\t");
+
+ printf("%s", p);
+
+ return 0;
+}
+
+void br_dump_interface_list(const char *br)
+{
+ int err;
+
+ first = 1;
+ err = br_foreach_port(br, dump_interface, NULL);
+ if (err < 0)
+ printf(" can't get port info: %s\n", strerror(-err));
+ else
+ printf("\n");
+}
+
+static int dump_port_info(const char *br, const char *p, void *arg)
+{
+ struct port_info pinfo;
+
+ if (br_get_port_info(br, p, &pinfo)) {
+ printf("Can't get info for %p",p);
+ return 1;
+ }
+
+ printf("%s (%d)\n", p, pinfo.port_no);
+ printf(" port id\t\t%.4x", pinfo.port_id);
+ printf("\t\t\tstate\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);
+
+ printf(" designated bridge\t");
+ br_dump_bridge_id((unsigned char *)&pinfo.designated_bridge);
+ printf("\tmessage age timer\t");
+ br_show_timer(&pinfo.message_age_timer_value);
+ printf("\n designated port\t%.4x", pinfo.designated_port);
+ printf("\t\t\tforward delay timer\t");
+ br_show_timer(&pinfo.forward_delay_timer_value);
+ printf("\n designated cost\t%4i", pinfo.designated_cost);
+ printf("\t\t\thold timer\t\t");
+ br_show_timer(&pinfo.hold_timer_value);
+ printf("\n flags\t\t\t");
+ if (pinfo.config_pending)
+ printf("CONFIG_PENDING ");
+ if (pinfo.top_change_ack)
+ printf("TOPOLOGY_CHANGE_ACK ");
+ if (pinfo.hairpin_mode)
+ printf("\n hairpin mode\t\t\%4i", pinfo.hairpin_mode);
+ printf("\n");
+ printf("\n");
+ return 0;
+}
+
+void br_dump_info(const char *br, const struct bridge_info *bri)
+{
+ int err;
+
+ printf("%s\n", br);
+ printf(" bridge id\t\t");
+ br_dump_bridge_id((unsigned char *)&bri->bridge_id);
+ printf("\n designated root\t");
+ br_dump_bridge_id((unsigned char *)&bri->designated_root);
+ printf("\n root port\t\t%4i\t\t\t", bri->root_port);
+ printf("path cost\t\t%4i\n", bri->root_path_cost);
+ printf(" max age\t\t");
+ br_show_timer(&bri->max_age);
+ printf("\t\t\tbridge max age\t\t");
+ br_show_timer(&bri->bridge_max_age);
+ printf("\n hello time\t\t");
+ br_show_timer(&bri->hello_time);
+ printf("\t\t\tbridge hello time\t");
+ br_show_timer(&bri->bridge_hello_time);
+ printf("\n forward delay\t\t");
+ br_show_timer(&bri->forward_delay);
+ printf("\t\t\tbridge forward delay\t");
+ br_show_timer(&bri->bridge_forward_delay);
+ printf("\n ageing time\t\t");
+ br_show_timer(&bri->ageing_time);
+ printf("\n hello timer\t\t");
+ br_show_timer(&bri->hello_timer_value);
+ printf("\t\t\ttcn timer\t\t");
+ br_show_timer(&bri->tcn_timer_value);
+ printf("\n topology change timer\t");
+ br_show_timer(&bri->topology_change_timer_value);
+ printf("\t\t\tgc timer\t\t");
+ br_show_timer(&bri->gc_timer_value);
+ printf("\n flags\t\t\t");
+ if (bri->topology_change)
+ printf("TOPOLOGY_CHANGE ");
+ if (bri->topology_change_detected)
+ printf("TOPOLOGY_CHANGE_DETECTED ");
+ printf("\n");
+ printf("\n");
+ printf("\n");
+
+ err = br_foreach_port(br, dump_port_info, NULL);
+ if (err < 0)
+ printf("can't get ports: %s\n", strerror(-err));
+}