aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge/br_multicast.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2010-02-27 14:41:50 -0500
committerDavid S. Miller <davem@davemloft.net>2010-02-28 03:49:46 -0500
commit561f1103a2b70de7e06e1e7fd072a5b142a4278c (patch)
tree219508a45a357c6dbd5e2fdf4924a474a6bab356 /net/bridge/br_multicast.c
parent0909e11758bd28848aeb6646e021ec1e031a3f0f (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.c61
1 files changed, 56 insertions, 5 deletions
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 674224b6729d..c7a1095ed84a 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)
656 del_timer_sync(&port->multicast_router_timer); 656 del_timer_sync(&port->multicast_router_timer);
657} 657}
658 658
659static void __br_multicast_enable_port(struct net_bridge_port *port)
660{
661 port->multicast_startup_queries_sent = 0;
662
663 if (try_to_del_timer_sync(&port->multicast_query_timer) >= 0 ||
664 del_timer(&port->multicast_query_timer))
665 mod_timer(&port->multicast_query_timer, jiffies);
666}
667
659void br_multicast_enable_port(struct net_bridge_port *port) 668void br_multicast_enable_port(struct net_bridge_port *port)
660{ 669{
661 struct net_bridge *br = port->br; 670 struct net_bridge *br = port->br;
@@ -664,11 +673,7 @@ void br_multicast_enable_port(struct net_bridge_port *port)
664 if (br->multicast_disabled || !netif_running(br->dev)) 673 if (br->multicast_disabled || !netif_running(br->dev))
665 goto out; 674 goto out;
666 675
667 port->multicast_startup_queries_sent = 0; 676 __br_multicast_enable_port(port);
668
669 if (try_to_del_timer_sync(&port->multicast_query_timer) >= 0 ||
670 del_timer(&port->multicast_query_timer))
671 mod_timer(&port->multicast_query_timer, jiffies);
672 677
673out: 678out:
674 spin_unlock(&br->multicast_lock); 679 spin_unlock(&br->multicast_lock);
@@ -1210,3 +1215,49 @@ unlock:
1210 1215
1211 return err; 1216 return err;
1212} 1217}
1218
1219int br_multicast_toggle(struct net_bridge *br, unsigned long val)
1220{
1221 struct net_bridge_port *port;
1222 int err = -ENOENT;
1223
1224 spin_lock(&br->multicast_lock);
1225 if (!netif_running(br->dev))
1226 goto unlock;
1227
1228 err = 0;
1229 if (br->multicast_disabled == !val)
1230 goto unlock;
1231
1232 br->multicast_disabled = !val;
1233 if (br->multicast_disabled)
1234 goto unlock;
1235
1236 if (br->mdb) {
1237 if (br->mdb->old) {
1238 err = -EEXIST;
1239rollback:
1240 br->multicast_disabled = !!val;
1241 goto unlock;
1242 }
1243
1244 err = br_mdb_rehash(&br->mdb, br->mdb->max,
1245 br->hash_elasticity);
1246 if (err)
1247 goto rollback;
1248 }
1249
1250 br_multicast_open(br);
1251 list_for_each_entry(port, &br->port_list, list) {
1252 if (port->state == BR_STATE_DISABLED ||
1253 port->state == BR_STATE_BLOCKING)
1254 continue;
1255
1256 __br_multicast_enable_port(port);
1257 }
1258
1259unlock:
1260 spin_unlock(&br->multicast_lock);
1261
1262 return err;
1263}