blob: ce2b77515a9e38ec1fc8baed84ae12f40374b335 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Generic address resolution entity
3 *
4 * Authors:
5 * Pedro Roque <roque@di.fc.ul.pt>
6 * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 *
13 * Fixes:
14 * Vitaly E. Lavrov releasing NULL neighbor in neigh_add.
15 * Harald Welte Add neighbour cache statistics like rtstat
16 */
17
Joe Perchese005d192012-05-16 19:58:40 +000018#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090020#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/types.h>
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/socket.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#include <linux/netdevice.h>
26#include <linux/proc_fs.h>
27#ifdef CONFIG_SYSCTL
28#include <linux/sysctl.h>
29#endif
30#include <linux/times.h>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020031#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <net/neighbour.h>
33#include <net/dst.h>
34#include <net/sock.h>
Tom Tucker8d717402006-07-30 20:43:36 -070035#include <net/netevent.h>
Thomas Grafa14a49d2006-08-07 17:53:08 -070036#include <net/netlink.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <linux/rtnetlink.h>
38#include <linux/random.h>
Paulo Marques543537b2005-06-23 00:09:02 -070039#include <linux/string.h>
vignesh babuc3609d52007-08-24 22:27:55 -070040#include <linux/log2.h>
Jiri Pirko1d4c8c22013-12-07 19:26:56 +010041#include <linux/inetdevice.h>
Jiri Pirkobba24892013-12-07 19:26:57 +010042#include <net/addrconf.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
Joe Perchesd5d427c2013-04-15 15:17:19 +000044#define DEBUG
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#define NEIGH_DEBUG 1
Joe Perchesd5d427c2013-04-15 15:17:19 +000046#define neigh_dbg(level, fmt, ...) \
47do { \
48 if (level <= NEIGH_DEBUG) \
49 pr_debug(fmt, ##__VA_ARGS__); \
50} while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52#define PNEIGH_HASHMASK 0xF
53
54static void neigh_timer_handler(unsigned long arg);
Thomas Grafd961db32007-08-08 23:12:56 -070055static void __neigh_notify(struct neighbour *n, int type, int flags);
56static void neigh_update_notify(struct neighbour *neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -070057static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
59static struct neigh_table *neigh_tables;
Amos Waterland45fc3b12005-09-24 16:53:16 -070060#ifdef CONFIG_PROC_FS
Arjan van de Ven9a321442007-02-12 00:55:35 -080061static const struct file_operations neigh_stat_seq_fops;
Amos Waterland45fc3b12005-09-24 16:53:16 -070062#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
64/*
65 Neighbour hash table buckets are protected with rwlock tbl->lock.
66
67 - All the scans/updates to hash buckets MUST be made under this lock.
68 - NOTHING clever should be made under this lock: no callbacks
69 to protocol backends, no attempts to send something to network.
70 It will result in deadlocks, if backend/driver wants to use neighbour
71 cache.
72 - If the entry requires some non-trivial actions, increase
73 its reference count and release table lock.
74
75 Neighbour entries are protected:
76 - with reference count.
77 - with rwlock neigh->lock
78
79 Reference count prevents destruction.
80
81 neigh->lock mainly serializes ll address data and its validity state.
82 However, the same lock is used to protect another entry fields:
83 - timer
84 - resolution queue
85
86 Again, nothing clever shall be made under neigh->lock,
87 the most complicated procedure, which we allow is dev->hard_header.
88 It is supposed, that dev->hard_header is simplistic and does
89 not make callbacks to neighbour tables.
90
91 The last lock is neigh_tbl_lock. It is pure SMP lock, protecting
92 list of neighbour tables. This list is used only in process context,
93 */
94
95static DEFINE_RWLOCK(neigh_tbl_lock);
96
David S. Miller8f40b162011-07-17 13:34:11 -070097static int neigh_blackhole(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -070098{
99 kfree_skb(skb);
100 return -ENETDOWN;
101}
102
Thomas Graf4f494552007-08-08 23:12:36 -0700103static void neigh_cleanup_and_release(struct neighbour *neigh)
104{
105 if (neigh->parms->neigh_cleanup)
106 neigh->parms->neigh_cleanup(neigh);
107
Thomas Grafd961db32007-08-08 23:12:56 -0700108 __neigh_notify(neigh, RTM_DELNEIGH, 0);
Thomas Graf4f494552007-08-08 23:12:36 -0700109 neigh_release(neigh);
110}
111
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112/*
113 * It is random distribution in the interval (1/2)*base...(3/2)*base.
114 * It corresponds to default IPv6 settings and is not overridable,
115 * because it is really reasonable choice.
116 */
117
118unsigned long neigh_rand_reach_time(unsigned long base)
119{
Eric Dumazeta02cec22010-09-22 20:43:57 +0000120 return base ? (net_random() % base) + (base >> 1) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900122EXPORT_SYMBOL(neigh_rand_reach_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
124
125static int neigh_forced_gc(struct neigh_table *tbl)
126{
127 int shrunk = 0;
128 int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000129 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
131 NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
132
133 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000134 nht = rcu_dereference_protected(tbl->nht,
135 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -0700136 for (i = 0; i < (1 << nht->hash_shift); i++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700137 struct neighbour *n;
138 struct neighbour __rcu **np;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000140 np = &nht->hash_buckets[i];
Eric Dumazet767e97e2010-10-06 17:49:21 -0700141 while ((n = rcu_dereference_protected(*np,
142 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 /* Neighbour record may be discarded if:
144 * - nobody refers to it.
145 * - it is not permanent
146 */
147 write_lock(&n->lock);
148 if (atomic_read(&n->refcnt) == 1 &&
149 !(n->nud_state & NUD_PERMANENT)) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700150 rcu_assign_pointer(*np,
151 rcu_dereference_protected(n->next,
152 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 n->dead = 1;
154 shrunk = 1;
155 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -0700156 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 continue;
158 }
159 write_unlock(&n->lock);
160 np = &n->next;
161 }
162 }
163
164 tbl->last_flush = jiffies;
165
166 write_unlock_bh(&tbl->lock);
167
168 return shrunk;
169}
170
Pavel Emelyanova43d8992007-12-20 15:49:05 -0800171static void neigh_add_timer(struct neighbour *n, unsigned long when)
172{
173 neigh_hold(n);
174 if (unlikely(mod_timer(&n->timer, when))) {
175 printk("NEIGH: BUG, double timer add, state is %x\n",
176 n->nud_state);
177 dump_stack();
178 }
179}
180
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181static int neigh_del_timer(struct neighbour *n)
182{
183 if ((n->nud_state & NUD_IN_TIMER) &&
184 del_timer(&n->timer)) {
185 neigh_release(n);
186 return 1;
187 }
188 return 0;
189}
190
191static void pneigh_queue_purge(struct sk_buff_head *list)
192{
193 struct sk_buff *skb;
194
195 while ((skb = skb_dequeue(list)) != NULL) {
196 dev_put(skb->dev);
197 kfree_skb(skb);
198 }
199}
200
Herbert Xu49636bb2005-10-23 17:18:00 +1000201static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202{
203 int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000204 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000206 nht = rcu_dereference_protected(tbl->nht,
207 lockdep_is_held(&tbl->lock));
208
David S. Millercd089332011-07-11 01:28:12 -0700209 for (i = 0; i < (1 << nht->hash_shift); i++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700210 struct neighbour *n;
211 struct neighbour __rcu **np = &nht->hash_buckets[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
Eric Dumazet767e97e2010-10-06 17:49:21 -0700213 while ((n = rcu_dereference_protected(*np,
214 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 if (dev && n->dev != dev) {
216 np = &n->next;
217 continue;
218 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700219 rcu_assign_pointer(*np,
220 rcu_dereference_protected(n->next,
221 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 write_lock(&n->lock);
223 neigh_del_timer(n);
224 n->dead = 1;
225
226 if (atomic_read(&n->refcnt) != 1) {
227 /* The most unpleasant situation.
228 We must destroy neighbour entry,
229 but someone still uses it.
230
231 The destroy will be delayed until
232 the last user releases us, but
233 we must kill timers etc. and move
234 it to safe state.
235 */
Eric Dumazetc9ab4d82013-06-28 02:37:42 -0700236 __skb_queue_purge(&n->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000237 n->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 n->output = neigh_blackhole;
239 if (n->nud_state & NUD_VALID)
240 n->nud_state = NUD_NOARP;
241 else
242 n->nud_state = NUD_NONE;
Joe Perchesd5d427c2013-04-15 15:17:19 +0000243 neigh_dbg(2, "neigh %p is stray\n", n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 }
245 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -0700246 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 }
248 }
Herbert Xu49636bb2005-10-23 17:18:00 +1000249}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
Herbert Xu49636bb2005-10-23 17:18:00 +1000251void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
252{
253 write_lock_bh(&tbl->lock);
254 neigh_flush_dev(tbl, dev);
255 write_unlock_bh(&tbl->lock);
256}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900257EXPORT_SYMBOL(neigh_changeaddr);
Herbert Xu49636bb2005-10-23 17:18:00 +1000258
259int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
260{
261 write_lock_bh(&tbl->lock);
262 neigh_flush_dev(tbl, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 pneigh_ifdown(tbl, dev);
264 write_unlock_bh(&tbl->lock);
265
266 del_timer_sync(&tbl->proxy_timer);
267 pneigh_queue_purge(&tbl->proxy_queue);
268 return 0;
269}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900270EXPORT_SYMBOL(neigh_ifdown);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
David Miller596b9b62011-07-25 00:01:25 +0000272static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273{
274 struct neighbour *n = NULL;
275 unsigned long now = jiffies;
276 int entries;
277
278 entries = atomic_inc_return(&tbl->entries) - 1;
279 if (entries >= tbl->gc_thresh3 ||
280 (entries >= tbl->gc_thresh2 &&
281 time_after(now, tbl->last_flush + 5 * HZ))) {
282 if (!neigh_forced_gc(tbl) &&
283 entries >= tbl->gc_thresh3)
284 goto out_entries;
285 }
286
YOSHIFUJI Hideaki / 吉藤英明08433ef2013-01-24 00:44:23 +0000287 n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 if (!n)
289 goto out_entries;
290
Eric Dumazetc9ab4d82013-06-28 02:37:42 -0700291 __skb_queue_head_init(&n->arp_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 rwlock_init(&n->lock);
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +0000293 seqlock_init(&n->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 n->updated = n->used = now;
295 n->nud_state = NUD_NONE;
296 n->output = neigh_blackhole;
David S. Millerf6b72b62011-07-14 07:53:20 -0700297 seqlock_init(&n->hh.hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 n->parms = neigh_parms_clone(&tbl->parms);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800299 setup_timer(&n->timer, neigh_timer_handler, (unsigned long)n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
301 NEIGH_CACHE_STAT_INC(tbl, allocs);
302 n->tbl = tbl;
303 atomic_set(&n->refcnt, 1);
304 n->dead = 1;
305out:
306 return n;
307
308out_entries:
309 atomic_dec(&tbl->entries);
310 goto out;
311}
312
David S. Miller2c2aba62011-12-28 15:06:58 -0500313static void neigh_get_hash_rnd(u32 *x)
314{
315 get_random_bytes(x, sizeof(*x));
316 *x |= 1;
317}
318
David S. Millercd089332011-07-11 01:28:12 -0700319static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320{
David S. Millercd089332011-07-11 01:28:12 -0700321 size_t size = (1 << shift) * sizeof(struct neighbour *);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000322 struct neigh_hash_table *ret;
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000323 struct neighbour __rcu **buckets;
David S. Miller2c2aba62011-12-28 15:06:58 -0500324 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000326 ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
327 if (!ret)
328 return NULL;
329 if (size <= PAGE_SIZE)
330 buckets = kzalloc(size, GFP_ATOMIC);
331 else
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000332 buckets = (struct neighbour __rcu **)
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000333 __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
334 get_order(size));
335 if (!buckets) {
336 kfree(ret);
337 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 }
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000339 ret->hash_buckets = buckets;
David S. Millercd089332011-07-11 01:28:12 -0700340 ret->hash_shift = shift;
David S. Miller2c2aba62011-12-28 15:06:58 -0500341 for (i = 0; i < NEIGH_NUM_HASH_RND; i++)
342 neigh_get_hash_rnd(&ret->hash_rnd[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 return ret;
344}
345
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000346static void neigh_hash_free_rcu(struct rcu_head *head)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347{
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000348 struct neigh_hash_table *nht = container_of(head,
349 struct neigh_hash_table,
350 rcu);
David S. Millercd089332011-07-11 01:28:12 -0700351 size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *);
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000352 struct neighbour __rcu **buckets = nht->hash_buckets;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
354 if (size <= PAGE_SIZE)
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000355 kfree(buckets);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 else
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000357 free_pages((unsigned long)buckets, get_order(size));
358 kfree(nht);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359}
360
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000361static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
David S. Millercd089332011-07-11 01:28:12 -0700362 unsigned long new_shift)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000364 unsigned int i, hash;
365 struct neigh_hash_table *new_nht, *old_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
367 NEIGH_CACHE_STAT_INC(tbl, hash_grows);
368
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000369 old_nht = rcu_dereference_protected(tbl->nht,
370 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -0700371 new_nht = neigh_hash_alloc(new_shift);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000372 if (!new_nht)
373 return old_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
David S. Millercd089332011-07-11 01:28:12 -0700375 for (i = 0; i < (1 << old_nht->hash_shift); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 struct neighbour *n, *next;
377
Eric Dumazet767e97e2010-10-06 17:49:21 -0700378 for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
379 lockdep_is_held(&tbl->lock));
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000380 n != NULL;
381 n = next) {
382 hash = tbl->hash(n->primary_key, n->dev,
383 new_nht->hash_rnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
David S. Millercd089332011-07-11 01:28:12 -0700385 hash >>= (32 - new_nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700386 next = rcu_dereference_protected(n->next,
387 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
Eric Dumazet767e97e2010-10-06 17:49:21 -0700389 rcu_assign_pointer(n->next,
390 rcu_dereference_protected(
391 new_nht->hash_buckets[hash],
392 lockdep_is_held(&tbl->lock)));
393 rcu_assign_pointer(new_nht->hash_buckets[hash], n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 }
395 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000397 rcu_assign_pointer(tbl->nht, new_nht);
398 call_rcu(&old_nht->rcu, neigh_hash_free_rcu);
399 return new_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400}
401
402struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
403 struct net_device *dev)
404{
405 struct neighbour *n;
406 int key_len = tbl->key_len;
Pavel Emelyanovbc4bf5f2008-02-23 19:57:02 -0800407 u32 hash_val;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000408 struct neigh_hash_table *nht;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900409
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 NEIGH_CACHE_STAT_INC(tbl, lookups);
411
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000412 rcu_read_lock_bh();
413 nht = rcu_dereference_bh(tbl->nht);
David S. Millercd089332011-07-11 01:28:12 -0700414 hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700415
416 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
417 n != NULL;
418 n = rcu_dereference_bh(n->next)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700420 if (!atomic_inc_not_zero(&n->refcnt))
421 n = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 NEIGH_CACHE_STAT_INC(tbl, hits);
423 break;
424 }
425 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700426
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000427 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 return n;
429}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900430EXPORT_SYMBOL(neigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431
Eric W. Biederman426b5302008-01-24 00:13:18 -0800432struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
433 const void *pkey)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434{
435 struct neighbour *n;
436 int key_len = tbl->key_len;
Pavel Emelyanovbc4bf5f2008-02-23 19:57:02 -0800437 u32 hash_val;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000438 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
440 NEIGH_CACHE_STAT_INC(tbl, lookups);
441
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000442 rcu_read_lock_bh();
443 nht = rcu_dereference_bh(tbl->nht);
David S. Millercd089332011-07-11 01:28:12 -0700444 hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700445
446 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
447 n != NULL;
448 n = rcu_dereference_bh(n->next)) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800449 if (!memcmp(n->primary_key, pkey, key_len) &&
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +0900450 net_eq(dev_net(n->dev), net)) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700451 if (!atomic_inc_not_zero(&n->refcnt))
452 n = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 NEIGH_CACHE_STAT_INC(tbl, hits);
454 break;
455 }
456 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700457
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000458 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 return n;
460}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900461EXPORT_SYMBOL(neigh_lookup_nodev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462
David S. Millera263b302012-07-02 02:02:15 -0700463struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
464 struct net_device *dev, bool want_ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465{
466 u32 hash_val;
467 int key_len = tbl->key_len;
468 int error;
David Miller596b9b62011-07-25 00:01:25 +0000469 struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000470 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471
472 if (!n) {
473 rc = ERR_PTR(-ENOBUFS);
474 goto out;
475 }
476
477 memcpy(n->primary_key, pkey, key_len);
478 n->dev = dev;
479 dev_hold(dev);
480
481 /* Protocol specific setup. */
482 if (tbl->constructor && (error = tbl->constructor(n)) < 0) {
483 rc = ERR_PTR(error);
484 goto out_neigh_release;
485 }
486
David Millerda6a8fa2011-07-25 00:01:38 +0000487 if (dev->netdev_ops->ndo_neigh_construct) {
488 error = dev->netdev_ops->ndo_neigh_construct(n);
489 if (error < 0) {
490 rc = ERR_PTR(error);
491 goto out_neigh_release;
492 }
493 }
494
David S. Miller447f2192011-12-19 15:04:41 -0500495 /* Device specific setup. */
496 if (n->parms->neigh_setup &&
497 (error = n->parms->neigh_setup(n)) < 0) {
498 rc = ERR_PTR(error);
499 goto out_neigh_release;
500 }
501
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100502 n->confirmed = jiffies - (NEIGH_VAR(n->parms, BASE_REACHABLE_TIME) << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
504 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000505 nht = rcu_dereference_protected(tbl->nht,
506 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
David S. Millercd089332011-07-11 01:28:12 -0700508 if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
509 nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
David S. Millercd089332011-07-11 01:28:12 -0700511 hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
513 if (n->parms->dead) {
514 rc = ERR_PTR(-EINVAL);
515 goto out_tbl_unlock;
516 }
517
Eric Dumazet767e97e2010-10-06 17:49:21 -0700518 for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
519 lockdep_is_held(&tbl->lock));
520 n1 != NULL;
521 n1 = rcu_dereference_protected(n1->next,
522 lockdep_is_held(&tbl->lock))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) {
David S. Millera263b302012-07-02 02:02:15 -0700524 if (want_ref)
525 neigh_hold(n1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 rc = n1;
527 goto out_tbl_unlock;
528 }
529 }
530
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 n->dead = 0;
David S. Millera263b302012-07-02 02:02:15 -0700532 if (want_ref)
533 neigh_hold(n);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700534 rcu_assign_pointer(n->next,
535 rcu_dereference_protected(nht->hash_buckets[hash_val],
536 lockdep_is_held(&tbl->lock)));
537 rcu_assign_pointer(nht->hash_buckets[hash_val], n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 write_unlock_bh(&tbl->lock);
Joe Perchesd5d427c2013-04-15 15:17:19 +0000539 neigh_dbg(2, "neigh %p is created\n", n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 rc = n;
541out:
542 return rc;
543out_tbl_unlock:
544 write_unlock_bh(&tbl->lock);
545out_neigh_release:
546 neigh_release(n);
547 goto out;
548}
David S. Millera263b302012-07-02 02:02:15 -0700549EXPORT_SYMBOL(__neigh_create);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900551static u32 pneigh_hash(const void *pkey, int key_len)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700552{
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700553 u32 hash_val = *(u32 *)(pkey + key_len - 4);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700554 hash_val ^= (hash_val >> 16);
555 hash_val ^= hash_val >> 8;
556 hash_val ^= hash_val >> 4;
557 hash_val &= PNEIGH_HASHMASK;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900558 return hash_val;
559}
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700560
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900561static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
562 struct net *net,
563 const void *pkey,
564 int key_len,
565 struct net_device *dev)
566{
567 while (n) {
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700568 if (!memcmp(n->key, pkey, key_len) &&
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900569 net_eq(pneigh_net(n), net) &&
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700570 (n->dev == dev || !n->dev))
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900571 return n;
572 n = n->next;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700573 }
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900574 return NULL;
575}
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700576
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900577struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
578 struct net *net, const void *pkey, struct net_device *dev)
579{
580 int key_len = tbl->key_len;
581 u32 hash_val = pneigh_hash(pkey, key_len);
582
583 return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
584 net, pkey, key_len, dev);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700585}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900586EXPORT_SYMBOL_GPL(__pneigh_lookup);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700587
Eric W. Biederman426b5302008-01-24 00:13:18 -0800588struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
589 struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 struct net_device *dev, int creat)
591{
592 struct pneigh_entry *n;
593 int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900594 u32 hash_val = pneigh_hash(pkey, key_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
596 read_lock_bh(&tbl->lock);
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900597 n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
598 net, pkey, key_len, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 read_unlock_bh(&tbl->lock);
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900600
601 if (n || !creat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 goto out;
603
Pavel Emelyanov4ae28942007-10-15 12:54:15 -0700604 ASSERT_RTNL();
605
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
607 if (!n)
608 goto out;
609
Eric Dumazete42ea982008-11-12 00:54:54 -0800610 write_pnet(&n->net, hold_net(net));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 memcpy(n->key, pkey, key_len);
612 n->dev = dev;
613 if (dev)
614 dev_hold(dev);
615
616 if (tbl->pconstructor && tbl->pconstructor(n)) {
617 if (dev)
618 dev_put(dev);
Denis V. Lunevda12f732008-02-20 00:26:16 -0800619 release_net(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 kfree(n);
621 n = NULL;
622 goto out;
623 }
624
625 write_lock_bh(&tbl->lock);
626 n->next = tbl->phash_buckets[hash_val];
627 tbl->phash_buckets[hash_val] = n;
628 write_unlock_bh(&tbl->lock);
629out:
630 return n;
631}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900632EXPORT_SYMBOL(pneigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
634
Eric W. Biederman426b5302008-01-24 00:13:18 -0800635int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 struct net_device *dev)
637{
638 struct pneigh_entry *n, **np;
639 int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900640 u32 hash_val = pneigh_hash(pkey, key_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
642 write_lock_bh(&tbl->lock);
643 for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
644 np = &n->next) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800645 if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +0900646 net_eq(pneigh_net(n), net)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 *np = n->next;
648 write_unlock_bh(&tbl->lock);
649 if (tbl->pdestructor)
650 tbl->pdestructor(n);
651 if (n->dev)
652 dev_put(n->dev);
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +0900653 release_net(pneigh_net(n));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 kfree(n);
655 return 0;
656 }
657 }
658 write_unlock_bh(&tbl->lock);
659 return -ENOENT;
660}
661
662static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
663{
664 struct pneigh_entry *n, **np;
665 u32 h;
666
667 for (h = 0; h <= PNEIGH_HASHMASK; h++) {
668 np = &tbl->phash_buckets[h];
669 while ((n = *np) != NULL) {
670 if (!dev || n->dev == dev) {
671 *np = n->next;
672 if (tbl->pdestructor)
673 tbl->pdestructor(n);
674 if (n->dev)
675 dev_put(n->dev);
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +0900676 release_net(pneigh_net(n));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 kfree(n);
678 continue;
679 }
680 np = &n->next;
681 }
682 }
683 return -ENOENT;
684}
685
Denis V. Lunev06f05112008-01-24 00:30:58 -0800686static void neigh_parms_destroy(struct neigh_parms *parms);
687
688static inline void neigh_parms_put(struct neigh_parms *parms)
689{
690 if (atomic_dec_and_test(&parms->refcnt))
691 neigh_parms_destroy(parms);
692}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
694/*
695 * neighbour must already be out of the table;
696 *
697 */
698void neigh_destroy(struct neighbour *neigh)
699{
David Millerda6a8fa2011-07-25 00:01:38 +0000700 struct net_device *dev = neigh->dev;
701
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
703
704 if (!neigh->dead) {
Joe Perchese005d192012-05-16 19:58:40 +0000705 pr_warn("Destroying alive neighbour %p\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 dump_stack();
707 return;
708 }
709
710 if (neigh_del_timer(neigh))
Joe Perchese005d192012-05-16 19:58:40 +0000711 pr_warn("Impossible event\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712
Eric Dumazetc9ab4d82013-06-28 02:37:42 -0700713 write_lock_bh(&neigh->lock);
714 __skb_queue_purge(&neigh->arp_queue);
715 write_unlock_bh(&neigh->lock);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000716 neigh->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717
David S. Miller447f2192011-12-19 15:04:41 -0500718 if (dev->netdev_ops->ndo_neigh_destroy)
719 dev->netdev_ops->ndo_neigh_destroy(neigh);
720
David Millerda6a8fa2011-07-25 00:01:38 +0000721 dev_put(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 neigh_parms_put(neigh->parms);
723
Joe Perchesd5d427c2013-04-15 15:17:19 +0000724 neigh_dbg(2, "neigh %p is destroyed\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 atomic_dec(&neigh->tbl->entries);
David Miller5b8b0062011-07-25 00:01:22 +0000727 kfree_rcu(neigh, rcu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900729EXPORT_SYMBOL(neigh_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730
731/* Neighbour state is suspicious;
732 disable fast path.
733
734 Called with write_locked neigh.
735 */
736static void neigh_suspect(struct neighbour *neigh)
737{
Joe Perchesd5d427c2013-04-15 15:17:19 +0000738 neigh_dbg(2, "neigh %p is suspected\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739
740 neigh->output = neigh->ops->output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741}
742
743/* Neighbour state is OK;
744 enable fast path.
745
746 Called with write_locked neigh.
747 */
748static void neigh_connect(struct neighbour *neigh)
749{
Joe Perchesd5d427c2013-04-15 15:17:19 +0000750 neigh_dbg(2, "neigh %p is connected\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751
752 neigh->output = neigh->ops->connected_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753}
754
Eric Dumazete4c4e442009-07-30 03:15:07 +0000755static void neigh_periodic_work(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756{
Eric Dumazete4c4e442009-07-30 03:15:07 +0000757 struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700758 struct neighbour *n;
759 struct neighbour __rcu **np;
Eric Dumazete4c4e442009-07-30 03:15:07 +0000760 unsigned int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000761 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
763 NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
764
Eric Dumazete4c4e442009-07-30 03:15:07 +0000765 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000766 nht = rcu_dereference_protected(tbl->nht,
767 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768
YOSHIFUJI Hideaki / 吉藤英明27246802013-01-22 05:20:05 +0000769 if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
770 goto out;
771
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 /*
773 * periodically recompute ReachableTime from random function
774 */
775
Eric Dumazete4c4e442009-07-30 03:15:07 +0000776 if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 struct neigh_parms *p;
Eric Dumazete4c4e442009-07-30 03:15:07 +0000778 tbl->last_rand = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 for (p = &tbl->parms; p; p = p->next)
780 p->reachable_time =
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100781 neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 }
783
David S. Millercd089332011-07-11 01:28:12 -0700784 for (i = 0 ; i < (1 << nht->hash_shift); i++) {
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000785 np = &nht->hash_buckets[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
Eric Dumazet767e97e2010-10-06 17:49:21 -0700787 while ((n = rcu_dereference_protected(*np,
788 lockdep_is_held(&tbl->lock))) != NULL) {
Eric Dumazete4c4e442009-07-30 03:15:07 +0000789 unsigned int state;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
Eric Dumazete4c4e442009-07-30 03:15:07 +0000791 write_lock(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792
Eric Dumazete4c4e442009-07-30 03:15:07 +0000793 state = n->nud_state;
794 if (state & (NUD_PERMANENT | NUD_IN_TIMER)) {
795 write_unlock(&n->lock);
796 goto next_elt;
797 }
798
799 if (time_before(n->used, n->confirmed))
800 n->used = n->confirmed;
801
802 if (atomic_read(&n->refcnt) == 1 &&
803 (state == NUD_FAILED ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100804 time_after(jiffies, n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) {
Eric Dumazete4c4e442009-07-30 03:15:07 +0000805 *np = n->next;
806 n->dead = 1;
807 write_unlock(&n->lock);
808 neigh_cleanup_and_release(n);
809 continue;
810 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 write_unlock(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
813next_elt:
Eric Dumazete4c4e442009-07-30 03:15:07 +0000814 np = &n->next;
815 }
816 /*
817 * It's fine to release lock here, even if hash table
818 * grows while we are preempted.
819 */
820 write_unlock_bh(&tbl->lock);
821 cond_resched();
822 write_lock_bh(&tbl->lock);
Michel Machado84338a62012-02-21 16:04:13 -0500823 nht = rcu_dereference_protected(tbl->nht,
824 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 }
YOSHIFUJI Hideaki / 吉藤英明27246802013-01-22 05:20:05 +0000826out:
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100827 /* Cycle through all hash buckets every BASE_REACHABLE_TIME/2 ticks.
828 * ARP entry timeouts range from 1/2 BASE_REACHABLE_TIME to 3/2
829 * BASE_REACHABLE_TIME.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 */
Eric Dumazete4c4e442009-07-30 03:15:07 +0000831 schedule_delayed_work(&tbl->gc_work,
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100832 NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME) >> 1);
Eric Dumazete4c4e442009-07-30 03:15:07 +0000833 write_unlock_bh(&tbl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834}
835
836static __inline__ int neigh_max_probes(struct neighbour *n)
837{
838 struct neigh_parms *p = n->parms;
Eric Dumazeta02cec22010-09-22 20:43:57 +0000839 return (n->nud_state & NUD_PROBE) ?
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100840 NEIGH_VAR(p, UCAST_PROBES) :
841 NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES) +
842 NEIGH_VAR(p, MCAST_PROBES);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843}
844
Timo Teras5ef12d92009-06-11 04:16:28 -0700845static void neigh_invalidate(struct neighbour *neigh)
Eric Dumazet0a141502010-03-09 19:40:54 +0000846 __releases(neigh->lock)
847 __acquires(neigh->lock)
Timo Teras5ef12d92009-06-11 04:16:28 -0700848{
849 struct sk_buff *skb;
850
851 NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
Joe Perchesd5d427c2013-04-15 15:17:19 +0000852 neigh_dbg(2, "neigh %p is failed\n", neigh);
Timo Teras5ef12d92009-06-11 04:16:28 -0700853 neigh->updated = jiffies;
854
855 /* It is very thin place. report_unreachable is very complicated
856 routine. Particularly, it can hit the same neighbour entry!
857
858 So that, we try to be accurate and avoid dead loop. --ANK
859 */
860 while (neigh->nud_state == NUD_FAILED &&
861 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
862 write_unlock(&neigh->lock);
863 neigh->ops->error_report(neigh, skb);
864 write_lock(&neigh->lock);
865 }
Eric Dumazetc9ab4d82013-06-28 02:37:42 -0700866 __skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000867 neigh->arp_queue_len_bytes = 0;
Timo Teras5ef12d92009-06-11 04:16:28 -0700868}
869
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000870static void neigh_probe(struct neighbour *neigh)
871 __releases(neigh->lock)
872{
Hannes Frederic Sowa4ed377e2013-09-21 06:32:34 +0200873 struct sk_buff *skb = skb_peek_tail(&neigh->arp_queue);
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000874 /* keep skb alive even if arp_queue overflows */
875 if (skb)
876 skb = skb_copy(skb, GFP_ATOMIC);
877 write_unlock(&neigh->lock);
878 neigh->ops->solicit(neigh, skb);
879 atomic_inc(&neigh->probes);
880 kfree_skb(skb);
881}
882
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883/* Called when a timer expires for a neighbour entry. */
884
885static void neigh_timer_handler(unsigned long arg)
886{
887 unsigned long now, next;
888 struct neighbour *neigh = (struct neighbour *)arg;
Eric Dumazet95c96172012-04-15 05:58:06 +0000889 unsigned int state;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 int notify = 0;
891
892 write_lock(&neigh->lock);
893
894 state = neigh->nud_state;
895 now = jiffies;
896 next = now + HZ;
897
David S. Miller045f7b32011-11-01 17:45:55 -0400898 if (!(state & NUD_IN_TIMER))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900
901 if (state & NUD_REACHABLE) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900902 if (time_before_eq(now,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 neigh->confirmed + neigh->parms->reachable_time)) {
Joe Perchesd5d427c2013-04-15 15:17:19 +0000904 neigh_dbg(2, "neigh %p is still alive\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 next = neigh->confirmed + neigh->parms->reachable_time;
906 } else if (time_before_eq(now,
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100907 neigh->used +
908 NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
Joe Perchesd5d427c2013-04-15 15:17:19 +0000909 neigh_dbg(2, "neigh %p is delayed\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800911 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 neigh_suspect(neigh);
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100913 next = now + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 } else {
Joe Perchesd5d427c2013-04-15 15:17:19 +0000915 neigh_dbg(2, "neigh %p is suspected\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 neigh->nud_state = NUD_STALE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800917 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 neigh_suspect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -0700919 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 }
921 } else if (state & NUD_DELAY) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900922 if (time_before_eq(now,
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100923 neigh->confirmed +
924 NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
Joe Perchesd5d427c2013-04-15 15:17:19 +0000925 neigh_dbg(2, "neigh %p is now reachable\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 neigh->nud_state = NUD_REACHABLE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800927 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 neigh_connect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -0700929 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 next = neigh->confirmed + neigh->parms->reachable_time;
931 } else {
Joe Perchesd5d427c2013-04-15 15:17:19 +0000932 neigh_dbg(2, "neigh %p is probed\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 neigh->nud_state = NUD_PROBE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800934 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 atomic_set(&neigh->probes, 0);
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100936 next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 }
938 } else {
939 /* NUD_PROBE|NUD_INCOMPLETE */
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100940 next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 }
942
943 if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
944 atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 neigh->nud_state = NUD_FAILED;
946 notify = 1;
Timo Teras5ef12d92009-06-11 04:16:28 -0700947 neigh_invalidate(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 }
949
950 if (neigh->nud_state & NUD_IN_TIMER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 if (time_before(next, jiffies + HZ/2))
952 next = jiffies + HZ/2;
Herbert Xu6fb99742005-10-23 16:37:48 +1000953 if (!mod_timer(&neigh->timer, next))
954 neigh_hold(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 }
956 if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000957 neigh_probe(neigh);
David S. Miller9ff56602008-02-17 18:39:54 -0800958 } else {
David S. Miller69cc64d2008-02-11 21:45:44 -0800959out:
David S. Miller9ff56602008-02-17 18:39:54 -0800960 write_unlock(&neigh->lock);
961 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
Thomas Grafd961db32007-08-08 23:12:56 -0700963 if (notify)
964 neigh_update_notify(neigh);
965
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 neigh_release(neigh);
967}
968
969int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
970{
971 int rc;
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000972 bool immediate_probe = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
974 write_lock_bh(&neigh->lock);
975
976 rc = 0;
977 if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
978 goto out_unlock_bh;
979
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100981 if (NEIGH_VAR(neigh->parms, MCAST_PROBES) +
982 NEIGH_VAR(neigh->parms, APP_PROBES)) {
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000983 unsigned long next, now = jiffies;
984
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100985 atomic_set(&neigh->probes,
986 NEIGH_VAR(neigh->parms, UCAST_PROBES));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 neigh->nud_state = NUD_INCOMPLETE;
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000988 neigh->updated = now;
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100989 next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
990 HZ/2);
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000991 neigh_add_timer(neigh, next);
992 immediate_probe = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 } else {
994 neigh->nud_state = NUD_FAILED;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800995 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 write_unlock_bh(&neigh->lock);
997
Wei Yongjunf3fbbe02009-02-25 00:37:32 +0000998 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 return 1;
1000 }
1001 } else if (neigh->nud_state & NUD_STALE) {
Joe Perchesd5d427c2013-04-15 15:17:19 +00001002 neigh_dbg(2, "neigh %p is delayed\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001004 neigh->updated = jiffies;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001005 neigh_add_timer(neigh, jiffies +
1006 NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 }
1008
1009 if (neigh->nud_state == NUD_INCOMPLETE) {
1010 if (skb) {
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001011 while (neigh->arp_queue_len_bytes + skb->truesize >
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001012 NEIGH_VAR(neigh->parms, QUEUE_LEN_BYTES)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 struct sk_buff *buff;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001014
David S. Millerf72051b2008-09-23 01:11:18 -07001015 buff = __skb_dequeue(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001016 if (!buff)
1017 break;
1018 neigh->arp_queue_len_bytes -= buff->truesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 kfree_skb(buff);
Neil Horman9a6d2762008-07-16 20:50:49 -07001020 NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 }
Eric Dumazeta4731132010-05-27 16:09:39 -07001022 skb_dst_force(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 __skb_queue_tail(&neigh->arp_queue, skb);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001024 neigh->arp_queue_len_bytes += skb->truesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 }
1026 rc = 1;
1027 }
1028out_unlock_bh:
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001029 if (immediate_probe)
1030 neigh_probe(neigh);
1031 else
1032 write_unlock(&neigh->lock);
1033 local_bh_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 return rc;
1035}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001036EXPORT_SYMBOL(__neigh_event_send);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037
David S. Millerf6b72b62011-07-14 07:53:20 -07001038static void neigh_update_hhs(struct neighbour *neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039{
1040 struct hh_cache *hh;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001041 void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
Doug Kehn91a72a72010-07-14 18:02:16 -07001042 = NULL;
1043
1044 if (neigh->dev->header_ops)
1045 update = neigh->dev->header_ops->cache_update;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046
1047 if (update) {
David S. Millerf6b72b62011-07-14 07:53:20 -07001048 hh = &neigh->hh;
1049 if (hh->hh_len) {
Stephen Hemminger3644f0c2006-12-07 15:08:17 -08001050 write_seqlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 update(hh, neigh->dev, neigh->ha);
Stephen Hemminger3644f0c2006-12-07 15:08:17 -08001052 write_sequnlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 }
1054 }
1055}
1056
1057
1058
1059/* Generic update routine.
1060 -- lladdr is new lladdr or NULL, if it is not supplied.
1061 -- new is new state.
1062 -- flags
1063 NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr,
1064 if it is different.
1065 NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected"
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001066 lladdr instead of overriding it
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 if it is different.
1068 It also allows to retain current state
1069 if lladdr is unchanged.
1070 NEIGH_UPDATE_F_ADMIN means that the change is administrative.
1071
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001072 NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 NTF_ROUTER flag.
1074 NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as
1075 a router.
1076
1077 Caller MUST hold reference count on the entry.
1078 */
1079
1080int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
1081 u32 flags)
1082{
1083 u8 old;
1084 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 int notify = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 struct net_device *dev;
1087 int update_isrouter = 0;
1088
1089 write_lock_bh(&neigh->lock);
1090
1091 dev = neigh->dev;
1092 old = neigh->nud_state;
1093 err = -EPERM;
1094
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001095 if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 (old & (NUD_NOARP | NUD_PERMANENT)))
1097 goto out;
1098
1099 if (!(new & NUD_VALID)) {
1100 neigh_del_timer(neigh);
1101 if (old & NUD_CONNECTED)
1102 neigh_suspect(neigh);
1103 neigh->nud_state = new;
1104 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 notify = old & NUD_VALID;
Timo Teras5ef12d92009-06-11 04:16:28 -07001106 if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
1107 (new & NUD_FAILED)) {
1108 neigh_invalidate(neigh);
1109 notify = 1;
1110 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 goto out;
1112 }
1113
1114 /* Compare new lladdr with cached one */
1115 if (!dev->addr_len) {
1116 /* First case: device needs no address. */
1117 lladdr = neigh->ha;
1118 } else if (lladdr) {
1119 /* The second case: if something is already cached
1120 and a new address is proposed:
1121 - compare new & old
1122 - if they are different, check override flag
1123 */
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001124 if ((old & NUD_VALID) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 !memcmp(lladdr, neigh->ha, dev->addr_len))
1126 lladdr = neigh->ha;
1127 } else {
1128 /* No address is supplied; if we know something,
1129 use it, otherwise discard the request.
1130 */
1131 err = -EINVAL;
1132 if (!(old & NUD_VALID))
1133 goto out;
1134 lladdr = neigh->ha;
1135 }
1136
1137 if (new & NUD_CONNECTED)
1138 neigh->confirmed = jiffies;
1139 neigh->updated = jiffies;
1140
1141 /* If entry was valid and address is not changed,
1142 do not change entry state, if new one is STALE.
1143 */
1144 err = 0;
1145 update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
1146 if (old & NUD_VALID) {
1147 if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {
1148 update_isrouter = 0;
1149 if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&
1150 (old & NUD_CONNECTED)) {
1151 lladdr = neigh->ha;
1152 new = NUD_STALE;
1153 } else
1154 goto out;
1155 } else {
1156 if (lladdr == neigh->ha && new == NUD_STALE &&
1157 ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) ||
1158 (old & NUD_CONNECTED))
1159 )
1160 new = old;
1161 }
1162 }
1163
1164 if (new != old) {
1165 neigh_del_timer(neigh);
Pavel Emelyanova43d8992007-12-20 15:49:05 -08001166 if (new & NUD_IN_TIMER)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001167 neigh_add_timer(neigh, (jiffies +
1168 ((new & NUD_REACHABLE) ?
David S. Miller667347f2005-09-27 12:07:44 -07001169 neigh->parms->reachable_time :
1170 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 neigh->nud_state = new;
1172 }
1173
1174 if (lladdr != neigh->ha) {
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001175 write_seqlock(&neigh->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 memcpy(&neigh->ha, lladdr, dev->addr_len);
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001177 write_sequnlock(&neigh->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 neigh_update_hhs(neigh);
1179 if (!(new & NUD_CONNECTED))
1180 neigh->confirmed = jiffies -
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001181 (NEIGH_VAR(neigh->parms, BASE_REACHABLE_TIME) << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 }
1184 if (new == old)
1185 goto out;
1186 if (new & NUD_CONNECTED)
1187 neigh_connect(neigh);
1188 else
1189 neigh_suspect(neigh);
1190 if (!(old & NUD_VALID)) {
1191 struct sk_buff *skb;
1192
1193 /* Again: avoid dead loop if something went wrong */
1194
1195 while (neigh->nud_state & NUD_VALID &&
1196 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
David S. Miller69cce1d2011-07-17 23:09:49 -07001197 struct dst_entry *dst = skb_dst(skb);
1198 struct neighbour *n2, *n1 = neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 write_unlock_bh(&neigh->lock);
roy.qing.li@gmail.come049f282011-10-17 22:32:42 +00001200
1201 rcu_read_lock();
David S. Miller13a43d92012-07-02 22:15:37 -07001202
1203 /* Why not just use 'neigh' as-is? The problem is that
1204 * things such as shaper, eql, and sch_teql can end up
1205 * using alternative, different, neigh objects to output
1206 * the packet in the output path. So what we need to do
1207 * here is re-lookup the top-level neigh in the path so
1208 * we can reinject the packet there.
1209 */
1210 n2 = NULL;
1211 if (dst) {
1212 n2 = dst_neigh_lookup_skb(dst, skb);
1213 if (n2)
1214 n1 = n2;
1215 }
David S. Miller8f40b162011-07-17 13:34:11 -07001216 n1->output(n1, skb);
David S. Miller13a43d92012-07-02 22:15:37 -07001217 if (n2)
1218 neigh_release(n2);
roy.qing.li@gmail.come049f282011-10-17 22:32:42 +00001219 rcu_read_unlock();
1220
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 write_lock_bh(&neigh->lock);
1222 }
Eric Dumazetc9ab4d82013-06-28 02:37:42 -07001223 __skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001224 neigh->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 }
1226out:
1227 if (update_isrouter) {
1228 neigh->flags = (flags & NEIGH_UPDATE_F_ISROUTER) ?
1229 (neigh->flags | NTF_ROUTER) :
1230 (neigh->flags & ~NTF_ROUTER);
1231 }
1232 write_unlock_bh(&neigh->lock);
Tom Tucker8d717402006-07-30 20:43:36 -07001233
1234 if (notify)
Thomas Grafd961db32007-08-08 23:12:56 -07001235 neigh_update_notify(neigh);
1236
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 return err;
1238}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001239EXPORT_SYMBOL(neigh_update);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240
1241struct neighbour *neigh_event_ns(struct neigh_table *tbl,
1242 u8 *lladdr, void *saddr,
1243 struct net_device *dev)
1244{
1245 struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
1246 lladdr || !dev->addr_len);
1247 if (neigh)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001248 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 NEIGH_UPDATE_F_OVERRIDE);
1250 return neigh;
1251}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001252EXPORT_SYMBOL(neigh_event_ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
Eric Dumazet34d101d2010-10-11 09:16:57 -07001254/* called with read_lock_bh(&n->lock); */
David S. Millerf6b72b62011-07-14 07:53:20 -07001255static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 struct net_device *dev = dst->dev;
David S. Millerf6b72b62011-07-14 07:53:20 -07001258 __be16 prot = dst->ops->protocol;
1259 struct hh_cache *hh = &n->hh;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001260
1261 write_lock_bh(&n->lock);
Eric Dumazet34d101d2010-10-11 09:16:57 -07001262
David S. Millerf6b72b62011-07-14 07:53:20 -07001263 /* Only one thread can come in here and initialize the
1264 * hh_cache entry.
1265 */
David S. Millerb23b5452011-07-16 17:45:02 -07001266 if (!hh->hh_len)
1267 dev->header_ops->cache(n, hh, prot);
David S. Millerf6b72b62011-07-14 07:53:20 -07001268
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001269 write_unlock_bh(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270}
1271
1272/* This function can be used in contexts, where only old dev_queue_xmit
Eric Dumazet767e97e2010-10-06 17:49:21 -07001273 * worked, f.e. if you want to override normal output path (eql, shaper),
1274 * but resolution is not made yet.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 */
1276
David S. Miller8f40b162011-07-17 13:34:11 -07001277int neigh_compat_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278{
1279 struct net_device *dev = skb->dev;
1280
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03001281 __skb_pull(skb, skb_network_offset(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282
Stephen Hemminger0c4e8582007-10-09 01:36:32 -07001283 if (dev_hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL,
1284 skb->len) < 0 &&
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001285 dev->header_ops->rebuild(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 return 0;
1287
1288 return dev_queue_xmit(skb);
1289}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001290EXPORT_SYMBOL(neigh_compat_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291
1292/* Slow and careful. */
1293
David S. Miller8f40b162011-07-17 13:34:11 -07001294int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295{
Eric Dumazetadf30902009-06-02 05:19:30 +00001296 struct dst_entry *dst = skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 int rc = 0;
1298
David S. Miller8f40b162011-07-17 13:34:11 -07001299 if (!dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 goto discard;
1301
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 if (!neigh_event_send(neigh, skb)) {
1303 int err;
1304 struct net_device *dev = neigh->dev;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001305 unsigned int seq;
Eric Dumazet34d101d2010-10-11 09:16:57 -07001306
David S. Millerf6b72b62011-07-14 07:53:20 -07001307 if (dev->header_ops->cache && !neigh->hh.hh_len)
1308 neigh_hh_init(neigh, dst);
Eric Dumazet34d101d2010-10-11 09:16:57 -07001309
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001310 do {
ramesh.nagappa@gmail.come1f16502012-10-05 19:10:15 +00001311 __skb_pull(skb, skb_network_offset(skb));
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001312 seq = read_seqbegin(&neigh->ha_lock);
1313 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1314 neigh->ha, NULL, skb->len);
1315 } while (read_seqretry(&neigh->ha_lock, seq));
Eric Dumazet34d101d2010-10-11 09:16:57 -07001316
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 if (err >= 0)
David S. Miller542d4d62011-07-16 18:06:24 -07001318 rc = dev_queue_xmit(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 else
1320 goto out_kfree_skb;
1321 }
1322out:
1323 return rc;
1324discard:
Joe Perchesd5d427c2013-04-15 15:17:19 +00001325 neigh_dbg(1, "%s: dst=%p neigh=%p\n", __func__, dst, neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326out_kfree_skb:
1327 rc = -EINVAL;
1328 kfree_skb(skb);
1329 goto out;
1330}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001331EXPORT_SYMBOL(neigh_resolve_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332
1333/* As fast as possible without hh cache */
1334
David S. Miller8f40b162011-07-17 13:34:11 -07001335int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 struct net_device *dev = neigh->dev;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001338 unsigned int seq;
David S. Miller8f40b162011-07-17 13:34:11 -07001339 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001341 do {
ramesh.nagappa@gmail.come1f16502012-10-05 19:10:15 +00001342 __skb_pull(skb, skb_network_offset(skb));
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001343 seq = read_seqbegin(&neigh->ha_lock);
1344 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1345 neigh->ha, NULL, skb->len);
1346 } while (read_seqretry(&neigh->ha_lock, seq));
1347
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 if (err >= 0)
David S. Miller542d4d62011-07-16 18:06:24 -07001349 err = dev_queue_xmit(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 else {
1351 err = -EINVAL;
1352 kfree_skb(skb);
1353 }
1354 return err;
1355}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001356EXPORT_SYMBOL(neigh_connected_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357
David S. Miller8f40b162011-07-17 13:34:11 -07001358int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
1359{
1360 return dev_queue_xmit(skb);
1361}
1362EXPORT_SYMBOL(neigh_direct_output);
1363
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364static void neigh_proxy_process(unsigned long arg)
1365{
1366 struct neigh_table *tbl = (struct neigh_table *)arg;
1367 long sched_next = 0;
1368 unsigned long now = jiffies;
David S. Millerf72051b2008-09-23 01:11:18 -07001369 struct sk_buff *skb, *n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
1371 spin_lock(&tbl->proxy_queue.lock);
1372
David S. Millerf72051b2008-09-23 01:11:18 -07001373 skb_queue_walk_safe(&tbl->proxy_queue, skb, n) {
1374 long tdif = NEIGH_CB(skb)->sched_next - now;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 if (tdif <= 0) {
David S. Millerf72051b2008-09-23 01:11:18 -07001377 struct net_device *dev = skb->dev;
Eric Dumazet20e60742011-08-22 19:32:42 +00001378
David S. Millerf72051b2008-09-23 01:11:18 -07001379 __skb_unlink(skb, &tbl->proxy_queue);
Eric Dumazet20e60742011-08-22 19:32:42 +00001380 if (tbl->proxy_redo && netif_running(dev)) {
1381 rcu_read_lock();
David S. Millerf72051b2008-09-23 01:11:18 -07001382 tbl->proxy_redo(skb);
Eric Dumazet20e60742011-08-22 19:32:42 +00001383 rcu_read_unlock();
1384 } else {
David S. Millerf72051b2008-09-23 01:11:18 -07001385 kfree_skb(skb);
Eric Dumazet20e60742011-08-22 19:32:42 +00001386 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
1388 dev_put(dev);
1389 } else if (!sched_next || tdif < sched_next)
1390 sched_next = tdif;
1391 }
1392 del_timer(&tbl->proxy_timer);
1393 if (sched_next)
1394 mod_timer(&tbl->proxy_timer, jiffies + sched_next);
1395 spin_unlock(&tbl->proxy_queue.lock);
1396}
1397
1398void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
1399 struct sk_buff *skb)
1400{
1401 unsigned long now = jiffies;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001402 unsigned long sched_next = now + (net_random() %
1403 NEIGH_VAR(p, PROXY_DELAY));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001405 if (tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 kfree_skb(skb);
1407 return;
1408 }
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001409
1410 NEIGH_CB(skb)->sched_next = sched_next;
1411 NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412
1413 spin_lock(&tbl->proxy_queue.lock);
1414 if (del_timer(&tbl->proxy_timer)) {
1415 if (time_before(tbl->proxy_timer.expires, sched_next))
1416 sched_next = tbl->proxy_timer.expires;
1417 }
Eric Dumazetadf30902009-06-02 05:19:30 +00001418 skb_dst_drop(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 dev_hold(skb->dev);
1420 __skb_queue_tail(&tbl->proxy_queue, skb);
1421 mod_timer(&tbl->proxy_timer, sched_next);
1422 spin_unlock(&tbl->proxy_queue.lock);
1423}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001424EXPORT_SYMBOL(pneigh_enqueue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07001426static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
Eric W. Biederman426b5302008-01-24 00:13:18 -08001427 struct net *net, int ifindex)
1428{
1429 struct neigh_parms *p;
1430
1431 for (p = &tbl->parms; p; p = p->next) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09001432 if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
Gao feng170d6f92013-06-20 10:01:33 +08001433 (!p->dev && !ifindex && net_eq(net, &init_net)))
Eric W. Biederman426b5302008-01-24 00:13:18 -08001434 return p;
1435 }
1436
1437 return NULL;
1438}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439
1440struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
1441 struct neigh_table *tbl)
1442{
Gao fengcf89d6b2013-06-20 10:01:32 +08001443 struct neigh_parms *p;
Stephen Hemminger00829822008-11-20 20:14:53 -08001444 struct net *net = dev_net(dev);
1445 const struct net_device_ops *ops = dev->netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446
Gao fengcf89d6b2013-06-20 10:01:32 +08001447 p = kmemdup(&tbl->parms, sizeof(*p), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 if (p) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 p->tbl = tbl;
1450 atomic_set(&p->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 p->reachable_time =
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001452 neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
Denis V. Lunev486b51d2008-01-14 22:59:59 -08001453 dev_hold(dev);
1454 p->dev = dev;
Eric Dumazete42ea982008-11-12 00:54:54 -08001455 write_pnet(&p->net, hold_net(net));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 p->sysctl_table = NULL;
Veaceslav Falico63134802013-08-02 19:07:38 +02001457
1458 if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
1459 release_net(net);
1460 dev_put(dev);
1461 kfree(p);
1462 return NULL;
1463 }
1464
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 write_lock_bh(&tbl->lock);
1466 p->next = tbl->parms.next;
1467 tbl->parms.next = p;
1468 write_unlock_bh(&tbl->lock);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01001469
1470 neigh_parms_data_state_cleanall(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 }
1472 return p;
1473}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001474EXPORT_SYMBOL(neigh_parms_alloc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475
1476static void neigh_rcu_free_parms(struct rcu_head *head)
1477{
1478 struct neigh_parms *parms =
1479 container_of(head, struct neigh_parms, rcu_head);
1480
1481 neigh_parms_put(parms);
1482}
1483
1484void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
1485{
1486 struct neigh_parms **p;
1487
1488 if (!parms || parms == &tbl->parms)
1489 return;
1490 write_lock_bh(&tbl->lock);
1491 for (p = &tbl->parms.next; *p; p = &(*p)->next) {
1492 if (*p == parms) {
1493 *p = parms->next;
1494 parms->dead = 1;
1495 write_unlock_bh(&tbl->lock);
David S. Millercecbb632008-01-20 16:39:03 -08001496 if (parms->dev)
1497 dev_put(parms->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
1499 return;
1500 }
1501 }
1502 write_unlock_bh(&tbl->lock);
Joe Perchesd5d427c2013-04-15 15:17:19 +00001503 neigh_dbg(1, "%s: not found\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001505EXPORT_SYMBOL(neigh_parms_release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506
Denis V. Lunev06f05112008-01-24 00:30:58 -08001507static void neigh_parms_destroy(struct neigh_parms *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508{
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +09001509 release_net(neigh_parms_net(parms));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 kfree(parms);
1511}
1512
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001513static struct lock_class_key neigh_table_proxy_queue_class;
1514
Hiroaki SHIMODAdcd2ba92012-04-13 07:34:44 +00001515static void neigh_table_init_no_netlink(struct neigh_table *tbl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516{
1517 unsigned long now = jiffies;
1518 unsigned long phsize;
1519
Eric Dumazete42ea982008-11-12 00:54:54 -08001520 write_pnet(&tbl->parms.net, &init_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 atomic_set(&tbl->parms.refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 tbl->parms.reachable_time =
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001523 neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 tbl->stats = alloc_percpu(struct neigh_statistics);
1526 if (!tbl->stats)
1527 panic("cannot create neighbour cache statistics");
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001528
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529#ifdef CONFIG_PROC_FS
Alexey Dobriyan9b739ba2008-11-11 16:47:44 -08001530 if (!proc_create_data(tbl->id, 0, init_net.proc_net_stat,
1531 &neigh_stat_seq_fops, tbl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 panic("cannot create neighbour proc dir entry");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533#endif
1534
David S. Millercd089332011-07-11 01:28:12 -07001535 RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536
1537 phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
Andrew Morton77d04bd2006-04-07 14:52:59 -07001538 tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001540 if (!tbl->nht || !tbl->phash_buckets)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 panic("cannot allocate neighbour cache hashes");
1542
YOSHIFUJI Hideaki / 吉藤英明08433ef2013-01-24 00:44:23 +00001543 if (!tbl->entry_size)
1544 tbl->entry_size = ALIGN(offsetof(struct neighbour, primary_key) +
1545 tbl->key_len, NEIGH_PRIV_ALIGN);
1546 else
1547 WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN);
1548
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 rwlock_init(&tbl->lock);
Tejun Heo203b42f2012-08-21 13:18:23 -07001550 INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work);
Eric Dumazete4c4e442009-07-30 03:15:07 +00001551 schedule_delayed_work(&tbl->gc_work, tbl->parms.reachable_time);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -08001552 setup_timer(&tbl->proxy_timer, neigh_proxy_process, (unsigned long)tbl);
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001553 skb_queue_head_init_class(&tbl->proxy_queue,
1554 &neigh_table_proxy_queue_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555
1556 tbl->last_flush = now;
1557 tbl->last_rand = now + tbl->parms.reachable_time * 20;
Simon Kelleybd89efc2006-05-12 14:56:08 -07001558}
1559
1560void neigh_table_init(struct neigh_table *tbl)
1561{
1562 struct neigh_table *tmp;
1563
1564 neigh_table_init_no_netlink(tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 write_lock(&neigh_tbl_lock);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001566 for (tmp = neigh_tables; tmp; tmp = tmp->next) {
1567 if (tmp->family == tbl->family)
1568 break;
1569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 tbl->next = neigh_tables;
1571 neigh_tables = tbl;
1572 write_unlock(&neigh_tbl_lock);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001573
1574 if (unlikely(tmp)) {
Joe Perchese005d192012-05-16 19:58:40 +00001575 pr_err("Registering multiple tables for family %d\n",
1576 tbl->family);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001577 dump_stack();
1578 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001580EXPORT_SYMBOL(neigh_table_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581
1582int neigh_table_clear(struct neigh_table *tbl)
1583{
1584 struct neigh_table **tp;
1585
1586 /* It is not clean... Fix it to unload IPv6 module safely */
Tejun Heoa5c30b32010-10-19 06:04:42 +00001587 cancel_delayed_work_sync(&tbl->gc_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 del_timer_sync(&tbl->proxy_timer);
1589 pneigh_queue_purge(&tbl->proxy_queue);
1590 neigh_ifdown(tbl, NULL);
1591 if (atomic_read(&tbl->entries))
Joe Perchese005d192012-05-16 19:58:40 +00001592 pr_crit("neighbour leakage\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 write_lock(&neigh_tbl_lock);
1594 for (tp = &neigh_tables; *tp; tp = &(*tp)->next) {
1595 if (*tp == tbl) {
1596 *tp = tbl->next;
1597 break;
1598 }
1599 }
1600 write_unlock(&neigh_tbl_lock);
1601
Eric Dumazet6193d2b2011-01-19 22:02:47 +00001602 call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
1603 neigh_hash_free_rcu);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001604 tbl->nht = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605
1606 kfree(tbl->phash_buckets);
1607 tbl->phash_buckets = NULL;
1608
Alexey Dobriyan3f192b52007-11-05 21:28:13 -08001609 remove_proc_entry(tbl->id, init_net.proc_net_stat);
1610
Kirill Korotaev3fcde742006-09-01 01:34:10 -07001611 free_percpu(tbl->stats);
1612 tbl->stats = NULL;
1613
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 return 0;
1615}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001616EXPORT_SYMBOL(neigh_table_clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617
Thomas Graf661d2962013-03-21 07:45:29 +00001618static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001620 struct net *net = sock_net(skb->sk);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001621 struct ndmsg *ndm;
1622 struct nlattr *dst_attr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 struct neigh_table *tbl;
1624 struct net_device *dev = NULL;
Thomas Grafa14a49d2006-08-07 17:53:08 -07001625 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626
Eric Dumazet110b2492010-10-04 04:27:36 +00001627 ASSERT_RTNL();
Thomas Grafa14a49d2006-08-07 17:53:08 -07001628 if (nlmsg_len(nlh) < sizeof(*ndm))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 goto out;
1630
Thomas Grafa14a49d2006-08-07 17:53:08 -07001631 dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
1632 if (dst_attr == NULL)
1633 goto out;
1634
1635 ndm = nlmsg_data(nlh);
1636 if (ndm->ndm_ifindex) {
Eric Dumazet110b2492010-10-04 04:27:36 +00001637 dev = __dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001638 if (dev == NULL) {
1639 err = -ENODEV;
1640 goto out;
1641 }
1642 }
1643
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 read_lock(&neigh_tbl_lock);
1645 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
Thomas Grafa14a49d2006-08-07 17:53:08 -07001646 struct neighbour *neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647
1648 if (tbl->family != ndm->ndm_family)
1649 continue;
1650 read_unlock(&neigh_tbl_lock);
1651
Thomas Grafa14a49d2006-08-07 17:53:08 -07001652 if (nla_len(dst_attr) < tbl->key_len)
Eric Dumazet110b2492010-10-04 04:27:36 +00001653 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654
1655 if (ndm->ndm_flags & NTF_PROXY) {
Eric W. Biederman426b5302008-01-24 00:13:18 -08001656 err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
Eric Dumazet110b2492010-10-04 04:27:36 +00001657 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 }
1659
Thomas Grafa14a49d2006-08-07 17:53:08 -07001660 if (dev == NULL)
Eric Dumazet110b2492010-10-04 04:27:36 +00001661 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662
Thomas Grafa14a49d2006-08-07 17:53:08 -07001663 neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
1664 if (neigh == NULL) {
1665 err = -ENOENT;
Eric Dumazet110b2492010-10-04 04:27:36 +00001666 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 }
Thomas Grafa14a49d2006-08-07 17:53:08 -07001668
1669 err = neigh_update(neigh, NULL, NUD_FAILED,
1670 NEIGH_UPDATE_F_OVERRIDE |
1671 NEIGH_UPDATE_F_ADMIN);
1672 neigh_release(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001673 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 }
1675 read_unlock(&neigh_tbl_lock);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001676 err = -EAFNOSUPPORT;
1677
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678out:
1679 return err;
1680}
1681
Thomas Graf661d2962013-03-21 07:45:29 +00001682static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001684 struct net *net = sock_net(skb->sk);
Thomas Graf5208deb2006-08-07 17:55:40 -07001685 struct ndmsg *ndm;
1686 struct nlattr *tb[NDA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 struct neigh_table *tbl;
1688 struct net_device *dev = NULL;
Thomas Graf5208deb2006-08-07 17:55:40 -07001689 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
Eric Dumazet110b2492010-10-04 04:27:36 +00001691 ASSERT_RTNL();
Thomas Graf5208deb2006-08-07 17:55:40 -07001692 err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
1693 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 goto out;
1695
Thomas Graf5208deb2006-08-07 17:55:40 -07001696 err = -EINVAL;
1697 if (tb[NDA_DST] == NULL)
1698 goto out;
1699
1700 ndm = nlmsg_data(nlh);
1701 if (ndm->ndm_ifindex) {
Eric Dumazet110b2492010-10-04 04:27:36 +00001702 dev = __dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Graf5208deb2006-08-07 17:55:40 -07001703 if (dev == NULL) {
1704 err = -ENODEV;
1705 goto out;
1706 }
1707
1708 if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len)
Eric Dumazet110b2492010-10-04 04:27:36 +00001709 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001710 }
1711
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 read_lock(&neigh_tbl_lock);
1713 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
Thomas Graf5208deb2006-08-07 17:55:40 -07001714 int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE;
1715 struct neighbour *neigh;
1716 void *dst, *lladdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717
1718 if (tbl->family != ndm->ndm_family)
1719 continue;
1720 read_unlock(&neigh_tbl_lock);
1721
Thomas Graf5208deb2006-08-07 17:55:40 -07001722 if (nla_len(tb[NDA_DST]) < tbl->key_len)
Eric Dumazet110b2492010-10-04 04:27:36 +00001723 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001724 dst = nla_data(tb[NDA_DST]);
1725 lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726
1727 if (ndm->ndm_flags & NTF_PROXY) {
Ville Nuorvala62dd9312006-09-22 14:43:19 -07001728 struct pneigh_entry *pn;
1729
1730 err = -ENOBUFS;
Eric W. Biederman426b5302008-01-24 00:13:18 -08001731 pn = pneigh_lookup(tbl, net, dst, dev, 1);
Ville Nuorvala62dd9312006-09-22 14:43:19 -07001732 if (pn) {
1733 pn->flags = ndm->ndm_flags;
1734 err = 0;
1735 }
Eric Dumazet110b2492010-10-04 04:27:36 +00001736 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 }
1738
Thomas Graf5208deb2006-08-07 17:55:40 -07001739 if (dev == NULL)
Eric Dumazet110b2492010-10-04 04:27:36 +00001740 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001741
1742 neigh = neigh_lookup(tbl, dst, dev);
1743 if (neigh == NULL) {
1744 if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
1745 err = -ENOENT;
Eric Dumazet110b2492010-10-04 04:27:36 +00001746 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001747 }
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001748
Thomas Graf5208deb2006-08-07 17:55:40 -07001749 neigh = __neigh_lookup_errno(tbl, dst, dev);
1750 if (IS_ERR(neigh)) {
1751 err = PTR_ERR(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001752 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001753 }
1754 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 if (nlh->nlmsg_flags & NLM_F_EXCL) {
1756 err = -EEXIST;
Thomas Graf5208deb2006-08-07 17:55:40 -07001757 neigh_release(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001758 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 }
Thomas Graf5208deb2006-08-07 17:55:40 -07001760
1761 if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
1762 flags &= ~NEIGH_UPDATE_F_OVERRIDE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 }
1764
Eric Biederman0c5c2d32009-03-04 00:03:08 -08001765 if (ndm->ndm_flags & NTF_USE) {
1766 neigh_event_send(neigh, NULL);
1767 err = 0;
1768 } else
1769 err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
Thomas Graf5208deb2006-08-07 17:55:40 -07001770 neigh_release(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001771 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 }
1773
1774 read_unlock(&neigh_tbl_lock);
Thomas Graf5208deb2006-08-07 17:55:40 -07001775 err = -EAFNOSUPPORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776out:
1777 return err;
1778}
1779
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001780static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
1781{
Thomas Grafca860fb2006-08-07 18:00:18 -07001782 struct nlattr *nest;
1783
1784 nest = nla_nest_start(skb, NDTA_PARMS);
1785 if (nest == NULL)
1786 return -ENOBUFS;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001787
David S. Miller9a6308d2012-04-01 20:06:28 -04001788 if ((parms->dev &&
1789 nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) ||
1790 nla_put_u32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt)) ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001791 nla_put_u32(skb, NDTPA_QUEUE_LENBYTES,
1792 NEIGH_VAR(parms, QUEUE_LEN_BYTES)) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04001793 /* approximative value for deprecated QUEUE_LEN (in packets) */
1794 nla_put_u32(skb, NDTPA_QUEUE_LEN,
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001795 NEIGH_VAR(parms, QUEUE_LEN_BYTES) / SKB_TRUESIZE(ETH_FRAME_LEN)) ||
1796 nla_put_u32(skb, NDTPA_PROXY_QLEN, NEIGH_VAR(parms, PROXY_QLEN)) ||
1797 nla_put_u32(skb, NDTPA_APP_PROBES, NEIGH_VAR(parms, APP_PROBES)) ||
1798 nla_put_u32(skb, NDTPA_UCAST_PROBES,
1799 NEIGH_VAR(parms, UCAST_PROBES)) ||
1800 nla_put_u32(skb, NDTPA_MCAST_PROBES,
1801 NEIGH_VAR(parms, MCAST_PROBES)) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04001802 nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time) ||
1803 nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME,
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001804 NEIGH_VAR(parms, BASE_REACHABLE_TIME)) ||
1805 nla_put_msecs(skb, NDTPA_GC_STALETIME,
1806 NEIGH_VAR(parms, GC_STALETIME)) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04001807 nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME,
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001808 NEIGH_VAR(parms, DELAY_PROBE_TIME)) ||
1809 nla_put_msecs(skb, NDTPA_RETRANS_TIME,
1810 NEIGH_VAR(parms, RETRANS_TIME)) ||
1811 nla_put_msecs(skb, NDTPA_ANYCAST_DELAY,
1812 NEIGH_VAR(parms, ANYCAST_DELAY)) ||
1813 nla_put_msecs(skb, NDTPA_PROXY_DELAY,
1814 NEIGH_VAR(parms, PROXY_DELAY)) ||
1815 nla_put_msecs(skb, NDTPA_LOCKTIME,
1816 NEIGH_VAR(parms, LOCKTIME)))
David S. Miller9a6308d2012-04-01 20:06:28 -04001817 goto nla_put_failure;
Thomas Grafca860fb2006-08-07 18:00:18 -07001818 return nla_nest_end(skb, nest);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001819
Thomas Grafca860fb2006-08-07 18:00:18 -07001820nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07001821 nla_nest_cancel(skb, nest);
1822 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001823}
1824
Thomas Grafca860fb2006-08-07 18:00:18 -07001825static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
1826 u32 pid, u32 seq, int type, int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001827{
1828 struct nlmsghdr *nlh;
1829 struct ndtmsg *ndtmsg;
1830
Thomas Grafca860fb2006-08-07 18:00:18 -07001831 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
1832 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001833 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001834
Thomas Grafca860fb2006-08-07 18:00:18 -07001835 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001836
1837 read_lock_bh(&tbl->lock);
1838 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07001839 ndtmsg->ndtm_pad1 = 0;
1840 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001841
David S. Miller9a6308d2012-04-01 20:06:28 -04001842 if (nla_put_string(skb, NDTA_NAME, tbl->id) ||
1843 nla_put_msecs(skb, NDTA_GC_INTERVAL, tbl->gc_interval) ||
1844 nla_put_u32(skb, NDTA_THRESH1, tbl->gc_thresh1) ||
1845 nla_put_u32(skb, NDTA_THRESH2, tbl->gc_thresh2) ||
1846 nla_put_u32(skb, NDTA_THRESH3, tbl->gc_thresh3))
1847 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001848 {
1849 unsigned long now = jiffies;
1850 unsigned int flush_delta = now - tbl->last_flush;
1851 unsigned int rand_delta = now - tbl->last_rand;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001852 struct neigh_hash_table *nht;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001853 struct ndt_config ndc = {
1854 .ndtc_key_len = tbl->key_len,
1855 .ndtc_entry_size = tbl->entry_size,
1856 .ndtc_entries = atomic_read(&tbl->entries),
1857 .ndtc_last_flush = jiffies_to_msecs(flush_delta),
1858 .ndtc_last_rand = jiffies_to_msecs(rand_delta),
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001859 .ndtc_proxy_qlen = tbl->proxy_queue.qlen,
1860 };
1861
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001862 rcu_read_lock_bh();
1863 nht = rcu_dereference_bh(tbl->nht);
David S. Miller2c2aba62011-12-28 15:06:58 -05001864 ndc.ndtc_hash_rnd = nht->hash_rnd[0];
David S. Millercd089332011-07-11 01:28:12 -07001865 ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001866 rcu_read_unlock_bh();
1867
David S. Miller9a6308d2012-04-01 20:06:28 -04001868 if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc))
1869 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001870 }
1871
1872 {
1873 int cpu;
1874 struct ndt_stats ndst;
1875
1876 memset(&ndst, 0, sizeof(ndst));
1877
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001878 for_each_possible_cpu(cpu) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001879 struct neigh_statistics *st;
1880
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001881 st = per_cpu_ptr(tbl->stats, cpu);
1882 ndst.ndts_allocs += st->allocs;
1883 ndst.ndts_destroys += st->destroys;
1884 ndst.ndts_hash_grows += st->hash_grows;
1885 ndst.ndts_res_failed += st->res_failed;
1886 ndst.ndts_lookups += st->lookups;
1887 ndst.ndts_hits += st->hits;
1888 ndst.ndts_rcv_probes_mcast += st->rcv_probes_mcast;
1889 ndst.ndts_rcv_probes_ucast += st->rcv_probes_ucast;
1890 ndst.ndts_periodic_gc_runs += st->periodic_gc_runs;
1891 ndst.ndts_forced_gc_runs += st->forced_gc_runs;
1892 }
1893
David S. Miller9a6308d2012-04-01 20:06:28 -04001894 if (nla_put(skb, NDTA_STATS, sizeof(ndst), &ndst))
1895 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001896 }
1897
1898 BUG_ON(tbl->parms.dev);
1899 if (neightbl_fill_parms(skb, &tbl->parms) < 0)
Thomas Grafca860fb2006-08-07 18:00:18 -07001900 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001901
1902 read_unlock_bh(&tbl->lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07001903 return nlmsg_end(skb, nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001904
Thomas Grafca860fb2006-08-07 18:00:18 -07001905nla_put_failure:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001906 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08001907 nlmsg_cancel(skb, nlh);
1908 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001909}
1910
Thomas Grafca860fb2006-08-07 18:00:18 -07001911static int neightbl_fill_param_info(struct sk_buff *skb,
1912 struct neigh_table *tbl,
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001913 struct neigh_parms *parms,
Thomas Grafca860fb2006-08-07 18:00:18 -07001914 u32 pid, u32 seq, int type,
1915 unsigned int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001916{
1917 struct ndtmsg *ndtmsg;
1918 struct nlmsghdr *nlh;
1919
Thomas Grafca860fb2006-08-07 18:00:18 -07001920 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
1921 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001922 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001923
Thomas Grafca860fb2006-08-07 18:00:18 -07001924 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001925
1926 read_lock_bh(&tbl->lock);
1927 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07001928 ndtmsg->ndtm_pad1 = 0;
1929 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001930
Thomas Grafca860fb2006-08-07 18:00:18 -07001931 if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
1932 neightbl_fill_parms(skb, parms) < 0)
1933 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001934
1935 read_unlock_bh(&tbl->lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07001936 return nlmsg_end(skb, nlh);
1937errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001938 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08001939 nlmsg_cancel(skb, nlh);
1940 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001941}
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001942
Patrick McHardyef7c79e2007-06-05 12:38:30 -07001943static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07001944 [NDTA_NAME] = { .type = NLA_STRING },
1945 [NDTA_THRESH1] = { .type = NLA_U32 },
1946 [NDTA_THRESH2] = { .type = NLA_U32 },
1947 [NDTA_THRESH3] = { .type = NLA_U32 },
1948 [NDTA_GC_INTERVAL] = { .type = NLA_U64 },
1949 [NDTA_PARMS] = { .type = NLA_NESTED },
1950};
1951
Patrick McHardyef7c79e2007-06-05 12:38:30 -07001952static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07001953 [NDTPA_IFINDEX] = { .type = NLA_U32 },
1954 [NDTPA_QUEUE_LEN] = { .type = NLA_U32 },
1955 [NDTPA_PROXY_QLEN] = { .type = NLA_U32 },
1956 [NDTPA_APP_PROBES] = { .type = NLA_U32 },
1957 [NDTPA_UCAST_PROBES] = { .type = NLA_U32 },
1958 [NDTPA_MCAST_PROBES] = { .type = NLA_U32 },
1959 [NDTPA_BASE_REACHABLE_TIME] = { .type = NLA_U64 },
1960 [NDTPA_GC_STALETIME] = { .type = NLA_U64 },
1961 [NDTPA_DELAY_PROBE_TIME] = { .type = NLA_U64 },
1962 [NDTPA_RETRANS_TIME] = { .type = NLA_U64 },
1963 [NDTPA_ANYCAST_DELAY] = { .type = NLA_U64 },
1964 [NDTPA_PROXY_DELAY] = { .type = NLA_U64 },
1965 [NDTPA_LOCKTIME] = { .type = NLA_U64 },
1966};
1967
Thomas Graf661d2962013-03-21 07:45:29 +00001968static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001969{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001970 struct net *net = sock_net(skb->sk);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001971 struct neigh_table *tbl;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001972 struct ndtmsg *ndtmsg;
1973 struct nlattr *tb[NDTA_MAX+1];
1974 int err;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001975
Thomas Graf6b3f8672006-08-07 17:58:53 -07001976 err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
1977 nl_neightbl_policy);
1978 if (err < 0)
1979 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001980
Thomas Graf6b3f8672006-08-07 17:58:53 -07001981 if (tb[NDTA_NAME] == NULL) {
1982 err = -EINVAL;
1983 goto errout;
1984 }
1985
1986 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001987 read_lock(&neigh_tbl_lock);
1988 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
1989 if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
1990 continue;
1991
Thomas Graf6b3f8672006-08-07 17:58:53 -07001992 if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001993 break;
1994 }
1995
1996 if (tbl == NULL) {
1997 err = -ENOENT;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001998 goto errout_locked;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001999 }
2000
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09002001 /*
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002002 * We acquire tbl->lock to be nice to the periodic timers and
2003 * make sure they always see a consistent set of values.
2004 */
2005 write_lock_bh(&tbl->lock);
2006
Thomas Graf6b3f8672006-08-07 17:58:53 -07002007 if (tb[NDTA_PARMS]) {
2008 struct nlattr *tbp[NDTPA_MAX+1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002009 struct neigh_parms *p;
Thomas Graf6b3f8672006-08-07 17:58:53 -07002010 int i, ifindex = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002011
Thomas Graf6b3f8672006-08-07 17:58:53 -07002012 err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS],
2013 nl_ntbl_parm_policy);
2014 if (err < 0)
2015 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002016
Thomas Graf6b3f8672006-08-07 17:58:53 -07002017 if (tbp[NDTPA_IFINDEX])
2018 ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002019
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07002020 p = lookup_neigh_parms(tbl, net, ifindex);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002021 if (p == NULL) {
2022 err = -ENOENT;
Thomas Graf6b3f8672006-08-07 17:58:53 -07002023 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002024 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002025
Thomas Graf6b3f8672006-08-07 17:58:53 -07002026 for (i = 1; i <= NDTPA_MAX; i++) {
2027 if (tbp[i] == NULL)
2028 continue;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002029
Thomas Graf6b3f8672006-08-07 17:58:53 -07002030 switch (i) {
2031 case NDTPA_QUEUE_LEN:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002032 NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
2033 nla_get_u32(tbp[i]) *
2034 SKB_TRUESIZE(ETH_FRAME_LEN));
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002035 break;
2036 case NDTPA_QUEUE_LENBYTES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002037 NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
2038 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002039 break;
2040 case NDTPA_PROXY_QLEN:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002041 NEIGH_VAR_SET(p, PROXY_QLEN,
2042 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002043 break;
2044 case NDTPA_APP_PROBES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002045 NEIGH_VAR_SET(p, APP_PROBES,
2046 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002047 break;
2048 case NDTPA_UCAST_PROBES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002049 NEIGH_VAR_SET(p, UCAST_PROBES,
2050 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002051 break;
2052 case NDTPA_MCAST_PROBES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002053 NEIGH_VAR_SET(p, MCAST_PROBES,
2054 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002055 break;
2056 case NDTPA_BASE_REACHABLE_TIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002057 NEIGH_VAR_SET(p, BASE_REACHABLE_TIME,
2058 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002059 break;
2060 case NDTPA_GC_STALETIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002061 NEIGH_VAR_SET(p, GC_STALETIME,
2062 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002063 break;
2064 case NDTPA_DELAY_PROBE_TIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002065 NEIGH_VAR_SET(p, DELAY_PROBE_TIME,
2066 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002067 break;
2068 case NDTPA_RETRANS_TIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002069 NEIGH_VAR_SET(p, RETRANS_TIME,
2070 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002071 break;
2072 case NDTPA_ANYCAST_DELAY:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002073 NEIGH_VAR_SET(p, ANYCAST_DELAY, nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002074 break;
2075 case NDTPA_PROXY_DELAY:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002076 NEIGH_VAR_SET(p, PROXY_DELAY, nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002077 break;
2078 case NDTPA_LOCKTIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002079 NEIGH_VAR_SET(p, LOCKTIME, nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002080 break;
2081 }
2082 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002083 }
2084
Gao fengdc25c672013-06-20 10:01:34 +08002085 err = -ENOENT;
2086 if ((tb[NDTA_THRESH1] || tb[NDTA_THRESH2] ||
2087 tb[NDTA_THRESH3] || tb[NDTA_GC_INTERVAL]) &&
2088 !net_eq(net, &init_net))
2089 goto errout_tbl_lock;
2090
Thomas Graf6b3f8672006-08-07 17:58:53 -07002091 if (tb[NDTA_THRESH1])
2092 tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
2093
2094 if (tb[NDTA_THRESH2])
2095 tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
2096
2097 if (tb[NDTA_THRESH3])
2098 tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
2099
2100 if (tb[NDTA_GC_INTERVAL])
2101 tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
2102
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002103 err = 0;
2104
Thomas Graf6b3f8672006-08-07 17:58:53 -07002105errout_tbl_lock:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002106 write_unlock_bh(&tbl->lock);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002107errout_locked:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002108 read_unlock(&neigh_tbl_lock);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002109errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002110 return err;
2111}
2112
Thomas Grafc8822a42007-03-22 11:50:06 -07002113static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002114{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002115 struct net *net = sock_net(skb->sk);
Thomas Grafca860fb2006-08-07 18:00:18 -07002116 int family, tidx, nidx = 0;
2117 int tbl_skip = cb->args[0];
2118 int neigh_skip = cb->args[1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002119 struct neigh_table *tbl;
2120
Thomas Grafca860fb2006-08-07 18:00:18 -07002121 family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002122
2123 read_lock(&neigh_tbl_lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07002124 for (tbl = neigh_tables, tidx = 0; tbl; tbl = tbl->next, tidx++) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002125 struct neigh_parms *p;
2126
Thomas Grafca860fb2006-08-07 18:00:18 -07002127 if (tidx < tbl_skip || (family && tbl->family != family))
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002128 continue;
2129
Eric W. Biederman15e47302012-09-07 20:12:54 +00002130 if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
Thomas Grafca860fb2006-08-07 18:00:18 -07002131 cb->nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
2132 NLM_F_MULTI) <= 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002133 break;
2134
Eric W. Biederman426b5302008-01-24 00:13:18 -08002135 for (nidx = 0, p = tbl->parms.next; p; p = p->next) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002136 if (!net_eq(neigh_parms_net(p), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002137 continue;
2138
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002139 if (nidx < neigh_skip)
2140 goto next;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002141
Thomas Grafca860fb2006-08-07 18:00:18 -07002142 if (neightbl_fill_param_info(skb, tbl, p,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002143 NETLINK_CB(cb->skb).portid,
Thomas Grafca860fb2006-08-07 18:00:18 -07002144 cb->nlh->nlmsg_seq,
2145 RTM_NEWNEIGHTBL,
2146 NLM_F_MULTI) <= 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002147 goto out;
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002148 next:
2149 nidx++;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002150 }
2151
Thomas Grafca860fb2006-08-07 18:00:18 -07002152 neigh_skip = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002153 }
2154out:
2155 read_unlock(&neigh_tbl_lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07002156 cb->args[0] = tidx;
2157 cb->args[1] = nidx;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002158
2159 return skb->len;
2160}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161
Thomas Graf8b8aec52006-08-07 17:56:37 -07002162static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
2163 u32 pid, u32 seq, int type, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164{
2165 unsigned long now = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 struct nda_cacheinfo ci;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002167 struct nlmsghdr *nlh;
2168 struct ndmsg *ndm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169
Thomas Graf8b8aec52006-08-07 17:56:37 -07002170 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
2171 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08002172 return -EMSGSIZE;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002173
2174 ndm = nlmsg_data(nlh);
2175 ndm->ndm_family = neigh->ops->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07002176 ndm->ndm_pad1 = 0;
2177 ndm->ndm_pad2 = 0;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002178 ndm->ndm_flags = neigh->flags;
2179 ndm->ndm_type = neigh->type;
2180 ndm->ndm_ifindex = neigh->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181
David S. Miller9a6308d2012-04-01 20:06:28 -04002182 if (nla_put(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key))
2183 goto nla_put_failure;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002184
2185 read_lock_bh(&neigh->lock);
2186 ndm->ndm_state = neigh->nud_state;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00002187 if (neigh->nud_state & NUD_VALID) {
2188 char haddr[MAX_ADDR_LEN];
2189
2190 neigh_ha_snapshot(haddr, neigh, neigh->dev);
2191 if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0) {
2192 read_unlock_bh(&neigh->lock);
2193 goto nla_put_failure;
2194 }
Thomas Graf8b8aec52006-08-07 17:56:37 -07002195 }
2196
Stephen Hemmingerb9f5f522008-06-03 16:03:15 -07002197 ci.ndm_used = jiffies_to_clock_t(now - neigh->used);
2198 ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
2199 ci.ndm_updated = jiffies_to_clock_t(now - neigh->updated);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002200 ci.ndm_refcnt = atomic_read(&neigh->refcnt) - 1;
2201 read_unlock_bh(&neigh->lock);
2202
David S. Miller9a6308d2012-04-01 20:06:28 -04002203 if (nla_put_u32(skb, NDA_PROBES, atomic_read(&neigh->probes)) ||
2204 nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
2205 goto nla_put_failure;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002206
2207 return nlmsg_end(skb, nlh);
2208
2209nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002210 nlmsg_cancel(skb, nlh);
2211 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212}
2213
Tony Zelenoff84920c12012-01-26 22:28:58 +00002214static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
2215 u32 pid, u32 seq, int type, unsigned int flags,
2216 struct neigh_table *tbl)
2217{
2218 struct nlmsghdr *nlh;
2219 struct ndmsg *ndm;
2220
2221 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
2222 if (nlh == NULL)
2223 return -EMSGSIZE;
2224
2225 ndm = nlmsg_data(nlh);
2226 ndm->ndm_family = tbl->family;
2227 ndm->ndm_pad1 = 0;
2228 ndm->ndm_pad2 = 0;
2229 ndm->ndm_flags = pn->flags | NTF_PROXY;
2230 ndm->ndm_type = NDA_DST;
2231 ndm->ndm_ifindex = pn->dev->ifindex;
2232 ndm->ndm_state = NUD_NONE;
2233
David S. Miller9a6308d2012-04-01 20:06:28 -04002234 if (nla_put(skb, NDA_DST, tbl->key_len, pn->key))
2235 goto nla_put_failure;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002236
2237 return nlmsg_end(skb, nlh);
2238
2239nla_put_failure:
2240 nlmsg_cancel(skb, nlh);
2241 return -EMSGSIZE;
2242}
2243
Thomas Grafd961db32007-08-08 23:12:56 -07002244static void neigh_update_notify(struct neighbour *neigh)
2245{
2246 call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
2247 __neigh_notify(neigh, RTM_NEWNEIGH, 0);
2248}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249
2250static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
2251 struct netlink_callback *cb)
2252{
Eric Dumazet767e97e2010-10-06 17:49:21 -07002253 struct net *net = sock_net(skb->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 struct neighbour *n;
2255 int rc, h, s_h = cb->args[1];
2256 int idx, s_idx = idx = cb->args[2];
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002257 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002259 rcu_read_lock_bh();
2260 nht = rcu_dereference_bh(tbl->nht);
2261
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002262 for (h = s_h; h < (1 << nht->hash_shift); h++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 if (h > s_h)
2264 s_idx = 0;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002265 for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
2266 n != NULL;
2267 n = rcu_dereference_bh(n->next)) {
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002268 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002269 continue;
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002270 if (idx < s_idx)
2271 goto next;
Eric W. Biederman15e47302012-09-07 20:12:54 +00002272 if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 cb->nlh->nlmsg_seq,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07002274 RTM_NEWNEIGH,
2275 NLM_F_MULTI) <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 rc = -1;
2277 goto out;
2278 }
Eric Dumazet767e97e2010-10-06 17:49:21 -07002279next:
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002280 idx++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 }
2283 rc = skb->len;
2284out:
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002285 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 cb->args[1] = h;
2287 cb->args[2] = idx;
2288 return rc;
2289}
2290
Tony Zelenoff84920c12012-01-26 22:28:58 +00002291static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
2292 struct netlink_callback *cb)
2293{
2294 struct pneigh_entry *n;
2295 struct net *net = sock_net(skb->sk);
2296 int rc, h, s_h = cb->args[3];
2297 int idx, s_idx = idx = cb->args[4];
2298
2299 read_lock_bh(&tbl->lock);
2300
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002301 for (h = s_h; h <= PNEIGH_HASHMASK; h++) {
Tony Zelenoff84920c12012-01-26 22:28:58 +00002302 if (h > s_h)
2303 s_idx = 0;
2304 for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
2305 if (dev_net(n->dev) != net)
2306 continue;
2307 if (idx < s_idx)
2308 goto next;
Eric W. Biederman15e47302012-09-07 20:12:54 +00002309 if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
Tony Zelenoff84920c12012-01-26 22:28:58 +00002310 cb->nlh->nlmsg_seq,
2311 RTM_NEWNEIGH,
2312 NLM_F_MULTI, tbl) <= 0) {
2313 read_unlock_bh(&tbl->lock);
2314 rc = -1;
2315 goto out;
2316 }
2317 next:
2318 idx++;
2319 }
2320 }
2321
2322 read_unlock_bh(&tbl->lock);
2323 rc = skb->len;
2324out:
2325 cb->args[3] = h;
2326 cb->args[4] = idx;
2327 return rc;
2328
2329}
2330
Thomas Grafc8822a42007-03-22 11:50:06 -07002331static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332{
2333 struct neigh_table *tbl;
2334 int t, family, s_t;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002335 int proxy = 0;
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002336 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337
2338 read_lock(&neigh_tbl_lock);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002339 family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002340
2341 /* check for full ndmsg structure presence, family member is
2342 * the same for both structures
2343 */
2344 if (nlmsg_len(cb->nlh) >= sizeof(struct ndmsg) &&
2345 ((struct ndmsg *) nlmsg_data(cb->nlh))->ndm_flags == NTF_PROXY)
2346 proxy = 1;
2347
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 s_t = cb->args[0];
2349
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002350 for (tbl = neigh_tables, t = 0; tbl;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002351 tbl = tbl->next, t++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 if (t < s_t || (family && tbl->family != family))
2353 continue;
2354 if (t > s_t)
2355 memset(&cb->args[1], 0, sizeof(cb->args) -
2356 sizeof(cb->args[0]));
Tony Zelenoff84920c12012-01-26 22:28:58 +00002357 if (proxy)
2358 err = pneigh_dump_table(tbl, skb, cb);
2359 else
2360 err = neigh_dump_table(tbl, skb, cb);
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002361 if (err < 0)
2362 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 }
2364 read_unlock(&neigh_tbl_lock);
2365
2366 cb->args[0] = t;
2367 return skb->len;
2368}
2369
2370void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
2371{
2372 int chain;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002373 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002375 rcu_read_lock_bh();
2376 nht = rcu_dereference_bh(tbl->nht);
2377
Eric Dumazet767e97e2010-10-06 17:49:21 -07002378 read_lock(&tbl->lock); /* avoid resizes */
David S. Millercd089332011-07-11 01:28:12 -07002379 for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 struct neighbour *n;
2381
Eric Dumazet767e97e2010-10-06 17:49:21 -07002382 for (n = rcu_dereference_bh(nht->hash_buckets[chain]);
2383 n != NULL;
2384 n = rcu_dereference_bh(n->next))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 cb(n, cookie);
2386 }
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002387 read_unlock(&tbl->lock);
2388 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389}
2390EXPORT_SYMBOL(neigh_for_each);
2391
2392/* The tbl->lock must be held as a writer and BH disabled. */
2393void __neigh_for_each_release(struct neigh_table *tbl,
2394 int (*cb)(struct neighbour *))
2395{
2396 int chain;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002397 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002399 nht = rcu_dereference_protected(tbl->nht,
2400 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -07002401 for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002402 struct neighbour *n;
2403 struct neighbour __rcu **np;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002405 np = &nht->hash_buckets[chain];
Eric Dumazet767e97e2010-10-06 17:49:21 -07002406 while ((n = rcu_dereference_protected(*np,
2407 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 int release;
2409
2410 write_lock(&n->lock);
2411 release = cb(n);
2412 if (release) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002413 rcu_assign_pointer(*np,
2414 rcu_dereference_protected(n->next,
2415 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 n->dead = 1;
2417 } else
2418 np = &n->next;
2419 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -07002420 if (release)
2421 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 }
2423 }
2424}
2425EXPORT_SYMBOL(__neigh_for_each_release);
2426
2427#ifdef CONFIG_PROC_FS
2428
2429static struct neighbour *neigh_get_first(struct seq_file *seq)
2430{
2431 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002432 struct net *net = seq_file_net(seq);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002433 struct neigh_hash_table *nht = state->nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 struct neighbour *n = NULL;
2435 int bucket = state->bucket;
2436
2437 state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
David S. Millercd089332011-07-11 01:28:12 -07002438 for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002439 n = rcu_dereference_bh(nht->hash_buckets[bucket]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440
2441 while (n) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002442 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002443 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 if (state->neigh_sub_iter) {
2445 loff_t fakep = 0;
2446 void *v;
2447
2448 v = state->neigh_sub_iter(state, n, &fakep);
2449 if (!v)
2450 goto next;
2451 }
2452 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
2453 break;
2454 if (n->nud_state & ~NUD_NOARP)
2455 break;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002456next:
2457 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 }
2459
2460 if (n)
2461 break;
2462 }
2463 state->bucket = bucket;
2464
2465 return n;
2466}
2467
2468static struct neighbour *neigh_get_next(struct seq_file *seq,
2469 struct neighbour *n,
2470 loff_t *pos)
2471{
2472 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002473 struct net *net = seq_file_net(seq);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002474 struct neigh_hash_table *nht = state->nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475
2476 if (state->neigh_sub_iter) {
2477 void *v = state->neigh_sub_iter(state, n, pos);
2478 if (v)
2479 return n;
2480 }
Eric Dumazet767e97e2010-10-06 17:49:21 -07002481 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482
2483 while (1) {
2484 while (n) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002485 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002486 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 if (state->neigh_sub_iter) {
2488 void *v = state->neigh_sub_iter(state, n, pos);
2489 if (v)
2490 return n;
2491 goto next;
2492 }
2493 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
2494 break;
2495
2496 if (n->nud_state & ~NUD_NOARP)
2497 break;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002498next:
2499 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 }
2501
2502 if (n)
2503 break;
2504
David S. Millercd089332011-07-11 01:28:12 -07002505 if (++state->bucket >= (1 << nht->hash_shift))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 break;
2507
Eric Dumazet767e97e2010-10-06 17:49:21 -07002508 n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 }
2510
2511 if (n && pos)
2512 --(*pos);
2513 return n;
2514}
2515
2516static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
2517{
2518 struct neighbour *n = neigh_get_first(seq);
2519
2520 if (n) {
Chris Larson745e2032008-08-03 01:10:55 -07002521 --(*pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 while (*pos) {
2523 n = neigh_get_next(seq, n, pos);
2524 if (!n)
2525 break;
2526 }
2527 }
2528 return *pos ? NULL : n;
2529}
2530
2531static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
2532{
2533 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002534 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 struct neigh_table *tbl = state->tbl;
2536 struct pneigh_entry *pn = NULL;
2537 int bucket = state->bucket;
2538
2539 state->flags |= NEIGH_SEQ_IS_PNEIGH;
2540 for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
2541 pn = tbl->phash_buckets[bucket];
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002542 while (pn && !net_eq(pneigh_net(pn), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002543 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 if (pn)
2545 break;
2546 }
2547 state->bucket = bucket;
2548
2549 return pn;
2550}
2551
2552static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
2553 struct pneigh_entry *pn,
2554 loff_t *pos)
2555{
2556 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002557 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 struct neigh_table *tbl = state->tbl;
2559
Jorge Boncompte [DTI2]df07a942011-11-25 13:24:49 -05002560 do {
2561 pn = pn->next;
2562 } while (pn && !net_eq(pneigh_net(pn), net));
2563
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 while (!pn) {
2565 if (++state->bucket > PNEIGH_HASHMASK)
2566 break;
2567 pn = tbl->phash_buckets[state->bucket];
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002568 while (pn && !net_eq(pneigh_net(pn), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002569 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 if (pn)
2571 break;
2572 }
2573
2574 if (pn && pos)
2575 --(*pos);
2576
2577 return pn;
2578}
2579
2580static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
2581{
2582 struct pneigh_entry *pn = pneigh_get_first(seq);
2583
2584 if (pn) {
Chris Larson745e2032008-08-03 01:10:55 -07002585 --(*pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 while (*pos) {
2587 pn = pneigh_get_next(seq, pn, pos);
2588 if (!pn)
2589 break;
2590 }
2591 }
2592 return *pos ? NULL : pn;
2593}
2594
2595static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
2596{
2597 struct neigh_seq_state *state = seq->private;
2598 void *rc;
Chris Larson745e2032008-08-03 01:10:55 -07002599 loff_t idxpos = *pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600
Chris Larson745e2032008-08-03 01:10:55 -07002601 rc = neigh_get_idx(seq, &idxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
Chris Larson745e2032008-08-03 01:10:55 -07002603 rc = pneigh_get_idx(seq, &idxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604
2605 return rc;
2606}
2607
2608void *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 +00002609 __acquires(rcu_bh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610{
2611 struct neigh_seq_state *state = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612
2613 state->tbl = tbl;
2614 state->bucket = 0;
2615 state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
2616
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002617 rcu_read_lock_bh();
2618 state->nht = rcu_dereference_bh(tbl->nht);
Eric Dumazet767e97e2010-10-06 17:49:21 -07002619
Chris Larson745e2032008-08-03 01:10:55 -07002620 return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621}
2622EXPORT_SYMBOL(neigh_seq_start);
2623
2624void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2625{
2626 struct neigh_seq_state *state;
2627 void *rc;
2628
2629 if (v == SEQ_START_TOKEN) {
Chris Larsonbff69732008-08-03 01:02:41 -07002630 rc = neigh_get_first(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 goto out;
2632 }
2633
2634 state = seq->private;
2635 if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {
2636 rc = neigh_get_next(seq, v, NULL);
2637 if (rc)
2638 goto out;
2639 if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))
2640 rc = pneigh_get_first(seq);
2641 } else {
2642 BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);
2643 rc = pneigh_get_next(seq, v, NULL);
2644 }
2645out:
2646 ++(*pos);
2647 return rc;
2648}
2649EXPORT_SYMBOL(neigh_seq_next);
2650
2651void neigh_seq_stop(struct seq_file *seq, void *v)
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002652 __releases(rcu_bh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653{
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002654 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655}
2656EXPORT_SYMBOL(neigh_seq_stop);
2657
2658/* statistics via seq_file */
2659
2660static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
2661{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002662 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 int cpu;
2664
2665 if (*pos == 0)
2666 return SEQ_START_TOKEN;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09002667
Rusty Russell0f23174a2008-12-29 12:23:42 +00002668 for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 if (!cpu_possible(cpu))
2670 continue;
2671 *pos = cpu+1;
2672 return per_cpu_ptr(tbl->stats, cpu);
2673 }
2674 return NULL;
2675}
2676
2677static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2678{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002679 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 int cpu;
2681
Rusty Russell0f23174a2008-12-29 12:23:42 +00002682 for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 if (!cpu_possible(cpu))
2684 continue;
2685 *pos = cpu+1;
2686 return per_cpu_ptr(tbl->stats, cpu);
2687 }
2688 return NULL;
2689}
2690
2691static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
2692{
2693
2694}
2695
2696static int neigh_stat_seq_show(struct seq_file *seq, void *v)
2697{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002698 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 struct neigh_statistics *st = v;
2700
2701 if (v == SEQ_START_TOKEN) {
Neil Horman9a6d2762008-07-16 20:50:49 -07002702 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 -07002703 return 0;
2704 }
2705
2706 seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx "
Neil Horman9a6d2762008-07-16 20:50:49 -07002707 "%08lx %08lx %08lx %08lx %08lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 atomic_read(&tbl->entries),
2709
2710 st->allocs,
2711 st->destroys,
2712 st->hash_grows,
2713
2714 st->lookups,
2715 st->hits,
2716
2717 st->res_failed,
2718
2719 st->rcv_probes_mcast,
2720 st->rcv_probes_ucast,
2721
2722 st->periodic_gc_runs,
Neil Horman9a6d2762008-07-16 20:50:49 -07002723 st->forced_gc_runs,
2724 st->unres_discards
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 );
2726
2727 return 0;
2728}
2729
Stephen Hemmingerf6908082007-03-12 14:34:29 -07002730static const struct seq_operations neigh_stat_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 .start = neigh_stat_seq_start,
2732 .next = neigh_stat_seq_next,
2733 .stop = neigh_stat_seq_stop,
2734 .show = neigh_stat_seq_show,
2735};
2736
2737static int neigh_stat_seq_open(struct inode *inode, struct file *file)
2738{
2739 int ret = seq_open(file, &neigh_stat_seq_ops);
2740
2741 if (!ret) {
2742 struct seq_file *sf = file->private_data;
Al Virod9dda782013-03-31 18:16:14 -04002743 sf->private = PDE_DATA(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 }
2745 return ret;
2746};
2747
Arjan van de Ven9a321442007-02-12 00:55:35 -08002748static const struct file_operations neigh_stat_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 .owner = THIS_MODULE,
2750 .open = neigh_stat_seq_open,
2751 .read = seq_read,
2752 .llseek = seq_lseek,
2753 .release = seq_release,
2754};
2755
2756#endif /* CONFIG_PROC_FS */
2757
Thomas Graf339bf982006-11-10 14:10:15 -08002758static inline size_t neigh_nlmsg_size(void)
2759{
2760 return NLMSG_ALIGN(sizeof(struct ndmsg))
2761 + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
2762 + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
2763 + nla_total_size(sizeof(struct nda_cacheinfo))
2764 + nla_total_size(4); /* NDA_PROBES */
2765}
2766
Thomas Grafb8673312006-08-15 00:33:14 -07002767static void __neigh_notify(struct neighbour *n, int type, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002769 struct net *net = dev_net(n->dev);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002770 struct sk_buff *skb;
Thomas Grafb8673312006-08-15 00:33:14 -07002771 int err = -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772
Thomas Graf339bf982006-11-10 14:10:15 -08002773 skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002774 if (skb == NULL)
Thomas Grafb8673312006-08-15 00:33:14 -07002775 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776
Thomas Grafb8673312006-08-15 00:33:14 -07002777 err = neigh_fill_info(skb, n, 0, 0, type, flags);
Patrick McHardy26932562007-01-31 23:16:40 -08002778 if (err < 0) {
2779 /* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
2780 WARN_ON(err == -EMSGSIZE);
2781 kfree_skb(skb);
2782 goto errout;
2783 }
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08002784 rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
2785 return;
Thomas Grafb8673312006-08-15 00:33:14 -07002786errout:
2787 if (err < 0)
Eric W. Biederman426b5302008-01-24 00:13:18 -08002788 rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
Thomas Grafb8673312006-08-15 00:33:14 -07002789}
2790
2791void neigh_app_ns(struct neighbour *n)
2792{
2793 __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09002795EXPORT_SYMBOL(neigh_app_ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796
2797#ifdef CONFIG_SYSCTL
Cong Wangb93196d2012-12-06 10:04:04 +08002798static int zero;
Francesco Fusco555445c2013-07-24 10:39:06 +02002799static int int_max = INT_MAX;
Cong Wangb93196d2012-12-06 10:04:04 +08002800static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801
Joe Perchesfe2c6332013-06-11 23:04:25 -07002802static int proc_unres_qlen(struct ctl_table *ctl, int write,
2803 void __user *buffer, size_t *lenp, loff_t *ppos)
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002804{
2805 int size, ret;
Joe Perchesfe2c6332013-06-11 23:04:25 -07002806 struct ctl_table tmp = *ctl;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002807
Shan Weice46cc62012-12-04 18:49:15 +00002808 tmp.extra1 = &zero;
2809 tmp.extra2 = &unres_qlen_max;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002810 tmp.data = &size;
Shan Weice46cc62012-12-04 18:49:15 +00002811
2812 size = *(int *)ctl->data / SKB_TRUESIZE(ETH_FRAME_LEN);
2813 ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
2814
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002815 if (write && !ret)
2816 *(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
2817 return ret;
2818}
2819
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002820static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev,
2821 int family)
2822{
Jiri Pirkobba24892013-12-07 19:26:57 +01002823 switch (family) {
2824 case AF_INET:
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002825 return __in_dev_arp_parms_get_rcu(dev);
Jiri Pirkobba24892013-12-07 19:26:57 +01002826 case AF_INET6:
2827 return __in6_dev_nd_parms_get_rcu(dev);
2828 }
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002829 return NULL;
2830}
2831
2832static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p,
2833 int index)
2834{
2835 struct net_device *dev;
2836 int family = neigh_parms_family(p);
2837
2838 rcu_read_lock();
2839 for_each_netdev_rcu(net, dev) {
2840 struct neigh_parms *dst_p =
2841 neigh_get_dev_parms_rcu(dev, family);
2842
2843 if (dst_p && !test_bit(index, dst_p->data_state))
2844 dst_p->data[index] = p->data[index];
2845 }
2846 rcu_read_unlock();
2847}
2848
2849static void neigh_proc_update(struct ctl_table *ctl, int write)
2850{
2851 struct net_device *dev = ctl->extra1;
2852 struct neigh_parms *p = ctl->extra2;
2853 struct net *net = p->net;
2854 int index = (int *) ctl->data - p->data;
2855
2856 if (!write)
2857 return;
2858
2859 set_bit(index, p->data_state);
2860 if (!dev) /* NULL dev means this is default value */
2861 neigh_copy_dflt_parms(net, p, index);
2862}
2863
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002864static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write,
2865 void __user *buffer,
2866 size_t *lenp, loff_t *ppos)
2867{
2868 struct ctl_table tmp = *ctl;
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002869 int ret;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002870
2871 tmp.extra1 = &zero;
2872 tmp.extra2 = &int_max;
2873
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002874 ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
2875 neigh_proc_update(ctl, write);
2876 return ret;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002877}
2878
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002879int neigh_proc_dointvec(struct ctl_table *ctl, int write,
2880 void __user *buffer, size_t *lenp, loff_t *ppos)
2881{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002882 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
2883
2884 neigh_proc_update(ctl, write);
2885 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002886}
2887EXPORT_SYMBOL(neigh_proc_dointvec);
2888
2889int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write,
2890 void __user *buffer,
2891 size_t *lenp, loff_t *ppos)
2892{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002893 int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
2894
2895 neigh_proc_update(ctl, write);
2896 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002897}
2898EXPORT_SYMBOL(neigh_proc_dointvec_jiffies);
2899
2900static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write,
2901 void __user *buffer,
2902 size_t *lenp, loff_t *ppos)
2903{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002904 int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos);
2905
2906 neigh_proc_update(ctl, write);
2907 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002908}
2909
2910int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write,
2911 void __user *buffer,
2912 size_t *lenp, loff_t *ppos)
2913{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002914 int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
2915
2916 neigh_proc_update(ctl, write);
2917 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002918}
2919EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies);
2920
2921static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write,
2922 void __user *buffer,
2923 size_t *lenp, loff_t *ppos)
2924{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01002925 int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos);
2926
2927 neigh_proc_update(ctl, write);
2928 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002929}
2930
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002931#define NEIGH_PARMS_DATA_OFFSET(index) \
2932 (&((struct neigh_parms *) 0)->data[index])
2933
2934#define NEIGH_SYSCTL_ENTRY(attr, data_attr, name, mval, proc) \
2935 [NEIGH_VAR_ ## attr] = { \
2936 .procname = name, \
2937 .data = NEIGH_PARMS_DATA_OFFSET(NEIGH_VAR_ ## data_attr), \
2938 .maxlen = sizeof(int), \
2939 .mode = mval, \
2940 .proc_handler = proc, \
2941 }
2942
2943#define NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(attr, name) \
2944 NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_zero_intmax)
2945
2946#define NEIGH_SYSCTL_JIFFIES_ENTRY(attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002947 NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_jiffies)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002948
2949#define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002950 NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002951
2952#define NEIGH_SYSCTL_MS_JIFFIES_ENTRY(attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002953 NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002954
2955#define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002956 NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002957
2958#define NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(attr, data_attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01002959 NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_unres_qlen)
Eric W. Biederman54716e32010-02-14 03:27:03 +00002960
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961static struct neigh_sysctl_table {
2962 struct ctl_table_header *sysctl_header;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002963 struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
Brian Haleyab32ea52006-09-22 14:15:41 -07002964} neigh_sysctl_template __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 .neigh_vars = {
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002966 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_PROBES, "mcast_solicit"),
2967 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(UCAST_PROBES, "ucast_solicit"),
2968 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(APP_PROBES, "app_solicit"),
2969 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(RETRANS_TIME, "retrans_time"),
2970 NEIGH_SYSCTL_JIFFIES_ENTRY(BASE_REACHABLE_TIME, "base_reachable_time"),
2971 NEIGH_SYSCTL_JIFFIES_ENTRY(DELAY_PROBE_TIME, "delay_first_probe_time"),
2972 NEIGH_SYSCTL_JIFFIES_ENTRY(GC_STALETIME, "gc_stale_time"),
2973 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(QUEUE_LEN_BYTES, "unres_qlen_bytes"),
2974 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(PROXY_QLEN, "proxy_qlen"),
2975 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(ANYCAST_DELAY, "anycast_delay"),
2976 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(PROXY_DELAY, "proxy_delay"),
2977 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(LOCKTIME, "locktime"),
2978 NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(QUEUE_LEN, QUEUE_LEN_BYTES, "unres_qlen"),
2979 NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(RETRANS_TIME_MS, RETRANS_TIME, "retrans_time_ms"),
2980 NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(BASE_REACHABLE_TIME_MS, BASE_REACHABLE_TIME, "base_reachable_time_ms"),
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002981 [NEIGH_VAR_GC_INTERVAL] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 .procname = "gc_interval",
2983 .maxlen = sizeof(int),
2984 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002985 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002987 [NEIGH_VAR_GC_THRESH1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 .procname = "gc_thresh1",
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_THRESH2] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 .procname = "gc_thresh2",
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 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003003 [NEIGH_VAR_GC_THRESH3] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 .procname = "gc_thresh3",
3005 .maxlen = sizeof(int),
3006 .mode = 0644,
Francesco Fusco555445c2013-07-24 10:39:06 +02003007 .extra1 = &zero,
3008 .extra2 = &int_max,
3009 .proc_handler = proc_dointvec_minmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 },
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11003011 {},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 },
3013};
3014
3015int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
Jiri Pirko73af6142013-12-07 19:26:55 +01003016 proc_handler *handler)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017{
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003018 int i;
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003019 struct neigh_sysctl_table *t;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003020 const char *dev_name_source;
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003021 char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ];
Jiri Pirko73af6142013-12-07 19:26:55 +01003022 char *p_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003024 t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 if (!t)
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003026 goto err;
3027
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003028 for (i = 0; i < ARRAY_SIZE(t->neigh_vars); i++) {
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003029 t->neigh_vars[i].data += (long) p;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003030 t->neigh_vars[i].extra1 = dev;
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003031 t->neigh_vars[i].extra2 = p;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003032 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033
3034 if (dev) {
3035 dev_name_source = dev->name;
Eric W. Biedermand12af672007-10-18 03:05:25 -07003036 /* Terminate the table early */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003037 memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
3038 sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 } else {
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003040 dev_name_source = "default";
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003041 t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = (int *)(p + 1);
3042 t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = (int *)(p + 1) + 1;
3043 t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = (int *)(p + 1) + 2;
3044 t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = (int *)(p + 1) + 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 }
3046
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08003047 if (handler) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 /* RetransTime */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003049 t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050 /* ReachableTime */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003051 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 /* RetransTime (in milliseconds)*/
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003053 t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 /* ReachableTime (in milliseconds) */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003055 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 }
3057
Eric W. Biederman464dc802012-11-16 03:02:59 +00003058 /* Don't export sysctls to unprivileged users */
3059 if (neigh_parms_net(p)->user_ns != &init_user_ns)
3060 t->neigh_vars[0].procname = NULL;
3061
Jiri Pirko73af6142013-12-07 19:26:55 +01003062 switch (neigh_parms_family(p)) {
3063 case AF_INET:
3064 p_name = "ipv4";
3065 break;
3066 case AF_INET6:
3067 p_name = "ipv6";
3068 break;
3069 default:
3070 BUG();
3071 }
3072
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003073 snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s",
3074 p_name, dev_name_source);
Denis V. Lunev4ab438f2008-02-28 20:48:01 -08003075 t->sysctl_header =
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003076 register_net_sysctl(neigh_parms_net(p), neigh_path, t->neigh_vars);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003077 if (!t->sysctl_header)
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003078 goto free;
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003079
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 p->sysctl_table = t;
3081 return 0;
3082
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003083free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 kfree(t);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003085err:
3086 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09003088EXPORT_SYMBOL(neigh_sysctl_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089
3090void neigh_sysctl_unregister(struct neigh_parms *p)
3091{
3092 if (p->sysctl_table) {
3093 struct neigh_sysctl_table *t = p->sysctl_table;
3094 p->sysctl_table = NULL;
Eric W. Biederman5dd3df12012-04-19 13:24:33 +00003095 unregister_net_sysctl_table(t->sysctl_header);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096 kfree(t);
3097 }
3098}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09003099EXPORT_SYMBOL(neigh_sysctl_unregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100
3101#endif /* CONFIG_SYSCTL */
3102
Thomas Grafc8822a42007-03-22 11:50:06 -07003103static int __init neigh_init(void)
3104{
Greg Rosec7ac8672011-06-10 01:27:09 +00003105 rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, NULL);
3106 rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, NULL);
3107 rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info, NULL);
Thomas Grafc8822a42007-03-22 11:50:06 -07003108
Greg Rosec7ac8672011-06-10 01:27:09 +00003109 rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
3110 NULL);
3111 rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, NULL);
Thomas Grafc8822a42007-03-22 11:50:06 -07003112
3113 return 0;
3114}
3115
3116subsys_initcall(neigh_init);
3117