[PATCH] ifupdown: basic support for bridge_ports

Joachim Nilsson troglobit at gmail.com
Sat May 9 14:38:39 UTC 2020


This patch adds basic support for setting up bridges with ifupdown.
The implementation is limited to listing actual interfaces in the
bridge_ports attribute of a stanza in /etc/network/interace:

    iface br0 inet static
        address 192.168.1.1
	netmask 255.255.255.0
	bridge_ports lan0 lan1

The patch hooks on to the manual method callbacks, adding the bridge
interface if it's missing and removing it when taking it down.  Like
the bridge-utils-interfaces extension of ifupdown in Debian does.

The patch takes care to support ifconfig, ip link/addr and the brctl
tool depending on the BusyBox config.

Other bridge_ attributes, as well as regexp ifname matching for the
bridge_ports attribute can be added later.

Signed-off-by: Joachim Nilsson <troglobit at gmail.com>
---
 networking/ifupdown.c | 215 +++++++++++++++++++++++++++++++++++++-----
 1 file changed, 194 insertions(+), 21 deletions(-)

diff --git a/networking/ifupdown.c b/networking/ifupdown.c
index 60ceb5a1f..c4f20bec2 100644
--- a/networking/ifupdown.c
+++ b/networking/ifupdown.c
@@ -138,6 +138,7 @@
 //usage:     "\n	-v	Print out what would happen before doing it"
 //usage:     "\n	-f	Force deconfiguration"
 
+#include <stdarg.h>
 #include <net/if.h>
 #include "libbb.h"
 #include "common_bufsiz.h"
@@ -457,6 +458,142 @@ static int execute(const char *command, struct interface_defn_t *ifd, execfn *ex
 
 #endif /* FEATURE_IFUPDOWN_IPV4 || FEATURE_IFUPDOWN_IPV6 */
 
+#ifdef ENABLE_BRCTL
+/*
+ * Opportunistic write() to /proc or /sys
+ */
+static void write_procint(int val, const char *fmt, ...)
+{
+	va_list argp;
+	char fn[120];
+        int fd;
+
+	va_start(argp, fmt);
+	vsnprintf(fn, sizeof(fn), fmt, argp);
+	fd = open(fn, O_WRONLY);
+	va_end(argp);
+
+        if (fd >= 0) {
+		(void)write(fd, &val, sizeof(val));
+		close(fd);
+	}
+}
+
+static char *bridge_ports(struct interface_defn_t *ifd)
+{
+	char *ports = NULL;
+	int i;
+
+	for (i = 0; i < ifd->n_options; i++) {
+		if (strstr(ifd->option[i].name, "bridge_ports")) {
+			ports = ifd->option[i].value;
+			break;
+		}
+	}
+
+	return ports;
+}
+#endif
+
+/*
+ * Currently only 'none' and a list of interfaces are supported.
+ * Debian ifupdown also support the keyword  'all', 'regex foo',
+ * and combinations thereof; see bridge-utils-interfaces(5)
+ *
+ * Also, VLAN ports (eth0.1) are not supported yet.  A possibly
+ * better idea is to add support for the new-style bridge with
+ * 'bridge vlan add vid VID dev port [pvid]'
+ */
+static int bridge_up(struct interface_defn_t *ifd, execfn *exec)
+{
+#ifdef ENABLE_BRCTL
+	char *port, *ports = NULL;
+	int result = 0;
+
+	ports = bridge_ports(ifd);
+	if (!ports)
+		return 0;
+
+	if (!if_nametoindex(ifd->iface))
+		result += execute("brctl addbr %iface%", ifd, exec);
+
+# if ENABLE_FEATURE_IFUPDOWN_IP
+	result += execute("ip link set %iface% up", ifd, exec);
+# else
+	result += execute("ifconfig %iface% up", ifd, exec);
+# endif
+
+	if (!strcmp(ports, "none"))
+		return 0;
+
+	port = strtok(ports, " \t");
+	while (port) {
+		char buf[80];
+
+		snprintf(buf, sizeof(buf), "/sys/class/net/%s/brif/%s", ifd->iface, port);
+		if (access(buf, F_OK)) {
+			snprintf(buf, sizeof(buf), "brctl addif %%iface%% %s", port);
+			result += execute(buf, ifd, exec);
+			write_procint(1, "/proc/sys/net/ipv6/conf/%s/disable_ipv6", port);
+		}
+
+# if ENABLE_FEATURE_IFUPDOWN_IP
+		snprintf(buf, sizeof(buf), "ip link set %s up", port);
+# else
+		snprintf(buf, sizeof(buf), "ifconfig %s up", port);
+# endif
+		result += execute(buf, ifd, exec);
+
+		port = strtok(NULL, " \t");
+	}
+
+	return result;
+#else
+	return 0;
+#endif
+}
+
+static int bridge_down(struct interface_defn_t *ifd, execfn *exec)
+{
+#ifdef ENABLE_BRCTL
+	char *port, *ports = NULL;
+	int result = 0;
+
+	ports = bridge_ports(ifd);
+	if (!ports)
+		return 0;
+
+	if (!if_nametoindex(ifd->iface))
+		return 0;
+
+	port = strtok(ports, " \t");
+	while (port) {
+		char buf[80];
+
+		snprintf(buf, sizeof(buf), "/sys/class/net/%s/brif/%s", ifd->iface, port);
+		if (access(buf, F_OK)) {
+			snprintf(buf, sizeof(buf), "brctl delif %%iface%% %s", port);
+			result += execute(buf, ifd, exec);
+			write_procint(0, "/proc/sys/net/ipv6/conf/%s/disable_ipv6", port);
+		}
+
+# if ENABLE_FEATURE_IFUPDOWN_IP
+		snprintf(buf, sizeof(buf), "ip link set %s down", port);
+# else
+		snprintf(buf, sizeof(buf), "ifconfig %s down", port);
+# endif
+		result += execute(buf, ifd, exec);
+
+		port = strtok(NULL, " \t");
+	}
+
+	result += execute("brctl delbr %iface%", ifd, exec);
+
+	return result;
+#else
+	return 0;
+#endif
+}
 
 #if ENABLE_FEATURE_IFUPDOWN_IPV6
 
@@ -481,14 +618,22 @@ static int FAST_FUNC loopback_down6(struct interface_defn_t *ifd, execfn *exec)
 # endif
 }
 
