net: bridge: shorten ageing time on topology change
authorVivien Didelot <vivien.didelot@savoirfairelinux.com>
Sat, 10 Dec 2016 18:44:29 +0000 (13:44 -0500)
committerDavid S. Miller <davem@davemloft.net>
Sun, 11 Dec 2016 02:28:28 +0000 (21:28 -0500)
802.1D [1] specifies that the bridges must use a short value to age out
dynamic entries in the Filtering Database for a period, once a topology
change has been communicated by the root bridge.

Add a bridge_ageing_time member in the net_bridge structure to store the
bridge ageing time value configured by the user (ioctl/netlink/sysfs).

If we are using in-kernel STP, shorten the ageing time value to twice
the forward delay used by the topology when the topology change flag is
set. When the flag is cleared, restore the configured ageing time.

[1] "8.3.5 Notifying topology changes ",
    http://profesores.elo.utfsm.cl/~agv/elo309/doc/802.1D-1998.pdf

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/bridge/br_device.c
net/bridge/br_private.h
net/bridge/br_stp.c

index c08e02b67818fd5f4d27f442eef91f16fdeb978c..bca5ead3e97324a895d48aba64b321ede593caa2 100644 (file)
@@ -409,7 +409,7 @@ void br_dev_setup(struct net_device *dev)
        br->bridge_max_age = br->max_age = 20 * HZ;
        br->bridge_hello_time = br->hello_time = 2 * HZ;
        br->bridge_forward_delay = br->forward_delay = 15 * HZ;
-       br->ageing_time = BR_DEFAULT_AGEING_TIME;
+       br->bridge_ageing_time = br->ageing_time = BR_DEFAULT_AGEING_TIME;
        dev->max_mtu = ETH_MAX_MTU;
 
        br_netfilter_rtable_init(br);
index e2cd6d12a273da8b7c8456931813fc3bb2a5d15f..8ce621e8345c478700ee64b76e41a98b2bd81d16 100644 (file)
@@ -300,10 +300,11 @@ struct net_bridge
        unsigned long                   max_age;
        unsigned long                   hello_time;
        unsigned long                   forward_delay;
-       unsigned long                   bridge_max_age;
        unsigned long                   ageing_time;
+       unsigned long                   bridge_max_age;
        unsigned long                   bridge_hello_time;
        unsigned long                   bridge_forward_delay;
+       unsigned long                   bridge_ageing_time;
 
        u8                              group_addr[ETH_ALEN];
        bool                            group_addr_set;
index 8d7b4c7a1d54f823add50d390195c118de5922ce..71fd1a4e63cc84ec047f56adf5fe24bb971522fa 100644 (file)
@@ -597,7 +597,11 @@ int br_set_ageing_time(struct net_bridge *br, clock_t ageing_time)
        if (err)
                return err;
 
+       spin_lock_bh(&br->lock);
+       br->bridge_ageing_time = t;
        br->ageing_time = t;
+       spin_unlock_bh(&br->lock);
+
        mod_timer(&br->gc_timer, jiffies);
 
        return 0;
@@ -606,6 +610,29 @@ int br_set_ageing_time(struct net_bridge *br, clock_t ageing_time)
 /* called under bridge lock */
 void __br_set_topology_change(struct net_bridge *br, unsigned char val)
 {
+       unsigned long t;
+       int err;
+
+       if (br->stp_enabled == BR_KERNEL_STP && br->topology_change != val) {
+               /* On topology change, set the bridge ageing time to twice the
+                * forward delay. Otherwise, restore its default ageing time.
+                */
+
+               if (val) {
+                       t = 2 * br->forward_delay;
+                       br_debug(br, "decreasing ageing time to %lu\n", t);
+               } else {
+                       t = br->bridge_ageing_time;
+                       br_debug(br, "restoring ageing time to %lu\n", t);
+               }
+
+               err = __set_ageing_time(br->dev, t);
+               if (err)
+                       br_warn(br, "error offloading ageing time\n");
+               else
+                       br->ageing_time = t;
+       }
+
        br->topology_change = val;
 }