diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2010-02-27 19:41:50 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-28 00:49:46 -0800 |
commit | 561f1103a2b70de7e06e1e7fd072a5b142a4278c (patch) | |
tree | 219508a45a357c6dbd5e2fdf4924a474a6bab356 /net/bridge/br_multicast.c | |
parent | 0909e11758bd28848aeb6646e021ec1e031a3f0f (diff) |
bridge: Add multicast_snooping sysfs toggle
This patch allows the user to disable IGMP snooping completely
through a sysfs toggle. It also allows the user to reenable
snooping when it has been automatically disabled due to hash
collisions. If the collisions have not been resolved however
the system will refuse to reenable snooping.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge/br_multicast.c')
-rw-r--r-- | net/bridge/br_multicast.c | 61 |
1 files changed, 56 insertions, 5 deletions
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 674224b6729..c7a1095ed84 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -656,6 +656,15 @@ void br_multicast_del_port(struct net_bridge_port *port) del_timer_sync(&port->multicast_router_timer); } +static void __br_multicast_enable_port(struct net_bridge_port *port) +{ + port->multicast_startup_queries_sent = 0; + + if (try_to_del_timer_sync(&port->multicast_query_timer) >= 0 || + del_timer(&port->multicast_query_timer)) + mod_timer(&port->multicast_query_timer, jiffies); +} + void br_multicast_enable_port(struct net_bridge_port *port) { struct net_bridge *br = port->br; @@ -664,11 +673,7 @@ void br_multicast_enable_port(struct net_bridge_port *port) if (br->multicast_disabled || !netif_running(br->dev)) goto out; - port->multicast_startup_queries_sent = 0; - - if (try_to_del_timer_sync(&port->multicast_query_timer) >= 0 || - del_timer(&port->multicast_query_timer)) - mod_timer(&port->multicast_query_timer, jiffies); + __br_multicast_enable_port(port); out: spin_unlock(&br->multicast_lock); @@ -1210,3 +1215,49 @@ unlock: return err; } + +int br_multicast_toggle(struct net_bridge *br, unsigned long val) +{ + struct net_bridge_port *port; + int err = -ENOENT; + + spin_lock(&br->multicast_lock); + if (!netif_running(br->dev)) + goto unlock; + + err = 0; + if (br->multicast_disabled == !val) + goto unlock; + + br->multicast_disabled = !val; + if (br->multicast_disabled) + goto unlock; + + if (br->mdb) { + if (br->mdb->old) { + err = -EEXIST; +rollback: + br->multicast_disabled = !!val; + goto unlock; + } + + err = br_mdb_rehash(&br->mdb, br->mdb->max, + br->hash_elasticity); + if (err) + goto rollback; + } + + br_multicast_open(br); + list_for_each_entry(port, &br->port_list, list) { + if (port->state == BR_STATE_DISABLED || + port->state == BR_STATE_BLOCKING) + continue; + + __br_multicast_enable_port(port); + } + +unlock: + spin_unlock(&br->multicast_lock); + + return err; +} |