[PATCH] brctl: add support for showstp command
Martin Lewis
martin.lewis.x84 at gmail.com
Thu Oct 10 21:00:19 UTC 2019
Signed-off-by: Martin Lewis <martin.lewis.x84 at gmail.com>
---
networking/brctl.c | 217 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 216 insertions(+), 1 deletion(-)
diff --git a/networking/brctl.c b/networking/brctl.c
index ba5b6226f..cb55b0c90 100644
--- a/networking/brctl.c
+++ b/networking/brctl.c
@@ -54,6 +54,7 @@
//usage: "\n delif BRIDGE IFACE Delete IFACE from BRIDGE"
//usage: IF_FEATURE_BRCTL_FANCY(
//usage: "\n stp BRIDGE 1/yes/on|0/no/off STP on/off"
+//usage: "\n showstp BRIDGE Show stp info"
//usage: "\n setageing BRIDGE SECONDS Set ageing time"
//usage: "\n setfd BRIDGE SECONDS Set bridge forward delay"
//usage: "\n sethello BRIDGE SECONDS Set hello time"
@@ -65,11 +66,12 @@
//usage: )
// Not yet implemented:
// hairpin BRIDGE IFACE on|off Hairpin on/off
-// showstp BRIDGE Show stp info
+
#include "libbb.h"
#include "common_bufsiz.h"
#include <linux/sockios.h>
+#include <linux/if_bridge.h>
#include <net/if.h>
#ifndef SIOCBRADDBR
@@ -85,6 +87,22 @@
# define SIOCBRDELIF BRCTL_DEL_IF
#endif
+#ifndef BR_STATE_DISABLED
+# define BR_STATE_DISABLED 0
+#endif
+#ifndef BR_STATE_LISTENING
+# define BR_STATE_LISTENING 1
+#endif
+#ifndef BR_STATE_LEARNING
+# define BR_STATE_LEARNING 2
+#endif
+#ifndef BR_STATE_FORWARDING
+# define BR_STATE_FORWARDING 3
+#endif
+#ifndef BR_STATE_BLOCKING
+# define BR_STATE_BLOCKING 4
+#endif
+
#if ENABLE_FEATURE_BRCTL_FANCY
static unsigned str_to_jiffies(const char *time_str)
{
@@ -279,6 +297,194 @@ static void show_bridge_macs(const char *name)
free(fdb);
}
+
+static int read_leaf(const char *name, const char *node, const char *leaf)
+{
+ char *node_path = concat_path_file(name, node);
+ char *leaf_path = concat_path_file(node_path, leaf);
+ int r = read_file(leaf_path);
+ free(leaf_path);
+ free(node_path);
+ return r;
+}
+
+static void show_bridge_timer(unsigned long long timer)
+{
+ unsigned long long tvusec = 10000ULL * timer;
+ unsigned int tv_sec = tvusec / 1000000;
+ unsigned int tv_usec = tvusec - (1000000 * tv_sec);
+
+ printf("%4u.%.2u", tv_sec, tv_usec / 10000);
+}
+
+static const char *show_bridge_state(unsigned state)
+{
+ static const char *state_names[] = {
+ [BR_STATE_DISABLED] = "disabled",
+ [BR_STATE_LISTENING] = "listening",
+ [BR_STATE_LEARNING] = "learning",
+ [BR_STATE_FORWARDING] = "forwarding",
+ [BR_STATE_BLOCKING] = "blocking",
+ };
+
+ if (state >= 0 && state < ARRAY_SIZE(state_names))
+ return state_names[state];
+
+ return "<INVALID STATE>";
+}
+
+static void show_bridge_port(const char *name)
+{
+ read_leaf(name, "brport", "port_no");
+ printf("%s (%u)\n", name, xstrtou(filedata, 0));
+
+ read_leaf(name, "brport", "port_id");
+ printf(" port id\t\t%.4x", xstrtou(filedata, 0));
+
+ read_leaf(name, "brport", "state");
+ printf("\t\t\tstate\t\t%15s\n", show_bridge_state(xstrtou(filedata, 0)));
+
+ read_leaf(name, "brport", "designated_root");
+ printf(" designated root\t");
+ printf("%s", filedata);
+
+ read_leaf(name, "brport", "path_cost");
+ printf("\tpath cost\t\t%4u\n", xstrtou(filedata, 0));
+
+ read_leaf(name, "brport", "designated_bridge");
+ printf(" designated bridge\t");
+ printf("%s", filedata);
+
+ read_leaf(name, "brport", "message_age_timer");
+ printf("\tmessage age timer\t");
+ show_bridge_timer(xstrtoull(filedata, 0));
+
+ read_leaf(name, "brport", "designated_port");
+ printf("\n designated port\t%.4x", xstrtou(filedata, 0));
+
+ read_leaf(name, "brport", "forward_delay_timer");
+ printf("\t\t\tforward delay timer\t");
+ show_bridge_timer(xstrtoull(filedata, 0));
+
+ read_leaf(name, "brport", "designated_cost");
+ printf("\n designated cost\t%4u", xstrtou(filedata, 0));
+
+ read_leaf(name, "brport", "hold_timer");
+ printf("\t\t\thold timer\t\t");
+ show_bridge_timer(xstrtoull(filedata, 0));
+
+
+ printf("\n flags\t\t\t");
+ read_leaf(name, "brport", "config_pending");
+ if (!LONE_CHAR(filedata, '0'))
+ printf("CONFIG_PENDING ");
+
+ read_leaf(name, "brport", "change_ack");
+ if (!LONE_CHAR(filedata, '0'))
+ printf("TOPOLOGY_CHANGE_ACK ");
+
+ read_leaf(name, "brport", "hairpin_mode");
+ if (!LONE_CHAR(filedata, '0'))
+ printf("\n hairpin mode\t\t\%4u", xstrtou(filedata, 0));
+ printf("\n");
+ printf("\n");
+}
+
+static void show_bridge_ports(const char *name)
+{
+ char *dir_path;
+ DIR *ifaces;
+ struct dirent *ent;
+
+ dir_path = concat_path_file(name, "/brif");
+ ifaces = opendir(dir_path);
+ free(dir_path);
+ if (ifaces) {
+ while ((ent = readdir(ifaces)) != NULL) {
+ if (DOT_OR_DOTDOT(ent->d_name))
+ continue; /* . or .. */
+ show_bridge_port(ent->d_name);
+ }
+ closedir(ifaces);
+ }
+}
+
+static int show_bridge_stp(const char *name)
+{
+ if (read_leaf(name, "bridge", "bridge_id") < 0)
+ return -1;
+
+ printf("%s\n", name);
+ printf(" bridge id\t\t");
+ printf("%s", filedata);
+
+ printf("\n designated root\t");
+ read_leaf(name, "bridge", "root_id");
+ printf("%s", filedata);
+
+ read_leaf(name, "bridge", "root_port");
+ printf("\n root port\t\t%4u\t\t\t", xstrtou(filedata, 0));
+
+ read_leaf(name, "bridge", "root_path_cost");
+ printf("path cost\t\t%4u\n", xstrtou(filedata, 0));
+
+ printf(" max age\t\t");
+ read_leaf(name, "bridge", "max_age");
+ show_bridge_timer(xstrtoull(filedata, 0));
+
+ printf("\t\t\tbridge max age\t\t");
+ show_bridge_timer(xstrtoull(filedata, 0));
+
+ printf("\n hello time\t\t");
+ read_leaf(name, "bridge", "hello_time");
+ show_bridge_timer(xstrtoull(filedata, 0));
+
+ printf("\t\t\tbridge hello time\t");
+ show_bridge_timer(xstrtoull(filedata, 0));
+
+ printf("\n forward delay\t\t");
+ read_leaf(name, "bridge", "forward_delay");
+ show_bridge_timer(xstrtoull(filedata, 0));
+
+ printf("\t\t\tbridge forward delay\t");
+ show_bridge_timer(xstrtoull(filedata, 0));
+
+ printf("\n ageing time\t\t");
+ read_leaf(name, "bridge", "ageing_time");
+ show_bridge_timer(xstrtoull(filedata, 0));
+
+ printf("\n hello timer\t\t");
+ read_leaf(name, "bridge", "hello_timer");
+ show_bridge_timer(xstrtoull(filedata, 0));
+
+ printf("\t\t\ttcn timer\t\t");
+ read_leaf(name, "bridge", "tcn_timer");
+ show_bridge_timer(xstrtoull(filedata, 0));
+
+ printf("\n topology change timer\t");
+ read_leaf(name, "bridge", "topology_change_timer");
+ show_bridge_timer(xstrtoull(filedata, 0));
+
+ printf("\t\t\tgc timer\t\t");
+ read_leaf(name, "bridge", "gc_timer");
+ show_bridge_timer(xstrtoull(filedata, 0));
+
+ printf("\n flags\t\t\t");
+ read_leaf(name, "bridge", "topology_change");
+ if (!LONE_CHAR(filedata, '0'))
+ printf("TOPOLOGY_CHANGE ");
+
+ read_leaf(name, "bridge", "topology_change_detected");
+ if (!LONE_CHAR(filedata, '0'))
+ printf("TOPOLOGY_CHANGE_DETECTED ");
+ printf("\n");
+ printf("\n");
+ printf("\n");
+
+ show_bridge_ports(name);
+
+ return 0;
+}
#endif
int brctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -288,6 +494,7 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
"addbr\0" "delbr\0" "addif\0" "delif\0"
IF_FEATURE_BRCTL_FANCY(
"stp\0"
+ "showstp\0"
"setageing\0" "setfd\0" "sethello\0" "setmaxage\0"
"setpathcost\0" "setportprio\0"
"setbridgeprio\0"
@@ -297,6 +504,7 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif
IF_FEATURE_BRCTL_FANCY(,
ARG_stp,
+ ARG_showstp,
ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage,
ARG_setpathcost, ARG_setportprio,
ARG_setbridgeprio,
@@ -388,6 +596,13 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
show_bridge_macs(br);
return EXIT_SUCCESS;
}
+ if (key == ARG_showstp) {
+ if (show_bridge_stp(br) < 0) {
+ bb_error_msg("bridge %s does not exist", br);
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+ }
if (!*argv) /* all but 'addbr/delbr' need at least two arguments */
bb_show_usage();
--
2.11.0
More information about the busybox
mailing list