blob: fe3c6eac5805788be5c1e1bda1375afff24c4126 [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
Amos Waterland45fc3b12005-09-24 16:53:16 -070059#ifdef CONFIG_PROC_FS
Arjan van de Ven9a321442007-02-12 00:55:35 -080060static const struct file_operations neigh_stat_seq_fops;
Amos Waterland45fc3b12005-09-24 16:53:16 -070061#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
63/*
64 Neighbour hash table buckets are protected with rwlock tbl->lock.
65
66 - All the scans/updates to hash buckets MUST be made under this lock.
67 - NOTHING clever should be made under this lock: no callbacks
68 to protocol backends, no attempts to send something to network.
69 It will result in deadlocks, if backend/driver wants to use neighbour
70 cache.
71 - If the entry requires some non-trivial actions, increase
72 its reference count and release table lock.
73
74 Neighbour entries are protected:
75 - with reference count.
76 - with rwlock neigh->lock
77
78 Reference count prevents destruction.
79
80 neigh->lock mainly serializes ll address data and its validity state.
81 However, the same lock is used to protect another entry fields:
82 - timer
83 - resolution queue
84
85 Again, nothing clever shall be made under neigh->lock,
86 the most complicated procedure, which we allow is dev->hard_header.
87 It is supposed, that dev->hard_header is simplistic and does
88 not make callbacks to neighbour tables.
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 */
90
David S. Miller8f40b162011-07-17 13:34:11 -070091static int neigh_blackhole(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -070092{
93 kfree_skb(skb);
94 return -ENETDOWN;
95}
96
Thomas Graf4f494552007-08-08 23:12:36 -070097static void neigh_cleanup_and_release(struct neighbour *neigh)
98{
99 if (neigh->parms->neigh_cleanup)
100 neigh->parms->neigh_cleanup(neigh);
101
Thomas Grafd961db32007-08-08 23:12:56 -0700102 __neigh_notify(neigh, RTM_DELNEIGH, 0);
Thomas Graf4f494552007-08-08 23:12:36 -0700103 neigh_release(neigh);
104}
105
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106/*
107 * It is random distribution in the interval (1/2)*base...(3/2)*base.
108 * It corresponds to default IPv6 settings and is not overridable,
109 * because it is really reasonable choice.
110 */
111
112unsigned long neigh_rand_reach_time(unsigned long base)
113{
Aruna-Hewapathirane63862b52014-01-11 07:15:59 -0500114 return base ? (prandom_u32() % base) + (base >> 1) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900116EXPORT_SYMBOL(neigh_rand_reach_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
118
119static int neigh_forced_gc(struct neigh_table *tbl)
120{
121 int shrunk = 0;
122 int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000123 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
125 NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
126
127 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000128 nht = rcu_dereference_protected(tbl->nht,
129 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -0700130 for (i = 0; i < (1 << nht->hash_shift); i++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700131 struct neighbour *n;
132 struct neighbour __rcu **np;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000134 np = &nht->hash_buckets[i];
Eric Dumazet767e97e2010-10-06 17:49:21 -0700135 while ((n = rcu_dereference_protected(*np,
136 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 /* Neighbour record may be discarded if:
138 * - nobody refers to it.
139 * - it is not permanent
140 */
141 write_lock(&n->lock);
142 if (atomic_read(&n->refcnt) == 1 &&
143 !(n->nud_state & NUD_PERMANENT)) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700144 rcu_assign_pointer(*np,
145 rcu_dereference_protected(n->next,
146 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 n->dead = 1;
148 shrunk = 1;
149 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -0700150 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 continue;
152 }
153 write_unlock(&n->lock);
154 np = &n->next;
155 }
156 }
157
158 tbl->last_flush = jiffies;
159
160 write_unlock_bh(&tbl->lock);
161
162 return shrunk;
163}
164
Pavel Emelyanova43d8992007-12-20 15:49:05 -0800165static void neigh_add_timer(struct neighbour *n, unsigned long when)
166{
167 neigh_hold(n);
168 if (unlikely(mod_timer(&n->timer, when))) {
169 printk("NEIGH: BUG, double timer add, state is %x\n",
170 n->nud_state);
171 dump_stack();
172 }
173}
174
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175static int neigh_del_timer(struct neighbour *n)
176{
177 if ((n->nud_state & NUD_IN_TIMER) &&
178 del_timer(&n->timer)) {
179 neigh_release(n);
180 return 1;
181 }
182 return 0;
183}
184
185static void pneigh_queue_purge(struct sk_buff_head *list)
186{
187 struct sk_buff *skb;
188
189 while ((skb = skb_dequeue(list)) != NULL) {
190 dev_put(skb->dev);
191 kfree_skb(skb);
192 }
193}
194
Herbert Xu49636bb2005-10-23 17:18:00 +1000195static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196{
197 int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000198 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000200 nht = rcu_dereference_protected(tbl->nht,
201 lockdep_is_held(&tbl->lock));
202
David S. Millercd089332011-07-11 01:28:12 -0700203 for (i = 0; i < (1 << nht->hash_shift); i++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700204 struct neighbour *n;
205 struct neighbour __rcu **np = &nht->hash_buckets[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
Eric Dumazet767e97e2010-10-06 17:49:21 -0700207 while ((n = rcu_dereference_protected(*np,
208 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 if (dev && n->dev != dev) {
210 np = &n->next;
211 continue;
212 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700213 rcu_assign_pointer(*np,
214 rcu_dereference_protected(n->next,
215 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 write_lock(&n->lock);
217 neigh_del_timer(n);
218 n->dead = 1;
219
220 if (atomic_read(&n->refcnt) != 1) {
221 /* The most unpleasant situation.
222 We must destroy neighbour entry,
223 but someone still uses it.
224
225 The destroy will be delayed until
226 the last user releases us, but
227 we must kill timers etc. and move
228 it to safe state.
229 */
Eric Dumazetc9ab4d82013-06-28 02:37:42 -0700230 __skb_queue_purge(&n->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000231 n->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 n->output = neigh_blackhole;
233 if (n->nud_state & NUD_VALID)
234 n->nud_state = NUD_NOARP;
235 else
236 n->nud_state = NUD_NONE;
Joe Perchesd5d427c2013-04-15 15:17:19 +0000237 neigh_dbg(2, "neigh %p is stray\n", n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 }
239 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -0700240 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 }
242 }
Herbert Xu49636bb2005-10-23 17:18:00 +1000243}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
Herbert Xu49636bb2005-10-23 17:18:00 +1000245void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
246{
247 write_lock_bh(&tbl->lock);
248 neigh_flush_dev(tbl, dev);
249 write_unlock_bh(&tbl->lock);
250}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900251EXPORT_SYMBOL(neigh_changeaddr);
Herbert Xu49636bb2005-10-23 17:18:00 +1000252
253int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
254{
255 write_lock_bh(&tbl->lock);
256 neigh_flush_dev(tbl, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 pneigh_ifdown(tbl, dev);
258 write_unlock_bh(&tbl->lock);
259
260 del_timer_sync(&tbl->proxy_timer);
261 pneigh_queue_purge(&tbl->proxy_queue);
262 return 0;
263}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900264EXPORT_SYMBOL(neigh_ifdown);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
David Miller596b9b62011-07-25 00:01:25 +0000266static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267{
268 struct neighbour *n = NULL;
269 unsigned long now = jiffies;
270 int entries;
271
272 entries = atomic_inc_return(&tbl->entries) - 1;
273 if (entries >= tbl->gc_thresh3 ||
274 (entries >= tbl->gc_thresh2 &&
275 time_after(now, tbl->last_flush + 5 * HZ))) {
276 if (!neigh_forced_gc(tbl) &&
277 entries >= tbl->gc_thresh3)
278 goto out_entries;
279 }
280
YOSHIFUJI Hideaki / 吉藤英明08433ef2013-01-24 00:44:23 +0000281 n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 if (!n)
283 goto out_entries;
284
Eric Dumazetc9ab4d82013-06-28 02:37:42 -0700285 __skb_queue_head_init(&n->arp_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 rwlock_init(&n->lock);
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +0000287 seqlock_init(&n->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 n->updated = n->used = now;
289 n->nud_state = NUD_NONE;
290 n->output = neigh_blackhole;
David S. Millerf6b72b622011-07-14 07:53:20 -0700291 seqlock_init(&n->hh.hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 n->parms = neigh_parms_clone(&tbl->parms);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800293 setup_timer(&n->timer, neigh_timer_handler, (unsigned long)n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295 NEIGH_CACHE_STAT_INC(tbl, allocs);
296 n->tbl = tbl;
297 atomic_set(&n->refcnt, 1);
298 n->dead = 1;
299out:
300 return n;
301
302out_entries:
303 atomic_dec(&tbl->entries);
304 goto out;
305}
306
David S. Miller2c2aba62011-12-28 15:06:58 -0500307static void neigh_get_hash_rnd(u32 *x)
308{
309 get_random_bytes(x, sizeof(*x));
310 *x |= 1;
311}
312
David S. Millercd089332011-07-11 01:28:12 -0700313static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314{
David S. Millercd089332011-07-11 01:28:12 -0700315 size_t size = (1 << shift) * sizeof(struct neighbour *);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000316 struct neigh_hash_table *ret;
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000317 struct neighbour __rcu **buckets;
David S. Miller2c2aba62011-12-28 15:06:58 -0500318 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000320 ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
321 if (!ret)
322 return NULL;
323 if (size <= PAGE_SIZE)
324 buckets = kzalloc(size, GFP_ATOMIC);
325 else
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000326 buckets = (struct neighbour __rcu **)
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000327 __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
328 get_order(size));
329 if (!buckets) {
330 kfree(ret);
331 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 }
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000333 ret->hash_buckets = buckets;
David S. Millercd089332011-07-11 01:28:12 -0700334 ret->hash_shift = shift;
David S. Miller2c2aba62011-12-28 15:06:58 -0500335 for (i = 0; i < NEIGH_NUM_HASH_RND; i++)
336 neigh_get_hash_rnd(&ret->hash_rnd[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 return ret;
338}
339
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000340static void neigh_hash_free_rcu(struct rcu_head *head)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341{
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000342 struct neigh_hash_table *nht = container_of(head,
343 struct neigh_hash_table,
344 rcu);
David S. Millercd089332011-07-11 01:28:12 -0700345 size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *);
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000346 struct neighbour __rcu **buckets = nht->hash_buckets;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
348 if (size <= PAGE_SIZE)
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000349 kfree(buckets);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 else
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000351 free_pages((unsigned long)buckets, get_order(size));
352 kfree(nht);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353}
354
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000355static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
David S. Millercd089332011-07-11 01:28:12 -0700356 unsigned long new_shift)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357{
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000358 unsigned int i, hash;
359 struct neigh_hash_table *new_nht, *old_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
361 NEIGH_CACHE_STAT_INC(tbl, hash_grows);
362
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000363 old_nht = rcu_dereference_protected(tbl->nht,
364 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -0700365 new_nht = neigh_hash_alloc(new_shift);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000366 if (!new_nht)
367 return old_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
David S. Millercd089332011-07-11 01:28:12 -0700369 for (i = 0; i < (1 << old_nht->hash_shift); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 struct neighbour *n, *next;
371
Eric Dumazet767e97e2010-10-06 17:49:21 -0700372 for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
373 lockdep_is_held(&tbl->lock));
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000374 n != NULL;
375 n = next) {
376 hash = tbl->hash(n->primary_key, n->dev,
377 new_nht->hash_rnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
David S. Millercd089332011-07-11 01:28:12 -0700379 hash >>= (32 - new_nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700380 next = rcu_dereference_protected(n->next,
381 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
Eric Dumazet767e97e2010-10-06 17:49:21 -0700383 rcu_assign_pointer(n->next,
384 rcu_dereference_protected(
385 new_nht->hash_buckets[hash],
386 lockdep_is_held(&tbl->lock)));
387 rcu_assign_pointer(new_nht->hash_buckets[hash], n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 }
389 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000391 rcu_assign_pointer(tbl->nht, new_nht);
392 call_rcu(&old_nht->rcu, neigh_hash_free_rcu);
393 return new_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394}
395
396struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
397 struct net_device *dev)
398{
399 struct neighbour *n;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900400
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 NEIGH_CACHE_STAT_INC(tbl, lookups);
402
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000403 rcu_read_lock_bh();
Eric W. Biederman60395a22015-03-03 17:10:44 -0600404 n = __neigh_lookup_noref(tbl, pkey, dev);
405 if (n) {
406 if (!atomic_inc_not_zero(&n->refcnt))
407 n = NULL;
408 NEIGH_CACHE_STAT_INC(tbl, hits);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700410
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000411 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 return n;
413}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900414EXPORT_SYMBOL(neigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
Eric W. Biederman426b5302008-01-24 00:13:18 -0800416struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
417 const void *pkey)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418{
419 struct neighbour *n;
420 int key_len = tbl->key_len;
Pavel Emelyanovbc4bf5f2008-02-23 19:57:02 -0800421 u32 hash_val;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000422 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
424 NEIGH_CACHE_STAT_INC(tbl, lookups);
425
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000426 rcu_read_lock_bh();
427 nht = rcu_dereference_bh(tbl->nht);
David S. Millercd089332011-07-11 01:28:12 -0700428 hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700429
430 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
431 n != NULL;
432 n = rcu_dereference_bh(n->next)) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800433 if (!memcmp(n->primary_key, pkey, key_len) &&
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +0900434 net_eq(dev_net(n->dev), net)) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700435 if (!atomic_inc_not_zero(&n->refcnt))
436 n = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 NEIGH_CACHE_STAT_INC(tbl, hits);
438 break;
439 }
440 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700441
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000442 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 return n;
444}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900445EXPORT_SYMBOL(neigh_lookup_nodev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446
David S. Millera263b302012-07-02 02:02:15 -0700447struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
448 struct net_device *dev, bool want_ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449{
450 u32 hash_val;
451 int key_len = tbl->key_len;
452 int error;
David Miller596b9b62011-07-25 00:01:25 +0000453 struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000454 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
456 if (!n) {
457 rc = ERR_PTR(-ENOBUFS);
458 goto out;
459 }
460
461 memcpy(n->primary_key, pkey, key_len);
462 n->dev = dev;
463 dev_hold(dev);
464
465 /* Protocol specific setup. */
466 if (tbl->constructor && (error = tbl->constructor(n)) < 0) {
467 rc = ERR_PTR(error);
468 goto out_neigh_release;
469 }
470
David Millerda6a8fa2011-07-25 00:01:38 +0000471 if (dev->netdev_ops->ndo_neigh_construct) {
472 error = dev->netdev_ops->ndo_neigh_construct(n);
473 if (error < 0) {
474 rc = ERR_PTR(error);
475 goto out_neigh_release;
476 }
477 }
478
David S. Miller447f2192011-12-19 15:04:41 -0500479 /* Device specific setup. */
480 if (n->parms->neigh_setup &&
481 (error = n->parms->neigh_setup(n)) < 0) {
482 rc = ERR_PTR(error);
483 goto out_neigh_release;
484 }
485
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100486 n->confirmed = jiffies - (NEIGH_VAR(n->parms, BASE_REACHABLE_TIME) << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
488 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000489 nht = rcu_dereference_protected(tbl->nht,
490 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491
David S. Millercd089332011-07-11 01:28:12 -0700492 if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
493 nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
David S. Millercd089332011-07-11 01:28:12 -0700495 hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
497 if (n->parms->dead) {
498 rc = ERR_PTR(-EINVAL);
499 goto out_tbl_unlock;
500 }
501
Eric Dumazet767e97e2010-10-06 17:49:21 -0700502 for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
503 lockdep_is_held(&tbl->lock));
504 n1 != NULL;
505 n1 = rcu_dereference_protected(n1->next,
506 lockdep_is_held(&tbl->lock))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) {
David S. Millera263b302012-07-02 02:02:15 -0700508 if (want_ref)
509 neigh_hold(n1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 rc = n1;
511 goto out_tbl_unlock;
512 }
513 }
514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 n->dead = 0;
David S. Millera263b302012-07-02 02:02:15 -0700516 if (want_ref)
517 neigh_hold(n);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700518 rcu_assign_pointer(n->next,
519 rcu_dereference_protected(nht->hash_buckets[hash_val],
520 lockdep_is_held(&tbl->lock)));
521 rcu_assign_pointer(nht->hash_buckets[hash_val], n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 write_unlock_bh(&tbl->lock);
Joe Perchesd5d427c2013-04-15 15:17:19 +0000523 neigh_dbg(2, "neigh %p is created\n", n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 rc = n;
525out:
526 return rc;
527out_tbl_unlock:
528 write_unlock_bh(&tbl->lock);
529out_neigh_release:
530 neigh_release(n);
531 goto out;
532}
David S. Millera263b302012-07-02 02:02:15 -0700533EXPORT_SYMBOL(__neigh_create);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900535static u32 pneigh_hash(const void *pkey, int key_len)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700536{
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700537 u32 hash_val = *(u32 *)(pkey + key_len - 4);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700538 hash_val ^= (hash_val >> 16);
539 hash_val ^= hash_val >> 8;
540 hash_val ^= hash_val >> 4;
541 hash_val &= PNEIGH_HASHMASK;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900542 return hash_val;
543}
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700544
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900545static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
546 struct net *net,
547 const void *pkey,
548 int key_len,
549 struct net_device *dev)
550{
551 while (n) {
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700552 if (!memcmp(n->key, pkey, key_len) &&
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900553 net_eq(pneigh_net(n), net) &&
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700554 (n->dev == dev || !n->dev))
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900555 return n;
556 n = n->next;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700557 }
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900558 return NULL;
559}
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700560
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900561struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
562 struct net *net, const void *pkey, struct net_device *dev)
563{
564 int key_len = tbl->key_len;
565 u32 hash_val = pneigh_hash(pkey, key_len);
566
567 return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
568 net, pkey, key_len, dev);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700569}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900570EXPORT_SYMBOL_GPL(__pneigh_lookup);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700571
Eric W. Biederman426b5302008-01-24 00:13:18 -0800572struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
573 struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 struct net_device *dev, int creat)
575{
576 struct pneigh_entry *n;
577 int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900578 u32 hash_val = pneigh_hash(pkey, key_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
580 read_lock_bh(&tbl->lock);
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900581 n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
582 net, pkey, key_len, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 read_unlock_bh(&tbl->lock);
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900584
585 if (n || !creat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 goto out;
587
Pavel Emelyanov4ae28942007-10-15 12:54:15 -0700588 ASSERT_RTNL();
589
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
591 if (!n)
592 goto out;
593
Eric Dumazete42ea982008-11-12 00:54:54 -0800594 write_pnet(&n->net, hold_net(net));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 memcpy(n->key, pkey, key_len);
596 n->dev = dev;
597 if (dev)
598 dev_hold(dev);
599
600 if (tbl->pconstructor && tbl->pconstructor(n)) {
601 if (dev)
602 dev_put(dev);
Denis V. Lunevda12f732008-02-20 00:26:16 -0800603 release_net(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 kfree(n);
605 n = NULL;
606 goto out;
607 }
608
609 write_lock_bh(&tbl->lock);
610 n->next = tbl->phash_buckets[hash_val];
611 tbl->phash_buckets[hash_val] = n;
612 write_unlock_bh(&tbl->lock);
613out:
614 return n;
615}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900616EXPORT_SYMBOL(pneigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
618
Eric W. Biederman426b5302008-01-24 00:13:18 -0800619int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 struct net_device *dev)
621{
622 struct pneigh_entry *n, **np;
623 int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900624 u32 hash_val = pneigh_hash(pkey, key_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
626 write_lock_bh(&tbl->lock);
627 for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
628 np = &n->next) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800629 if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +0900630 net_eq(pneigh_net(n), net)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 *np = n->next;
632 write_unlock_bh(&tbl->lock);
633 if (tbl->pdestructor)
634 tbl->pdestructor(n);
635 if (n->dev)
636 dev_put(n->dev);
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +0900637 release_net(pneigh_net(n));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 kfree(n);
639 return 0;
640 }
641 }
642 write_unlock_bh(&tbl->lock);
643 return -ENOENT;
644}
645
646static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
647{
648 struct pneigh_entry *n, **np;
649 u32 h;
650
651 for (h = 0; h <= PNEIGH_HASHMASK; h++) {
652 np = &tbl->phash_buckets[h];
653 while ((n = *np) != NULL) {
654 if (!dev || n->dev == dev) {
655 *np = n->next;
656 if (tbl->pdestructor)
657 tbl->pdestructor(n);
658 if (n->dev)
659 dev_put(n->dev);
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +0900660 release_net(pneigh_net(n));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 kfree(n);
662 continue;
663 }
664 np = &n->next;
665 }
666 }
667 return -ENOENT;
668}
669
Denis V. Lunev06f05112008-01-24 00:30:58 -0800670static void neigh_parms_destroy(struct neigh_parms *parms);
671
672static inline void neigh_parms_put(struct neigh_parms *parms)
673{
674 if (atomic_dec_and_test(&parms->refcnt))
675 neigh_parms_destroy(parms);
676}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
678/*
679 * neighbour must already be out of the table;
680 *
681 */
682void neigh_destroy(struct neighbour *neigh)
683{
David Millerda6a8fa2011-07-25 00:01:38 +0000684 struct net_device *dev = neigh->dev;
685
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
687
688 if (!neigh->dead) {
Joe Perchese005d192012-05-16 19:58:40 +0000689 pr_warn("Destroying alive neighbour %p\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 dump_stack();
691 return;
692 }
693
694 if (neigh_del_timer(neigh))
Joe Perchese005d192012-05-16 19:58:40 +0000695 pr_warn("Impossible event\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696
Eric Dumazetc9ab4d82013-06-28 02:37:42 -0700697 write_lock_bh(&neigh->lock);
698 __skb_queue_purge(&neigh->arp_queue);
699 write_unlock_bh(&neigh->lock);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000700 neigh->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
David S. Miller447f2192011-12-19 15:04:41 -0500702 if (dev->netdev_ops->ndo_neigh_destroy)
703 dev->netdev_ops->ndo_neigh_destroy(neigh);
704
David Millerda6a8fa2011-07-25 00:01:38 +0000705 dev_put(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 neigh_parms_put(neigh->parms);
707
Joe Perchesd5d427c2013-04-15 15:17:19 +0000708 neigh_dbg(2, "neigh %p is destroyed\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710 atomic_dec(&neigh->tbl->entries);
David Miller5b8b0062011-07-25 00:01:22 +0000711 kfree_rcu(neigh, rcu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900713EXPORT_SYMBOL(neigh_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
715/* Neighbour state is suspicious;
716 disable fast path.
717
718 Called with write_locked neigh.
719 */
720static void neigh_suspect(struct neighbour *neigh)
721{
Joe Perchesd5d427c2013-04-15 15:17:19 +0000722 neigh_dbg(2, "neigh %p is suspected\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
724 neigh->output = neigh->ops->output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725}
726
727/* Neighbour state is OK;
728 enable fast path.
729
730 Called with write_locked neigh.
731 */
732static void neigh_connect(struct neighbour *neigh)
733{
Joe Perchesd5d427c2013-04-15 15:17:19 +0000734 neigh_dbg(2, "neigh %p is connected\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
736 neigh->output = neigh->ops->connected_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737}
738
Eric Dumazete4c4e442009-07-30 03:15:07 +0000739static void neigh_periodic_work(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740{
Eric Dumazete4c4e442009-07-30 03:15:07 +0000741 struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700742 struct neighbour *n;
743 struct neighbour __rcu **np;
Eric Dumazete4c4e442009-07-30 03:15:07 +0000744 unsigned int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000745 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746
747 NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
748
Eric Dumazete4c4e442009-07-30 03:15:07 +0000749 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000750 nht = rcu_dereference_protected(tbl->nht,
751 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
753 /*
754 * periodically recompute ReachableTime from random function
755 */
756
Eric Dumazete4c4e442009-07-30 03:15:07 +0000757 if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 struct neigh_parms *p;
Eric Dumazete4c4e442009-07-30 03:15:07 +0000759 tbl->last_rand = jiffies;
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +0100760 list_for_each_entry(p, &tbl->parms_list, list)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 p->reachable_time =
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100762 neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 }
764
Duan Jiongfeff9ab2014-02-27 17:14:41 +0800765 if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
766 goto out;
767
David S. Millercd089332011-07-11 01:28:12 -0700768 for (i = 0 ; i < (1 << nht->hash_shift); i++) {
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000769 np = &nht->hash_buckets[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
Eric Dumazet767e97e2010-10-06 17:49:21 -0700771 while ((n = rcu_dereference_protected(*np,
772 lockdep_is_held(&tbl->lock))) != NULL) {
Eric Dumazete4c4e442009-07-30 03:15:07 +0000773 unsigned int state;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774
Eric Dumazete4c4e442009-07-30 03:15:07 +0000775 write_lock(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
Eric Dumazete4c4e442009-07-30 03:15:07 +0000777 state = n->nud_state;
778 if (state & (NUD_PERMANENT | NUD_IN_TIMER)) {
779 write_unlock(&n->lock);
780 goto next_elt;
781 }
782
783 if (time_before(n->used, n->confirmed))
784 n->used = n->confirmed;
785
786 if (atomic_read(&n->refcnt) == 1 &&
787 (state == NUD_FAILED ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100788 time_after(jiffies, n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) {
Eric Dumazete4c4e442009-07-30 03:15:07 +0000789 *np = n->next;
790 n->dead = 1;
791 write_unlock(&n->lock);
792 neigh_cleanup_and_release(n);
793 continue;
794 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 write_unlock(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
797next_elt:
Eric Dumazete4c4e442009-07-30 03:15:07 +0000798 np = &n->next;
799 }
800 /*
801 * It's fine to release lock here, even if hash table
802 * grows while we are preempted.
803 */
804 write_unlock_bh(&tbl->lock);
805 cond_resched();
806 write_lock_bh(&tbl->lock);
Michel Machado84338a62012-02-21 16:04:13 -0500807 nht = rcu_dereference_protected(tbl->nht,
808 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 }
YOSHIFUJI Hideaki / 吉藤英明27246802013-01-22 05:20:05 +0000810out:
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100811 /* Cycle through all hash buckets every BASE_REACHABLE_TIME/2 ticks.
812 * ARP entry timeouts range from 1/2 BASE_REACHABLE_TIME to 3/2
813 * BASE_REACHABLE_TIME.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 */
viresh kumarf6180022014-01-22 12:23:33 +0530815 queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100816 NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME) >> 1);
Eric Dumazete4c4e442009-07-30 03:15:07 +0000817 write_unlock_bh(&tbl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818}
819
820static __inline__ int neigh_max_probes(struct neighbour *n)
821{
822 struct neigh_parms *p = n->parms;
Timo Teräsa960ff82014-02-26 11:43:04 +0200823 int max_probes = NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES);
824 if (!(n->nud_state & NUD_PROBE))
825 max_probes += NEIGH_VAR(p, MCAST_PROBES);
826 return max_probes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827}
828
Timo Teras5ef12d92009-06-11 04:16:28 -0700829static void neigh_invalidate(struct neighbour *neigh)
Eric Dumazet0a141502010-03-09 19:40:54 +0000830 __releases(neigh->lock)
831 __acquires(neigh->lock)
Timo Teras5ef12d92009-06-11 04:16:28 -0700832{
833 struct sk_buff *skb;
834
835 NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
Joe Perchesd5d427c2013-04-15 15:17:19 +0000836 neigh_dbg(2, "neigh %p is failed\n", neigh);
Timo Teras5ef12d92009-06-11 04:16:28 -0700837 neigh->updated = jiffies;
838
839 /* It is very thin place. report_unreachable is very complicated
840 routine. Particularly, it can hit the same neighbour entry!
841
842 So that, we try to be accurate and avoid dead loop. --ANK
843 */
844 while (neigh->nud_state == NUD_FAILED &&
845 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
846 write_unlock(&neigh->lock);
847 neigh->ops->error_report(neigh, skb);
848 write_lock(&neigh->lock);
849 }
Eric Dumazetc9ab4d82013-06-28 02:37:42 -0700850 __skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000851 neigh->arp_queue_len_bytes = 0;
Timo Teras5ef12d92009-06-11 04:16:28 -0700852}
853
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000854static void neigh_probe(struct neighbour *neigh)
855 __releases(neigh->lock)
856{
Hannes Frederic Sowa4ed377e2013-09-21 06:32:34 +0200857 struct sk_buff *skb = skb_peek_tail(&neigh->arp_queue);
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000858 /* keep skb alive even if arp_queue overflows */
859 if (skb)
860 skb = skb_copy(skb, GFP_ATOMIC);
861 write_unlock(&neigh->lock);
862 neigh->ops->solicit(neigh, skb);
863 atomic_inc(&neigh->probes);
864 kfree_skb(skb);
865}
866
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867/* Called when a timer expires for a neighbour entry. */
868
869static void neigh_timer_handler(unsigned long arg)
870{
871 unsigned long now, next;
872 struct neighbour *neigh = (struct neighbour *)arg;
Eric Dumazet95c96172012-04-15 05:58:06 +0000873 unsigned int state;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 int notify = 0;
875
876 write_lock(&neigh->lock);
877
878 state = neigh->nud_state;
879 now = jiffies;
880 next = now + HZ;
881
David S. Miller045f7b32011-11-01 17:45:55 -0400882 if (!(state & NUD_IN_TIMER))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
885 if (state & NUD_REACHABLE) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900886 if (time_before_eq(now,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 neigh->confirmed + neigh->parms->reachable_time)) {
Joe Perchesd5d427c2013-04-15 15:17:19 +0000888 neigh_dbg(2, "neigh %p is still alive\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 next = neigh->confirmed + neigh->parms->reachable_time;
890 } else if (time_before_eq(now,
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100891 neigh->used +
892 NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
Joe Perchesd5d427c2013-04-15 15:17:19 +0000893 neigh_dbg(2, "neigh %p is delayed\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800895 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 neigh_suspect(neigh);
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100897 next = now + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 } else {
Joe Perchesd5d427c2013-04-15 15:17:19 +0000899 neigh_dbg(2, "neigh %p is suspected\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 neigh->nud_state = NUD_STALE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800901 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 neigh_suspect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -0700903 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 }
905 } else if (state & NUD_DELAY) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900906 if (time_before_eq(now,
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100907 neigh->confirmed +
908 NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
Joe Perchesd5d427c2013-04-15 15:17:19 +0000909 neigh_dbg(2, "neigh %p is now reachable\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 neigh->nud_state = NUD_REACHABLE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800911 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 neigh_connect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -0700913 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 next = neigh->confirmed + neigh->parms->reachable_time;
915 } else {
Joe Perchesd5d427c2013-04-15 15:17:19 +0000916 neigh_dbg(2, "neigh %p is probed\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 neigh->nud_state = NUD_PROBE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800918 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 atomic_set(&neigh->probes, 0);
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100920 next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 }
922 } else {
923 /* NUD_PROBE|NUD_INCOMPLETE */
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100924 next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 }
926
927 if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
928 atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 neigh->nud_state = NUD_FAILED;
930 notify = 1;
Timo Teras5ef12d92009-06-11 04:16:28 -0700931 neigh_invalidate(neigh);
Duan Jiong5e2c21d2014-02-27 17:03:03 +0800932 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 }
934
935 if (neigh->nud_state & NUD_IN_TIMER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 if (time_before(next, jiffies + HZ/2))
937 next = jiffies + HZ/2;
Herbert Xu6fb99742005-10-23 16:37:48 +1000938 if (!mod_timer(&neigh->timer, next))
939 neigh_hold(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 }
941 if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000942 neigh_probe(neigh);
David S. Miller9ff56602008-02-17 18:39:54 -0800943 } else {
David S. Miller69cc64d2008-02-11 21:45:44 -0800944out:
David S. Miller9ff56602008-02-17 18:39:54 -0800945 write_unlock(&neigh->lock);
946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
Thomas Grafd961db32007-08-08 23:12:56 -0700948 if (notify)
949 neigh_update_notify(neigh);
950
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 neigh_release(neigh);
952}
953
954int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
955{
956 int rc;
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000957 bool immediate_probe = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
959 write_lock_bh(&neigh->lock);
960
961 rc = 0;
962 if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
963 goto out_unlock_bh;
964
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100966 if (NEIGH_VAR(neigh->parms, MCAST_PROBES) +
967 NEIGH_VAR(neigh->parms, APP_PROBES)) {
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000968 unsigned long next, now = jiffies;
969
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100970 atomic_set(&neigh->probes,
971 NEIGH_VAR(neigh->parms, UCAST_PROBES));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 neigh->nud_state = NUD_INCOMPLETE;
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000973 neigh->updated = now;
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100974 next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
975 HZ/2);
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000976 neigh_add_timer(neigh, next);
977 immediate_probe = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 } else {
979 neigh->nud_state = NUD_FAILED;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800980 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 write_unlock_bh(&neigh->lock);
982
Wei Yongjunf3fbbe02009-02-25 00:37:32 +0000983 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 return 1;
985 }
986 } else if (neigh->nud_state & NUD_STALE) {
Joe Perchesd5d427c2013-04-15 15:17:19 +0000987 neigh_dbg(2, "neigh %p is delayed\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800989 neigh->updated = jiffies;
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100990 neigh_add_timer(neigh, jiffies +
991 NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 }
993
994 if (neigh->nud_state == NUD_INCOMPLETE) {
995 if (skb) {
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000996 while (neigh->arp_queue_len_bytes + skb->truesize >
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100997 NEIGH_VAR(neigh->parms, QUEUE_LEN_BYTES)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 struct sk_buff *buff;
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000999
David S. Millerf72051b2008-09-23 01:11:18 -07001000 buff = __skb_dequeue(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001001 if (!buff)
1002 break;
1003 neigh->arp_queue_len_bytes -= buff->truesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 kfree_skb(buff);
Neil Horman9a6d2762008-07-16 20:50:49 -07001005 NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 }
Eric Dumazeta4731132010-05-27 16:09:39 -07001007 skb_dst_force(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 __skb_queue_tail(&neigh->arp_queue, skb);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001009 neigh->arp_queue_len_bytes += skb->truesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 }
1011 rc = 1;
1012 }
1013out_unlock_bh:
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001014 if (immediate_probe)
1015 neigh_probe(neigh);
1016 else
1017 write_unlock(&neigh->lock);
1018 local_bh_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 return rc;
1020}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001021EXPORT_SYMBOL(__neigh_event_send);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
David S. Millerf6b72b622011-07-14 07:53:20 -07001023static void neigh_update_hhs(struct neighbour *neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024{
1025 struct hh_cache *hh;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001026 void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
Doug Kehn91a72a72010-07-14 18:02:16 -07001027 = NULL;
1028
1029 if (neigh->dev->header_ops)
1030 update = neigh->dev->header_ops->cache_update;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031
1032 if (update) {
David S. Millerf6b72b622011-07-14 07:53:20 -07001033 hh = &neigh->hh;
1034 if (hh->hh_len) {
Stephen Hemminger3644f0c2006-12-07 15:08:17 -08001035 write_seqlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 update(hh, neigh->dev, neigh->ha);
Stephen Hemminger3644f0c2006-12-07 15:08:17 -08001037 write_sequnlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 }
1039 }
1040}
1041
1042
1043
1044/* Generic update routine.
1045 -- lladdr is new lladdr or NULL, if it is not supplied.
1046 -- new is new state.
1047 -- flags
1048 NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr,
1049 if it is different.
1050 NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected"
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001051 lladdr instead of overriding it
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 if it is different.
1053 It also allows to retain current state
1054 if lladdr is unchanged.
1055 NEIGH_UPDATE_F_ADMIN means that the change is administrative.
1056
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001057 NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 NTF_ROUTER flag.
1059 NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as
1060 a router.
1061
1062 Caller MUST hold reference count on the entry.
1063 */
1064
1065int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
1066 u32 flags)
1067{
1068 u8 old;
1069 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 int notify = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 struct net_device *dev;
1072 int update_isrouter = 0;
1073
1074 write_lock_bh(&neigh->lock);
1075
1076 dev = neigh->dev;
1077 old = neigh->nud_state;
1078 err = -EPERM;
1079
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001080 if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 (old & (NUD_NOARP | NUD_PERMANENT)))
1082 goto out;
1083
1084 if (!(new & NUD_VALID)) {
1085 neigh_del_timer(neigh);
1086 if (old & NUD_CONNECTED)
1087 neigh_suspect(neigh);
1088 neigh->nud_state = new;
1089 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 notify = old & NUD_VALID;
Timo Teras5ef12d92009-06-11 04:16:28 -07001091 if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
1092 (new & NUD_FAILED)) {
1093 neigh_invalidate(neigh);
1094 notify = 1;
1095 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 goto out;
1097 }
1098
1099 /* Compare new lladdr with cached one */
1100 if (!dev->addr_len) {
1101 /* First case: device needs no address. */
1102 lladdr = neigh->ha;
1103 } else if (lladdr) {
1104 /* The second case: if something is already cached
1105 and a new address is proposed:
1106 - compare new & old
1107 - if they are different, check override flag
1108 */
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001109 if ((old & NUD_VALID) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 !memcmp(lladdr, neigh->ha, dev->addr_len))
1111 lladdr = neigh->ha;
1112 } else {
1113 /* No address is supplied; if we know something,
1114 use it, otherwise discard the request.
1115 */
1116 err = -EINVAL;
1117 if (!(old & NUD_VALID))
1118 goto out;
1119 lladdr = neigh->ha;
1120 }
1121
1122 if (new & NUD_CONNECTED)
1123 neigh->confirmed = jiffies;
1124 neigh->updated = jiffies;
1125
1126 /* If entry was valid and address is not changed,
1127 do not change entry state, if new one is STALE.
1128 */
1129 err = 0;
1130 update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
1131 if (old & NUD_VALID) {
1132 if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {
1133 update_isrouter = 0;
1134 if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&
1135 (old & NUD_CONNECTED)) {
1136 lladdr = neigh->ha;
1137 new = NUD_STALE;
1138 } else
1139 goto out;
1140 } else {
1141 if (lladdr == neigh->ha && new == NUD_STALE &&
1142 ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) ||
1143 (old & NUD_CONNECTED))
1144 )
1145 new = old;
1146 }
1147 }
1148
1149 if (new != old) {
1150 neigh_del_timer(neigh);
Pavel Emelyanova43d8992007-12-20 15:49:05 -08001151 if (new & NUD_IN_TIMER)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001152 neigh_add_timer(neigh, (jiffies +
1153 ((new & NUD_REACHABLE) ?
David S. Miller667347f2005-09-27 12:07:44 -07001154 neigh->parms->reachable_time :
1155 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 neigh->nud_state = new;
Bob Gilligan53385d22013-12-15 13:39:56 -08001157 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 }
1159
1160 if (lladdr != neigh->ha) {
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001161 write_seqlock(&neigh->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 memcpy(&neigh->ha, lladdr, dev->addr_len);
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001163 write_sequnlock(&neigh->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 neigh_update_hhs(neigh);
1165 if (!(new & NUD_CONNECTED))
1166 neigh->confirmed = jiffies -
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001167 (NEIGH_VAR(neigh->parms, BASE_REACHABLE_TIME) << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 }
1170 if (new == old)
1171 goto out;
1172 if (new & NUD_CONNECTED)
1173 neigh_connect(neigh);
1174 else
1175 neigh_suspect(neigh);
1176 if (!(old & NUD_VALID)) {
1177 struct sk_buff *skb;
1178
1179 /* Again: avoid dead loop if something went wrong */
1180
1181 while (neigh->nud_state & NUD_VALID &&
1182 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
David S. Miller69cce1d2011-07-17 23:09:49 -07001183 struct dst_entry *dst = skb_dst(skb);
1184 struct neighbour *n2, *n1 = neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 write_unlock_bh(&neigh->lock);
roy.qing.li@gmail.come049f282011-10-17 22:32:42 +00001186
1187 rcu_read_lock();
David S. Miller13a43d92012-07-02 22:15:37 -07001188
1189 /* Why not just use 'neigh' as-is? The problem is that
1190 * things such as shaper, eql, and sch_teql can end up
1191 * using alternative, different, neigh objects to output
1192 * the packet in the output path. So what we need to do
1193 * here is re-lookup the top-level neigh in the path so
1194 * we can reinject the packet there.
1195 */
1196 n2 = NULL;
1197 if (dst) {
1198 n2 = dst_neigh_lookup_skb(dst, skb);
1199 if (n2)
1200 n1 = n2;
1201 }
David S. Miller8f40b162011-07-17 13:34:11 -07001202 n1->output(n1, skb);
David S. Miller13a43d92012-07-02 22:15:37 -07001203 if (n2)
1204 neigh_release(n2);
roy.qing.li@gmail.come049f282011-10-17 22:32:42 +00001205 rcu_read_unlock();
1206
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 write_lock_bh(&neigh->lock);
1208 }
Eric Dumazetc9ab4d82013-06-28 02:37:42 -07001209 __skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001210 neigh->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 }
1212out:
1213 if (update_isrouter) {
1214 neigh->flags = (flags & NEIGH_UPDATE_F_ISROUTER) ?
1215 (neigh->flags | NTF_ROUTER) :
1216 (neigh->flags & ~NTF_ROUTER);
1217 }
1218 write_unlock_bh(&neigh->lock);
Tom Tucker8d717402006-07-30 20:43:36 -07001219
1220 if (notify)
Thomas Grafd961db32007-08-08 23:12:56 -07001221 neigh_update_notify(neigh);
1222
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 return err;
1224}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001225EXPORT_SYMBOL(neigh_update);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
Jiri Benc7e980562013-12-11 13:48:20 +01001227/* Update the neigh to listen temporarily for probe responses, even if it is
1228 * in a NUD_FAILED state. The caller has to hold neigh->lock for writing.
1229 */
1230void __neigh_set_probe_once(struct neighbour *neigh)
1231{
1232 neigh->updated = jiffies;
1233 if (!(neigh->nud_state & NUD_FAILED))
1234 return;
Duan Jiong2176d5d2014-05-09 13:16:48 +08001235 neigh->nud_state = NUD_INCOMPLETE;
1236 atomic_set(&neigh->probes, neigh_max_probes(neigh));
Jiri Benc7e980562013-12-11 13:48:20 +01001237 neigh_add_timer(neigh,
1238 jiffies + NEIGH_VAR(neigh->parms, RETRANS_TIME));
1239}
1240EXPORT_SYMBOL(__neigh_set_probe_once);
1241
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242struct neighbour *neigh_event_ns(struct neigh_table *tbl,
1243 u8 *lladdr, void *saddr,
1244 struct net_device *dev)
1245{
1246 struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
1247 lladdr || !dev->addr_len);
1248 if (neigh)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001249 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 NEIGH_UPDATE_F_OVERRIDE);
1251 return neigh;
1252}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001253EXPORT_SYMBOL(neigh_event_ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254
Eric Dumazet34d101d2010-10-11 09:16:57 -07001255/* called with read_lock_bh(&n->lock); */
Eric W. Biedermanbdf53c52015-03-02 00:13:22 -06001256static void neigh_hh_init(struct neighbour *n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257{
Eric W. Biedermanbdf53c52015-03-02 00:13:22 -06001258 struct net_device *dev = n->dev;
1259 __be16 prot = n->tbl->protocol;
David S. Millerf6b72b622011-07-14 07:53:20 -07001260 struct hh_cache *hh = &n->hh;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001261
1262 write_lock_bh(&n->lock);
Eric Dumazet34d101d2010-10-11 09:16:57 -07001263
David S. Millerf6b72b622011-07-14 07:53:20 -07001264 /* Only one thread can come in here and initialize the
1265 * hh_cache entry.
1266 */
David S. Millerb23b5452011-07-16 17:45:02 -07001267 if (!hh->hh_len)
1268 dev->header_ops->cache(n, hh, prot);
David S. Millerf6b72b622011-07-14 07:53:20 -07001269
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001270 write_unlock_bh(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271}
1272
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273/* Slow and careful. */
1274
David S. Miller8f40b162011-07-17 13:34:11 -07001275int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 int rc = 0;
1278
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 if (!neigh_event_send(neigh, skb)) {
1280 int err;
1281 struct net_device *dev = neigh->dev;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001282 unsigned int seq;
Eric Dumazet34d101d2010-10-11 09:16:57 -07001283
David S. Millerf6b72b622011-07-14 07:53:20 -07001284 if (dev->header_ops->cache && !neigh->hh.hh_len)
Eric W. Biedermanbdf53c52015-03-02 00:13:22 -06001285 neigh_hh_init(neigh);
Eric Dumazet34d101d2010-10-11 09:16:57 -07001286
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001287 do {
ramesh.nagappa@gmail.come1f16502012-10-05 19:10:15 +00001288 __skb_pull(skb, skb_network_offset(skb));
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001289 seq = read_seqbegin(&neigh->ha_lock);
1290 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1291 neigh->ha, NULL, skb->len);
1292 } while (read_seqretry(&neigh->ha_lock, seq));
Eric Dumazet34d101d2010-10-11 09:16:57 -07001293
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 if (err >= 0)
David S. Miller542d4d62011-07-16 18:06:24 -07001295 rc = dev_queue_xmit(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 else
1297 goto out_kfree_skb;
1298 }
1299out:
1300 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301out_kfree_skb:
1302 rc = -EINVAL;
1303 kfree_skb(skb);
1304 goto out;
1305}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001306EXPORT_SYMBOL(neigh_resolve_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307
1308/* As fast as possible without hh cache */
1309
David S. Miller8f40b162011-07-17 13:34:11 -07001310int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 struct net_device *dev = neigh->dev;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001313 unsigned int seq;
David S. Miller8f40b162011-07-17 13:34:11 -07001314 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001316 do {
ramesh.nagappa@gmail.come1f16502012-10-05 19:10:15 +00001317 __skb_pull(skb, skb_network_offset(skb));
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001318 seq = read_seqbegin(&neigh->ha_lock);
1319 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1320 neigh->ha, NULL, skb->len);
1321 } while (read_seqretry(&neigh->ha_lock, seq));
1322
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 if (err >= 0)
David S. Miller542d4d62011-07-16 18:06:24 -07001324 err = dev_queue_xmit(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 else {
1326 err = -EINVAL;
1327 kfree_skb(skb);
1328 }
1329 return err;
1330}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001331EXPORT_SYMBOL(neigh_connected_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332
David S. Miller8f40b162011-07-17 13:34:11 -07001333int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
1334{
1335 return dev_queue_xmit(skb);
1336}
1337EXPORT_SYMBOL(neigh_direct_output);
1338
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339static void neigh_proxy_process(unsigned long arg)
1340{
1341 struct neigh_table *tbl = (struct neigh_table *)arg;
1342 long sched_next = 0;
1343 unsigned long now = jiffies;
David S. Millerf72051b2008-09-23 01:11:18 -07001344 struct sk_buff *skb, *n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345
1346 spin_lock(&tbl->proxy_queue.lock);
1347
David S. Millerf72051b2008-09-23 01:11:18 -07001348 skb_queue_walk_safe(&tbl->proxy_queue, skb, n) {
1349 long tdif = NEIGH_CB(skb)->sched_next - now;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 if (tdif <= 0) {
David S. Millerf72051b2008-09-23 01:11:18 -07001352 struct net_device *dev = skb->dev;
Eric Dumazet20e60742011-08-22 19:32:42 +00001353
David S. Millerf72051b2008-09-23 01:11:18 -07001354 __skb_unlink(skb, &tbl->proxy_queue);
Eric Dumazet20e60742011-08-22 19:32:42 +00001355 if (tbl->proxy_redo && netif_running(dev)) {
1356 rcu_read_lock();
David S. Millerf72051b2008-09-23 01:11:18 -07001357 tbl->proxy_redo(skb);
Eric Dumazet20e60742011-08-22 19:32:42 +00001358 rcu_read_unlock();
1359 } else {
David S. Millerf72051b2008-09-23 01:11:18 -07001360 kfree_skb(skb);
Eric Dumazet20e60742011-08-22 19:32:42 +00001361 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362
1363 dev_put(dev);
1364 } else if (!sched_next || tdif < sched_next)
1365 sched_next = tdif;
1366 }
1367 del_timer(&tbl->proxy_timer);
1368 if (sched_next)
1369 mod_timer(&tbl->proxy_timer, jiffies + sched_next);
1370 spin_unlock(&tbl->proxy_queue.lock);
1371}
1372
1373void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
1374 struct sk_buff *skb)
1375{
1376 unsigned long now = jiffies;
Aruna-Hewapathirane63862b52014-01-11 07:15:59 -05001377
1378 unsigned long sched_next = now + (prandom_u32() %
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001379 NEIGH_VAR(p, PROXY_DELAY));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001381 if (tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 kfree_skb(skb);
1383 return;
1384 }
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001385
1386 NEIGH_CB(skb)->sched_next = sched_next;
1387 NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388
1389 spin_lock(&tbl->proxy_queue.lock);
1390 if (del_timer(&tbl->proxy_timer)) {
1391 if (time_before(tbl->proxy_timer.expires, sched_next))
1392 sched_next = tbl->proxy_timer.expires;
1393 }
Eric Dumazetadf30902009-06-02 05:19:30 +00001394 skb_dst_drop(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 dev_hold(skb->dev);
1396 __skb_queue_tail(&tbl->proxy_queue, skb);
1397 mod_timer(&tbl->proxy_timer, sched_next);
1398 spin_unlock(&tbl->proxy_queue.lock);
1399}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001400EXPORT_SYMBOL(pneigh_enqueue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07001402static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
Eric W. Biederman426b5302008-01-24 00:13:18 -08001403 struct net *net, int ifindex)
1404{
1405 struct neigh_parms *p;
1406
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001407 list_for_each_entry(p, &tbl->parms_list, list) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09001408 if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
Gao feng170d6f92013-06-20 10:01:33 +08001409 (!p->dev && !ifindex && net_eq(net, &init_net)))
Eric W. Biederman426b5302008-01-24 00:13:18 -08001410 return p;
1411 }
1412
1413 return NULL;
1414}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415
1416struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
1417 struct neigh_table *tbl)
1418{
Gao fengcf89d6b2013-06-20 10:01:32 +08001419 struct neigh_parms *p;
Stephen Hemminger00829822008-11-20 20:14:53 -08001420 struct net *net = dev_net(dev);
1421 const struct net_device_ops *ops = dev->netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422
Gao fengcf89d6b2013-06-20 10:01:32 +08001423 p = kmemdup(&tbl->parms, sizeof(*p), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 if (p) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 p->tbl = tbl;
1426 atomic_set(&p->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 p->reachable_time =
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001428 neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
Denis V. Lunev486b51d2008-01-14 22:59:59 -08001429 dev_hold(dev);
1430 p->dev = dev;
Eric Dumazete42ea982008-11-12 00:54:54 -08001431 write_pnet(&p->net, hold_net(net));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 p->sysctl_table = NULL;
Veaceslav Falico63134802013-08-02 19:07:38 +02001433
1434 if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
1435 release_net(net);
1436 dev_put(dev);
1437 kfree(p);
1438 return NULL;
1439 }
1440
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 write_lock_bh(&tbl->lock);
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001442 list_add(&p->list, &tbl->parms.list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 write_unlock_bh(&tbl->lock);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01001444
1445 neigh_parms_data_state_cleanall(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 }
1447 return p;
1448}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001449EXPORT_SYMBOL(neigh_parms_alloc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450
1451static void neigh_rcu_free_parms(struct rcu_head *head)
1452{
1453 struct neigh_parms *parms =
1454 container_of(head, struct neigh_parms, rcu_head);
1455
1456 neigh_parms_put(parms);
1457}
1458
1459void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
1460{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 if (!parms || parms == &tbl->parms)
1462 return;
1463 write_lock_bh(&tbl->lock);
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001464 list_del(&parms->list);
1465 parms->dead = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 write_unlock_bh(&tbl->lock);
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001467 if (parms->dev)
1468 dev_put(parms->dev);
1469 call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001471EXPORT_SYMBOL(neigh_parms_release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472
Denis V. Lunev06f05112008-01-24 00:30:58 -08001473static void neigh_parms_destroy(struct neigh_parms *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474{
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +09001475 release_net(neigh_parms_net(parms));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 kfree(parms);
1477}
1478
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001479static struct lock_class_key neigh_table_proxy_queue_class;
1480
WANG Congd7480fd2014-11-10 15:59:36 -08001481static struct neigh_table *neigh_tables[NEIGH_NR_TABLES] __read_mostly;
1482
1483void neigh_table_init(int index, struct neigh_table *tbl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484{
1485 unsigned long now = jiffies;
1486 unsigned long phsize;
1487
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001488 INIT_LIST_HEAD(&tbl->parms_list);
1489 list_add(&tbl->parms.list, &tbl->parms_list);
Eric Dumazete42ea982008-11-12 00:54:54 -08001490 write_pnet(&tbl->parms.net, &init_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 atomic_set(&tbl->parms.refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 tbl->parms.reachable_time =
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001493 neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 tbl->stats = alloc_percpu(struct neigh_statistics);
1496 if (!tbl->stats)
1497 panic("cannot create neighbour cache statistics");
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001498
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499#ifdef CONFIG_PROC_FS
Alexey Dobriyan9b739ba2008-11-11 16:47:44 -08001500 if (!proc_create_data(tbl->id, 0, init_net.proc_net_stat,
1501 &neigh_stat_seq_fops, tbl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 panic("cannot create neighbour proc dir entry");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503#endif
1504
David S. Millercd089332011-07-11 01:28:12 -07001505 RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506
1507 phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
Andrew Morton77d04bd2006-04-07 14:52:59 -07001508 tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001510 if (!tbl->nht || !tbl->phash_buckets)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 panic("cannot allocate neighbour cache hashes");
1512
YOSHIFUJI Hideaki / 吉藤英明08433ef2013-01-24 00:44:23 +00001513 if (!tbl->entry_size)
1514 tbl->entry_size = ALIGN(offsetof(struct neighbour, primary_key) +
1515 tbl->key_len, NEIGH_PRIV_ALIGN);
1516 else
1517 WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN);
1518
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 rwlock_init(&tbl->lock);
Tejun Heo203b42f2012-08-21 13:18:23 -07001520 INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work);
viresh kumarf6180022014-01-22 12:23:33 +05301521 queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
1522 tbl->parms.reachable_time);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -08001523 setup_timer(&tbl->proxy_timer, neigh_proxy_process, (unsigned long)tbl);
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001524 skb_queue_head_init_class(&tbl->proxy_queue,
1525 &neigh_table_proxy_queue_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526
1527 tbl->last_flush = now;
1528 tbl->last_rand = now + tbl->parms.reachable_time * 20;
Simon Kelleybd89efc2006-05-12 14:56:08 -07001529
WANG Congd7480fd2014-11-10 15:59:36 -08001530 neigh_tables[index] = tbl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001532EXPORT_SYMBOL(neigh_table_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533
WANG Congd7480fd2014-11-10 15:59:36 -08001534int neigh_table_clear(int index, struct neigh_table *tbl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535{
WANG Congd7480fd2014-11-10 15:59:36 -08001536 neigh_tables[index] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 /* It is not clean... Fix it to unload IPv6 module safely */
Tejun Heoa5c30b32010-10-19 06:04:42 +00001538 cancel_delayed_work_sync(&tbl->gc_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 del_timer_sync(&tbl->proxy_timer);
1540 pneigh_queue_purge(&tbl->proxy_queue);
1541 neigh_ifdown(tbl, NULL);
1542 if (atomic_read(&tbl->entries))
Joe Perchese005d192012-05-16 19:58:40 +00001543 pr_crit("neighbour leakage\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544
Eric Dumazet6193d2b2011-01-19 22:02:47 +00001545 call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
1546 neigh_hash_free_rcu);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001547 tbl->nht = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548
1549 kfree(tbl->phash_buckets);
1550 tbl->phash_buckets = NULL;
1551
Alexey Dobriyan3f192b52007-11-05 21:28:13 -08001552 remove_proc_entry(tbl->id, init_net.proc_net_stat);
1553
Kirill Korotaev3fcde742006-09-01 01:34:10 -07001554 free_percpu(tbl->stats);
1555 tbl->stats = NULL;
1556
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 return 0;
1558}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001559EXPORT_SYMBOL(neigh_table_clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560
WANG Congd7480fd2014-11-10 15:59:36 -08001561static struct neigh_table *neigh_find_table(int family)
1562{
1563 struct neigh_table *tbl = NULL;
1564
1565 switch (family) {
1566 case AF_INET:
1567 tbl = neigh_tables[NEIGH_ARP_TABLE];
1568 break;
1569 case AF_INET6:
1570 tbl = neigh_tables[NEIGH_ND_TABLE];
1571 break;
1572 case AF_DECnet:
1573 tbl = neigh_tables[NEIGH_DN_TABLE];
1574 break;
1575 }
1576
1577 return tbl;
1578}
1579
Thomas Graf661d2962013-03-21 07:45:29 +00001580static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001582 struct net *net = sock_net(skb->sk);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001583 struct ndmsg *ndm;
1584 struct nlattr *dst_attr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 struct neigh_table *tbl;
WANG Congd7480fd2014-11-10 15:59:36 -08001586 struct neighbour *neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 struct net_device *dev = NULL;
Thomas Grafa14a49d2006-08-07 17:53:08 -07001588 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589
Eric Dumazet110b2492010-10-04 04:27:36 +00001590 ASSERT_RTNL();
Thomas Grafa14a49d2006-08-07 17:53:08 -07001591 if (nlmsg_len(nlh) < sizeof(*ndm))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 goto out;
1593
Thomas Grafa14a49d2006-08-07 17:53:08 -07001594 dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
1595 if (dst_attr == NULL)
1596 goto out;
1597
1598 ndm = nlmsg_data(nlh);
1599 if (ndm->ndm_ifindex) {
Eric Dumazet110b2492010-10-04 04:27:36 +00001600 dev = __dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001601 if (dev == NULL) {
1602 err = -ENODEV;
1603 goto out;
1604 }
1605 }
1606
WANG Congd7480fd2014-11-10 15:59:36 -08001607 tbl = neigh_find_table(ndm->ndm_family);
1608 if (tbl == NULL)
1609 return -EAFNOSUPPORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610
WANG Congd7480fd2014-11-10 15:59:36 -08001611 if (nla_len(dst_attr) < tbl->key_len)
1612 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613
WANG Congd7480fd2014-11-10 15:59:36 -08001614 if (ndm->ndm_flags & NTF_PROXY) {
1615 err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
Eric Dumazet110b2492010-10-04 04:27:36 +00001616 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 }
WANG Congd7480fd2014-11-10 15:59:36 -08001618
1619 if (dev == NULL)
1620 goto out;
1621
1622 neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
1623 if (neigh == NULL) {
1624 err = -ENOENT;
1625 goto out;
1626 }
1627
1628 err = neigh_update(neigh, NULL, NUD_FAILED,
1629 NEIGH_UPDATE_F_OVERRIDE |
1630 NEIGH_UPDATE_F_ADMIN);
1631 neigh_release(neigh);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001632
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633out:
1634 return err;
1635}
1636
Thomas Graf661d2962013-03-21 07:45:29 +00001637static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638{
WANG Congd7480fd2014-11-10 15:59:36 -08001639 int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001640 struct net *net = sock_net(skb->sk);
Thomas Graf5208deb2006-08-07 17:55:40 -07001641 struct ndmsg *ndm;
1642 struct nlattr *tb[NDA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 struct neigh_table *tbl;
1644 struct net_device *dev = NULL;
WANG Congd7480fd2014-11-10 15:59:36 -08001645 struct neighbour *neigh;
1646 void *dst, *lladdr;
Thomas Graf5208deb2006-08-07 17:55:40 -07001647 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648
Eric Dumazet110b2492010-10-04 04:27:36 +00001649 ASSERT_RTNL();
Thomas Graf5208deb2006-08-07 17:55:40 -07001650 err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
1651 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 goto out;
1653
Thomas Graf5208deb2006-08-07 17:55:40 -07001654 err = -EINVAL;
1655 if (tb[NDA_DST] == NULL)
1656 goto out;
1657
1658 ndm = nlmsg_data(nlh);
1659 if (ndm->ndm_ifindex) {
Eric Dumazet110b2492010-10-04 04:27:36 +00001660 dev = __dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Graf5208deb2006-08-07 17:55:40 -07001661 if (dev == NULL) {
1662 err = -ENODEV;
1663 goto out;
1664 }
1665
1666 if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len)
Eric Dumazet110b2492010-10-04 04:27:36 +00001667 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001668 }
1669
WANG Congd7480fd2014-11-10 15:59:36 -08001670 tbl = neigh_find_table(ndm->ndm_family);
1671 if (tbl == NULL)
1672 return -EAFNOSUPPORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673
WANG Congd7480fd2014-11-10 15:59:36 -08001674 if (nla_len(tb[NDA_DST]) < tbl->key_len)
1675 goto out;
1676 dst = nla_data(tb[NDA_DST]);
1677 lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678
WANG Congd7480fd2014-11-10 15:59:36 -08001679 if (ndm->ndm_flags & NTF_PROXY) {
1680 struct pneigh_entry *pn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681
WANG Congd7480fd2014-11-10 15:59:36 -08001682 err = -ENOBUFS;
1683 pn = pneigh_lookup(tbl, net, dst, dev, 1);
1684 if (pn) {
1685 pn->flags = ndm->ndm_flags;
Eric Biederman0c5c2d32009-03-04 00:03:08 -08001686 err = 0;
WANG Congd7480fd2014-11-10 15:59:36 -08001687 }
Eric Dumazet110b2492010-10-04 04:27:36 +00001688 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 }
1690
WANG Congd7480fd2014-11-10 15:59:36 -08001691 if (dev == NULL)
1692 goto out;
1693
1694 neigh = neigh_lookup(tbl, dst, dev);
1695 if (neigh == NULL) {
1696 if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
1697 err = -ENOENT;
1698 goto out;
1699 }
1700
1701 neigh = __neigh_lookup_errno(tbl, dst, dev);
1702 if (IS_ERR(neigh)) {
1703 err = PTR_ERR(neigh);
1704 goto out;
1705 }
1706 } else {
1707 if (nlh->nlmsg_flags & NLM_F_EXCL) {
1708 err = -EEXIST;
1709 neigh_release(neigh);
1710 goto out;
1711 }
1712
1713 if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
1714 flags &= ~NEIGH_UPDATE_F_OVERRIDE;
1715 }
1716
1717 if (ndm->ndm_flags & NTF_USE) {
1718 neigh_event_send(neigh, NULL);
1719 err = 0;
1720 } else
1721 err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
1722 neigh_release(neigh);
1723
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724out:
1725 return err;
1726}
1727
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001728static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
1729{
Thomas Grafca860fb2006-08-07 18:00:18 -07001730 struct nlattr *nest;
1731
1732 nest = nla_nest_start(skb, NDTA_PARMS);
1733 if (nest == NULL)
1734 return -ENOBUFS;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001735
David S. Miller9a6308d2012-04-01 20:06:28 -04001736 if ((parms->dev &&
1737 nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) ||
1738 nla_put_u32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt)) ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001739 nla_put_u32(skb, NDTPA_QUEUE_LENBYTES,
1740 NEIGH_VAR(parms, QUEUE_LEN_BYTES)) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04001741 /* approximative value for deprecated QUEUE_LEN (in packets) */
1742 nla_put_u32(skb, NDTPA_QUEUE_LEN,
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001743 NEIGH_VAR(parms, QUEUE_LEN_BYTES) / SKB_TRUESIZE(ETH_FRAME_LEN)) ||
1744 nla_put_u32(skb, NDTPA_PROXY_QLEN, NEIGH_VAR(parms, PROXY_QLEN)) ||
1745 nla_put_u32(skb, NDTPA_APP_PROBES, NEIGH_VAR(parms, APP_PROBES)) ||
1746 nla_put_u32(skb, NDTPA_UCAST_PROBES,
1747 NEIGH_VAR(parms, UCAST_PROBES)) ||
1748 nla_put_u32(skb, NDTPA_MCAST_PROBES,
1749 NEIGH_VAR(parms, MCAST_PROBES)) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04001750 nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time) ||
1751 nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME,
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001752 NEIGH_VAR(parms, BASE_REACHABLE_TIME)) ||
1753 nla_put_msecs(skb, NDTPA_GC_STALETIME,
1754 NEIGH_VAR(parms, GC_STALETIME)) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04001755 nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME,
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001756 NEIGH_VAR(parms, DELAY_PROBE_TIME)) ||
1757 nla_put_msecs(skb, NDTPA_RETRANS_TIME,
1758 NEIGH_VAR(parms, RETRANS_TIME)) ||
1759 nla_put_msecs(skb, NDTPA_ANYCAST_DELAY,
1760 NEIGH_VAR(parms, ANYCAST_DELAY)) ||
1761 nla_put_msecs(skb, NDTPA_PROXY_DELAY,
1762 NEIGH_VAR(parms, PROXY_DELAY)) ||
1763 nla_put_msecs(skb, NDTPA_LOCKTIME,
1764 NEIGH_VAR(parms, LOCKTIME)))
David S. Miller9a6308d2012-04-01 20:06:28 -04001765 goto nla_put_failure;
Thomas Grafca860fb2006-08-07 18:00:18 -07001766 return nla_nest_end(skb, nest);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001767
Thomas Grafca860fb2006-08-07 18:00:18 -07001768nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07001769 nla_nest_cancel(skb, nest);
1770 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001771}
1772
Thomas Grafca860fb2006-08-07 18:00:18 -07001773static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
1774 u32 pid, u32 seq, int type, int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001775{
1776 struct nlmsghdr *nlh;
1777 struct ndtmsg *ndtmsg;
1778
Thomas Grafca860fb2006-08-07 18:00:18 -07001779 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
1780 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001781 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001782
Thomas Grafca860fb2006-08-07 18:00:18 -07001783 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001784
1785 read_lock_bh(&tbl->lock);
1786 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07001787 ndtmsg->ndtm_pad1 = 0;
1788 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001789
David S. Miller9a6308d2012-04-01 20:06:28 -04001790 if (nla_put_string(skb, NDTA_NAME, tbl->id) ||
1791 nla_put_msecs(skb, NDTA_GC_INTERVAL, tbl->gc_interval) ||
1792 nla_put_u32(skb, NDTA_THRESH1, tbl->gc_thresh1) ||
1793 nla_put_u32(skb, NDTA_THRESH2, tbl->gc_thresh2) ||
1794 nla_put_u32(skb, NDTA_THRESH3, tbl->gc_thresh3))
1795 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001796 {
1797 unsigned long now = jiffies;
1798 unsigned int flush_delta = now - tbl->last_flush;
1799 unsigned int rand_delta = now - tbl->last_rand;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001800 struct neigh_hash_table *nht;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001801 struct ndt_config ndc = {
1802 .ndtc_key_len = tbl->key_len,
1803 .ndtc_entry_size = tbl->entry_size,
1804 .ndtc_entries = atomic_read(&tbl->entries),
1805 .ndtc_last_flush = jiffies_to_msecs(flush_delta),
1806 .ndtc_last_rand = jiffies_to_msecs(rand_delta),
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001807 .ndtc_proxy_qlen = tbl->proxy_queue.qlen,
1808 };
1809
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001810 rcu_read_lock_bh();
1811 nht = rcu_dereference_bh(tbl->nht);
David S. Miller2c2aba62011-12-28 15:06:58 -05001812 ndc.ndtc_hash_rnd = nht->hash_rnd[0];
David S. Millercd089332011-07-11 01:28:12 -07001813 ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001814 rcu_read_unlock_bh();
1815
David S. Miller9a6308d2012-04-01 20:06:28 -04001816 if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc))
1817 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001818 }
1819
1820 {
1821 int cpu;
1822 struct ndt_stats ndst;
1823
1824 memset(&ndst, 0, sizeof(ndst));
1825
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001826 for_each_possible_cpu(cpu) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001827 struct neigh_statistics *st;
1828
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001829 st = per_cpu_ptr(tbl->stats, cpu);
1830 ndst.ndts_allocs += st->allocs;
1831 ndst.ndts_destroys += st->destroys;
1832 ndst.ndts_hash_grows += st->hash_grows;
1833 ndst.ndts_res_failed += st->res_failed;
1834 ndst.ndts_lookups += st->lookups;
1835 ndst.ndts_hits += st->hits;
1836 ndst.ndts_rcv_probes_mcast += st->rcv_probes_mcast;
1837 ndst.ndts_rcv_probes_ucast += st->rcv_probes_ucast;
1838 ndst.ndts_periodic_gc_runs += st->periodic_gc_runs;
1839 ndst.ndts_forced_gc_runs += st->forced_gc_runs;
1840 }
1841
David S. Miller9a6308d2012-04-01 20:06:28 -04001842 if (nla_put(skb, NDTA_STATS, sizeof(ndst), &ndst))
1843 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001844 }
1845
1846 BUG_ON(tbl->parms.dev);
1847 if (neightbl_fill_parms(skb, &tbl->parms) < 0)
Thomas Grafca860fb2006-08-07 18:00:18 -07001848 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001849
1850 read_unlock_bh(&tbl->lock);
Johannes Berg053c0952015-01-16 22:09:00 +01001851 nlmsg_end(skb, nlh);
1852 return 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001853
Thomas Grafca860fb2006-08-07 18:00:18 -07001854nla_put_failure:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001855 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08001856 nlmsg_cancel(skb, nlh);
1857 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001858}
1859
Thomas Grafca860fb2006-08-07 18:00:18 -07001860static int neightbl_fill_param_info(struct sk_buff *skb,
1861 struct neigh_table *tbl,
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001862 struct neigh_parms *parms,
Thomas Grafca860fb2006-08-07 18:00:18 -07001863 u32 pid, u32 seq, int type,
1864 unsigned int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001865{
1866 struct ndtmsg *ndtmsg;
1867 struct nlmsghdr *nlh;
1868
Thomas Grafca860fb2006-08-07 18:00:18 -07001869 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
1870 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001871 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001872
Thomas Grafca860fb2006-08-07 18:00:18 -07001873 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001874
1875 read_lock_bh(&tbl->lock);
1876 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07001877 ndtmsg->ndtm_pad1 = 0;
1878 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001879
Thomas Grafca860fb2006-08-07 18:00:18 -07001880 if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
1881 neightbl_fill_parms(skb, parms) < 0)
1882 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001883
1884 read_unlock_bh(&tbl->lock);
Johannes Berg053c0952015-01-16 22:09:00 +01001885 nlmsg_end(skb, nlh);
1886 return 0;
Thomas Grafca860fb2006-08-07 18:00:18 -07001887errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001888 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08001889 nlmsg_cancel(skb, nlh);
1890 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001891}
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001892
Patrick McHardyef7c79e2007-06-05 12:38:30 -07001893static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07001894 [NDTA_NAME] = { .type = NLA_STRING },
1895 [NDTA_THRESH1] = { .type = NLA_U32 },
1896 [NDTA_THRESH2] = { .type = NLA_U32 },
1897 [NDTA_THRESH3] = { .type = NLA_U32 },
1898 [NDTA_GC_INTERVAL] = { .type = NLA_U64 },
1899 [NDTA_PARMS] = { .type = NLA_NESTED },
1900};
1901
Patrick McHardyef7c79e2007-06-05 12:38:30 -07001902static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07001903 [NDTPA_IFINDEX] = { .type = NLA_U32 },
1904 [NDTPA_QUEUE_LEN] = { .type = NLA_U32 },
1905 [NDTPA_PROXY_QLEN] = { .type = NLA_U32 },
1906 [NDTPA_APP_PROBES] = { .type = NLA_U32 },
1907 [NDTPA_UCAST_PROBES] = { .type = NLA_U32 },
1908 [NDTPA_MCAST_PROBES] = { .type = NLA_U32 },
1909 [NDTPA_BASE_REACHABLE_TIME] = { .type = NLA_U64 },
1910 [NDTPA_GC_STALETIME] = { .type = NLA_U64 },
1911 [NDTPA_DELAY_PROBE_TIME] = { .type = NLA_U64 },
1912 [NDTPA_RETRANS_TIME] = { .type = NLA_U64 },
1913 [NDTPA_ANYCAST_DELAY] = { .type = NLA_U64 },
1914 [NDTPA_PROXY_DELAY] = { .type = NLA_U64 },
1915 [NDTPA_LOCKTIME] = { .type = NLA_U64 },
1916};
1917
Thomas Graf661d2962013-03-21 07:45:29 +00001918static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001919{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001920 struct net *net = sock_net(skb->sk);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001921 struct neigh_table *tbl;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001922 struct ndtmsg *ndtmsg;
1923 struct nlattr *tb[NDTA_MAX+1];
WANG Congd7480fd2014-11-10 15:59:36 -08001924 bool found = false;
1925 int err, tidx;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001926
Thomas Graf6b3f8672006-08-07 17:58:53 -07001927 err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
1928 nl_neightbl_policy);
1929 if (err < 0)
1930 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001931
Thomas Graf6b3f8672006-08-07 17:58:53 -07001932 if (tb[NDTA_NAME] == NULL) {
1933 err = -EINVAL;
1934 goto errout;
1935 }
1936
1937 ndtmsg = nlmsg_data(nlh);
WANG Congd7480fd2014-11-10 15:59:36 -08001938
1939 for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
1940 tbl = neigh_tables[tidx];
1941 if (!tbl)
1942 continue;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001943 if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
1944 continue;
WANG Congd7480fd2014-11-10 15:59:36 -08001945 if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0) {
1946 found = true;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001947 break;
WANG Congd7480fd2014-11-10 15:59:36 -08001948 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001949 }
1950
WANG Congd7480fd2014-11-10 15:59:36 -08001951 if (!found)
1952 return -ENOENT;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001953
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001954 /*
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001955 * We acquire tbl->lock to be nice to the periodic timers and
1956 * make sure they always see a consistent set of values.
1957 */
1958 write_lock_bh(&tbl->lock);
1959
Thomas Graf6b3f8672006-08-07 17:58:53 -07001960 if (tb[NDTA_PARMS]) {
1961 struct nlattr *tbp[NDTPA_MAX+1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001962 struct neigh_parms *p;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001963 int i, ifindex = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001964
Thomas Graf6b3f8672006-08-07 17:58:53 -07001965 err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS],
1966 nl_ntbl_parm_policy);
1967 if (err < 0)
1968 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001969
Thomas Graf6b3f8672006-08-07 17:58:53 -07001970 if (tbp[NDTPA_IFINDEX])
1971 ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001972
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07001973 p = lookup_neigh_parms(tbl, net, ifindex);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001974 if (p == NULL) {
1975 err = -ENOENT;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001976 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001977 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001978
Thomas Graf6b3f8672006-08-07 17:58:53 -07001979 for (i = 1; i <= NDTPA_MAX; i++) {
1980 if (tbp[i] == NULL)
1981 continue;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001982
Thomas Graf6b3f8672006-08-07 17:58:53 -07001983 switch (i) {
1984 case NDTPA_QUEUE_LEN:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001985 NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
1986 nla_get_u32(tbp[i]) *
1987 SKB_TRUESIZE(ETH_FRAME_LEN));
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001988 break;
1989 case NDTPA_QUEUE_LENBYTES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001990 NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
1991 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07001992 break;
1993 case NDTPA_PROXY_QLEN:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001994 NEIGH_VAR_SET(p, PROXY_QLEN,
1995 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07001996 break;
1997 case NDTPA_APP_PROBES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001998 NEIGH_VAR_SET(p, APP_PROBES,
1999 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002000 break;
2001 case NDTPA_UCAST_PROBES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002002 NEIGH_VAR_SET(p, UCAST_PROBES,
2003 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002004 break;
2005 case NDTPA_MCAST_PROBES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002006 NEIGH_VAR_SET(p, MCAST_PROBES,
2007 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002008 break;
2009 case NDTPA_BASE_REACHABLE_TIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002010 NEIGH_VAR_SET(p, BASE_REACHABLE_TIME,
2011 nla_get_msecs(tbp[i]));
Jean-Francois Remy4bf69802015-01-14 04:22:39 +01002012 /* update reachable_time as well, otherwise, the change will
2013 * only be effective after the next time neigh_periodic_work
2014 * decides to recompute it (can be multiple minutes)
2015 */
2016 p->reachable_time =
2017 neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002018 break;
2019 case NDTPA_GC_STALETIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002020 NEIGH_VAR_SET(p, GC_STALETIME,
2021 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002022 break;
2023 case NDTPA_DELAY_PROBE_TIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002024 NEIGH_VAR_SET(p, DELAY_PROBE_TIME,
2025 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002026 break;
2027 case NDTPA_RETRANS_TIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002028 NEIGH_VAR_SET(p, RETRANS_TIME,
2029 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002030 break;
2031 case NDTPA_ANYCAST_DELAY:
Jiri Pirko39774582014-01-14 15:46:07 +01002032 NEIGH_VAR_SET(p, ANYCAST_DELAY,
2033 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002034 break;
2035 case NDTPA_PROXY_DELAY:
Jiri Pirko39774582014-01-14 15:46:07 +01002036 NEIGH_VAR_SET(p, PROXY_DELAY,
2037 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002038 break;
2039 case NDTPA_LOCKTIME:
Jiri Pirko39774582014-01-14 15:46:07 +01002040 NEIGH_VAR_SET(p, LOCKTIME,
2041 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002042 break;
2043 }
2044 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002045 }
2046
Gao fengdc25c672013-06-20 10:01:34 +08002047 err = -ENOENT;
2048 if ((tb[NDTA_THRESH1] || tb[NDTA_THRESH2] ||
2049 tb[NDTA_THRESH3] || tb[NDTA_GC_INTERVAL]) &&
2050 !net_eq(net, &init_net))
2051 goto errout_tbl_lock;
2052
Thomas Graf6b3f8672006-08-07 17:58:53 -07002053 if (tb[NDTA_THRESH1])
2054 tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
2055
2056 if (tb[NDTA_THRESH2])
2057 tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
2058
2059 if (tb[NDTA_THRESH3])
2060 tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
2061
2062 if (tb[NDTA_GC_INTERVAL])
2063 tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
2064
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002065 err = 0;
2066
Thomas Graf6b3f8672006-08-07 17:58:53 -07002067errout_tbl_lock:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002068 write_unlock_bh(&tbl->lock);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002069errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002070 return err;
2071}
2072
Thomas Grafc8822a42007-03-22 11:50:06 -07002073static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002074{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002075 struct net *net = sock_net(skb->sk);
Thomas Grafca860fb2006-08-07 18:00:18 -07002076 int family, tidx, nidx = 0;
2077 int tbl_skip = cb->args[0];
2078 int neigh_skip = cb->args[1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002079 struct neigh_table *tbl;
2080
Thomas Grafca860fb2006-08-07 18:00:18 -07002081 family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002082
WANG Congd7480fd2014-11-10 15:59:36 -08002083 for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002084 struct neigh_parms *p;
2085
WANG Congd7480fd2014-11-10 15:59:36 -08002086 tbl = neigh_tables[tidx];
2087 if (!tbl)
2088 continue;
2089
Thomas Grafca860fb2006-08-07 18:00:18 -07002090 if (tidx < tbl_skip || (family && tbl->family != family))
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002091 continue;
2092
Eric W. Biederman15e47302012-09-07 20:12:54 +00002093 if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
Thomas Grafca860fb2006-08-07 18:00:18 -07002094 cb->nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
David S. Miller7b46a642015-01-18 23:36:08 -05002095 NLM_F_MULTI) < 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002096 break;
2097
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01002098 nidx = 0;
2099 p = list_next_entry(&tbl->parms, list);
2100 list_for_each_entry_from(p, &tbl->parms_list, list) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002101 if (!net_eq(neigh_parms_net(p), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002102 continue;
2103
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002104 if (nidx < neigh_skip)
2105 goto next;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002106
Thomas Grafca860fb2006-08-07 18:00:18 -07002107 if (neightbl_fill_param_info(skb, tbl, p,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002108 NETLINK_CB(cb->skb).portid,
Thomas Grafca860fb2006-08-07 18:00:18 -07002109 cb->nlh->nlmsg_seq,
2110 RTM_NEWNEIGHTBL,
David S. Miller7b46a642015-01-18 23:36:08 -05002111 NLM_F_MULTI) < 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002112 goto out;
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002113 next:
2114 nidx++;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002115 }
2116
Thomas Grafca860fb2006-08-07 18:00:18 -07002117 neigh_skip = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002118 }
2119out:
Thomas Grafca860fb2006-08-07 18:00:18 -07002120 cb->args[0] = tidx;
2121 cb->args[1] = nidx;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002122
2123 return skb->len;
2124}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125
Thomas Graf8b8aec52006-08-07 17:56:37 -07002126static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
2127 u32 pid, u32 seq, int type, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128{
2129 unsigned long now = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 struct nda_cacheinfo ci;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002131 struct nlmsghdr *nlh;
2132 struct ndmsg *ndm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133
Thomas Graf8b8aec52006-08-07 17:56:37 -07002134 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
2135 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08002136 return -EMSGSIZE;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002137
2138 ndm = nlmsg_data(nlh);
2139 ndm->ndm_family = neigh->ops->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07002140 ndm->ndm_pad1 = 0;
2141 ndm->ndm_pad2 = 0;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002142 ndm->ndm_flags = neigh->flags;
2143 ndm->ndm_type = neigh->type;
2144 ndm->ndm_ifindex = neigh->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145
David S. Miller9a6308d2012-04-01 20:06:28 -04002146 if (nla_put(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key))
2147 goto nla_put_failure;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002148
2149 read_lock_bh(&neigh->lock);
2150 ndm->ndm_state = neigh->nud_state;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00002151 if (neigh->nud_state & NUD_VALID) {
2152 char haddr[MAX_ADDR_LEN];
2153
2154 neigh_ha_snapshot(haddr, neigh, neigh->dev);
2155 if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0) {
2156 read_unlock_bh(&neigh->lock);
2157 goto nla_put_failure;
2158 }
Thomas Graf8b8aec52006-08-07 17:56:37 -07002159 }
2160
Stephen Hemmingerb9f5f522008-06-03 16:03:15 -07002161 ci.ndm_used = jiffies_to_clock_t(now - neigh->used);
2162 ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
2163 ci.ndm_updated = jiffies_to_clock_t(now - neigh->updated);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002164 ci.ndm_refcnt = atomic_read(&neigh->refcnt) - 1;
2165 read_unlock_bh(&neigh->lock);
2166
David S. Miller9a6308d2012-04-01 20:06:28 -04002167 if (nla_put_u32(skb, NDA_PROBES, atomic_read(&neigh->probes)) ||
2168 nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
2169 goto nla_put_failure;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002170
Johannes Berg053c0952015-01-16 22:09:00 +01002171 nlmsg_end(skb, nlh);
2172 return 0;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002173
2174nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002175 nlmsg_cancel(skb, nlh);
2176 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177}
2178
Tony Zelenoff84920c12012-01-26 22:28:58 +00002179static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
2180 u32 pid, u32 seq, int type, unsigned int flags,
2181 struct neigh_table *tbl)
2182{
2183 struct nlmsghdr *nlh;
2184 struct ndmsg *ndm;
2185
2186 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
2187 if (nlh == NULL)
2188 return -EMSGSIZE;
2189
2190 ndm = nlmsg_data(nlh);
2191 ndm->ndm_family = tbl->family;
2192 ndm->ndm_pad1 = 0;
2193 ndm->ndm_pad2 = 0;
2194 ndm->ndm_flags = pn->flags | NTF_PROXY;
Jun Zhao545469f2014-07-26 00:38:59 +08002195 ndm->ndm_type = RTN_UNICAST;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002196 ndm->ndm_ifindex = pn->dev->ifindex;
2197 ndm->ndm_state = NUD_NONE;
2198
David S. Miller9a6308d2012-04-01 20:06:28 -04002199 if (nla_put(skb, NDA_DST, tbl->key_len, pn->key))
2200 goto nla_put_failure;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002201
Johannes Berg053c0952015-01-16 22:09:00 +01002202 nlmsg_end(skb, nlh);
2203 return 0;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002204
2205nla_put_failure:
2206 nlmsg_cancel(skb, nlh);
2207 return -EMSGSIZE;
2208}
2209
Thomas Grafd961db32007-08-08 23:12:56 -07002210static void neigh_update_notify(struct neighbour *neigh)
2211{
2212 call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
2213 __neigh_notify(neigh, RTM_NEWNEIGH, 0);
2214}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215
2216static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
2217 struct netlink_callback *cb)
2218{
Eric Dumazet767e97e2010-10-06 17:49:21 -07002219 struct net *net = sock_net(skb->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 struct neighbour *n;
2221 int rc, h, s_h = cb->args[1];
2222 int idx, s_idx = idx = cb->args[2];
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002223 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002225 rcu_read_lock_bh();
2226 nht = rcu_dereference_bh(tbl->nht);
2227
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002228 for (h = s_h; h < (1 << nht->hash_shift); h++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 if (h > s_h)
2230 s_idx = 0;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002231 for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
2232 n != NULL;
2233 n = rcu_dereference_bh(n->next)) {
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002234 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002235 continue;
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002236 if (idx < s_idx)
2237 goto next;
Eric W. Biederman15e47302012-09-07 20:12:54 +00002238 if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 cb->nlh->nlmsg_seq,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07002240 RTM_NEWNEIGH,
David S. Miller7b46a642015-01-18 23:36:08 -05002241 NLM_F_MULTI) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 rc = -1;
2243 goto out;
2244 }
Eric Dumazet767e97e2010-10-06 17:49:21 -07002245next:
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002246 idx++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 }
2249 rc = skb->len;
2250out:
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002251 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 cb->args[1] = h;
2253 cb->args[2] = idx;
2254 return rc;
2255}
2256
Tony Zelenoff84920c12012-01-26 22:28:58 +00002257static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
2258 struct netlink_callback *cb)
2259{
2260 struct pneigh_entry *n;
2261 struct net *net = sock_net(skb->sk);
2262 int rc, h, s_h = cb->args[3];
2263 int idx, s_idx = idx = cb->args[4];
2264
2265 read_lock_bh(&tbl->lock);
2266
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002267 for (h = s_h; h <= PNEIGH_HASHMASK; h++) {
Tony Zelenoff84920c12012-01-26 22:28:58 +00002268 if (h > s_h)
2269 s_idx = 0;
2270 for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
2271 if (dev_net(n->dev) != net)
2272 continue;
2273 if (idx < s_idx)
2274 goto next;
Eric W. Biederman15e47302012-09-07 20:12:54 +00002275 if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
Tony Zelenoff84920c12012-01-26 22:28:58 +00002276 cb->nlh->nlmsg_seq,
2277 RTM_NEWNEIGH,
David S. Miller7b46a642015-01-18 23:36:08 -05002278 NLM_F_MULTI, tbl) < 0) {
Tony Zelenoff84920c12012-01-26 22:28:58 +00002279 read_unlock_bh(&tbl->lock);
2280 rc = -1;
2281 goto out;
2282 }
2283 next:
2284 idx++;
2285 }
2286 }
2287
2288 read_unlock_bh(&tbl->lock);
2289 rc = skb->len;
2290out:
2291 cb->args[3] = h;
2292 cb->args[4] = idx;
2293 return rc;
2294
2295}
2296
Thomas Grafc8822a42007-03-22 11:50:06 -07002297static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298{
2299 struct neigh_table *tbl;
2300 int t, family, s_t;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002301 int proxy = 0;
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002302 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303
Thomas Graf8b8aec52006-08-07 17:56:37 -07002304 family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002305
2306 /* check for full ndmsg structure presence, family member is
2307 * the same for both structures
2308 */
2309 if (nlmsg_len(cb->nlh) >= sizeof(struct ndmsg) &&
2310 ((struct ndmsg *) nlmsg_data(cb->nlh))->ndm_flags == NTF_PROXY)
2311 proxy = 1;
2312
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 s_t = cb->args[0];
2314
WANG Congd7480fd2014-11-10 15:59:36 -08002315 for (t = 0; t < NEIGH_NR_TABLES; t++) {
2316 tbl = neigh_tables[t];
2317
2318 if (!tbl)
2319 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 if (t < s_t || (family && tbl->family != family))
2321 continue;
2322 if (t > s_t)
2323 memset(&cb->args[1], 0, sizeof(cb->args) -
2324 sizeof(cb->args[0]));
Tony Zelenoff84920c12012-01-26 22:28:58 +00002325 if (proxy)
2326 err = pneigh_dump_table(tbl, skb, cb);
2327 else
2328 err = neigh_dump_table(tbl, skb, cb);
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002329 if (err < 0)
2330 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332
2333 cb->args[0] = t;
2334 return skb->len;
2335}
2336
2337void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
2338{
2339 int chain;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002340 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002342 rcu_read_lock_bh();
2343 nht = rcu_dereference_bh(tbl->nht);
2344
Eric Dumazet767e97e2010-10-06 17:49:21 -07002345 read_lock(&tbl->lock); /* avoid resizes */
David S. Millercd089332011-07-11 01:28:12 -07002346 for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347 struct neighbour *n;
2348
Eric Dumazet767e97e2010-10-06 17:49:21 -07002349 for (n = rcu_dereference_bh(nht->hash_buckets[chain]);
2350 n != NULL;
2351 n = rcu_dereference_bh(n->next))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 cb(n, cookie);
2353 }
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002354 read_unlock(&tbl->lock);
2355 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356}
2357EXPORT_SYMBOL(neigh_for_each);
2358
2359/* The tbl->lock must be held as a writer and BH disabled. */
2360void __neigh_for_each_release(struct neigh_table *tbl,
2361 int (*cb)(struct neighbour *))
2362{
2363 int chain;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002364 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002366 nht = rcu_dereference_protected(tbl->nht,
2367 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -07002368 for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002369 struct neighbour *n;
2370 struct neighbour __rcu **np;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002372 np = &nht->hash_buckets[chain];
Eric Dumazet767e97e2010-10-06 17:49:21 -07002373 while ((n = rcu_dereference_protected(*np,
2374 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 int release;
2376
2377 write_lock(&n->lock);
2378 release = cb(n);
2379 if (release) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002380 rcu_assign_pointer(*np,
2381 rcu_dereference_protected(n->next,
2382 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 n->dead = 1;
2384 } else
2385 np = &n->next;
2386 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -07002387 if (release)
2388 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 }
2390 }
2391}
2392EXPORT_SYMBOL(__neigh_for_each_release);
2393
2394#ifdef CONFIG_PROC_FS
2395
2396static struct neighbour *neigh_get_first(struct seq_file *seq)
2397{
2398 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002399 struct net *net = seq_file_net(seq);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002400 struct neigh_hash_table *nht = state->nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 struct neighbour *n = NULL;
2402 int bucket = state->bucket;
2403
2404 state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
David S. Millercd089332011-07-11 01:28:12 -07002405 for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002406 n = rcu_dereference_bh(nht->hash_buckets[bucket]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407
2408 while (n) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002409 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002410 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 if (state->neigh_sub_iter) {
2412 loff_t fakep = 0;
2413 void *v;
2414
2415 v = state->neigh_sub_iter(state, n, &fakep);
2416 if (!v)
2417 goto next;
2418 }
2419 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
2420 break;
2421 if (n->nud_state & ~NUD_NOARP)
2422 break;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002423next:
2424 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 }
2426
2427 if (n)
2428 break;
2429 }
2430 state->bucket = bucket;
2431
2432 return n;
2433}
2434
2435static struct neighbour *neigh_get_next(struct seq_file *seq,
2436 struct neighbour *n,
2437 loff_t *pos)
2438{
2439 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002440 struct net *net = seq_file_net(seq);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002441 struct neigh_hash_table *nht = state->nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442
2443 if (state->neigh_sub_iter) {
2444 void *v = state->neigh_sub_iter(state, n, pos);
2445 if (v)
2446 return n;
2447 }
Eric Dumazet767e97e2010-10-06 17:49:21 -07002448 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449
2450 while (1) {
2451 while (n) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002452 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002453 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 if (state->neigh_sub_iter) {
2455 void *v = state->neigh_sub_iter(state, n, pos);
2456 if (v)
2457 return n;
2458 goto next;
2459 }
2460 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
2461 break;
2462
2463 if (n->nud_state & ~NUD_NOARP)
2464 break;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002465next:
2466 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 }
2468
2469 if (n)
2470 break;
2471
David S. Millercd089332011-07-11 01:28:12 -07002472 if (++state->bucket >= (1 << nht->hash_shift))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 break;
2474
Eric Dumazet767e97e2010-10-06 17:49:21 -07002475 n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 }
2477
2478 if (n && pos)
2479 --(*pos);
2480 return n;
2481}
2482
2483static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
2484{
2485 struct neighbour *n = neigh_get_first(seq);
2486
2487 if (n) {
Chris Larson745e2032008-08-03 01:10:55 -07002488 --(*pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 while (*pos) {
2490 n = neigh_get_next(seq, n, pos);
2491 if (!n)
2492 break;
2493 }
2494 }
2495 return *pos ? NULL : n;
2496}
2497
2498static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
2499{
2500 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002501 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 struct neigh_table *tbl = state->tbl;
2503 struct pneigh_entry *pn = NULL;
2504 int bucket = state->bucket;
2505
2506 state->flags |= NEIGH_SEQ_IS_PNEIGH;
2507 for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
2508 pn = tbl->phash_buckets[bucket];
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002509 while (pn && !net_eq(pneigh_net(pn), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002510 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 if (pn)
2512 break;
2513 }
2514 state->bucket = bucket;
2515
2516 return pn;
2517}
2518
2519static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
2520 struct pneigh_entry *pn,
2521 loff_t *pos)
2522{
2523 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002524 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 struct neigh_table *tbl = state->tbl;
2526
Jorge Boncompte [DTI2]df07a942011-11-25 13:24:49 -05002527 do {
2528 pn = pn->next;
2529 } while (pn && !net_eq(pneigh_net(pn), net));
2530
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 while (!pn) {
2532 if (++state->bucket > PNEIGH_HASHMASK)
2533 break;
2534 pn = tbl->phash_buckets[state->bucket];
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002535 while (pn && !net_eq(pneigh_net(pn), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002536 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 if (pn)
2538 break;
2539 }
2540
2541 if (pn && pos)
2542 --(*pos);
2543
2544 return pn;
2545}
2546
2547static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
2548{
2549 struct pneigh_entry *pn = pneigh_get_first(seq);
2550
2551 if (pn) {
Chris Larson745e2032008-08-03 01:10:55 -07002552 --(*pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 while (*pos) {
2554 pn = pneigh_get_next(seq, pn, pos);
2555 if (!pn)
2556 break;
2557 }
2558 }
2559 return *pos ? NULL : pn;
2560}
2561
2562static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
2563{
2564 struct neigh_seq_state *state = seq->private;
2565 void *rc;
Chris Larson745e2032008-08-03 01:10:55 -07002566 loff_t idxpos = *pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567
Chris Larson745e2032008-08-03 01:10:55 -07002568 rc = neigh_get_idx(seq, &idxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
Chris Larson745e2032008-08-03 01:10:55 -07002570 rc = pneigh_get_idx(seq, &idxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571
2572 return rc;
2573}
2574
2575void *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 +00002576 __acquires(rcu_bh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577{
2578 struct neigh_seq_state *state = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579
2580 state->tbl = tbl;
2581 state->bucket = 0;
2582 state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
2583
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002584 rcu_read_lock_bh();
2585 state->nht = rcu_dereference_bh(tbl->nht);
Eric Dumazet767e97e2010-10-06 17:49:21 -07002586
Chris Larson745e2032008-08-03 01:10:55 -07002587 return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588}
2589EXPORT_SYMBOL(neigh_seq_start);
2590
2591void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2592{
2593 struct neigh_seq_state *state;
2594 void *rc;
2595
2596 if (v == SEQ_START_TOKEN) {
Chris Larsonbff69732008-08-03 01:02:41 -07002597 rc = neigh_get_first(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 goto out;
2599 }
2600
2601 state = seq->private;
2602 if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {
2603 rc = neigh_get_next(seq, v, NULL);
2604 if (rc)
2605 goto out;
2606 if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))
2607 rc = pneigh_get_first(seq);
2608 } else {
2609 BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);
2610 rc = pneigh_get_next(seq, v, NULL);
2611 }
2612out:
2613 ++(*pos);
2614 return rc;
2615}
2616EXPORT_SYMBOL(neigh_seq_next);
2617
2618void neigh_seq_stop(struct seq_file *seq, void *v)
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002619 __releases(rcu_bh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620{
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002621 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622}
2623EXPORT_SYMBOL(neigh_seq_stop);
2624
2625/* statistics via seq_file */
2626
2627static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
2628{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002629 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 int cpu;
2631
2632 if (*pos == 0)
2633 return SEQ_START_TOKEN;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09002634
Rusty Russell0f23174a2008-12-29 12:23:42 +00002635 for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 if (!cpu_possible(cpu))
2637 continue;
2638 *pos = cpu+1;
2639 return per_cpu_ptr(tbl->stats, cpu);
2640 }
2641 return NULL;
2642}
2643
2644static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2645{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002646 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 int cpu;
2648
Rusty Russell0f23174a2008-12-29 12:23:42 +00002649 for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 if (!cpu_possible(cpu))
2651 continue;
2652 *pos = cpu+1;
2653 return per_cpu_ptr(tbl->stats, cpu);
2654 }
2655 return NULL;
2656}
2657
2658static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
2659{
2660
2661}
2662
2663static int neigh_stat_seq_show(struct seq_file *seq, void *v)
2664{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002665 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 struct neigh_statistics *st = v;
2667
2668 if (v == SEQ_START_TOKEN) {
Neil Horman9a6d2762008-07-16 20:50:49 -07002669 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 -07002670 return 0;
2671 }
2672
2673 seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx "
Neil Horman9a6d2762008-07-16 20:50:49 -07002674 "%08lx %08lx %08lx %08lx %08lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 atomic_read(&tbl->entries),
2676
2677 st->allocs,
2678 st->destroys,
2679 st->hash_grows,
2680
2681 st->lookups,
2682 st->hits,
2683
2684 st->res_failed,
2685
2686 st->rcv_probes_mcast,
2687 st->rcv_probes_ucast,
2688
2689 st->periodic_gc_runs,
Neil Horman9a6d2762008-07-16 20:50:49 -07002690 st->forced_gc_runs,
2691 st->unres_discards
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 );
2693
2694 return 0;
2695}
2696
Stephen Hemmingerf6908082007-03-12 14:34:29 -07002697static const struct seq_operations neigh_stat_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 .start = neigh_stat_seq_start,
2699 .next = neigh_stat_seq_next,
2700 .stop = neigh_stat_seq_stop,
2701 .show = neigh_stat_seq_show,
2702};
2703
2704static int neigh_stat_seq_open(struct inode *inode, struct file *file)
2705{
2706 int ret = seq_open(file, &neigh_stat_seq_ops);
2707
2708 if (!ret) {
2709 struct seq_file *sf = file->private_data;
Al Virod9dda782013-03-31 18:16:14 -04002710 sf->private = PDE_DATA(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 }
2712 return ret;
2713};
2714
Arjan van de Ven9a321442007-02-12 00:55:35 -08002715static const struct file_operations neigh_stat_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 .owner = THIS_MODULE,
2717 .open = neigh_stat_seq_open,
2718 .read = seq_read,
2719 .llseek = seq_lseek,
2720 .release = seq_release,
2721};
2722
2723#endif /* CONFIG_PROC_FS */
2724
Thomas Graf339bf982006-11-10 14:10:15 -08002725static inline size_t neigh_nlmsg_size(void)
2726{
2727 return NLMSG_ALIGN(sizeof(struct ndmsg))
2728 + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
2729 + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
2730 + nla_total_size(sizeof(struct nda_cacheinfo))
2731 + nla_total_size(4); /* NDA_PROBES */
2732}
2733
Thomas Grafb8673312006-08-15 00:33:14 -07002734static void __neigh_notify(struct neighbour *n, int type, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002736 struct net *net = dev_net(n->dev);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002737 struct sk_buff *skb;
Thomas Grafb8673312006-08-15 00:33:14 -07002738 int err = -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739
Thomas Graf339bf982006-11-10 14:10:15 -08002740 skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002741 if (skb == NULL)
Thomas Grafb8673312006-08-15 00:33:14 -07002742 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743
Thomas Grafb8673312006-08-15 00:33:14 -07002744 err = neigh_fill_info(skb, n, 0, 0, type, flags);
Patrick McHardy26932562007-01-31 23:16:40 -08002745 if (err < 0) {
2746 /* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
2747 WARN_ON(err == -EMSGSIZE);
2748 kfree_skb(skb);
2749 goto errout;
2750 }
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08002751 rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
2752 return;
Thomas Grafb8673312006-08-15 00:33:14 -07002753errout:
2754 if (err < 0)
Eric W. Biederman426b5302008-01-24 00:13:18 -08002755 rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
Thomas Grafb8673312006-08-15 00:33:14 -07002756}
2757
2758void neigh_app_ns(struct neighbour *n)
2759{
2760 __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09002762EXPORT_SYMBOL(neigh_app_ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763
2764#ifdef CONFIG_SYSCTL
Cong Wangb93196d2012-12-06 10:04:04 +08002765static int zero;
Francesco Fusco555445c2013-07-24 10:39:06 +02002766static int int_max = INT_MAX;
Cong Wangb93196d2012-12-06 10:04:04 +08002767static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768
Joe Perchesfe2c6332013-06-11 23:04:25 -07002769static int proc_unres_qlen(struct ctl_table *ctl, int write,
2770 void __user *buffer, size_t *lenp, loff_t *ppos)
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002771{
2772 int size, ret;
Joe Perchesfe2c6332013-06-11 23:04:25 -07002773 struct ctl_table tmp = *ctl;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002774
Shan Weice46cc62012-12-04 18:49:15 +00002775 tmp.extra1 = &zero;
2776 tmp.extra2 = &unres_qlen_max;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002777 tmp.data = &size;
Shan Weice46cc62012-12-04 18:49:15 +00002778
2779 size = *(int *)ctl->data / SKB_TRUESIZE(ETH_FRAME_LEN);
2780 ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
2781
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002782 if (write && !ret)
2783 *(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
2784 return ret;
2785}
2786
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002787static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev,
2788 int family)
2789{
Jiri Pirkobba24892013-12-07 19:26:57 +01002790 switch (family) {
2791 case AF_INET:
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002792 return __in_dev_arp_parms_get_rcu(dev);
Jiri Pirkobba24892013-12-07 19:26:57 +01002793 case AF_INET6:
2794 return __in6_dev_nd_parms_get_rcu(dev);
2795 }
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002796 return NULL;
2797}
2798
2799static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p,
2800 int index)
2801{
2802 struct net_device *dev;
2803 int family = neigh_parms_family(p);
2804
2805 rcu_read_lock();
2806 for_each_netdev_rcu(net, dev) {
2807 struct neigh_parms *dst_p =
2808 neigh_get_dev_parms_rcu(dev, family);
2809
2810 if (dst_p && !test_bit(index, dst_p->data_state))
2811 dst_p->data[index] = p->data[index];
2812 }
2813 rcu_read_unlock();
2814}
2815
2816static void neigh_proc_update(struct ctl_table *ctl, int write)
2817{
2818 struct net_device *dev = ctl->extra1;
2819 struct neigh_parms *p = ctl->extra2;
Jiri Pirko77d47af2013-12-10 23:55:07 +01002820 struct net *net = neigh_parms_net(p);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002821 int index = (int *) ctl->data - p->data;
2822
2823 if (!write)
2824 return;
2825
2826 set_bit(index, p->data_state);
2827 if (!dev) /* NULL dev means this is default value */
2828 neigh_copy_dflt_parms(net, p, index);
2829}
2830
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002831static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write,
2832 void __user *buffer,
2833 size_t *lenp, loff_t *ppos)
2834{
2835 struct ctl_table tmp = *ctl;
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002836 int ret;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002837
2838 tmp.extra1 = &zero;
2839 tmp.extra2 = &int_max;
2840
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002841 ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
2842 neigh_proc_update(ctl, write);
2843 return ret;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002844}
2845
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002846int neigh_proc_dointvec(struct ctl_table *ctl, int write,
2847 void __user *buffer, size_t *lenp, loff_t *ppos)
2848{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002849 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
2850
2851 neigh_proc_update(ctl, write);
2852 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002853}
2854EXPORT_SYMBOL(neigh_proc_dointvec);
2855
2856int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write,
2857 void __user *buffer,
2858 size_t *lenp, loff_t *ppos)
2859{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002860 int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
2861
2862 neigh_proc_update(ctl, write);
2863 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002864}
2865EXPORT_SYMBOL(neigh_proc_dointvec_jiffies);
2866
2867static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write,
2868 void __user *buffer,
2869 size_t *lenp, loff_t *ppos)
2870{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002871 int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos);
2872
2873 neigh_proc_update(ctl, write);
2874 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002875}
2876
2877int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write,
2878 void __user *buffer,
2879 size_t *lenp, loff_t *ppos)
2880{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002881 int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
2882
2883 neigh_proc_update(ctl, write);
2884 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002885}
2886EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies);
2887
2888static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write,
2889 void __user *buffer,
2890 size_t *lenp, loff_t *ppos)
2891{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002892 int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos);
2893
2894 neigh_proc_update(ctl, write);
2895 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002896}
2897
Jean-Francois Remy4bf69802015-01-14 04:22:39 +01002898static int neigh_proc_base_reachable_time(struct ctl_table *ctl, int write,
2899 void __user *buffer,
2900 size_t *lenp, loff_t *ppos)
2901{
2902 struct neigh_parms *p = ctl->extra2;
2903 int ret;
2904
2905 if (strcmp(ctl->procname, "base_reachable_time") == 0)
2906 ret = neigh_proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
2907 else if (strcmp(ctl->procname, "base_reachable_time_ms") == 0)
2908 ret = neigh_proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
2909 else
2910 ret = -1;
2911
2912 if (write && ret == 0) {
2913 /* update reachable_time as well, otherwise, the change will
2914 * only be effective after the next time neigh_periodic_work
2915 * decides to recompute it
2916 */
2917 p->reachable_time =
2918 neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
2919 }
2920 return ret;
2921}
2922
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002923#define NEIGH_PARMS_DATA_OFFSET(index) \
2924 (&((struct neigh_parms *) 0)->data[index])
2925
2926#define NEIGH_SYSCTL_ENTRY(attr, data_attr, name, mval, proc) \
2927 [NEIGH_VAR_ ## attr] = { \
2928 .procname = name, \
2929 .data = NEIGH_PARMS_DATA_OFFSET(NEIGH_VAR_ ## data_attr), \
2930 .maxlen = sizeof(int), \
2931 .mode = mval, \
2932 .proc_handler = proc, \
2933 }
2934
2935#define NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(attr, name) \
2936 NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_zero_intmax)
2937
2938#define NEIGH_SYSCTL_JIFFIES_ENTRY(attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002939 NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_jiffies)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002940
2941#define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002942 NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002943
2944#define NEIGH_SYSCTL_MS_JIFFIES_ENTRY(attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002945 NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002946
2947#define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002948 NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002949
2950#define NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(attr, data_attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002951 NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_unres_qlen)
Eric W. Biederman54716e32010-02-14 03:27:03 +00002952
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953static struct neigh_sysctl_table {
2954 struct ctl_table_header *sysctl_header;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002955 struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
Brian Haleyab32ea52006-09-22 14:15:41 -07002956} neigh_sysctl_template __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 .neigh_vars = {
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002958 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_PROBES, "mcast_solicit"),
2959 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(UCAST_PROBES, "ucast_solicit"),
2960 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(APP_PROBES, "app_solicit"),
2961 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(RETRANS_TIME, "retrans_time"),
2962 NEIGH_SYSCTL_JIFFIES_ENTRY(BASE_REACHABLE_TIME, "base_reachable_time"),
2963 NEIGH_SYSCTL_JIFFIES_ENTRY(DELAY_PROBE_TIME, "delay_first_probe_time"),
2964 NEIGH_SYSCTL_JIFFIES_ENTRY(GC_STALETIME, "gc_stale_time"),
2965 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(QUEUE_LEN_BYTES, "unres_qlen_bytes"),
2966 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(PROXY_QLEN, "proxy_qlen"),
2967 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(ANYCAST_DELAY, "anycast_delay"),
2968 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(PROXY_DELAY, "proxy_delay"),
2969 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(LOCKTIME, "locktime"),
2970 NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(QUEUE_LEN, QUEUE_LEN_BYTES, "unres_qlen"),
2971 NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(RETRANS_TIME_MS, RETRANS_TIME, "retrans_time_ms"),
2972 NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(BASE_REACHABLE_TIME_MS, BASE_REACHABLE_TIME, "base_reachable_time_ms"),
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002973 [NEIGH_VAR_GC_INTERVAL] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 .procname = "gc_interval",
2975 .maxlen = sizeof(int),
2976 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002977 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002979 [NEIGH_VAR_GC_THRESH1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 .procname = "gc_thresh1",
2981 .maxlen = sizeof(int),
2982 .mode = 0644,
Francesco Fusco555445c2013-07-24 10:39:06 +02002983 .extra1 = &zero,
2984 .extra2 = &int_max,
2985 .proc_handler = proc_dointvec_minmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002987 [NEIGH_VAR_GC_THRESH2] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 .procname = "gc_thresh2",
2989 .maxlen = sizeof(int),
2990 .mode = 0644,
Francesco Fusco555445c2013-07-24 10:39:06 +02002991 .extra1 = &zero,
2992 .extra2 = &int_max,
2993 .proc_handler = proc_dointvec_minmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002995 [NEIGH_VAR_GC_THRESH3] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 .procname = "gc_thresh3",
2997 .maxlen = sizeof(int),
2998 .mode = 0644,
Francesco Fusco555445c2013-07-24 10:39:06 +02002999 .extra1 = &zero,
3000 .extra2 = &int_max,
3001 .proc_handler = proc_dointvec_minmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 },
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11003003 {},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 },
3005};
3006
3007int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
Jiri Pirko73af6142013-12-07 19:26:55 +01003008 proc_handler *handler)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009{
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003010 int i;
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003011 struct neigh_sysctl_table *t;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003012 const char *dev_name_source;
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003013 char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ];
Jiri Pirko73af6142013-12-07 19:26:55 +01003014 char *p_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003016 t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 if (!t)
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003018 goto err;
3019
Jiri Pirkob194c1f2014-02-21 14:52:57 +01003020 for (i = 0; i < NEIGH_VAR_GC_INTERVAL; i++) {
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003021 t->neigh_vars[i].data += (long) p;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003022 t->neigh_vars[i].extra1 = dev;
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003023 t->neigh_vars[i].extra2 = p;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003024 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025
3026 if (dev) {
3027 dev_name_source = dev->name;
Eric W. Biedermand12af672007-10-18 03:05:25 -07003028 /* Terminate the table early */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003029 memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
3030 sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 } else {
Mathias Krause9ecf07a2014-07-12 22:36:44 +02003032 struct neigh_table *tbl = p->tbl;
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003033 dev_name_source = "default";
Mathias Krause9ecf07a2014-07-12 22:36:44 +02003034 t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = &tbl->gc_interval;
3035 t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = &tbl->gc_thresh1;
3036 t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = &tbl->gc_thresh2;
3037 t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = &tbl->gc_thresh3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 }
3039
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08003040 if (handler) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 /* RetransTime */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003042 t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 /* ReachableTime */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003044 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 /* RetransTime (in milliseconds)*/
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003046 t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 /* ReachableTime (in milliseconds) */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003048 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
Jean-Francois Remy4bf69802015-01-14 04:22:39 +01003049 } else {
3050 /* Those handlers will update p->reachable_time after
3051 * base_reachable_time(_ms) is set to ensure the new timer starts being
3052 * applied after the next neighbour update instead of waiting for
3053 * neigh_periodic_work to update its value (can be multiple minutes)
3054 * So any handler that replaces them should do this as well
3055 */
3056 /* ReachableTime */
3057 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler =
3058 neigh_proc_base_reachable_time;
3059 /* ReachableTime (in milliseconds) */
3060 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler =
3061 neigh_proc_base_reachable_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 }
3063
Eric W. Biederman464dc802012-11-16 03:02:59 +00003064 /* Don't export sysctls to unprivileged users */
3065 if (neigh_parms_net(p)->user_ns != &init_user_ns)
3066 t->neigh_vars[0].procname = NULL;
3067
Jiri Pirko73af6142013-12-07 19:26:55 +01003068 switch (neigh_parms_family(p)) {
3069 case AF_INET:
3070 p_name = "ipv4";
3071 break;
3072 case AF_INET6:
3073 p_name = "ipv6";
3074 break;
3075 default:
3076 BUG();
3077 }
3078
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003079 snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s",
3080 p_name, dev_name_source);
Denis V. Lunev4ab438f2008-02-28 20:48:01 -08003081 t->sysctl_header =
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003082 register_net_sysctl(neigh_parms_net(p), neigh_path, t->neigh_vars);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003083 if (!t->sysctl_header)
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003084 goto free;
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003085
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086 p->sysctl_table = t;
3087 return 0;
3088
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003089free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 kfree(t);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003091err:
3092 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09003094EXPORT_SYMBOL(neigh_sysctl_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095
3096void neigh_sysctl_unregister(struct neigh_parms *p)
3097{
3098 if (p->sysctl_table) {
3099 struct neigh_sysctl_table *t = p->sysctl_table;
3100 p->sysctl_table = NULL;
Eric W. Biederman5dd3df12012-04-19 13:24:33 +00003101 unregister_net_sysctl_table(t->sysctl_header);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 kfree(t);
3103 }
3104}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09003105EXPORT_SYMBOL(neigh_sysctl_unregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106
3107#endif /* CONFIG_SYSCTL */
3108
Thomas Grafc8822a42007-03-22 11:50:06 -07003109static int __init neigh_init(void)
3110{
Greg Rosec7ac8672011-06-10 01:27:09 +00003111 rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, NULL);
3112 rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, NULL);
3113 rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info, NULL);
Thomas Grafc8822a42007-03-22 11:50:06 -07003114
Greg Rosec7ac8672011-06-10 01:27:09 +00003115 rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
3116 NULL);
3117 rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, NULL);
Thomas Grafc8822a42007-03-22 11:50:06 -07003118
3119 return 0;
3120}
3121
3122subsys_initcall(neigh_init);
3123