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 <[email protected]>
---
 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

_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to