bridge: Allow setting multicast_fast_leave_option
authorHans Dedecker <dedeckeh@gmail.com>
Tue, 13 Sep 2016 12:33:38 +0000 (14:33 +0200)
committerFelix Fietkau <nbd@nbd.name>
Wed, 14 Sep 2016 10:59:37 +0000 (12:59 +0200)
Setting the multicast_fast_leave option of a bridge allows to control
the forwarding of multicast traffic when an IGMP/MLD leave is received.
In case multicast_leave_option is enabled and a leave is received the
multicast membership will immediately be dropped on the bridge port while
in the other case the multicast membership will time out in the bridge.

This could be usefull in scenarios where explicit multicast membership
host tracking is not supported in the upstream network. In this case the
multicast stream is still flowing after a leave is received resulting into
possible bandwidth saturation on the lan if a new stream is joined as
multiple multicast streams are received.

Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
device.c
device.h
system-linux.c

index 8174ca080204034e1803a6c6cc532069b61c65f9..a7d18af7d1d489d61c88411ab503e6e0daf04352 100644 (file)
--- a/device.c
+++ b/device.c
@@ -54,6 +54,7 @@ static const struct blobmsg_policy dev_attrs[__DEV_ATTR_MAX] = {
        [DEV_ATTR_DADTRANSMITS] = { .name = "dadtransmits", .type = BLOBMSG_TYPE_INT32 },
        [DEV_ATTR_MULTICAST_TO_UNICAST] = { .name = "multicast_to_unicast", .type = BLOBMSG_TYPE_BOOL },
        [DEV_ATTR_MULTICAST_ROUTER] = { .name = "multicast_router", .type = BLOBMSG_TYPE_INT32 },
+       [DEV_ATTR_MULTICAST_FAST_LEAVE] = { .name = "multicast_fast_leave", . type = BLOBMSG_TYPE_BOOL },
        [DEV_ATTR_MULTICAST] = { .name ="multicast", .type = BLOBMSG_TYPE_BOOL },
        [DEV_ATTR_LEARNING] = { .name ="learning", .type = BLOBMSG_TYPE_BOOL },
        [DEV_ATTR_UNICAST_FLOOD] = { .name ="unicast_flood", .type = BLOBMSG_TYPE_BOOL },
@@ -231,6 +232,7 @@ device_merge_settings(struct device *dev, struct device_settings *n)
                s->multicast : os->multicast;
        n->multicast_to_unicast = s->multicast_to_unicast;
        n->multicast_router = s->multicast_router;
+       n->multicast_fast_leave = s->multicast_fast_leave;
        n->learning = s->learning;
        n->unicast_flood = s->unicast_flood;
        n->flags = s->flags | os->flags | os->valid_flags;
@@ -351,6 +353,11 @@ device_init_settings(struct device *dev, struct blob_attr **tb)
                        DPRINTF("Invalid value: %d - (Use 0: never, 1: learn, 2: always)\n", blobmsg_get_u32(cur));
        }
 
+       if ((cur = tb[DEV_ATTR_MULTICAST_FAST_LEAVE])) {
+               s->multicast_fast_leave = blobmsg_get_bool(cur);
+               s->flags |= DEV_OPT_MULTICAST_FAST_LEAVE;
+       }
+
        if ((cur = tb[DEV_ATTR_MULTICAST])) {
                s->multicast = blobmsg_get_bool(cur);
                s->flags |= DEV_OPT_MULTICAST;
@@ -1041,6 +1048,8 @@ device_dump_status(struct blob_buf *b, struct device *dev)
                        blobmsg_add_u8(b, "multicast_to_unicast", st.multicast_to_unicast);
                if (st.flags & DEV_OPT_MULTICAST_ROUTER)
                        blobmsg_add_u32(b, "multicast_router", st.multicast_router);
+               if (st.flags & DEV_OPT_MULTICAST_FAST_LEAVE)
+                       blobmsg_add_u8(b, "multicast_fast_leave", st.multicast_fast_leave);
                if (st.flags & DEV_OPT_MULTICAST)
                        blobmsg_add_u8(b, "multicast", st.multicast);
                if (st.flags & DEV_OPT_LEARNING)
index ef8d9a88d9f484e8e115c1b2f7ec182603630aff..c669beb966f31f3d62864a4dc71f5784b00cdb90 100644 (file)
--- a/device.h
+++ b/device.h
@@ -45,6 +45,7 @@ enum {
        DEV_ATTR_DADTRANSMITS,
        DEV_ATTR_MULTICAST_TO_UNICAST,
        DEV_ATTR_MULTICAST_ROUTER,
+       DEV_ATTR_MULTICAST_FAST_LEAVE,
        DEV_ATTR_MULTICAST,
        DEV_ATTR_LEARNING,
        DEV_ATTR_UNICAST_FLOOD,
@@ -99,6 +100,7 @@ enum {
        DEV_OPT_LEARNING                = (1 << 17),
        DEV_OPT_UNICAST_FLOOD           = (1 << 18),
        DEV_OPT_NEIGHGCSTALETIME        = (1 << 19),
+       DEV_OPT_MULTICAST_FAST_LEAVE    = (1 << 20),
 };
 
 /* events broadcasted to all users of a device */
@@ -161,6 +163,7 @@ struct device_settings {
        unsigned int dadtransmits;
        bool multicast_to_unicast;
        unsigned int multicast_router;
+       bool multicast_fast_leave;
        bool multicast;
        bool learning;
        bool unicast_flood;
index d868c15debe82b96ff4b572556aa6f98c9da9009..6e4a1949a11874443e05d45ebf41e916fcf23219 100644 (file)
@@ -326,6 +326,11 @@ static void system_bridge_set_multicast_to_unicast(struct device *dev, const cha
        system_set_dev_sysctl("/sys/class/net/%s/brport/multicast_to_unicast", dev->ifname, val);
 }
 
+static void system_bridge_set_multicast_fast_leave(struct device *dev, const char *val)
+{
+       system_set_dev_sysctl("/sys/class/net/%s/brport/multicast_fast_leave", dev->ifname, val);
+}
+
 static void system_bridge_set_hairpin_mode(struct device *dev, const char *val)
 {
        system_set_dev_sysctl("/sys/class/net/%s/brport/hairpin_mode", dev->ifname, val);
@@ -680,6 +685,10 @@ int system_bridge_addif(struct device *bridge, struct device *dev)
                system_bridge_set_multicast_router(dev, buf, false);
        }
 
+       if (dev->settings.flags & DEV_OPT_MULTICAST_FAST_LEAVE &&
+           dev->settings.multicast_fast_leave)
+               system_bridge_set_multicast_fast_leave(dev, "1");
+
        if (dev->settings.flags & DEV_OPT_LEARNING &&
            !dev->settings.learning)
                system_bridge_set_learning(dev, "0");