blob: edd04116ecb7d7d973edf5f802d465aed5b6fcac [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>
Jiri Pirko1d4c8c22013-12-07 19:26:56 +010041#include <linux/inetdevice.h>
Jiri Pirkobba24892013-12-07 19:26:57 +010042#include <net/addrconf.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
Joe Perchesd5d427c2013-04-15 15:17:19 +000044#define DEBUG
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#define NEIGH_DEBUG 1
Joe Perchesd5d427c2013-04-15 15:17:19 +000046#define neigh_dbg(level, fmt, ...) \
47do { \
48 if (level <= NEIGH_DEBUG) \
49 pr_debug(fmt, ##__VA_ARGS__); \
50} while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52#define PNEIGH_HASHMASK 0xF
53
54static void neigh_timer_handler(unsigned long arg);
Thomas Grafd961db32007-08-08 23:12:56 -070055static void __neigh_notify(struct neighbour *n, int type, int flags);
56static void neigh_update_notify(struct neighbour *neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -070057static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
59static struct neigh_table *neigh_tables;
Amos Waterland45fc3b12005-09-24 16:53:16 -070060#ifdef CONFIG_PROC_FS
Arjan van de Ven9a321442007-02-12 00:55:35 -080061static const struct file_operations neigh_stat_seq_fops;
Amos Waterland45fc3b12005-09-24 16:53:16 -070062#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
64/*
65 Neighbour hash table buckets are protected with rwlock tbl->lock.
66
67 - All the scans/updates to hash buckets MUST be made under this lock.
68 - NOTHING clever should be made under this lock: no callbacks
69 to protocol backends, no attempts to send something to network.
70 It will result in deadlocks, if backend/driver wants to use neighbour
71 cache.
72 - If the entry requires some non-trivial actions, increase
73 its reference count and release table lock.
74
75 Neighbour entries are protected:
76 - with reference count.
77 - with rwlock neigh->lock
78
79 Reference count prevents destruction.
80
81 neigh->lock mainly serializes ll address data and its validity state.
82 However, the same lock is used to protect another entry fields:
83 - timer
84 - resolution queue
85
86 Again, nothing clever shall be made under neigh->lock,
87 the most complicated procedure, which we allow is dev->hard_header.
88 It is supposed, that dev->hard_header is simplistic and does
89 not make callbacks to neighbour tables.
90
91 The last lock is neigh_tbl_lock. It is pure SMP lock, protecting
92 list of neighbour tables. This list is used only in process context,
93 */
94
95static DEFINE_RWLOCK(neigh_tbl_lock);
96
David S. Miller8f40b162011-07-17 13:34:11 -070097static int neigh_blackhole(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -070098{
99 kfree_skb(skb);
100 return -ENETDOWN;
101}
102
Thomas Graf4f494552007-08-08 23:12:36 -0700103static void neigh_cleanup_and_release(struct neighbour *neigh)
104{
105 if (neigh->parms->neigh_cleanup)
106 neigh->parms->neigh_cleanup(neigh);
107
Thomas Grafd961db32007-08-08 23:12:56 -0700108 __neigh_notify(neigh, RTM_DELNEIGH, 0);
Thomas Graf4f494552007-08-08 23:12:36 -0700109 neigh_release(neigh);
110}
111
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112/*
113 * It is random distribution in the interval (1/2)*base...(3/2)*base.
114 * It corresponds to default IPv6 settings and is not overridable,
115 * because it is really reasonable choice.
116 */
117
118unsigned long neigh_rand_reach_time(unsigned long base)
119{
Aruna-Hewapathirane63862b52014-01-11 07:15:59 -0500120 return base ? (prandom_u32() % base) + (base >> 1) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900122EXPORT_SYMBOL(neigh_rand_reach_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
124
125static int neigh_forced_gc(struct neigh_table *tbl)
126{
127 int shrunk = 0;
128 int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000129 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
131 NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
132
133 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000134 nht = rcu_dereference_protected(tbl->nht,
135 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -0700136 for (i = 0; i < (1 << nht->hash_shift); i++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700137 struct neighbour *n;
138 struct neighbour __rcu **np;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000140 np = &nht->hash_buckets[i];
Eric Dumazet767e97e2010-10-06 17:49:21 -0700141 while ((n = rcu_dereference_protected(*np,
142 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 /* Neighbour record may be discarded if:
144 * - nobody refers to it.
145 * - it is not permanent
146 */
147 write_lock(&n->lock);
148 if (atomic_read(&n->refcnt) == 1 &&
149 !(n->nud_state & NUD_PERMANENT)) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700150 rcu_assign_pointer(*np,
151 rcu_dereference_protected(n->next,
152 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 n->dead = 1;
154 shrunk = 1;
155 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -0700156 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 continue;
158 }
159 write_unlock(&n->lock);
160 np = &n->next;
161 }
162 }
163
164 tbl->last_flush = jiffies;
165
166 write_unlock_bh(&tbl->lock);
167
168 return shrunk;
169}
170
Pavel Emelyanova43d8992007-12-20 15:49:05 -0800171static void neigh_add_timer(struct neighbour *n, unsigned long when)
172{
173 neigh_hold(n);
174 if (unlikely(mod_timer(&n->timer, when))) {
175 printk("NEIGH: BUG, double timer add, state is %x\n",
176 n->nud_state);
177 dump_stack();
178 }
179}
180
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181static int neigh_del_timer(struct neighbour *n)
182{
183 if ((n->nud_state & NUD_IN_TIMER) &&
184 del_timer(&n->timer)) {
185 neigh_release(n);
186 return 1;
187 }
188 return 0;
189}
190
191static void pneigh_queue_purge(struct sk_buff_head *list)
192{
193 struct sk_buff *skb;
194
195 while ((skb = skb_dequeue(list)) != NULL) {
196 dev_put(skb->dev);
197 kfree_skb(skb);
198 }
199}
200
Herbert Xu49636bb2005-10-23 17:18:00 +1000201static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202{
203 int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000204 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000206 nht = rcu_dereference_protected(tbl->nht,
207 lockdep_is_held(&tbl->lock));
208
David S. Millercd089332011-07-11 01:28:12 -0700209 for (i = 0; i < (1 << nht->hash_shift); i++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700210 struct neighbour *n;
211 struct neighbour __rcu **np = &nht->hash_buckets[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
Eric Dumazet767e97e2010-10-06 17:49:21 -0700213 while ((n = rcu_dereference_protected(*np,
214 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 if (dev && n->dev != dev) {
216 np = &n->next;
217 continue;
218 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700219 rcu_assign_pointer(*np,
220 rcu_dereference_protected(n->next,
221 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 write_lock(&n->lock);
223 neigh_del_timer(n);
224 n->dead = 1;
225
226 if (atomic_read(&n->refcnt) != 1) {
227 /* The most unpleasant situation.
228 We must destroy neighbour entry,
229 but someone still uses it.
230
231 The destroy will be delayed until
232 the last user releases us, but
233 we must kill timers etc. and move
234 it to safe state.
235 */
Eric Dumazetc9ab4d82013-06-28 02:37:42 -0700236 __skb_queue_purge(&n->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000237 n->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 n->output = neigh_blackhole;
239 if (n->nud_state & NUD_VALID)
240 n->nud_state = NUD_NOARP;
241 else
242 n->nud_state = NUD_NONE;
Joe Perchesd5d427c2013-04-15 15:17:19 +0000243 neigh_dbg(2, "neigh %p is stray\n", n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 }
245 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -0700246 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 }
248 }
Herbert Xu49636bb2005-10-23 17:18:00 +1000249}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
Herbert Xu49636bb2005-10-23 17:18:00 +1000251void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
252{
253 write_lock_bh(&tbl->lock);
254 neigh_flush_dev(tbl, dev);
255 write_unlock_bh(&tbl->lock);
256}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900257EXPORT_SYMBOL(neigh_changeaddr);
Herbert Xu49636bb2005-10-23 17:18:00 +1000258
259int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
260{
261 write_lock_bh(&tbl->lock);
262 neigh_flush_dev(tbl, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 pneigh_ifdown(tbl, dev);
264 write_unlock_bh(&tbl->lock);
265
266 del_timer_sync(&tbl->proxy_timer);
267 pneigh_queue_purge(&tbl->proxy_queue);
268 return 0;
269}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900270EXPORT_SYMBOL(neigh_ifdown);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
David Miller596b9b62011-07-25 00:01:25 +0000272static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273{
274 struct neighbour *n = NULL;
275 unsigned long now = jiffies;
276 int entries;
277
278 entries = atomic_inc_return(&tbl->entries) - 1;
279 if (entries >= tbl->gc_thresh3 ||
280 (entries >= tbl->gc_thresh2 &&
281 time_after(now, tbl->last_flush + 5 * HZ))) {
282 if (!neigh_forced_gc(tbl) &&
283 entries >= tbl->gc_thresh3)
284 goto out_entries;
285 }
286
YOSHIFUJI Hideaki / 吉藤英明08433ef2013-01-24 00:44:23 +0000287 n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 if (!n)
289 goto out_entries;
290
Eric Dumazetc9ab4d82013-06-28 02:37:42 -0700291 __skb_queue_head_init(&n->arp_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 rwlock_init(&n->lock);
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +0000293 seqlock_init(&n->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 n->updated = n->used = now;
295 n->nud_state = NUD_NONE;
296 n->output = neigh_blackhole;
David S. Millerf6b72b62011-07-14 07:53:20 -0700297 seqlock_init(&n->hh.hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 n->parms = neigh_parms_clone(&tbl->parms);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800299 setup_timer(&n->timer, neigh_timer_handler, (unsigned long)n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
301 NEIGH_CACHE_STAT_INC(tbl, allocs);
302 n->tbl = tbl;
303 atomic_set(&n->refcnt, 1);
304 n->dead = 1;
305out:
306 return n;
307
308out_entries:
309 atomic_dec(&tbl->entries);
310 goto out;
311}
312
David S. Miller2c2aba62011-12-28 15:06:58 -0500313static void neigh_get_hash_rnd(u32 *x)
314{
315 get_random_bytes(x, sizeof(*x));
316 *x |= 1;
317}
318
David S. Millercd089332011-07-11 01:28:12 -0700319static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320{
David S. Millercd089332011-07-11 01:28:12 -0700321 size_t size = (1 << shift) * sizeof(struct neighbour *);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000322 struct neigh_hash_table *ret;
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000323 struct neighbour __rcu **buckets;
David S. Miller2c2aba62011-12-28 15:06:58 -0500324 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000326 ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
327 if (!ret)
328 return NULL;
329 if (size <= PAGE_SIZE)
330 buckets = kzalloc(size, GFP_ATOMIC);
331 else
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000332 buckets = (struct neighbour __rcu **)
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000333 __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
334 get_order(size));
335 if (!buckets) {
336 kfree(ret);
337 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 }
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000339 ret->hash_buckets = buckets;
David S. Millercd089332011-07-11 01:28:12 -0700340 ret->hash_shift = shift;
David S. Miller2c2aba62011-12-28 15:06:58 -0500341 for (i = 0; i < NEIGH_NUM_HASH_RND; i++)
342 neigh_get_hash_rnd(&ret->hash_rnd[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 return ret;
344}
345
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000346static void neigh_hash_free_rcu(struct rcu_head *head)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347{
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000348 struct neigh_hash_table *nht = container_of(head,
349 struct neigh_hash_table,
350 rcu);
David S. Millercd089332011-07-11 01:28:12 -0700351 size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *);
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000352 struct neighbour __rcu **buckets = nht->hash_buckets;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
354 if (size <= PAGE_SIZE)
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000355 kfree(buckets);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 else
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000357 free_pages((unsigned long)buckets, get_order(size));
358 kfree(nht);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359}
360
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000361static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
David S. Millercd089332011-07-11 01:28:12 -0700362 unsigned long new_shift)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000364 unsigned int i, hash;
365 struct neigh_hash_table *new_nht, *old_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
367 NEIGH_CACHE_STAT_INC(tbl, hash_grows);
368
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000369 old_nht = rcu_dereference_protected(tbl->nht,
370 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -0700371 new_nht = neigh_hash_alloc(new_shift);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000372 if (!new_nht)
373 return old_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
David S. Millercd089332011-07-11 01:28:12 -0700375 for (i = 0; i < (1 << old_nht->hash_shift); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 struct neighbour *n, *next;
377
Eric Dumazet767e97e2010-10-06 17:49:21 -0700378 for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
379 lockdep_is_held(&tbl->lock));
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000380 n != NULL;
381 n = next) {
382 hash = tbl->hash(n->primary_key, n->dev,
383 new_nht->hash_rnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
David S. Millercd089332011-07-11 01:28:12 -0700385 hash >>= (32 - new_nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700386 next = rcu_dereference_protected(n->next,
387 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
Eric Dumazet767e97e2010-10-06 17:49:21 -0700389 rcu_assign_pointer(n->next,
390 rcu_dereference_protected(
391 new_nht->hash_buckets[hash],
392 lockdep_is_held(&tbl->lock)));
393 rcu_assign_pointer(new_nht->hash_buckets[hash], n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 }
395 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000397 rcu_assign_pointer(tbl->nht, new_nht);
398 call_rcu(&old_nht->rcu, neigh_hash_free_rcu);
399 return new_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400}
401
402struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
403 struct net_device *dev)
404{
405 struct neighbour *n;
406 int key_len = tbl->key_len;
Pavel Emelyanovbc4bf5f2008-02-23 19:57:02 -0800407 u32 hash_val;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000408 struct neigh_hash_table *nht;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900409
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 NEIGH_CACHE_STAT_INC(tbl, lookups);
411
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000412 rcu_read_lock_bh();
413 nht = rcu_dereference_bh(tbl->nht);
David S. Millercd089332011-07-11 01:28:12 -0700414 hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700415
416 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
417 n != NULL;
418 n = rcu_dereference_bh(n->next)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700420 if (!atomic_inc_not_zero(&n->refcnt))
421 n = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 NEIGH_CACHE_STAT_INC(tbl, hits);
423 break;
424 }
425 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700426
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000427 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 return n;
429}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900430EXPORT_SYMBOL(neigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431
Eric W. Biederman426b5302008-01-24 00:13:18 -0800432struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
433 const void *pkey)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434{
435 struct neighbour *n;
436 int key_len = tbl->key_len;
Pavel Emelyanovbc4bf5f2008-02-23 19:57:02 -0800437 u32 hash_val;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000438 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
440 NEIGH_CACHE_STAT_INC(tbl, lookups);
441
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000442 rcu_read_lock_bh();
443 nht = rcu_dereference_bh(tbl->nht);
David S. Millercd089332011-07-11 01:28:12 -0700444 hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700445
446 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
447 n != NULL;
448 n = rcu_dereference_bh(n->next)) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800449 if (!memcmp(n->primary_key, pkey, key_len) &&
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +0900450 net_eq(dev_net(n->dev), net)) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700451 if (!atomic_inc_not_zero(&n->refcnt))
452 n = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 NEIGH_CACHE_STAT_INC(tbl, hits);
454 break;
455 }
456 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700457
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000458 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 return n;
460}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900461EXPORT_SYMBOL(neigh_lookup_nodev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462
David S. Millera263b302012-07-02 02:02:15 -0700463struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
464 struct net_device *dev, bool want_ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465{
466 u32 hash_val;
467 int key_len = tbl->key_len;
468 int error;
David Miller596b9b62011-07-25 00:01:25 +0000469 struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000470 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471
472 if (!n) {
473 rc = ERR_PTR(-ENOBUFS);
474 goto out;
475 }
476
477 memcpy(n->primary_key, pkey, key_len);
478 n->dev = dev;
479 dev_hold(dev);
480
481 /* Protocol specific setup. */
482 if (tbl->constructor && (error = tbl->constructor(n)) < 0) {
483 rc = ERR_PTR(error);
484 goto out_neigh_release;
485 }
486
David Millerda6a8fa2011-07-25 00:01:38 +0000487 if (dev->netdev_ops->ndo_neigh_construct) {
488 error = dev->netdev_ops->ndo_neigh_construct(n);
489 if (error < 0) {
490 rc = ERR_PTR(error);
491 goto out_neigh_release;
492 }
493 }
494
David S. Miller447f2192011-12-19 15:04:41 -0500495 /* Device specific setup. */
496 if (n->parms->neigh_setup &&
497 (error = n->parms->neigh_setup(n)) < 0) {
498 rc = ERR_PTR(error);
499 goto out_neigh_release;
500 }
501
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100502 n->confirmed = jiffies - (NEIGH_VAR(n->parms, BASE_REACHABLE_TIME) << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
504 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000505 nht = rcu_dereference_protected(tbl->nht,
506 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
David S. Millercd089332011-07-11 01:28:12 -0700508 if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
509 nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
David S. Millercd089332011-07-11 01:28:12 -0700511 hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
513 if (n->parms->dead) {
514 rc = ERR_PTR(-EINVAL);
515 goto out_tbl_unlock;
516 }
517
Eric Dumazet767e97e2010-10-06 17:49:21 -0700518 for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
519 lockdep_is_held(&tbl->lock));
520 n1 != NULL;
521 n1 = rcu_dereference_protected(n1->next,
522 lockdep_is_held(&tbl->lock))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) {
David S. Millera263b302012-07-02 02:02:15 -0700524 if (want_ref)
525 neigh_hold(n1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 rc = n1;
527 goto out_tbl_unlock;
528 }
529 }
530
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 n->dead = 0;
David S. Millera263b302012-07-02 02:02:15 -0700532 if (want_ref)
533 neigh_hold(n);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700534 rcu_assign_pointer(n->next,
535 rcu_dereference_protected(nht->hash_buckets[hash_val],
536 lockdep_is_held(&tbl->lock)));
537 rcu_assign_pointer(nht->hash_buckets[hash_val], n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 write_unlock_bh(&tbl->lock);
Joe Perchesd5d427c2013-04-15 15:17:19 +0000539 neigh_dbg(2, "neigh %p is created\n", n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 rc = n;
541out:
542 return rc;
543out_tbl_unlock:
544 write_unlock_bh(&tbl->lock);
545out_neigh_release:
546 neigh_release(n);
547 goto out;
548}
David S. Millera263b302012-07-02 02:02:15 -0700549EXPORT_SYMBOL(__neigh_create);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900551static u32 pneigh_hash(const void *pkey, int key_len)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700552{
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700553 u32 hash_val = *(u32 *)(pkey + key_len - 4);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700554 hash_val ^= (hash_val >> 16);
555 hash_val ^= hash_val >> 8;
556 hash_val ^= hash_val >> 4;
557 hash_val &= PNEIGH_HASHMASK;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900558 return hash_val;
559}
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700560
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900561static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
562 struct net *net,
563 const void *pkey,
564 int key_len,
565 struct net_device *dev)
566{
567 while (n) {
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700568 if (!memcmp(n->key, pkey, key_len) &&
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900569 net_eq(pneigh_net(n), net) &&
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700570 (n->dev == dev || !n->dev))
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900571 return n;
572 n = n->next;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700573 }
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900574 return NULL;
575}
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700576
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900577struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
578 struct net *net, const void *pkey, struct net_device *dev)
579{
580 int key_len = tbl->key_len;
581 u32 hash_val = pneigh_hash(pkey, key_len);
582
583 return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
584 net, pkey, key_len, dev);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700585}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900586EXPORT_SYMBOL_GPL(__pneigh_lookup);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700587
Eric W. Biederman426b5302008-01-24 00:13:18 -0800588struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
589 struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 struct net_device *dev, int creat)
591{
592 struct pneigh_entry *n;
593 int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900594 u32 hash_val = pneigh_hash(pkey, key_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
596 read_lock_bh(&tbl->lock);
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900597 n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
598 net, pkey, key_len, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 read_unlock_bh(&tbl->lock);
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900600
601 if (n || !creat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 goto out;
603
Pavel Emelyanov4ae28942007-10-15 12:54:15 -0700604 ASSERT_RTNL();
605
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
607 if (!n)
608 goto out;
609
Eric Dumazete42ea982008-11-12 00:54:54 -0800610 write_pnet(&n->net, hold_net(net));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 memcpy(n->key, pkey, key_len);
612 n->dev = dev;
613 if (dev)
614 dev_hold(dev);
615
616 if (tbl->pconstructor && tbl->pconstructor(n)) {
617 if (dev)
618 dev_put(dev);
Denis V. Lunevda12f732008-02-20 00:26:16 -0800619 release_net(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 kfree(n);
621 n = NULL;
622 goto out;
623 }
624
625 write_lock_bh(&tbl->lock);
626 n->next = tbl->phash_buckets[hash_val];
627 tbl->phash_buckets[hash_val] = n;
628 write_unlock_bh(&tbl->lock);
629out:
630 return n;
631}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900632EXPORT_SYMBOL(pneigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
634
Eric W. Biederman426b5302008-01-24 00:13:18 -0800635int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 struct net_device *dev)
637{
638 struct pneigh_entry *n, **np;
639 int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900640 u32 hash_val = pneigh_hash(pkey, key_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
642 write_lock_bh(&tbl->lock);
643 for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
644 np = &n->next) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800645 if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +0900646 net_eq(pneigh_net(n), net)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 *np = n->next;
648 write_unlock_bh(&tbl->lock);
649 if (tbl->pdestructor)
650 tbl->pdestructor(n);
651 if (n->dev)
652 dev_put(n->dev);
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +0900653 release_net(pneigh_net(n));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 kfree(n);
655 return 0;
656 }
657 }
658 write_unlock_bh(&tbl->lock);
659 return -ENOENT;
660}
661
662static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
663{
664 struct pneigh_entry *n, **np;
665 u32 h;
666
667 for (h = 0; h <= PNEIGH_HASHMASK; h++) {
668 np = &tbl->phash_buckets[h];
669 while ((n = *np) != NULL) {
670 if (!dev || n->dev == dev) {
671 *np = n->next;
672 if (tbl->pdestructor)
673 tbl->pdestructor(n);
674 if (n->dev)
675 dev_put(n->dev);
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +0900676 release_net(pneigh_net(n));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 kfree(n);
678 continue;
679 }
680 np = &n->next;
681 }
682 }
683 return -ENOENT;
684}
685
Denis V. Lunev06f05112008-01-24 00:30:58 -0800686static void neigh_parms_destroy(struct neigh_parms *parms);
687
688static inline void neigh_parms_put(struct neigh_parms *parms)
689{
690 if (atomic_dec_and_test(&parms->refcnt))
691 neigh_parms_destroy(parms);
692}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
694/*
695 * neighbour must already be out of the table;
696 *
697 */
698void neigh_destroy(struct neighbour *neigh)
699{
David Millerda6a8fa2011-07-25 00:01:38 +0000700 struct net_device *dev = neigh->dev;
701
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
703
704 if (!neigh->dead) {
Joe Perchese005d192012-05-16 19:58:40 +0000705 pr_warn("Destroying alive neighbour %p\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 dump_stack();
707 return;
708 }
709
710 if (neigh_del_timer(neigh))
Joe Perchese005d192012-05-16 19:58:40 +0000711 pr_warn("Impossible event\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712
Eric Dumazetc9ab4d82013-06-28 02:37:42 -0700713 write_lock_bh(&neigh->lock);
714 __skb_queue_purge(&neigh->arp_queue);
715 write_unlock_bh(&neigh->lock);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000716 neigh->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717
David S. Miller447f2192011-12-19 15:04:41 -0500718 if (dev->netdev_ops->ndo_neigh_destroy)
719 dev->netdev_ops->ndo_neigh_destroy(neigh);
720
David Millerda6a8fa2011-07-25 00:01:38 +0000721 dev_put(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 neigh_parms_put(neigh->parms);
723
Joe Perchesd5d427c2013-04-15 15:17:19 +0000724 neigh_dbg(2, "neigh %p is destroyed\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 atomic_dec(&neigh->tbl->entries);
David Miller5b8b0062011-07-25 00:01:22 +0000727 kfree_rcu(neigh, rcu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900729EXPORT_SYMBOL(neigh_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730
731/* Neighbour state is suspicious;
732 disable fast path.
733
734 Called with write_locked neigh.
735 */
736static void neigh_suspect(struct neighbour *neigh)
737{
Joe Perchesd5d427c2013-04-15 15:17:19 +0000738 neigh_dbg(2, "neigh %p is suspected\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739
740 neigh->output = neigh->ops->output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741}
742
743/* Neighbour state is OK;
744 enable fast path.
745
746 Called with write_locked neigh.
747 */
748static void neigh_connect(struct neighbour *neigh)
749{
Joe Perchesd5d427c2013-04-15 15:17:19 +0000750 neigh_dbg(2, "neigh %p is connected\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751
752 neigh->output = neigh->ops->connected_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753}
754
Eric Dumazete4c4e442009-07-30 03:15:07 +0000755static void neigh_periodic_work(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756{
Eric Dumazete4c4e442009-07-30 03:15:07 +0000757 struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700758 struct neighbour *n;
759 struct neighbour __rcu **np;
Eric Dumazete4c4e442009-07-30 03:15:07 +0000760 unsigned int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000761 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
763 NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
764
Eric Dumazete4c4e442009-07-30 03:15:07 +0000765 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000766 nht = rcu_dereference_protected(tbl->nht,
767 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768
769 /*
770 * periodically recompute ReachableTime from random function
771 */
772
Eric Dumazete4c4e442009-07-30 03:15:07 +0000773 if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 struct neigh_parms *p;
Eric Dumazete4c4e442009-07-30 03:15:07 +0000775 tbl->last_rand = jiffies;
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +0100776 list_for_each_entry(p, &tbl->parms_list, list)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 p->reachable_time =
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100778 neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 }
780
Duan Jiongfeff9ab2014-02-27 17:14:41 +0800781 if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
782 goto out;
783
David S. Millercd089332011-07-11 01:28:12 -0700784 for (i = 0 ; i < (1 << nht->hash_shift); i++) {
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000785 np = &nht->hash_buckets[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
Eric Dumazet767e97e2010-10-06 17:49:21 -0700787 while ((n = rcu_dereference_protected(*np,
788 lockdep_is_held(&tbl->lock))) != NULL) {
Eric Dumazete4c4e442009-07-30 03:15:07 +0000789 unsigned int state;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
Eric Dumazete4c4e442009-07-30 03:15:07 +0000791 write_lock(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792
Eric Dumazete4c4e442009-07-30 03:15:07 +0000793 state = n->nud_state;
794 if (state & (NUD_PERMANENT | NUD_IN_TIMER)) {
795 write_unlock(&n->lock);
796 goto next_elt;
797 }
798
799 if (time_before(n->used, n->confirmed))
800 n->used = n->confirmed;
801
802 if (atomic_read(&n->refcnt) == 1 &&
803 (state == NUD_FAILED ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100804 time_after(jiffies, n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) {
Eric Dumazete4c4e442009-07-30 03:15:07 +0000805 *np = n->next;
806 n->dead = 1;
807 write_unlock(&n->lock);
808 neigh_cleanup_and_release(n);
809 continue;
810 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 write_unlock(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
813next_elt:
Eric Dumazete4c4e442009-07-30 03:15:07 +0000814 np = &n->next;
815 }
816 /*
817 * It's fine to release lock here, even if hash table
818 * grows while we are preempted.
819 */
820 write_unlock_bh(&tbl->lock);
821 cond_resched();
822 write_lock_bh(&tbl->lock);
Michel Machado84338a62012-02-21 16:04:13 -0500823 nht = rcu_dereference_protected(tbl->nht,
824 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 }
YOSHIFUJI Hideaki / 吉藤英明27246802013-01-22 05:20:05 +0000826out:
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100827 /* Cycle through all hash buckets every BASE_REACHABLE_TIME/2 ticks.
828 * ARP entry timeouts range from 1/2 BASE_REACHABLE_TIME to 3/2
829 * BASE_REACHABLE_TIME.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 */
viresh kumarf6180022014-01-22 12:23:33 +0530831 queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100832 NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME) >> 1);
Eric Dumazete4c4e442009-07-30 03:15:07 +0000833 write_unlock_bh(&tbl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834}
835
836static __inline__ int neigh_max_probes(struct neighbour *n)
837{
838 struct neigh_parms *p = n->parms;
Timo Teräsa960ff82014-02-26 11:43:04 +0200839 int max_probes = NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES);
840 if (!(n->nud_state & NUD_PROBE))
841 max_probes += NEIGH_VAR(p, MCAST_PROBES);
842 return max_probes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843}
844
Timo Teras5ef12d92009-06-11 04:16:28 -0700845static void neigh_invalidate(struct neighbour *neigh)
Eric Dumazet0a141502010-03-09 19:40:54 +0000846 __releases(neigh->lock)
847 __acquires(neigh->lock)
Timo Teras5ef12d92009-06-11 04:16:28 -0700848{
849 struct sk_buff *skb;
850
851 NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
Joe Perchesd5d427c2013-04-15 15:17:19 +0000852 neigh_dbg(2, "neigh %p is failed\n", neigh);
Timo Teras5ef12d92009-06-11 04:16:28 -0700853 neigh->updated = jiffies;
854
855 /* It is very thin place. report_unreachable is very complicated
856 routine. Particularly, it can hit the same neighbour entry!
857
858 So that, we try to be accurate and avoid dead loop. --ANK
859 */
860 while (neigh->nud_state == NUD_FAILED &&
861 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
862 write_unlock(&neigh->lock);
863 neigh->ops->error_report(neigh, skb);
864 write_lock(&neigh->lock);
865 }
Eric Dumazetc9ab4d82013-06-28 02:37:42 -0700866 __skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000867 neigh->arp_queue_len_bytes = 0;
Timo Teras5ef12d92009-06-11 04:16:28 -0700868}
869
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000870static void neigh_probe(struct neighbour *neigh)
871 __releases(neigh->lock)
872{
Hannes Frederic Sowa4ed377e2013-09-21 06:32:34 +0200873 struct sk_buff *skb = skb_peek_tail(&neigh->arp_queue);
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000874 /* keep skb alive even if arp_queue overflows */
875 if (skb)
876 skb = skb_copy(skb, GFP_ATOMIC);
877 write_unlock(&neigh->lock);
878 neigh->ops->solicit(neigh, skb);
879 atomic_inc(&neigh->probes);
880 kfree_skb(skb);
881}
882
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883/* Called when a timer expires for a neighbour entry. */
884
885static void neigh_timer_handler(unsigned long arg)
886{
887 unsigned long now, next;
888 struct neighbour *neigh = (struct neighbour *)arg;
Eric Dumazet95c96172012-04-15 05:58:06 +0000889 unsigned int state;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 int notify = 0;
891
892 write_lock(&neigh->lock);
893
894 state = neigh->nud_state;
895 now = jiffies;
896 next = now + HZ;
897
David S. Miller045f7b32011-11-01 17:45:55 -0400898 if (!(state & NUD_IN_TIMER))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900
901 if (state & NUD_REACHABLE) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900902 if (time_before_eq(now,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 neigh->confirmed + neigh->parms->reachable_time)) {
Joe Perchesd5d427c2013-04-15 15:17:19 +0000904 neigh_dbg(2, "neigh %p is still alive\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 next = neigh->confirmed + neigh->parms->reachable_time;
906 } else if (time_before_eq(now,
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100907 neigh->used +
908 NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
Joe Perchesd5d427c2013-04-15 15:17:19 +0000909 neigh_dbg(2, "neigh %p is delayed\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800911 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 neigh_suspect(neigh);
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100913 next = now + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 } else {
Joe Perchesd5d427c2013-04-15 15:17:19 +0000915 neigh_dbg(2, "neigh %p is suspected\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 neigh->nud_state = NUD_STALE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800917 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 neigh_suspect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -0700919 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 }
921 } else if (state & NUD_DELAY) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900922 if (time_before_eq(now,
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100923 neigh->confirmed +
924 NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
Joe Perchesd5d427c2013-04-15 15:17:19 +0000925 neigh_dbg(2, "neigh %p is now reachable\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 neigh->nud_state = NUD_REACHABLE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800927 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 neigh_connect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -0700929 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 next = neigh->confirmed + neigh->parms->reachable_time;
931 } else {
Joe Perchesd5d427c2013-04-15 15:17:19 +0000932 neigh_dbg(2, "neigh %p is probed\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 neigh->nud_state = NUD_PROBE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800934 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 atomic_set(&neigh->probes, 0);
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100936 next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 }
938 } else {
939 /* NUD_PROBE|NUD_INCOMPLETE */
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100940 next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 }
942
943 if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
944 atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 neigh->nud_state = NUD_FAILED;
946 notify = 1;
Timo Teras5ef12d92009-06-11 04:16:28 -0700947 neigh_invalidate(neigh);
Duan Jiong5e2c21d2014-02-27 17:03:03 +0800948 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 }
950
951 if (neigh->nud_state & NUD_IN_TIMER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 if (time_before(next, jiffies + HZ/2))
953 next = jiffies + HZ/2;
Herbert Xu6fb99742005-10-23 16:37:48 +1000954 if (!mod_timer(&neigh->timer, next))
955 neigh_hold(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 }
957 if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000958 neigh_probe(neigh);
David S. Miller9ff56602008-02-17 18:39:54 -0800959 } else {
David S. Miller69cc64d2008-02-11 21:45:44 -0800960out:
David S. Miller9ff56602008-02-17 18:39:54 -0800961 write_unlock(&neigh->lock);
962 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963
Thomas Grafd961db32007-08-08 23:12:56 -0700964 if (notify)
965 neigh_update_notify(neigh);
966
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 neigh_release(neigh);
968}
969
970int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
971{
972 int rc;
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000973 bool immediate_probe = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
975 write_lock_bh(&neigh->lock);
976
977 rc = 0;
978 if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
979 goto out_unlock_bh;
980
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100982 if (NEIGH_VAR(neigh->parms, MCAST_PROBES) +
983 NEIGH_VAR(neigh->parms, APP_PROBES)) {
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000984 unsigned long next, now = jiffies;
985
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100986 atomic_set(&neigh->probes,
987 NEIGH_VAR(neigh->parms, UCAST_PROBES));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 neigh->nud_state = NUD_INCOMPLETE;
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000989 neigh->updated = now;
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100990 next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
991 HZ/2);
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000992 neigh_add_timer(neigh, next);
993 immediate_probe = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 } else {
995 neigh->nud_state = NUD_FAILED;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800996 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 write_unlock_bh(&neigh->lock);
998
Wei Yongjunf3fbbe02009-02-25 00:37:32 +0000999 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 return 1;
1001 }
1002 } else if (neigh->nud_state & NUD_STALE) {
Joe Perchesd5d427c2013-04-15 15:17:19 +00001003 neigh_dbg(2, "neigh %p is delayed\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001005 neigh->updated = jiffies;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001006 neigh_add_timer(neigh, jiffies +
1007 NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 }
1009
1010 if (neigh->nud_state == NUD_INCOMPLETE) {
1011 if (skb) {
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001012 while (neigh->arp_queue_len_bytes + skb->truesize >
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001013 NEIGH_VAR(neigh->parms, QUEUE_LEN_BYTES)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 struct sk_buff *buff;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001015
David S. Millerf72051b2008-09-23 01:11:18 -07001016 buff = __skb_dequeue(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001017 if (!buff)
1018 break;
1019 neigh->arp_queue_len_bytes -= buff->truesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 kfree_skb(buff);
Neil Horman9a6d2762008-07-16 20:50:49 -07001021 NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 }
Eric Dumazeta4731132010-05-27 16:09:39 -07001023 skb_dst_force(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 __skb_queue_tail(&neigh->arp_queue, skb);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001025 neigh->arp_queue_len_bytes += skb->truesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 }
1027 rc = 1;
1028 }
1029out_unlock_bh:
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001030 if (immediate_probe)
1031 neigh_probe(neigh);
1032 else
1033 write_unlock(&neigh->lock);
1034 local_bh_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 return rc;
1036}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001037EXPORT_SYMBOL(__neigh_event_send);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038
David S. Millerf6b72b62011-07-14 07:53:20 -07001039static void neigh_update_hhs(struct neighbour *neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040{
1041 struct hh_cache *hh;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001042 void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
Doug Kehn91a72a72010-07-14 18:02:16 -07001043 = NULL;
1044
1045 if (neigh->dev->header_ops)
1046 update = neigh->dev->header_ops->cache_update;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047
1048 if (update) {
David S. Millerf6b72b62011-07-14 07:53:20 -07001049 hh = &neigh->hh;
1050 if (hh->hh_len) {
Stephen Hemminger3644f0c2006-12-07 15:08:17 -08001051 write_seqlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 update(hh, neigh->dev, neigh->ha);
Stephen Hemminger3644f0c2006-12-07 15:08:17 -08001053 write_sequnlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 }
1055 }
1056}
1057
1058
1059
1060/* Generic update routine.
1061 -- lladdr is new lladdr or NULL, if it is not supplied.
1062 -- new is new state.
1063 -- flags
1064 NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr,
1065 if it is different.
1066 NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected"
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001067 lladdr instead of overriding it
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 if it is different.
1069 It also allows to retain current state
1070 if lladdr is unchanged.
1071 NEIGH_UPDATE_F_ADMIN means that the change is administrative.
1072
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001073 NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 NTF_ROUTER flag.
1075 NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as
1076 a router.
1077
1078 Caller MUST hold reference count on the entry.
1079 */
1080
1081int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
1082 u32 flags)
1083{
1084 u8 old;
1085 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 int notify = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 struct net_device *dev;
1088 int update_isrouter = 0;
1089
1090 write_lock_bh(&neigh->lock);
1091
1092 dev = neigh->dev;
1093 old = neigh->nud_state;
1094 err = -EPERM;
1095
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001096 if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 (old & (NUD_NOARP | NUD_PERMANENT)))
1098 goto out;
1099
1100 if (!(new & NUD_VALID)) {
1101 neigh_del_timer(neigh);
1102 if (old & NUD_CONNECTED)
1103 neigh_suspect(neigh);
1104 neigh->nud_state = new;
1105 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 notify = old & NUD_VALID;
Timo Teras5ef12d92009-06-11 04:16:28 -07001107 if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
1108 (new & NUD_FAILED)) {
1109 neigh_invalidate(neigh);
1110 notify = 1;
1111 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 goto out;
1113 }
1114
1115 /* Compare new lladdr with cached one */
1116 if (!dev->addr_len) {
1117 /* First case: device needs no address. */
1118 lladdr = neigh->ha;
1119 } else if (lladdr) {
1120 /* The second case: if something is already cached
1121 and a new address is proposed:
1122 - compare new & old
1123 - if they are different, check override flag
1124 */
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001125 if ((old & NUD_VALID) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 !memcmp(lladdr, neigh->ha, dev->addr_len))
1127 lladdr = neigh->ha;
1128 } else {
1129 /* No address is supplied; if we know something,
1130 use it, otherwise discard the request.
1131 */
1132 err = -EINVAL;
1133 if (!(old & NUD_VALID))
1134 goto out;
1135 lladdr = neigh->ha;
1136 }
1137
1138 if (new & NUD_CONNECTED)
1139 neigh->confirmed = jiffies;
1140 neigh->updated = jiffies;
1141
1142 /* If entry was valid and address is not changed,
1143 do not change entry state, if new one is STALE.
1144 */
1145 err = 0;
1146 update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
1147 if (old & NUD_VALID) {
1148 if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {
1149 update_isrouter = 0;
1150 if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&
1151 (old & NUD_CONNECTED)) {
1152 lladdr = neigh->ha;
1153 new = NUD_STALE;
1154 } else
1155 goto out;
1156 } else {
1157 if (lladdr == neigh->ha && new == NUD_STALE &&
1158 ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) ||
1159 (old & NUD_CONNECTED))
1160 )
1161 new = old;
1162 }
1163 }
1164
1165 if (new != old) {
1166 neigh_del_timer(neigh);
Pavel Emelyanova43d8992007-12-20 15:49:05 -08001167 if (new & NUD_IN_TIMER)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001168 neigh_add_timer(neigh, (jiffies +
1169 ((new & NUD_REACHABLE) ?
David S. Miller667347f2005-09-27 12:07:44 -07001170 neigh->parms->reachable_time :
1171 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 neigh->nud_state = new;
Bob Gilligan53385d22013-12-15 13:39:56 -08001173 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 }
1175
1176 if (lladdr != neigh->ha) {
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001177 write_seqlock(&neigh->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 memcpy(&neigh->ha, lladdr, dev->addr_len);
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001179 write_sequnlock(&neigh->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 neigh_update_hhs(neigh);
1181 if (!(new & NUD_CONNECTED))
1182 neigh->confirmed = jiffies -
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001183 (NEIGH_VAR(neigh->parms, BASE_REACHABLE_TIME) << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 }
1186 if (new == old)
1187 goto out;
1188 if (new & NUD_CONNECTED)
1189 neigh_connect(neigh);
1190 else
1191 neigh_suspect(neigh);
1192 if (!(old & NUD_VALID)) {
1193 struct sk_buff *skb;
1194
1195 /* Again: avoid dead loop if something went wrong */
1196
1197 while (neigh->nud_state & NUD_VALID &&
1198 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
David S. Miller69cce1d2011-07-17 23:09:49 -07001199 struct dst_entry *dst = skb_dst(skb);
1200 struct neighbour *n2, *n1 = neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 write_unlock_bh(&neigh->lock);
roy.qing.li@gmail.come049f282011-10-17 22:32:42 +00001202
1203 rcu_read_lock();
David S. Miller13a43d92012-07-02 22:15:37 -07001204
1205 /* Why not just use 'neigh' as-is? The problem is that
1206 * things such as shaper, eql, and sch_teql can end up
1207 * using alternative, different, neigh objects to output
1208 * the packet in the output path. So what we need to do
1209 * here is re-lookup the top-level neigh in the path so
1210 * we can reinject the packet there.
1211 */
1212 n2 = NULL;
1213 if (dst) {
1214 n2 = dst_neigh_lookup_skb(dst, skb);
1215 if (n2)
1216 n1 = n2;
1217 }
David S. Miller8f40b162011-07-17 13:34:11 -07001218 n1->output(n1, skb);
David S. Miller13a43d92012-07-02 22:15:37 -07001219 if (n2)
1220 neigh_release(n2);
roy.qing.li@gmail.come049f282011-10-17 22:32:42 +00001221 rcu_read_unlock();
1222
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 write_lock_bh(&neigh->lock);
1224 }
Eric Dumazetc9ab4d82013-06-28 02:37:42 -07001225 __skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001226 neigh->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 }
1228out:
1229 if (update_isrouter) {
1230 neigh->flags = (flags & NEIGH_UPDATE_F_ISROUTER) ?
1231 (neigh->flags | NTF_ROUTER) :
1232 (neigh->flags & ~NTF_ROUTER);
1233 }
1234 write_unlock_bh(&neigh->lock);
Tom Tucker8d717402006-07-30 20:43:36 -07001235
1236 if (notify)
Thomas Grafd961db32007-08-08 23:12:56 -07001237 neigh_update_notify(neigh);
1238
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 return err;
1240}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001241EXPORT_SYMBOL(neigh_update);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242
Jiri Benc7e980562013-12-11 13:48:20 +01001243/* Update the neigh to listen temporarily for probe responses, even if it is
1244 * in a NUD_FAILED state. The caller has to hold neigh->lock for writing.
1245 */
1246void __neigh_set_probe_once(struct neighbour *neigh)
1247{
1248 neigh->updated = jiffies;
1249 if (!(neigh->nud_state & NUD_FAILED))
1250 return;
Duan Jiong2176d5d2014-05-09 13:16:48 +08001251 neigh->nud_state = NUD_INCOMPLETE;
1252 atomic_set(&neigh->probes, neigh_max_probes(neigh));
Jiri Benc7e980562013-12-11 13:48:20 +01001253 neigh_add_timer(neigh,
1254 jiffies + NEIGH_VAR(neigh->parms, RETRANS_TIME));
1255}
1256EXPORT_SYMBOL(__neigh_set_probe_once);
1257
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258struct neighbour *neigh_event_ns(struct neigh_table *tbl,
1259 u8 *lladdr, void *saddr,
1260 struct net_device *dev)
1261{
1262 struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
1263 lladdr || !dev->addr_len);
1264 if (neigh)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001265 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 NEIGH_UPDATE_F_OVERRIDE);
1267 return neigh;
1268}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001269EXPORT_SYMBOL(neigh_event_ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270
Eric Dumazet34d101d2010-10-11 09:16:57 -07001271/* called with read_lock_bh(&n->lock); */
David S. Millerf6b72b62011-07-14 07:53:20 -07001272static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 struct net_device *dev = dst->dev;
David S. Millerf6b72b62011-07-14 07:53:20 -07001275 __be16 prot = dst->ops->protocol;
1276 struct hh_cache *hh = &n->hh;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001277
1278 write_lock_bh(&n->lock);
Eric Dumazet34d101d2010-10-11 09:16:57 -07001279
David S. Millerf6b72b62011-07-14 07:53:20 -07001280 /* Only one thread can come in here and initialize the
1281 * hh_cache entry.
1282 */
David S. Millerb23b5452011-07-16 17:45:02 -07001283 if (!hh->hh_len)
1284 dev->header_ops->cache(n, hh, prot);
David S. Millerf6b72b62011-07-14 07:53:20 -07001285
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001286 write_unlock_bh(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287}
1288
1289/* This function can be used in contexts, where only old dev_queue_xmit
Eric Dumazet767e97e2010-10-06 17:49:21 -07001290 * worked, f.e. if you want to override normal output path (eql, shaper),
1291 * but resolution is not made yet.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 */
1293
David S. Miller8f40b162011-07-17 13:34:11 -07001294int neigh_compat_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295{
1296 struct net_device *dev = skb->dev;
1297
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03001298 __skb_pull(skb, skb_network_offset(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
Stephen Hemminger0c4e8582007-10-09 01:36:32 -07001300 if (dev_hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL,
1301 skb->len) < 0 &&
David S. Miller22053692013-12-31 16:23:35 -05001302 dev_rebuild_header(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 return 0;
1304
1305 return dev_queue_xmit(skb);
1306}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001307EXPORT_SYMBOL(neigh_compat_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308
1309/* Slow and careful. */
1310
David S. Miller8f40b162011-07-17 13:34:11 -07001311int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312{
Eric Dumazetadf30902009-06-02 05:19:30 +00001313 struct dst_entry *dst = skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 int rc = 0;
1315
David S. Miller8f40b162011-07-17 13:34:11 -07001316 if (!dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 goto discard;
1318
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 if (!neigh_event_send(neigh, skb)) {
1320 int err;
1321 struct net_device *dev = neigh->dev;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001322 unsigned int seq;
Eric Dumazet34d101d2010-10-11 09:16:57 -07001323
David S. Millerf6b72b62011-07-14 07:53:20 -07001324 if (dev->header_ops->cache && !neigh->hh.hh_len)
1325 neigh_hh_init(neigh, dst);
Eric Dumazet34d101d2010-10-11 09:16:57 -07001326
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001327 do {
ramesh.nagappa@gmail.come1f16502012-10-05 19:10:15 +00001328 __skb_pull(skb, skb_network_offset(skb));
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001329 seq = read_seqbegin(&neigh->ha_lock);
1330 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1331 neigh->ha, NULL, skb->len);
1332 } while (read_seqretry(&neigh->ha_lock, seq));
Eric Dumazet34d101d2010-10-11 09:16:57 -07001333
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 if (err >= 0)
David S. Miller542d4d62011-07-16 18:06:24 -07001335 rc = dev_queue_xmit(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 else
1337 goto out_kfree_skb;
1338 }
1339out:
1340 return rc;
1341discard:
Joe Perchesd5d427c2013-04-15 15:17:19 +00001342 neigh_dbg(1, "%s: dst=%p neigh=%p\n", __func__, dst, neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343out_kfree_skb:
1344 rc = -EINVAL;
1345 kfree_skb(skb);
1346 goto out;
1347}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001348EXPORT_SYMBOL(neigh_resolve_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349
1350/* As fast as possible without hh cache */
1351
David S. Miller8f40b162011-07-17 13:34:11 -07001352int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 struct net_device *dev = neigh->dev;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001355 unsigned int seq;
David S. Miller8f40b162011-07-17 13:34:11 -07001356 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001358 do {
ramesh.nagappa@gmail.come1f16502012-10-05 19:10:15 +00001359 __skb_pull(skb, skb_network_offset(skb));
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001360 seq = read_seqbegin(&neigh->ha_lock);
1361 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1362 neigh->ha, NULL, skb->len);
1363 } while (read_seqretry(&neigh->ha_lock, seq));
1364
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 if (err >= 0)
David S. Miller542d4d62011-07-16 18:06:24 -07001366 err = dev_queue_xmit(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 else {
1368 err = -EINVAL;
1369 kfree_skb(skb);
1370 }
1371 return err;
1372}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001373EXPORT_SYMBOL(neigh_connected_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374
David S. Miller8f40b162011-07-17 13:34:11 -07001375int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
1376{
1377 return dev_queue_xmit(skb);
1378}
1379EXPORT_SYMBOL(neigh_direct_output);
1380
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381static void neigh_proxy_process(unsigned long arg)
1382{
1383 struct neigh_table *tbl = (struct neigh_table *)arg;
1384 long sched_next = 0;
1385 unsigned long now = jiffies;
David S. Millerf72051b2008-09-23 01:11:18 -07001386 struct sk_buff *skb, *n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
1388 spin_lock(&tbl->proxy_queue.lock);
1389
David S. Millerf72051b2008-09-23 01:11:18 -07001390 skb_queue_walk_safe(&tbl->proxy_queue, skb, n) {
1391 long tdif = NEIGH_CB(skb)->sched_next - now;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 if (tdif <= 0) {
David S. Millerf72051b2008-09-23 01:11:18 -07001394 struct net_device *dev = skb->dev;
Eric Dumazet20e60742011-08-22 19:32:42 +00001395
David S. Millerf72051b2008-09-23 01:11:18 -07001396 __skb_unlink(skb, &tbl->proxy_queue);
Eric Dumazet20e60742011-08-22 19:32:42 +00001397 if (tbl->proxy_redo && netif_running(dev)) {
1398 rcu_read_lock();
David S. Millerf72051b2008-09-23 01:11:18 -07001399 tbl->proxy_redo(skb);
Eric Dumazet20e60742011-08-22 19:32:42 +00001400 rcu_read_unlock();
1401 } else {
David S. Millerf72051b2008-09-23 01:11:18 -07001402 kfree_skb(skb);
Eric Dumazet20e60742011-08-22 19:32:42 +00001403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404
1405 dev_put(dev);
1406 } else if (!sched_next || tdif < sched_next)
1407 sched_next = tdif;
1408 }
1409 del_timer(&tbl->proxy_timer);
1410 if (sched_next)
1411 mod_timer(&tbl->proxy_timer, jiffies + sched_next);
1412 spin_unlock(&tbl->proxy_queue.lock);
1413}
1414
1415void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
1416 struct sk_buff *skb)
1417{
1418 unsigned long now = jiffies;
Aruna-Hewapathirane63862b52014-01-11 07:15:59 -05001419
1420 unsigned long sched_next = now + (prandom_u32() %
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001421 NEIGH_VAR(p, PROXY_DELAY));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001423 if (tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 kfree_skb(skb);
1425 return;
1426 }
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001427
1428 NEIGH_CB(skb)->sched_next = sched_next;
1429 NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430
1431 spin_lock(&tbl->proxy_queue.lock);
1432 if (del_timer(&tbl->proxy_timer)) {
1433 if (time_before(tbl->proxy_timer.expires, sched_next))
1434 sched_next = tbl->proxy_timer.expires;
1435 }
Eric Dumazetadf30902009-06-02 05:19:30 +00001436 skb_dst_drop(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 dev_hold(skb->dev);
1438 __skb_queue_tail(&tbl->proxy_queue, skb);
1439 mod_timer(&tbl->proxy_timer, sched_next);
1440 spin_unlock(&tbl->proxy_queue.lock);
1441}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001442EXPORT_SYMBOL(pneigh_enqueue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07001444static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
Eric W. Biederman426b5302008-01-24 00:13:18 -08001445 struct net *net, int ifindex)
1446{
1447 struct neigh_parms *p;
1448
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001449 list_for_each_entry(p, &tbl->parms_list, list) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09001450 if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
Gao feng170d6f92013-06-20 10:01:33 +08001451 (!p->dev && !ifindex && net_eq(net, &init_net)))
Eric W. Biederman426b5302008-01-24 00:13:18 -08001452 return p;
1453 }
1454
1455 return NULL;
1456}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457
1458struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
1459 struct neigh_table *tbl)
1460{
Gao fengcf89d6b2013-06-20 10:01:32 +08001461 struct neigh_parms *p;
Stephen Hemminger00829822008-11-20 20:14:53 -08001462 struct net *net = dev_net(dev);
1463 const struct net_device_ops *ops = dev->netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464
Gao fengcf89d6b2013-06-20 10:01:32 +08001465 p = kmemdup(&tbl->parms, sizeof(*p), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 if (p) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 p->tbl = tbl;
1468 atomic_set(&p->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 p->reachable_time =
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001470 neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
Denis V. Lunev486b51d2008-01-14 22:59:59 -08001471 dev_hold(dev);
1472 p->dev = dev;
Eric Dumazete42ea982008-11-12 00:54:54 -08001473 write_pnet(&p->net, hold_net(net));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 p->sysctl_table = NULL;
Veaceslav Falico63134802013-08-02 19:07:38 +02001475
1476 if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
1477 release_net(net);
1478 dev_put(dev);
1479 kfree(p);
1480 return NULL;
1481 }
1482
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 write_lock_bh(&tbl->lock);
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001484 list_add(&p->list, &tbl->parms.list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 write_unlock_bh(&tbl->lock);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01001486
1487 neigh_parms_data_state_cleanall(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 }
1489 return p;
1490}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001491EXPORT_SYMBOL(neigh_parms_alloc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492
1493static void neigh_rcu_free_parms(struct rcu_head *head)
1494{
1495 struct neigh_parms *parms =
1496 container_of(head, struct neigh_parms, rcu_head);
1497
1498 neigh_parms_put(parms);
1499}
1500
1501void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
1502{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 if (!parms || parms == &tbl->parms)
1504 return;
1505 write_lock_bh(&tbl->lock);
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001506 list_del(&parms->list);
1507 parms->dead = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 write_unlock_bh(&tbl->lock);
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001509 if (parms->dev)
1510 dev_put(parms->dev);
1511 call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001513EXPORT_SYMBOL(neigh_parms_release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514
Denis V. Lunev06f05112008-01-24 00:30:58 -08001515static void neigh_parms_destroy(struct neigh_parms *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516{
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +09001517 release_net(neigh_parms_net(parms));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 kfree(parms);
1519}
1520
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001521static struct lock_class_key neigh_table_proxy_queue_class;
1522
Hiroaki SHIMODAdcd2ba92012-04-13 07:34:44 +00001523static void neigh_table_init_no_netlink(struct neigh_table *tbl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524{
1525 unsigned long now = jiffies;
1526 unsigned long phsize;
1527
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001528 INIT_LIST_HEAD(&tbl->parms_list);
1529 list_add(&tbl->parms.list, &tbl->parms_list);
Eric Dumazete42ea982008-11-12 00:54:54 -08001530 write_pnet(&tbl->parms.net, &init_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 atomic_set(&tbl->parms.refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 tbl->parms.reachable_time =
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001533 neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 tbl->stats = alloc_percpu(struct neigh_statistics);
1536 if (!tbl->stats)
1537 panic("cannot create neighbour cache statistics");
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001538
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539#ifdef CONFIG_PROC_FS
Alexey Dobriyan9b739ba2008-11-11 16:47:44 -08001540 if (!proc_create_data(tbl->id, 0, init_net.proc_net_stat,
1541 &neigh_stat_seq_fops, tbl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 panic("cannot create neighbour proc dir entry");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543#endif
1544
David S. Millercd089332011-07-11 01:28:12 -07001545 RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546
1547 phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
Andrew Morton77d04bd2006-04-07 14:52:59 -07001548 tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001550 if (!tbl->nht || !tbl->phash_buckets)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 panic("cannot allocate neighbour cache hashes");
1552
YOSHIFUJI Hideaki / 吉藤英明08433ef2013-01-24 00:44:23 +00001553 if (!tbl->entry_size)
1554 tbl->entry_size = ALIGN(offsetof(struct neighbour, primary_key) +
1555 tbl->key_len, NEIGH_PRIV_ALIGN);
1556 else
1557 WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN);
1558
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 rwlock_init(&tbl->lock);
Tejun Heo203b42f2012-08-21 13:18:23 -07001560 INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work);
viresh kumarf6180022014-01-22 12:23:33 +05301561 queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
1562 tbl->parms.reachable_time);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -08001563 setup_timer(&tbl->proxy_timer, neigh_proxy_process, (unsigned long)tbl);
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001564 skb_queue_head_init_class(&tbl->proxy_queue,
1565 &neigh_table_proxy_queue_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566
1567 tbl->last_flush = now;
1568 tbl->last_rand = now + tbl->parms.reachable_time * 20;
Simon Kelleybd89efc2006-05-12 14:56:08 -07001569}
1570
1571void neigh_table_init(struct neigh_table *tbl)
1572{
1573 struct neigh_table *tmp;
1574
1575 neigh_table_init_no_netlink(tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 write_lock(&neigh_tbl_lock);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001577 for (tmp = neigh_tables; tmp; tmp = tmp->next) {
1578 if (tmp->family == tbl->family)
1579 break;
1580 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 tbl->next = neigh_tables;
1582 neigh_tables = tbl;
1583 write_unlock(&neigh_tbl_lock);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001584
1585 if (unlikely(tmp)) {
Joe Perchese005d192012-05-16 19:58:40 +00001586 pr_err("Registering multiple tables for family %d\n",
1587 tbl->family);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001588 dump_stack();
1589 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001591EXPORT_SYMBOL(neigh_table_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592
1593int neigh_table_clear(struct neigh_table *tbl)
1594{
1595 struct neigh_table **tp;
1596
1597 /* It is not clean... Fix it to unload IPv6 module safely */
Tejun Heoa5c30b32010-10-19 06:04:42 +00001598 cancel_delayed_work_sync(&tbl->gc_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 del_timer_sync(&tbl->proxy_timer);
1600 pneigh_queue_purge(&tbl->proxy_queue);
1601 neigh_ifdown(tbl, NULL);
1602 if (atomic_read(&tbl->entries))
Joe Perchese005d192012-05-16 19:58:40 +00001603 pr_crit("neighbour leakage\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 write_lock(&neigh_tbl_lock);
1605 for (tp = &neigh_tables; *tp; tp = &(*tp)->next) {
1606 if (*tp == tbl) {
1607 *tp = tbl->next;
1608 break;
1609 }
1610 }
1611 write_unlock(&neigh_tbl_lock);
1612
Eric Dumazet6193d2b2011-01-19 22:02:47 +00001613 call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
1614 neigh_hash_free_rcu);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001615 tbl->nht = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616
1617 kfree(tbl->phash_buckets);
1618 tbl->phash_buckets = NULL;
1619
Alexey Dobriyan3f192b52007-11-05 21:28:13 -08001620 remove_proc_entry(tbl->id, init_net.proc_net_stat);
1621
Kirill Korotaev3fcde742006-09-01 01:34:10 -07001622 free_percpu(tbl->stats);
1623 tbl->stats = NULL;
1624
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 return 0;
1626}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001627EXPORT_SYMBOL(neigh_table_clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628
Thomas Graf661d2962013-03-21 07:45:29 +00001629static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001631 struct net *net = sock_net(skb->sk);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001632 struct ndmsg *ndm;
1633 struct nlattr *dst_attr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 struct neigh_table *tbl;
1635 struct net_device *dev = NULL;
Thomas Grafa14a49d2006-08-07 17:53:08 -07001636 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637
Eric Dumazet110b2492010-10-04 04:27:36 +00001638 ASSERT_RTNL();
Thomas Grafa14a49d2006-08-07 17:53:08 -07001639 if (nlmsg_len(nlh) < sizeof(*ndm))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 goto out;
1641
Thomas Grafa14a49d2006-08-07 17:53:08 -07001642 dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
1643 if (dst_attr == NULL)
1644 goto out;
1645
1646 ndm = nlmsg_data(nlh);
1647 if (ndm->ndm_ifindex) {
Eric Dumazet110b2492010-10-04 04:27:36 +00001648 dev = __dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001649 if (dev == NULL) {
1650 err = -ENODEV;
1651 goto out;
1652 }
1653 }
1654
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 read_lock(&neigh_tbl_lock);
1656 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
Thomas Grafa14a49d2006-08-07 17:53:08 -07001657 struct neighbour *neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658
1659 if (tbl->family != ndm->ndm_family)
1660 continue;
1661 read_unlock(&neigh_tbl_lock);
1662
Thomas Grafa14a49d2006-08-07 17:53:08 -07001663 if (nla_len(dst_attr) < tbl->key_len)
Eric Dumazet110b2492010-10-04 04:27:36 +00001664 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665
1666 if (ndm->ndm_flags & NTF_PROXY) {
Eric W. Biederman426b5302008-01-24 00:13:18 -08001667 err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
Eric Dumazet110b2492010-10-04 04:27:36 +00001668 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 }
1670
Thomas Grafa14a49d2006-08-07 17:53:08 -07001671 if (dev == NULL)
Eric Dumazet110b2492010-10-04 04:27:36 +00001672 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673
Thomas Grafa14a49d2006-08-07 17:53:08 -07001674 neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
1675 if (neigh == NULL) {
1676 err = -ENOENT;
Eric Dumazet110b2492010-10-04 04:27:36 +00001677 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 }
Thomas Grafa14a49d2006-08-07 17:53:08 -07001679
1680 err = neigh_update(neigh, NULL, NUD_FAILED,
1681 NEIGH_UPDATE_F_OVERRIDE |
1682 NEIGH_UPDATE_F_ADMIN);
1683 neigh_release(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001684 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 }
1686 read_unlock(&neigh_tbl_lock);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001687 err = -EAFNOSUPPORT;
1688
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689out:
1690 return err;
1691}
1692
Thomas Graf661d2962013-03-21 07:45:29 +00001693static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001695 struct net *net = sock_net(skb->sk);
Thomas Graf5208deb2006-08-07 17:55:40 -07001696 struct ndmsg *ndm;
1697 struct nlattr *tb[NDA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 struct neigh_table *tbl;
1699 struct net_device *dev = NULL;
Thomas Graf5208deb2006-08-07 17:55:40 -07001700 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701
Eric Dumazet110b2492010-10-04 04:27:36 +00001702 ASSERT_RTNL();
Thomas Graf5208deb2006-08-07 17:55:40 -07001703 err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
1704 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 goto out;
1706
Thomas Graf5208deb2006-08-07 17:55:40 -07001707 err = -EINVAL;
1708 if (tb[NDA_DST] == NULL)
1709 goto out;
1710
1711 ndm = nlmsg_data(nlh);
1712 if (ndm->ndm_ifindex) {
Eric Dumazet110b2492010-10-04 04:27:36 +00001713 dev = __dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Graf5208deb2006-08-07 17:55:40 -07001714 if (dev == NULL) {
1715 err = -ENODEV;
1716 goto out;
1717 }
1718
1719 if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len)
Eric Dumazet110b2492010-10-04 04:27:36 +00001720 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001721 }
1722
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 read_lock(&neigh_tbl_lock);
1724 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
Thomas Graf5208deb2006-08-07 17:55:40 -07001725 int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE;
1726 struct neighbour *neigh;
1727 void *dst, *lladdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728
1729 if (tbl->family != ndm->ndm_family)
1730 continue;
1731 read_unlock(&neigh_tbl_lock);
1732
Thomas Graf5208deb2006-08-07 17:55:40 -07001733 if (nla_len(tb[NDA_DST]) < tbl->key_len)
Eric Dumazet110b2492010-10-04 04:27:36 +00001734 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001735 dst = nla_data(tb[NDA_DST]);
1736 lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737
1738 if (ndm->ndm_flags & NTF_PROXY) {
Ville Nuorvala62dd9312006-09-22 14:43:19 -07001739 struct pneigh_entry *pn;
1740
1741 err = -ENOBUFS;
Eric W. Biederman426b5302008-01-24 00:13:18 -08001742 pn = pneigh_lookup(tbl, net, dst, dev, 1);
Ville Nuorvala62dd9312006-09-22 14:43:19 -07001743 if (pn) {
1744 pn->flags = ndm->ndm_flags;
1745 err = 0;
1746 }
Eric Dumazet110b2492010-10-04 04:27:36 +00001747 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 }
1749
Thomas Graf5208deb2006-08-07 17:55:40 -07001750 if (dev == NULL)
Eric Dumazet110b2492010-10-04 04:27:36 +00001751 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001752
1753 neigh = neigh_lookup(tbl, dst, dev);
1754 if (neigh == NULL) {
1755 if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
1756 err = -ENOENT;
Eric Dumazet110b2492010-10-04 04:27:36 +00001757 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001758 }
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001759
Thomas Graf5208deb2006-08-07 17:55:40 -07001760 neigh = __neigh_lookup_errno(tbl, dst, dev);
1761 if (IS_ERR(neigh)) {
1762 err = PTR_ERR(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001763 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001764 }
1765 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 if (nlh->nlmsg_flags & NLM_F_EXCL) {
1767 err = -EEXIST;
Thomas Graf5208deb2006-08-07 17:55:40 -07001768 neigh_release(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001769 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 }
Thomas Graf5208deb2006-08-07 17:55:40 -07001771
1772 if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
1773 flags &= ~NEIGH_UPDATE_F_OVERRIDE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 }
1775
Eric Biederman0c5c2d32009-03-04 00:03:08 -08001776 if (ndm->ndm_flags & NTF_USE) {
1777 neigh_event_send(neigh, NULL);
1778 err = 0;
1779 } else
1780 err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
Thomas Graf5208deb2006-08-07 17:55:40 -07001781 neigh_release(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001782 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 }
1784
1785 read_unlock(&neigh_tbl_lock);
Thomas Graf5208deb2006-08-07 17:55:40 -07001786 err = -EAFNOSUPPORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787out:
1788 return err;
1789}
1790
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001791static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
1792{
Thomas Grafca860fb2006-08-07 18:00:18 -07001793 struct nlattr *nest;
1794
1795 nest = nla_nest_start(skb, NDTA_PARMS);
1796 if (nest == NULL)
1797 return -ENOBUFS;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001798
David S. Miller9a6308d2012-04-01 20:06:28 -04001799 if ((parms->dev &&
1800 nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) ||
1801 nla_put_u32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt)) ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001802 nla_put_u32(skb, NDTPA_QUEUE_LENBYTES,
1803 NEIGH_VAR(parms, QUEUE_LEN_BYTES)) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04001804 /* approximative value for deprecated QUEUE_LEN (in packets) */
1805 nla_put_u32(skb, NDTPA_QUEUE_LEN,
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001806 NEIGH_VAR(parms, QUEUE_LEN_BYTES) / SKB_TRUESIZE(ETH_FRAME_LEN)) ||
1807 nla_put_u32(skb, NDTPA_PROXY_QLEN, NEIGH_VAR(parms, PROXY_QLEN)) ||
1808 nla_put_u32(skb, NDTPA_APP_PROBES, NEIGH_VAR(parms, APP_PROBES)) ||
1809 nla_put_u32(skb, NDTPA_UCAST_PROBES,
1810 NEIGH_VAR(parms, UCAST_PROBES)) ||
1811 nla_put_u32(skb, NDTPA_MCAST_PROBES,
1812 NEIGH_VAR(parms, MCAST_PROBES)) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04001813 nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time) ||
1814 nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME,
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001815 NEIGH_VAR(parms, BASE_REACHABLE_TIME)) ||
1816 nla_put_msecs(skb, NDTPA_GC_STALETIME,
1817 NEIGH_VAR(parms, GC_STALETIME)) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04001818 nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME,
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001819 NEIGH_VAR(parms, DELAY_PROBE_TIME)) ||
1820 nla_put_msecs(skb, NDTPA_RETRANS_TIME,
1821 NEIGH_VAR(parms, RETRANS_TIME)) ||
1822 nla_put_msecs(skb, NDTPA_ANYCAST_DELAY,
1823 NEIGH_VAR(parms, ANYCAST_DELAY)) ||
1824 nla_put_msecs(skb, NDTPA_PROXY_DELAY,
1825 NEIGH_VAR(parms, PROXY_DELAY)) ||
1826 nla_put_msecs(skb, NDTPA_LOCKTIME,
1827 NEIGH_VAR(parms, LOCKTIME)))
David S. Miller9a6308d2012-04-01 20:06:28 -04001828 goto nla_put_failure;
Thomas Grafca860fb2006-08-07 18:00:18 -07001829 return nla_nest_end(skb, nest);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001830
Thomas Grafca860fb2006-08-07 18:00:18 -07001831nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07001832 nla_nest_cancel(skb, nest);
1833 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001834}
1835
Thomas Grafca860fb2006-08-07 18:00:18 -07001836static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
1837 u32 pid, u32 seq, int type, int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001838{
1839 struct nlmsghdr *nlh;
1840 struct ndtmsg *ndtmsg;
1841
Thomas Grafca860fb2006-08-07 18:00:18 -07001842 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
1843 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001844 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001845
Thomas Grafca860fb2006-08-07 18:00:18 -07001846 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001847
1848 read_lock_bh(&tbl->lock);
1849 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07001850 ndtmsg->ndtm_pad1 = 0;
1851 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001852
David S. Miller9a6308d2012-04-01 20:06:28 -04001853 if (nla_put_string(skb, NDTA_NAME, tbl->id) ||
1854 nla_put_msecs(skb, NDTA_GC_INTERVAL, tbl->gc_interval) ||
1855 nla_put_u32(skb, NDTA_THRESH1, tbl->gc_thresh1) ||
1856 nla_put_u32(skb, NDTA_THRESH2, tbl->gc_thresh2) ||
1857 nla_put_u32(skb, NDTA_THRESH3, tbl->gc_thresh3))
1858 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001859 {
1860 unsigned long now = jiffies;
1861 unsigned int flush_delta = now - tbl->last_flush;
1862 unsigned int rand_delta = now - tbl->last_rand;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001863 struct neigh_hash_table *nht;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001864 struct ndt_config ndc = {
1865 .ndtc_key_len = tbl->key_len,
1866 .ndtc_entry_size = tbl->entry_size,
1867 .ndtc_entries = atomic_read(&tbl->entries),
1868 .ndtc_last_flush = jiffies_to_msecs(flush_delta),
1869 .ndtc_last_rand = jiffies_to_msecs(rand_delta),
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001870 .ndtc_proxy_qlen = tbl->proxy_queue.qlen,
1871 };
1872
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001873 rcu_read_lock_bh();
1874 nht = rcu_dereference_bh(tbl->nht);
David S. Miller2c2aba62011-12-28 15:06:58 -05001875 ndc.ndtc_hash_rnd = nht->hash_rnd[0];
David S. Millercd089332011-07-11 01:28:12 -07001876 ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001877 rcu_read_unlock_bh();
1878
David S. Miller9a6308d2012-04-01 20:06:28 -04001879 if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc))
1880 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001881 }
1882
1883 {
1884 int cpu;
1885 struct ndt_stats ndst;
1886
1887 memset(&ndst, 0, sizeof(ndst));
1888
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001889 for_each_possible_cpu(cpu) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001890 struct neigh_statistics *st;
1891
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001892 st = per_cpu_ptr(tbl->stats, cpu);
1893 ndst.ndts_allocs += st->allocs;
1894 ndst.ndts_destroys += st->destroys;
1895 ndst.ndts_hash_grows += st->hash_grows;
1896 ndst.ndts_res_failed += st->res_failed;
1897 ndst.ndts_lookups += st->lookups;
1898 ndst.ndts_hits += st->hits;
1899 ndst.ndts_rcv_probes_mcast += st->rcv_probes_mcast;
1900 ndst.ndts_rcv_probes_ucast += st->rcv_probes_ucast;
1901 ndst.ndts_periodic_gc_runs += st->periodic_gc_runs;
1902 ndst.ndts_forced_gc_runs += st->forced_gc_runs;
1903 }
1904
David S. Miller9a6308d2012-04-01 20:06:28 -04001905 if (nla_put(skb, NDTA_STATS, sizeof(ndst), &ndst))
1906 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001907 }
1908
1909 BUG_ON(tbl->parms.dev);
1910 if (neightbl_fill_parms(skb, &tbl->parms) < 0)
Thomas Grafca860fb2006-08-07 18:00:18 -07001911 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001912
1913 read_unlock_bh(&tbl->lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07001914 return nlmsg_end(skb, nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001915
Thomas Grafca860fb2006-08-07 18:00:18 -07001916nla_put_failure:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001917 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08001918 nlmsg_cancel(skb, nlh);
1919 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001920}
1921
Thomas Grafca860fb2006-08-07 18:00:18 -07001922static int neightbl_fill_param_info(struct sk_buff *skb,
1923 struct neigh_table *tbl,
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001924 struct neigh_parms *parms,
Thomas Grafca860fb2006-08-07 18:00:18 -07001925 u32 pid, u32 seq, int type,
1926 unsigned int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001927{
1928 struct ndtmsg *ndtmsg;
1929 struct nlmsghdr *nlh;
1930
Thomas Grafca860fb2006-08-07 18:00:18 -07001931 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
1932 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001933 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001934
Thomas Grafca860fb2006-08-07 18:00:18 -07001935 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001936
1937 read_lock_bh(&tbl->lock);
1938 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07001939 ndtmsg->ndtm_pad1 = 0;
1940 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001941
Thomas Grafca860fb2006-08-07 18:00:18 -07001942 if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
1943 neightbl_fill_parms(skb, parms) < 0)
1944 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001945
1946 read_unlock_bh(&tbl->lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07001947 return nlmsg_end(skb, nlh);
1948errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001949 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08001950 nlmsg_cancel(skb, nlh);
1951 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001952}
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001953
Patrick McHardyef7c79e2007-06-05 12:38:30 -07001954static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07001955 [NDTA_NAME] = { .type = NLA_STRING },
1956 [NDTA_THRESH1] = { .type = NLA_U32 },
1957 [NDTA_THRESH2] = { .type = NLA_U32 },
1958 [NDTA_THRESH3] = { .type = NLA_U32 },
1959 [NDTA_GC_INTERVAL] = { .type = NLA_U64 },
1960 [NDTA_PARMS] = { .type = NLA_NESTED },
1961};
1962
Patrick McHardyef7c79e2007-06-05 12:38:30 -07001963static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07001964 [NDTPA_IFINDEX] = { .type = NLA_U32 },
1965 [NDTPA_QUEUE_LEN] = { .type = NLA_U32 },
1966 [NDTPA_PROXY_QLEN] = { .type = NLA_U32 },
1967 [NDTPA_APP_PROBES] = { .type = NLA_U32 },
1968 [NDTPA_UCAST_PROBES] = { .type = NLA_U32 },
1969 [NDTPA_MCAST_PROBES] = { .type = NLA_U32 },
1970 [NDTPA_BASE_REACHABLE_TIME] = { .type = NLA_U64 },
1971 [NDTPA_GC_STALETIME] = { .type = NLA_U64 },
1972 [NDTPA_DELAY_PROBE_TIME] = { .type = NLA_U64 },
1973 [NDTPA_RETRANS_TIME] = { .type = NLA_U64 },
1974 [NDTPA_ANYCAST_DELAY] = { .type = NLA_U64 },
1975 [NDTPA_PROXY_DELAY] = { .type = NLA_U64 },
1976 [NDTPA_LOCKTIME] = { .type = NLA_U64 },
1977};
1978
Thomas Graf661d2962013-03-21 07:45:29 +00001979static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001980{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001981 struct net *net = sock_net(skb->sk);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001982 struct neigh_table *tbl;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001983 struct ndtmsg *ndtmsg;
1984 struct nlattr *tb[NDTA_MAX+1];
1985 int err;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001986
Thomas Graf6b3f8672006-08-07 17:58:53 -07001987 err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
1988 nl_neightbl_policy);
1989 if (err < 0)
1990 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001991
Thomas Graf6b3f8672006-08-07 17:58:53 -07001992 if (tb[NDTA_NAME] == NULL) {
1993 err = -EINVAL;
1994 goto errout;
1995 }
1996
1997 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001998 read_lock(&neigh_tbl_lock);
1999 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
2000 if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
2001 continue;
2002
Thomas Graf6b3f8672006-08-07 17:58:53 -07002003 if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002004 break;
2005 }
2006
2007 if (tbl == NULL) {
2008 err = -ENOENT;
Thomas Graf6b3f8672006-08-07 17:58:53 -07002009 goto errout_locked;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002010 }
2011
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09002012 /*
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002013 * We acquire tbl->lock to be nice to the periodic timers and
2014 * make sure they always see a consistent set of values.
2015 */
2016 write_lock_bh(&tbl->lock);
2017
Thomas Graf6b3f8672006-08-07 17:58:53 -07002018 if (tb[NDTA_PARMS]) {
2019 struct nlattr *tbp[NDTPA_MAX+1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002020 struct neigh_parms *p;
Thomas Graf6b3f8672006-08-07 17:58:53 -07002021 int i, ifindex = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002022
Thomas Graf6b3f8672006-08-07 17:58:53 -07002023 err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS],
2024 nl_ntbl_parm_policy);
2025 if (err < 0)
2026 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002027
Thomas Graf6b3f8672006-08-07 17:58:53 -07002028 if (tbp[NDTPA_IFINDEX])
2029 ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002030
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07002031 p = lookup_neigh_parms(tbl, net, ifindex);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002032 if (p == NULL) {
2033 err = -ENOENT;
Thomas Graf6b3f8672006-08-07 17:58:53 -07002034 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002035 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002036
Thomas Graf6b3f8672006-08-07 17:58:53 -07002037 for (i = 1; i <= NDTPA_MAX; i++) {
2038 if (tbp[i] == NULL)
2039 continue;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002040
Thomas Graf6b3f8672006-08-07 17:58:53 -07002041 switch (i) {
2042 case NDTPA_QUEUE_LEN:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002043 NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
2044 nla_get_u32(tbp[i]) *
2045 SKB_TRUESIZE(ETH_FRAME_LEN));
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002046 break;
2047 case NDTPA_QUEUE_LENBYTES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002048 NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
2049 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002050 break;
2051 case NDTPA_PROXY_QLEN:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002052 NEIGH_VAR_SET(p, PROXY_QLEN,
2053 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002054 break;
2055 case NDTPA_APP_PROBES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002056 NEIGH_VAR_SET(p, APP_PROBES,
2057 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002058 break;
2059 case NDTPA_UCAST_PROBES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002060 NEIGH_VAR_SET(p, UCAST_PROBES,
2061 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002062 break;
2063 case NDTPA_MCAST_PROBES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002064 NEIGH_VAR_SET(p, MCAST_PROBES,
2065 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002066 break;
2067 case NDTPA_BASE_REACHABLE_TIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002068 NEIGH_VAR_SET(p, BASE_REACHABLE_TIME,
2069 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002070 break;
2071 case NDTPA_GC_STALETIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002072 NEIGH_VAR_SET(p, GC_STALETIME,
2073 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002074 break;
2075 case NDTPA_DELAY_PROBE_TIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002076 NEIGH_VAR_SET(p, DELAY_PROBE_TIME,
2077 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002078 break;
2079 case NDTPA_RETRANS_TIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002080 NEIGH_VAR_SET(p, RETRANS_TIME,
2081 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002082 break;
2083 case NDTPA_ANYCAST_DELAY:
Jiri Pirko39774582014-01-14 15:46:07 +01002084 NEIGH_VAR_SET(p, ANYCAST_DELAY,
2085 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002086 break;
2087 case NDTPA_PROXY_DELAY:
Jiri Pirko39774582014-01-14 15:46:07 +01002088 NEIGH_VAR_SET(p, PROXY_DELAY,
2089 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002090 break;
2091 case NDTPA_LOCKTIME:
Jiri Pirko39774582014-01-14 15:46:07 +01002092 NEIGH_VAR_SET(p, LOCKTIME,
2093 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002094 break;
2095 }
2096 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002097 }
2098
Gao fengdc25c672013-06-20 10:01:34 +08002099 err = -ENOENT;
2100 if ((tb[NDTA_THRESH1] || tb[NDTA_THRESH2] ||
2101 tb[NDTA_THRESH3] || tb[NDTA_GC_INTERVAL]) &&
2102 !net_eq(net, &init_net))
2103 goto errout_tbl_lock;
2104
Thomas Graf6b3f8672006-08-07 17:58:53 -07002105 if (tb[NDTA_THRESH1])
2106 tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
2107
2108 if (tb[NDTA_THRESH2])
2109 tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
2110
2111 if (tb[NDTA_THRESH3])
2112 tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
2113
2114 if (tb[NDTA_GC_INTERVAL])
2115 tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
2116
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002117 err = 0;
2118
Thomas Graf6b3f8672006-08-07 17:58:53 -07002119errout_tbl_lock:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002120 write_unlock_bh(&tbl->lock);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002121errout_locked:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002122 read_unlock(&neigh_tbl_lock);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002123errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002124 return err;
2125}
2126
Thomas Grafc8822a42007-03-22 11:50:06 -07002127static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002128{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002129 struct net *net = sock_net(skb->sk);
Thomas Grafca860fb2006-08-07 18:00:18 -07002130 int family, tidx, nidx = 0;
2131 int tbl_skip = cb->args[0];
2132 int neigh_skip = cb->args[1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002133 struct neigh_table *tbl;
2134
Thomas Grafca860fb2006-08-07 18:00:18 -07002135 family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002136
2137 read_lock(&neigh_tbl_lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07002138 for (tbl = neigh_tables, tidx = 0; tbl; tbl = tbl->next, tidx++) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002139 struct neigh_parms *p;
2140
Thomas Grafca860fb2006-08-07 18:00:18 -07002141 if (tidx < tbl_skip || (family && tbl->family != family))
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002142 continue;
2143
Eric W. Biederman15e47302012-09-07 20:12:54 +00002144 if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
Thomas Grafca860fb2006-08-07 18:00:18 -07002145 cb->nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
2146 NLM_F_MULTI) <= 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002147 break;
2148
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01002149 nidx = 0;
2150 p = list_next_entry(&tbl->parms, list);
2151 list_for_each_entry_from(p, &tbl->parms_list, list) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002152 if (!net_eq(neigh_parms_net(p), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002153 continue;
2154
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002155 if (nidx < neigh_skip)
2156 goto next;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002157
Thomas Grafca860fb2006-08-07 18:00:18 -07002158 if (neightbl_fill_param_info(skb, tbl, p,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002159 NETLINK_CB(cb->skb).portid,
Thomas Grafca860fb2006-08-07 18:00:18 -07002160 cb->nlh->nlmsg_seq,
2161 RTM_NEWNEIGHTBL,
2162 NLM_F_MULTI) <= 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002163 goto out;
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002164 next:
2165 nidx++;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002166 }
2167
Thomas Grafca860fb2006-08-07 18:00:18 -07002168 neigh_skip = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002169 }
2170out:
2171 read_unlock(&neigh_tbl_lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07002172 cb->args[0] = tidx;
2173 cb->args[1] = nidx;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002174
2175 return skb->len;
2176}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177
Thomas Graf8b8aec52006-08-07 17:56:37 -07002178static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
2179 u32 pid, u32 seq, int type, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180{
2181 unsigned long now = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 struct nda_cacheinfo ci;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002183 struct nlmsghdr *nlh;
2184 struct ndmsg *ndm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185
Thomas Graf8b8aec52006-08-07 17:56:37 -07002186 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
2187 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08002188 return -EMSGSIZE;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002189
2190 ndm = nlmsg_data(nlh);
2191 ndm->ndm_family = neigh->ops->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07002192 ndm->ndm_pad1 = 0;
2193 ndm->ndm_pad2 = 0;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002194 ndm->ndm_flags = neigh->flags;
2195 ndm->ndm_type = neigh->type;
2196 ndm->ndm_ifindex = neigh->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197
David S. Miller9a6308d2012-04-01 20:06:28 -04002198 if (nla_put(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key))
2199 goto nla_put_failure;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002200
2201 read_lock_bh(&neigh->lock);
2202 ndm->ndm_state = neigh->nud_state;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00002203 if (neigh->nud_state & NUD_VALID) {
2204 char haddr[MAX_ADDR_LEN];
2205
2206 neigh_ha_snapshot(haddr, neigh, neigh->dev);
2207 if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0) {
2208 read_unlock_bh(&neigh->lock);
2209 goto nla_put_failure;
2210 }
Thomas Graf8b8aec52006-08-07 17:56:37 -07002211 }
2212
Stephen Hemmingerb9f5f522008-06-03 16:03:15 -07002213 ci.ndm_used = jiffies_to_clock_t(now - neigh->used);
2214 ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
2215 ci.ndm_updated = jiffies_to_clock_t(now - neigh->updated);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002216 ci.ndm_refcnt = atomic_read(&neigh->refcnt) - 1;
2217 read_unlock_bh(&neigh->lock);
2218
David S. Miller9a6308d2012-04-01 20:06:28 -04002219 if (nla_put_u32(skb, NDA_PROBES, atomic_read(&neigh->probes)) ||
2220 nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
2221 goto nla_put_failure;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002222
2223 return nlmsg_end(skb, nlh);
2224
2225nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002226 nlmsg_cancel(skb, nlh);
2227 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228}
2229
Tony Zelenoff84920c12012-01-26 22:28:58 +00002230static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
2231 u32 pid, u32 seq, int type, unsigned int flags,
2232 struct neigh_table *tbl)
2233{
2234 struct nlmsghdr *nlh;
2235 struct ndmsg *ndm;
2236
2237 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
2238 if (nlh == NULL)
2239 return -EMSGSIZE;
2240
2241 ndm = nlmsg_data(nlh);
2242 ndm->ndm_family = tbl->family;
2243 ndm->ndm_pad1 = 0;
2244 ndm->ndm_pad2 = 0;
2245 ndm->ndm_flags = pn->flags | NTF_PROXY;
Jun Zhao545469f2014-07-26 00:38:59 +08002246 ndm->ndm_type = RTN_UNICAST;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002247 ndm->ndm_ifindex = pn->dev->ifindex;
2248 ndm->ndm_state = NUD_NONE;
2249
David S. Miller9a6308d2012-04-01 20:06:28 -04002250 if (nla_put(skb, NDA_DST, tbl->key_len, pn->key))
2251 goto nla_put_failure;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002252
2253 return nlmsg_end(skb, nlh);
2254
2255nla_put_failure:
2256 nlmsg_cancel(skb, nlh);
2257 return -EMSGSIZE;
2258}
2259
Thomas Grafd961db32007-08-08 23:12:56 -07002260static void neigh_update_notify(struct neighbour *neigh)
2261{
2262 call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
2263 __neigh_notify(neigh, RTM_NEWNEIGH, 0);
2264}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265
2266static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
2267 struct netlink_callback *cb)
2268{
Eric Dumazet767e97e2010-10-06 17:49:21 -07002269 struct net *net = sock_net(skb->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 struct neighbour *n;
2271 int rc, h, s_h = cb->args[1];
2272 int idx, s_idx = idx = cb->args[2];
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002273 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002275 rcu_read_lock_bh();
2276 nht = rcu_dereference_bh(tbl->nht);
2277
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002278 for (h = s_h; h < (1 << nht->hash_shift); h++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 if (h > s_h)
2280 s_idx = 0;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002281 for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
2282 n != NULL;
2283 n = rcu_dereference_bh(n->next)) {
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002284 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002285 continue;
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002286 if (idx < s_idx)
2287 goto next;
Eric W. Biederman15e47302012-09-07 20:12:54 +00002288 if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 cb->nlh->nlmsg_seq,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07002290 RTM_NEWNEIGH,
2291 NLM_F_MULTI) <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 rc = -1;
2293 goto out;
2294 }
Eric Dumazet767e97e2010-10-06 17:49:21 -07002295next:
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002296 idx++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 }
2299 rc = skb->len;
2300out:
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002301 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 cb->args[1] = h;
2303 cb->args[2] = idx;
2304 return rc;
2305}
2306
Tony Zelenoff84920c12012-01-26 22:28:58 +00002307static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
2308 struct netlink_callback *cb)
2309{
2310 struct pneigh_entry *n;
2311 struct net *net = sock_net(skb->sk);
2312 int rc, h, s_h = cb->args[3];
2313 int idx, s_idx = idx = cb->args[4];
2314
2315 read_lock_bh(&tbl->lock);
2316
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002317 for (h = s_h; h <= PNEIGH_HASHMASK; h++) {
Tony Zelenoff84920c12012-01-26 22:28:58 +00002318 if (h > s_h)
2319 s_idx = 0;
2320 for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
2321 if (dev_net(n->dev) != net)
2322 continue;
2323 if (idx < s_idx)
2324 goto next;
Eric W. Biederman15e47302012-09-07 20:12:54 +00002325 if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
Tony Zelenoff84920c12012-01-26 22:28:58 +00002326 cb->nlh->nlmsg_seq,
2327 RTM_NEWNEIGH,
2328 NLM_F_MULTI, tbl) <= 0) {
2329 read_unlock_bh(&tbl->lock);
2330 rc = -1;
2331 goto out;
2332 }
2333 next:
2334 idx++;
2335 }
2336 }
2337
2338 read_unlock_bh(&tbl->lock);
2339 rc = skb->len;
2340out:
2341 cb->args[3] = h;
2342 cb->args[4] = idx;
2343 return rc;
2344
2345}
2346
Thomas Grafc8822a42007-03-22 11:50:06 -07002347static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348{
2349 struct neigh_table *tbl;
2350 int t, family, s_t;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002351 int proxy = 0;
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002352 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353
2354 read_lock(&neigh_tbl_lock);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002355 family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002356
2357 /* check for full ndmsg structure presence, family member is
2358 * the same for both structures
2359 */
2360 if (nlmsg_len(cb->nlh) >= sizeof(struct ndmsg) &&
2361 ((struct ndmsg *) nlmsg_data(cb->nlh))->ndm_flags == NTF_PROXY)
2362 proxy = 1;
2363
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 s_t = cb->args[0];
2365
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002366 for (tbl = neigh_tables, t = 0; tbl;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002367 tbl = tbl->next, t++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 if (t < s_t || (family && tbl->family != family))
2369 continue;
2370 if (t > s_t)
2371 memset(&cb->args[1], 0, sizeof(cb->args) -
2372 sizeof(cb->args[0]));
Tony Zelenoff84920c12012-01-26 22:28:58 +00002373 if (proxy)
2374 err = pneigh_dump_table(tbl, skb, cb);
2375 else
2376 err = neigh_dump_table(tbl, skb, cb);
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002377 if (err < 0)
2378 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 }
2380 read_unlock(&neigh_tbl_lock);
2381
2382 cb->args[0] = t;
2383 return skb->len;
2384}
2385
2386void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
2387{
2388 int chain;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002389 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002391 rcu_read_lock_bh();
2392 nht = rcu_dereference_bh(tbl->nht);
2393
Eric Dumazet767e97e2010-10-06 17:49:21 -07002394 read_lock(&tbl->lock); /* avoid resizes */
David S. Millercd089332011-07-11 01:28:12 -07002395 for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 struct neighbour *n;
2397
Eric Dumazet767e97e2010-10-06 17:49:21 -07002398 for (n = rcu_dereference_bh(nht->hash_buckets[chain]);
2399 n != NULL;
2400 n = rcu_dereference_bh(n->next))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 cb(n, cookie);
2402 }
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002403 read_unlock(&tbl->lock);
2404 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405}
2406EXPORT_SYMBOL(neigh_for_each);
2407
2408/* The tbl->lock must be held as a writer and BH disabled. */
2409void __neigh_for_each_release(struct neigh_table *tbl,
2410 int (*cb)(struct neighbour *))
2411{
2412 int chain;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002413 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002415 nht = rcu_dereference_protected(tbl->nht,
2416 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -07002417 for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002418 struct neighbour *n;
2419 struct neighbour __rcu **np;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002421 np = &nht->hash_buckets[chain];
Eric Dumazet767e97e2010-10-06 17:49:21 -07002422 while ((n = rcu_dereference_protected(*np,
2423 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 int release;
2425
2426 write_lock(&n->lock);
2427 release = cb(n);
2428 if (release) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002429 rcu_assign_pointer(*np,
2430 rcu_dereference_protected(n->next,
2431 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 n->dead = 1;
2433 } else
2434 np = &n->next;
2435 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -07002436 if (release)
2437 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 }
2439 }
2440}
2441EXPORT_SYMBOL(__neigh_for_each_release);
2442
2443#ifdef CONFIG_PROC_FS
2444
2445static struct neighbour *neigh_get_first(struct seq_file *seq)
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 struct neighbour *n = NULL;
2451 int bucket = state->bucket;
2452
2453 state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
David S. Millercd089332011-07-11 01:28:12 -07002454 for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002455 n = rcu_dereference_bh(nht->hash_buckets[bucket]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456
2457 while (n) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002458 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002459 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 if (state->neigh_sub_iter) {
2461 loff_t fakep = 0;
2462 void *v;
2463
2464 v = state->neigh_sub_iter(state, n, &fakep);
2465 if (!v)
2466 goto next;
2467 }
2468 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
2469 break;
2470 if (n->nud_state & ~NUD_NOARP)
2471 break;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002472next:
2473 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 }
2475
2476 if (n)
2477 break;
2478 }
2479 state->bucket = bucket;
2480
2481 return n;
2482}
2483
2484static struct neighbour *neigh_get_next(struct seq_file *seq,
2485 struct neighbour *n,
2486 loff_t *pos)
2487{
2488 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002489 struct net *net = seq_file_net(seq);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002490 struct neigh_hash_table *nht = state->nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491
2492 if (state->neigh_sub_iter) {
2493 void *v = state->neigh_sub_iter(state, n, pos);
2494 if (v)
2495 return n;
2496 }
Eric Dumazet767e97e2010-10-06 17:49:21 -07002497 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498
2499 while (1) {
2500 while (n) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002501 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002502 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 if (state->neigh_sub_iter) {
2504 void *v = state->neigh_sub_iter(state, n, pos);
2505 if (v)
2506 return n;
2507 goto next;
2508 }
2509 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
2510 break;
2511
2512 if (n->nud_state & ~NUD_NOARP)
2513 break;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002514next:
2515 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 }
2517
2518 if (n)
2519 break;
2520
David S. Millercd089332011-07-11 01:28:12 -07002521 if (++state->bucket >= (1 << nht->hash_shift))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 break;
2523
Eric Dumazet767e97e2010-10-06 17:49:21 -07002524 n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 }
2526
2527 if (n && pos)
2528 --(*pos);
2529 return n;
2530}
2531
2532static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
2533{
2534 struct neighbour *n = neigh_get_first(seq);
2535
2536 if (n) {
Chris Larson745e2032008-08-03 01:10:55 -07002537 --(*pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 while (*pos) {
2539 n = neigh_get_next(seq, n, pos);
2540 if (!n)
2541 break;
2542 }
2543 }
2544 return *pos ? NULL : n;
2545}
2546
2547static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
2548{
2549 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002550 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 struct neigh_table *tbl = state->tbl;
2552 struct pneigh_entry *pn = NULL;
2553 int bucket = state->bucket;
2554
2555 state->flags |= NEIGH_SEQ_IS_PNEIGH;
2556 for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
2557 pn = tbl->phash_buckets[bucket];
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002558 while (pn && !net_eq(pneigh_net(pn), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002559 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 if (pn)
2561 break;
2562 }
2563 state->bucket = bucket;
2564
2565 return pn;
2566}
2567
2568static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
2569 struct pneigh_entry *pn,
2570 loff_t *pos)
2571{
2572 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002573 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 struct neigh_table *tbl = state->tbl;
2575
Jorge Boncompte [DTI2]df07a942011-11-25 13:24:49 -05002576 do {
2577 pn = pn->next;
2578 } while (pn && !net_eq(pneigh_net(pn), net));
2579
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 while (!pn) {
2581 if (++state->bucket > PNEIGH_HASHMASK)
2582 break;
2583 pn = tbl->phash_buckets[state->bucket];
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002584 while (pn && !net_eq(pneigh_net(pn), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002585 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 if (pn)
2587 break;
2588 }
2589
2590 if (pn && pos)
2591 --(*pos);
2592
2593 return pn;
2594}
2595
2596static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
2597{
2598 struct pneigh_entry *pn = pneigh_get_first(seq);
2599
2600 if (pn) {
Chris Larson745e2032008-08-03 01:10:55 -07002601 --(*pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 while (*pos) {
2603 pn = pneigh_get_next(seq, pn, pos);
2604 if (!pn)
2605 break;
2606 }
2607 }
2608 return *pos ? NULL : pn;
2609}
2610
2611static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
2612{
2613 struct neigh_seq_state *state = seq->private;
2614 void *rc;
Chris Larson745e2032008-08-03 01:10:55 -07002615 loff_t idxpos = *pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616
Chris Larson745e2032008-08-03 01:10:55 -07002617 rc = neigh_get_idx(seq, &idxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
Chris Larson745e2032008-08-03 01:10:55 -07002619 rc = pneigh_get_idx(seq, &idxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620
2621 return rc;
2622}
2623
2624void *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 +00002625 __acquires(rcu_bh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626{
2627 struct neigh_seq_state *state = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628
2629 state->tbl = tbl;
2630 state->bucket = 0;
2631 state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
2632
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002633 rcu_read_lock_bh();
2634 state->nht = rcu_dereference_bh(tbl->nht);
Eric Dumazet767e97e2010-10-06 17:49:21 -07002635
Chris Larson745e2032008-08-03 01:10:55 -07002636 return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637}
2638EXPORT_SYMBOL(neigh_seq_start);
2639
2640void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2641{
2642 struct neigh_seq_state *state;
2643 void *rc;
2644
2645 if (v == SEQ_START_TOKEN) {
Chris Larsonbff69732008-08-03 01:02:41 -07002646 rc = neigh_get_first(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 goto out;
2648 }
2649
2650 state = seq->private;
2651 if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {
2652 rc = neigh_get_next(seq, v, NULL);
2653 if (rc)
2654 goto out;
2655 if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))
2656 rc = pneigh_get_first(seq);
2657 } else {
2658 BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);
2659 rc = pneigh_get_next(seq, v, NULL);
2660 }
2661out:
2662 ++(*pos);
2663 return rc;
2664}
2665EXPORT_SYMBOL(neigh_seq_next);
2666
2667void neigh_seq_stop(struct seq_file *seq, void *v)
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002668 __releases(rcu_bh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669{
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002670 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671}
2672EXPORT_SYMBOL(neigh_seq_stop);
2673
2674/* statistics via seq_file */
2675
2676static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
2677{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002678 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 int cpu;
2680
2681 if (*pos == 0)
2682 return SEQ_START_TOKEN;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09002683
Rusty Russell0f23174a2008-12-29 12:23:42 +00002684 for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 if (!cpu_possible(cpu))
2686 continue;
2687 *pos = cpu+1;
2688 return per_cpu_ptr(tbl->stats, cpu);
2689 }
2690 return NULL;
2691}
2692
2693static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2694{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002695 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 int cpu;
2697
Rusty Russell0f23174a2008-12-29 12:23:42 +00002698 for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 if (!cpu_possible(cpu))
2700 continue;
2701 *pos = cpu+1;
2702 return per_cpu_ptr(tbl->stats, cpu);
2703 }
2704 return NULL;
2705}
2706
2707static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
2708{
2709
2710}
2711
2712static int neigh_stat_seq_show(struct seq_file *seq, void *v)
2713{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002714 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 struct neigh_statistics *st = v;
2716
2717 if (v == SEQ_START_TOKEN) {
Neil Horman9a6d2762008-07-16 20:50:49 -07002718 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 -07002719 return 0;
2720 }
2721
2722 seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx "
Neil Horman9a6d2762008-07-16 20:50:49 -07002723 "%08lx %08lx %08lx %08lx %08lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 atomic_read(&tbl->entries),
2725
2726 st->allocs,
2727 st->destroys,
2728 st->hash_grows,
2729
2730 st->lookups,
2731 st->hits,
2732
2733 st->res_failed,
2734
2735 st->rcv_probes_mcast,
2736 st->rcv_probes_ucast,
2737
2738 st->periodic_gc_runs,
Neil Horman9a6d2762008-07-16 20:50:49 -07002739 st->forced_gc_runs,
2740 st->unres_discards
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 );
2742
2743 return 0;
2744}
2745
Stephen Hemmingerf6908082007-03-12 14:34:29 -07002746static const struct seq_operations neigh_stat_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 .start = neigh_stat_seq_start,
2748 .next = neigh_stat_seq_next,
2749 .stop = neigh_stat_seq_stop,
2750 .show = neigh_stat_seq_show,
2751};
2752
2753static int neigh_stat_seq_open(struct inode *inode, struct file *file)
2754{
2755 int ret = seq_open(file, &neigh_stat_seq_ops);
2756
2757 if (!ret) {
2758 struct seq_file *sf = file->private_data;
Al Virod9dda782013-03-31 18:16:14 -04002759 sf->private = PDE_DATA(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 }
2761 return ret;
2762};
2763
Arjan van de Ven9a321442007-02-12 00:55:35 -08002764static const struct file_operations neigh_stat_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 .owner = THIS_MODULE,
2766 .open = neigh_stat_seq_open,
2767 .read = seq_read,
2768 .llseek = seq_lseek,
2769 .release = seq_release,
2770};
2771
2772#endif /* CONFIG_PROC_FS */
2773
Thomas Graf339bf982006-11-10 14:10:15 -08002774static inline size_t neigh_nlmsg_size(void)
2775{
2776 return NLMSG_ALIGN(sizeof(struct ndmsg))
2777 + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
2778 + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
2779 + nla_total_size(sizeof(struct nda_cacheinfo))
2780 + nla_total_size(4); /* NDA_PROBES */
2781}
2782
Thomas Grafb8673312006-08-15 00:33:14 -07002783static void __neigh_notify(struct neighbour *n, int type, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002785 struct net *net = dev_net(n->dev);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002786 struct sk_buff *skb;
Thomas Grafb8673312006-08-15 00:33:14 -07002787 int err = -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788
Thomas Graf339bf982006-11-10 14:10:15 -08002789 skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002790 if (skb == NULL)
Thomas Grafb8673312006-08-15 00:33:14 -07002791 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792
Thomas Grafb8673312006-08-15 00:33:14 -07002793 err = neigh_fill_info(skb, n, 0, 0, type, flags);
Patrick McHardy26932562007-01-31 23:16:40 -08002794 if (err < 0) {
2795 /* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
2796 WARN_ON(err == -EMSGSIZE);
2797 kfree_skb(skb);
2798 goto errout;
2799 }
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08002800 rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
2801 return;
Thomas Grafb8673312006-08-15 00:33:14 -07002802errout:
2803 if (err < 0)
Eric W. Biederman426b5302008-01-24 00:13:18 -08002804 rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
Thomas Grafb8673312006-08-15 00:33:14 -07002805}
2806
2807void neigh_app_ns(struct neighbour *n)
2808{
2809 __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09002811EXPORT_SYMBOL(neigh_app_ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812
2813#ifdef CONFIG_SYSCTL
Cong Wangb93196d2012-12-06 10:04:04 +08002814static int zero;
Francesco Fusco555445c2013-07-24 10:39:06 +02002815static int int_max = INT_MAX;
Cong Wangb93196d2012-12-06 10:04:04 +08002816static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817
Joe Perchesfe2c6332013-06-11 23:04:25 -07002818static int proc_unres_qlen(struct ctl_table *ctl, int write,
2819 void __user *buffer, size_t *lenp, loff_t *ppos)
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002820{
2821 int size, ret;
Joe Perchesfe2c6332013-06-11 23:04:25 -07002822 struct ctl_table tmp = *ctl;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002823
Shan Weice46cc62012-12-04 18:49:15 +00002824 tmp.extra1 = &zero;
2825 tmp.extra2 = &unres_qlen_max;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002826 tmp.data = &size;
Shan Weice46cc62012-12-04 18:49:15 +00002827
2828 size = *(int *)ctl->data / SKB_TRUESIZE(ETH_FRAME_LEN);
2829 ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
2830
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002831 if (write && !ret)
2832 *(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
2833 return ret;
2834}
2835
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002836static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev,
2837 int family)
2838{
Jiri Pirkobba24892013-12-07 19:26:57 +01002839 switch (family) {
2840 case AF_INET:
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002841 return __in_dev_arp_parms_get_rcu(dev);
Jiri Pirkobba24892013-12-07 19:26:57 +01002842 case AF_INET6:
2843 return __in6_dev_nd_parms_get_rcu(dev);
2844 }
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002845 return NULL;
2846}
2847
2848static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p,
2849 int index)
2850{
2851 struct net_device *dev;
2852 int family = neigh_parms_family(p);
2853
2854 rcu_read_lock();
2855 for_each_netdev_rcu(net, dev) {
2856 struct neigh_parms *dst_p =
2857 neigh_get_dev_parms_rcu(dev, family);
2858
2859 if (dst_p && !test_bit(index, dst_p->data_state))
2860 dst_p->data[index] = p->data[index];
2861 }
2862 rcu_read_unlock();
2863}
2864
2865static void neigh_proc_update(struct ctl_table *ctl, int write)
2866{
2867 struct net_device *dev = ctl->extra1;
2868 struct neigh_parms *p = ctl->extra2;
Jiri Pirko77d47af2013-12-10 23:55:07 +01002869 struct net *net = neigh_parms_net(p);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002870 int index = (int *) ctl->data - p->data;
2871
2872 if (!write)
2873 return;
2874
2875 set_bit(index, p->data_state);
2876 if (!dev) /* NULL dev means this is default value */
2877 neigh_copy_dflt_parms(net, p, index);
2878}
2879
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002880static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write,
2881 void __user *buffer,
2882 size_t *lenp, loff_t *ppos)
2883{
2884 struct ctl_table tmp = *ctl;
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002885 int ret;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002886
2887 tmp.extra1 = &zero;
2888 tmp.extra2 = &int_max;
2889
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002890 ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
2891 neigh_proc_update(ctl, write);
2892 return ret;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002893}
2894
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002895int neigh_proc_dointvec(struct ctl_table *ctl, int write,
2896 void __user *buffer, size_t *lenp, loff_t *ppos)
2897{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002898 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
2899
2900 neigh_proc_update(ctl, write);
2901 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002902}
2903EXPORT_SYMBOL(neigh_proc_dointvec);
2904
2905int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write,
2906 void __user *buffer,
2907 size_t *lenp, loff_t *ppos)
2908{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002909 int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
2910
2911 neigh_proc_update(ctl, write);
2912 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002913}
2914EXPORT_SYMBOL(neigh_proc_dointvec_jiffies);
2915
2916static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write,
2917 void __user *buffer,
2918 size_t *lenp, loff_t *ppos)
2919{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002920 int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos);
2921
2922 neigh_proc_update(ctl, write);
2923 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002924}
2925
2926int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write,
2927 void __user *buffer,
2928 size_t *lenp, loff_t *ppos)
2929{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002930 int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
2931
2932 neigh_proc_update(ctl, write);
2933 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002934}
2935EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies);
2936
2937static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write,
2938 void __user *buffer,
2939 size_t *lenp, loff_t *ppos)
2940{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002941 int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos);
2942
2943 neigh_proc_update(ctl, write);
2944 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002945}
2946
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002947#define NEIGH_PARMS_DATA_OFFSET(index) \
2948 (&((struct neigh_parms *) 0)->data[index])
2949
2950#define NEIGH_SYSCTL_ENTRY(attr, data_attr, name, mval, proc) \
2951 [NEIGH_VAR_ ## attr] = { \
2952 .procname = name, \
2953 .data = NEIGH_PARMS_DATA_OFFSET(NEIGH_VAR_ ## data_attr), \
2954 .maxlen = sizeof(int), \
2955 .mode = mval, \
2956 .proc_handler = proc, \
2957 }
2958
2959#define NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(attr, name) \
2960 NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_zero_intmax)
2961
2962#define NEIGH_SYSCTL_JIFFIES_ENTRY(attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002963 NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_jiffies)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002964
2965#define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002966 NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002967
2968#define NEIGH_SYSCTL_MS_JIFFIES_ENTRY(attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002969 NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002970
2971#define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002972 NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002973
2974#define NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(attr, data_attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002975 NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_unres_qlen)
Eric W. Biederman54716e32010-02-14 03:27:03 +00002976
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977static struct neigh_sysctl_table {
2978 struct ctl_table_header *sysctl_header;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002979 struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
Brian Haleyab32ea52006-09-22 14:15:41 -07002980} neigh_sysctl_template __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 .neigh_vars = {
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002982 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_PROBES, "mcast_solicit"),
2983 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(UCAST_PROBES, "ucast_solicit"),
2984 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(APP_PROBES, "app_solicit"),
2985 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(RETRANS_TIME, "retrans_time"),
2986 NEIGH_SYSCTL_JIFFIES_ENTRY(BASE_REACHABLE_TIME, "base_reachable_time"),
2987 NEIGH_SYSCTL_JIFFIES_ENTRY(DELAY_PROBE_TIME, "delay_first_probe_time"),
2988 NEIGH_SYSCTL_JIFFIES_ENTRY(GC_STALETIME, "gc_stale_time"),
2989 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(QUEUE_LEN_BYTES, "unres_qlen_bytes"),
2990 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(PROXY_QLEN, "proxy_qlen"),
2991 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(ANYCAST_DELAY, "anycast_delay"),
2992 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(PROXY_DELAY, "proxy_delay"),
2993 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(LOCKTIME, "locktime"),
2994 NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(QUEUE_LEN, QUEUE_LEN_BYTES, "unres_qlen"),
2995 NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(RETRANS_TIME_MS, RETRANS_TIME, "retrans_time_ms"),
2996 NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(BASE_REACHABLE_TIME_MS, BASE_REACHABLE_TIME, "base_reachable_time_ms"),
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002997 [NEIGH_VAR_GC_INTERVAL] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 .procname = "gc_interval",
2999 .maxlen = sizeof(int),
3000 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003001 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003003 [NEIGH_VAR_GC_THRESH1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 .procname = "gc_thresh1",
3005 .maxlen = sizeof(int),
3006 .mode = 0644,
Francesco Fusco555445c2013-07-24 10:39:06 +02003007 .extra1 = &zero,
3008 .extra2 = &int_max,
3009 .proc_handler = proc_dointvec_minmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003011 [NEIGH_VAR_GC_THRESH2] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 .procname = "gc_thresh2",
3013 .maxlen = sizeof(int),
3014 .mode = 0644,
Francesco Fusco555445c2013-07-24 10:39:06 +02003015 .extra1 = &zero,
3016 .extra2 = &int_max,
3017 .proc_handler = proc_dointvec_minmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003019 [NEIGH_VAR_GC_THRESH3] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 .procname = "gc_thresh3",
3021 .maxlen = sizeof(int),
3022 .mode = 0644,
Francesco Fusco555445c2013-07-24 10:39:06 +02003023 .extra1 = &zero,
3024 .extra2 = &int_max,
3025 .proc_handler = proc_dointvec_minmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 },
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11003027 {},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 },
3029};
3030
3031int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
Jiri Pirko73af6142013-12-07 19:26:55 +01003032 proc_handler *handler)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033{
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003034 int i;
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003035 struct neigh_sysctl_table *t;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003036 const char *dev_name_source;
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003037 char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ];
Jiri Pirko73af6142013-12-07 19:26:55 +01003038 char *p_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003040 t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 if (!t)
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003042 goto err;
3043
Jiri Pirkob194c1f2014-02-21 14:52:57 +01003044 for (i = 0; i < NEIGH_VAR_GC_INTERVAL; i++) {
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003045 t->neigh_vars[i].data += (long) p;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003046 t->neigh_vars[i].extra1 = dev;
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003047 t->neigh_vars[i].extra2 = p;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003048 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049
3050 if (dev) {
3051 dev_name_source = dev->name;
Eric W. Biedermand12af672007-10-18 03:05:25 -07003052 /* Terminate the table early */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003053 memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
3054 sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 } else {
Mathias Krause9ecf07a2014-07-12 22:36:44 +02003056 struct neigh_table *tbl = p->tbl;
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003057 dev_name_source = "default";
Mathias Krause9ecf07a2014-07-12 22:36:44 +02003058 t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = &tbl->gc_interval;
3059 t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = &tbl->gc_thresh1;
3060 t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = &tbl->gc_thresh2;
3061 t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = &tbl->gc_thresh3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 }
3063
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08003064 if (handler) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 /* RetransTime */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003066 t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067 /* ReachableTime */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003068 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 /* RetransTime (in milliseconds)*/
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003070 t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 /* ReachableTime (in milliseconds) */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003072 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 }
3074
Eric W. Biederman464dc802012-11-16 03:02:59 +00003075 /* Don't export sysctls to unprivileged users */
3076 if (neigh_parms_net(p)->user_ns != &init_user_ns)
3077 t->neigh_vars[0].procname = NULL;
3078
Jiri Pirko73af6142013-12-07 19:26:55 +01003079 switch (neigh_parms_family(p)) {
3080 case AF_INET:
3081 p_name = "ipv4";
3082 break;
3083 case AF_INET6:
3084 p_name = "ipv6";
3085 break;
3086 default:
3087 BUG();
3088 }
3089
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003090 snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s",
3091 p_name, dev_name_source);
Denis V. Lunev4ab438f2008-02-28 20:48:01 -08003092 t->sysctl_header =
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003093 register_net_sysctl(neigh_parms_net(p), neigh_path, t->neigh_vars);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003094 if (!t->sysctl_header)
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003095 goto free;
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003096
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 p->sysctl_table = t;
3098 return 0;
3099
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003100free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 kfree(t);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003102err:
3103 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09003105EXPORT_SYMBOL(neigh_sysctl_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106
3107void neigh_sysctl_unregister(struct neigh_parms *p)
3108{
3109 if (p->sysctl_table) {
3110 struct neigh_sysctl_table *t = p->sysctl_table;
3111 p->sysctl_table = NULL;
Eric W. Biederman5dd3df12012-04-19 13:24:33 +00003112 unregister_net_sysctl_table(t->sysctl_header);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 kfree(t);
3114 }
3115}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09003116EXPORT_SYMBOL(neigh_sysctl_unregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117
3118#endif /* CONFIG_SYSCTL */
3119
Thomas Grafc8822a42007-03-22 11:50:06 -07003120static int __init neigh_init(void)
3121{
Greg Rosec7ac8672011-06-10 01:27:09 +00003122 rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, NULL);
3123 rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, NULL);
3124 rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info, NULL);
Thomas Grafc8822a42007-03-22 11:50:06 -07003125
Greg Rosec7ac8672011-06-10 01:27:09 +00003126 rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
3127 NULL);
3128 rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, NULL);
Thomas Grafc8822a42007-03-22 11:50:06 -07003129
3130 return 0;
3131}
3132
3133subsys_initcall(neigh_init);
3134