-static int FAST_FUNC manual_up_down6(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM)
+static int FAST_FUNC manual_up6(struct interface_defn_t *ifd, execfn *exec)
 {
-	return 1;
+	return bridge_up(ifd, exec);
+}
+
+static int FAST_FUNC manual_down6(struct interface_defn_t *ifd, execfn *exec)
+{
+	return bridge_down(ifd, exec);
 }
 
 static int FAST_FUNC static_up6(struct interface_defn_t *ifd, execfn *exec)
 {
 	int result;
+
+	result = manual_up6(ifd, exec);
+
 # if ENABLE_FEATURE_IFUPDOWN_IP
 	result = execute("ip addr add %address%/%netmask% dev %iface%[[ label %label%]]", ifd, exec);
 	result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec);
@@ -504,13 +649,20 @@ static int FAST_FUNC static_up6(struct interface_defn_t *ifd, execfn *exec)
 
 static int FAST_FUNC static_down6(struct interface_defn_t *ifd, execfn *exec)
 {
+	int result = 0;
+
 	if (!if_nametoindex(ifd->iface))
 		return 1; /* already gone */
+
 # if ENABLE_FEATURE_IFUPDOWN_IP
-	return execute("ip link set %iface% down", ifd, exec);
+	result += execute("ip link set %iface% down", ifd, exec);
 # else
-	return execute("ifconfig %iface% down", ifd, exec);
+	result += execute("ifconfig %iface% down", ifd, exec);
 # endif
+
+	result += manual_down6(ifd, exec);
+
+	return result;
 }
 
 # if ENABLE_FEATURE_IFUPDOWN_IP
@@ -537,7 +689,7 @@ static const struct method_t methods6[] = {
 	{ "v4tunnel" , v4tunnel_up     , v4tunnel_down   , },
 # endif
 	{ "static"   , static_up6      , static_down6    , },
-	{ "manual"   , manual_up_down6 , manual_up_down6 , },
+	{ "manual"   , manual_up6      , manual_down6    , },
 	{ "loopback" , loopback_up6    , loopback_down6  , },
 };
 
@@ -576,25 +728,38 @@ static int FAST_FUNC loopback_down(struct interface_defn_t *ifd, execfn *exec)
 # endif
 }
 
+static int FAST_FUNC manual_up(struct interface_defn_t *ifd, execfn *exec)
+{
+	return bridge_up(ifd, exec);
+}
+
+static int FAST_FUNC manual_down(struct interface_defn_t *ifd, execfn *exec)
+{
+	return bridge_down(ifd, exec);
+}
+
 static int FAST_FUNC static_up(struct interface_defn_t *ifd, execfn *exec)
 {
 	int result;
+
+	result = manual_up(ifd, exec);
+
 # if ENABLE_FEATURE_IFUPDOWN_IP
-	result = execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] "
-			"dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec);
+	result += execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] "
+			  "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec);
 	result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec);
 	result += execute("[[ip route add default via %gateway% dev %iface%[[ metric %metric%]]]]", ifd, exec);
