[git commit] brctl: convert remaining commands to work via /sys

Denys Vlasenko vda.linux at googlemail.com
Sat Apr 13 11:58:06 UTC 2019


commit: https://git.busybox.net/busybox/commit/?id=dc1b2d43565dee709229dd76d856736bf543792d
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
write_ulong                                            -      96     +96
show_bridge                                          310     338     +28
static.ops                                             3       -      -3
arm_ioctl                                             20       -     -20
packed_usage                                       33344   33315     -29
brctl_main                                           885     721    -164
------------------------------------------------------------------------------
(add/remove: 1/2 grow/shrink: 1/2 up/down: 124/-216)          Total: -92 bytes
   text	   data	    bss	    dec	    hex	filename
 982112	    485	   7296	 989893	  f1ac5	busybox_old
 982157	    485	   7296	 989938	  f1af2	busybox_unstripped

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 networking/brctl.c | 331 ++++++++++++++++++++++++-----------------------------
 1 file changed, 147 insertions(+), 184 deletions(-)

diff --git a/networking/brctl.c b/networking/brctl.c
index 706ecfc07..804728e3c 100644
--- a/networking/brctl.c
+++ b/networking/brctl.c
@@ -44,27 +44,31 @@
 //kbuild:lib-$(CONFIG_BRCTL) += brctl.o
 
 //usage:#define brctl_trivial_usage
-//usage:       "COMMAND [BRIDGE [INTERFACE]]"
+//usage:       "COMMAND [BRIDGE [ARGS]]"
 //usage:#define brctl_full_usage "\n\n"
 //usage:       "Manage ethernet bridges\n"
 //usage:     "\nCommands:"
 //usage:	IF_FEATURE_BRCTL_SHOW(
-//usage:     "\n	show			Show a list of bridges"
+//usage:     "\n	show [BRIDGE]...	Show bridges"
 //usage:	)
 //usage:     "\n	addbr BRIDGE		Create BRIDGE"
 //usage:     "\n	delbr BRIDGE		Delete BRIDGE"
 //usage:     "\n	addif BRIDGE IFACE	Add IFACE to BRIDGE"
 //usage:     "\n	delif BRIDGE IFACE	Delete IFACE from BRIDGE"
 //usage:	IF_FEATURE_BRCTL_FANCY(
-//usage:     "\n	setageing BRIDGE TIME		Set ageing time"
-//usage:     "\n	setfd BRIDGE TIME		Set bridge forward delay"
-//usage:     "\n	sethello BRIDGE TIME		Set hello time"
-//usage:     "\n	setmaxage BRIDGE TIME		Set max message age"
-//usage:     "\n	setpathcost BRIDGE COST		Set path cost"
-//usage:     "\n	setportprio BRIDGE PRIO		Set port priority"
+//usage:     "\n	stp BRIDGE 1/yes/on|0/no/off	STP on/off"
+//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"
+//usage:     "\n	setmaxage BRIDGE SECONDS	Set max message age"
 //usage:     "\n	setbridgeprio BRIDGE PRIO	Set bridge priority"
-//usage:     "\n	stp BRIDGE [1/yes/on|0/no/off]	STP on/off"
+//usage:     "\n	setportprio BRIDGE IFACE PRIO	Set port priority"
+//usage:     "\n	setpathcost BRIDGE IFACE COST	Set path cost"
 //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"
 #include "common_bufsiz.h"
@@ -84,69 +88,11 @@
 # define SIOCBRDELIF BRCTL_DEL_IF
 #endif
 
-
-/* Maximum number of ports supported per bridge interface.  */
-#ifndef MAX_PORTS
-# define MAX_PORTS 32
-#endif
-
 /* Use internal number parsing and not the "exact" conversion.  */
 /* #define BRCTL_USE_INTERNAL 0 */ /* use exact conversion */
 #define BRCTL_USE_INTERNAL 1
 
 #if ENABLE_FEATURE_BRCTL_FANCY
