[PATCH] brctl: Added support for showmacs command

Martin Lewis martin.lewis.x84 at gmail.com
Sun Sep 15 16:04:49 UTC 2019


Signed-off-by: Martin Lewis <martin.lewis.x84 at gmail.com>
---
 networking/brctl.c | 119 ++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 100 insertions(+), 19 deletions(-)

diff --git a/networking/brctl.c b/networking/brctl.c
index 586ca9b..35771a5 100644
--- a/networking/brctl.c
+++ b/networking/brctl.c
@@ -61,10 +61,10 @@
 //usage:     "\n	setbridgeprio BRIDGE PRIO	Set bridge priority"
 //usage:     "\n	setportprio BRIDGE IFACE PRIO	Set port priority"
 //usage:     "\n	setpathcost BRIDGE IFACE COST	Set path cost"
+//usage:     "\n	showmacs BRIDGE		List mac addrs"
 //usage:	)
 // Not yet implemented:
 //			hairpin BRIDGE IFACE on|off	Hairpin on/off
-//			showmacs BRIDGE			List mac addrs
 //			showstp	BRIDGE			Show stp info
 
 #include "libbb.h"
@@ -196,6 +196,94 @@ static void write_uint(const char *name, const char *leaf, unsigned val)
 		bb_simple_perror_msg_and_die(name);
 	close(fd);
 }
+
+struct __fdb_entry {
+	uint8_t mac_addr[6];
+	uint8_t port_no;
+	uint8_t is_local;
+	uint32_t ageing_timer_value;
+	uint8_t port_hi;
+	uint8_t pad0;
+	uint16_t unused;
+};
+
+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 read_bridge_forward_db(const char *name, struct __fdb_entry **_fdb, size_t *_nentries)
+{
+	struct __fdb_entry *fdb = NULL;
+	size_t nentries = 0;
+
+	char *path;
+	int fd;
+	ssize_t cc;
+
+	path = concat_path_file(name, "/brforward");
+	fd = open(path, O_RDONLY);
+	free(path);
+	if (fd < 0)
+		return -1;
+
+	for (;;) {
+		fdb = xrealloc(fdb, (nentries + 1) * sizeof(*fdb));
+		cc = full_read(fd, &fdb[nentries], sizeof(*fdb));
+		if (cc < 0) {
+			bb_perror_msg_and_die("can't read bridge %s forward db", name);
+		}
+		if (cc == 0) {
+			break;
+		}
+		++nentries;
+	}
+
+	close(fd);
+
+	qsort(fdb, nentries, sizeof(*fdb), compare_fdbs);
+
+	*_fdb = fdb;
+	*_nentries = nentries;
+	return 0;
+}
+
+static inline void show_bridge_timer(uint32_t ageing_timer)
+{
+	unsigned long long tvusec = 10000ULL * ageing_timer;
+	unsigned int tv_sec = tvusec / 1000000;
+	unsigned int tv_usec = tvusec - (1000000 * tv_sec);
+
+	printf("%4u.%.2u", tv_sec, tv_usec / 10000);
+}
+
+static int show_bridge_macs(const char *name)
+{
+	struct __fdb_entry *fdb;
+	size_t nentries;
+	size_t i;
+
+	if (read_bridge_forward_db(name, &fdb, &nentries) < 0)
+		return -1;
+
+	printf("port no\tmac addr\t\tis local?\tageing timer\n");
+	for (i = 0; i < nentries; ++i) {
+		const struct __fdb_entry *f = &fdb[i];
+		printf("%3u\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");
+		show_bridge_timer(f->ageing_timer_value);
+		printf("\n");
+	}
+
+	free(fdb);
+	return 0;
+}
 #endif
 
 int brctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -208,6 +296,7 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
 		"setageing\0" "setfd\0" "sethello\0" "setmaxage\0"
 		"setpathcost\0" "setportprio\0"
 		"setbridgeprio\0"
+		"showmacs\0"
 	)
 	IF_FEATURE_BRCTL_SHOW("show\0");
 	enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif
@@ -215,7 +304,8 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
 			ARG_stp,
 			ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage,
 			ARG_setpathcost, ARG_setportprio,
-			ARG_setbridgeprio
+			ARG_setbridgeprio,
+			ARG_showmacs
 		)
 		IF_FEATURE_BRCTL_SHOW(, ARG_show)
 	};
@@ -299,6 +389,14 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
 			return EXIT_SUCCESS;
 		}
 
+		if (key == ARG_showmacs) {
+			if (show_bridge_macs(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();
 
@@ -365,23 +463,6 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
 			//goto done_next_argv;
 			return EXIT_SUCCESS;
 		}
-
-/* TODO: "showmacs BR"
- *	port no\tmac addr\t\tis local?\tageing timer
- *	<sp><sp>1\txx:xx:xx:xx:xx:xx\tno\t\t<sp><sp><sp>1.31
- *	port no	mac addr		is local?	ageing timer
- *	  1	xx:xx:xx:xx:xx:xx	no		   1.31
- * Read fixed-sized records from /sys/class/net/BR/brforward:
- *	struct __fdb_entry {
- *		uint8_t  mac_addr[ETH_ALEN];
- *		uint8_t  port_no; //lsb
- *		uint8_t  is_local;
- *		uint32_t ageing_timer_value;
- *		uint8_t  port_hi;
- *		uint8_t  pad0;
- *		uint16_t unused;
- *	};
- */
 #endif
 		/* always true: if (key == ARG_addif || key == ARG_delif) */ {
 			/* addif or delif */
-- 
1.9.1



More information about the busybox mailing list