diff options
Diffstat (limited to 'net/bridge')
-rw-r--r-- | net/bridge/br.c | 10 | ||||
-rw-r--r-- | net/bridge/br_fdb.c | 43 | ||||
-rw-r--r-- | net/bridge/br_private.h | 12 |
3 files changed, 31 insertions, 34 deletions
diff --git a/net/bridge/br.c b/net/bridge/br.c index 4d2c1f1cb524..9aac5213105a 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c | |||
@@ -65,8 +65,9 @@ static int __init br_init(void) | |||
65 | brioctl_set(br_ioctl_deviceless_stub); | 65 | brioctl_set(br_ioctl_deviceless_stub); |
66 | br_handle_frame_hook = br_handle_frame; | 66 | br_handle_frame_hook = br_handle_frame; |
67 | 67 | ||
68 | br_fdb_get_hook = br_fdb_get; | 68 | #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) |
69 | br_fdb_put_hook = br_fdb_put; | 69 | br_fdb_test_addr_hook = br_fdb_test_addr; |
70 | #endif | ||
70 | 71 | ||
71 | return 0; | 72 | return 0; |
72 | err_out4: | 73 | err_out4: |
@@ -95,8 +96,9 @@ static void __exit br_deinit(void) | |||
95 | synchronize_net(); | 96 | synchronize_net(); |
96 | 97 | ||
97 | br_netfilter_fini(); | 98 | br_netfilter_fini(); |
98 | br_fdb_get_hook = NULL; | 99 | #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) |
99 | br_fdb_put_hook = NULL; | 100 | br_fdb_test_addr_hook = NULL; |
101 | #endif | ||
100 | 102 | ||
101 | br_handle_frame_hook = NULL; | 103 | br_handle_frame_hook = NULL; |
102 | br_fdb_fini(); | 104 | br_fdb_fini(); |
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index cb3e97b93aeb..57bf05c353bc 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c | |||
@@ -71,10 +71,17 @@ static inline int br_mac_hash(const unsigned char *mac) | |||
71 | return jhash_1word(key, fdb_salt) & (BR_HASH_SIZE - 1); | 71 | return jhash_1word(key, fdb_salt) & (BR_HASH_SIZE - 1); |
72 | } | 72 | } |
73 | 73 | ||
74 | static void fdb_rcu_free(struct rcu_head *head) | ||
75 | { | ||
76 | struct net_bridge_fdb_entry *ent | ||
77 | = container_of(head, struct net_bridge_fdb_entry, rcu); | ||
78 | kmem_cache_free(br_fdb_cache, ent); | ||
79 | } | ||
80 | |||
74 | static inline void fdb_delete(struct net_bridge_fdb_entry *f) | 81 | static inline void fdb_delete(struct net_bridge_fdb_entry *f) |
75 | { | 82 | { |
76 | hlist_del_rcu(&f->hlist); | 83 | hlist_del_rcu(&f->hlist); |
77 | br_fdb_put(f); | 84 | call_rcu(&f->rcu, fdb_rcu_free); |
78 | } | 85 | } |
79 | 86 | ||
80 | void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr) | 87 | void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr) |
@@ -226,33 +233,26 @@ struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, | |||
226 | return NULL; | 233 | return NULL; |
227 | } | 234 | } |
228 | 235 | ||
229 | /* Interface used by ATM hook that keeps a ref count */ | 236 | #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) |
230 | struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br, | 237 | /* Interface used by ATM LANE hook to test |
231 | unsigned char *addr) | 238 | * if an addr is on some other bridge port */ |
239 | int br_fdb_test_addr(struct net_device *dev, unsigned char *addr) | ||
232 | { | 240 | { |
233 | struct net_bridge_fdb_entry *fdb; | 241 | struct net_bridge_fdb_entry *fdb; |
242 | int ret; | ||
243 | |||
244 | if (!dev->br_port) | ||
245 | return 0; | ||
234 | 246 | ||
235 | rcu_read_lock(); | 247 | rcu_read_lock(); |
236 | fdb = __br_fdb_get(br, addr); | 248 | fdb = __br_fdb_get(dev->br_port->br, addr); |
237 | if (fdb && !atomic_inc_not_zero(&fdb->use_count)) | 249 | ret = fdb && fdb->dst->dev != dev && |
238 | fdb = NULL; | 250 | fdb->dst->state == BR_STATE_FORWARDING; |
239 | rcu_read_unlock(); | 251 | rcu_read_unlock(); |
240 | return fdb; | ||
241 | } | ||
242 | |||
243 | static void fdb_rcu_free(struct rcu_head *head) | ||
244 | { | ||
245 | struct net_bridge_fdb_entry *ent | ||
246 | = container_of(head, struct net_bridge_fdb_entry, rcu); | ||
247 | kmem_cache_free(br_fdb_cache, ent); | ||
248 | } | ||
249 | 252 | ||
250 | /* Set entry up for deletion with RCU */ | 253 | return ret; |
251 | void br_fdb_put(struct net_bridge_fdb_entry *ent) | ||
252 | { | ||
253 | if (atomic_dec_and_test(&ent->use_count)) | ||
254 | call_rcu(&ent->rcu, fdb_rcu_free); | ||
255 | } | 254 | } |
255 | #endif /* CONFIG_ATM_LANE */ | ||
256 | 256 | ||
257 | /* | 257 | /* |
258 | * Fill buffer with forwarding table records in | 258 | * Fill buffer with forwarding table records in |
@@ -326,7 +326,6 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head, | |||
326 | fdb = kmem_cache_alloc(br_fdb_cache, GFP_ATOMIC); | 326 | fdb = kmem_cache_alloc(br_fdb_cache, GFP_ATOMIC); |
327 | if (fdb) { | 327 | if (fdb) { |
328 | memcpy(fdb->addr.addr, addr, ETH_ALEN); | 328 | memcpy(fdb->addr.addr, addr, ETH_ALEN); |
329 | atomic_set(&fdb->use_count, 1); | ||
330 | hlist_add_head_rcu(&fdb->hlist, head); | 329 | hlist_add_head_rcu(&fdb->hlist, head); |
331 | 330 | ||
332 | fdb->dst = source; | 331 | fdb->dst = source; |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index b6c3b71974dc..d5b5537272b4 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -51,7 +51,6 @@ struct net_bridge_fdb_entry | |||
51 | struct net_bridge_port *dst; | 51 | struct net_bridge_port *dst; |
52 | 52 | ||
53 | struct rcu_head rcu; | 53 | struct rcu_head rcu; |
54 | atomic_t use_count; | ||
55 | unsigned long ageing_timer; | 54 | unsigned long ageing_timer; |
56 | mac_addr addr; | 55 | mac_addr addr; |
57 | unsigned char is_local; | 56 | unsigned char is_local; |
@@ -154,9 +153,7 @@ extern void br_fdb_delete_by_port(struct net_bridge *br, | |||
154 | const struct net_bridge_port *p, int do_all); | 153 | const struct net_bridge_port *p, int do_all); |
155 | extern struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, | 154 | extern struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, |
156 | const unsigned char *addr); | 155 | const unsigned char *addr); |
157 | extern struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br, | 156 | extern int br_fdb_test_addr(struct net_device *dev, unsigned char *addr); |
158 | unsigned char *addr); | ||
159 | extern void br_fdb_put(struct net_bridge_fdb_entry *ent); | ||
160 | extern int br_fdb_fillbuf(struct net_bridge *br, void *buf, | 157 | extern int br_fdb_fillbuf(struct net_bridge *br, void *buf, |
161 | unsigned long count, unsigned long off); | 158 | unsigned long count, unsigned long off); |
162 | extern int br_fdb_insert(struct net_bridge *br, | 159 | extern int br_fdb_insert(struct net_bridge *br, |
@@ -242,10 +239,9 @@ extern void br_stp_port_timer_init(struct net_bridge_port *p); | |||
242 | extern unsigned long br_timer_value(const struct timer_list *timer); | 239 | extern unsigned long br_timer_value(const struct timer_list *timer); |
243 | 240 | ||
244 | /* br.c */ | 241 | /* br.c */ |
245 | extern struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br, | 242 | #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) |
246 | unsigned char *addr); | 243 | extern int (*br_fdb_test_addr_hook)(struct net_device *dev, unsigned char *addr); |
247 | extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent); | 244 | #endif |
248 | |||
249 | 245 | ||
250 | /* br_netlink.c */ | 246 | /* br_netlink.c */ |
251 | extern int br_netlink_init(void); | 247 | extern int br_netlink_init(void); |