blob: 36fc692e2bdea89f63395f5b5732e5a239d095b9 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Generic address resolution entity
3 *
4 * Authors:
5 * Pedro Roque <roque@di.fc.ul.pt>
6 * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 *
13 * Fixes:
14 * Vitaly E. Lavrov releasing NULL neighbor in neigh_add.
15 * Harald Welte Add neighbour cache statistics like rtstat
16 */
17
Joe Perchese005d192012-05-16 19:58:40 +000018#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090020#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/types.h>
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/socket.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#include <linux/netdevice.h>
26#include <linux/proc_fs.h>
27#ifdef CONFIG_SYSCTL
28#include <linux/sysctl.h>
29#endif
30#include <linux/times.h>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020031#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <net/neighbour.h>
33#include <net/dst.h>
34#include <net/sock.h>
Tom Tucker8d717402006-07-30 20:43:36 -070035#include <net/netevent.h>
Thomas Grafa14a49d2006-08-07 17:53:08 -070036#include <net/netlink.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <linux/rtnetlink.h>
38#include <linux/random.h>
Paulo Marques543537b2005-06-23 00:09:02 -070039#include <linux/string.h>
vignesh babuc3609d52007-08-24 22:27:55 -070040#include <linux/log2.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42#define NEIGH_DEBUG 1
43
44#define NEIGH_PRINTK(x...) printk(x)
45#define NEIGH_NOPRINTK(x...) do { ; } while(0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#define NEIGH_PRINTK1 NEIGH_NOPRINTK
47#define NEIGH_PRINTK2 NEIGH_NOPRINTK
48
49#if NEIGH_DEBUG >= 1
50#undef NEIGH_PRINTK1
51#define NEIGH_PRINTK1 NEIGH_PRINTK
52#endif
53#if NEIGH_DEBUG >= 2
54#undef NEIGH_PRINTK2
55#define NEIGH_PRINTK2 NEIGH_PRINTK
56#endif
57
58#define PNEIGH_HASHMASK 0xF
59
60static void neigh_timer_handler(unsigned long arg);
Thomas Grafd961db32007-08-08 23:12:56 -070061static void __neigh_notify(struct neighbour *n, int type, int flags);
62static void neigh_update_notify(struct neighbour *neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
Shan Weice46cc62012-12-04 18:49:15 +000065static int zero;
66static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
67
Linus Torvalds1da177e2005-04-16 15:20:36 -070068static struct neigh_table *neigh_tables;
Amos Waterland45fc3b12005-09-24 16:53:16 -070069#ifdef CONFIG_PROC_FS
Arjan van de Ven9a321442007-02-12 00:55:35 -080070static const struct file_operations neigh_stat_seq_fops;
Amos Waterland45fc3b12005-09-24 16:53:16 -070071#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
73/*
74 Neighbour hash table buckets are protected with rwlock tbl->lock.
75
76 - All the scans/updates to hash buckets MUST be made under this lock.
77 - NOTHING clever should be made under this lock: no callbacks
78 to protocol backends, no attempts to send something to network.
79 It will result in deadlocks, if backend/driver wants to use neighbour
80 cache.
81 - If the entry requires some non-trivial actions, increase
82 its reference count and release table lock.
83
84 Neighbour entries are protected:
85 - with reference count.
86 - with rwlock neigh->lock
87
88 Reference count prevents destruction.
89
90 neigh->lock mainly serializes ll address data and its validity state.
91 However, the same lock is used to protect another entry fields:
92 - timer
93 - resolution queue
94
95 Again, nothing clever shall be made under neigh->lock,
96 the most complicated procedure, which we allow is dev->hard_header.
97 It is supposed, that dev->hard_header is simplistic and does
98 not make callbacks to neighbour tables.
99
100 The last lock is neigh_tbl_lock. It is pure SMP lock, protecting
101 list of neighbour tables. This list is used only in process context,
102 */
103
104static DEFINE_RWLOCK(neigh_tbl_lock);
105
David S. Miller8f40b162011-07-17 13:34:11 -0700106static int neigh_blackhole(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107{
108 kfree_skb(skb);
109 return -ENETDOWN;
110}
111
Thomas Graf4f494552007-08-08 23:12:36 -0700112static void neigh_cleanup_and_release(struct neighbour *neigh)
113{
114 if (neigh->parms->neigh_cleanup)
115 neigh->parms->neigh_cleanup(neigh);
116
Thomas Grafd961db32007-08-08 23:12:56 -0700117 __neigh_notify(neigh, RTM_DELNEIGH, 0);
Thomas Graf4f494552007-08-08 23:12:36 -0700118 neigh_release(neigh);
119}
120
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121/*
122 * It is random distribution in the interval (1/2)*base...(3/2)*base.
123 * It corresponds to default IPv6 settings and is not overridable,
124 * because it is really reasonable choice.
125 */
126
127unsigned long neigh_rand_reach_time(unsigned long base)
128{
Eric Dumazeta02cec22010-09-22 20:43:57 +0000129 return base ? (net_random() % base) + (base >> 1) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900131EXPORT_SYMBOL(neigh_rand_reach_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
133
134static int neigh_forced_gc(struct neigh_table *tbl)
135{
136 int shrunk = 0;
137 int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000138 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
140 NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
141
142 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000143 nht = rcu_dereference_protected(tbl->nht,
144 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -0700145 for (i = 0; i < (1 << nht->hash_shift); i++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700146 struct neighbour *n;
147 struct neighbour __rcu **np;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000149 np = &nht->hash_buckets[i];
Eric Dumazet767e97e2010-10-06 17:49:21 -0700150 while ((n = rcu_dereference_protected(*np,
151 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 /* Neighbour record may be discarded if:
153 * - nobody refers to it.
154 * - it is not permanent
155 */
156 write_lock(&n->lock);
157 if (atomic_read(&n->refcnt) == 1 &&
158 !(n->nud_state & NUD_PERMANENT)) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700159 rcu_assign_pointer(*np,
160 rcu_dereference_protected(n->next,
161 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 n->dead = 1;
163 shrunk = 1;
164 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -0700165 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 continue;
167 }
168 write_unlock(&n->lock);
169 np = &n->next;
170 }
171 }
172
173 tbl->last_flush = jiffies;
174
175 write_unlock_bh(&tbl->lock);
176
177 return shrunk;
178}
179
Pavel Emelyanova43d8992007-12-20 15:49:05 -0800180static void neigh_add_timer(struct neighbour *n, unsigned long when)
181{
182 neigh_hold(n);
183 if (unlikely(mod_timer(&n->timer, when))) {
184 printk("NEIGH: BUG, double timer add, state is %x\n",
185 n->nud_state);
186 dump_stack();
187 }
188}
189
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190static int neigh_del_timer(struct neighbour *n)
191{
192 if ((n->nud_state & NUD_IN_TIMER) &&
193 del_timer(&n->timer)) {
194 neigh_release(n);
195 return 1;
196 }
197 return 0;
198}
199
200static void pneigh_queue_purge(struct sk_buff_head *list)
201{
202 struct sk_buff *skb;
203
204 while ((skb = skb_dequeue(list)) != NULL) {
205 dev_put(skb->dev);
206 kfree_skb(skb);
207 }
208}
209
Herbert Xu49636bb2005-10-23 17:18:00 +1000210static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211{
212 int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000213 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000215 nht = rcu_dereference_protected(tbl->nht,
216 lockdep_is_held(&tbl->lock));
217
David S. Millercd089332011-07-11 01:28:12 -0700218 for (i = 0; i < (1 << nht->hash_shift); i++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700219 struct neighbour *n;
220 struct neighbour __rcu **np = &nht->hash_buckets[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221
Eric Dumazet767e97e2010-10-06 17:49:21 -0700222 while ((n = rcu_dereference_protected(*np,
223 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 if (dev && n->dev != dev) {
225 np = &n->next;
226 continue;
227 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700228 rcu_assign_pointer(*np,
229 rcu_dereference_protected(n->next,
230 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 write_lock(&n->lock);
232 neigh_del_timer(n);
233 n->dead = 1;
234
235 if (atomic_read(&n->refcnt) != 1) {
236 /* The most unpleasant situation.
237 We must destroy neighbour entry,
238 but someone still uses it.
239
240 The destroy will be delayed until
241 the last user releases us, but
242 we must kill timers etc. and move
243 it to safe state.
244 */
245 skb_queue_purge(&n->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000246 n->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 n->output = neigh_blackhole;
248 if (n->nud_state & NUD_VALID)
249 n->nud_state = NUD_NOARP;
250 else
251 n->nud_state = NUD_NONE;
252 NEIGH_PRINTK2("neigh %p is stray.\n", n);
253 }
254 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -0700255 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 }
257 }
Herbert Xu49636bb2005-10-23 17:18:00 +1000258}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
Herbert Xu49636bb2005-10-23 17:18:00 +1000260void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
261{
262 write_lock_bh(&tbl->lock);
263 neigh_flush_dev(tbl, dev);
264 write_unlock_bh(&tbl->lock);
265}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900266EXPORT_SYMBOL(neigh_changeaddr);
Herbert Xu49636bb2005-10-23 17:18:00 +1000267
268int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
269{
270 write_lock_bh(&tbl->lock);
271 neigh_flush_dev(tbl, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 pneigh_ifdown(tbl, dev);
273 write_unlock_bh(&tbl->lock);
274
275 del_timer_sync(&tbl->proxy_timer);
276 pneigh_queue_purge(&tbl->proxy_queue);
277 return 0;
278}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900279EXPORT_SYMBOL(neigh_ifdown);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
David Miller596b9b62011-07-25 00:01:25 +0000281static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282{
283 struct neighbour *n = NULL;
284 unsigned long now = jiffies;
285 int entries;
286
287 entries = atomic_inc_return(&tbl->entries) - 1;
288 if (entries >= tbl->gc_thresh3 ||
289 (entries >= tbl->gc_thresh2 &&
290 time_after(now, tbl->last_flush + 5 * HZ))) {
291 if (!neigh_forced_gc(tbl) &&
292 entries >= tbl->gc_thresh3)
293 goto out_entries;
294 }
295
David Miller596b9b62011-07-25 00:01:25 +0000296 if (tbl->entry_size)
297 n = kzalloc(tbl->entry_size, GFP_ATOMIC);
298 else {
299 int sz = sizeof(*n) + tbl->key_len;
300
301 sz = ALIGN(sz, NEIGH_PRIV_ALIGN);
302 sz += dev->neigh_priv_len;
303 n = kzalloc(sz, GFP_ATOMIC);
304 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 if (!n)
306 goto out_entries;
307
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 skb_queue_head_init(&n->arp_queue);
309 rwlock_init(&n->lock);
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +0000310 seqlock_init(&n->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 n->updated = n->used = now;
312 n->nud_state = NUD_NONE;
313 n->output = neigh_blackhole;
David S. Millerf6b72b622011-07-14 07:53:20 -0700314 seqlock_init(&n->hh.hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 n->parms = neigh_parms_clone(&tbl->parms);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800316 setup_timer(&n->timer, neigh_timer_handler, (unsigned long)n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
318 NEIGH_CACHE_STAT_INC(tbl, allocs);
319 n->tbl = tbl;
320 atomic_set(&n->refcnt, 1);
321 n->dead = 1;
322out:
323 return n;
324
325out_entries:
326 atomic_dec(&tbl->entries);
327 goto out;
328}
329
David S. Miller2c2aba62011-12-28 15:06:58 -0500330static void neigh_get_hash_rnd(u32 *x)
331{
332 get_random_bytes(x, sizeof(*x));
333 *x |= 1;
334}
335
David S. Millercd089332011-07-11 01:28:12 -0700336static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337{
David S. Millercd089332011-07-11 01:28:12 -0700338 size_t size = (1 << shift) * sizeof(struct neighbour *);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000339 struct neigh_hash_table *ret;
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000340 struct neighbour __rcu **buckets;
David S. Miller2c2aba62011-12-28 15:06:58 -0500341 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000343 ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
344 if (!ret)
345 return NULL;
346 if (size <= PAGE_SIZE)
347 buckets = kzalloc(size, GFP_ATOMIC);
348 else
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000349 buckets = (struct neighbour __rcu **)
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000350 __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
351 get_order(size));
352 if (!buckets) {
353 kfree(ret);
354 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 }
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000356 ret->hash_buckets = buckets;
David S. Millercd089332011-07-11 01:28:12 -0700357 ret->hash_shift = shift;
David S. Miller2c2aba62011-12-28 15:06:58 -0500358 for (i = 0; i < NEIGH_NUM_HASH_RND; i++)
359 neigh_get_hash_rnd(&ret->hash_rnd[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 return ret;
361}
362
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000363static void neigh_hash_free_rcu(struct rcu_head *head)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364{
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000365 struct neigh_hash_table *nht = container_of(head,
366 struct neigh_hash_table,
367 rcu);
David S. Millercd089332011-07-11 01:28:12 -0700368 size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *);
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000369 struct neighbour __rcu **buckets = nht->hash_buckets;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
371 if (size <= PAGE_SIZE)
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000372 kfree(buckets);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 else
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000374 free_pages((unsigned long)buckets, get_order(size));
375 kfree(nht);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376}
377
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000378static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
David S. Millercd089332011-07-11 01:28:12 -0700379 unsigned long new_shift)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380{
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000381 unsigned int i, hash;
382 struct neigh_hash_table *new_nht, *old_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
384 NEIGH_CACHE_STAT_INC(tbl, hash_grows);
385
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000386 old_nht = rcu_dereference_protected(tbl->nht,
387 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -0700388 new_nht = neigh_hash_alloc(new_shift);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000389 if (!new_nht)
390 return old_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
David S. Millercd089332011-07-11 01:28:12 -0700392 for (i = 0; i < (1 << old_nht->hash_shift); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 struct neighbour *n, *next;
394
Eric Dumazet767e97e2010-10-06 17:49:21 -0700395 for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
396 lockdep_is_held(&tbl->lock));
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000397 n != NULL;
398 n = next) {
399 hash = tbl->hash(n->primary_key, n->dev,
400 new_nht->hash_rnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
David S. Millercd089332011-07-11 01:28:12 -0700402 hash >>= (32 - new_nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700403 next = rcu_dereference_protected(n->next,
404 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
Eric Dumazet767e97e2010-10-06 17:49:21 -0700406 rcu_assign_pointer(n->next,
407 rcu_dereference_protected(
408 new_nht->hash_buckets[hash],
409 lockdep_is_held(&tbl->lock)));
410 rcu_assign_pointer(new_nht->hash_buckets[hash], n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 }
412 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000414 rcu_assign_pointer(tbl->nht, new_nht);
415 call_rcu(&old_nht->rcu, neigh_hash_free_rcu);
416 return new_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417}
418
419struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
420 struct net_device *dev)
421{
422 struct neighbour *n;
423 int key_len = tbl->key_len;
Pavel Emelyanovbc4bf5f2008-02-23 19:57:02 -0800424 u32 hash_val;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000425 struct neigh_hash_table *nht;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900426
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 NEIGH_CACHE_STAT_INC(tbl, lookups);
428
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000429 rcu_read_lock_bh();
430 nht = rcu_dereference_bh(tbl->nht);
David S. Millercd089332011-07-11 01:28:12 -0700431 hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700432
433 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
434 n != NULL;
435 n = rcu_dereference_bh(n->next)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700437 if (!atomic_inc_not_zero(&n->refcnt))
438 n = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 NEIGH_CACHE_STAT_INC(tbl, hits);
440 break;
441 }
442 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700443
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000444 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 return n;
446}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900447EXPORT_SYMBOL(neigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
Eric W. Biederman426b5302008-01-24 00:13:18 -0800449struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
450 const void *pkey)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451{
452 struct neighbour *n;
453 int key_len = tbl->key_len;
Pavel Emelyanovbc4bf5f2008-02-23 19:57:02 -0800454 u32 hash_val;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000455 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456
457 NEIGH_CACHE_STAT_INC(tbl, lookups);
458
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000459 rcu_read_lock_bh();
460 nht = rcu_dereference_bh(tbl->nht);
David S. Millercd089332011-07-11 01:28:12 -0700461 hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700462
463 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
464 n != NULL;
465 n = rcu_dereference_bh(n->next)) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800466 if (!memcmp(n->primary_key, pkey, key_len) &&
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +0900467 net_eq(dev_net(n->dev), net)) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700468 if (!atomic_inc_not_zero(&n->refcnt))
469 n = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 NEIGH_CACHE_STAT_INC(tbl, hits);
471 break;
472 }
473 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700474
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000475 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 return n;
477}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900478EXPORT_SYMBOL(neigh_lookup_nodev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479
David S. Millera263b302012-07-02 02:02:15 -0700480struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
481 struct net_device *dev, bool want_ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
483 u32 hash_val;
484 int key_len = tbl->key_len;
485 int error;
David Miller596b9b62011-07-25 00:01:25 +0000486 struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000487 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
489 if (!n) {
490 rc = ERR_PTR(-ENOBUFS);
491 goto out;
492 }
493
494 memcpy(n->primary_key, pkey, key_len);
495 n->dev = dev;
496 dev_hold(dev);
497
498 /* Protocol specific setup. */
499 if (tbl->constructor && (error = tbl->constructor(n)) < 0) {
500 rc = ERR_PTR(error);
501 goto out_neigh_release;
502 }
503
David Millerda6a8fa2011-07-25 00:01:38 +0000504 if (dev->netdev_ops->ndo_neigh_construct) {
505 error = dev->netdev_ops->ndo_neigh_construct(n);
506 if (error < 0) {
507 rc = ERR_PTR(error);
508 goto out_neigh_release;
509 }
510 }
511
David S. Miller447f2192011-12-19 15:04:41 -0500512 /* Device specific setup. */
513 if (n->parms->neigh_setup &&
514 (error = n->parms->neigh_setup(n)) < 0) {
515 rc = ERR_PTR(error);
516 goto out_neigh_release;
517 }
518
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 n->confirmed = jiffies - (n->parms->base_reachable_time << 1);
520
521 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000522 nht = rcu_dereference_protected(tbl->nht,
523 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
David S. Millercd089332011-07-11 01:28:12 -0700525 if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
526 nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
David S. Millercd089332011-07-11 01:28:12 -0700528 hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529
530 if (n->parms->dead) {
531 rc = ERR_PTR(-EINVAL);
532 goto out_tbl_unlock;
533 }
534
Eric Dumazet767e97e2010-10-06 17:49:21 -0700535 for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
536 lockdep_is_held(&tbl->lock));
537 n1 != NULL;
538 n1 = rcu_dereference_protected(n1->next,
539 lockdep_is_held(&tbl->lock))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) {
David S. Millera263b302012-07-02 02:02:15 -0700541 if (want_ref)
542 neigh_hold(n1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 rc = n1;
544 goto out_tbl_unlock;
545 }
546 }
547
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 n->dead = 0;
David S. Millera263b302012-07-02 02:02:15 -0700549 if (want_ref)
550 neigh_hold(n);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700551 rcu_assign_pointer(n->next,
552 rcu_dereference_protected(nht->hash_buckets[hash_val],
553 lockdep_is_held(&tbl->lock)));
554 rcu_assign_pointer(nht->hash_buckets[hash_val], n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 write_unlock_bh(&tbl->lock);
556 NEIGH_PRINTK2("neigh %p is created.\n", n);
557 rc = n;
558out:
559 return rc;
560out_tbl_unlock:
561 write_unlock_bh(&tbl->lock);
562out_neigh_release:
563 neigh_release(n);
564 goto out;
565}
David S. Millera263b302012-07-02 02:02:15 -0700566EXPORT_SYMBOL(__neigh_create);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900568static u32 pneigh_hash(const void *pkey, int key_len)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700569{
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700570 u32 hash_val = *(u32 *)(pkey + key_len - 4);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700571 hash_val ^= (hash_val >> 16);
572 hash_val ^= hash_val >> 8;
573 hash_val ^= hash_val >> 4;
574 hash_val &= PNEIGH_HASHMASK;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900575 return hash_val;
576}
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700577
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900578static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
579 struct net *net,
580 const void *pkey,
581 int key_len,
582 struct net_device *dev)
583{
584 while (n) {
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700585 if (!memcmp(n->key, pkey, key_len) &&
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900586 net_eq(pneigh_net(n), net) &&
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700587 (n->dev == dev || !n->dev))
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900588 return n;
589 n = n->next;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700590 }
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900591 return NULL;
592}
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700593
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900594struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
595 struct net *net, const void *pkey, struct net_device *dev)
596{
597 int key_len = tbl->key_len;
598 u32 hash_val = pneigh_hash(pkey, key_len);
599
600 return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
601 net, pkey, key_len, dev);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700602}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900603EXPORT_SYMBOL_GPL(__pneigh_lookup);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700604
Eric W. Biederman426b5302008-01-24 00:13:18 -0800605struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
606 struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 struct net_device *dev, int creat)
608{
609 struct pneigh_entry *n;
610 int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900611 u32 hash_val = pneigh_hash(pkey, key_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
613 read_lock_bh(&tbl->lock);
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900614 n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
615 net, pkey, key_len, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 read_unlock_bh(&tbl->lock);
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900617
618 if (n || !creat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 goto out;
620
Pavel Emelyanov4ae28942007-10-15 12:54:15 -0700621 ASSERT_RTNL();
622
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
624 if (!n)
625 goto out;
626
Eric Dumazete42ea982008-11-12 00:54:54 -0800627 write_pnet(&n->net, hold_net(net));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 memcpy(n->key, pkey, key_len);
629 n->dev = dev;
630 if (dev)
631 dev_hold(dev);
632
633 if (tbl->pconstructor && tbl->pconstructor(n)) {
634 if (dev)
635 dev_put(dev);
Denis V. Lunevda12f732008-02-20 00:26:16 -0800636 release_net(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 kfree(n);
638 n = NULL;
639 goto out;
640 }
641
642 write_lock_bh(&tbl->lock);
643 n->next = tbl->phash_buckets[hash_val];
644 tbl->phash_buckets[hash_val] = n;
645 write_unlock_bh(&tbl->lock);
646out:
647 return n;
648}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900649EXPORT_SYMBOL(pneigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
651
Eric W. Biederman426b5302008-01-24 00:13:18 -0800652int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 struct net_device *dev)
654{
655 struct pneigh_entry *n, **np;
656 int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900657 u32 hash_val = pneigh_hash(pkey, key_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
659 write_lock_bh(&tbl->lock);
660 for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
661 np = &n->next) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800662 if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +0900663 net_eq(pneigh_net(n), net)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 *np = n->next;
665 write_unlock_bh(&tbl->lock);
666 if (tbl->pdestructor)
667 tbl->pdestructor(n);
668 if (n->dev)
669 dev_put(n->dev);
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +0900670 release_net(pneigh_net(n));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 kfree(n);
672 return 0;
673 }
674 }
675 write_unlock_bh(&tbl->lock);
676 return -ENOENT;
677}
678
679static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
680{
681 struct pneigh_entry *n, **np;
682 u32 h;
683
684 for (h = 0; h <= PNEIGH_HASHMASK; h++) {
685 np = &tbl->phash_buckets[h];
686 while ((n = *np) != NULL) {
687 if (!dev || n->dev == dev) {
688 *np = n->next;
689 if (tbl->pdestructor)
690 tbl->pdestructor(n);
691 if (n->dev)
692 dev_put(n->dev);
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +0900693 release_net(pneigh_net(n));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 kfree(n);
695 continue;
696 }
697 np = &n->next;
698 }
699 }
700 return -ENOENT;
701}
702
Denis V. Lunev06f05112008-01-24 00:30:58 -0800703static void neigh_parms_destroy(struct neigh_parms *parms);
704
705static inline void neigh_parms_put(struct neigh_parms *parms)
706{
707 if (atomic_dec_and_test(&parms->refcnt))
708 neigh_parms_destroy(parms);
709}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
711/*
712 * neighbour must already be out of the table;
713 *
714 */
715void neigh_destroy(struct neighbour *neigh)
716{
David Millerda6a8fa2011-07-25 00:01:38 +0000717 struct net_device *dev = neigh->dev;
718
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
720
721 if (!neigh->dead) {
Joe Perchese005d192012-05-16 19:58:40 +0000722 pr_warn("Destroying alive neighbour %p\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 dump_stack();
724 return;
725 }
726
727 if (neigh_del_timer(neigh))
Joe Perchese005d192012-05-16 19:58:40 +0000728 pr_warn("Impossible event\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000731 neigh->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
David S. Miller447f2192011-12-19 15:04:41 -0500733 if (dev->netdev_ops->ndo_neigh_destroy)
734 dev->netdev_ops->ndo_neigh_destroy(neigh);
735
David Millerda6a8fa2011-07-25 00:01:38 +0000736 dev_put(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 neigh_parms_put(neigh->parms);
738
739 NEIGH_PRINTK2("neigh %p is destroyed.\n", neigh);
740
741 atomic_dec(&neigh->tbl->entries);
David Miller5b8b0062011-07-25 00:01:22 +0000742 kfree_rcu(neigh, rcu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900744EXPORT_SYMBOL(neigh_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745
746/* Neighbour state is suspicious;
747 disable fast path.
748
749 Called with write_locked neigh.
750 */
751static void neigh_suspect(struct neighbour *neigh)
752{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 NEIGH_PRINTK2("neigh %p is suspected.\n", neigh);
754
755 neigh->output = neigh->ops->output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756}
757
758/* Neighbour state is OK;
759 enable fast path.
760
761 Called with write_locked neigh.
762 */
763static void neigh_connect(struct neighbour *neigh)
764{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 NEIGH_PRINTK2("neigh %p is connected.\n", neigh);
766
767 neigh->output = neigh->ops->connected_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768}
769
Eric Dumazete4c4e442009-07-30 03:15:07 +0000770static void neigh_periodic_work(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771{
Eric Dumazete4c4e442009-07-30 03:15:07 +0000772 struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700773 struct neighbour *n;
774 struct neighbour __rcu **np;
Eric Dumazete4c4e442009-07-30 03:15:07 +0000775 unsigned int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000776 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777
778 NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
779
Eric Dumazete4c4e442009-07-30 03:15:07 +0000780 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000781 nht = rcu_dereference_protected(tbl->nht,
782 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
784 /*
785 * periodically recompute ReachableTime from random function
786 */
787
Eric Dumazete4c4e442009-07-30 03:15:07 +0000788 if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 struct neigh_parms *p;
Eric Dumazete4c4e442009-07-30 03:15:07 +0000790 tbl->last_rand = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 for (p = &tbl->parms; p; p = p->next)
792 p->reachable_time =
793 neigh_rand_reach_time(p->base_reachable_time);
794 }
795
David S. Millercd089332011-07-11 01:28:12 -0700796 for (i = 0 ; i < (1 << nht->hash_shift); i++) {
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000797 np = &nht->hash_buckets[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
Eric Dumazet767e97e2010-10-06 17:49:21 -0700799 while ((n = rcu_dereference_protected(*np,
800 lockdep_is_held(&tbl->lock))) != NULL) {
Eric Dumazete4c4e442009-07-30 03:15:07 +0000801 unsigned int state;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802
Eric Dumazete4c4e442009-07-30 03:15:07 +0000803 write_lock(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
Eric Dumazete4c4e442009-07-30 03:15:07 +0000805 state = n->nud_state;
806 if (state & (NUD_PERMANENT | NUD_IN_TIMER)) {
807 write_unlock(&n->lock);
808 goto next_elt;
809 }
810
811 if (time_before(n->used, n->confirmed))
812 n->used = n->confirmed;
813
814 if (atomic_read(&n->refcnt) == 1 &&
815 (state == NUD_FAILED ||
816 time_after(jiffies, n->used + n->parms->gc_staletime))) {
817 *np = n->next;
818 n->dead = 1;
819 write_unlock(&n->lock);
820 neigh_cleanup_and_release(n);
821 continue;
822 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 write_unlock(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
825next_elt:
Eric Dumazete4c4e442009-07-30 03:15:07 +0000826 np = &n->next;
827 }
828 /*
829 * It's fine to release lock here, even if hash table
830 * grows while we are preempted.
831 */
832 write_unlock_bh(&tbl->lock);
833 cond_resched();
834 write_lock_bh(&tbl->lock);
Michel Machado84338a62012-02-21 16:04:13 -0500835 nht = rcu_dereference_protected(tbl->nht,
836 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 }
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900838 /* Cycle through all hash buckets every base_reachable_time/2 ticks.
839 * ARP entry timeouts range from 1/2 base_reachable_time to 3/2
840 * base_reachable_time.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 */
Eric Dumazete4c4e442009-07-30 03:15:07 +0000842 schedule_delayed_work(&tbl->gc_work,
843 tbl->parms.base_reachable_time >> 1);
844 write_unlock_bh(&tbl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845}
846
847static __inline__ int neigh_max_probes(struct neighbour *n)
848{
849 struct neigh_parms *p = n->parms;
Eric Dumazeta02cec22010-09-22 20:43:57 +0000850 return (n->nud_state & NUD_PROBE) ?
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 p->ucast_probes :
Eric Dumazeta02cec22010-09-22 20:43:57 +0000852 p->ucast_probes + p->app_probes + p->mcast_probes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853}
854
Timo Teras5ef12d92009-06-11 04:16:28 -0700855static void neigh_invalidate(struct neighbour *neigh)
Eric Dumazet0a141502010-03-09 19:40:54 +0000856 __releases(neigh->lock)
857 __acquires(neigh->lock)
Timo Teras5ef12d92009-06-11 04:16:28 -0700858{
859 struct sk_buff *skb;
860
861 NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
862 NEIGH_PRINTK2("neigh %p is failed.\n", neigh);
863 neigh->updated = jiffies;
864
865 /* It is very thin place. report_unreachable is very complicated
866 routine. Particularly, it can hit the same neighbour entry!
867
868 So that, we try to be accurate and avoid dead loop. --ANK
869 */
870 while (neigh->nud_state == NUD_FAILED &&
871 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
872 write_unlock(&neigh->lock);
873 neigh->ops->error_report(neigh, skb);
874 write_lock(&neigh->lock);
875 }
876 skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000877 neigh->arp_queue_len_bytes = 0;
Timo Teras5ef12d92009-06-11 04:16:28 -0700878}
879
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000880static void neigh_probe(struct neighbour *neigh)
881 __releases(neigh->lock)
882{
883 struct sk_buff *skb = skb_peek(&neigh->arp_queue);
884 /* keep skb alive even if arp_queue overflows */
885 if (skb)
886 skb = skb_copy(skb, GFP_ATOMIC);
887 write_unlock(&neigh->lock);
888 neigh->ops->solicit(neigh, skb);
889 atomic_inc(&neigh->probes);
890 kfree_skb(skb);
891}
892
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893/* Called when a timer expires for a neighbour entry. */
894
895static void neigh_timer_handler(unsigned long arg)
896{
897 unsigned long now, next;
898 struct neighbour *neigh = (struct neighbour *)arg;
Eric Dumazet95c96172012-04-15 05:58:06 +0000899 unsigned int state;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 int notify = 0;
901
902 write_lock(&neigh->lock);
903
904 state = neigh->nud_state;
905 now = jiffies;
906 next = now + HZ;
907
David S. Miller045f7b32011-11-01 17:45:55 -0400908 if (!(state & NUD_IN_TIMER))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
911 if (state & NUD_REACHABLE) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900912 if (time_before_eq(now,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 neigh->confirmed + neigh->parms->reachable_time)) {
914 NEIGH_PRINTK2("neigh %p is still alive.\n", neigh);
915 next = neigh->confirmed + neigh->parms->reachable_time;
916 } else if (time_before_eq(now,
917 neigh->used + neigh->parms->delay_probe_time)) {
918 NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
919 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800920 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 neigh_suspect(neigh);
922 next = now + neigh->parms->delay_probe_time;
923 } else {
924 NEIGH_PRINTK2("neigh %p is suspected.\n", neigh);
925 neigh->nud_state = NUD_STALE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800926 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 neigh_suspect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -0700928 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 }
930 } else if (state & NUD_DELAY) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900931 if (time_before_eq(now,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 neigh->confirmed + neigh->parms->delay_probe_time)) {
933 NEIGH_PRINTK2("neigh %p is now reachable.\n", neigh);
934 neigh->nud_state = NUD_REACHABLE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800935 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 neigh_connect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -0700937 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 next = neigh->confirmed + neigh->parms->reachable_time;
939 } else {
940 NEIGH_PRINTK2("neigh %p is probed.\n", neigh);
941 neigh->nud_state = NUD_PROBE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800942 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 atomic_set(&neigh->probes, 0);
944 next = now + neigh->parms->retrans_time;
945 }
946 } else {
947 /* NUD_PROBE|NUD_INCOMPLETE */
948 next = now + neigh->parms->retrans_time;
949 }
950
951 if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
952 atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 neigh->nud_state = NUD_FAILED;
954 notify = 1;
Timo Teras5ef12d92009-06-11 04:16:28 -0700955 neigh_invalidate(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 }
957
958 if (neigh->nud_state & NUD_IN_TIMER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 if (time_before(next, jiffies + HZ/2))
960 next = jiffies + HZ/2;
Herbert Xu6fb99742005-10-23 16:37:48 +1000961 if (!mod_timer(&neigh->timer, next))
962 neigh_hold(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 }
964 if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000965 neigh_probe(neigh);
David S. Miller9ff56602008-02-17 18:39:54 -0800966 } else {
David S. Miller69cc64d2008-02-11 21:45:44 -0800967out:
David S. Miller9ff56602008-02-17 18:39:54 -0800968 write_unlock(&neigh->lock);
969 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Thomas Grafd961db32007-08-08 23:12:56 -0700971 if (notify)
972 neigh_update_notify(neigh);
973
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 neigh_release(neigh);
975}
976
977int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
978{
979 int rc;
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000980 bool immediate_probe = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
982 write_lock_bh(&neigh->lock);
983
984 rc = 0;
985 if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
986 goto out_unlock_bh;
987
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
989 if (neigh->parms->mcast_probes + neigh->parms->app_probes) {
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000990 unsigned long next, now = jiffies;
991
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 atomic_set(&neigh->probes, neigh->parms->ucast_probes);
993 neigh->nud_state = NUD_INCOMPLETE;
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000994 neigh->updated = now;
995 next = now + max(neigh->parms->retrans_time, HZ/2);
996 neigh_add_timer(neigh, next);
997 immediate_probe = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 } else {
999 neigh->nud_state = NUD_FAILED;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001000 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 write_unlock_bh(&neigh->lock);
1002
Wei Yongjunf3fbbe02009-02-25 00:37:32 +00001003 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 return 1;
1005 }
1006 } else if (neigh->nud_state & NUD_STALE) {
1007 NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001009 neigh->updated = jiffies;
David S. Miller667347f2005-09-27 12:07:44 -07001010 neigh_add_timer(neigh,
1011 jiffies + neigh->parms->delay_probe_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 }
1013
1014 if (neigh->nud_state == NUD_INCOMPLETE) {
1015 if (skb) {
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001016 while (neigh->arp_queue_len_bytes + skb->truesize >
1017 neigh->parms->queue_len_bytes) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 struct sk_buff *buff;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001019
David S. Millerf72051b2008-09-23 01:11:18 -07001020 buff = __skb_dequeue(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001021 if (!buff)
1022 break;
1023 neigh->arp_queue_len_bytes -= buff->truesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 kfree_skb(buff);
Neil Horman9a6d2762008-07-16 20:50:49 -07001025 NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 }
Eric Dumazeta4731132010-05-27 16:09:39 -07001027 skb_dst_force(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 __skb_queue_tail(&neigh->arp_queue, skb);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001029 neigh->arp_queue_len_bytes += skb->truesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 }
1031 rc = 1;
1032 }
1033out_unlock_bh:
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001034 if (immediate_probe)
1035 neigh_probe(neigh);
1036 else
1037 write_unlock(&neigh->lock);
1038 local_bh_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 return rc;
1040}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001041EXPORT_SYMBOL(__neigh_event_send);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042
David S. Millerf6b72b622011-07-14 07:53:20 -07001043static void neigh_update_hhs(struct neighbour *neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044{
1045 struct hh_cache *hh;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001046 void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
Doug Kehn91a72a72010-07-14 18:02:16 -07001047 = NULL;
1048
1049 if (neigh->dev->header_ops)
1050 update = neigh->dev->header_ops->cache_update;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051
1052 if (update) {
David S. Millerf6b72b622011-07-14 07:53:20 -07001053 hh = &neigh->hh;
1054 if (hh->hh_len) {
Stephen Hemminger3644f0c2006-12-07 15:08:17 -08001055 write_seqlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 update(hh, neigh->dev, neigh->ha);
Stephen Hemminger3644f0c2006-12-07 15:08:17 -08001057 write_sequnlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 }
1059 }
1060}
1061
1062
1063
1064/* Generic update routine.
1065 -- lladdr is new lladdr or NULL, if it is not supplied.
1066 -- new is new state.
1067 -- flags
1068 NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr,
1069 if it is different.
1070 NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected"
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001071 lladdr instead of overriding it
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 if it is different.
1073 It also allows to retain current state
1074 if lladdr is unchanged.
1075 NEIGH_UPDATE_F_ADMIN means that the change is administrative.
1076
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001077 NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 NTF_ROUTER flag.
1079 NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as
1080 a router.
1081
1082 Caller MUST hold reference count on the entry.
1083 */
1084
1085int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
1086 u32 flags)
1087{
1088 u8 old;
1089 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 int notify = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 struct net_device *dev;
1092 int update_isrouter = 0;
1093
1094 write_lock_bh(&neigh->lock);
1095
1096 dev = neigh->dev;
1097 old = neigh->nud_state;
1098 err = -EPERM;
1099
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001100 if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 (old & (NUD_NOARP | NUD_PERMANENT)))
1102 goto out;
1103
1104 if (!(new & NUD_VALID)) {
1105 neigh_del_timer(neigh);
1106 if (old & NUD_CONNECTED)
1107 neigh_suspect(neigh);
1108 neigh->nud_state = new;
1109 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 notify = old & NUD_VALID;
Timo Teras5ef12d92009-06-11 04:16:28 -07001111 if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
1112 (new & NUD_FAILED)) {
1113 neigh_invalidate(neigh);
1114 notify = 1;
1115 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 goto out;
1117 }
1118
1119 /* Compare new lladdr with cached one */
1120 if (!dev->addr_len) {
1121 /* First case: device needs no address. */
1122 lladdr = neigh->ha;
1123 } else if (lladdr) {
1124 /* The second case: if something is already cached
1125 and a new address is proposed:
1126 - compare new & old
1127 - if they are different, check override flag
1128 */
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001129 if ((old & NUD_VALID) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 !memcmp(lladdr, neigh->ha, dev->addr_len))
1131 lladdr = neigh->ha;
1132 } else {
1133 /* No address is supplied; if we know something,
1134 use it, otherwise discard the request.
1135 */
1136 err = -EINVAL;
1137 if (!(old & NUD_VALID))
1138 goto out;
1139 lladdr = neigh->ha;
1140 }
1141
1142 if (new & NUD_CONNECTED)
1143 neigh->confirmed = jiffies;
1144 neigh->updated = jiffies;
1145
1146 /* If entry was valid and address is not changed,
1147 do not change entry state, if new one is STALE.
1148 */
1149 err = 0;
1150 update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
1151 if (old & NUD_VALID) {
1152 if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {
1153 update_isrouter = 0;
1154 if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&
1155 (old & NUD_CONNECTED)) {
1156 lladdr = neigh->ha;
1157 new = NUD_STALE;
1158 } else
1159 goto out;
1160 } else {
1161 if (lladdr == neigh->ha && new == NUD_STALE &&
1162 ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) ||
1163 (old & NUD_CONNECTED))
1164 )
1165 new = old;
1166 }
1167 }
1168
1169 if (new != old) {
1170 neigh_del_timer(neigh);
Pavel Emelyanova43d8992007-12-20 15:49:05 -08001171 if (new & NUD_IN_TIMER)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001172 neigh_add_timer(neigh, (jiffies +
1173 ((new & NUD_REACHABLE) ?
David S. Miller667347f2005-09-27 12:07:44 -07001174 neigh->parms->reachable_time :
1175 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 neigh->nud_state = new;
1177 }
1178
1179 if (lladdr != neigh->ha) {
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001180 write_seqlock(&neigh->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 memcpy(&neigh->ha, lladdr, dev->addr_len);
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001182 write_sequnlock(&neigh->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 neigh_update_hhs(neigh);
1184 if (!(new & NUD_CONNECTED))
1185 neigh->confirmed = jiffies -
1186 (neigh->parms->base_reachable_time << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 }
1189 if (new == old)
1190 goto out;
1191 if (new & NUD_CONNECTED)
1192 neigh_connect(neigh);
1193 else
1194 neigh_suspect(neigh);
1195 if (!(old & NUD_VALID)) {
1196 struct sk_buff *skb;
1197
1198 /* Again: avoid dead loop if something went wrong */
1199
1200 while (neigh->nud_state & NUD_VALID &&
1201 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
David S. Miller69cce1d2011-07-17 23:09:49 -07001202 struct dst_entry *dst = skb_dst(skb);
1203 struct neighbour *n2, *n1 = neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 write_unlock_bh(&neigh->lock);
roy.qing.li@gmail.come049f282011-10-17 22:32:42 +00001205
1206 rcu_read_lock();
David S. Miller13a43d92012-07-02 22:15:37 -07001207
1208 /* Why not just use 'neigh' as-is? The problem is that
1209 * things such as shaper, eql, and sch_teql can end up
1210 * using alternative, different, neigh objects to output
1211 * the packet in the output path. So what we need to do
1212 * here is re-lookup the top-level neigh in the path so
1213 * we can reinject the packet there.
1214 */
1215 n2 = NULL;
1216 if (dst) {
1217 n2 = dst_neigh_lookup_skb(dst, skb);
1218 if (n2)
1219 n1 = n2;
1220 }
David S. Miller8f40b162011-07-17 13:34:11 -07001221 n1->output(n1, skb);
David S. Miller13a43d92012-07-02 22:15:37 -07001222 if (n2)
1223 neigh_release(n2);
roy.qing.li@gmail.come049f282011-10-17 22:32:42 +00001224 rcu_read_unlock();
1225
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 write_lock_bh(&neigh->lock);
1227 }
1228 skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001229 neigh->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 }
1231out:
1232 if (update_isrouter) {
1233 neigh->flags = (flags & NEIGH_UPDATE_F_ISROUTER) ?
1234 (neigh->flags | NTF_ROUTER) :
1235 (neigh->flags & ~NTF_ROUTER);
1236 }
1237 write_unlock_bh(&neigh->lock);
Tom Tucker8d717402006-07-30 20:43:36 -07001238
1239 if (notify)
Thomas Grafd961db32007-08-08 23:12:56 -07001240 neigh_update_notify(neigh);
1241
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 return err;
1243}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001244EXPORT_SYMBOL(neigh_update);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245
1246struct neighbour *neigh_event_ns(struct neigh_table *tbl,
1247 u8 *lladdr, void *saddr,
1248 struct net_device *dev)
1249{
1250 struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
1251 lladdr || !dev->addr_len);
1252 if (neigh)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001253 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 NEIGH_UPDATE_F_OVERRIDE);
1255 return neigh;
1256}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001257EXPORT_SYMBOL(neigh_event_ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258
Eric Dumazet34d101d2010-10-11 09:16:57 -07001259/* called with read_lock_bh(&n->lock); */
David S. Millerf6b72b622011-07-14 07:53:20 -07001260static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 struct net_device *dev = dst->dev;
David S. Millerf6b72b622011-07-14 07:53:20 -07001263 __be16 prot = dst->ops->protocol;
1264 struct hh_cache *hh = &n->hh;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001265
1266 write_lock_bh(&n->lock);
Eric Dumazet34d101d2010-10-11 09:16:57 -07001267
David S. Millerf6b72b622011-07-14 07:53:20 -07001268 /* Only one thread can come in here and initialize the
1269 * hh_cache entry.
1270 */
David S. Millerb23b5452011-07-16 17:45:02 -07001271 if (!hh->hh_len)
1272 dev->header_ops->cache(n, hh, prot);
David S. Millerf6b72b622011-07-14 07:53:20 -07001273
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001274 write_unlock_bh(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275}
1276
1277/* This function can be used in contexts, where only old dev_queue_xmit
Eric Dumazet767e97e2010-10-06 17:49:21 -07001278 * worked, f.e. if you want to override normal output path (eql, shaper),
1279 * but resolution is not made yet.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 */
1281
David S. Miller8f40b162011-07-17 13:34:11 -07001282int neigh_compat_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283{
1284 struct net_device *dev = skb->dev;
1285
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03001286 __skb_pull(skb, skb_network_offset(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287
Stephen Hemminger0c4e8582007-10-09 01:36:32 -07001288 if (dev_hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL,
1289 skb->len) < 0 &&
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001290 dev->header_ops->rebuild(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 return 0;
1292
1293 return dev_queue_xmit(skb);
1294}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001295EXPORT_SYMBOL(neigh_compat_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296
1297/* Slow and careful. */
1298
David S. Miller8f40b162011-07-17 13:34:11 -07001299int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300{
Eric Dumazetadf30902009-06-02 05:19:30 +00001301 struct dst_entry *dst = skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 int rc = 0;
1303
David S. Miller8f40b162011-07-17 13:34:11 -07001304 if (!dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 goto discard;
1306
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 if (!neigh_event_send(neigh, skb)) {
1308 int err;
1309 struct net_device *dev = neigh->dev;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001310 unsigned int seq;
Eric Dumazet34d101d2010-10-11 09:16:57 -07001311
David S. Millerf6b72b622011-07-14 07:53:20 -07001312 if (dev->header_ops->cache && !neigh->hh.hh_len)
1313 neigh_hh_init(neigh, dst);
Eric Dumazet34d101d2010-10-11 09:16:57 -07001314
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001315 do {
ramesh.nagappa@gmail.come1f16502012-10-05 19:10:15 +00001316 __skb_pull(skb, skb_network_offset(skb));
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001317 seq = read_seqbegin(&neigh->ha_lock);
1318 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1319 neigh->ha, NULL, skb->len);
1320 } while (read_seqretry(&neigh->ha_lock, seq));
Eric Dumazet34d101d2010-10-11 09:16:57 -07001321
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 if (err >= 0)
David S. Miller542d4d62011-07-16 18:06:24 -07001323 rc = dev_queue_xmit(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 else
1325 goto out_kfree_skb;
1326 }
1327out:
1328 return rc;
1329discard:
1330 NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n",
David S. Miller8f40b162011-07-17 13:34:11 -07001331 dst, neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332out_kfree_skb:
1333 rc = -EINVAL;
1334 kfree_skb(skb);
1335 goto out;
1336}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001337EXPORT_SYMBOL(neigh_resolve_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338
1339/* As fast as possible without hh cache */
1340
David S. Miller8f40b162011-07-17 13:34:11 -07001341int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 struct net_device *dev = neigh->dev;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001344 unsigned int seq;
David S. Miller8f40b162011-07-17 13:34:11 -07001345 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001347 do {
ramesh.nagappa@gmail.come1f16502012-10-05 19:10:15 +00001348 __skb_pull(skb, skb_network_offset(skb));
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001349 seq = read_seqbegin(&neigh->ha_lock);
1350 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1351 neigh->ha, NULL, skb->len);
1352 } while (read_seqretry(&neigh->ha_lock, seq));
1353
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 if (err >= 0)
David S. Miller542d4d62011-07-16 18:06:24 -07001355 err = dev_queue_xmit(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 else {
1357 err = -EINVAL;
1358 kfree_skb(skb);
1359 }
1360 return err;
1361}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001362EXPORT_SYMBOL(neigh_connected_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363
David S. Miller8f40b162011-07-17 13:34:11 -07001364int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
1365{
1366 return dev_queue_xmit(skb);
1367}
1368EXPORT_SYMBOL(neigh_direct_output);
1369
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370static void neigh_proxy_process(unsigned long arg)
1371{
1372 struct neigh_table *tbl = (struct neigh_table *)arg;
1373 long sched_next = 0;
1374 unsigned long now = jiffies;
David S. Millerf72051b2008-09-23 01:11:18 -07001375 struct sk_buff *skb, *n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376
1377 spin_lock(&tbl->proxy_queue.lock);
1378
David S. Millerf72051b2008-09-23 01:11:18 -07001379 skb_queue_walk_safe(&tbl->proxy_queue, skb, n) {
1380 long tdif = NEIGH_CB(skb)->sched_next - now;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 if (tdif <= 0) {
David S. Millerf72051b2008-09-23 01:11:18 -07001383 struct net_device *dev = skb->dev;
Eric Dumazet20e60742011-08-22 19:32:42 +00001384
David S. Millerf72051b2008-09-23 01:11:18 -07001385 __skb_unlink(skb, &tbl->proxy_queue);
Eric Dumazet20e60742011-08-22 19:32:42 +00001386 if (tbl->proxy_redo && netif_running(dev)) {
1387 rcu_read_lock();
David S. Millerf72051b2008-09-23 01:11:18 -07001388 tbl->proxy_redo(skb);
Eric Dumazet20e60742011-08-22 19:32:42 +00001389 rcu_read_unlock();
1390 } else {
David S. Millerf72051b2008-09-23 01:11:18 -07001391 kfree_skb(skb);
Eric Dumazet20e60742011-08-22 19:32:42 +00001392 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
1394 dev_put(dev);
1395 } else if (!sched_next || tdif < sched_next)
1396 sched_next = tdif;
1397 }
1398 del_timer(&tbl->proxy_timer);
1399 if (sched_next)
1400 mod_timer(&tbl->proxy_timer, jiffies + sched_next);
1401 spin_unlock(&tbl->proxy_queue.lock);
1402}
1403
1404void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
1405 struct sk_buff *skb)
1406{
1407 unsigned long now = jiffies;
1408 unsigned long sched_next = now + (net_random() % p->proxy_delay);
1409
1410 if (tbl->proxy_queue.qlen > p->proxy_qlen) {
1411 kfree_skb(skb);
1412 return;
1413 }
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001414
1415 NEIGH_CB(skb)->sched_next = sched_next;
1416 NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417
1418 spin_lock(&tbl->proxy_queue.lock);
1419 if (del_timer(&tbl->proxy_timer)) {
1420 if (time_before(tbl->proxy_timer.expires, sched_next))
1421 sched_next = tbl->proxy_timer.expires;
1422 }
Eric Dumazetadf30902009-06-02 05:19:30 +00001423 skb_dst_drop(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 dev_hold(skb->dev);
1425 __skb_queue_tail(&tbl->proxy_queue, skb);
1426 mod_timer(&tbl->proxy_timer, sched_next);
1427 spin_unlock(&tbl->proxy_queue.lock);
1428}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001429EXPORT_SYMBOL(pneigh_enqueue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07001431static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
Eric W. Biederman426b5302008-01-24 00:13:18 -08001432 struct net *net, int ifindex)
1433{
1434 struct neigh_parms *p;
1435
1436 for (p = &tbl->parms; p; p = p->next) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09001437 if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
Eric W. Biederman426b5302008-01-24 00:13:18 -08001438 (!p->dev && !ifindex))
1439 return p;
1440 }
1441
1442 return NULL;
1443}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444
1445struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
1446 struct neigh_table *tbl)
1447{
Eric W. Biederman426b5302008-01-24 00:13:18 -08001448 struct neigh_parms *p, *ref;
Stephen Hemminger00829822008-11-20 20:14:53 -08001449 struct net *net = dev_net(dev);
1450 const struct net_device_ops *ops = dev->netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07001452 ref = lookup_neigh_parms(tbl, net, 0);
Eric W. Biederman426b5302008-01-24 00:13:18 -08001453 if (!ref)
1454 return NULL;
1455
1456 p = kmemdup(ref, sizeof(*p), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 if (p) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 p->tbl = tbl;
1459 atomic_set(&p->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 p->reachable_time =
1461 neigh_rand_reach_time(p->base_reachable_time);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001462
Stephen Hemminger00829822008-11-20 20:14:53 -08001463 if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
Denis V. Lunev486b51d2008-01-14 22:59:59 -08001464 kfree(p);
1465 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 }
Denis V. Lunev486b51d2008-01-14 22:59:59 -08001467
1468 dev_hold(dev);
1469 p->dev = dev;
Eric Dumazete42ea982008-11-12 00:54:54 -08001470 write_pnet(&p->net, hold_net(net));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 p->sysctl_table = NULL;
1472 write_lock_bh(&tbl->lock);
1473 p->next = tbl->parms.next;
1474 tbl->parms.next = p;
1475 write_unlock_bh(&tbl->lock);
1476 }
1477 return p;
1478}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001479EXPORT_SYMBOL(neigh_parms_alloc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480
1481static void neigh_rcu_free_parms(struct rcu_head *head)
1482{
1483 struct neigh_parms *parms =
1484 container_of(head, struct neigh_parms, rcu_head);
1485
1486 neigh_parms_put(parms);
1487}
1488
1489void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
1490{
1491 struct neigh_parms **p;
1492
1493 if (!parms || parms == &tbl->parms)
1494 return;
1495 write_lock_bh(&tbl->lock);
1496 for (p = &tbl->parms.next; *p; p = &(*p)->next) {
1497 if (*p == parms) {
1498 *p = parms->next;
1499 parms->dead = 1;
1500 write_unlock_bh(&tbl->lock);
David S. Millercecbb632008-01-20 16:39:03 -08001501 if (parms->dev)
1502 dev_put(parms->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
1504 return;
1505 }
1506 }
1507 write_unlock_bh(&tbl->lock);
1508 NEIGH_PRINTK1("neigh_parms_release: not found\n");
1509}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001510EXPORT_SYMBOL(neigh_parms_release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511
Denis V. Lunev06f05112008-01-24 00:30:58 -08001512static void neigh_parms_destroy(struct neigh_parms *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513{
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +09001514 release_net(neigh_parms_net(parms));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 kfree(parms);
1516}
1517
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001518static struct lock_class_key neigh_table_proxy_queue_class;
1519
Hiroaki SHIMODAdcd2ba92012-04-13 07:34:44 +00001520static void neigh_table_init_no_netlink(struct neigh_table *tbl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521{
1522 unsigned long now = jiffies;
1523 unsigned long phsize;
1524
Eric Dumazete42ea982008-11-12 00:54:54 -08001525 write_pnet(&tbl->parms.net, &init_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 atomic_set(&tbl->parms.refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 tbl->parms.reachable_time =
1528 neigh_rand_reach_time(tbl->parms.base_reachable_time);
1529
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 tbl->stats = alloc_percpu(struct neigh_statistics);
1531 if (!tbl->stats)
1532 panic("cannot create neighbour cache statistics");
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001533
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534#ifdef CONFIG_PROC_FS
Alexey Dobriyan9b739ba2008-11-11 16:47:44 -08001535 if (!proc_create_data(tbl->id, 0, init_net.proc_net_stat,
1536 &neigh_stat_seq_fops, tbl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 panic("cannot create neighbour proc dir entry");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538#endif
1539
David S. Millercd089332011-07-11 01:28:12 -07001540 RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541
1542 phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
Andrew Morton77d04bd2006-04-07 14:52:59 -07001543 tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001545 if (!tbl->nht || !tbl->phash_buckets)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 panic("cannot allocate neighbour cache hashes");
1547
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 rwlock_init(&tbl->lock);
Tejun Heo203b42f2012-08-21 13:18:23 -07001549 INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work);
Eric Dumazete4c4e442009-07-30 03:15:07 +00001550 schedule_delayed_work(&tbl->gc_work, tbl->parms.reachable_time);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -08001551 setup_timer(&tbl->proxy_timer, neigh_proxy_process, (unsigned long)tbl);
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001552 skb_queue_head_init_class(&tbl->proxy_queue,
1553 &neigh_table_proxy_queue_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554
1555 tbl->last_flush = now;
1556 tbl->last_rand = now + tbl->parms.reachable_time * 20;
Simon Kelleybd89efc2006-05-12 14:56:08 -07001557}
1558
1559void neigh_table_init(struct neigh_table *tbl)
1560{
1561 struct neigh_table *tmp;
1562
1563 neigh_table_init_no_netlink(tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 write_lock(&neigh_tbl_lock);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001565 for (tmp = neigh_tables; tmp; tmp = tmp->next) {
1566 if (tmp->family == tbl->family)
1567 break;
1568 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 tbl->next = neigh_tables;
1570 neigh_tables = tbl;
1571 write_unlock(&neigh_tbl_lock);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001572
1573 if (unlikely(tmp)) {
Joe Perchese005d192012-05-16 19:58:40 +00001574 pr_err("Registering multiple tables for family %d\n",
1575 tbl->family);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001576 dump_stack();
1577 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001579EXPORT_SYMBOL(neigh_table_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580
1581int neigh_table_clear(struct neigh_table *tbl)
1582{
1583 struct neigh_table **tp;
1584
1585 /* It is not clean... Fix it to unload IPv6 module safely */
Tejun Heoa5c30b32010-10-19 06:04:42 +00001586 cancel_delayed_work_sync(&tbl->gc_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 del_timer_sync(&tbl->proxy_timer);
1588 pneigh_queue_purge(&tbl->proxy_queue);
1589 neigh_ifdown(tbl, NULL);
1590 if (atomic_read(&tbl->entries))
Joe Perchese005d192012-05-16 19:58:40 +00001591 pr_crit("neighbour leakage\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 write_lock(&neigh_tbl_lock);
1593 for (tp = &neigh_tables; *tp; tp = &(*tp)->next) {
1594 if (*tp == tbl) {
1595 *tp = tbl->next;
1596 break;
1597 }
1598 }
1599 write_unlock(&neigh_tbl_lock);
1600
Eric Dumazet6193d2b2011-01-19 22:02:47 +00001601 call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
1602 neigh_hash_free_rcu);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001603 tbl->nht = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604
1605 kfree(tbl->phash_buckets);
1606 tbl->phash_buckets = NULL;
1607
Alexey Dobriyan3f192b52007-11-05 21:28:13 -08001608 remove_proc_entry(tbl->id, init_net.proc_net_stat);
1609
Kirill Korotaev3fcde742006-09-01 01:34:10 -07001610 free_percpu(tbl->stats);
1611 tbl->stats = NULL;
1612
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 return 0;
1614}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001615EXPORT_SYMBOL(neigh_table_clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616
Thomas Grafc8822a42007-03-22 11:50:06 -07001617static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001619 struct net *net = sock_net(skb->sk);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001620 struct ndmsg *ndm;
1621 struct nlattr *dst_attr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 struct neigh_table *tbl;
1623 struct net_device *dev = NULL;
Thomas Grafa14a49d2006-08-07 17:53:08 -07001624 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625
Eric Dumazet110b2492010-10-04 04:27:36 +00001626 ASSERT_RTNL();
Thomas Grafa14a49d2006-08-07 17:53:08 -07001627 if (nlmsg_len(nlh) < sizeof(*ndm))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 goto out;
1629
Thomas Grafa14a49d2006-08-07 17:53:08 -07001630 dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
1631 if (dst_attr == NULL)
1632 goto out;
1633
1634 ndm = nlmsg_data(nlh);
1635 if (ndm->ndm_ifindex) {
Eric Dumazet110b2492010-10-04 04:27:36 +00001636 dev = __dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001637 if (dev == NULL) {
1638 err = -ENODEV;
1639 goto out;
1640 }
1641 }
1642
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 read_lock(&neigh_tbl_lock);
1644 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
Thomas Grafa14a49d2006-08-07 17:53:08 -07001645 struct neighbour *neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646
1647 if (tbl->family != ndm->ndm_family)
1648 continue;
1649 read_unlock(&neigh_tbl_lock);
1650
Thomas Grafa14a49d2006-08-07 17:53:08 -07001651 if (nla_len(dst_attr) < tbl->key_len)
Eric Dumazet110b2492010-10-04 04:27:36 +00001652 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653
1654 if (ndm->ndm_flags & NTF_PROXY) {
Eric W. Biederman426b5302008-01-24 00:13:18 -08001655 err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
Eric Dumazet110b2492010-10-04 04:27:36 +00001656 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 }
1658
Thomas Grafa14a49d2006-08-07 17:53:08 -07001659 if (dev == NULL)
Eric Dumazet110b2492010-10-04 04:27:36 +00001660 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661
Thomas Grafa14a49d2006-08-07 17:53:08 -07001662 neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
1663 if (neigh == NULL) {
1664 err = -ENOENT;
Eric Dumazet110b2492010-10-04 04:27:36 +00001665 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 }
Thomas Grafa14a49d2006-08-07 17:53:08 -07001667
1668 err = neigh_update(neigh, NULL, NUD_FAILED,
1669 NEIGH_UPDATE_F_OVERRIDE |
1670 NEIGH_UPDATE_F_ADMIN);
1671 neigh_release(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001672 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 }
1674 read_unlock(&neigh_tbl_lock);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001675 err = -EAFNOSUPPORT;
1676
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677out:
1678 return err;
1679}
1680
Thomas Grafc8822a42007-03-22 11:50:06 -07001681static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001683 struct net *net = sock_net(skb->sk);
Thomas Graf5208deb2006-08-07 17:55:40 -07001684 struct ndmsg *ndm;
1685 struct nlattr *tb[NDA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 struct neigh_table *tbl;
1687 struct net_device *dev = NULL;
Thomas Graf5208deb2006-08-07 17:55:40 -07001688 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
Eric Dumazet110b2492010-10-04 04:27:36 +00001690 ASSERT_RTNL();
Thomas Graf5208deb2006-08-07 17:55:40 -07001691 err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
1692 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 goto out;
1694
Thomas Graf5208deb2006-08-07 17:55:40 -07001695 err = -EINVAL;
1696 if (tb[NDA_DST] == NULL)
1697 goto out;
1698
1699 ndm = nlmsg_data(nlh);
1700 if (ndm->ndm_ifindex) {
Eric Dumazet110b2492010-10-04 04:27:36 +00001701 dev = __dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Graf5208deb2006-08-07 17:55:40 -07001702 if (dev == NULL) {
1703 err = -ENODEV;
1704 goto out;
1705 }
1706
1707 if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len)
Eric Dumazet110b2492010-10-04 04:27:36 +00001708 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001709 }
1710
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 read_lock(&neigh_tbl_lock);
1712 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
Thomas Graf5208deb2006-08-07 17:55:40 -07001713 int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE;
1714 struct neighbour *neigh;
1715 void *dst, *lladdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716
1717 if (tbl->family != ndm->ndm_family)
1718 continue;
1719 read_unlock(&neigh_tbl_lock);
1720
Thomas Graf5208deb2006-08-07 17:55:40 -07001721 if (nla_len(tb[NDA_DST]) < tbl->key_len)
Eric Dumazet110b2492010-10-04 04:27:36 +00001722 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001723 dst = nla_data(tb[NDA_DST]);
1724 lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725
1726 if (ndm->ndm_flags & NTF_PROXY) {
Ville Nuorvala62dd9312006-09-22 14:43:19 -07001727 struct pneigh_entry *pn;
1728
1729 err = -ENOBUFS;
Eric W. Biederman426b5302008-01-24 00:13:18 -08001730 pn = pneigh_lookup(tbl, net, dst, dev, 1);
Ville Nuorvala62dd9312006-09-22 14:43:19 -07001731 if (pn) {
1732 pn->flags = ndm->ndm_flags;
1733 err = 0;
1734 }
Eric Dumazet110b2492010-10-04 04:27:36 +00001735 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 }
1737
Thomas Graf5208deb2006-08-07 17:55:40 -07001738 if (dev == NULL)
Eric Dumazet110b2492010-10-04 04:27:36 +00001739 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001740
1741 neigh = neigh_lookup(tbl, dst, dev);
1742 if (neigh == NULL) {
1743 if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
1744 err = -ENOENT;
Eric Dumazet110b2492010-10-04 04:27:36 +00001745 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001746 }
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001747
Thomas Graf5208deb2006-08-07 17:55:40 -07001748 neigh = __neigh_lookup_errno(tbl, dst, dev);
1749 if (IS_ERR(neigh)) {
1750 err = PTR_ERR(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001751 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001752 }
1753 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 if (nlh->nlmsg_flags & NLM_F_EXCL) {
1755 err = -EEXIST;
Thomas Graf5208deb2006-08-07 17:55:40 -07001756 neigh_release(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001757 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 }
Thomas Graf5208deb2006-08-07 17:55:40 -07001759
1760 if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
1761 flags &= ~NEIGH_UPDATE_F_OVERRIDE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 }
1763
Eric Biederman0c5c2d32009-03-04 00:03:08 -08001764 if (ndm->ndm_flags & NTF_USE) {
1765 neigh_event_send(neigh, NULL);
1766 err = 0;
1767 } else
1768 err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
Thomas Graf5208deb2006-08-07 17:55:40 -07001769 neigh_release(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001770 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 }
1772
1773 read_unlock(&neigh_tbl_lock);
Thomas Graf5208deb2006-08-07 17:55:40 -07001774 err = -EAFNOSUPPORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775out:
1776 return err;
1777}
1778
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001779static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
1780{
Thomas Grafca860fb2006-08-07 18:00:18 -07001781 struct nlattr *nest;
1782
1783 nest = nla_nest_start(skb, NDTA_PARMS);
1784 if (nest == NULL)
1785 return -ENOBUFS;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001786
David S. Miller9a6308d2012-04-01 20:06:28 -04001787 if ((parms->dev &&
1788 nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) ||
1789 nla_put_u32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt)) ||
1790 nla_put_u32(skb, NDTPA_QUEUE_LENBYTES, parms->queue_len_bytes) ||
1791 /* approximative value for deprecated QUEUE_LEN (in packets) */
1792 nla_put_u32(skb, NDTPA_QUEUE_LEN,
Shan Weice46cc62012-12-04 18:49:15 +00001793 parms->queue_len_bytes / SKB_TRUESIZE(ETH_FRAME_LEN)) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04001794 nla_put_u32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen) ||
1795 nla_put_u32(skb, NDTPA_APP_PROBES, parms->app_probes) ||
1796 nla_put_u32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes) ||
1797 nla_put_u32(skb, NDTPA_MCAST_PROBES, parms->mcast_probes) ||
1798 nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time) ||
1799 nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME,
1800 parms->base_reachable_time) ||
1801 nla_put_msecs(skb, NDTPA_GC_STALETIME, parms->gc_staletime) ||
1802 nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME,
1803 parms->delay_probe_time) ||
1804 nla_put_msecs(skb, NDTPA_RETRANS_TIME, parms->retrans_time) ||
1805 nla_put_msecs(skb, NDTPA_ANYCAST_DELAY, parms->anycast_delay) ||
1806 nla_put_msecs(skb, NDTPA_PROXY_DELAY, parms->proxy_delay) ||
1807 nla_put_msecs(skb, NDTPA_LOCKTIME, parms->locktime))
1808 goto nla_put_failure;
Thomas Grafca860fb2006-08-07 18:00:18 -07001809 return nla_nest_end(skb, nest);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001810
Thomas Grafca860fb2006-08-07 18:00:18 -07001811nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07001812 nla_nest_cancel(skb, nest);
1813 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001814}
1815
Thomas Grafca860fb2006-08-07 18:00:18 -07001816static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
1817 u32 pid, u32 seq, int type, int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001818{
1819 struct nlmsghdr *nlh;
1820 struct ndtmsg *ndtmsg;
1821
Thomas Grafca860fb2006-08-07 18:00:18 -07001822 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
1823 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001824 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001825
Thomas Grafca860fb2006-08-07 18:00:18 -07001826 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001827
1828 read_lock_bh(&tbl->lock);
1829 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07001830 ndtmsg->ndtm_pad1 = 0;
1831 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001832
David S. Miller9a6308d2012-04-01 20:06:28 -04001833 if (nla_put_string(skb, NDTA_NAME, tbl->id) ||
1834 nla_put_msecs(skb, NDTA_GC_INTERVAL, tbl->gc_interval) ||
1835 nla_put_u32(skb, NDTA_THRESH1, tbl->gc_thresh1) ||
1836 nla_put_u32(skb, NDTA_THRESH2, tbl->gc_thresh2) ||
1837 nla_put_u32(skb, NDTA_THRESH3, tbl->gc_thresh3))
1838 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001839 {
1840 unsigned long now = jiffies;
1841 unsigned int flush_delta = now - tbl->last_flush;
1842 unsigned int rand_delta = now - tbl->last_rand;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001843 struct neigh_hash_table *nht;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001844 struct ndt_config ndc = {
1845 .ndtc_key_len = tbl->key_len,
1846 .ndtc_entry_size = tbl->entry_size,
1847 .ndtc_entries = atomic_read(&tbl->entries),
1848 .ndtc_last_flush = jiffies_to_msecs(flush_delta),
1849 .ndtc_last_rand = jiffies_to_msecs(rand_delta),
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001850 .ndtc_proxy_qlen = tbl->proxy_queue.qlen,
1851 };
1852
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001853 rcu_read_lock_bh();
1854 nht = rcu_dereference_bh(tbl->nht);
David S. Miller2c2aba62011-12-28 15:06:58 -05001855 ndc.ndtc_hash_rnd = nht->hash_rnd[0];
David S. Millercd089332011-07-11 01:28:12 -07001856 ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001857 rcu_read_unlock_bh();
1858
David S. Miller9a6308d2012-04-01 20:06:28 -04001859 if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc))
1860 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001861 }
1862
1863 {
1864 int cpu;
1865 struct ndt_stats ndst;
1866
1867 memset(&ndst, 0, sizeof(ndst));
1868
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001869 for_each_possible_cpu(cpu) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001870 struct neigh_statistics *st;
1871
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001872 st = per_cpu_ptr(tbl->stats, cpu);
1873 ndst.ndts_allocs += st->allocs;
1874 ndst.ndts_destroys += st->destroys;
1875 ndst.ndts_hash_grows += st->hash_grows;
1876 ndst.ndts_res_failed += st->res_failed;
1877 ndst.ndts_lookups += st->lookups;
1878 ndst.ndts_hits += st->hits;
1879 ndst.ndts_rcv_probes_mcast += st->rcv_probes_mcast;
1880 ndst.ndts_rcv_probes_ucast += st->rcv_probes_ucast;
1881 ndst.ndts_periodic_gc_runs += st->periodic_gc_runs;
1882 ndst.ndts_forced_gc_runs += st->forced_gc_runs;
1883 }
1884
David S. Miller9a6308d2012-04-01 20:06:28 -04001885 if (nla_put(skb, NDTA_STATS, sizeof(ndst), &ndst))
1886 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001887 }
1888
1889 BUG_ON(tbl->parms.dev);
1890 if (neightbl_fill_parms(skb, &tbl->parms) < 0)
Thomas Grafca860fb2006-08-07 18:00:18 -07001891 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001892
1893 read_unlock_bh(&tbl->lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07001894 return nlmsg_end(skb, nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001895
Thomas Grafca860fb2006-08-07 18:00:18 -07001896nla_put_failure:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001897 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08001898 nlmsg_cancel(skb, nlh);
1899 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001900}
1901
Thomas Grafca860fb2006-08-07 18:00:18 -07001902static int neightbl_fill_param_info(struct sk_buff *skb,
1903 struct neigh_table *tbl,
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001904 struct neigh_parms *parms,
Thomas Grafca860fb2006-08-07 18:00:18 -07001905 u32 pid, u32 seq, int type,
1906 unsigned int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001907{
1908 struct ndtmsg *ndtmsg;
1909 struct nlmsghdr *nlh;
1910
Thomas Grafca860fb2006-08-07 18:00:18 -07001911 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
1912 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001913 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001914
Thomas Grafca860fb2006-08-07 18:00:18 -07001915 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001916
1917 read_lock_bh(&tbl->lock);
1918 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07001919 ndtmsg->ndtm_pad1 = 0;
1920 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001921
Thomas Grafca860fb2006-08-07 18:00:18 -07001922 if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
1923 neightbl_fill_parms(skb, parms) < 0)
1924 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001925
1926 read_unlock_bh(&tbl->lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07001927 return nlmsg_end(skb, nlh);
1928errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001929 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08001930 nlmsg_cancel(skb, nlh);
1931 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001932}
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001933
Patrick McHardyef7c79e2007-06-05 12:38:30 -07001934static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07001935 [NDTA_NAME] = { .type = NLA_STRING },
1936 [NDTA_THRESH1] = { .type = NLA_U32 },
1937 [NDTA_THRESH2] = { .type = NLA_U32 },
1938 [NDTA_THRESH3] = { .type = NLA_U32 },
1939 [NDTA_GC_INTERVAL] = { .type = NLA_U64 },
1940 [NDTA_PARMS] = { .type = NLA_NESTED },
1941};
1942
Patrick McHardyef7c79e2007-06-05 12:38:30 -07001943static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07001944 [NDTPA_IFINDEX] = { .type = NLA_U32 },
1945 [NDTPA_QUEUE_LEN] = { .type = NLA_U32 },
1946 [NDTPA_PROXY_QLEN] = { .type = NLA_U32 },
1947 [NDTPA_APP_PROBES] = { .type = NLA_U32 },
1948 [NDTPA_UCAST_PROBES] = { .type = NLA_U32 },
1949 [NDTPA_MCAST_PROBES] = { .type = NLA_U32 },
1950 [NDTPA_BASE_REACHABLE_TIME] = { .type = NLA_U64 },
1951 [NDTPA_GC_STALETIME] = { .type = NLA_U64 },
1952 [NDTPA_DELAY_PROBE_TIME] = { .type = NLA_U64 },
1953 [NDTPA_RETRANS_TIME] = { .type = NLA_U64 },
1954 [NDTPA_ANYCAST_DELAY] = { .type = NLA_U64 },
1955 [NDTPA_PROXY_DELAY] = { .type = NLA_U64 },
1956 [NDTPA_LOCKTIME] = { .type = NLA_U64 },
1957};
1958
Thomas Grafc8822a42007-03-22 11:50:06 -07001959static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001960{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001961 struct net *net = sock_net(skb->sk);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001962 struct neigh_table *tbl;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001963 struct ndtmsg *ndtmsg;
1964 struct nlattr *tb[NDTA_MAX+1];
1965 int err;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001966
Thomas Graf6b3f8672006-08-07 17:58:53 -07001967 err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
1968 nl_neightbl_policy);
1969 if (err < 0)
1970 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001971
Thomas Graf6b3f8672006-08-07 17:58:53 -07001972 if (tb[NDTA_NAME] == NULL) {
1973 err = -EINVAL;
1974 goto errout;
1975 }
1976
1977 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001978 read_lock(&neigh_tbl_lock);
1979 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
1980 if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
1981 continue;
1982
Thomas Graf6b3f8672006-08-07 17:58:53 -07001983 if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001984 break;
1985 }
1986
1987 if (tbl == NULL) {
1988 err = -ENOENT;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001989 goto errout_locked;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001990 }
1991
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001992 /*
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001993 * We acquire tbl->lock to be nice to the periodic timers and
1994 * make sure they always see a consistent set of values.
1995 */
1996 write_lock_bh(&tbl->lock);
1997
Thomas Graf6b3f8672006-08-07 17:58:53 -07001998 if (tb[NDTA_PARMS]) {
1999 struct nlattr *tbp[NDTPA_MAX+1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002000 struct neigh_parms *p;
Thomas Graf6b3f8672006-08-07 17:58:53 -07002001 int i, ifindex = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002002
Thomas Graf6b3f8672006-08-07 17:58:53 -07002003 err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS],
2004 nl_ntbl_parm_policy);
2005 if (err < 0)
2006 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002007
Thomas Graf6b3f8672006-08-07 17:58:53 -07002008 if (tbp[NDTPA_IFINDEX])
2009 ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002010
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07002011 p = lookup_neigh_parms(tbl, net, ifindex);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002012 if (p == NULL) {
2013 err = -ENOENT;
Thomas Graf6b3f8672006-08-07 17:58:53 -07002014 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002015 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002016
Thomas Graf6b3f8672006-08-07 17:58:53 -07002017 for (i = 1; i <= NDTPA_MAX; i++) {
2018 if (tbp[i] == NULL)
2019 continue;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002020
Thomas Graf6b3f8672006-08-07 17:58:53 -07002021 switch (i) {
2022 case NDTPA_QUEUE_LEN:
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002023 p->queue_len_bytes = nla_get_u32(tbp[i]) *
2024 SKB_TRUESIZE(ETH_FRAME_LEN);
2025 break;
2026 case NDTPA_QUEUE_LENBYTES:
2027 p->queue_len_bytes = nla_get_u32(tbp[i]);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002028 break;
2029 case NDTPA_PROXY_QLEN:
2030 p->proxy_qlen = nla_get_u32(tbp[i]);
2031 break;
2032 case NDTPA_APP_PROBES:
2033 p->app_probes = nla_get_u32(tbp[i]);
2034 break;
2035 case NDTPA_UCAST_PROBES:
2036 p->ucast_probes = nla_get_u32(tbp[i]);
2037 break;
2038 case NDTPA_MCAST_PROBES:
2039 p->mcast_probes = nla_get_u32(tbp[i]);
2040 break;
2041 case NDTPA_BASE_REACHABLE_TIME:
2042 p->base_reachable_time = nla_get_msecs(tbp[i]);
2043 break;
2044 case NDTPA_GC_STALETIME:
2045 p->gc_staletime = nla_get_msecs(tbp[i]);
2046 break;
2047 case NDTPA_DELAY_PROBE_TIME:
2048 p->delay_probe_time = nla_get_msecs(tbp[i]);
2049 break;
2050 case NDTPA_RETRANS_TIME:
2051 p->retrans_time = nla_get_msecs(tbp[i]);
2052 break;
2053 case NDTPA_ANYCAST_DELAY:
2054 p->anycast_delay = nla_get_msecs(tbp[i]);
2055 break;
2056 case NDTPA_PROXY_DELAY:
2057 p->proxy_delay = nla_get_msecs(tbp[i]);
2058 break;
2059 case NDTPA_LOCKTIME:
2060 p->locktime = nla_get_msecs(tbp[i]);
2061 break;
2062 }
2063 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002064 }
2065
Thomas Graf6b3f8672006-08-07 17:58:53 -07002066 if (tb[NDTA_THRESH1])
2067 tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
2068
2069 if (tb[NDTA_THRESH2])
2070 tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
2071
2072 if (tb[NDTA_THRESH3])
2073 tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
2074
2075 if (tb[NDTA_GC_INTERVAL])
2076 tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
2077
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002078 err = 0;
2079
Thomas Graf6b3f8672006-08-07 17:58:53 -07002080errout_tbl_lock:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002081 write_unlock_bh(&tbl->lock);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002082errout_locked:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002083 read_unlock(&neigh_tbl_lock);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002084errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002085 return err;
2086}
2087
Thomas Grafc8822a42007-03-22 11:50:06 -07002088static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002089{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002090 struct net *net = sock_net(skb->sk);
Thomas Grafca860fb2006-08-07 18:00:18 -07002091 int family, tidx, nidx = 0;
2092 int tbl_skip = cb->args[0];
2093 int neigh_skip = cb->args[1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002094 struct neigh_table *tbl;
2095
Thomas Grafca860fb2006-08-07 18:00:18 -07002096 family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002097
2098 read_lock(&neigh_tbl_lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07002099 for (tbl = neigh_tables, tidx = 0; tbl; tbl = tbl->next, tidx++) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002100 struct neigh_parms *p;
2101
Thomas Grafca860fb2006-08-07 18:00:18 -07002102 if (tidx < tbl_skip || (family && tbl->family != family))
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002103 continue;
2104
Eric W. Biederman15e47302012-09-07 20:12:54 +00002105 if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
Thomas Grafca860fb2006-08-07 18:00:18 -07002106 cb->nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
2107 NLM_F_MULTI) <= 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002108 break;
2109
Eric W. Biederman426b5302008-01-24 00:13:18 -08002110 for (nidx = 0, p = tbl->parms.next; p; p = p->next) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002111 if (!net_eq(neigh_parms_net(p), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002112 continue;
2113
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002114 if (nidx < neigh_skip)
2115 goto next;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002116
Thomas Grafca860fb2006-08-07 18:00:18 -07002117 if (neightbl_fill_param_info(skb, tbl, p,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002118 NETLINK_CB(cb->skb).portid,
Thomas Grafca860fb2006-08-07 18:00:18 -07002119 cb->nlh->nlmsg_seq,
2120 RTM_NEWNEIGHTBL,
2121 NLM_F_MULTI) <= 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002122 goto out;
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002123 next:
2124 nidx++;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002125 }
2126
Thomas Grafca860fb2006-08-07 18:00:18 -07002127 neigh_skip = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002128 }
2129out:
2130 read_unlock(&neigh_tbl_lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07002131 cb->args[0] = tidx;
2132 cb->args[1] = nidx;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002133
2134 return skb->len;
2135}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136
Thomas Graf8b8aec52006-08-07 17:56:37 -07002137static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
2138 u32 pid, u32 seq, int type, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139{
2140 unsigned long now = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 struct nda_cacheinfo ci;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002142 struct nlmsghdr *nlh;
2143 struct ndmsg *ndm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144
Thomas Graf8b8aec52006-08-07 17:56:37 -07002145 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
2146 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08002147 return -EMSGSIZE;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002148
2149 ndm = nlmsg_data(nlh);
2150 ndm->ndm_family = neigh->ops->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07002151 ndm->ndm_pad1 = 0;
2152 ndm->ndm_pad2 = 0;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002153 ndm->ndm_flags = neigh->flags;
2154 ndm->ndm_type = neigh->type;
2155 ndm->ndm_ifindex = neigh->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156
David S. Miller9a6308d2012-04-01 20:06:28 -04002157 if (nla_put(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key))
2158 goto nla_put_failure;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002159
2160 read_lock_bh(&neigh->lock);
2161 ndm->ndm_state = neigh->nud_state;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00002162 if (neigh->nud_state & NUD_VALID) {
2163 char haddr[MAX_ADDR_LEN];
2164
2165 neigh_ha_snapshot(haddr, neigh, neigh->dev);
2166 if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0) {
2167 read_unlock_bh(&neigh->lock);
2168 goto nla_put_failure;
2169 }
Thomas Graf8b8aec52006-08-07 17:56:37 -07002170 }
2171
Stephen Hemmingerb9f5f522008-06-03 16:03:15 -07002172 ci.ndm_used = jiffies_to_clock_t(now - neigh->used);
2173 ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
2174 ci.ndm_updated = jiffies_to_clock_t(now - neigh->updated);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002175 ci.ndm_refcnt = atomic_read(&neigh->refcnt) - 1;
2176 read_unlock_bh(&neigh->lock);
2177
David S. Miller9a6308d2012-04-01 20:06:28 -04002178 if (nla_put_u32(skb, NDA_PROBES, atomic_read(&neigh->probes)) ||
2179 nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
2180 goto nla_put_failure;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002181
2182 return nlmsg_end(skb, nlh);
2183
2184nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002185 nlmsg_cancel(skb, nlh);
2186 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187}
2188
Tony Zelenoff84920c12012-01-26 22:28:58 +00002189static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
2190 u32 pid, u32 seq, int type, unsigned int flags,
2191 struct neigh_table *tbl)
2192{
2193 struct nlmsghdr *nlh;
2194 struct ndmsg *ndm;
2195
2196 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
2197 if (nlh == NULL)
2198 return -EMSGSIZE;
2199
2200 ndm = nlmsg_data(nlh);
2201 ndm->ndm_family = tbl->family;
2202 ndm->ndm_pad1 = 0;
2203 ndm->ndm_pad2 = 0;
2204 ndm->ndm_flags = pn->flags | NTF_PROXY;
2205 ndm->ndm_type = NDA_DST;
2206 ndm->ndm_ifindex = pn->dev->ifindex;
2207 ndm->ndm_state = NUD_NONE;
2208
David S. Miller9a6308d2012-04-01 20:06:28 -04002209 if (nla_put(skb, NDA_DST, tbl->key_len, pn->key))
2210 goto nla_put_failure;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002211
2212 return nlmsg_end(skb, nlh);
2213
2214nla_put_failure:
2215 nlmsg_cancel(skb, nlh);
2216 return -EMSGSIZE;
2217}
2218
Thomas Grafd961db32007-08-08 23:12:56 -07002219static void neigh_update_notify(struct neighbour *neigh)
2220{
2221 call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
2222 __neigh_notify(neigh, RTM_NEWNEIGH, 0);
2223}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224
2225static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
2226 struct netlink_callback *cb)
2227{
Eric Dumazet767e97e2010-10-06 17:49:21 -07002228 struct net *net = sock_net(skb->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 struct neighbour *n;
2230 int rc, h, s_h = cb->args[1];
2231 int idx, s_idx = idx = cb->args[2];
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002232 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002234 rcu_read_lock_bh();
2235 nht = rcu_dereference_bh(tbl->nht);
2236
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002237 for (h = s_h; h < (1 << nht->hash_shift); h++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 if (h > s_h)
2239 s_idx = 0;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002240 for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
2241 n != NULL;
2242 n = rcu_dereference_bh(n->next)) {
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002243 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002244 continue;
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002245 if (idx < s_idx)
2246 goto next;
Eric W. Biederman15e47302012-09-07 20:12:54 +00002247 if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 cb->nlh->nlmsg_seq,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07002249 RTM_NEWNEIGH,
2250 NLM_F_MULTI) <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 rc = -1;
2252 goto out;
2253 }
Eric Dumazet767e97e2010-10-06 17:49:21 -07002254next:
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002255 idx++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 }
2258 rc = skb->len;
2259out:
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002260 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 cb->args[1] = h;
2262 cb->args[2] = idx;
2263 return rc;
2264}
2265
Tony Zelenoff84920c12012-01-26 22:28:58 +00002266static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
2267 struct netlink_callback *cb)
2268{
2269 struct pneigh_entry *n;
2270 struct net *net = sock_net(skb->sk);
2271 int rc, h, s_h = cb->args[3];
2272 int idx, s_idx = idx = cb->args[4];
2273
2274 read_lock_bh(&tbl->lock);
2275
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002276 for (h = s_h; h <= PNEIGH_HASHMASK; h++) {
Tony Zelenoff84920c12012-01-26 22:28:58 +00002277 if (h > s_h)
2278 s_idx = 0;
2279 for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
2280 if (dev_net(n->dev) != net)
2281 continue;
2282 if (idx < s_idx)
2283 goto next;
Eric W. Biederman15e47302012-09-07 20:12:54 +00002284 if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
Tony Zelenoff84920c12012-01-26 22:28:58 +00002285 cb->nlh->nlmsg_seq,
2286 RTM_NEWNEIGH,
2287 NLM_F_MULTI, tbl) <= 0) {
2288 read_unlock_bh(&tbl->lock);
2289 rc = -1;
2290 goto out;
2291 }
2292 next:
2293 idx++;
2294 }
2295 }
2296
2297 read_unlock_bh(&tbl->lock);
2298 rc = skb->len;
2299out:
2300 cb->args[3] = h;
2301 cb->args[4] = idx;
2302 return rc;
2303
2304}
2305
Thomas Grafc8822a42007-03-22 11:50:06 -07002306static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307{
2308 struct neigh_table *tbl;
2309 int t, family, s_t;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002310 int proxy = 0;
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002311 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312
2313 read_lock(&neigh_tbl_lock);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002314 family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002315
2316 /* check for full ndmsg structure presence, family member is
2317 * the same for both structures
2318 */
2319 if (nlmsg_len(cb->nlh) >= sizeof(struct ndmsg) &&
2320 ((struct ndmsg *) nlmsg_data(cb->nlh))->ndm_flags == NTF_PROXY)
2321 proxy = 1;
2322
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 s_t = cb->args[0];
2324
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002325 for (tbl = neigh_tables, t = 0; tbl;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002326 tbl = tbl->next, t++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 if (t < s_t || (family && tbl->family != family))
2328 continue;
2329 if (t > s_t)
2330 memset(&cb->args[1], 0, sizeof(cb->args) -
2331 sizeof(cb->args[0]));
Tony Zelenoff84920c12012-01-26 22:28:58 +00002332 if (proxy)
2333 err = pneigh_dump_table(tbl, skb, cb);
2334 else
2335 err = neigh_dump_table(tbl, skb, cb);
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002336 if (err < 0)
2337 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 }
2339 read_unlock(&neigh_tbl_lock);
2340
2341 cb->args[0] = t;
2342 return skb->len;
2343}
2344
2345void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
2346{
2347 int chain;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002348 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002350 rcu_read_lock_bh();
2351 nht = rcu_dereference_bh(tbl->nht);
2352
Eric Dumazet767e97e2010-10-06 17:49:21 -07002353 read_lock(&tbl->lock); /* avoid resizes */
David S. Millercd089332011-07-11 01:28:12 -07002354 for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 struct neighbour *n;
2356
Eric Dumazet767e97e2010-10-06 17:49:21 -07002357 for (n = rcu_dereference_bh(nht->hash_buckets[chain]);
2358 n != NULL;
2359 n = rcu_dereference_bh(n->next))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 cb(n, cookie);
2361 }
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002362 read_unlock(&tbl->lock);
2363 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364}
2365EXPORT_SYMBOL(neigh_for_each);
2366
2367/* The tbl->lock must be held as a writer and BH disabled. */
2368void __neigh_for_each_release(struct neigh_table *tbl,
2369 int (*cb)(struct neighbour *))
2370{
2371 int chain;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002372 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002374 nht = rcu_dereference_protected(tbl->nht,
2375 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -07002376 for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002377 struct neighbour *n;
2378 struct neighbour __rcu **np;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002380 np = &nht->hash_buckets[chain];
Eric Dumazet767e97e2010-10-06 17:49:21 -07002381 while ((n = rcu_dereference_protected(*np,
2382 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 int release;
2384
2385 write_lock(&n->lock);
2386 release = cb(n);
2387 if (release) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002388 rcu_assign_pointer(*np,
2389 rcu_dereference_protected(n->next,
2390 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 n->dead = 1;
2392 } else
2393 np = &n->next;
2394 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -07002395 if (release)
2396 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 }
2398 }
2399}
2400EXPORT_SYMBOL(__neigh_for_each_release);
2401
2402#ifdef CONFIG_PROC_FS
2403
2404static struct neighbour *neigh_get_first(struct seq_file *seq)
2405{
2406 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002407 struct net *net = seq_file_net(seq);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002408 struct neigh_hash_table *nht = state->nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 struct neighbour *n = NULL;
2410 int bucket = state->bucket;
2411
2412 state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
David S. Millercd089332011-07-11 01:28:12 -07002413 for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002414 n = rcu_dereference_bh(nht->hash_buckets[bucket]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415
2416 while (n) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002417 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002418 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 if (state->neigh_sub_iter) {
2420 loff_t fakep = 0;
2421 void *v;
2422
2423 v = state->neigh_sub_iter(state, n, &fakep);
2424 if (!v)
2425 goto next;
2426 }
2427 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
2428 break;
2429 if (n->nud_state & ~NUD_NOARP)
2430 break;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002431next:
2432 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 }
2434
2435 if (n)
2436 break;
2437 }
2438 state->bucket = bucket;
2439
2440 return n;
2441}
2442
2443static struct neighbour *neigh_get_next(struct seq_file *seq,
2444 struct neighbour *n,
2445 loff_t *pos)
2446{
2447 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002448 struct net *net = seq_file_net(seq);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002449 struct neigh_hash_table *nht = state->nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450
2451 if (state->neigh_sub_iter) {
2452 void *v = state->neigh_sub_iter(state, n, pos);
2453 if (v)
2454 return n;
2455 }
Eric Dumazet767e97e2010-10-06 17:49:21 -07002456 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457
2458 while (1) {
2459 while (n) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002460 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002461 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 if (state->neigh_sub_iter) {
2463 void *v = state->neigh_sub_iter(state, n, pos);
2464 if (v)
2465 return n;
2466 goto next;
2467 }
2468 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
2469 break;
2470
2471 if (n->nud_state & ~NUD_NOARP)
2472 break;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002473next:
2474 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 }
2476
2477 if (n)
2478 break;
2479
David S. Millercd089332011-07-11 01:28:12 -07002480 if (++state->bucket >= (1 << nht->hash_shift))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 break;
2482
Eric Dumazet767e97e2010-10-06 17:49:21 -07002483 n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 }
2485
2486 if (n && pos)
2487 --(*pos);
2488 return n;
2489}
2490
2491static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
2492{
2493 struct neighbour *n = neigh_get_first(seq);
2494
2495 if (n) {
Chris Larson745e2032008-08-03 01:10:55 -07002496 --(*pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 while (*pos) {
2498 n = neigh_get_next(seq, n, pos);
2499 if (!n)
2500 break;
2501 }
2502 }
2503 return *pos ? NULL : n;
2504}
2505
2506static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
2507{
2508 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002509 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 struct neigh_table *tbl = state->tbl;
2511 struct pneigh_entry *pn = NULL;
2512 int bucket = state->bucket;
2513
2514 state->flags |= NEIGH_SEQ_IS_PNEIGH;
2515 for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
2516 pn = tbl->phash_buckets[bucket];
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002517 while (pn && !net_eq(pneigh_net(pn), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002518 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 if (pn)
2520 break;
2521 }
2522 state->bucket = bucket;
2523
2524 return pn;
2525}
2526
2527static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
2528 struct pneigh_entry *pn,
2529 loff_t *pos)
2530{
2531 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002532 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533 struct neigh_table *tbl = state->tbl;
2534
Jorge Boncompte [DTI2]df07a942011-11-25 13:24:49 -05002535 do {
2536 pn = pn->next;
2537 } while (pn && !net_eq(pneigh_net(pn), net));
2538
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 while (!pn) {
2540 if (++state->bucket > PNEIGH_HASHMASK)
2541 break;
2542 pn = tbl->phash_buckets[state->bucket];
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002543 while (pn && !net_eq(pneigh_net(pn), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002544 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 if (pn)
2546 break;
2547 }
2548
2549 if (pn && pos)
2550 --(*pos);
2551
2552 return pn;
2553}
2554
2555static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
2556{
2557 struct pneigh_entry *pn = pneigh_get_first(seq);
2558
2559 if (pn) {
Chris Larson745e2032008-08-03 01:10:55 -07002560 --(*pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 while (*pos) {
2562 pn = pneigh_get_next(seq, pn, pos);
2563 if (!pn)
2564 break;
2565 }
2566 }
2567 return *pos ? NULL : pn;
2568}
2569
2570static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
2571{
2572 struct neigh_seq_state *state = seq->private;
2573 void *rc;
Chris Larson745e2032008-08-03 01:10:55 -07002574 loff_t idxpos = *pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575
Chris Larson745e2032008-08-03 01:10:55 -07002576 rc = neigh_get_idx(seq, &idxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
Chris Larson745e2032008-08-03 01:10:55 -07002578 rc = pneigh_get_idx(seq, &idxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579
2580 return rc;
2581}
2582
2583void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl, unsigned int neigh_seq_flags)
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002584 __acquires(rcu_bh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585{
2586 struct neigh_seq_state *state = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587
2588 state->tbl = tbl;
2589 state->bucket = 0;
2590 state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
2591
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002592 rcu_read_lock_bh();
2593 state->nht = rcu_dereference_bh(tbl->nht);
Eric Dumazet767e97e2010-10-06 17:49:21 -07002594
Chris Larson745e2032008-08-03 01:10:55 -07002595 return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596}
2597EXPORT_SYMBOL(neigh_seq_start);
2598
2599void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2600{
2601 struct neigh_seq_state *state;
2602 void *rc;
2603
2604 if (v == SEQ_START_TOKEN) {
Chris Larsonbff69732008-08-03 01:02:41 -07002605 rc = neigh_get_first(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 goto out;
2607 }
2608
2609 state = seq->private;
2610 if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {
2611 rc = neigh_get_next(seq, v, NULL);
2612 if (rc)
2613 goto out;
2614 if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))
2615 rc = pneigh_get_first(seq);
2616 } else {
2617 BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);
2618 rc = pneigh_get_next(seq, v, NULL);
2619 }
2620out:
2621 ++(*pos);
2622 return rc;
2623}
2624EXPORT_SYMBOL(neigh_seq_next);
2625
2626void neigh_seq_stop(struct seq_file *seq, void *v)
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002627 __releases(rcu_bh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628{
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002629 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630}
2631EXPORT_SYMBOL(neigh_seq_stop);
2632
2633/* statistics via seq_file */
2634
2635static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
2636{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002637 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 int cpu;
2639
2640 if (*pos == 0)
2641 return SEQ_START_TOKEN;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09002642
Rusty Russell0f23174a2008-12-29 12:23:42 +00002643 for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 if (!cpu_possible(cpu))
2645 continue;
2646 *pos = cpu+1;
2647 return per_cpu_ptr(tbl->stats, cpu);
2648 }
2649 return NULL;
2650}
2651
2652static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2653{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002654 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 int cpu;
2656
Rusty Russell0f23174a2008-12-29 12:23:42 +00002657 for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 if (!cpu_possible(cpu))
2659 continue;
2660 *pos = cpu+1;
2661 return per_cpu_ptr(tbl->stats, cpu);
2662 }
2663 return NULL;
2664}
2665
2666static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
2667{
2668
2669}
2670
2671static int neigh_stat_seq_show(struct seq_file *seq, void *v)
2672{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002673 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 struct neigh_statistics *st = v;
2675
2676 if (v == SEQ_START_TOKEN) {
Neil Horman9a6d2762008-07-16 20:50:49 -07002677 seq_printf(seq, "entries allocs destroys hash_grows lookups hits res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs unresolved_discards\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 return 0;
2679 }
2680
2681 seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx "
Neil Horman9a6d2762008-07-16 20:50:49 -07002682 "%08lx %08lx %08lx %08lx %08lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 atomic_read(&tbl->entries),
2684
2685 st->allocs,
2686 st->destroys,
2687 st->hash_grows,
2688
2689 st->lookups,
2690 st->hits,
2691
2692 st->res_failed,
2693
2694 st->rcv_probes_mcast,
2695 st->rcv_probes_ucast,
2696
2697 st->periodic_gc_runs,
Neil Horman9a6d2762008-07-16 20:50:49 -07002698 st->forced_gc_runs,
2699 st->unres_discards
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 );
2701
2702 return 0;
2703}
2704
Stephen Hemmingerf6908082007-03-12 14:34:29 -07002705static const struct seq_operations neigh_stat_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 .start = neigh_stat_seq_start,
2707 .next = neigh_stat_seq_next,
2708 .stop = neigh_stat_seq_stop,
2709 .show = neigh_stat_seq_show,
2710};
2711
2712static int neigh_stat_seq_open(struct inode *inode, struct file *file)
2713{
2714 int ret = seq_open(file, &neigh_stat_seq_ops);
2715
2716 if (!ret) {
2717 struct seq_file *sf = file->private_data;
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002718 sf->private = PDE(inode)->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 }
2720 return ret;
2721};
2722
Arjan van de Ven9a321442007-02-12 00:55:35 -08002723static const struct file_operations neigh_stat_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 .owner = THIS_MODULE,
2725 .open = neigh_stat_seq_open,
2726 .read = seq_read,
2727 .llseek = seq_lseek,
2728 .release = seq_release,
2729};
2730
2731#endif /* CONFIG_PROC_FS */
2732
Thomas Graf339bf982006-11-10 14:10:15 -08002733static inline size_t neigh_nlmsg_size(void)
2734{
2735 return NLMSG_ALIGN(sizeof(struct ndmsg))
2736 + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
2737 + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
2738 + nla_total_size(sizeof(struct nda_cacheinfo))
2739 + nla_total_size(4); /* NDA_PROBES */
2740}
2741
Thomas Grafb8673312006-08-15 00:33:14 -07002742static void __neigh_notify(struct neighbour *n, int type, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002744 struct net *net = dev_net(n->dev);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002745 struct sk_buff *skb;
Thomas Grafb8673312006-08-15 00:33:14 -07002746 int err = -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747
Thomas Graf339bf982006-11-10 14:10:15 -08002748 skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002749 if (skb == NULL)
Thomas Grafb8673312006-08-15 00:33:14 -07002750 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751
Thomas Grafb8673312006-08-15 00:33:14 -07002752 err = neigh_fill_info(skb, n, 0, 0, type, flags);
Patrick McHardy26932562007-01-31 23:16:40 -08002753 if (err < 0) {
2754 /* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
2755 WARN_ON(err == -EMSGSIZE);
2756 kfree_skb(skb);
2757 goto errout;
2758 }
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08002759 rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
2760 return;
Thomas Grafb8673312006-08-15 00:33:14 -07002761errout:
2762 if (err < 0)
Eric W. Biederman426b5302008-01-24 00:13:18 -08002763 rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
Thomas Grafb8673312006-08-15 00:33:14 -07002764}
2765
Thomas Grafd961db32007-08-08 23:12:56 -07002766#ifdef CONFIG_ARPD
Thomas Grafb8673312006-08-15 00:33:14 -07002767void neigh_app_ns(struct neighbour *n)
2768{
2769 __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09002771EXPORT_SYMBOL(neigh_app_ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772#endif /* CONFIG_ARPD */
2773
2774#ifdef CONFIG_SYSCTL
2775
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002776static int proc_unres_qlen(ctl_table *ctl, int write, void __user *buffer,
2777 size_t *lenp, loff_t *ppos)
2778{
2779 int size, ret;
2780 ctl_table tmp = *ctl;
2781
Shan Weice46cc62012-12-04 18:49:15 +00002782 tmp.extra1 = &zero;
2783 tmp.extra2 = &unres_qlen_max;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002784 tmp.data = &size;
Shan Weice46cc62012-12-04 18:49:15 +00002785
2786 size = *(int *)ctl->data / SKB_TRUESIZE(ETH_FRAME_LEN);
2787 ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
2788
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002789 if (write && !ret)
2790 *(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
2791 return ret;
2792}
2793
2794enum {
2795 NEIGH_VAR_MCAST_PROBE,
2796 NEIGH_VAR_UCAST_PROBE,
2797 NEIGH_VAR_APP_PROBE,
2798 NEIGH_VAR_RETRANS_TIME,
2799 NEIGH_VAR_BASE_REACHABLE_TIME,
2800 NEIGH_VAR_DELAY_PROBE_TIME,
2801 NEIGH_VAR_GC_STALETIME,
2802 NEIGH_VAR_QUEUE_LEN,
2803 NEIGH_VAR_QUEUE_LEN_BYTES,
2804 NEIGH_VAR_PROXY_QLEN,
2805 NEIGH_VAR_ANYCAST_DELAY,
2806 NEIGH_VAR_PROXY_DELAY,
2807 NEIGH_VAR_LOCKTIME,
2808 NEIGH_VAR_RETRANS_TIME_MS,
2809 NEIGH_VAR_BASE_REACHABLE_TIME_MS,
2810 NEIGH_VAR_GC_INTERVAL,
2811 NEIGH_VAR_GC_THRESH1,
2812 NEIGH_VAR_GC_THRESH2,
2813 NEIGH_VAR_GC_THRESH3,
2814 NEIGH_VAR_MAX
2815};
Eric W. Biederman54716e32010-02-14 03:27:03 +00002816
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817static struct neigh_sysctl_table {
2818 struct ctl_table_header *sysctl_header;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002819 struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
Brian Haleyab32ea52006-09-22 14:15:41 -07002820} neigh_sysctl_template __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 .neigh_vars = {
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002822 [NEIGH_VAR_MCAST_PROBE] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 .procname = "mcast_solicit",
2824 .maxlen = sizeof(int),
2825 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002826 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002828 [NEIGH_VAR_UCAST_PROBE] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 .procname = "ucast_solicit",
2830 .maxlen = sizeof(int),
2831 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002832 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002834 [NEIGH_VAR_APP_PROBE] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 .procname = "app_solicit",
2836 .maxlen = sizeof(int),
2837 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002838 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002840 [NEIGH_VAR_RETRANS_TIME] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 .procname = "retrans_time",
2842 .maxlen = sizeof(int),
2843 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002844 .proc_handler = proc_dointvec_userhz_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002846 [NEIGH_VAR_BASE_REACHABLE_TIME] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 .procname = "base_reachable_time",
2848 .maxlen = sizeof(int),
2849 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002850 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002852 [NEIGH_VAR_DELAY_PROBE_TIME] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 .procname = "delay_first_probe_time",
2854 .maxlen = sizeof(int),
2855 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002856 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002858 [NEIGH_VAR_GC_STALETIME] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 .procname = "gc_stale_time",
2860 .maxlen = sizeof(int),
2861 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002862 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002864 [NEIGH_VAR_QUEUE_LEN] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 .procname = "unres_qlen",
2866 .maxlen = sizeof(int),
2867 .mode = 0644,
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002868 .proc_handler = proc_unres_qlen,
2869 },
2870 [NEIGH_VAR_QUEUE_LEN_BYTES] = {
2871 .procname = "unres_qlen_bytes",
2872 .maxlen = sizeof(int),
2873 .mode = 0644,
Shan Weice46cc62012-12-04 18:49:15 +00002874 .extra1 = &zero,
2875 .proc_handler = proc_dointvec_minmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002877 [NEIGH_VAR_PROXY_QLEN] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 .procname = "proxy_qlen",
2879 .maxlen = sizeof(int),
2880 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002881 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002883 [NEIGH_VAR_ANYCAST_DELAY] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 .procname = "anycast_delay",
2885 .maxlen = sizeof(int),
2886 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002887 .proc_handler = proc_dointvec_userhz_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002889 [NEIGH_VAR_PROXY_DELAY] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 .procname = "proxy_delay",
2891 .maxlen = sizeof(int),
2892 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002893 .proc_handler = proc_dointvec_userhz_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002895 [NEIGH_VAR_LOCKTIME] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 .procname = "locktime",
2897 .maxlen = sizeof(int),
2898 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002899 .proc_handler = proc_dointvec_userhz_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002901 [NEIGH_VAR_RETRANS_TIME_MS] = {
Eric W. Biedermand12af672007-10-18 03:05:25 -07002902 .procname = "retrans_time_ms",
2903 .maxlen = sizeof(int),
2904 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002905 .proc_handler = proc_dointvec_ms_jiffies,
Eric W. Biedermand12af672007-10-18 03:05:25 -07002906 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002907 [NEIGH_VAR_BASE_REACHABLE_TIME_MS] = {
Eric W. Biedermand12af672007-10-18 03:05:25 -07002908 .procname = "base_reachable_time_ms",
2909 .maxlen = sizeof(int),
2910 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002911 .proc_handler = proc_dointvec_ms_jiffies,
Eric W. Biedermand12af672007-10-18 03:05:25 -07002912 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002913 [NEIGH_VAR_GC_INTERVAL] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 .procname = "gc_interval",
2915 .maxlen = sizeof(int),
2916 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002917 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002919 [NEIGH_VAR_GC_THRESH1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 .procname = "gc_thresh1",
2921 .maxlen = sizeof(int),
2922 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002923 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002925 [NEIGH_VAR_GC_THRESH2] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 .procname = "gc_thresh2",
2927 .maxlen = sizeof(int),
2928 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002929 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002931 [NEIGH_VAR_GC_THRESH3] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 .procname = "gc_thresh3",
2933 .maxlen = sizeof(int),
2934 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002935 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 },
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002937 {},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 },
2939};
2940
2941int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
Eric W. Biederman54716e32010-02-14 03:27:03 +00002942 char *p_name, proc_handler *handler)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943{
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002944 struct neigh_sysctl_table *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 const char *dev_name_source = NULL;
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00002946 char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002948 t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 if (!t)
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002950 goto err;
2951
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002952 t->neigh_vars[NEIGH_VAR_MCAST_PROBE].data = &p->mcast_probes;
2953 t->neigh_vars[NEIGH_VAR_UCAST_PROBE].data = &p->ucast_probes;
2954 t->neigh_vars[NEIGH_VAR_APP_PROBE].data = &p->app_probes;
2955 t->neigh_vars[NEIGH_VAR_RETRANS_TIME].data = &p->retrans_time;
2956 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].data = &p->base_reachable_time;
2957 t->neigh_vars[NEIGH_VAR_DELAY_PROBE_TIME].data = &p->delay_probe_time;
2958 t->neigh_vars[NEIGH_VAR_GC_STALETIME].data = &p->gc_staletime;
2959 t->neigh_vars[NEIGH_VAR_QUEUE_LEN].data = &p->queue_len_bytes;
2960 t->neigh_vars[NEIGH_VAR_QUEUE_LEN_BYTES].data = &p->queue_len_bytes;
2961 t->neigh_vars[NEIGH_VAR_PROXY_QLEN].data = &p->proxy_qlen;
2962 t->neigh_vars[NEIGH_VAR_ANYCAST_DELAY].data = &p->anycast_delay;
2963 t->neigh_vars[NEIGH_VAR_PROXY_DELAY].data = &p->proxy_delay;
2964 t->neigh_vars[NEIGH_VAR_LOCKTIME].data = &p->locktime;
2965 t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].data = &p->retrans_time;
2966 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].data = &p->base_reachable_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967
2968 if (dev) {
2969 dev_name_source = dev->name;
Eric W. Biedermand12af672007-10-18 03:05:25 -07002970 /* Terminate the table early */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002971 memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
2972 sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 } else {
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00002974 dev_name_source = "default";
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002975 t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = (int *)(p + 1);
2976 t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = (int *)(p + 1) + 1;
2977 t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = (int *)(p + 1) + 2;
2978 t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = (int *)(p + 1) + 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 }
2980
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002982 if (handler) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 /* RetransTime */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002984 t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
2985 t->neigh_vars[NEIGH_VAR_RETRANS_TIME].extra1 = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 /* ReachableTime */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002987 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
2988 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].extra1 = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 /* RetransTime (in milliseconds)*/
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002990 t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
2991 t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].extra1 = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 /* ReachableTime (in milliseconds) */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002993 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
2994 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].extra1 = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 }
2996
Eric W. Biederman464dc802012-11-16 03:02:59 +00002997 /* Don't export sysctls to unprivileged users */
2998 if (neigh_parms_net(p)->user_ns != &init_user_ns)
2999 t->neigh_vars[0].procname = NULL;
3000
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003001 snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s",
3002 p_name, dev_name_source);
Denis V. Lunev4ab438f2008-02-28 20:48:01 -08003003 t->sysctl_header =
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003004 register_net_sysctl(neigh_parms_net(p), neigh_path, t->neigh_vars);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003005 if (!t->sysctl_header)
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003006 goto free;
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003007
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 p->sysctl_table = t;
3009 return 0;
3010
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003011free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 kfree(t);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003013err:
3014 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09003016EXPORT_SYMBOL(neigh_sysctl_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017
3018void neigh_sysctl_unregister(struct neigh_parms *p)
3019{
3020 if (p->sysctl_table) {
3021 struct neigh_sysctl_table *t = p->sysctl_table;
3022 p->sysctl_table = NULL;
Eric W. Biederman5dd3df12012-04-19 13:24:33 +00003023 unregister_net_sysctl_table(t->sysctl_header);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 kfree(t);
3025 }
3026}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09003027EXPORT_SYMBOL(neigh_sysctl_unregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028
3029#endif /* CONFIG_SYSCTL */
3030
Thomas Grafc8822a42007-03-22 11:50:06 -07003031static int __init neigh_init(void)
3032{
Greg Rosec7ac8672011-06-10 01:27:09 +00003033 rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, NULL);
3034 rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, NULL);
3035 rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info, NULL);
Thomas Grafc8822a42007-03-22 11:50:06 -07003036
Greg Rosec7ac8672011-06-10 01:27:09 +00003037 rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
3038 NULL);
3039 rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, NULL);
Thomas Grafc8822a42007-03-22 11:50:06 -07003040
3041 return 0;
3042}
3043
3044subsys_initcall(neigh_init);
3045