add more options for bridges, enable stp by default and set forwarding delay to 1
authorFelix Fietkau <nbd@openwrt.org>
Sun, 9 Oct 2011 20:30:16 +0000 (22:30 +0200)
committerFelix Fietkau <nbd@openwrt.org>
Sun, 9 Oct 2011 20:30:16 +0000 (22:30 +0200)
bridge.c
system-dummy.c
system-linux.c
system.h

index c3b02bd2d5ecdd5442498a0da0ffad0fc194dcb4..caf6197968d5022a8e18aac9dc00a6204dbce8fb 100644 (file)
--- a/bridge.c
+++ b/bridge.c
 enum {
        BRIDGE_ATTR_IFNAME,
        BRIDGE_ATTR_STP,
+       BRIDGE_ATTR_FORWARD_DELAY,
+       BRIDGE_ATTR_AGEING_TIME,
+       BRIDGE_ATTR_HELLO_TIME,
+       BRIDGE_ATTR_MAX_AGE,
        __BRIDGE_ATTR_MAX
 };
 
 static const struct blobmsg_policy bridge_attrs[__BRIDGE_ATTR_MAX] = {
        [BRIDGE_ATTR_IFNAME] = { "ifname", BLOBMSG_TYPE_ARRAY },
        [BRIDGE_ATTR_STP] = { "stp", BLOBMSG_TYPE_BOOL },
+       [BRIDGE_ATTR_FORWARD_DELAY] = { "forward_delay", BLOBMSG_TYPE_INT32 },
+       [BRIDGE_ATTR_AGEING_TIME] = { "ageing_time", BLOBMSG_TYPE_INT32 },
+       [BRIDGE_ATTR_HELLO_TIME] = { "hello_time", BLOBMSG_TYPE_INT32 },
+       [BRIDGE_ATTR_MAX_AGE] = { "max_age", BLOBMSG_TYPE_INT32 },
 };
 
 static const union config_param_info bridge_attr_info[__BRIDGE_ATTR_MAX] = {
@@ -52,6 +60,7 @@ struct bridge_state {
        struct device dev;
        device_state_cb set_state;
 
+       struct bridge_config config;
        struct blob_attr *ifnames;
        bool active;
 
@@ -166,7 +175,7 @@ bridge_set_up(struct bridge_state *bst)
        if (!bst->n_present)
                return -ENOENT;
 
-       ret = system_bridge_addbr(&bst->dev);
+       ret = system_bridge_addbr(&bst->dev, &bst->config);
        if (ret < 0)
                goto out;
 
@@ -322,6 +331,38 @@ bridge_config_init(struct device *dev)
        }
 }
 
+static void
+bridge_apply_settings(struct bridge_state *bst, struct blob_attr **tb)
+{
+       struct bridge_config *cfg = &bst->config;
+       struct blob_attr *cur;
+
+       /* defaults */
+       cfg->stp = true;
+       cfg->forward_delay = 1;
+
+       if ((cur = tb[BRIDGE_ATTR_STP]))
+               cfg->stp = blobmsg_get_bool(cur);
+
+       if ((cur = tb[BRIDGE_ATTR_FORWARD_DELAY]))
+               cfg->forward_delay = blobmsg_get_u32(cur);
+
+       if ((cur = tb[BRIDGE_ATTR_AGEING_TIME])) {
+               cfg->ageing_time = blobmsg_get_u32(cur);
+               cfg->flags |= BRIDGE_OPT_AGEING_TIME;
+       }
+
+       if ((cur = tb[BRIDGE_ATTR_HELLO_TIME])) {
+               cfg->hello_time = blobmsg_get_u32(cur);
+               cfg->flags |= BRIDGE_OPT_HELLO_TIME;
+       }
+
+       if ((cur = tb[BRIDGE_ATTR_MAX_AGE])) {
+               cfg->max_age = blobmsg_get_u32(cur);
+               cfg->flags |= BRIDGE_OPT_MAX_AGE;
+       }
+}
+
 static struct device *
 bridge_create(struct blob_attr *attr)
 {
@@ -353,6 +394,7 @@ bridge_create(struct blob_attr *attr)
        device_init_settings(dev, tb_dev);
        dev->config_pending = true;
        bst->ifnames = tb_br[BRIDGE_ATTR_IFNAME];
+       bridge_apply_settings(bst, tb_br);
 
        bst->set_state = dev->set_state;
        dev->set_state = bridge_set_state;
index d1557f9011aacddfb1ec6a91e9898f82f360efd6..9a646dcdb5fb85e5a6aea7ff651d2d20c5855577 100644 (file)
@@ -16,7 +16,7 @@ int system_init(void)
        return 0;
 }
 
