Blame view

net/bridge/br_fdb.c 17.3 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
  /*
   *	Forwarding database
   *	Linux ethernet bridge
   *
   *	Authors:
   *	Lennert Buytenhek		<buytenh@gnu.org>
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
11
12
13
14
15
   *	This program is free software; you can redistribute it and/or
   *	modify it under the terms of the GNU General Public License
   *	as published by the Free Software Foundation; either version
   *	2 of the License, or (at your option) any later version.
   */
  
  #include <linux/kernel.h>
  #include <linux/init.h>
82524746c   Franck Bui-Huu   rcu: split list.h...
16
  #include <linux/rculist.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
21
  #include <linux/spinlock.h>
  #include <linux/times.h>
  #include <linux/netdevice.h>
  #include <linux/etherdevice.h>
  #include <linux/jhash.h>
3f8909231   Stephen Hemminger   bridge: simpler h...
22
  #include <linux/random.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
23
  #include <linux/slab.h>
60063497a   Arun Sharma   atomic: use <linu...
24
  #include <linux/atomic.h>
3f8909231   Stephen Hemminger   bridge: simpler h...
25
  #include <asm/unaligned.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  #include "br_private.h"
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
27
  static struct kmem_cache *br_fdb_cache __read_mostly;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
  static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
  		      const unsigned char *addr);
31e8a49c1   stephen hemminger   bridge: rearrange...
30
31
  static void fdb_notify(struct net_bridge *br,
  		       const struct net_bridge_fdb_entry *, int);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32

3f8909231   Stephen Hemminger   bridge: simpler h...
33
  static u32 fdb_salt __read_mostly;
87a596e0b   Akinobu Mita   bridge: check kme...
34
  int __init br_fdb_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