-	return ((result == 3) ? 3 : 0);
+	return ((result >= 3) ? 3 : 0);
 # else
 	/* ifconfig said to set iface up before it processes hw %hwaddress%,
 	 * which then of course fails. Thus we run two separate ifconfig */
-	result = execute("ifconfig %iface%[[ hw %hwaddress%]][[ media %media%]][[ mtu %mtu%]] up",
+	result += execute("ifconfig %iface%[[ hw %hwaddress%]][[ media %media%]][[ mtu %mtu%]] up",
 				ifd, exec);
 	result += execute("ifconfig %iface% %address% netmask %netmask%"
 				"[[ broadcast %broadcast%]][[ pointopoint %pointopoint%]]",
 				ifd, exec);
 	result += execute("[[route add default gw %gateway%[[ metric %metric%]] %iface%]]", ifd, exec);
-	return ((result == 3) ? 3 : 0);
+	return ((result >= 3) ? 3 : 0);
 # endif
 }
 
@@ -617,7 +782,9 @@ static int FAST_FUNC static_down(struct interface_defn_t *ifd, execfn *exec)
 	result = 1;
 	result += execute("ifconfig %iface% down", ifd, exec);
 # endif
-	return ((result == 2) ? 2 : 0);
+	result += manual_down(ifd, exec);
+
+	return ((result >= 2) ? 2 : 0);
 }
 
 # if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
@@ -652,6 +819,10 @@ static const struct dhcp_client_t ext_dhcp_clients[] = {
 static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd, execfn *exec)
 {
 	unsigned i;
+
+	/* Bring up interface, may be a bridge */
+	manual_up(ifd, exec);
+
 #  if ENABLE_FEATURE_IFUPDOWN_IP
 	/* ip doesn't up iface when it configures it (unlike ifconfig) */
 	if (!execute("ip link set[[ addr %hwaddress%]] %iface% up", ifd, exec))
@@ -671,6 +842,9 @@ static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd, execfn *exec)
 # elif ENABLE_UDHCPC
 static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd, execfn *exec)
 {
+	/* Bring up interface, may be a bridge */
+	manual_up(ifd, exec);
+
 #  if ENABLE_FEATURE_IFUPDOWN_IP
 	/* ip doesn't up iface when it configures it (unlike ifconfig) */
 	if (!execute("ip link set[[ addr %hwaddress%]] %iface% up", ifd, exec))
@@ -688,7 +862,7 @@ static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd, execfn *exec)
 static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd UNUSED_PARAM,
 		execfn *exec UNUSED_PARAM)
 {
-	return 0; /* no dhcp support */
+	return manual_up(ifd, exec); /* no dhcp support */
 }
 # endif
 
@@ -713,7 +887,9 @@ static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec)
 	   and it may come back up because udhcpc is still shutting down */
 	usleep(100000);
 	result += static_down(ifd, exec);
-	return ((result == 3) ? 3 : 0);
+	result += manual_down(ifd, exec);
+
+	return ((result >= 3) ? 3 : 0);
 }
 # elif ENABLE_UDHCPC
 static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec)
@@ -730,21 +906,18 @@ static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec)
 	   and it may come back up because udhcpc is still shutting down */
 	usleep(100000);
 	result += static_down(ifd, exec);
-	return ((result == 3) ? 3 : 0);
+	result += manual_down(ifd, exec);
+
+	return ((result >= 3) ? 3 : 0);
 }
 # else
 static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd UNUSED_PARAM,
 		execfn *exec UNUSED_PARAM)
 {
-	return 0; /* no dhcp support */
+	return manual_down(ifd, exec); /* no dhcp support */
 }
 # endif
 
-static int FAST_FUNC manual_up_down(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM)
-{
-	return 1;
-}
-
 static int FAST_FUNC bootp_up(struct interface_defn_t *ifd, execfn *exec)
 {
 	return execute("bootpc[[ --bootfile %bootfile%]] --dev %iface%"
@@ -775,7 +948,7 @@ static int FAST_FUNC wvdial_down(struct interface_defn_t *ifd, execfn *exec)
 }
 
 static const struct method_t methods[] = {
-	{ "manual"  , manual_up_down, manual_up_down, },
+	{ "manual"  , manual_up     , manual_down   , },
 	{ "wvdial"  , wvdial_up     , wvdial_down   , },
 	{ "ppp"     , ppp_up        , ppp_down      , },
 	{ "static"  , static_up     , static_down   , },
-- 
2.25.1



More information about the busybox mailing list