diff options
author | Linus Lüssing <linus.luessing@c0d3.blue> | 2016-03-05 23:53:52 +0100 |
---|---|---|
committer | Felix Fietkau <nbd@openwrt.org> | 2016-03-07 09:43:47 +0100 |
commit | bd1ee3efb46ae013d81b1aec51668e7595274e69 (patch) | |
tree | 63373cfb59ae6430ad8337a396d98c73b802f55b | |
parent | 7a51f23e7034157dee8e00910513d95e935eeab6 (diff) |
bridge: multicast: Export some parameters RFCs suggest to be tunable
RFCs suggest some parameters of IGMP and MLD to be configurable by
the administrator. With this patch the following parameters are
configurable:
* robustness (default: 2)
* query_interval (default: 12500 [125s])
* query_response_interval (default: 1000 [10s])
* last_member_interval (default: 100 [1s])
Depending on the size and nature of the network topology administrators
might want to increase or decrease these parameters.
netifd will take care of configuring any other parameters which are
dependant on the ones above and set them according to the formulas
provided in the RFCs. These parameters of the bridge are
membership_interval, querier_interval, startup_query_interval,
startup_query_count and last_member_count.
RFCs allow setting three more parameters to be configurable:
startup_query_interval, startup_query_count and last_member_count.
However this patch does not export them, as they can be indirectly
tuned via the given, exported four parameters, too.
Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
-rw-r--r-- | bridge.c | 32 | ||||
-rw-r--r-- | system-linux.c | 131 | ||||
-rw-r--r-- | system.h | 16 |
3 files changed, 163 insertions, 16 deletions
@@ -34,6 +34,10 @@ enum { BRIDGE_ATTR_BRIDGE_EMPTY, BRIDGE_ATTR_MULTICAST_QUERIER, BRIDGE_ATTR_HASH_MAX, + BRIDGE_ATTR_ROBUSTNESS, + BRIDGE_ATTR_QUERY_INTERVAL, + BRIDGE_ATTR_QUERY_RESPONSE_INTERVAL, + BRIDGE_ATTR_LAST_MEMBER_INTERVAL, __BRIDGE_ATTR_MAX }; @@ -49,6 +53,10 @@ static const struct blobmsg_policy bridge_attrs[__BRIDGE_ATTR_MAX] = { [BRIDGE_ATTR_BRIDGE_EMPTY] = { "bridge_empty", BLOBMSG_TYPE_BOOL }, [BRIDGE_ATTR_MULTICAST_QUERIER] = { "multicast_querier", BLOBMSG_TYPE_BOOL }, [BRIDGE_ATTR_HASH_MAX] = { "hash_max", BLOBMSG_TYPE_INT32 }, + [BRIDGE_ATTR_ROBUSTNESS] = { "robustness", BLOBMSG_TYPE_INT32 }, + [BRIDGE_ATTR_QUERY_INTERVAL] = { "query_interval", BLOBMSG_TYPE_INT32 }, + [BRIDGE_ATTR_QUERY_RESPONSE_INTERVAL] = { "query_response_interval", BLOBMSG_TYPE_INT32 }, + [BRIDGE_ATTR_LAST_MEMBER_INTERVAL] = { "last_member_interval", BLOBMSG_TYPE_INT32 }, }; static const struct uci_blob_param_info bridge_attr_info[__BRIDGE_ATTR_MAX] = { @@ -553,6 +561,10 @@ bridge_apply_settings(struct bridge_state *bst, struct blob_attr **tb) cfg->forward_delay = 2; cfg->igmp_snoop = true; cfg->multicast_querier = true; + cfg->robustness = 2; + cfg->query_interval = 12500; + cfg->query_response_interval = 1000; + cfg->last_member_interval = 100; cfg->hash_max = 512; cfg->bridge_empty = false; cfg->priority = 0x7FFF; @@ -575,6 +587,26 @@ bridge_apply_settings(struct bridge_state *bst, struct blob_attr **tb) if ((cur = tb[BRIDGE_ATTR_HASH_MAX])) cfg->hash_max = blobmsg_get_u32(cur); + if ((cur = tb[BRIDGE_ATTR_ROBUSTNESS])) { + cfg->robustness = blobmsg_get_u32(cur); + cfg->flags |= BRIDGE_OPT_ROBUSTNESS; + } + + if ((cur = tb[BRIDGE_ATTR_QUERY_INTERVAL])) { + cfg->query_interval = blobmsg_get_u32(cur); + cfg->flags |= BRIDGE_OPT_QUERY_INTERVAL; + } + + if ((cur = tb[BRIDGE_ATTR_QUERY_RESPONSE_INTERVAL])) { + cfg->query_response_interval = blobmsg_get_u32(cur); + cfg->flags |= BRIDGE_OPT_QUERY_RESPONSE_INTERVAL; + } + + if ((cur = tb[BRIDGE_ATTR_LAST_MEMBER_INTERVAL])) { + cfg->last_member_interval = blobmsg_get_u32(cur); + cfg->flags |= BRIDGE_OPT_LAST_MEMBER_INTERVAL; + } + if ((cur = tb[BRIDGE_ATTR_AGEING_TIME])) { cfg->ageing_time = blobmsg_get_u32(cur); cfg->flags |= BRIDGE_OPT_AGEING_TIME; diff --git a/system-linux.c b/system-linux.c index 052bc94..7638086 100644 --- a/system-linux.c +++ b/system-linux.c @@ -332,6 +332,50 @@ static void system_bridge_set_multicast_router(struct device *dev, const char *v dev->ifname, val); } +static void system_bridge_set_robustness(struct device *dev, const char *val) +{ + system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_startup_query_count", + dev->ifname, val); + system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_last_member_count", + dev->ifname, val); +} + +static void system_bridge_set_query_interval(struct device *dev, const char *val) +{ + system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_query_interval", + dev->ifname, val); +} + +static void system_bridge_set_query_response_interval(struct device *dev, const char *val) +{ + system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_query_response_interval", + dev->ifname, val); +} + +static void system_bridge_set_last_member_interval(struct device *dev, const char *val) +{ + system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_last_member_interval", + dev->ifname, val); +} + +static void system_bridge_set_membership_interval(struct device *dev, const char *val) +{ + system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_membership_interval", + dev->ifname, val); +} + +static void system_bridge_set_other_querier_timeout(struct device *dev, const char *val) +{ + system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_querier_interval", + dev->ifname, val); +} + +static void system_bridge_set_startup_query_interval(struct device *dev, const char *val) +{ + system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_startup_query_interval", + dev->ifname, val); +} + static int system_get_sysctl(const char *path, char *buf, const size_t buf_sz) { int fd = -1, ret = -1; @@ -832,37 +876,98 @@ sec_to_jiffies(int val) return (unsigned long) val * 100; } -int system_bridge_addbr(struct device *bridge, struct bridge_config *cfg) +static void system_bridge_conf_multicast_deps(struct device *bridge, + struct bridge_config *cfg, + char *buf, + int buf_len) { - char buf[64]; - unsigned long args[4] = {}; + int val; - if (ioctl(sock_ioctl, SIOCBRADDBR, bridge->ifname) < 0) - return -1; + if (cfg->flags & BRIDGE_OPT_ROBUSTNESS || + cfg->flags & BRIDGE_OPT_QUERY_INTERVAL || + cfg->flags & BRIDGE_OPT_QUERY_RESPONSE_INTERVAL) { + val = cfg->robustness * cfg->query_interval + + cfg->query_response_interval; - args[0] = BRCTL_SET_BRIDGE_STP_STATE; - args[1] = !!cfg->stp; - system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args); + snprintf(buf, buf_len, "%i", val); + system_bridge_set_membership_interval(bridge, buf); - args[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY; - args[1] = sec_to_jiffies(cfg->forward_delay); - system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args); + val = cfg->robustness * cfg->query_interval + + cfg->query_response_interval / 2; + + snprintf(buf, buf_len, "%i", val); + system_bridge_set_other_querier_timeout(bridge, buf); + } + if (cfg->flags & BRIDGE_OPT_QUERY_INTERVAL) { + val = cfg->query_interval / 4; + + snprintf(buf, buf_len, "%i", val); + system_bridge_set_startup_query_interval(bridge, buf); + } +} + +static void system_bridge_conf_multicast(struct device *bridge, + struct bridge_config *cfg, + char *buf, + int buf_len) +{ system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_snooping", bridge->ifname, cfg->igmp_snoop ? "1" : "0"); system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_querier", bridge->ifname, cfg->multicast_querier ? "1" : "0"); - snprintf(buf, sizeof(buf), "%i", cfg->hash_max); + snprintf(buf, buf_len, "%i", cfg->hash_max); system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/hash_max", bridge->ifname, buf); if (bridge->settings.flags & DEV_OPT_MULTICAST_ROUTER) { - snprintf(buf, sizeof(buf), "%i", bridge->settings.multicast_router); + snprintf(buf, buf_len, "%i", bridge->settings.multicast_router); system_bridge_set_multicast_router(bridge, buf, true); } + if (cfg->flags & BRIDGE_OPT_ROBUSTNESS) { + snprintf(buf, buf_len, "%i", cfg->robustness); + system_bridge_set_robustness(bridge, buf); + } + + if (cfg->flags & BRIDGE_OPT_QUERY_INTERVAL) { + snprintf(buf, buf_len, "%i", cfg->query_interval); + system_bridge_set_query_interval(bridge, buf); + } + + if (cfg->flags & BRIDGE_OPT_QUERY_RESPONSE_INTERVAL) { + snprintf(buf, buf_len, "%i", cfg->query_response_interval); + system_bridge_set_query_response_interval(bridge, buf); + } + + if (cfg->flags & BRIDGE_OPT_LAST_MEMBER_INTERVAL) { + snprintf(buf, buf_len, "%i", cfg->last_member_interval); + system_bridge_set_last_member_interval(bridge, buf); + } + + system_bridge_conf_multicast_deps(bridge, cfg, buf, buf_len); +} + +int system_bridge_addbr(struct device *bridge, struct bridge_config *cfg) +{ + char buf[64]; + unsigned long args[4] = {}; + + 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); + + system_bridge_conf_multicast(bridge, cfg, buf, sizeof(buf)); + args[0] = BRCTL_SET_BRIDGE_PRIORITY; args[1] = cfg->priority; system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args); @@ -41,16 +41,26 @@ extern const struct uci_blob_param_list tunnel_attr_list; 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), + BRIDGE_OPT_AGEING_TIME = (1 << 0), + BRIDGE_OPT_HELLO_TIME = (1 << 1), + BRIDGE_OPT_MAX_AGE = (1 << 2), + BRIDGE_OPT_ROBUSTNESS = (1 << 3), + BRIDGE_OPT_QUERY_INTERVAL = (1 << 4), + BRIDGE_OPT_QUERY_RESPONSE_INTERVAL = (1 << 5), + BRIDGE_OPT_LAST_MEMBER_INTERVAL = (1 << 6), }; struct bridge_config { enum bridge_opt flags; bool stp; + bool igmp_snoop; bool multicast_querier; + int robustness; + int query_interval; + int query_response_interval; + int last_member_interval; + unsigned short priority; int forward_delay; bool bridge_empty; |