diff options
-rw-r--r-- | net/bridge/br_fdb.c | 19 | ||||
-rw-r--r-- | net/bridge/br_private.h | 1 | ||||
-rw-r--r-- | net/bridge/br_sysfs_br.c | 14 | ||||
-rw-r--r-- | net/bridge/br_sysfs_if.c | 8 |
4 files changed, 42 insertions, 0 deletions
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index dd5a5d5fb280..22645e3edf23 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c | |||
@@ -135,7 +135,26 @@ void br_fdb_cleanup(unsigned long _data) | |||
135 | mod_timer(&br->gc_timer, jiffies + HZ/10); | 135 | mod_timer(&br->gc_timer, jiffies + HZ/10); |
136 | } | 136 | } |
137 | 137 | ||
138 | /* Completely flush all dynamic entries in forwarding database.*/ | ||
139 | void br_fdb_flush(struct net_bridge *br) | ||
140 | { | ||
141 | int i; | ||
138 | 142 | ||
143 | spin_lock_bh(&br->hash_lock); | ||
144 | for (i = 0; i < BR_HASH_SIZE; i++) { | ||
145 | struct net_bridge_fdb_entry *f; | ||
146 | struct hlist_node *h, *n; | ||
147 | hlist_for_each_entry_safe(f, h, n, &br->hash[i], hlist) { | ||
148 | if (!f->is_static) | ||
149 | fdb_delete(f); | ||
150 | } | ||
151 | } | ||
152 | spin_unlock_bh(&br->hash_lock); | ||
153 | } | ||
154 | |||
155 | /* Flush all entries refering to a specific port. | ||
156 | * if do_all is set also flush static entries | ||
157 | */ | ||
139 | void br_fdb_delete_by_port(struct net_bridge *br, | 158 | void br_fdb_delete_by_port(struct net_bridge *br, |
140 | const struct net_bridge_port *p, | 159 | const struct net_bridge_port *p, |
141 | int do_all) | 160 | int do_all) |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index fab8ce0ce88d..3adacdf3406f 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -135,6 +135,7 @@ extern int br_dev_xmit(struct sk_buff *skb, struct net_device *dev); | |||
135 | /* br_fdb.c */ | 135 | /* br_fdb.c */ |
136 | extern void br_fdb_init(void); | 136 | extern void br_fdb_init(void); |
137 | extern void br_fdb_fini(void); | 137 | extern void br_fdb_fini(void); |
138 | extern void br_fdb_flush(struct net_bridge *br); | ||
138 | extern void br_fdb_changeaddr(struct net_bridge_port *p, | 139 | extern void br_fdb_changeaddr(struct net_bridge_port *p, |
139 | const unsigned char *newaddr); | 140 | const unsigned char *newaddr); |
140 | extern void br_fdb_cleanup(unsigned long arg); | 141 | extern void br_fdb_cleanup(unsigned long arg); |
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index 01a22ad0cc75..6cc5cfe665cd 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c | |||
@@ -309,6 +309,19 @@ static ssize_t store_group_addr(struct device *d, | |||
309 | static DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR, | 309 | static DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR, |
310 | show_group_addr, store_group_addr); | 310 | show_group_addr, store_group_addr); |
311 | 311 | ||
312 | static ssize_t store_flush(struct device *d, | ||
313 | struct device_attribute *attr, | ||
314 | const char *buf, size_t len) | ||
315 | { | ||
316 | struct net_bridge *br = to_bridge(d); | ||
317 | |||
318 | if (!capable(CAP_NET_ADMIN)) | ||
319 | return -EPERM; | ||
320 | |||
321 | br_fdb_flush(br); | ||
322 | return len; | ||
323 | } | ||
324 | static DEVICE_ATTR(flush, S_IWUSR, NULL, store_flush); | ||
312 | 325 | ||
313 | static struct attribute *bridge_attrs[] = { | 326 | static struct attribute *bridge_attrs[] = { |
314 | &dev_attr_forward_delay.attr, | 327 | &dev_attr_forward_delay.attr, |
@@ -328,6 +341,7 @@ static struct attribute *bridge_attrs[] = { | |||
328 | &dev_attr_topology_change_timer.attr, | 341 | &dev_attr_topology_change_timer.attr, |
329 | &dev_attr_gc_timer.attr, | 342 | &dev_attr_gc_timer.attr, |
330 | &dev_attr_group_addr.attr, | 343 | &dev_attr_group_addr.attr, |
344 | &dev_attr_flush.attr, | ||
331 | NULL | 345 | NULL |
332 | }; | 346 | }; |
333 | 347 | ||
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 0bc2aef8f9f3..2da22927d8dd 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c | |||
@@ -137,6 +137,13 @@ static ssize_t show_hold_timer(struct net_bridge_port *p, | |||
137 | } | 137 | } |
138 | static BRPORT_ATTR(hold_timer, S_IRUGO, show_hold_timer, NULL); | 138 | static BRPORT_ATTR(hold_timer, S_IRUGO, show_hold_timer, NULL); |
139 | 139 | ||
140 | static ssize_t store_flush(struct net_bridge_port *p, unsigned long v) | ||
141 | { | ||
142 | br_fdb_delete_by_port(p->br, p, 0); // Don't delete local entry | ||
143 | return 0; | ||
144 | } | ||
145 | static BRPORT_ATTR(flush, S_IWUSR, NULL, store_flush); | ||
146 | |||
140 | static struct brport_attribute *brport_attrs[] = { | 147 | static struct brport_attribute *brport_attrs[] = { |
141 | &brport_attr_path_cost, | 148 | &brport_attr_path_cost, |
142 | &brport_attr_priority, | 149 | &brport_attr_priority, |
@@ -152,6 +159,7 @@ static struct brport_attribute *brport_attrs[] = { | |||
152 | &brport_attr_message_age_timer, | 159 | &brport_attr_message_age_timer, |
153 | &brport_attr_forward_delay_timer, | 160 | &brport_attr_forward_delay_timer, |
154 | &brport_attr_hold_timer, | 161 | &brport_attr_hold_timer, |
162 | &brport_attr_flush, | ||
155 | NULL | 163 | NULL |
156 | }; | 164 | }; |
157 | 165 | ||