-/* #include <linux/if_bridge.h>
- * breaks on musl: we already included netinet/in.h in libbb.h,
- * if we include <linux/if_bridge.h> here, we get this:
- * In file included from /usr/include/linux/if_bridge.h:18,
- *                  from networking/brctl.c:67:
- * /usr/include/linux/in6.h:32: error: redefinition of 'struct in6_addr'
- * /usr/include/linux/in6.h:49: error: redefinition of 'struct sockaddr_in6'
- * /usr/include/linux/in6.h:59: error: redefinition of 'struct ipv6_mreq'
- */
-/* From <linux/if_bridge.h> */
-#define BRCTL_GET_VERSION 0
-#define BRCTL_GET_BRIDGES 1
-#define BRCTL_ADD_BRIDGE 2
-#define BRCTL_DEL_BRIDGE 3
-#define BRCTL_ADD_IF 4
-#define BRCTL_DEL_IF 5
-#define BRCTL_GET_BRIDGE_INFO 6
-#define BRCTL_GET_PORT_LIST 7
-#define BRCTL_SET_BRIDGE_FORWARD_DELAY 8
-#define BRCTL_SET_BRIDGE_HELLO_TIME 9
-#define BRCTL_SET_BRIDGE_MAX_AGE 10
-#define BRCTL_SET_AGEING_TIME 11
-#define BRCTL_SET_GC_INTERVAL 12
-#define BRCTL_GET_PORT_INFO 13
-#define BRCTL_SET_BRIDGE_STP_STATE 14
-#define BRCTL_SET_BRIDGE_PRIORITY 15
-#define BRCTL_SET_PORT_PRIORITY 16
-#define BRCTL_SET_PATH_COST 17
-#define BRCTL_GET_FDB_ENTRIES 18
-struct __bridge_info {
-	uint64_t designated_root;
-	uint64_t bridge_id;
-	uint32_t root_path_cost;
-	uint32_t max_age;
-	uint32_t hello_time;
-	uint32_t forward_delay;
-	uint32_t bridge_max_age;
-	uint32_t bridge_hello_time;
-	uint32_t bridge_forward_delay;
-	uint8_t  topology_change;
-	uint8_t  topology_change_detected;
-	uint8_t  root_port;
-	uint8_t  stp_enabled;
-	uint32_t ageing_time;
-	uint32_t gc_interval;
-	uint32_t hello_timer_value;
-	uint32_t tcn_timer_value;
-	uint32_t topology_change_timer_value;
-	uint32_t gc_timer_value;
-};
-/* end <linux/if_bridge.h> */
-
 /* FIXME: These 4 funcs are not really clean and could be improved */
 static ALWAYS_INLINE void bb_strtotimeval(struct timeval *tv,
 		const char *time_str)
@@ -188,18 +134,10 @@ static unsigned long str_to_jiffies(const char *time_str)
 	bb_strtotimeval(&tv, time_str);
 	return tv_to_jiffies(&tv);
 }
-
-static void arm_ioctl(unsigned long *args,
-		unsigned long arg0, unsigned long arg1, unsigned long arg2)
-{
-	args[0] = arg0;
-	args[1] = arg1;
-	args[2] = arg2;
-	args[3] = 0;
-}
 #endif
 
 #define filedata bb_common_bufsiz1
