bridge: mcast: add support for temporary port router
authorNikolay Aleksandrov <nikolay@cumulusnetworks.com>
Fri, 26 Feb 2016 20:20:03 +0000 (21:20 +0100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 1 Mar 2016 21:55:07 +0000 (16:55 -0500)
Add support for a temporary router port which doesn't depend only on the
incoming query. It can be refreshed if set to the same value, which is
a no-op for the rest.

Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/uapi/linux/if_bridge.h
net/bridge/br_multicast.c

index e47f3bc7f323a55807a80a69552466b7f4de9e4b..74ee03a47e79ea4818ae52c5ac2037eade35845e 100644 (file)
@@ -182,6 +182,7 @@ enum {
        MDB_RTR_TYPE_DISABLED,
        MDB_RTR_TYPE_TEMP_QUERY,
        MDB_RTR_TYPE_PERM,
+       MDB_RTR_TYPE_TEMP
 };
 
 enum {
index f1140cf5168daf1f8141d57bb72d1b4186570aa5..a4c15df2b7920301f7d12918dc21a1d6f2474352 100644 (file)
@@ -759,13 +759,17 @@ static void br_multicast_router_expired(unsigned long data)
        struct net_bridge *br = port->br;
 
        spin_lock(&br->multicast_lock);
-       if (port->multicast_router != MDB_RTR_TYPE_TEMP_QUERY ||
+       if (port->multicast_router == MDB_RTR_TYPE_DISABLED ||
+           port->multicast_router == MDB_RTR_TYPE_PERM ||
            timer_pending(&port->multicast_router_timer) ||
            hlist_unhashed(&port->rlist))
                goto out;
 
        hlist_del_init_rcu(&port->rlist);
        br_rtr_notify(br->dev, port, RTM_DELMDB);
+       /* Don't allow timer refresh if the router expired */
+       if (port->multicast_router == MDB_RTR_TYPE_TEMP)
+               port->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
 
 out:
        spin_unlock(&br->multicast_lock);
@@ -981,6 +985,9 @@ void br_multicast_disable_port(struct net_bridge_port *port)
        if (!hlist_unhashed(&port->rlist)) {
                hlist_del_init_rcu(&port->rlist);
                br_rtr_notify(br->dev, port, RTM_DELMDB);
+               /* Don't allow timer refresh if disabling */
+               if (port->multicast_router == MDB_RTR_TYPE_TEMP)
+                       port->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
        }
        del_timer(&port->multicast_router_timer);
        del_timer(&port->ip4_own_query.timer);
@@ -1234,7 +1241,8 @@ static void br_multicast_mark_router(struct net_bridge *br,
                return;
        }
 
-       if (port->multicast_router != MDB_RTR_TYPE_TEMP_QUERY)
+       if (port->multicast_router == MDB_RTR_TYPE_DISABLED ||
+           port->multicast_router == MDB_RTR_TYPE_PERM)
                return;
 
        br_multicast_add_router(br, port);
@@ -1850,10 +1858,15 @@ static void __del_port_router(struct net_bridge_port *p)
 int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
 {
        struct net_bridge *br = p->br;
+       unsigned long now = jiffies;
        int err = -EINVAL;
 
        spin_lock(&br->multicast_lock);
        if (p->multicast_router == val) {
+               /* Refresh the temp router port timer */
+               if (p->multicast_router == MDB_RTR_TYPE_TEMP)
+                       mod_timer(&p->multicast_router_timer,
+                                 now + br->multicast_querier_interval);
                err = 0;
                goto unlock;
        }
@@ -1872,6 +1885,10 @@ int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
                del_timer(&p->multicast_router_timer);
                br_multicast_add_router(br, p);
                break;
+       case MDB_RTR_TYPE_TEMP:
+               p->multicast_router = MDB_RTR_TYPE_TEMP;
+               br_multicast_mark_router(br, p);
+               break;
        default:
                goto unlock;
        }