38
  {
  	br_fdb_cache = kmem_cache_create("bridge_fdb_cache",
  					 sizeof(struct net_bridge_fdb_entry),
  					 0,
20c2df83d   Paul Mundt   mm: Remove slab d...
39
  					 SLAB_HWCACHE_ALIGN, NULL);
87a596e0b   Akinobu Mita   bridge: check kme...
40
41
  	if (!br_fdb_cache)
  		return -ENOMEM;
3f8909231   Stephen Hemminger   bridge: simpler h...
42
  	get_random_bytes(&fdb_salt, sizeof(fdb_salt));
87a596e0b   Akinobu Mita   bridge: check kme...
43
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  }
73afc9069   Andrew Morton   [BRIDGE]: Section...
45
  void br_fdb_fini(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
49
50
51
52
53
  {
  	kmem_cache_destroy(br_fdb_cache);
  }
  
  
  /* if topology_changing then use forward_delay (default 15 sec)
   * otherwise keep longer (default 5 minutes)
   */
3f8909231   Stephen Hemminger   bridge: simpler h...
54
  static inline unsigned long hold_time(const struct net_bridge *br)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
  {
  	return br->topology_change ? br->forward_delay : br->ageing_time;
  }
3f8909231   Stephen Hemminger   bridge: simpler h...
58
  static inline int has_expired(const struct net_bridge *br,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
60
  				  const struct net_bridge_fdb_entry *fdb)
  {
f64f9e719   Joe Perches   net: Move && and ...
61
  	return !fdb->is_static &&
7cd8861ab   stephen hemminger   bridge: track las...
62
  		time_before_eq(fdb->updated + hold_time(br), jiffies);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
  }
3f8909231   Stephen Hemminger   bridge: simpler h...
64
  static inline int br_mac_hash(const unsigned char *mac)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
  {
3f8909231   Stephen Hemminger   bridge: simpler h...
66
67
68
  	/* use 1 byte of OUI cnd 3 bytes of NIC */
  	u32 key = get_unaligned((u32 *)(mac + 2));
  	return jhash_1word(key, fdb_salt) & (BR_HASH_SIZE - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
  }
da6782927   Michał Mirosław   bridge: Simplify ...
70
71
72
73
74
75
  static void fdb_rcu_free(struct rcu_head *head)
  {
  	struct net_bridge_fdb_entry *ent
  		= container_of(head, struct net_bridge_fdb_entry, rcu);
  	kmem_cache_free(br_fdb_cache, ent);
  }
31e8a49c1   stephen hemminger   bridge: rearrange...
76
  static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
  {
  	hlist_del_rcu(&f->hlist);
31e8a49c1   stephen hemminger   bridge: rearrange...
79
  	fdb_notify(br, f, RTM_DELNEIGH);
da6782927   Michał Mirosław   bridge: Simplify ...
80
  	call_rcu(&f->rcu, fdb_rcu_free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
83
84
85
86
  }
  
  void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
  {
  	struct net_bridge *br = p->br;
  	int i;
9d6f229fc   YOSHIFUJI Hideaki   [NET] BRIDGE: Fix...
87

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
89
90
91
92
93
94
95
96
97
98
99
100
  	spin_lock_bh(&br->hash_lock);
  
  	/* Search all chains since old address/hash is unknown */
  	for (i = 0; i < BR_HASH_SIZE; i++) {
  		struct hlist_node *h;
  		hlist_for_each(h, &br->hash[i]) {
  			struct net_bridge_fdb_entry *f;
  
  			f = hlist_entry(h, struct net_bridge_fdb_entry, hlist);
  			if (f->dst == p && f->is_local) {
  				/* maybe another port has same hw addr? */
  				struct net_bridge_port *op;
  				list_for_each_entry(op, &br->port_list, list) {
9d6f229fc   YOSHIFUJI Hideaki   [NET] BRIDGE: Fix...
101
  					if (op != p &&
6ede2463c   Stephen Hemminger   [BRIDGE]: Use eth...
102
103
  					    !compare_ether_addr(op->dev->dev_addr,
  								f->addr.addr)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
106
107
108
109
  						f->dst = op;
  						goto insert;
  					}
  				}
  
  				/* delete old one */
31e8a49c1   stephen hemminger   bridge: rearrange...
110
  				fdb_delete(br, f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
112
113
114
115
116
117
118
119
120
  				goto insert;
  			}
  		}
  	}
   insert:
  	/* insert new address,  may fail if invalid address or dup. */
  	fdb_insert(br, p, newaddr);
  
  	spin_unlock_bh(&br->hash_lock);
  }
435988133   stephen hemminger   bridge: add local...
121
122
123
124
125
126
127
128
129
130
131
  void br_fdb_change_mac_address(struct net_bridge *br, const u8 *newaddr)
  {
  	struct net_bridge_fdb_entry *f;
  
  	/* If old entry was unassociated with any port, then delete it. */
  	f = __br_fdb_get(br, br->dev->dev_addr);
  	if (f && f->is_local && !f->dst)
  		fdb_delete(br, f);
  
  	fdb_insert(br, NULL, newaddr);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
134
135
  void br_fdb_cleanup(unsigned long _data)
  {
  	struct net_bridge *br = (struct net_bridge *)_data;
  	unsigned long delay = hold_time(br);
25442e06d   stephen hemminger   bridge: fdb clean...
136
  	unsigned long next_timer = jiffies + br->ageing_time;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
139
140
141
142
143
144
  	int i;
  
  	spin_lock_bh(&br->hash_lock);
  	for (i = 0; i < BR_HASH_SIZE; i++) {
  		struct net_bridge_fdb_entry *f;
  		struct hlist_node *h, *n;
  
  		hlist_for_each_entry_safe(f, h, n, &br->hash[i], hlist) {
071f77226   Baruch Even   [BRIDGE]: Reduce ...
145
146
147
  			unsigned long this_timer;
  			if (f->is_static)
  				continue;
7cd8861ab   stephen hemminger   bridge: track las...
148
  			this_timer = f->updated + delay;
071f77226   Baruch Even   [BRIDGE]: Reduce ...
149
  			if (time_before_eq(this_timer, jiffies))
31e8a49c1   stephen hemminger   bridge: rearrange...
150
  				fdb_delete(br, f);
2bec008ca   Fabio Checconi   bridge: use time_...
151
  			else if (time_before(this_timer, next_timer))
071f77226   Baruch Even   [BRIDGE]: Reduce ...
152
  				next_timer = this_timer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
  		}
  	}
  	spin_unlock_bh(&br->hash_lock);
25442e06d   stephen hemminger   bridge: fdb clean...
156
  	mod_timer(&br->gc_timer, round_jiffies_up(next_timer));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
  }
9cf637473   Stephen Hemminger   bridge: add sysfs...
158
159
160
161
162
163
164
165
166
167
168
  /* Completely flush all dynamic entries in forwarding database.*/
  void br_fdb_flush(struct net_bridge *br)
  {
  	int i;
  
  	spin_lock_bh(&br->hash_lock);
  	for (i = 0; i < BR_HASH_SIZE; i++) {
  		struct net_bridge_fdb_entry *f;
  		struct hlist_node *h, *n;
  		hlist_for_each_entry_safe(f, h, n, &br->hash[i], hlist) {
  			if (!f->is_static)
31e8a49c1   stephen hemminger   bridge: rearrange...
169
  				fdb_delete(br, f);
9cf637473   Stephen Hemminger   bridge: add sysfs...
170
171
172
173
  		}
  	}
  	spin_unlock_bh(&br->hash_lock);
  }
1a620698c   Stephen Hemminger   [BRIDGE]: flush f...
174

25985edce   Lucas De Marchi   Fix common misspe...
175
  /* Flush all entries referring to a specific port.
9cf637473   Stephen Hemminger   bridge: add sysfs...
176
177
   * if do_all is set also flush static entries
   */
1a620698c   Stephen Hemminger   [BRIDGE]: flush f...
178
179
180
  void br_fdb_delete_by_port(struct net_bridge *br,
  			   const struct net_bridge_port *p,
  			   int do_all)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
184
185
186
  {
  	int i;
  
  	spin_lock_bh(&br->hash_lock);
  	for (i = 0; i < BR_HASH_SIZE; i++) {
  		struct hlist_node *h, *g;
9d6f229fc   YOSHIFUJI Hideaki   [NET] BRIDGE: Fix...
187

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
190
  		hlist_for_each_safe(h, g, &br->hash[i]) {
  			struct net_bridge_fdb_entry *f
  				= hlist_entry(h, struct net_bridge_fdb_entry, hlist);
9d6f229fc   YOSHIFUJI Hideaki   [NET] BRIDGE: Fix...
191
  			if (f->dst != p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
  				continue;
1a620698c   Stephen Hemminger   [BRIDGE]: flush f...
193
194
  			if (f->is_static && !do_all)
  				continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
196
197
198
199
200
201
202
  			/*
  			 * if multiple ports all have the same device address
  			 * then when one port is deleted, assign
  			 * the local entry to other port
  			 */
  			if (f->is_local) {
  				struct net_bridge_port *op;
  				list_for_each_entry(op, &br->port_list, list) {
9d6f229fc   YOSHIFUJI Hideaki   [NET] BRIDGE: Fix...
203
  					if (op != p &&
6ede2463c   Stephen Hemminger   [BRIDGE]: Use eth...
204
205
  					    !compare_ether_addr(op->dev->dev_addr,
  								f->addr.addr)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
207
208
209
210
  						f->dst = op;
  						goto skip_delete;
  					}
  				}
  			}
31e8a49c1   stephen hemminger   bridge: rearrange...
211
  			fdb_delete(br, f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
214
215
216
  		skip_delete: ;
  		}
  	}
  	spin_unlock_bh(&br->hash_lock);
  }
eeaf61d88   stephen hemminger   bridge: add rcu_r...
217
  /* No locking or refcounting, assumes caller has rcu_read_lock */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
220
221
222
223
224
  struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br,
  					  const unsigned char *addr)
  {
  	struct hlist_node *h;
  	struct net_bridge_fdb_entry *fdb;
  
  	hlist_for_each_entry_rcu(fdb, h, &br->hash[br_mac_hash(addr)], hlist) {
6ede2463c   Stephen Hemminger   [BRIDGE]: Use eth...
225
  		if (!compare_ether_addr(fdb->addr.addr, addr)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
230
231
232
233
  			if (unlikely(has_expired(br, fdb)))
  				break;
  			return fdb;
  		}
  	}
  
  	return NULL;
  }
e6373c4c0   Igor Maravić   net:bridge: use I...
234
  #if IS_ENABLED(CONFIG_ATM_LANE)
da6782927   Michał Mirosław   bridge: Simplify ...
235
236
237
  /* Interface used by ATM LANE hook to test
   * if an addr is on some other bridge port */
  int br_fdb_test_addr(struct net_device *dev, unsigned char *addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
239
  {
  	struct net_bridge_fdb_entry *fdb;
b5ed54e94   stephen hemminger   bridge: fix RCU r...
240
  	struct net_bridge_port *port;
da6782927   Michał Mirosław   bridge: Simplify ...
241
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
  	rcu_read_lock();
b5ed54e94   stephen hemminger   bridge: fix RCU r...
243
244
245
246
247
  	port = br_port_get_rcu(dev);
  	if (!port)
  		ret = 0;
  	else {
  		fdb = __br_fdb_get(port->br, addr);
435988133   stephen hemminger   bridge: add local...
248
  		ret = fdb && fdb->dst && fdb->dst->dev != dev &&
b5ed54e94   stephen hemminger   bridge: fix RCU r...
249
250
  			fdb->dst->state == BR_STATE_FORWARDING;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252

da6782927   Michał Mirosław   bridge: Simplify ...
253
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
  }
da6782927   Michał Mirosław   bridge: Simplify ...
255
  #endif /* CONFIG_ATM_LANE */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
  
  /*
9d6f229fc   YOSHIFUJI Hideaki   [NET] BRIDGE: Fix...
258
   * Fill buffer with forwarding table records in
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
   * the API format.
   */
  int br_fdb_fillbuf(struct net_bridge *br, void *buf,
  		   unsigned long maxnum, unsigned long skip)
  {
  	struct __fdb_entry *fe = buf;
  	int i, num = 0;
  	struct hlist_node *h;
  	struct net_bridge_fdb_entry *f;
  
  	memset(buf, 0, maxnum*sizeof(struct __fdb_entry));
  
  	rcu_read_lock();
  	for (i = 0; i < BR_HASH_SIZE; i++) {
  		hlist_for_each_entry_rcu(f, h, &br->hash[i], hlist) {
  			if (num >= maxnum)
  				goto out;
9d6f229fc   YOSHIFUJI Hideaki   [NET] BRIDGE: Fix...
276
  			if (has_expired(br, f))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
  				continue;
435988133   stephen hemminger   bridge: add local...
278
279
280
  			/* ignore pseudo entry for local MAC address */
  			if (!f->dst)
  				continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
282
283
284
285
286
287
  			if (skip) {
  				--skip;
  				continue;
  			}
  
  			/* convert from internal format to API */
  			memcpy(fe->mac_addr, f->addr.addr, ETH_ALEN);
ae4f8fca4   Stephen Hemminger   bridge: forwardin...
288
289
  
  			/* due to ABI compat need to split into hi/lo */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
  			fe->port_no = f->dst->port_no;
ae4f8fca4   Stephen Hemminger   bridge: forwardin...
291
  			fe->port_hi = f->dst->port_no >> 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
  			fe->is_local = f->is_local;
  			if (!f->is_static)
7cd8861ab   stephen hemminger   bridge: track las...
294
  				fe->ageing_timer_value = jiffies_to_clock_t(jiffies - f->updated);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
296
297
298
299
300
301
302
303
304
  			++fe;
  			++num;
  		}
  	}
  
   out:
  	rcu_read_unlock();
  
  	return num;
  }
664de48bb   stephen hemminger   bridge: split rcu...
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
  static struct net_bridge_fdb_entry *fdb_find(struct hlist_head *head,
  					     const unsigned char *addr)
  {
  	struct hlist_node *h;
  	struct net_bridge_fdb_entry *fdb;
  
  	hlist_for_each_entry(fdb, h, head, hlist) {
  		if (!compare_ether_addr(fdb->addr.addr, addr))
  			return fdb;
  	}
  	return NULL;
  }
  
  static struct net_bridge_fdb_entry *fdb_find_rcu(struct hlist_head *head,
  						 const unsigned char *addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
321
322
323
324
  {
  	struct hlist_node *h;
  	struct net_bridge_fdb_entry *fdb;
  
  	hlist_for_each_entry_rcu(fdb, h, head, hlist) {
6ede2463c   Stephen Hemminger   [BRIDGE]: Use eth...
325
  		if (!compare_ether_addr(fdb->addr.addr, addr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
328
329
330
331
332
  			return fdb;
  	}
  	return NULL;
  }
  
  static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
  					       struct net_bridge_port *source,
03e9b64b8   stephen hemminger   bridge: change ar...
333
  					       const unsigned char *addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
335
336
337
338
339
  {
  	struct net_bridge_fdb_entry *fdb;
  
  	fdb = kmem_cache_alloc(br_fdb_cache, GFP_ATOMIC);
  	if (fdb) {
  		memcpy(fdb->addr.addr, addr, ETH_ALEN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
  		fdb->dst = source;
03e9b64b8   stephen hemminger   bridge: change ar...
341
342
  		fdb->is_local = 0;
  		fdb->is_static = 0;
7cd8861ab   stephen hemminger   bridge: track las...
343
  		fdb->updated = fdb->used = jiffies;
1158f762e   Pavel Emelyanov   bridge: Don't put...
344
  		hlist_add_head_rcu(&fdb->hlist, head);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
  	}
  	return fdb;
  }
  
  static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
  		  const unsigned char *addr)
  {
  	struct hlist_head *head = &br->hash[br_mac_hash(addr)];
  	struct net_bridge_fdb_entry *fdb;
  
  	if (!is_valid_ether_addr(addr))
  		return -EINVAL;
  
  	fdb = fdb_find(head, addr);
  	if (fdb) {
9d6f229fc   YOSHIFUJI Hideaki   [NET] BRIDGE: Fix...
360
  		/* it is okay to have multiple ports with same
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
362
  		 * address, just use the first one.
  		 */
9d6f229fc   YOSHIFUJI Hideaki   [NET] BRIDGE: Fix...
363
  		if (fdb->is_local)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
  			return 0;
28a16c979   stephen hemminger   bridge: change co...
365
  		br_warn(br, "adding interface %s with same address "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
367
368
  		       "as a received packet
  ",
  		       source->dev->name);
31e8a49c1   stephen hemminger   bridge: rearrange...
369
  		fdb_delete(br, fdb);
9d6f229fc   YOSHIFUJI Hideaki   [NET] BRIDGE: Fix...
370
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371

03e9b64b8   stephen hemminger   bridge: change ar...
372
373
  	fdb = fdb_create(head, source, addr);
  	if (!fdb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
  		return -ENOMEM;
03e9b64b8   stephen hemminger   bridge: change ar...
375
  	fdb->is_local = fdb->is_static = 1;
31e8a49c1   stephen hemminger   bridge: rearrange...
376
  	fdb_notify(br, fdb, RTM_NEWNEIGH);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
  	return 0;
  }
03e9b64b8   stephen hemminger   bridge: change ar...
379
  /* Add entry for local address of interface */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
  int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
  		  const unsigned char *addr)
  {
  	int ret;
  
  	spin_lock_bh(&br->hash_lock);
  	ret = fdb_insert(br, source, addr);
  	spin_unlock_bh(&br->hash_lock);
  	return ret;
  }
  
  void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
  		   const unsigned char *addr)
  {
  	struct hlist_head *head = &br->hash[br_mac_hash(addr)];
  	struct net_bridge_fdb_entry *fdb;
  
  	/* some users want to always flood. */
  	if (hold_time(br) == 0)
  		return;
df1c0b846   Stephen Hemminger   [BRIDGE]: Packets...
400
401
402
403
  	/* ignore packets unless we are using this port */
  	if (!(source->state == BR_STATE_LEARNING ||
  	      source->state == BR_STATE_FORWARDING))
  		return;
664de48bb   stephen hemminger   bridge: split rcu...
404
  	fdb = fdb_find_rcu(head, addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
406
407
  	if (likely(fdb)) {
  		/* attempt to update an entry for a local interface */
  		if (unlikely(fdb->is_local)) {
9d6f229fc   YOSHIFUJI Hideaki   [NET] BRIDGE: Fix...
408
  			if (net_ratelimit())
28a16c979   stephen hemminger   bridge: change co...
409
410
411
412
  				br_warn(br, "received packet on %s with "
  					"own address as source address
  ",
  					source->dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
414
415
  		} else {
  			/* fastpath: update of existing entry */
  			fdb->dst = source;
7cd8861ab   stephen hemminger   bridge: track las...
416
  			fdb->updated = jiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
418
  		}
  	} else {
f8ae737de   Stephen Hemminger   [BRIDGE]: forward...
419
  		spin_lock(&br->hash_lock);
f58ee4e1a   stephen hemminger   bridge: refactor ...
420
421
422
  		if (likely(!fdb_find(head, addr))) {
  			fdb = fdb_create(head, source, addr);
  			if (fdb)
31e8a49c1   stephen hemminger   bridge: rearrange...
423
  				fdb_notify(br, fdb, RTM_NEWNEIGH);
f58ee4e1a   stephen hemminger   bridge: refactor ...
424
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
426
427
  		/* else  we lose race and someone else inserts
  		 * it first, don't bother updating
  		 */
f8ae737de   Stephen Hemminger   [BRIDGE]: forward...
428
  		spin_unlock(&br->hash_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
  }
b078f0df6   stephen hemminger   bridge: add netli...
431
432
433
434
435
436
437
438
439
440
441
442
  
  static int fdb_to_nud(const struct net_bridge_fdb_entry *fdb)
  {
  	if (fdb->is_local)
  		return NUD_PERMANENT;
  	else if (fdb->is_static)
  		return NUD_NOARP;
  	else if (has_expired(fdb->dst->br, fdb))
  		return NUD_STALE;
  	else
  		return NUD_REACHABLE;
  }
31e8a49c1   stephen hemminger   bridge: rearrange...
443
  static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
b078f0df6   stephen hemminger   bridge: add netli...
444
445
446
447
448
449
450
451
452
453
454
  			 const struct net_bridge_fdb_entry *fdb,
  			 u32 pid, u32 seq, int type, unsigned int flags)
  {
  	unsigned long now = jiffies;
  	struct nda_cacheinfo ci;
  	struct nlmsghdr *nlh;
  	struct ndmsg *ndm;
  
  	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
  	if (nlh == NULL)
  		return -EMSGSIZE;
b078f0df6   stephen hemminger   bridge: add netli...
455
456
457
458
459
460
  	ndm = nlmsg_data(nlh);
  	ndm->ndm_family	 = AF_BRIDGE;
  	ndm->ndm_pad1    = 0;
  	ndm->ndm_pad2    = 0;
  	ndm->ndm_flags	 = 0;
  	ndm->ndm_type	 = 0;
435988133   stephen hemminger   bridge: add local...
461
  	ndm->ndm_ifindex = fdb->dst ? fdb->dst->dev->ifindex : br->dev->ifindex;
b078f0df6   stephen hemminger   bridge: add netli...
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
  	ndm->ndm_state   = fdb_to_nud(fdb);
  
  	NLA_PUT(skb, NDA_LLADDR, ETH_ALEN, &fdb->addr);
  
  	ci.ndm_used	 = jiffies_to_clock_t(now - fdb->used);
  	ci.ndm_confirmed = 0;
  	ci.ndm_updated	 = jiffies_to_clock_t(now - fdb->updated);
  	ci.ndm_refcnt	 = 0;
  	NLA_PUT(skb, NDA_CACHEINFO, sizeof(ci), &ci);
  
  	return nlmsg_end(skb, nlh);
  
  nla_put_failure:
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
  }
  
  static inline size_t fdb_nlmsg_size(void)
  {
  	return NLMSG_ALIGN(sizeof(struct ndmsg))
  		+ nla_total_size(ETH_ALEN) /* NDA_LLADDR */
  		+ nla_total_size(sizeof(struct nda_cacheinfo));
  }
31e8a49c1   stephen hemminger   bridge: rearrange...
485
486
  static void fdb_notify(struct net_bridge *br,
  		       const struct net_bridge_fdb_entry *fdb, int type)
b078f0df6   stephen hemminger   bridge: add netli...
487
  {
31e8a49c1   stephen hemminger   bridge: rearrange...
488
  	struct net *net = dev_net(br->dev);
b078f0df6   stephen hemminger   bridge: add netli...
489
490
491
492
493
494
  	struct sk_buff *skb;
  	int err = -ENOBUFS;
  
  	skb = nlmsg_new(fdb_nlmsg_size(), GFP_ATOMIC);
  	if (skb == NULL)
  		goto errout;
31e8a49c1   stephen hemminger   bridge: rearrange...
495
  	err = fdb_fill_info(skb, br, fdb, 0, 0, type, 0);
b078f0df6   stephen hemminger   bridge: add netli...
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
  	if (err < 0) {
  		/* -EMSGSIZE implies BUG in fdb_nlmsg_size() */
  		WARN_ON(err == -EMSGSIZE);
  		kfree_skb(skb);
  		goto errout;
  	}
  	rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
  	return;
  errout:
  	if (err < 0)
  		rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
  }
  
  /* Dump information about entries, in response to GETNEIGH */
  int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
  {
  	struct net *net = sock_net(skb->sk);
  	struct net_device *dev;
  	int idx = 0;
  
  	rcu_read_lock();
  	for_each_netdev_rcu(net, dev) {
  		struct net_bridge *br = netdev_priv(dev);
  		int i;
  
  		if (!(dev->priv_flags & IFF_EBRIDGE))
  			continue;
  
  		for (i = 0; i < BR_HASH_SIZE; i++) {
  			struct hlist_node *h;
  			struct net_bridge_fdb_entry *f;
  
  			hlist_for_each_entry_rcu(f, h, &br->hash[i], hlist) {
  				if (idx < cb->args[0])
  					goto skip;
31e8a49c1   stephen hemminger   bridge: rearrange...
531
  				if (fdb_fill_info(skb, br, f,
b078f0df6   stephen hemminger   bridge: add netli...
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
  						  NETLINK_CB(cb->skb).pid,
  						  cb->nlh->nlmsg_seq,
  						  RTM_NEWNEIGH,
  						  NLM_F_MULTI) < 0)
  					break;
  skip:
  				++idx;
  			}
  		}
  	}
  	rcu_read_unlock();
  
  	cb->args[0] = idx;
  
  	return skb->len;
  }
36fd2b63e   stephen hemminger   bridge: allow cre...
548

292d13989   stephen hemminger   bridge: add NTF_U...
549
  /* Update (create or replace) forwarding database entry */
36fd2b63e   stephen hemminger   bridge: allow cre...
550
  static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
64af1bac9   stephen hemminger   bridge: allow upd...
551
  			 __u16 state, __u16 flags)
36fd2b63e   stephen hemminger   bridge: allow cre...
552
553
554
555
556
557
  {
  	struct net_bridge *br = source->br;
  	struct hlist_head *head = &br->hash[br_mac_hash(addr)];
  	struct net_bridge_fdb_entry *fdb;
  
  	fdb = fdb_find(head, addr);
64af1bac9   stephen hemminger   bridge: allow upd...
558
559
560
  	if (fdb == NULL) {
  		if (!(flags & NLM_F_CREATE))
  			return -ENOENT;
36fd2b63e   stephen hemminger   bridge: allow cre...
561

64af1bac9   stephen hemminger   bridge: allow upd...
562
563
564
  		fdb = fdb_create(head, source, addr);
  		if (!fdb)
  			return -ENOMEM;
31e8a49c1   stephen hemminger   bridge: rearrange...
565
  		fdb_notify(br, fdb, RTM_NEWNEIGH);
64af1bac9   stephen hemminger   bridge: allow upd...
566
567
568
  	} else {
  		if (flags & NLM_F_EXCL)
  			return -EEXIST;
292d13989   stephen hemminger   bridge: add NTF_U...
569
570
571
572
573
574
575
576
577
578
  	}
  
  	if (fdb_to_nud(fdb) != state) {
  		if (state & NUD_PERMANENT)
  			fdb->is_local = fdb->is_static = 1;
  		else if (state & NUD_NOARP) {
  			fdb->is_local = 0;
  			fdb->is_static = 1;
  		} else
  			fdb->is_local = fdb->is_static = 0;
64af1bac9   stephen hemminger   bridge: allow upd...
579

292d13989   stephen hemminger   bridge: add NTF_U...
580
  		fdb->updated = fdb->used = jiffies;
31e8a49c1   stephen hemminger   bridge: rearrange...
581
  		fdb_notify(br, fdb, RTM_NEWNEIGH);
64af1bac9   stephen hemminger   bridge: allow upd...
582
  	}
36fd2b63e   stephen hemminger   bridge: allow cre...
583

36fd2b63e   stephen hemminger   bridge: allow cre...
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
  	return 0;
  }
  
  /* Add new permanent fdb entry with RTM_NEWNEIGH */
  int br_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
  {
  	struct net *net = sock_net(skb->sk);
  	struct ndmsg *ndm;
  	struct nlattr *tb[NDA_MAX+1];
  	struct net_device *dev;
  	struct net_bridge_port *p;
  	const __u8 *addr;
  	int err;
  
  	ASSERT_RTNL();
  	err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
  	if (err < 0)
  		return err;
  
  	ndm = nlmsg_data(nlh);
  	if (ndm->ndm_ifindex == 0) {
  		pr_info("bridge: RTM_NEWNEIGH with invalid ifindex
  ");
  		return -EINVAL;
  	}
  
  	dev = __dev_get_by_index(net, ndm->ndm_ifindex);
  	if (dev == NULL) {
  		pr_info("bridge: RTM_NEWNEIGH with unknown ifindex
  ");
  		return -ENODEV;
  	}
  
  	if (!tb[NDA_LLADDR] || nla_len(tb[NDA_LLADDR]) != ETH_ALEN) {
  		pr_info("bridge: RTM_NEWNEIGH with invalid address
  ");
  		return -EINVAL;
  	}
  
  	addr = nla_data(tb[NDA_LLADDR]);
  	if (!is_valid_ether_addr(addr)) {
  		pr_info("bridge: RTM_NEWNEIGH with invalid ether address
  ");
  		return -EINVAL;
  	}
292d13989   stephen hemminger   bridge: add NTF_U...
629
630
631
632
633
  	if (!(ndm->ndm_state & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE))) {
  		pr_info("bridge: RTM_NEWNEIGH with invalid state %#x
  ", ndm->ndm_state);
  		return -EINVAL;
  	}
36fd2b63e   stephen hemminger   bridge: allow cre...
634
635
636
637
638
639
640
  	p = br_port_get_rtnl(dev);
  	if (p == NULL) {
  		pr_info("bridge: RTM_NEWNEIGH %s not a bridge port
  ",
  			dev->name);
  		return -EINVAL;
  	}
292d13989   stephen hemminger   bridge: add NTF_U...
641
642
643
644
645
646
647
648
649
  	if (ndm->ndm_flags & NTF_USE) {
  		rcu_read_lock();
  		br_fdb_update(p->br, p, addr);
  		rcu_read_unlock();
  	} else {
  		spin_lock_bh(&p->br->hash_lock);
  		err = fdb_add_entry(p, addr, ndm->ndm_state, nlh->nlmsg_flags);
  		spin_unlock_bh(&p->br->hash_lock);
  	}
36fd2b63e   stephen hemminger   bridge: allow cre...
650
651
652
653
654
655
656
657
658
659
660
661
662
  
  	return err;
  }
  
  static int fdb_delete_by_addr(struct net_bridge_port *p, const u8 *addr)
  {
  	struct net_bridge *br = p->br;
  	struct hlist_head *head = &br->hash[br_mac_hash(addr)];
  	struct net_bridge_fdb_entry *fdb;
  
  	fdb = fdb_find(head, addr);
  	if (!fdb)
  		return -ENOENT;
31e8a49c1   stephen hemminger   bridge: rearrange...
663
  	fdb_delete(p->br, fdb);
36fd2b63e   stephen hemminger   bridge: allow cre...
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
  	return 0;
  }
  
  /* Remove neighbor entry with RTM_DELNEIGH */
  int br_fdb_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
  {
  	struct net *net = sock_net(skb->sk);
  	struct ndmsg *ndm;
  	struct net_bridge_port *p;
  	struct nlattr *llattr;
  	const __u8 *addr;
  	struct net_device *dev;
  	int err;
  
  	ASSERT_RTNL();
  	if (nlmsg_len(nlh) < sizeof(*ndm))
  		return -EINVAL;
  
  	ndm = nlmsg_data(nlh);
  	if (ndm->ndm_ifindex == 0) {
  		pr_info("bridge: RTM_DELNEIGH with invalid ifindex
  ");
  		return -EINVAL;
  	}
  
  	dev = __dev_get_by_index(net, ndm->ndm_ifindex);
  	if (dev == NULL) {
  		pr_info("bridge: RTM_DELNEIGH with unknown ifindex
  ");
  		return -ENODEV;
  	}
  
  	llattr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_LLADDR);
  	if (llattr == NULL || nla_len(llattr) != ETH_ALEN) {
  		pr_info("bridge: RTM_DELNEIGH with invalid address
  ");
  		return -EINVAL;
  	}
  
  	addr = nla_data(llattr);
  
  	p = br_port_get_rtnl(dev);
  	if (p == NULL) {
  		pr_info("bridge: RTM_DELNEIGH %s not a bridge port
  ",
  			dev->name);
  		return -EINVAL;
  	}
  
  	spin_lock_bh(&p->br->hash_lock);
  	err = fdb_delete_by_addr(p, addr);
  	spin_unlock_bh(&p->br->hash_lock);
  
  	return err;
  }