aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2010-02-27 14:41:51 -0500
committerDavid S. Miller <davem@davemloft.net>2010-02-28 03:49:46 -0500
commitb195167fcf089dbdc650bb874084555035f07f98 (patch)
tree9b0c491bd1e6e13472d074986869a9aafcb3ae3f
parent561f1103a2b70de7e06e1e7fd072a5b142a4278c (diff)
bridge: Add hash elasticity/max sysfs entries
This patch allows the user to control the hash elasticity/max parameters. The elasticity setting does not take effect until the next new multicast group is added. At which point it is checked and if after rehashing it still can't be satisfied then snooping will be disabled. The max setting on the other hand takes effect immediately. It must be a power of two and cannot be set to a value less than the current number of multicast group entries. This is the only way to shrink the multicast hash. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/bridge/br_multicast.c41
-rw-r--r--net/bridge/br_private.h1
-rw-r--r--net/bridge/br_sysfs_br.c39
3 files changed, 81 insertions, 0 deletions
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index c7a1095ed84a..2559fb539836 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -15,6 +15,7 @@
15#include <linux/igmp.h> 15#include <linux/igmp.h>
16#include <linux/jhash.h> 16#include <linux/jhash.h>
17#include <linux/kernel.h> 17#include <linux/kernel.h>
18#include <linux/log2.h>
18#include <linux/netdevice.h> 19#include <linux/netdevice.h>
19#include <linux/netfilter_bridge.h> 20#include <linux/netfilter_bridge.h>
20#include <linux/random.h> 21#include <linux/random.h>
@@ -1261,3 +1262,43 @@ unlock:
1261 1262
1262 return err; 1263 return err;
1263} 1264}
1265
1266int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val)
1267{
1268 int err = -ENOENT;
1269 u32 old;
1270
1271 spin_lock(&br->multicast_lock);
1272 if (!netif_running(br->dev))
1273 goto unlock;
1274
1275 err = -EINVAL;
1276 if (!is_power_of_2(val))
1277 goto unlock;
1278 if (br->mdb && val < br->mdb->size)
1279 goto unlock;
1280
1281 err = 0;
1282
1283 old = br->hash_max;
1284 br->hash_max = val;
1285
1286 if (br->mdb) {
1287 if (br->mdb->old) {
1288 err = -EEXIST;
1289rollback:
1290 br->hash_max = old;
1291 goto unlock;
1292 }
1293
1294 err = br_mdb_rehash(&br->mdb, br->hash_max,
1295 br->hash_elasticity);
1296 if (err)
1297 goto rollback;
1298 }
1299
1300unlock:
1301 spin_unlock(&br->multicast_lock);
1302
1303 return err;
1304}
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index bf162fa6b23b..9191198c4f1b 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -301,6 +301,7 @@ extern 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); 303extern int br_multicast_toggle(struct net_bridge *br, unsigned long val);
304extern int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val);
304#else 305#else
305static inline int br_multicast_rcv(struct net_bridge *br, 306static inline int br_multicast_rcv(struct net_bridge *br,
306 struct net_bridge_port *port, 307 struct net_bridge_port *port,
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index 0ab288332fc5..d2ee53b3ad7d 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -378,6 +378,43 @@ static ssize_t store_multicast_snooping(struct device *d,
378} 378}
379static DEVICE_ATTR(multicast_snooping, S_IRUGO | S_IWUSR, 379static DEVICE_ATTR(multicast_snooping, S_IRUGO | S_IWUSR,
380 show_multicast_snooping, store_multicast_snooping); 380 show_multicast_snooping, store_multicast_snooping);
381
382static ssize_t show_hash_elasticity(struct device *d,
383 struct device_attribute *attr, char *buf)
384{
385 struct net_bridge *br = to_bridge(d);
386 return sprintf(buf, "%u\n", br->hash_elasticity);
387}
388
389static int set_elasticity(struct net_bridge *br, unsigned long val)
390{
391 br->hash_elasticity = val;
392 return 0;
393}
394
395static ssize_t store_hash_elasticity(struct device *d,
396 struct device_attribute *attr,
397 const char *buf, size_t len)
398{
399 return store_bridge_parm(d, buf, len, set_elasticity);
400}
401static DEVICE_ATTR(hash_elasticity, S_IRUGO | S_IWUSR, show_hash_elasticity,
402 store_hash_elasticity);
403
404static ssize_t show_hash_max(struct device *d, struct device_attribute *attr,
405 char *buf)
406{
407 struct net_bridge *br = to_bridge(d);
408 return sprintf(buf, "%u\n", br->hash_max);
409}
410
411static ssize_t store_hash_max(struct device *d, struct device_attribute *attr,
412 const char *buf, size_t len)
413{
414 return store_bridge_parm(d, buf, len, br_multicast_set_hash_max);
415}
416static DEVICE_ATTR(hash_max, S_IRUGO | S_IWUSR, show_hash_max,
417 store_hash_max);
381#endif 418#endif
382 419
383static struct attribute *bridge_attrs[] = { 420static struct attribute *bridge_attrs[] = {
@@ -402,6 +439,8 @@ static struct attribute *bridge_attrs[] = {
402#ifdef CONFIG_BRIDGE_IGMP_SNOOPING 439#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
403 &dev_attr_multicast_router.attr, 440 &dev_attr_multicast_router.attr,
404 &dev_attr_multicast_snooping.attr, 441 &dev_attr_multicast_snooping.attr,
442 &dev_attr_hash_elasticity.attr,
443 &dev_attr_hash_max.attr,
405#endif 444#endif
406 NULL 445 NULL
407}; 446};