+
 static int read_file(const char *name)
 {
 	int n = open_read_close(name, filedata, COMMON_BUFSIZE - 1);
@@ -217,16 +155,21 @@ static int read_file(const char *name)
  */
 static int show_bridge(const char *name, int need_hdr)
 {
-// Output:
-//bridge name	bridge id		STP enabled	interfaces
-//br0		8000.000000000000	no		eth0
+/* Output:
+ *bridge name	bridge id		STP enabled	interfaces
+ *br0		8000.000000000000	no		eth0
+ */
 	char pathbuf[IFNAMSIZ + sizeof("/bridge/bridge_id") + 32];
 	int tabs;
 	DIR *ifaces;
 	struct dirent *ent;
 	char *sfx;
 
-	sfx = pathbuf + sprintf(pathbuf, "%s/bridge/", name);
+#if IFNAMSIZ == 16
+	sfx = pathbuf + sprintf(pathbuf, "%.16s/bridge/", name);
+#else
+	sfx = pathbuf + sprintf(pathbuf, "%.*s/bridge/", (int)IFNAMSIZ, name);
+#endif
 	strcpy(sfx, "bridge_id");
 	if (read_file(pathbuf) < 0)
 		return -1; /* this iface is not a bridge */
@@ -243,13 +186,15 @@ static int show_bridge(const char *name, int need_hdr)
 	else
 	if (LONE_CHAR(filedata, '1'))
 		strcpy(filedata, "yes");
-	printf(filedata);
+	fputs(filedata, stdout);
 
-	strcpy(sfx, "brif");
+	strcpy(sfx - (sizeof("bridge/")-1), "brif");
 	tabs = 0;
 	ifaces = opendir(pathbuf);
 	if (ifaces) {
 		while ((ent = readdir(ifaces)) != NULL) {
+			if (DOT_OR_DOTDOT(ent->d_name))
+				continue; /* . or .. */
 			if (tabs)
 				printf("\t\t\t\t\t");
 			else
@@ -263,6 +208,23 @@ static int show_bridge(const char *name, int need_hdr)
 	return 0;
 }
 
+static void write_ulong(const char *name, const char *leaf, unsigned long val)
+{
+	char pathbuf[IFNAMSIZ + sizeof("/bridge/bridge_id") + 32];
+	int fd, n;
+
+#if IFNAMSIZ == 16
+	sprintf(pathbuf, "%.16s/%s", name, leaf);
+#else
+	sprintf(pathbuf, "%.*s/%s", (int)IFNAMSIZ, name, leaf);
+#endif
+	fd = xopen(pathbuf, O_WRONLY);
+	n = sprintf(filedata, "%lu\n", val);
+	if (write(fd, filedata, n) < 0)
+		bb_simple_perror_msg_and_die(name);
+	close(fd);
+}
+
 int brctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int brctl_main(int argc UNUSED_PARAM, char **argv)
 {
@@ -271,24 +233,20 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
 	IF_FEATURE_BRCTL_FANCY(
 		"stp\0"
 		"setageing\0" "setfd\0" "sethello\0" "setmaxage\0"
-		"setpathcost\0" "setportprio\0" "setbridgeprio\0"
+		"setpathcost\0" "setportprio\0"
+		"setbridgeprio\0"
 	)
 	IF_FEATURE_BRCTL_SHOW("show\0");
-
 	enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif
 		IF_FEATURE_BRCTL_FANCY(,
 			ARG_stp,
 			ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage,
-			ARG_setpathcost, ARG_setportprio, ARG_setbridgeprio
+			ARG_setpathcost, ARG_setportprio,
+			ARG_setbridgeprio
 		)
 		IF_FEATURE_BRCTL_SHOW(, ARG_show)
 	};
 
-	int fd;
-	smallint key;
-	struct ifreq ifr;
-	char *br, *brif;
-
 	argv++;
 	if (!*argv) {
 		/* bare "brctl" shows --help */
@@ -297,12 +255,10 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
 
 	xchdir("/sys/class/net");
 
-	while (*argv) {
-#if ENABLE_FEATURE_BRCTL_FANCY
-		int ifidx[MAX_PORTS];
-		unsigned long args[4];
-		ifr.ifr_data = (char *) &args;
-#endif
+//	while (*argv)
+	{
+		smallint key;
+		char *br;
 
 		key = index_in_strings(keywords, *argv);
 		if (key == -1) /* no match found in keywords array, bail out. */
@@ -310,28 +266,28 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
 		argv++;
 
 #if ENABLE_FEATURE_BRCTL_SHOW
-		if (key == ARG_show) { /* show */
+		if (key == ARG_show) { /* show [BR]... */
 			DIR *net;
 			struct dirent *ent;
 			int need_hdr = 1;
 			int exitcode = EXIT_SUCCESS;
 
 			if (*argv) {
-				/* "brctl show BR1 BR2 BR3" */
+				/* "show BR1 BR2 BR3" */
 				do {
 					if (show_bridge(*argv, need_hdr) >= 0) {
 						need_hdr = 0;
 					} else {
 						bb_error_msg("bridge %s does not exist", *argv);
-//TODO: if device exists, but is not a BR, brctl from bridge-utils 1.6 says this instead:
-// "device eth0 is not a bridge"
+//TODO: if device exists, but is not a BR, brctl from bridge-utils 1.6
+//says this instead: "device eth0 is not a bridge"
 						exitcode = EXIT_FAILURE;
 					}
 				} while (*++argv != NULL);
 				return exitcode;
 			}
 
-			/* "brctl show" (if no ifaces, shows nothing, not even header) */
+			/* "show" (if no ifaces, shows nothing, not even header) */
 			net = xopendir(".");
 			while ((ent = readdir(net)) != NULL) {
 				if (DOT_OR_DOTDOT(ent->d_name))
@@ -339,7 +295,8 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
 				if (show_bridge(ent->d_name, need_hdr) >= 0)
 					need_hdr = 0;
 			}
-			closedir(net);
+			if (ENABLE_FEATURE_CLEAN_UP)
+				closedir(net);
 			return exitcode;
 		}
 #endif
@@ -347,33 +304,31 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
 		if (!*argv) /* all but 'show' need at least one argument */
 			bb_show_usage();
 
-		fd = xsocket(AF_INET, SOCK_STREAM, 0);
 		br = *argv++;
 
-//brctl from bridge-utils 1.6 also still uses ioctl
-//for SIOCBRADDBR / SIOCBRDELBR, not /sys accesses
-		if (key == ARG_addbr || key == ARG_delbr) { /* addbr or delbr */
+		if (key == ARG_addbr || key == ARG_delbr) {
+			/* addbr or delbr */
+			/* brctl from bridge-utils 1.6 still uses ioctl
+			 * for SIOCBRADDBR / SIOCBRDELBR, not /sys accesses
+			 */
+			int fd = xsocket(AF_INET, SOCK_STREAM, 0);
 			ioctl_or_perror_and_die(fd,
-					key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR,
-					br, "bridge %s", br);
-			goto done;
+				key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR,
+				br, "bridge %s", br
+			);
+			//close(fd);
+			//goto done;
+			/* bridge-utils 1.6 simply ignores trailing args:
+			 * "brctl addbr BR1 ARGS" ignores ARGS
+			 */
+			if (ENABLE_FEATURE_CLEAN_UP)
+				close(fd);
+			return EXIT_SUCCESS;
 		}
 
 		if (!*argv) /* all but 'addbr/delbr' need at least two arguments */
 			bb_show_usage();
 
-		strncpy_IFNAMSIZ(ifr.ifr_name, br);
-		if (key == ARG_addif || key == ARG_delif) { /* addif or delif */
-			brif = *argv;
-			ifr.ifr_ifindex = if_nametoindex(brif);
-			if (!ifr.ifr_ifindex) {
-				bb_perror_msg_and_die("iface %s", brif);
-			}
-			ioctl_or_perror_and_die(fd,
-					key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF,
-					&ifr, "bridge %s", br);
-			goto done_next_argv;
-		}
 #if ENABLE_FEATURE_BRCTL_FANCY
 		if (key == ARG_stp) { /* stp */
 			static const char no_yes[] ALIGN1 =
@@ -382,78 +337,86 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
 			int onoff = index_in_strings(no_yes, *argv);
 			if (onoff < 0)
 				bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name);
-//TODO: replace with:
-//write "0\n" or "1\n" to /sys/class/net/BR/bridge/stp_state
 			onoff = (unsigned)onoff / 4;
-			arm_ioctl(args, BRCTL_SET_BRIDGE_STP_STATE, onoff, 0);
-			goto fire;
+			write_ulong(br, "bridge/stp_state", onoff);
+			//goto done_next_argv;
+			return EXIT_SUCCESS;
 		}
+
 		if ((unsigned)(key - ARG_setageing) < 4) { /* time related ops */
-			static const uint8_t ops[] ALIGN1 = {
-				BRCTL_SET_AGEING_TIME,          /* ARG_setageing */
-				BRCTL_SET_BRIDGE_FORWARD_DELAY, /* ARG_setfd     */
-				BRCTL_SET_BRIDGE_HELLO_TIME,    /* ARG_sethello  */
-				BRCTL_SET_BRIDGE_MAX_AGE        /* ARG_setmaxage */
-			};
-//TODO: replace with:
-//setageing BR N: write "N*100\n" to /sys/class/net/BR/bridge/ageing_time
-//setfd BR N: write "N*100\n" to /sys/class/net/BR/bridge/forward_delay
-//sethello BR N: write "N*100\n" to /sys/class/net/BR/bridge/hello_time
-//setmaxage BR N: write "N*100\n" to /sys/class/net/BR/bridge/max_age
-			arm_ioctl(args, ops[key - ARG_setageing], str_to_jiffies(*argv), 0);
-			goto fire;
+			/* setageing BR N: "N*100\n" to /sys/class/net/BR/bridge/ageing_time
+			 * setfd BR N:     "N*100\n" to /sys/class/net/BR/bridge/forward_delay
+			 * sethello BR N:  "N*100\n" to /sys/class/net/BR/bridge/hello_time
+			 * setmaxage BR N: "N*100\n" to /sys/class/net/BR/bridge/max_age
+			 */
+			write_ulong(br,
+				nth_string(
+					"bridge/ageing_time"  "\0" /* ARG_setageing */
+					"bridge/forward_delay""\0" /* ARG_setfd     */
+					"bridge/hello_time"   "\0" /* ARG_sethello  */
+					"bridge/max_age",          /* ARG_setmaxage */
+					key - ARG_setageing
+				),
+				str_to_jiffies(*argv)
+			);
+			//goto done_next_argv;
+			return EXIT_SUCCESS;
+		}
+
+		if (key == ARG_setbridgeprio) {
+			write_ulong(br, "bridge/priority", xatoi_positive(*argv));
+			//goto done_next_argv;
+			return EXIT_SUCCESS;
 		}
+
 		if (key == ARG_setpathcost
 		 || key == ARG_setportprio
-		 || key == ARG_setbridgeprio
 		) {
-			static const uint8_t ops[] ALIGN1 = {
-				BRCTL_SET_PATH_COST,      /* ARG_setpathcost   */
-				BRCTL_SET_PORT_PRIORITY,  /* ARG_setportprio   */
-				BRCTL_SET_BRIDGE_PRIORITY /* ARG_setbridgeprio */
-			};
-			int port = -1;
-			unsigned arg1, arg2;
-
-//TODO: replace with:
-//setbridgeprio BR N: write "N\n" to /sys/class/net/BR/bridge/priority
-//setpathcost BR PORT N: ??
-//setportprio BR PORT N: ??
-
-			if (key != ARG_setbridgeprio) {
-				/* get portnum */
-				unsigned i;
-
-				port = if_nametoindex(*argv++);
-				if (!port)
-					bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, "port");
-				memset(ifidx, 0, sizeof ifidx);
-				arm_ioctl(args, BRCTL_GET_PORT_LIST, (unsigned long)ifidx,
-						MAX_PORTS);
-				xioctl(fd, SIOCDEVPRIVATE, &ifr);
-				for (i = 0; i < MAX_PORTS; i++) {
-					if (ifidx[i] == port) {
-						port = i;
-						break;
-					}
-				}
-			}
-			arg1 = port;
-			arg2 = xatoi_positive(*argv);
-			if (key == ARG_setbridgeprio) {
-				arg1 = arg2;
-				arg2 = 0;
-			}
-			arm_ioctl(args, ops[key - ARG_setpathcost], arg1, arg2);
+			if (!argv[1])
+				bb_show_usage();
+			/* BR is not used (and ignored!) for these commands:
+			 * "setpathcost BR PORT N" writes "N\n" to
+			 * /sys/class/net/PORT/brport/path_cost
+			 * "setportprio BR PORT N" writes "N\n" to
+			 * /sys/class/net/PORT/brport/priority
+			 */
+			write_ulong(argv[0],
+				nth_string(
+					"brport/path_cost" "\0" /* ARG_setpathcost */
+					"brport/priority",      /* ARG_setportprio */
+					key - ARG_setpathcost
+				),
+				xatoi_positive(argv[1])
+			);
+			//argv++;
+			//goto done_next_argv;
+			return EXIT_SUCCESS;
 		}
- fire:
-		/* Execute the previously set command */
-		xioctl(fd, SIOCDEVPRIVATE, &ifr);
 #endif
- done_next_argv:
-		argv++;
- done:
-		close(fd);
+		/* always true: if (key == ARG_addif || key == ARG_delif) */ {
+			/* addif or delif */
+			struct ifreq ifr;
+			int fd = xsocket(AF_INET, SOCK_STREAM, 0);
+
+			strncpy_IFNAMSIZ(ifr.ifr_name, br);
+			ifr.ifr_ifindex = if_nametoindex(*argv);
+			if (ifr.ifr_ifindex == 0) {
+				bb_perror_msg_and_die("iface %s", *argv);
+			}
+			ioctl_or_perror_and_die(fd,
+				key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF,
+				&ifr, "bridge %s", br
+			);
+			//close(fd);
+			//goto done_next_argv;
+			if (ENABLE_FEATURE_CLEAN_UP)
+				close(fd);
+			return EXIT_SUCCESS;
+		}
+
+// done_next_argv:
+//		argv++;
+// done:
 	}
 
 	return EXIT_SUCCESS;


More information about the busybox-cvs mailing list