diff options
Diffstat (limited to 'net/bridge/br_fdb.c')
-rw-r--r-- | net/bridge/br_fdb.c | 42 |
1 files changed, 36 insertions, 6 deletions
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 8d566c13cc73..91b017016d5b 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c | |||
@@ -20,19 +20,28 @@ | |||
20 | #include <linux/netdevice.h> | 20 | #include <linux/netdevice.h> |
21 | #include <linux/etherdevice.h> | 21 | #include <linux/etherdevice.h> |
22 | #include <linux/jhash.h> | 22 | #include <linux/jhash.h> |
23 | #include <linux/random.h> | ||
23 | #include <asm/atomic.h> | 24 | #include <asm/atomic.h> |
25 | #include <asm/unaligned.h> | ||
24 | #include "br_private.h" | 26 | #include "br_private.h" |
25 | 27 | ||
26 | static struct kmem_cache *br_fdb_cache __read_mostly; | 28 | static struct kmem_cache *br_fdb_cache __read_mostly; |
27 | static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, | 29 | static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, |
28 | const unsigned char *addr); | 30 | const unsigned char *addr); |
29 | 31 | ||
30 | void __init br_fdb_init(void) | 32 | static u32 fdb_salt __read_mostly; |
33 | |||
34 | int __init br_fdb_init(void) | ||
31 | { | 35 | { |
32 | br_fdb_cache = kmem_cache_create("bridge_fdb_cache", | 36 | br_fdb_cache = kmem_cache_create("bridge_fdb_cache", |
33 | sizeof(struct net_bridge_fdb_entry), | 37 | sizeof(struct net_bridge_fdb_entry), |
34 | 0, | 38 | 0, |
35 | SLAB_HWCACHE_ALIGN, NULL, NULL); | 39 | SLAB_HWCACHE_ALIGN, NULL, NULL); |
40 | if (!br_fdb_cache) | ||
41 | return -ENOMEM; | ||
42 | |||
43 | get_random_bytes(&fdb_salt, sizeof(fdb_salt)); | ||
44 | return 0; | ||
36 | } | 45 | } |
37 | 46 | ||
38 | void __exit br_fdb_fini(void) | 47 | void __exit br_fdb_fini(void) |
@@ -44,24 +53,26 @@ void __exit br_fdb_fini(void) | |||
44 | /* if topology_changing then use forward_delay (default 15 sec) | 53 | /* if topology_changing then use forward_delay (default 15 sec) |
45 | * otherwise keep longer (default 5 minutes) | 54 | * otherwise keep longer (default 5 minutes) |
46 | */ | 55 | */ |
47 | static __inline__ unsigned long hold_time(const struct net_bridge *br) | 56 | static inline unsigned long hold_time(const struct net_bridge *br) |
48 | { | 57 | { |
49 | return br->topology_change ? br->forward_delay : br->ageing_time; | 58 | return br->topology_change ? br->forward_delay : br->ageing_time; |
50 | } | 59 | } |
51 | 60 | ||
52 | static __inline__ int has_expired(const struct net_bridge *br, | 61 | static inline int has_expired(const struct net_bridge *br, |
53 | const struct net_bridge_fdb_entry *fdb) | 62 | const struct net_bridge_fdb_entry *fdb) |
54 | { | 63 | { |
55 | return !fdb->is_static | 64 | return !fdb->is_static |
56 | && time_before_eq(fdb->ageing_timer + hold_time(br), jiffies); | 65 | && time_before_eq(fdb->ageing_timer + hold_time(br), jiffies); |
57 | } | 66 | } |
58 | 67 | ||
59 | static __inline__ int br_mac_hash(const unsigned char *mac) | 68 | static inline int br_mac_hash(const unsigned char *mac) |
60 | { | 69 | { |
61 | return jhash(mac, ETH_ALEN, 0) & (BR_HASH_SIZE - 1); | 70 | /* use 1 byte of OUI cnd 3 bytes of NIC */ |
71 | u32 key = get_unaligned((u32 *)(mac + 2)); | ||
72 | return jhash_1word(key, fdb_salt) & (BR_HASH_SIZE - 1); | ||
62 | } | 73 | } |
63 | 74 | ||
64 | static __inline__ void fdb_delete(struct net_bridge_fdb_entry *f) | 75 | static inline void fdb_delete(struct net_bridge_fdb_entry *f) |
65 | { | 76 | { |
66 | hlist_del_rcu(&f->hlist); | 77 | hlist_del_rcu(&f->hlist); |
67 | br_fdb_put(f); | 78 | br_fdb_put(f); |
@@ -128,7 +139,26 @@ void br_fdb_cleanup(unsigned long _data) | |||
128 | mod_timer(&br->gc_timer, jiffies + HZ/10); | 139 | mod_timer(&br->gc_timer, jiffies + HZ/10); |
129 | } | 140 | } |
130 | 141 | ||
142 | /* Completely flush all dynamic entries in forwarding database.*/ | ||
143 | void br_fdb_flush(struct net_bridge *br) | ||
144 | { | ||
145 | int i; | ||
131 | 146 | ||
147 | spin_lock_bh(&br->hash_lock); | ||
148 | for (i = 0; i < BR_HASH_SIZE; i++) { | ||
149 | struct net_bridge_fdb_entry *f; | ||
150 | struct hlist_node *h, *n; | ||
151 | hlist_for_each_entry_safe(f, h, n, &br->hash[i], hlist) { | ||
152 | if (!f->is_static) | ||
153 | fdb_delete(f); | ||
154 | } | ||
155 | } | ||
156 | spin_unlock_bh(&br->hash_lock); | ||
157 | } | ||
158 | |||
159 | /* Flush all entries refering to a specific port. | ||
160 | * if do_all is set also flush static entries | ||
161 | */ | ||
132 | void br_fdb_delete_by_port(struct net_bridge *br, | 162 | void br_fdb_delete_by_port(struct net_bridge *br, |
133 | const struct net_bridge_port *p, | 163 | const struct net_bridge_port *p, |
134 | int do_all) | 164 | int do_all) |