[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