diff options
-rw-r--r-- | net/bridge/br_multicast.c | 41 | ||||
-rw-r--r-- | net/bridge/br_private.h | 1 | ||||
-rw-r--r-- | net/bridge/br_sysfs_br.c | 39 |
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 | |||
1266 | int 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; | ||
1289 | rollback: | ||
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 | |||
1300 | unlock: | ||
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); | |||
301 | extern int br_multicast_set_port_router(struct net_bridge_port *p, | 301 | extern int br_multicast_set_port_router(struct net_bridge_port *p, |
302 | unsigned long val); | 302 | unsigned long val); |
303 | extern int br_multicast_toggle(struct net_bridge *br, unsigned long val); | 303 | extern int br_multicast_toggle(struct net_bridge *br, unsigned long val); |
304 | extern int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val); | ||
304 | #else | 305 | #else |
305 | static inline int br_multicast_rcv(struct net_bridge *br, | 306 | static 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 | } |
379 | static DEVICE_ATTR(multicast_snooping, S_IRUGO | S_IWUSR, | 379 | static DEVICE_ATTR(multicast_snooping, S_IRUGO | S_IWUSR, |
380 | show_multicast_snooping, store_multicast_snooping); | 380 | show_multicast_snooping, store_multicast_snooping); |
381 | |||
382 | static 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 | |||
389 | static int set_elasticity(struct net_bridge *br, unsigned long val) | ||
390 | { | ||
391 | br->hash_elasticity = val; | ||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | static 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 | } | ||
401 | static DEVICE_ATTR(hash_elasticity, S_IRUGO | S_IWUSR, show_hash_elasticity, | ||
402 | store_hash_elasticity); | ||
403 | |||
404 | static 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 | |||
411 | static 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 | } | ||
416 | static DEVICE_ATTR(hash_max, S_IRUGO | S_IWUSR, show_hash_max, | ||
417 | store_hash_max); | ||
381 | #endif | 418 | #endif |
382 | 419 | ||
383 | static struct attribute *bridge_attrs[] = { | 420 | static 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 | }; |