-int system_bridge_addbr(struct device *bridge)
+int system_bridge_addbr(struct device *bridge, struct bridge_config *cfg)
 {
        D(SYSTEM, "brctl addbr %s\n", bridge->ifname);
        return 0;
index 725723dfbafc3a9a46539c29a9617ba448fbf198..b823099fc5da6fff6e215e6bcd8c016dd38cf6b3 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/sockios.h>
 #include <linux/if_vlan.h>
+#include <linux/if_bridge.h>
 
 #include <unistd.h>
 #include <string.h>
@@ -121,22 +122,25 @@ int system_bridge_delbr(struct device *bridge)
        return ioctl(sock_ioctl, SIOCBRDELBR, bridge->ifname);
 }
 
-static int system_bridge_if(const char *bridge, struct device *dev, int cmd)
+static int system_bridge_if(const char *bridge, struct device *dev, int cmd, void *data)
 {
        struct ifreq ifr;
-       ifr.ifr_ifindex = dev->ifindex;
+       if (dev)
+               ifr.ifr_ifindex = dev->ifindex;
+       else
+               ifr.ifr_data = data;
        strncpy(ifr.ifr_name, bridge, sizeof(ifr.ifr_name));
        return ioctl(sock_ioctl, cmd, &ifr);
 }
 
 int system_bridge_addif(struct device *bridge, struct device *dev)
 {
-       return system_bridge_if(bridge->ifname, dev, SIOCBRADDIF);
+       return system_bridge_if(bridge->ifname, dev, SIOCBRADDIF, NULL);
 }
 
 int system_bridge_delif(struct device *bridge, struct device *dev)
 {
-       return system_bridge_if(bridge->ifname, dev, SIOCBRDELIF);
+       return system_bridge_if(bridge->ifname, dev, SIOCBRDELIF, NULL);
 }
 
 static bool system_is_bridge(const char *name, char *buf, int buflen)
@@ -218,14 +222,51 @@ static void system_if_clear_state(struct device *dev)
        bridge = system_get_bridge(dev->ifname, buf, sizeof(buf));
        if (bridge) {
                D(SYSTEM, "Remove device '%s' from bridge '%s'\n", dev->ifname, bridge);
-               system_bridge_if(bridge, dev, SIOCBRDELIF);
+               system_bridge_if(bridge, dev, SIOCBRDELIF, NULL);
        }
 }
 
-int system_bridge_addbr(struct device *bridge)
+static inline unsigned long
+sec_to_jiffies(int val)
+{
+       return (unsigned long) val * 100;
+}
+
+int system_bridge_addbr(struct device *bridge, struct bridge_config *cfg)
 {
+       unsigned long args[4] = {};
+
        system_if_clear_state(bridge);
-       return ioctl(sock_ioctl, SIOCBRADDBR, bridge->ifname);
+       if (ioctl(sock_ioctl, SIOCBRADDBR, bridge->ifname) < 0)
+               return -1;
+
+       args[0] = BRCTL_SET_BRIDGE_STP_STATE;
+       args[1] = !!cfg->stp;
+       system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
+
+       args[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
+       args[1] = sec_to_jiffies(cfg->forward_delay);
+       system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
+
+       if (cfg->flags & BRIDGE_OPT_AGEING_TIME) {
+               args[0] = BRCTL_SET_AGEING_TIME;
+               args[1] = sec_to_jiffies(cfg->ageing_time);
+               system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
+       }
+
+       if (cfg->flags & BRIDGE_OPT_HELLO_TIME) {
+               args[0] = BRCTL_SET_BRIDGE_HELLO_TIME;
+               args[1] = sec_to_jiffies(cfg->hello_time);
+               system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
+       }
+
+       if (cfg->flags & BRIDGE_OPT_MAX_AGE) {
+               args[0] = BRCTL_SET_BRIDGE_MAX_AGE;
+               args[1] = sec_to_jiffies(cfg->max_age);
+               system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
+       }
+
+       return 0;
 }
 
 static int system_vlan(struct device *dev, int id)
index c9b28c8bed6a02f113c76fe2ce1ee4a9c56135ef..a2bcf044e96e469e1274b98c4d652a8f2ee6a4e9 100644 (file)
--- a/system.h
+++ b/system.h
@@ -5,9 +5,26 @@
 #include "device.h"
 #include "interface-ip.h"
 
+enum bridge_opt {
+       /* stp and forward delay always set */
+       BRIDGE_OPT_AGEING_TIME = (1 << 0),
+       BRIDGE_OPT_HELLO_TIME  = (1 << 1),
+       BRIDGE_OPT_MAX_AGE     = (1 << 2),
+};
+
+struct bridge_config {
+       enum bridge_opt flags;
+       bool stp;
+       int forward_delay;
+
+       int ageing_time;
+       int hello_time;
+       int max_age;
+};
+
 int system_init(void);
 
-int system_bridge_addbr(struct device *bridge);
+int system_bridge_addbr(struct device *bridge, struct bridge_config *cfg);
 int system_bridge_delbr(struct device *bridge);
 int system_bridge_addif(struct device *bridge, struct device *dev);
 int system_bridge_delif(struct device *bridge, struct device *dev);