Skip to content

Commit 561f110

Browse files
herbertxdavem330
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 0909e11 commit 561f110

File tree

3 files changed

+75
-5
lines changed

3 files changed

+75
-5
lines changed

net/bridge/br_multicast.c

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,15 @@ void br_multicast_del_port(struct net_bridge_port *port)
656656
del_timer_sync(&port->multicast_router_timer);
657657
}
658658

659+
static 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+
659668
void br_multicast_enable_port(struct net_bridge_port *port)
660669
{
661670
struct net_bridge *br = port->br;
@@ -664,11 +673,7 @@ void br_multicast_enable_port(struct net_bridge_port *port)
664673
if (br->multicast_disabled || !netif_running(br->dev))
665674
goto out;
666675

667-
port->multicast_startup_queries_sent = 0;
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);
676+
__br_multicast_enable_port(port);
672677

673678
out:
674679
spin_unlock(&br->multicast_lock);
@@ -1210,3 +1215,49 @@ int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
12101215

12111216
return err;
12121217
}
1218+
1219+
int 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;
1239+
rollback:
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+
1259+
unlock:
1260+
spin_unlock(&br->multicast_lock);
1261+
1262+
return err;
1263+
}

net/bridge/br_private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ extern void br_multicast_forward(struct net_bridge_mdb_entry *mdst,
300300
extern int br_multicast_set_router(struct net_bridge *br, unsigned long val);
301301
extern int br_multicast_set_port_router(struct net_bridge_port *p,
302302
unsigned long val);
303+
extern int br_multicast_toggle(struct net_bridge *br, unsigned long val);
303304
#else
304305
static inline int br_multicast_rcv(struct net_bridge *br,
305306
struct net_bridge_port *port,

net/bridge/br_sysfs_br.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,23 @@ static ssize_t store_multicast_router(struct device *d,
361361
}
362362
static DEVICE_ATTR(multicast_router, S_IRUGO | S_IWUSR, show_multicast_router,
363363
store_multicast_router);
364+
365+
static 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+
373+
static 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+
}
379+
static DEVICE_ATTR(multicast_snooping, S_IRUGO | S_IWUSR,
380+
show_multicast_snooping, store_multicast_snooping);
364381
#endif
365382

366383
static struct attribute *bridge_attrs[] = {
@@ -384,6 +401,7 @@ static struct attribute *bridge_attrs[] = {
384401
&dev_attr_flush.attr,
385402
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
386403
&dev_attr_multicast_router.attr,
404+
&dev_attr_multicast_snooping.attr,
387405
#endif
388406
NULL
389407
};

0 commit comments

Comments
 (0)