aboutsummaryrefslogtreecommitdiffstats
path: root/net
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
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')
-rw-r--r--net/bridge/br_multicast.c61
-rw-r--r--net/bridge/br_private.h1
-rw-r--r--net/bridge/br_sysfs_br.c18
3 files changed, 75 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}
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index dcdfafbe4b17..bf162fa6b23b 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -300,6 +300,7 @@ extern void br_multicast_forward(struct net_bridge_mdb_entry *mdst,
300extern int br_multicast_set_router(struct net_bridge *br, unsigned long val); 300extern int br_multicast_set_router(struct net_bridge *br, unsigned long val);
301extern int br_multicast_set_port_router(struct net_bridge_port *p, 301extern int br_multicast_set_port_router(struct net_bridge_port *p,
302 unsigned long val); 302 unsigned long val);
303extern int br_multicast_toggle(struct net_bridge *br, unsigned long val);
303#else 304#else
304static inline int br_multicast_rcv(struct net_bridge *br, 305static inline int br_multicast_rcv(struct net_bridge *br,
305 struct net_bridge_port *port, 306 struct net_bridge_port *port,
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index cb742016db21..0ab288332fc5 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -361,6 +361,23 @@ static ssize_t store_multicast_router(struct device *d,
361} 361}
362static DEVICE_ATTR(multicast_router, S_IRUGO | S_IWUSR, show_multicast_router, 362static DEVICE_ATTR(multicast_router, S_IRUGO | S_IWUSR, show_multicast_router,
363 store_multicast_router); 363 store_multicast_router);
364
365static ssize_t show_multicast_snooping(struct device *d,
366 struct device_attribute *attr,
367 char *buf)
368{
369 struct net_bridge *br = to_bridge(d);
370 return sprintf(buf, "%d\n", !br->multicast_disabled);
371}
372
373static ssize_t store_multicast_snooping(struct device *d,
374 struct device_attribute *attr,
375 const char *buf, size_t len)
376{
377 return store_bridge_parm(d, buf, len, br_multicast_toggle);
378}
379static DEVICE_ATTR(multicast_snooping, S_IRUGO | S_IWUSR,
380 show_multicast_snooping, store_multicast_snooping);
364#endif 381#endif
365 382
366static struct attribute *bridge_attrs[] = { 383static struct attribute *bridge_attrs[] = {
@@ -384,6 +401,7 @@ static struct attribute *bridge_attrs[] = {
384 &dev_attr_flush.attr, 401 &dev_attr_flush.attr,
385#ifdef CONFIG_BRIDGE_IGMP_SNOOPING 402#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
386 &dev_attr_multicast_router.attr, 403 &dev_attr_multicast_router.attr,
404 &dev_attr_multicast_snooping.attr,
387#endif 405#endif
388 NULL 406 NULL
389}; 407};