bridge: mcast: add support for temporary port router

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>
This commit is contained in:
Nikolay Aleksandrov 2016-02-26 21:20:03 +01:00 committed by David S. Miller
parent 4950cfd1e6
commit a55d8246ab
2 changed files with 20 additions and 2 deletions

View File

@ -182,6 +182,7 @@ enum {
MDB_RTR_TYPE_DISABLED, MDB_RTR_TYPE_DISABLED,
MDB_RTR_TYPE_TEMP_QUERY, MDB_RTR_TYPE_TEMP_QUERY,
MDB_RTR_TYPE_PERM, MDB_RTR_TYPE_PERM,
MDB_RTR_TYPE_TEMP
}; };
enum { enum {

View File

@ -759,13 +759,17 @@ static void br_multicast_router_expired(unsigned long data)
struct net_bridge *br = port->br; struct net_bridge *br = port->br;
spin_lock(&br->multicast_lock); 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) || timer_pending(&port->multicast_router_timer) ||
hlist_unhashed(&port->rlist)) hlist_unhashed(&port->rlist))
goto out; goto out;
hlist_del_init_rcu(&port->rlist); hlist_del_init_rcu(&port->rlist);
br_rtr_notify(br->dev, port, RTM_DELMDB); 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: out:
spin_unlock(&br->multicast_lock); spin_unlock(&br->multicast_lock);
@ -981,6 +985,9 @@ void br_multicast_disable_port(struct net_bridge_port *port)
if (!hlist_unhashed(&port->rlist)) { if (!hlist_unhashed(&port->rlist)) {
hlist_del_init_rcu(&port->rlist); hlist_del_init_rcu(&port->rlist);
br_rtr_notify(br->dev, port, RTM_DELMDB); 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->multicast_router_timer);
del_timer(&port->ip4_own_query.timer); del_timer(&port->ip4_own_query.timer);
@ -1234,7 +1241,8 @@ static void br_multicast_mark_router(struct net_bridge *br,
return; 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; return;
br_multicast_add_router(br, port); 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) int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
{ {
struct net_bridge *br = p->br; struct net_bridge *br = p->br;
unsigned long now = jiffies;
int err = -EINVAL; int err = -EINVAL;
spin_lock(&br->multicast_lock); spin_lock(&br->multicast_lock);
if (p->multicast_router == val) { 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; err = 0;
goto unlock; 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); del_timer(&p->multicast_router_timer);
br_multicast_add_router(br, p); br_multicast_add_router(br, p);
break; break;
case MDB_RTR_TYPE_TEMP:
p->multicast_router = MDB_RTR_TYPE_TEMP;
br_multicast_mark_router(br, p);
break;
default: default:
goto unlock; goto unlock;
} }