Blame view

net/ipv4/route.c 82.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
  /*
   * INET		An implementation of the TCP/IP protocol suite for the LINUX
   *		operating system.  INET is implemented using the  BSD Socket
   *		interface as the means of communication with the user level.
   *
   *		ROUTE - implementation of the IP router.
   *
02c30a84e   Jesper Juhl   [PATCH] update Ro...
8
   * Authors:	Ross Biro
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
13
14
15
16
17
18
19
20
   *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
   *		Alan Cox, <gw4pts@gw4pts.ampr.org>
   *		Linus Torvalds, <Linus.Torvalds@helsinki.fi>
   *		Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
   *
   * Fixes:
   *		Alan Cox	:	Verify area fixes.
   *		Alan Cox	:	cli() protects routing changes
   *		Rui Oliveira	:	ICMP routing table updates
   *		(rco@di.uminho.pt)	Routing table insertion and update
   *		Linus Torvalds	:	Rewrote bits to be sensible
   *		Alan Cox	:	Added BSD route gw semantics
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
21
   *		Alan Cox	:	Super /proc >4K
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
   *		Alan Cox	:	MTU in route table
   *		Alan Cox	: 	MSS actually. Also added the window
   *					clamper.
   *		Sam Lantinga	:	Fixed route matching in rt_del()
   *		Alan Cox	:	Routing cache support.
   *		Alan Cox	:	Removed compatibility cruft.
   *		Alan Cox	:	RTF_REJECT support.
   *		Alan Cox	:	TCP irtt support.
   *		Jonathan Naylor	:	Added Metric support.
   *	Miquel van Smoorenburg	:	BSD API fixes.
   *	Miquel van Smoorenburg	:	Metrics.
   *		Alan Cox	:	Use __u32 properly
   *		Alan Cox	:	Aligned routing errors more closely with BSD
   *					our system is still very different.
   *		Alan Cox	:	Faster /proc handling
   *	Alexey Kuznetsov	:	Massive rework to support tree based routing,
   *					routing caches and better behaviour.
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
39
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
   *		Olaf Erb	:	irtt wasn't being copied right.
   *		Bjorn Ekwall	:	Kerneld route support.
   *		Alan Cox	:	Multicast fixed (I hope)
   * 		Pavel Krauz	:	Limited broadcast fixed
   *		Mike McLagan	:	Routing by source
   *	Alexey Kuznetsov	:	End of old history. Split to fib.c and
   *					route.c and rewritten from scratch.
   *		Andi Kleen	:	Load-limit warning messages.
   *	Vitaly E. Lavrov	:	Transparent proxy revived after year coma.
   *	Vitaly E. Lavrov	:	Race condition in ip_route_input_slow.
   *	Tobias Ringstrom	:	Uninitialized res.type in ip_route_output_slow.
   *	Vladimir V. Ivanov	:	IP rule info (flowid) is really useful.
   *		Marc Boucher	:	routing by fwmark
   *	Robert Olsson		:	Added rt_cache statistics
   *	Arnaldo C. Melo		:	Convert proc stuff to seq_file
bb1d23b02   Eric Dumazet   [IPV4]: Bug fix i...
55
   *	Eric Dumazet		:	hashed spinlocks and rt_check_expire() fixes.
cef2685e0   Ilia Sotnikov   [IPV4]: Aggregate...
56
57
   * 	Ilia Sotnikov		:	Ignore TOS on PMTUD and Redirect
   * 	Ilia Sotnikov		:	Removed TOS from hash calculations
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
61
62
63
   *
   *		This program is free software; you can redistribute it and/or
   *		modify it under the terms of the GNU General Public License
   *		as published by the Free Software Foundation; either version
   *		2 of the License, or (at your option) any later version.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
66
67
68
69
  #include <linux/module.h>
  #include <asm/uaccess.h>
  #include <asm/system.h>
  #include <linux/bitops.h>
  #include <linux/types.h>
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
  #include <linux/mm.h>
424c4b70c   Eric Dumazet   [IPV4]: Use the f...
71
  #include <linux/bootmem.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
75
76
77
78
79
80
  #include <linux/string.h>
  #include <linux/socket.h>
  #include <linux/sockios.h>
  #include <linux/errno.h>
  #include <linux/in.h>
  #include <linux/inet.h>
  #include <linux/netdevice.h>
  #include <linux/proc_fs.h>
  #include <linux/init.h>
39c90ece7   Eric Dumazet   [IPV4]: Convert r...
81
  #include <linux/workqueue.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
  #include <linux/skbuff.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
85
86
87
88
89
90
91
  #include <linux/inetdevice.h>
  #include <linux/igmp.h>
  #include <linux/pkt_sched.h>
  #include <linux/mroute.h>
  #include <linux/netfilter_ipv4.h>
  #include <linux/random.h>
  #include <linux/jhash.h>
  #include <linux/rcupdate.h>
  #include <linux/times.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
92
  #include <linux/slab.h>
352e512c3   Herbert Xu   [NET]: Eliminate ...
93
  #include <net/dst.h>
457c4cbc5   Eric W. Biederman   [NET]: Make /proc...
94
  #include <net/net_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
97
98
99
100
101
102
103
104
  #include <net/protocol.h>
  #include <net/ip.h>
  #include <net/route.h>
  #include <net/inetpeer.h>
  #include <net/sock.h>
  #include <net/ip_fib.h>
  #include <net/arp.h>
  #include <net/tcp.h>
  #include <net/icmp.h>
  #include <net/xfrm.h>
8d71740c5   Tom Tucker   [NET]: Core net c...
105
  #include <net/netevent.h>
63f3444fb   Thomas Graf   [IPv4]: Use rtnl ...
106
  #include <net/rtnetlink.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
109
110
111
112
113
114
115
116
  #ifdef CONFIG_SYSCTL
  #include <linux/sysctl.h>
  #endif
  
  #define RT_FL_TOS(oldflp) \
      ((u32)(oldflp->fl4_tos & (IPTOS_RT_MASK | RTO_ONLINK)))
  
  #define IP_MAX_MTU	0xFFF0
  
  #define RT_GC_TIMEOUT (300*HZ)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
  static int ip_rt_max_size;
817bc4db7   Stephen Hemminger   [IPV4] route: use...
118
119
120
121
122
123
124
125
126
127
128
129
  static int ip_rt_gc_timeout __read_mostly	= RT_GC_TIMEOUT;
  static int ip_rt_gc_interval __read_mostly	= 60 * HZ;
  static int ip_rt_gc_min_interval __read_mostly	= HZ / 2;
  static int ip_rt_redirect_number __read_mostly	= 9;
  static int ip_rt_redirect_load __read_mostly	= HZ / 50;
  static int ip_rt_redirect_silence __read_mostly	= ((HZ / 50) << (9 + 1));
  static int ip_rt_error_cost __read_mostly	= HZ;
  static int ip_rt_error_burst __read_mostly	= 5 * HZ;
  static int ip_rt_gc_elasticity __read_mostly	= 8;
  static int ip_rt_mtu_expires __read_mostly	= 10 * 60 * HZ;
  static int ip_rt_min_pmtu __read_mostly		= 512 + 20 + 20;
  static int ip_rt_min_advmss __read_mostly	= 256;
1080d709f   Neil Horman   net: implement em...
130
  static int rt_chain_length_max __read_mostly	= 20;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131

125bb8f56   Eric Dumazet   net: use a deferr...
132
133
  static struct delayed_work expires_work;
  static unsigned long expires_ljiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
136
137
138
139
140
141
142
143
144
145
  
  /*
   *	Interface to generic destination cache.
   */
  
  static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie);
  static void		 ipv4_dst_destroy(struct dst_entry *dst);
  static void		 ipv4_dst_ifdown(struct dst_entry *dst,
  					 struct net_device *dev, int how);
  static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst);
  static void		 ipv4_link_failure(struct sk_buff *skb);
  static void		 ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
569d36452   Daniel Lezcano   [NETNS][DST] dst:...
146
  static int rt_garbage_collect(struct dst_ops *ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
149
150
  
  
  static struct dst_ops ipv4_dst_ops = {
  	.family =		AF_INET,
09640e636   Harvey Harrison   net: replace uses...
151
  	.protocol =		cpu_to_be16(ETH_P_IP),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
154
155
156
157
158
  	.gc =			rt_garbage_collect,
  	.check =		ipv4_dst_check,
  	.destroy =		ipv4_dst_destroy,
  	.ifdown =		ipv4_dst_ifdown,
  	.negative_advice =	ipv4_negative_advice,
  	.link_failure =		ipv4_link_failure,
  	.update_pmtu =		ip_rt_update_pmtu,
1ac06e030   Herbert Xu   ipsec: Use the co...
159
  	.local_out =		__ip_local_out,
e24229705   Eric Dumazet   [NET]: should exp...
160
  	.entries =		ATOMIC_INIT(0),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
163
  };
  
  #define ECN_OR_COST(class)	TC_PRIO_##class
4839c52b0   Philippe De Muyter   [IPV4]: Make ip_t...
164
  const __u8 ip_tos2prio[16] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
  	TC_PRIO_BESTEFFORT,
  	ECN_OR_COST(FILLER),
  	TC_PRIO_BESTEFFORT,
  	ECN_OR_COST(BESTEFFORT),
  	TC_PRIO_BULK,
  	ECN_OR_COST(BULK),
  	TC_PRIO_BULK,
  	ECN_OR_COST(BULK),
  	TC_PRIO_INTERACTIVE,
  	ECN_OR_COST(INTERACTIVE),
  	TC_PRIO_INTERACTIVE,
  	ECN_OR_COST(INTERACTIVE),
  	TC_PRIO_INTERACTIVE_BULK,
  	ECN_OR_COST(INTERACTIVE_BULK),
  	TC_PRIO_INTERACTIVE_BULK,
  	ECN_OR_COST(INTERACTIVE_BULK)
  };
  
  
  /*
   * Route cache.
   */
  
  /* The locking scheme is rather straight forward:
   *
   * 1) Read-Copy Update protects the buckets of the central route hash.
   * 2) Only writers remove entries, and they hold the lock
   *    as they look at rtable reference counts.
   * 3) Only readers acquire references to rtable entries,
   *    they do so with atomic increments and with the
   *    lock held.
   */
  
  struct rt_hash_bucket {
  	struct rtable	*chain;
22c047ccb   Eric Dumazet   [NET]: Hashed spi...
200
  };
1080d709f   Neil Horman   net: implement em...
201

8a25d5deb   Ingo Molnar   [PATCH] lockdep: ...
202
203
  #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) || \
  	defined(CONFIG_PROVE_LOCKING)
22c047ccb   Eric Dumazet   [NET]: Hashed spi...
204
205
206
  /*
   * Instead of using one spinlock for each rt_hash_bucket, we use a table of spinlocks
   * The size of this table is a power of two and depends on the number of CPUS.
620512004   Ingo Molnar   [PATCH] lockdep: ...
207
   * (on lockdep we have a quite big spinlock_t, so keep the size down there)
22c047ccb   Eric Dumazet   [NET]: Hashed spi...
208
   */
620512004   Ingo Molnar   [PATCH] lockdep: ...
209
210
  #ifdef CONFIG_LOCKDEP
  # define RT_HASH_LOCK_SZ	256
22c047ccb   Eric Dumazet   [NET]: Hashed spi...
211
  #else
620512004   Ingo Molnar   [PATCH] lockdep: ...
212
213
214
215
216
217
218
219
220
221
222
  # if NR_CPUS >= 32
  #  define RT_HASH_LOCK_SZ	4096
  # elif NR_CPUS >= 16
  #  define RT_HASH_LOCK_SZ	2048
  # elif NR_CPUS >= 8
  #  define RT_HASH_LOCK_SZ	1024
  # elif NR_CPUS >= 4
  #  define RT_HASH_LOCK_SZ	512
  # else
  #  define RT_HASH_LOCK_SZ	256
  # endif
22c047ccb   Eric Dumazet   [NET]: Hashed spi...
223
224
225
226
  #endif
  
  static spinlock_t	*rt_hash_locks;
  # define rt_hash_lock_addr(slot) &rt_hash_locks[(slot) & (RT_HASH_LOCK_SZ - 1)]
1ff1cc202   Pavel Emelyanov   [IPV4] ROUTE: Con...
227
228
229
230
231
232
233
234
235
236
237
238
239
240
  
  static __init void rt_hash_lock_init(void)
  {
  	int i;
  
  	rt_hash_locks = kmalloc(sizeof(spinlock_t) * RT_HASH_LOCK_SZ,
  			GFP_KERNEL);
  	if (!rt_hash_locks)
  		panic("IP: failed to allocate rt_hash_locks
  ");
  
  	for (i = 0; i < RT_HASH_LOCK_SZ; i++)
  		spin_lock_init(&rt_hash_locks[i]);
  }
22c047ccb   Eric Dumazet   [NET]: Hashed spi...
241
242
  #else
  # define rt_hash_lock_addr(slot) NULL
1ff1cc202   Pavel Emelyanov   [IPV4] ROUTE: Con...
243
244
245
246
  
  static inline void rt_hash_lock_init(void)
  {
  }
22c047ccb   Eric Dumazet   [NET]: Hashed spi...
247
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248

817bc4db7   Stephen Hemminger   [IPV4] route: use...
249
250
251
  static struct rt_hash_bucket 	*rt_hash_table __read_mostly;
  static unsigned			rt_hash_mask __read_mostly;
  static unsigned int		rt_hash_log  __read_mostly;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252

2f970d835   Eric Dumazet   [IPV4]: rt_cache_...
253
  static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat);
27f39c73e   Eric Dumazet   net: Use __this_c...
254
  #define RT_CACHE_STAT_INC(field) __this_cpu_inc(rt_cache_stat.field)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255

b00180def   Denis V. Lunev   ipv4: pass curren...
256
  static inline unsigned int rt_hash(__be32 daddr, __be32 saddr, int idx,
0eae88f31   Eric Dumazet   net: Fix various ...
257
  				   int genid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
  {
0eae88f31   Eric Dumazet   net: Fix various ...
259
  	return jhash_3words((__force u32)daddr, (__force u32)saddr,
b00180def   Denis V. Lunev   ipv4: pass curren...
260
  			    idx, genid)
29e75252d   Eric Dumazet   [IPV4] route cach...
261
  		& rt_hash_mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
  }
e84f84f27   Denis V. Lunev   netns: place rt_g...
263
264
265
266
  static inline int rt_genid(struct net *net)
  {
  	return atomic_read(&net->ipv4.rt_genid);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
268
  #ifdef CONFIG_PROC_FS
  struct rt_cache_iter_state {
a75e936f2   Denis V. Lunev   [NETNS]: Process ...
269
  	struct seq_net_private p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
  	int bucket;
29e75252d   Eric Dumazet   [IPV4] route cach...
271
  	int genid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
  };
1218854af   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
273
  static struct rtable *rt_cache_get_first(struct seq_file *seq)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  {
1218854af   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
275
  	struct rt_cache_iter_state *st = seq->private;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
  	struct rtable *r = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
278
  
  	for (st->bucket = rt_hash_mask; st->bucket >= 0; --st->bucket) {
a62726657   Eric Dumazet   ip: speedup /proc...
279
280
  		if (!rt_hash_table[st->bucket].chain)
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
  		rcu_read_lock_bh();
a898def29   Paul E. McKenney   net: Add checking...
282
  		r = rcu_dereference_bh(rt_hash_table[st->bucket].chain);
29e75252d   Eric Dumazet   [IPV4] route cach...
283
  		while (r) {
d8d1f30b9   Changli Gao   net-next: remove ...
284
  			if (dev_net(r->dst.dev) == seq_file_net(seq) &&
a75e936f2   Denis V. Lunev   [NETNS]: Process ...
285
  			    r->rt_genid == st->genid)
29e75252d   Eric Dumazet   [IPV4] route cach...
286
  				return r;
d8d1f30b9   Changli Gao   net-next: remove ...
287
  			r = rcu_dereference_bh(r->dst.rt_next);
29e75252d   Eric Dumazet   [IPV4] route cach...
288
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
  		rcu_read_unlock_bh();
  	}
29e75252d   Eric Dumazet   [IPV4] route cach...
291
  	return r;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
  }
1218854af   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
293
  static struct rtable *__rt_cache_get_next(struct seq_file *seq,
642d63181   Denis V. Lunev   [IPV4]: rt_cache_...
294
  					  struct rtable *r)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
  {
1218854af   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
296
  	struct rt_cache_iter_state *st = seq->private;
a62726657   Eric Dumazet   ip: speedup /proc...
297

d8d1f30b9   Changli Gao   net-next: remove ...
298
  	r = r->dst.rt_next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
300
  	while (!r) {
  		rcu_read_unlock_bh();
a62726657   Eric Dumazet   ip: speedup /proc...
301
302
303
304
  		do {
  			if (--st->bucket < 0)
  				return NULL;
  		} while (!rt_hash_table[st->bucket].chain);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
307
  		rcu_read_lock_bh();
  		r = rt_hash_table[st->bucket].chain;
  	}
a898def29   Paul E. McKenney   net: Add checking...
308
  	return rcu_dereference_bh(r);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
  }
1218854af   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
310
  static struct rtable *rt_cache_get_next(struct seq_file *seq,
642d63181   Denis V. Lunev   [IPV4]: rt_cache_...
311
312
  					struct rtable *r)
  {
1218854af   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
313
314
  	struct rt_cache_iter_state *st = seq->private;
  	while ((r = __rt_cache_get_next(seq, r)) != NULL) {
d8d1f30b9   Changli Gao   net-next: remove ...
315
  		if (dev_net(r->dst.dev) != seq_file_net(seq))
a75e936f2   Denis V. Lunev   [NETNS]: Process ...
316
  			continue;
642d63181   Denis V. Lunev   [IPV4]: rt_cache_...
317
318
319
320
321
  		if (r->rt_genid == st->genid)
  			break;
  	}
  	return r;
  }
1218854af   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
322
  static struct rtable *rt_cache_get_idx(struct seq_file *seq, loff_t pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
  {
1218854af   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
324
  	struct rtable *r = rt_cache_get_first(seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
326
  
  	if (r)
1218854af   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
327
  		while (pos && (r = rt_cache_get_next(seq, r)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
330
331
332
333
  			--pos;
  	return pos ? NULL : r;
  }
  
  static void *rt_cache_seq_start(struct seq_file *seq, loff_t *pos)
  {
29e75252d   Eric Dumazet   [IPV4] route cach...
334
  	struct rt_cache_iter_state *st = seq->private;
29e75252d   Eric Dumazet   [IPV4] route cach...
335
  	if (*pos)
1218854af   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
336
  		return rt_cache_get_idx(seq, *pos - 1);
e84f84f27   Denis V. Lunev   netns: place rt_g...
337
  	st->genid = rt_genid(seq_file_net(seq));
29e75252d   Eric Dumazet   [IPV4] route cach...
338
  	return SEQ_START_TOKEN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
341
342
  }
  
  static void *rt_cache_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  {
29e75252d   Eric Dumazet   [IPV4] route cach...
343
  	struct rtable *r;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
  
  	if (v == SEQ_START_TOKEN)
1218854af   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
346
  		r = rt_cache_get_first(seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
  	else
1218854af   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
348
  		r = rt_cache_get_next(seq, v);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
  	++*pos;
  	return r;
  }
  
  static void rt_cache_seq_stop(struct seq_file *seq, void *v)
  {
  	if (v && v != SEQ_START_TOKEN)
  		rcu_read_unlock_bh();
  }
  
  static int rt_cache_seq_show(struct seq_file *seq, void *v)
  {
  	if (v == SEQ_START_TOKEN)
  		seq_printf(seq, "%-127s
  ",
  			   "Iface\tDestination\tGateway \tFlags\t\tRefCnt\tUse\t"
  			   "Metric\tSource\t\tMTU\tWindow\tIRTT\tTOS\tHHRef\t"
  			   "HHUptod\tSpecDst");
  	else {
  		struct rtable *r = v;
5e659e4cb   Pavel Emelyanov   [NET]: Fix heavy ...
369
  		int len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370

0eae88f31   Eric Dumazet   net: Fix various ...
371
372
  		seq_printf(seq, "%s\t%08X\t%08X\t%8X\t%d\t%u\t%d\t"
  			      "%08X\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X%n",
d8d1f30b9   Changli Gao   net-next: remove ...
373
  			r->dst.dev ? r->dst.dev->name : "*",
0eae88f31   Eric Dumazet   net: Fix various ...
374
375
  			(__force u32)r->rt_dst,
  			(__force u32)r->rt_gateway,
d8d1f30b9   Changli Gao   net-next: remove ...
376
377
378
379
380
381
382
  			r->rt_flags, atomic_read(&r->dst.__refcnt),
  			r->dst.__use, 0, (__force u32)r->rt_src,
  			(dst_metric(&r->dst, RTAX_ADVMSS) ?
  			     (int)dst_metric(&r->dst, RTAX_ADVMSS) + 40 : 0),
  			dst_metric(&r->dst, RTAX_WINDOW),
  			(int)((dst_metric(&r->dst, RTAX_RTT) >> 3) +
  			      dst_metric(&r->dst, RTAX_RTTVAR)),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
  			r->fl.fl4_tos,
d8d1f30b9   Changli Gao   net-next: remove ...
384
385
  			r->dst.hh ? atomic_read(&r->dst.hh->hh_refcnt) : -1,
  			r->dst.hh ? (r->dst.hh->hh_output ==
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
  				       dev_queue_xmit) : 0,
5e659e4cb   Pavel Emelyanov   [NET]: Fix heavy ...
387
388
389
390
  			r->rt_spec_dst, &len);
  
  		seq_printf(seq, "%*s
  ", 127 - len, "");
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
391
392
  	}
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
  }
f690808e1   Stephen Hemminger   [NET]: make seq_o...
394
  static const struct seq_operations rt_cache_seq_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
397
398
399
400
401
402
  	.start  = rt_cache_seq_start,
  	.next   = rt_cache_seq_next,
  	.stop   = rt_cache_seq_stop,
  	.show   = rt_cache_seq_show,
  };
  
  static int rt_cache_seq_open(struct inode *inode, struct file *file)
  {
a75e936f2   Denis V. Lunev   [NETNS]: Process ...
403
  	return seq_open_net(inode, file, &rt_cache_seq_ops,
cf7732e4c   Pavel Emelyanov   [NET]: Make core ...
404
  			sizeof(struct rt_cache_iter_state));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
  }
9a32144e9   Arjan van de Ven   [PATCH] mark stru...
406
  static const struct file_operations rt_cache_seq_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
409
410
  	.owner	 = THIS_MODULE,
  	.open	 = rt_cache_seq_open,
  	.read	 = seq_read,
  	.llseek	 = seq_lseek,
a75e936f2   Denis V. Lunev   [NETNS]: Process ...
411
  	.release = seq_release_net,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
413
414
415
416
417
418
419
420
  };
  
  
  static void *rt_cpu_seq_start(struct seq_file *seq, loff_t *pos)
  {
  	int cpu;
  
  	if (*pos == 0)
  		return SEQ_START_TOKEN;
0f23174aa   Rusty Russell   cpumask: prepare ...
421
  	for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
424
  		if (!cpu_possible(cpu))
  			continue;
  		*pos = cpu+1;
2f970d835   Eric Dumazet   [IPV4]: rt_cache_...
425
  		return &per_cpu(rt_cache_stat, cpu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
427
428
429
430
431
432
  	}
  	return NULL;
  }
  
  static void *rt_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  {
  	int cpu;
0f23174aa   Rusty Russell   cpumask: prepare ...
433
  	for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
435
436
  		if (!cpu_possible(cpu))
  			continue;
  		*pos = cpu+1;
2f970d835   Eric Dumazet   [IPV4]: rt_cache_...
437
  		return &per_cpu(rt_cache_stat, cpu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
439
  	}
  	return NULL;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
440

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
442
443
444
445
446
447
448
449
450
451
452
  }
  
  static void rt_cpu_seq_stop(struct seq_file *seq, void *v)
  {
  
  }
  
  static int rt_cpu_seq_show(struct seq_file *seq, void *v)
  {
  	struct rt_cache_stat *st = v;
  
  	if (v == SEQ_START_TOKEN) {
5bec0039f   Olaf Rempel   [NET]: /proc/net/...
453
454
  		seq_printf(seq, "entries  in_hit in_slow_tot in_slow_mc in_no_route in_brd in_martian_dst in_martian_src  out_hit out_slow_tot out_slow_mc  gc_total gc_ignored gc_goal_miss gc_dst_overflow in_hlist_search out_hlist_search
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
456
  		return 0;
  	}
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
457

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
460
461
462
463
464
465
466
467
468
469
470
471
  	seq_printf(seq,"%08x  %08x %08x %08x %08x %08x %08x %08x "
  		   " %08x %08x %08x %08x %08x %08x %08x %08x %08x 
  ",
  		   atomic_read(&ipv4_dst_ops.entries),
  		   st->in_hit,
  		   st->in_slow_tot,
  		   st->in_slow_mc,
  		   st->in_no_route,
  		   st->in_brd,
  		   st->in_martian_dst,
  		   st->in_martian_src,
  
  		   st->out_hit,
  		   st->out_slow_tot,
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
472
  		   st->out_slow_mc,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
474
475
476
477
478
479
480
481
482
  
  		   st->gc_total,
  		   st->gc_ignored,
  		   st->gc_goal_miss,
  		   st->gc_dst_overflow,
  		   st->in_hlist_search,
  		   st->out_hlist_search
  		);
  	return 0;
  }
f690808e1   Stephen Hemminger   [NET]: make seq_o...
483
  static const struct seq_operations rt_cpu_seq_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
485
486
487
488
489
490
491
492
493
494
  	.start  = rt_cpu_seq_start,
  	.next   = rt_cpu_seq_next,
  	.stop   = rt_cpu_seq_stop,
  	.show   = rt_cpu_seq_show,
  };
  
  
  static int rt_cpu_seq_open(struct inode *inode, struct file *file)
  {
  	return seq_open(file, &rt_cpu_seq_ops);
  }
9a32144e9   Arjan van de Ven   [PATCH] mark stru...
495
  static const struct file_operations rt_cpu_seq_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
497
498
499
500
501
  	.owner	 = THIS_MODULE,
  	.open	 = rt_cpu_seq_open,
  	.read	 = seq_read,
  	.llseek	 = seq_lseek,
  	.release = seq_release,
  };
78c686e9f   Pavel Emelyanov   [IPV4] ROUTE: Col...
502
  #ifdef CONFIG_NET_CLS_ROUTE
a661c4199   Alexey Dobriyan   net: convert /pro...
503
  static int rt_acct_proc_show(struct seq_file *m, void *v)
78c686e9f   Pavel Emelyanov   [IPV4] ROUTE: Col...
504
  {
a661c4199   Alexey Dobriyan   net: convert /pro...
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
  	struct ip_rt_acct *dst, *src;
  	unsigned int i, j;
  
  	dst = kcalloc(256, sizeof(struct ip_rt_acct), GFP_KERNEL);
  	if (!dst)
  		return -ENOMEM;
  
  	for_each_possible_cpu(i) {
  		src = (struct ip_rt_acct *)per_cpu_ptr(ip_rt_acct, i);
  		for (j = 0; j < 256; j++) {
  			dst[j].o_bytes   += src[j].o_bytes;
  			dst[j].o_packets += src[j].o_packets;
  			dst[j].i_bytes   += src[j].i_bytes;
  			dst[j].i_packets += src[j].i_packets;
  		}
78c686e9f   Pavel Emelyanov   [IPV4] ROUTE: Col...
520
  	}
a661c4199   Alexey Dobriyan   net: convert /pro...
521
522
523
524
  	seq_write(m, dst, 256 * sizeof(struct ip_rt_acct));
  	kfree(dst);
  	return 0;
  }
78c686e9f   Pavel Emelyanov   [IPV4] ROUTE: Col...
525

a661c4199   Alexey Dobriyan   net: convert /pro...
526
527
528
  static int rt_acct_proc_open(struct inode *inode, struct file *file)
  {
  	return single_open(file, rt_acct_proc_show, NULL);
78c686e9f   Pavel Emelyanov   [IPV4] ROUTE: Col...
529
  }
a661c4199   Alexey Dobriyan   net: convert /pro...
530
531
532
533
534
535
536
537
  
  static const struct file_operations rt_acct_proc_fops = {
  	.owner		= THIS_MODULE,
  	.open		= rt_acct_proc_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
  	.release	= single_release,
  };
78c686e9f   Pavel Emelyanov   [IPV4] ROUTE: Col...
538
  #endif
107f16342   Pavel Emelyanov   [IPV4] ROUTE: Cle...
539

73b387116   Denis V. Lunev   [NETNS]: Register...
540
  static int __net_init ip_rt_do_proc_init(struct net *net)
107f16342   Pavel Emelyanov   [IPV4] ROUTE: Cle...
541
542
543
544
545
546
547
  {
  	struct proc_dir_entry *pde;
  
  	pde = proc_net_fops_create(net, "rt_cache", S_IRUGO,
  			&rt_cache_seq_fops);
  	if (!pde)
  		goto err1;
770207208   Wang Chen   [IPV4]: Use proc_...
548
549
  	pde = proc_create("rt_cache", S_IRUGO,
  			  net->proc_net_stat, &rt_cpu_seq_fops);
107f16342   Pavel Emelyanov   [IPV4] ROUTE: Cle...
550
551
  	if (!pde)
  		goto err2;
107f16342   Pavel Emelyanov   [IPV4] ROUTE: Cle...
552
  #ifdef CONFIG_NET_CLS_ROUTE
a661c4199   Alexey Dobriyan   net: convert /pro...
553
  	pde = proc_create("rt_acct", 0, net->proc_net, &rt_acct_proc_fops);
107f16342   Pavel Emelyanov   [IPV4] ROUTE: Cle...
554
555
556
557
558
559
560
561
562
563
564
565
566
567
  	if (!pde)
  		goto err3;
  #endif
  	return 0;
  
  #ifdef CONFIG_NET_CLS_ROUTE
  err3:
  	remove_proc_entry("rt_cache", net->proc_net_stat);
  #endif
  err2:
  	remove_proc_entry("rt_cache", net->proc_net);
  err1:
  	return -ENOMEM;
  }
73b387116   Denis V. Lunev   [NETNS]: Register...
568
569
570
571
572
  
  static void __net_exit ip_rt_do_proc_exit(struct net *net)
  {
  	remove_proc_entry("rt_cache", net->proc_net_stat);
  	remove_proc_entry("rt_cache", net->proc_net);
0a931acfd   Alexey Dobriyan   ipv4: don't remov...
573
  #ifdef CONFIG_NET_CLS_ROUTE
73b387116   Denis V. Lunev   [NETNS]: Register...
574
  	remove_proc_entry("rt_acct", net->proc_net);
0a931acfd   Alexey Dobriyan   ipv4: don't remov...
575
  #endif
73b387116   Denis V. Lunev   [NETNS]: Register...
576
577
578
579
580
581
582
583
584
585
586
  }
  
  static struct pernet_operations ip_rt_proc_ops __net_initdata =  {
  	.init = ip_rt_do_proc_init,
  	.exit = ip_rt_do_proc_exit,
  };
  
  static int __init ip_rt_proc_init(void)
  {
  	return register_pernet_subsys(&ip_rt_proc_ops);
  }
107f16342   Pavel Emelyanov   [IPV4] ROUTE: Cle...
587
  #else
73b387116   Denis V. Lunev   [NETNS]: Register...
588
  static inline int ip_rt_proc_init(void)
107f16342   Pavel Emelyanov   [IPV4] ROUTE: Cle...
589
590
591
  {
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
  #endif /* CONFIG_PROC_FS */
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
593

5969f71d5   Stephen Hemminger   IPV4: route inlin...
594
  static inline void rt_free(struct rtable *rt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
  {
d8d1f30b9   Changli Gao   net-next: remove ...
596
  	call_rcu_bh(&rt->dst.rcu_head, dst_rcu_free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
  }
5969f71d5   Stephen Hemminger   IPV4: route inlin...
598
  static inline void rt_drop(struct rtable *rt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
  	ip_rt_put(rt);
d8d1f30b9   Changli Gao   net-next: remove ...
601
  	call_rcu_bh(&rt->dst.rcu_head, dst_rcu_free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
  }
5969f71d5   Stephen Hemminger   IPV4: route inlin...
603
  static inline int rt_fast_clean(struct rtable *rth)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
605
606
607
  {
  	/* Kill broadcast/multicast entries very aggresively, if they
  	   collide in hash table with more useful entries */
  	return (rth->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) &&
d8d1f30b9   Changli Gao   net-next: remove ...
608
  		rth->fl.iif && rth->dst.rt_next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
  }
5969f71d5   Stephen Hemminger   IPV4: route inlin...
610
  static inline int rt_valuable(struct rtable *rth)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
612
  {
  	return (rth->rt_flags & (RTCF_REDIRECTED | RTCF_NOTIFY)) ||
d8d1f30b9   Changli Gao   net-next: remove ...
613
  		rth->dst.expires;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
615
616
617
618
619
  }
  
  static int rt_may_expire(struct rtable *rth, unsigned long tmo1, unsigned long tmo2)
  {
  	unsigned long age;
  	int ret = 0;
d8d1f30b9   Changli Gao   net-next: remove ...
620
  	if (atomic_read(&rth->dst.__refcnt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
622
623
  		goto out;
  
  	ret = 1;
d8d1f30b9   Changli Gao   net-next: remove ...
624
625
  	if (rth->dst.expires &&
  	    time_after_eq(jiffies, rth->dst.expires))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626
  		goto out;
d8d1f30b9   Changli Gao   net-next: remove ...
627
  	age = jiffies - rth->dst.lastuse;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
  	ret = 0;
  	if ((age <= tmo1 && !rt_fast_clean(rth)) ||
  	    (age <= tmo2 && rt_valuable(rth)))
  		goto out;
  	ret = 1;
  out:	return ret;
  }
  
  /* Bits of score are:
   * 31: very valuable
   * 30: not quite useless
   * 29..0: usage counter
   */
  static inline u32 rt_score(struct rtable *rt)
  {
d8d1f30b9   Changli Gao   net-next: remove ...
643
  	u32 score = jiffies - rt->dst.lastuse;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
645
646
647
648
649
650
651
652
653
654
655
  
  	score = ~score & ~(3<<30);
  
  	if (rt_valuable(rt))
  		score |= (1<<31);
  
  	if (!rt->fl.iif ||
  	    !(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL)))
  		score |= (1<<30);
  
  	return score;
  }
1080d709f   Neil Horman   net: implement em...
656
657
658
659
660
661
662
663
664
  static inline bool rt_caching(const struct net *net)
  {
  	return net->ipv4.current_rt_cache_rebuild_count <=
  		net->ipv4.sysctl_rt_cache_rebuild_count;
  }
  
  static inline bool compare_hash_inputs(const struct flowi *fl1,
  					const struct flowi *fl2)
  {
0eae88f31   Eric Dumazet   net: Fix various ...
665
666
  	return ((((__force u32)fl1->nl_u.ip4_u.daddr ^ (__force u32)fl2->nl_u.ip4_u.daddr) |
  		((__force u32)fl1->nl_u.ip4_u.saddr ^ (__force u32)fl2->nl_u.ip4_u.saddr) |
1080d709f   Neil Horman   net: implement em...
667
668
  		(fl1->iif ^ fl2->iif)) == 0);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
670
  static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
  {
0eae88f31   Eric Dumazet   net: Fix various ...
671
672
  	return (((__force u32)fl1->nl_u.ip4_u.daddr ^ (__force u32)fl2->nl_u.ip4_u.daddr) |
  		((__force u32)fl1->nl_u.ip4_u.saddr ^ (__force u32)fl2->nl_u.ip4_u.saddr) |
47dcf0cb1   Thomas Graf   [NET]: Rethink ma...
673
  		(fl1->mark ^ fl2->mark) |
0eae88f31   Eric Dumazet   net: Fix various ...
674
  		(*(u16 *)&fl1->nl_u.ip4_u.tos ^ *(u16 *)&fl2->nl_u.ip4_u.tos) |
8238b218e   David S. Miller   [NET]: Do not mem...
675
676
  		(fl1->oif ^ fl2->oif) |
  		(fl1->iif ^ fl2->iif)) == 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
  }
b5921910a   Denis V. Lunev   [NETNS]: Routing ...
678
679
  static inline int compare_netns(struct rtable *rt1, struct rtable *rt2)
  {
d8d1f30b9   Changli Gao   net-next: remove ...
680
  	return net_eq(dev_net(rt1->dst.dev), dev_net(rt2->dst.dev));
b5921910a   Denis V. Lunev   [NETNS]: Routing ...
681
  }
e84f84f27   Denis V. Lunev   netns: place rt_g...
682
683
  static inline int rt_is_expired(struct rtable *rth)
  {
d8d1f30b9   Changli Gao   net-next: remove ...
684
  	return rth->rt_genid != rt_genid(dev_net(rth->dst.dev));
e84f84f27   Denis V. Lunev   netns: place rt_g...
685
  }
beb659bd8   Eric Dumazet   [PATCH] IPV4 : Mo...
686
687
688
689
690
691
692
693
694
  /*
   * Perform a full scan of hash table and free all entries.
   * Can be called by a softirq or a process.
   * In the later case, we want to be reschedule if necessary
   */
  static void rt_do_flush(int process_context)
  {
  	unsigned int i;
  	struct rtable *rth, *next;
32cb5b4e0   Denis V. Lunev   netns: selective ...
695
  	struct rtable * tail;
beb659bd8   Eric Dumazet   [PATCH] IPV4 : Mo...
696
697
698
699
700
701
702
703
704
  
  	for (i = 0; i <= rt_hash_mask; i++) {
  		if (process_context && need_resched())
  			cond_resched();
  		rth = rt_hash_table[i].chain;
  		if (!rth)
  			continue;
  
  		spin_lock_bh(rt_hash_lock_addr(i));
32cb5b4e0   Denis V. Lunev   netns: selective ...
705
706
707
708
709
710
711
  #ifdef CONFIG_NET_NS
  		{
  		struct rtable ** prev, * p;
  
  		rth = rt_hash_table[i].chain;
  
  		/* defer releasing the head of the list after spin_unlock */
d8d1f30b9   Changli Gao   net-next: remove ...
712
  		for (tail = rth; tail; tail = tail->dst.rt_next)
32cb5b4e0   Denis V. Lunev   netns: selective ...
713
714
715
716
717
718
719
720
  			if (!rt_is_expired(tail))
  				break;
  		if (rth != tail)
  			rt_hash_table[i].chain = tail;
  
  		/* call rt_free on entries after the tail requiring flush */
  		prev = &rt_hash_table[i].chain;
  		for (p = *prev; p; p = next) {
d8d1f30b9   Changli Gao   net-next: remove ...
721
  			next = p->dst.rt_next;
32cb5b4e0   Denis V. Lunev   netns: selective ...
722
  			if (!rt_is_expired(p)) {
d8d1f30b9   Changli Gao   net-next: remove ...
723
  				prev = &p->dst.rt_next;
32cb5b4e0   Denis V. Lunev   netns: selective ...
724
725
726
727
728
729
730
  			} else {
  				*prev = next;
  				rt_free(p);
  			}
  		}
  		}
  #else
beb659bd8   Eric Dumazet   [PATCH] IPV4 : Mo...
731
732
  		rth = rt_hash_table[i].chain;
  		rt_hash_table[i].chain = NULL;
32cb5b4e0   Denis V. Lunev   netns: selective ...
733
734
  		tail = NULL;
  #endif
beb659bd8   Eric Dumazet   [PATCH] IPV4 : Mo...
735
  		spin_unlock_bh(rt_hash_lock_addr(i));
32cb5b4e0   Denis V. Lunev   netns: selective ...
736
  		for (; rth != tail; rth = next) {
d8d1f30b9   Changli Gao   net-next: remove ...
737
  			next = rth->dst.rt_next;
beb659bd8   Eric Dumazet   [PATCH] IPV4 : Mo...
738
739
740
741
  			rt_free(rth);
  		}
  	}
  }
1080d709f   Neil Horman   net: implement em...
742
743
744
745
746
747
748
749
750
751
  /*
   * While freeing expired entries, we compute average chain length
   * and standard deviation, using fixed-point arithmetic.
   * This to have an estimation of rt_chain_length_max
   *  rt_chain_length_max = max(elasticity, AVG + 4*SD)
   * We use 3 bits for frational part, and 29 (or 61) for magnitude.
   */
  
  #define FRACT_BITS 3
  #define ONE (1UL << FRACT_BITS)
983763872   Eric Dumazet   net: fix route ca...
752
753
754
755
756
757
758
759
760
761
762
763
764
765
  /*
   * Given a hash chain and an item in this hash chain,
   * find if a previous entry has the same hash_inputs
   * (but differs on tos, mark or oif)
   * Returns 0 if an alias is found.
   * Returns ONE if rth has no alias before itself.
   */
  static int has_noalias(const struct rtable *head, const struct rtable *rth)
  {
  	const struct rtable *aux = head;
  
  	while (aux != rth) {
  		if (compare_hash_inputs(&aux->fl, &rth->fl))
  			return 0;
d8d1f30b9   Changli Gao   net-next: remove ...
766
  		aux = aux->dst.rt_next;
983763872   Eric Dumazet   net: fix route ca...
767
768
769
  	}
  	return ONE;
  }
beb659bd8   Eric Dumazet   [PATCH] IPV4 : Mo...
770
  static void rt_check_expire(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
  {
bb1d23b02   Eric Dumazet   [IPV4]: Bug fix i...
772
773
  	static unsigned int rover;
  	unsigned int i = rover, goal;
983763872   Eric Dumazet   net: fix route ca...
774
  	struct rtable *rth, **rthp;
cf8da764f   Eric Dumazet   net: fix length c...
775
  	unsigned long samples = 0;
1080d709f   Neil Horman   net: implement em...
776
  	unsigned long sum = 0, sum2 = 0;
125bb8f56   Eric Dumazet   net: use a deferr...
777
  	unsigned long delta;
bb1d23b02   Eric Dumazet   [IPV4]: Bug fix i...
778
  	u64 mult;
125bb8f56   Eric Dumazet   net: use a deferr...
779
780
781
  	delta = jiffies - expires_ljiffies;
  	expires_ljiffies = jiffies;
  	mult = ((u64)delta) << rt_hash_log;
bb1d23b02   Eric Dumazet   [IPV4]: Bug fix i...
782
783
784
  	if (ip_rt_gc_timeout > 1)
  		do_div(mult, ip_rt_gc_timeout);
  	goal = (unsigned int)mult;
39c90ece7   Eric Dumazet   [IPV4]: Convert r...
785
786
  	if (goal > rt_hash_mask)
  		goal = rt_hash_mask + 1;
bb1d23b02   Eric Dumazet   [IPV4]: Bug fix i...
787
  	for (; goal > 0; goal--) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788
  		unsigned long tmo = ip_rt_gc_timeout;
cf8da764f   Eric Dumazet   net: fix length c...
789
  		unsigned long length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
790
791
792
  
  		i = (i + 1) & rt_hash_mask;
  		rthp = &rt_hash_table[i].chain;
d90bf5a97   Eric Dumazet   [NET]: rt_check_e...
793
794
  		if (need_resched())
  			cond_resched();
1080d709f   Neil Horman   net: implement em...
795
  		samples++;
cfcabdcc2   Stephen Hemminger   [NET]: sparse war...
796
  		if (*rthp == NULL)
bb1d23b02   Eric Dumazet   [IPV4]: Bug fix i...
797
  			continue;
cf8da764f   Eric Dumazet   net: fix length c...
798
  		length = 0;
39c90ece7   Eric Dumazet   [IPV4]: Convert r...
799
  		spin_lock_bh(rt_hash_lock_addr(i));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
  		while ((rth = *rthp) != NULL) {
d8d1f30b9   Changli Gao   net-next: remove ...
801
  			prefetch(rth->dst.rt_next);
e84f84f27   Denis V. Lunev   netns: place rt_g...
802
  			if (rt_is_expired(rth)) {
d8d1f30b9   Changli Gao   net-next: remove ...
803
  				*rthp = rth->dst.rt_next;
29e75252d   Eric Dumazet   [IPV4] route cach...
804
805
806
  				rt_free(rth);
  				continue;
  			}
d8d1f30b9   Changli Gao   net-next: remove ...
807
  			if (rth->dst.expires) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
  				/* Entry is expired even if it is in use */
d8d1f30b9   Changli Gao   net-next: remove ...
809
  				if (time_before_eq(jiffies, rth->dst.expires)) {
1ddbcb005   Eric Dumazet   net: fix rtable l...
810
  nofree:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
811
  					tmo >>= 1;
d8d1f30b9   Changli Gao   net-next: remove ...
812
  					rthp = &rth->dst.rt_next;
1080d709f   Neil Horman   net: implement em...
813
  					/*
1ddbcb005   Eric Dumazet   net: fix rtable l...
814
  					 * We only count entries on
1080d709f   Neil Horman   net: implement em...
815
816
817
818
819
820
  					 * a chain with equal hash inputs once
  					 * so that entries for different QOS
  					 * levels, and other non-hash input
  					 * attributes don't unfairly skew
  					 * the length computation
  					 */
983763872   Eric Dumazet   net: fix route ca...
821
  					length += has_noalias(rt_hash_table[i].chain, rth);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
823
  					continue;
  				}
1ddbcb005   Eric Dumazet   net: fix rtable l...
824
825
  			} else if (!rt_may_expire(rth, tmo, ip_rt_gc_timeout))
  				goto nofree;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826
827
  
  			/* Cleanup aged off entries. */
d8d1f30b9   Changli Gao   net-next: remove ...
828
  			*rthp = rth->dst.rt_next;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
829
  			rt_free(rth);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
830
  		}
39c90ece7   Eric Dumazet   [IPV4]: Convert r...
831
  		spin_unlock_bh(rt_hash_lock_addr(i));
1080d709f   Neil Horman   net: implement em...
832
833
834
835
836
837
838
839
840
  		sum += length;
  		sum2 += length*length;
  	}
  	if (samples) {
  		unsigned long avg = sum / samples;
  		unsigned long sd = int_sqrt(sum2 / samples - avg*avg);
  		rt_chain_length_max = max_t(unsigned long,
  					ip_rt_gc_elasticity,
  					(avg + 4*sd) >> FRACT_BITS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
842
  	}
  	rover = i;
beb659bd8   Eric Dumazet   [PATCH] IPV4 : Mo...
843
844
845
846
  }
  
  /*
   * rt_worker_func() is run in process context.
29e75252d   Eric Dumazet   [IPV4] route cach...
847
   * we call rt_check_expire() to scan part of the hash table
beb659bd8   Eric Dumazet   [PATCH] IPV4 : Mo...
848
849
850
   */
  static void rt_worker_func(struct work_struct *work)
  {
29e75252d   Eric Dumazet   [IPV4] route cach...
851
  	rt_check_expire();
39c90ece7   Eric Dumazet   [IPV4]: Convert r...
852
  	schedule_delayed_work(&expires_work, ip_rt_gc_interval);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
  }
29e75252d   Eric Dumazet   [IPV4] route cach...
854
855
856
857
858
  /*
   * Pertubation of rt_genid by a small quantity [1..256]
   * Using 8 bits of shuffling ensure we can call rt_cache_invalidate()
   * many times (2^24) without giving recent rt_genid.
   * Jenkins hash is strong enough that litle changes of rt_genid are OK.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
   */
86c657f6b   Denis V. Lunev   netns: add struct...
860
  static void rt_cache_invalidate(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861
  {
29e75252d   Eric Dumazet   [IPV4] route cach...
862
  	unsigned char shuffle;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863

29e75252d   Eric Dumazet   [IPV4] route cach...
864
  	get_random_bytes(&shuffle, sizeof(shuffle));
e84f84f27   Denis V. Lunev   netns: place rt_g...
865
  	atomic_add(shuffle + 1U, &net->ipv4.rt_genid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866
  }
29e75252d   Eric Dumazet   [IPV4] route cach...
867
868
869
870
  /*
   * delay < 0  : invalidate cache (fast : entries will be deleted later)
   * delay >= 0 : invalidate & flush cache (can be long)
   */
76e6ebfb4   Denis V. Lunev   netns: add namesp...
871
  void rt_cache_flush(struct net *net, int delay)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
  {
86c657f6b   Denis V. Lunev   netns: add struct...
873
  	rt_cache_invalidate(net);
29e75252d   Eric Dumazet   [IPV4] route cach...
874
875
  	if (delay >= 0)
  		rt_do_flush(!in_softirq());
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
  }
a5ee15513   Eric W. Biederman   net: NETDEV_UNREG...
877
878
879
880
881
  /* Flush previous cache invalidated entries from the cache */
  void rt_cache_flush_batch(void)
  {
  	rt_do_flush(!in_softirq());
  }
1080d709f   Neil Horman   net: implement em...
882
883
  static void rt_emergency_hash_rebuild(struct net *net)
  {
3ee943728   Neil Horman   ipv4: remove ip_r...
884
  	if (net_ratelimit())
1080d709f   Neil Horman   net: implement em...
885
886
  		printk(KERN_WARNING "Route hash chain too long!
  ");
3ee943728   Neil Horman   ipv4: remove ip_r...
887
  	rt_cache_invalidate(net);
1080d709f   Neil Horman   net: implement em...
888
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889
890
891
892
893
894
895
896
897
898
899
900
  /*
     Short description of GC goals.
  
     We want to build algorithm, which will keep routing cache
     at some equilibrium point, when number of aged off entries
     is kept approximately equal to newly generated ones.
  
     Current expiration strength is variable "expire".
     We try to adjust it dynamically, so that if networking
     is idle expires is large enough to keep enough of warm entries,
     and when load increases it reduces to limit cache size.
   */
569d36452   Daniel Lezcano   [NETNS][DST] dst:...
901
  static int rt_garbage_collect(struct dst_ops *ops)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
  {
  	static unsigned long expire = RT_GC_TIMEOUT;
  	static unsigned long last_gc;
  	static int rover;
  	static int equilibrium;
  	struct rtable *rth, **rthp;
  	unsigned long now = jiffies;
  	int goal;
  
  	/*
  	 * Garbage collection is pretty expensive,
  	 * do not make it too frequently.
  	 */
  
  	RT_CACHE_STAT_INC(gc_total);
  
  	if (now - last_gc < ip_rt_gc_min_interval &&
  	    atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size) {
  		RT_CACHE_STAT_INC(gc_ignored);
  		goto out;
  	}
  
  	/* Calculate number of entries, which we want to expire now. */
  	goal = atomic_read(&ipv4_dst_ops.entries) -
  		(ip_rt_gc_elasticity << rt_hash_log);
  	if (goal <= 0) {
  		if (equilibrium < ipv4_dst_ops.gc_thresh)
  			equilibrium = ipv4_dst_ops.gc_thresh;
  		goal = atomic_read(&ipv4_dst_ops.entries) - equilibrium;
  		if (goal > 0) {
b790cedd2   Eric Dumazet   [INET]: Avoid an ...
932
  			equilibrium += min_t(unsigned int, goal >> 1, rt_hash_mask + 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
933
934
935
936
937
938
  			goal = atomic_read(&ipv4_dst_ops.entries) - equilibrium;
  		}
  	} else {
  		/* We are in dangerous area. Try to reduce cache really
  		 * aggressively.
  		 */
b790cedd2   Eric Dumazet   [INET]: Avoid an ...
939
  		goal = max_t(unsigned int, goal >> 1, rt_hash_mask + 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
  		equilibrium = atomic_read(&ipv4_dst_ops.entries) - goal;
  	}
  
  	if (now - last_gc >= ip_rt_gc_min_interval)
  		last_gc = now;
  
  	if (goal <= 0) {
  		equilibrium += goal;
  		goto work_done;
  	}
  
  	do {
  		int i, k;
  
  		for (i = rt_hash_mask, k = rover; i >= 0; i--) {
  			unsigned long tmo = expire;
  
  			k = (k + 1) & rt_hash_mask;
  			rthp = &rt_hash_table[k].chain;
22c047ccb   Eric Dumazet   [NET]: Hashed spi...
959
  			spin_lock_bh(rt_hash_lock_addr(k));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
  			while ((rth = *rthp) != NULL) {
e84f84f27   Denis V. Lunev   netns: place rt_g...
961
  				if (!rt_is_expired(rth) &&
29e75252d   Eric Dumazet   [IPV4] route cach...
962
  					!rt_may_expire(rth, tmo, expire)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
963
  					tmo >>= 1;
d8d1f30b9   Changli Gao   net-next: remove ...
964
  					rthp = &rth->dst.rt_next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
965
966
  					continue;
  				}
d8d1f30b9   Changli Gao   net-next: remove ...
967
  				*rthp = rth->dst.rt_next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
968
969
  				rt_free(rth);
  				goal--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
970
  			}
22c047ccb   Eric Dumazet   [NET]: Hashed spi...
971
  			spin_unlock_bh(rt_hash_lock_addr(k));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
  			if (goal <= 0)
  				break;
  		}
  		rover = k;
  
  		if (goal <= 0)
  			goto work_done;
  
  		/* Goal is not achieved. We stop process if:
  
  		   - if expire reduced to zero. Otherwise, expire is halfed.
  		   - if table is not full.
  		   - if we are called from interrupt.
  		   - jiffies check is just fallback/debug loop breaker.
  		     We will not spin here for long time in any case.
  		 */
  
  		RT_CACHE_STAT_INC(gc_goal_miss);
  
  		if (expire == 0)
  			break;
  
  		expire >>= 1;
  #if RT_CACHE_DEBUG >= 2
  		printk(KERN_DEBUG "expire>> %u %d %d %d
  ", expire,
  				atomic_read(&ipv4_dst_ops.entries), goal, i);
  #endif
  
  		if (atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size)
  			goto out;
  	} while (!in_softirq() && time_before_eq(jiffies, now));
  
  	if (atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size)
  		goto out;
  	if (net_ratelimit())
  		printk(KERN_WARNING "dst cache overflow
  ");
  	RT_CACHE_STAT_INC(gc_dst_overflow);
  	return 1;
  
  work_done:
  	expire += ip_rt_gc_min_interval;
  	if (expire > ip_rt_gc_timeout ||
  	    atomic_read(&ipv4_dst_ops.entries) < ipv4_dst_ops.gc_thresh)
  		expire = ip_rt_gc_timeout;
  #if RT_CACHE_DEBUG >= 2
  	printk(KERN_DEBUG "expire++ %u %d %d %d
  ", expire,
  			atomic_read(&ipv4_dst_ops.entries), goal, rover);
  #endif
  out:	return 0;
  }
983763872   Eric Dumazet   net: fix route ca...
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
  /*
   * Returns number of entries in a hash chain that have different hash_inputs
   */
  static int slow_chain_length(const struct rtable *head)
  {
  	int length = 0;
  	const struct rtable *rth = head;
  
  	while (rth) {
  		length += has_noalias(head, rth);
d8d1f30b9   Changli Gao   net-next: remove ...
1035
  		rth = rth->dst.rt_next;
983763872   Eric Dumazet   net: fix route ca...
1036
1037
1038
  	}
  	return length >> FRACT_BITS;
  }
511c3f92a   Eric Dumazet   net: skb->rtable ...
1039
  static int rt_intern_hash(unsigned hash, struct rtable *rt,
6a2bad70d   Pavel Emelyanov   ipv4: Restart rt_...
1040
  			  struct rtable **rp, struct sk_buff *skb, int ifindex)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
  {
  	struct rtable	*rth, **rthp;
  	unsigned long	now;
  	struct rtable *cand, **candp;
  	u32 		min_score;
  	int		chain_length;
  	int attempts = !in_softirq();
  
  restart:
  	chain_length = 0;
  	min_score = ~(u32)0;
  	cand = NULL;
  	candp = NULL;
  	now = jiffies;
d8d1f30b9   Changli Gao   net-next: remove ...
1055
  	if (!rt_caching(dev_net(rt->dst.dev))) {
73e42897e   Neil Horman   ipv4: fix NULL po...
1056
1057
1058
1059
1060
1061
1062
1063
  		/*
  		 * If we're not caching, just tell the caller we
  		 * were successful and don't touch the route.  The
  		 * caller hold the sole reference to the cache entry, and
  		 * it will be released when the caller is done with it.
  		 * If we drop it here, the callers have no way to resolve routes
  		 * when we're not caching.  Instead, just point *rp at rt, so
  		 * the caller gets a single use out of the route
b6280b47a   Neil Horman   ipv4 routing: Ens...
1064
1065
1066
1067
1068
1069
  		 * Note that we do rt_free on this new route entry, so that
  		 * once its refcount hits zero, we are still able to reap it
  		 * (Thanks Alexey)
  		 * Note also the rt_free uses call_rcu.  We don't actually
  		 * need rcu protection here, this is just our path to get
  		 * on the route gc list.
73e42897e   Neil Horman   ipv4: fix NULL po...
1070
  		 */
b6280b47a   Neil Horman   ipv4 routing: Ens...
1071
1072
  
  		if (rt->rt_type == RTN_UNICAST || rt->fl.iif == 0) {
d8d1f30b9   Changli Gao   net-next: remove ...
1073
  			int err = arp_bind_neighbour(&rt->dst);
b6280b47a   Neil Horman   ipv4 routing: Ens...
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
  			if (err) {
  				if (net_ratelimit())
  					printk(KERN_WARNING
  					    "Neighbour table failure & not caching routes.
  ");
  				rt_drop(rt);
  				return err;
  			}
  		}
  
  		rt_free(rt);
  		goto skip_hashing;
1080d709f   Neil Horman   net: implement em...
1086
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1087
  	rthp = &rt_hash_table[hash].chain;
22c047ccb   Eric Dumazet   [NET]: Hashed spi...
1088
  	spin_lock_bh(rt_hash_lock_addr(hash));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1089
  	while ((rth = *rthp) != NULL) {
e84f84f27   Denis V. Lunev   netns: place rt_g...
1090
  		if (rt_is_expired(rth)) {
d8d1f30b9   Changli Gao   net-next: remove ...
1091
  			*rthp = rth->dst.rt_next;
29e75252d   Eric Dumazet   [IPV4] route cach...
1092
1093
1094
  			rt_free(rth);
  			continue;
  		}
b5921910a   Denis V. Lunev   [NETNS]: Routing ...
1095
  		if (compare_keys(&rth->fl, &rt->fl) && compare_netns(rth, rt)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1096
  			/* Put it first */
d8d1f30b9   Changli Gao   net-next: remove ...
1097
  			*rthp = rth->dst.rt_next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1098
1099
1100
1101
1102
  			/*
  			 * Since lookup is lockfree, the deletion
  			 * must be visible to another weakly ordered CPU before
  			 * the insertion at the start of the hash chain.
  			 */
d8d1f30b9   Changli Gao   net-next: remove ...
1103
  			rcu_assign_pointer(rth->dst.rt_next,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1104
1105
1106
1107
1108
1109
  					   rt_hash_table[hash].chain);
  			/*
  			 * Since lookup is lockfree, the update writes
  			 * must be ordered for consistency on SMP.
  			 */
  			rcu_assign_pointer(rt_hash_table[hash].chain, rth);
d8d1f30b9   Changli Gao   net-next: remove ...
1110
  			dst_use(&rth->dst, now);
22c047ccb   Eric Dumazet   [NET]: Hashed spi...
1111
  			spin_unlock_bh(rt_hash_lock_addr(hash));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1112
1113
  
  			rt_drop(rt);
511c3f92a   Eric Dumazet   net: skb->rtable ...
1114
1115
1116
  			if (rp)
  				*rp = rth;
  			else
d8d1f30b9   Changli Gao   net-next: remove ...
1117
  				skb_dst_set(skb, &rth->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1118
1119
  			return 0;
  		}
d8d1f30b9   Changli Gao   net-next: remove ...
1120
  		if (!atomic_read(&rth->dst.__refcnt)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
  			u32 score = rt_score(rth);
  
  			if (score <= min_score) {
  				cand = rth;
  				candp = rthp;
  				min_score = score;
  			}
  		}
  
  		chain_length++;
d8d1f30b9   Changli Gao   net-next: remove ...
1131
  		rthp = &rth->dst.rt_next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
  	}
  
  	if (cand) {
  		/* ip_rt_gc_elasticity used to be average length of chain
  		 * length, when exceeded gc becomes really aggressive.
  		 *
  		 * The second limit is less certain. At the moment it allows
  		 * only 2 entries per bucket. We will see.
  		 */
  		if (chain_length > ip_rt_gc_elasticity) {
d8d1f30b9   Changli Gao   net-next: remove ...
1142
  			*candp = cand->dst.rt_next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1143
1144
  			rt_free(cand);
  		}
1080d709f   Neil Horman   net: implement em...
1145
  	} else {
983763872   Eric Dumazet   net: fix route ca...
1146
1147
  		if (chain_length > rt_chain_length_max &&
  		    slow_chain_length(rt_hash_table[hash].chain) > rt_chain_length_max) {
d8d1f30b9   Changli Gao   net-next: remove ...
1148
  			struct net *net = dev_net(rt->dst.dev);
1080d709f   Neil Horman   net: implement em...
1149
  			int num = ++net->ipv4.current_rt_cache_rebuild_count;
b35ecb5d4   Pavel Emelyanov   ipv4: Cleanup str...
1150
  			if (!rt_caching(net)) {
1080d709f   Neil Horman   net: implement em...
1151
1152
  				printk(KERN_WARNING "%s: %d rebuilds is over limit, route caching disabled
  ",
d8d1f30b9   Changli Gao   net-next: remove ...
1153
  					rt->dst.dev->name, num);
1080d709f   Neil Horman   net: implement em...
1154
  			}
b35ecb5d4   Pavel Emelyanov   ipv4: Cleanup str...
1155
  			rt_emergency_hash_rebuild(net);
6a2bad70d   Pavel Emelyanov   ipv4: Restart rt_...
1156
1157
1158
1159
1160
  			spin_unlock_bh(rt_hash_lock_addr(hash));
  
  			hash = rt_hash(rt->fl.fl4_dst, rt->fl.fl4_src,
  					ifindex, rt_genid(net));
  			goto restart;
1080d709f   Neil Horman   net: implement em...
1161
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1162
1163
1164
1165
1166
1167
  	}
  
  	/* Try to bind route to arp only if it is output
  	   route or unicast forwarding path.
  	 */
  	if (rt->rt_type == RTN_UNICAST || rt->fl.iif == 0) {
d8d1f30b9   Changli Gao   net-next: remove ...
1168
  		int err = arp_bind_neighbour(&rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1169
  		if (err) {
22c047ccb   Eric Dumazet   [NET]: Hashed spi...
1170
  			spin_unlock_bh(rt_hash_lock_addr(hash));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
  
  			if (err != -ENOBUFS) {
  				rt_drop(rt);
  				return err;
  			}
  
  			/* Neighbour tables are full and nothing
  			   can be released. Try to shrink route cache,
  			   it is most likely it holds some neighbour records.
  			 */
  			if (attempts-- > 0) {
  				int saved_elasticity = ip_rt_gc_elasticity;
  				int saved_int = ip_rt_gc_min_interval;
  				ip_rt_gc_elasticity	= 1;
  				ip_rt_gc_min_interval	= 0;
569d36452   Daniel Lezcano   [NETNS][DST] dst:...
1186
  				rt_garbage_collect(&ipv4_dst_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
  				ip_rt_gc_min_interval	= saved_int;
  				ip_rt_gc_elasticity	= saved_elasticity;
  				goto restart;
  			}
  
  			if (net_ratelimit())
  				printk(KERN_WARNING "Neighbour table overflow.
  ");
  			rt_drop(rt);
  			return -ENOBUFS;
  		}
  	}
d8d1f30b9   Changli Gao   net-next: remove ...
1199
  	rt->dst.rt_next = rt_hash_table[hash].chain;
1080d709f   Neil Horman   net: implement em...
1200

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1201
  #if RT_CACHE_DEBUG >= 2
d8d1f30b9   Changli Gao   net-next: remove ...
1202
  	if (rt->dst.rt_next) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1203
  		struct rtable *trt;
b6280b47a   Neil Horman   ipv4 routing: Ens...
1204
1205
  		printk(KERN_DEBUG "rt_cache @%02x: %pI4",
  		       hash, &rt->rt_dst);
d8d1f30b9   Changli Gao   net-next: remove ...
1206
  		for (trt = rt->dst.rt_next; trt; trt = trt->dst.rt_next)
673d57e72   Harvey Harrison   net: replace NIPQ...
1207
  			printk(" . %pI4", &trt->rt_dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1208
1209
1210
1211
  		printk("
  ");
  	}
  #endif
00269b54e   Eric Dumazet   ipv4: Add a missi...
1212
1213
1214
1215
1216
  	/*
  	 * Since lookup is lockfree, we must make sure
  	 * previous writes to rt are comitted to memory
  	 * before making rt visible to other CPUS.
  	 */
1ddbcb005   Eric Dumazet   net: fix rtable l...
1217
  	rcu_assign_pointer(rt_hash_table[hash].chain, rt);
1080d709f   Neil Horman   net: implement em...
1218

22c047ccb   Eric Dumazet   [NET]: Hashed spi...
1219
  	spin_unlock_bh(rt_hash_lock_addr(hash));
73e42897e   Neil Horman   ipv4: fix NULL po...
1220

b6280b47a   Neil Horman   ipv4 routing: Ens...
1221
  skip_hashing:
511c3f92a   Eric Dumazet   net: skb->rtable ...
1222
1223
1224
  	if (rp)
  		*rp = rt;
  	else
d8d1f30b9   Changli Gao   net-next: remove ...
1225
  		skb_dst_set(skb, &rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
  	return 0;
  }
  
  void rt_bind_peer(struct rtable *rt, int create)
  {
  	static DEFINE_SPINLOCK(rt_peer_lock);
  	struct inet_peer *peer;
  
  	peer = inet_getpeer(rt->rt_dst, create);
  
  	spin_lock_bh(&rt_peer_lock);
  	if (rt->peer == NULL) {
  		rt->peer = peer;
  		peer = NULL;
  	}
  	spin_unlock_bh(&rt_peer_lock);
  	if (peer)
  		inet_putpeer(peer);
  }
  
  /*
   * Peer allocation may fail only in serious out-of-memory conditions.  However
   * we still can generate some output.
   * Random ID selection looks a bit dangerous because we have no chances to
   * select ID being unique in a reasonable period of time.
   * But broken packet identifier may be better than no packet at all.
   */
  static void ip_select_fb_ident(struct iphdr *iph)
  {
  	static DEFINE_SPINLOCK(ip_fb_id_lock);
  	static u32 ip_fallback_id;
  	u32 salt;
  
  	spin_lock_bh(&ip_fb_id_lock);
e448515c7   Al Viro   [IPV4] net/ipv4/r...
1260
  	salt = secure_ip_id((__force __be32)ip_fallback_id ^ iph->daddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
  	iph->id = htons(salt & 0xFFFF);
  	ip_fallback_id = salt;
  	spin_unlock_bh(&ip_fb_id_lock);
  }
  
  void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more)
  {
  	struct rtable *rt = (struct rtable *) dst;
  
  	if (rt) {
  		if (rt->peer == NULL)
  			rt_bind_peer(rt, 1);
  
  		/* If peer is attached to destination, it is never detached,
  		   so that we need not to grab a lock to dereference it.
  		 */
  		if (rt->peer) {
  			iph->id = htons(inet_getid(rt->peer, more));
  			return;
  		}
  	} else
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1282
1283
  		printk(KERN_DEBUG "rt_bind_peer(0) @%p
  ",
9c2b3328f   Stephen Hemminger   [NET]: skbuff: re...
1284
  		       __builtin_return_address(0));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1285
1286
1287
  
  	ip_select_fb_ident(iph);
  }
4bc2f18ba   Eric Dumazet   net/ipv4: EXPORT_...
1288
  EXPORT_SYMBOL(__ip_select_ident);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1289
1290
1291
  
  static void rt_del(unsigned hash, struct rtable *rt)
  {
29e75252d   Eric Dumazet   [IPV4] route cach...
1292
  	struct rtable **rthp, *aux;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1293

29e75252d   Eric Dumazet   [IPV4] route cach...
1294
  	rthp = &rt_hash_table[hash].chain;
22c047ccb   Eric Dumazet   [NET]: Hashed spi...
1295
  	spin_lock_bh(rt_hash_lock_addr(hash));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1296
  	ip_rt_put(rt);
29e75252d   Eric Dumazet   [IPV4] route cach...
1297
  	while ((aux = *rthp) != NULL) {
e84f84f27   Denis V. Lunev   netns: place rt_g...
1298
  		if (aux == rt || rt_is_expired(aux)) {
d8d1f30b9   Changli Gao   net-next: remove ...
1299
  			*rthp = aux->dst.rt_next;
29e75252d   Eric Dumazet   [IPV4] route cach...
1300
1301
  			rt_free(aux);
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1302
  		}
d8d1f30b9   Changli Gao   net-next: remove ...
1303
  		rthp = &aux->dst.rt_next;
29e75252d   Eric Dumazet   [IPV4] route cach...
1304
  	}
22c047ccb   Eric Dumazet   [NET]: Hashed spi...
1305
  	spin_unlock_bh(rt_hash_lock_addr(hash));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1306
  }
ed7865a47   Eric Dumazet   ipv4: avoid two a...
1307
  /* called in rcu_read_lock() section */
f7655229c   Al Viro   [IPV4]: ip_rt_red...
1308
1309
  void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
  		    __be32 saddr, struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1310
1311
  {
  	int i, k;
ed7865a47   Eric Dumazet   ipv4: avoid two a...
1312
  	struct in_device *in_dev = __in_dev_get_rcu(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1313
  	struct rtable *rth, **rthp;
f7655229c   Al Viro   [IPV4]: ip_rt_red...
1314
  	__be32  skeys[2] = { saddr, 0 };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1315
  	int  ikeys[2] = { dev->ifindex, 0 };
8d71740c5   Tom Tucker   [NET]: Core net c...
1316
  	struct netevent_redirect netevent;
317805b8f   Denis V. Lunev   [NETNS]: Process ...
1317
  	struct net *net;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1318

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1319
1320
  	if (!in_dev)
  		return;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1321
  	net = dev_net(dev);
9d4fb27db   Joe Perches   net/ipv4: Move &&...
1322
1323
1324
  	if (new_gw == old_gw || !IN_DEV_RX_REDIRECTS(in_dev) ||
  	    ipv4_is_multicast(new_gw) || ipv4_is_lbcast(new_gw) ||
  	    ipv4_is_zeronet(new_gw))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1325
  		goto reject_redirect;
1080d709f   Neil Horman   net: implement em...
1326
1327
  	if (!rt_caching(net))
  		goto reject_redirect;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1328
1329
1330
1331
1332
1333
  	if (!IN_DEV_SHARED_MEDIA(in_dev)) {
  		if (!inet_addr_onlink(in_dev, new_gw, old_gw))
  			goto reject_redirect;
  		if (IN_DEV_SEC_REDIRECTS(in_dev) && ip_fib_check_default(new_gw, dev))
  			goto reject_redirect;
  	} else {
317805b8f   Denis V. Lunev   [NETNS]: Process ...
1334
  		if (inet_addr_type(net, new_gw) != RTN_UNICAST)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1335
1336
1337
1338
1339
  			goto reject_redirect;
  	}
  
  	for (i = 0; i < 2; i++) {
  		for (k = 0; k < 2; k++) {
b00180def   Denis V. Lunev   ipv4: pass curren...
1340
  			unsigned hash = rt_hash(daddr, skeys[i], ikeys[k],
e84f84f27   Denis V. Lunev   netns: place rt_g...
1341
  						rt_genid(net));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1342
1343
  
  			rthp=&rt_hash_table[hash].chain;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1344
1345
1346
1347
1348
  			while ((rth = rcu_dereference(*rthp)) != NULL) {
  				struct rtable *rt;
  
  				if (rth->fl.fl4_dst != daddr ||
  				    rth->fl.fl4_src != skeys[i] ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1349
  				    rth->fl.oif != ikeys[k] ||
29e75252d   Eric Dumazet   [IPV4] route cach...
1350
  				    rth->fl.iif != 0 ||
e84f84f27   Denis V. Lunev   netns: place rt_g...
1351
  				    rt_is_expired(rth) ||
d8d1f30b9   Changli Gao   net-next: remove ...
1352
1353
  				    !net_eq(dev_net(rth->dst.dev), net)) {
  					rthp = &rth->dst.rt_next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1354
1355
1356
1357
1358
  					continue;
  				}
  
  				if (rth->rt_dst != daddr ||
  				    rth->rt_src != saddr ||
d8d1f30b9   Changli Gao   net-next: remove ...
1359
  				    rth->dst.error ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1360
  				    rth->rt_gateway != old_gw ||
d8d1f30b9   Changli Gao   net-next: remove ...
1361
  				    rth->dst.dev != dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1362
  					break;
d8d1f30b9   Changli Gao   net-next: remove ...
1363
  				dst_hold(&rth->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1364
1365
1366
1367
  
  				rt = dst_alloc(&ipv4_dst_ops);
  				if (rt == NULL) {
  					ip_rt_put(rth);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1368
1369
1370
1371
1372
  					return;
  				}
  
  				/* Copy all the information. */
  				*rt = *rth;
d8d1f30b9   Changli Gao   net-next: remove ...
1373
1374
1375
1376
1377
  				rt->dst.__use		= 1;
  				atomic_set(&rt->dst.__refcnt, 1);
  				rt->dst.child		= NULL;
  				if (rt->dst.dev)
  					dev_hold(rt->dst.dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1378
1379
  				if (rt->idev)
  					in_dev_hold(rt->idev);
d8d1f30b9   Changli Gao   net-next: remove ...
1380
1381
1382
1383
1384
  				rt->dst.obsolete	= -1;
  				rt->dst.lastuse	= jiffies;
  				rt->dst.path		= &rt->dst;
  				rt->dst.neighbour	= NULL;
  				rt->dst.hh		= NULL;
def8b4faf   Alexey Dobriyan   net: reduce struc...
1385
  #ifdef CONFIG_XFRM
d8d1f30b9   Changli Gao   net-next: remove ...
1386
  				rt->dst.xfrm		= NULL;
def8b4faf   Alexey Dobriyan   net: reduce struc...
1387
  #endif
e84f84f27   Denis V. Lunev   netns: place rt_g...
1388
  				rt->rt_genid		= rt_genid(net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1389
1390
1391
1392
1393
1394
  				rt->rt_flags		|= RTCF_REDIRECTED;
  
  				/* Gateway is different ... */
  				rt->rt_gateway		= new_gw;
  
  				/* Redirect received -> path was valid */
d8d1f30b9   Changli Gao   net-next: remove ...
1395
  				dst_confirm(&rth->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1396
1397
1398
  
  				if (rt->peer)
  					atomic_inc(&rt->peer->refcnt);
d8d1f30b9   Changli Gao   net-next: remove ...
1399
1400
  				if (arp_bind_neighbour(&rt->dst) ||
  				    !(rt->dst.neighbour->nud_state &
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1401
  					    NUD_VALID)) {
d8d1f30b9   Changli Gao   net-next: remove ...
1402
1403
  					if (rt->dst.neighbour)
  						neigh_event_send(rt->dst.neighbour, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1404
1405
1406
1407
  					ip_rt_put(rth);
  					rt_drop(rt);
  					goto do_next;
  				}
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1408

d8d1f30b9   Changli Gao   net-next: remove ...
1409
1410
  				netevent.old = &rth->dst;
  				netevent.new = &rt->dst;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1411
1412
  				call_netevent_notifiers(NETEVENT_REDIRECT,
  							&netevent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1413
1414
  
  				rt_del(hash, rth);
6a2bad70d   Pavel Emelyanov   ipv4: Restart rt_...
1415
  				if (!rt_intern_hash(hash, rt, &rt, NULL, rt->fl.oif))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1416
1417
1418
  					ip_rt_put(rt);
  				goto do_next;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1419
1420
1421
1422
  		do_next:
  			;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1423
1424
1425
1426
1427
  	return;
  
  reject_redirect:
  #ifdef CONFIG_IP_ROUTE_VERBOSE
  	if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit())
673d57e72   Harvey Harrison   net: replace NIPQ...
1428
1429
1430
1431
1432
1433
  		printk(KERN_INFO "Redirect from %pI4 on %s about %pI4 ignored.
  "
  			"  Advised path = %pI4 -> %pI4
  ",
  		       &old_gw, dev->name, &new_gw,
  		       &saddr, &daddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1434
  #endif
ed7865a47   Eric Dumazet   ipv4: avoid two a...
1435
  	;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1436
1437
1438
1439
  }
  
  static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
  {
ee6b96730   Eric Dumazet   [IPV4]: Add 'rtab...
1440
  	struct rtable *rt = (struct rtable *)dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1441
1442
1443
  	struct dst_entry *ret = dst;
  
  	if (rt) {
d11a4dc18   Timo Teräs   ipv4: check rt_ge...
1444
  		if (dst->obsolete > 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1445
1446
1447
  			ip_rt_put(rt);
  			ret = NULL;
  		} else if ((rt->rt_flags & RTCF_REDIRECTED) ||
d8d1f30b9   Changli Gao   net-next: remove ...
1448
1449
  			   (rt->dst.expires &&
  			    time_after_eq(jiffies, rt->dst.expires))) {
8c7bc8408   Al Viro   [IPV4]: annotate ...
1450
  			unsigned hash = rt_hash(rt->fl.fl4_dst, rt->fl.fl4_src,
b00180def   Denis V. Lunev   ipv4: pass curren...
1451
  						rt->fl.oif,
e84f84f27   Denis V. Lunev   netns: place rt_g...
1452
  						rt_genid(dev_net(dst->dev)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1453
  #if RT_CACHE_DEBUG >= 1
673d57e72   Harvey Harrison   net: replace NIPQ...
1454
1455
1456
  			printk(KERN_DEBUG "ipv4_negative_advice: redirect to %pI4/%02x dropped
  ",
  				&rt->rt_dst, rt->fl.fl4_tos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
  #endif
  			rt_del(hash, rt);
  			ret = NULL;
  		}
  	}
  	return ret;
  }
  
  /*
   * Algorithm:
   *	1. The first ip_rt_redirect_number redirects are sent
   *	   with exponential backoff, then we stop sending them at all,
   *	   assuming that the host ignores our redirects.
   *	2. If we did not see packets requiring redirects
   *	   during ip_rt_redirect_silence, we assume that the host
   *	   forgot redirected route and start to send redirects again.
   *
   * This algorithm is much cheaper and more intelligent than dumb load limiting
   * in icmp.c.
   *
   * NOTE. Do not forget to inhibit load limiting for redirects (redundant)
   * and "frag. need" (breaks PMTU discovery) in icmp.c.
   */
  
  void ip_rt_send_redirect(struct sk_buff *skb)
  {
511c3f92a   Eric Dumazet   net: skb->rtable ...
1483
  	struct rtable *rt = skb_rtable(skb);
30038fc61   Eric Dumazet   net: ip_rt_send_r...
1484
1485
  	struct in_device *in_dev;
  	int log_martians;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1486

30038fc61   Eric Dumazet   net: ip_rt_send_r...
1487
  	rcu_read_lock();
d8d1f30b9   Changli Gao   net-next: remove ...
1488
  	in_dev = __in_dev_get_rcu(rt->dst.dev);
30038fc61   Eric Dumazet   net: ip_rt_send_r...
1489
1490
  	if (!in_dev || !IN_DEV_TX_REDIRECTS(in_dev)) {
  		rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1491
  		return;
30038fc61   Eric Dumazet   net: ip_rt_send_r...
1492
1493
1494
  	}
  	log_martians = IN_DEV_LOG_MARTIANS(in_dev);
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1495
1496
1497
1498
  
  	/* No redirected packets during ip_rt_redirect_silence;
  	 * reset the algorithm.
  	 */
d8d1f30b9   Changli Gao   net-next: remove ...
1499
1500
  	if (time_after(jiffies, rt->dst.rate_last + ip_rt_redirect_silence))
  		rt->dst.rate_tokens = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1501
1502
  
  	/* Too many ignored redirects; do not send anything
d8d1f30b9   Changli Gao   net-next: remove ...
1503
  	 * set dst.rate_last to the last seen redirected packet.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1504
  	 */
d8d1f30b9   Changli Gao   net-next: remove ...
1505
1506
  	if (rt->dst.rate_tokens >= ip_rt_redirect_number) {
  		rt->dst.rate_last = jiffies;
30038fc61   Eric Dumazet   net: ip_rt_send_r...
1507
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1508
1509
1510
1511
1512
  	}
  
  	/* Check for load limit; set rate_last to the latest sent
  	 * redirect.
  	 */
d8d1f30b9   Changli Gao   net-next: remove ...
1513
  	if (rt->dst.rate_tokens == 0 ||
14fb8a764   Li Yewang   [IPV4]: Fix BUG o...
1514
  	    time_after(jiffies,
d8d1f30b9   Changli Gao   net-next: remove ...
1515
1516
  		       (rt->dst.rate_last +
  			(ip_rt_redirect_load << rt->dst.rate_tokens)))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1517
  		icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, rt->rt_gateway);
d8d1f30b9   Changli Gao   net-next: remove ...
1518
1519
  		rt->dst.rate_last = jiffies;
  		++rt->dst.rate_tokens;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1520
  #ifdef CONFIG_IP_ROUTE_VERBOSE
30038fc61   Eric Dumazet   net: ip_rt_send_r...
1521
  		if (log_martians &&
d8d1f30b9   Changli Gao   net-next: remove ...
1522
  		    rt->dst.rate_tokens == ip_rt_redirect_number &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1523
  		    net_ratelimit())
673d57e72   Harvey Harrison   net: replace NIPQ...
1524
1525
1526
1527
  			printk(KERN_WARNING "host %pI4/if%d ignores redirects for %pI4 to %pI4.
  ",
  				&rt->rt_src, rt->rt_iif,
  				&rt->rt_dst, &rt->rt_gateway);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1528
1529
  #endif
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1530
1531
1532
1533
  }
  
  static int ip_error(struct sk_buff *skb)
  {
511c3f92a   Eric Dumazet   net: skb->rtable ...
1534
  	struct rtable *rt = skb_rtable(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1535
1536
  	unsigned long now;
  	int code;
d8d1f30b9   Changli Gao   net-next: remove ...
1537
  	switch (rt->dst.error) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1538
1539
1540
1541
1542
1543
1544
1545
  		case EINVAL:
  		default:
  			goto out;
  		case EHOSTUNREACH:
  			code = ICMP_HOST_UNREACH;
  			break;
  		case ENETUNREACH:
  			code = ICMP_NET_UNREACH;
d8d1f30b9   Changli Gao   net-next: remove ...
1546
  			IP_INC_STATS_BH(dev_net(rt->dst.dev),
7c73a6faf   Pavel Emelyanov   mib: add net to I...
1547
  					IPSTATS_MIB_INNOROUTES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1548
1549
1550
1551
1552
1553
1554
  			break;
  		case EACCES:
  			code = ICMP_PKT_FILTERED;
  			break;
  	}
  
  	now = jiffies;
d8d1f30b9   Changli Gao   net-next: remove ...
1555
1556
1557
1558
1559
1560
  	rt->dst.rate_tokens += now - rt->dst.rate_last;
  	if (rt->dst.rate_tokens > ip_rt_error_burst)
  		rt->dst.rate_tokens = ip_rt_error_burst;
  	rt->dst.rate_last = now;
  	if (rt->dst.rate_tokens >= ip_rt_error_cost) {
  		rt->dst.rate_tokens -= ip_rt_error_cost;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1561
1562
1563
1564
1565
  		icmp_send(skb, ICMP_DEST_UNREACH, code, 0);
  	}
  
  out:	kfree_skb(skb);
  	return 0;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1566
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1567
1568
1569
1570
1571
  
  /*
   *	The last two values are not from the RFC but
   *	are needed for AMPRnet AX.25 paths.
   */
9b5b5cff9   Arjan van de Ven   [NET]: Add const ...
1572
  static const unsigned short mtu_plateau[] =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1573
  {32000, 17914, 8166, 4352, 2002, 1492, 576, 296, 216, 128 };
5969f71d5   Stephen Hemminger   IPV4: route inlin...
1574
  static inline unsigned short guess_mtu(unsigned short old_mtu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1575
1576
  {
  	int i;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1577

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1578
1579
1580
1581
1582
  	for (i = 0; i < ARRAY_SIZE(mtu_plateau); i++)
  		if (old_mtu > mtu_plateau[i])
  			return mtu_plateau[i];
  	return 68;
  }
b5921910a   Denis V. Lunev   [NETNS]: Routing ...
1583
  unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph,
0010e4657   Timo Teras   ipv4: Update MTU ...
1584
1585
  				 unsigned short new_mtu,
  				 struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1586
  {
0010e4657   Timo Teras   ipv4: Update MTU ...
1587
  	int i, k;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1588
1589
  	unsigned short old_mtu = ntohs(iph->tot_len);
  	struct rtable *rth;
0010e4657   Timo Teras   ipv4: Update MTU ...
1590
  	int  ikeys[2] = { dev->ifindex, 0 };
e448515c7   Al Viro   [IPV4] net/ipv4/r...
1591
1592
  	__be32  skeys[2] = { iph->saddr, 0, };
  	__be32  daddr = iph->daddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1593
  	unsigned short est_mtu = 0;
0010e4657   Timo Teras   ipv4: Update MTU ...
1594
1595
  	for (k = 0; k < 2; k++) {
  		for (i = 0; i < 2; i++) {
b00180def   Denis V. Lunev   ipv4: pass curren...
1596
  			unsigned hash = rt_hash(daddr, skeys[i], ikeys[k],
e84f84f27   Denis V. Lunev   netns: place rt_g...
1597
  						rt_genid(net));
0010e4657   Timo Teras   ipv4: Update MTU ...
1598
1599
1600
  
  			rcu_read_lock();
  			for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
d8d1f30b9   Changli Gao   net-next: remove ...
1601
  			     rth = rcu_dereference(rth->dst.rt_next)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1602
  				unsigned short mtu = new_mtu;
0010e4657   Timo Teras   ipv4: Update MTU ...
1603
1604
1605
1606
1607
1608
  				if (rth->fl.fl4_dst != daddr ||
  				    rth->fl.fl4_src != skeys[i] ||
  				    rth->rt_dst != daddr ||
  				    rth->rt_src != iph->saddr ||
  				    rth->fl.oif != ikeys[k] ||
  				    rth->fl.iif != 0 ||
d8d1f30b9   Changli Gao   net-next: remove ...
1609
1610
  				    dst_metric_locked(&rth->dst, RTAX_MTU) ||
  				    !net_eq(dev_net(rth->dst.dev), net) ||
6c3b8fc61   Hugh Dickins   netns: fix ip_rt_...
1611
  				    rt_is_expired(rth))
0010e4657   Timo Teras   ipv4: Update MTU ...
1612
  					continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1613
1614
1615
1616
  				if (new_mtu < 68 || new_mtu >= old_mtu) {
  
  					/* BSD 4.2 compatibility hack :-( */
  					if (mtu == 0 &&
d8d1f30b9   Changli Gao   net-next: remove ...
1617
  					    old_mtu >= dst_mtu(&rth->dst) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1618
1619
1620
1621
1622
  					    old_mtu >= 68 + (iph->ihl << 2))
  						old_mtu -= iph->ihl << 2;
  
  					mtu = guess_mtu(old_mtu);
  				}
d8d1f30b9   Changli Gao   net-next: remove ...
1623
1624
1625
  				if (mtu <= dst_mtu(&rth->dst)) {
  					if (mtu < dst_mtu(&rth->dst)) {
  						dst_confirm(&rth->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1626
1627
  						if (mtu < ip_rt_min_pmtu) {
  							mtu = ip_rt_min_pmtu;
d8d1f30b9   Changli Gao   net-next: remove ...
1628
  							rth->dst.metrics[RTAX_LOCK-1] |=
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1629
1630
  								(1 << RTAX_MTU);
  						}
d8d1f30b9   Changli Gao   net-next: remove ...
1631
1632
  						rth->dst.metrics[RTAX_MTU-1] = mtu;
  						dst_set_expires(&rth->dst,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1633
1634
1635
1636
1637
  							ip_rt_mtu_expires);
  					}
  					est_mtu = mtu;
  				}
  			}
0010e4657   Timo Teras   ipv4: Update MTU ...
1638
  			rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1639
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1640
1641
1642
1643
1644
1645
  	}
  	return est_mtu ? : new_mtu;
  }
  
  static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
  {
6d273f8d0   Rami Rosen   ipv4: replace dst...
1646
  	if (dst_mtu(dst) > mtu && mtu >= 68 &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1647
1648
1649
1650
1651
1652
1653
  	    !(dst_metric_locked(dst, RTAX_MTU))) {
  		if (mtu < ip_rt_min_pmtu) {
  			mtu = ip_rt_min_pmtu;
  			dst->metrics[RTAX_LOCK-1] |= (1 << RTAX_MTU);
  		}
  		dst->metrics[RTAX_MTU-1] = mtu;
  		dst_set_expires(dst, ip_rt_mtu_expires);
8d71740c5   Tom Tucker   [NET]: Core net c...
1654
  		call_netevent_notifiers(NETEVENT_PMTU_UPDATE, dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1655
1656
1657
1658
1659
  	}
  }
  
  static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie)
  {
d11a4dc18   Timo Teräs   ipv4: check rt_ge...
1660
1661
1662
  	if (rt_is_expired((struct rtable *)dst))
  		return NULL;
  	return dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
  }
  
  static void ipv4_dst_destroy(struct dst_entry *dst)
  {
  	struct rtable *rt = (struct rtable *) dst;
  	struct inet_peer *peer = rt->peer;
  	struct in_device *idev = rt->idev;
  
  	if (peer) {
  		rt->peer = NULL;
  		inet_putpeer(peer);
  	}
  
  	if (idev) {
  		rt->idev = NULL;
  		in_dev_put(idev);
  	}
  }
  
  static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
  			    int how)
  {
  	struct rtable *rt = (struct rtable *) dst;
  	struct in_device *idev = rt->idev;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1687
  	if (dev != dev_net(dev)->loopback_dev && idev && idev->dev == dev) {
5a3e55d68   Denis V. Lunev   [NET]: Multiple n...
1688
  		struct in_device *loopback_idev =
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1689
  			in_dev_get(dev_net(dev)->loopback_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
  		if (loopback_idev) {
  			rt->idev = loopback_idev;
  			in_dev_put(idev);
  		}
  	}
  }
  
  static void ipv4_link_failure(struct sk_buff *skb)
  {
  	struct rtable *rt;
  
  	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
511c3f92a   Eric Dumazet   net: skb->rtable ...
1702
  	rt = skb_rtable(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1703
  	if (rt)
d8d1f30b9   Changli Gao   net-next: remove ...
1704
  		dst_set_expires(&rt->dst, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1705
1706
1707
1708
  }
  
  static int ip_rt_bug(struct sk_buff *skb)
  {
673d57e72   Harvey Harrison   net: replace NIPQ...
1709
1710
1711
  	printk(KERN_DEBUG "ip_rt_bug: %pI4 -> %pI4, %s
  ",
  		&ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
  		skb->dev ? skb->dev->name : "?");
  	kfree_skb(skb);
  	return 0;
  }
  
  /*
     We do not cache source address of outgoing interface,
     because it is used only by IP RR, TS and SRR options,
     so that it out of fast path.
  
     BTW remember: "addr" is allowed to be not aligned
     in IP options!
   */
  
  void ip_rt_get_source(u8 *addr, struct rtable *rt)
  {
a61ced5d1   Al Viro   [IPV4]: inet_sele...
1728
  	__be32 src;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1729
1730
1731
1732
  	struct fib_result res;
  
  	if (rt->fl.iif == 0)
  		src = rt->rt_src;
d8d1f30b9   Changli Gao   net-next: remove ...
1733
  	else if (fib_lookup(dev_net(rt->dst.dev), &rt->fl, &res) == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1734
1735
1736
  		src = FIB_RES_PREFSRC(res);
  		fib_res_put(&res);
  	} else
d8d1f30b9   Changli Gao   net-next: remove ...
1737
  		src = inet_select_addr(rt->dst.dev, rt->rt_gateway,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1738
1739
1740
1741
1742
1743
1744
  					RT_SCOPE_UNIVERSE);
  	memcpy(addr, &src, 4);
  }
  
  #ifdef CONFIG_NET_CLS_ROUTE
  static void set_class_tag(struct rtable *rt, u32 tag)
  {
d8d1f30b9   Changli Gao   net-next: remove ...
1745
1746
1747
1748
  	if (!(rt->dst.tclassid & 0xFFFF))
  		rt->dst.tclassid |= tag & 0xFFFF;
  	if (!(rt->dst.tclassid & 0xFFFF0000))
  		rt->dst.tclassid |= tag & 0xFFFF0000;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
  }
  #endif
  
  static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag)
  {
  	struct fib_info *fi = res->fi;
  
  	if (fi) {
  		if (FIB_RES_GW(*res) &&
  		    FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
  			rt->rt_gateway = FIB_RES_GW(*res);
d8d1f30b9   Changli Gao   net-next: remove ...
1760
1761
  		memcpy(rt->dst.metrics, fi->fib_metrics,
  		       sizeof(rt->dst.metrics));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1762
  		if (fi->fib_mtu == 0) {
d8d1f30b9   Changli Gao   net-next: remove ...
1763
1764
  			rt->dst.metrics[RTAX_MTU-1] = rt->dst.dev->mtu;
  			if (dst_metric_locked(&rt->dst, RTAX_MTU) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1765
  			    rt->rt_gateway != rt->rt_dst &&
d8d1f30b9   Changli Gao   net-next: remove ...
1766
1767
  			    rt->dst.dev->mtu > 576)
  				rt->dst.metrics[RTAX_MTU-1] = 576;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1768
1769
  		}
  #ifdef CONFIG_NET_CLS_ROUTE
d8d1f30b9   Changli Gao   net-next: remove ...
1770
  		rt->dst.tclassid = FIB_RES_NH(*res).nh_tclassid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1771
1772
  #endif
  	} else
d8d1f30b9   Changli Gao   net-next: remove ...
1773
1774
1775
1776
1777
1778
1779
1780
  		rt->dst.metrics[RTAX_MTU-1]= rt->dst.dev->mtu;
  
  	if (dst_metric(&rt->dst, RTAX_HOPLIMIT) == 0)
  		rt->dst.metrics[RTAX_HOPLIMIT-1] = sysctl_ip_default_ttl;
  	if (dst_mtu(&rt->dst) > IP_MAX_MTU)
  		rt->dst.metrics[RTAX_MTU-1] = IP_MAX_MTU;
  	if (dst_metric(&rt->dst, RTAX_ADVMSS) == 0)
  		rt->dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, rt->dst.dev->mtu - 40,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1781
  				       ip_rt_min_advmss);
d8d1f30b9   Changli Gao   net-next: remove ...
1782
1783
  	if (dst_metric(&rt->dst, RTAX_ADVMSS) > 65535 - 40)
  		rt->dst.metrics[RTAX_ADVMSS-1] = 65535 - 40;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1784
1785
1786
1787
1788
1789
1790
  
  #ifdef CONFIG_NET_CLS_ROUTE
  #ifdef CONFIG_IP_MULTIPLE_TABLES
  	set_class_tag(rt, fib_rules_tclass(res));
  #endif
  	set_class_tag(rt, itag);
  #endif
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1791
  	rt->rt_type = res->type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1792
  }
96d362202   Eric Dumazet   ipv4: RCU convers...
1793
  /* called in rcu_read_lock() section */
9e12bb22e   Al Viro   [IPV4]: ip_route_...
1794
  static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1795
1796
  				u8 tos, struct net_device *dev, int our)
  {
96d362202   Eric Dumazet   ipv4: RCU convers...
1797
  	unsigned int hash;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1798
  	struct rtable *rth;
a61ced5d1   Al Viro   [IPV4]: inet_sele...
1799
  	__be32 spec_dst;
96d362202   Eric Dumazet   ipv4: RCU convers...
1800
  	struct in_device *in_dev = __in_dev_get_rcu(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1801
  	u32 itag = 0;
b5f7e7554   Eric Dumazet   ipv4: add LINUX_M...
1802
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1803
1804
1805
1806
1807
  
  	/* Primary sanity checks. */
  
  	if (in_dev == NULL)
  		return -EINVAL;
1e637c74b   Jan Engelhardt   [IPV4]: Enable us...
1808
  	if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr) ||
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
1809
  	    ipv4_is_loopback(saddr) || skb->protocol != htons(ETH_P_IP))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1810
  		goto e_inval;
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
1811
1812
  	if (ipv4_is_zeronet(saddr)) {
  		if (!ipv4_is_local_multicast(daddr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1813
1814
  			goto e_inval;
  		spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
b5f7e7554   Eric Dumazet   ipv4: add LINUX_M...
1815
1816
1817
1818
1819
1820
  	} else {
  		err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst,
  					  &itag, 0);
  		if (err < 0)
  			goto e_err;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1821
1822
1823
  	rth = dst_alloc(&ipv4_dst_ops);
  	if (!rth)
  		goto e_nobufs;
d8d1f30b9   Changli Gao   net-next: remove ...
1824
1825
  	rth->dst.output = ip_rt_bug;
  	rth->dst.obsolete = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1826

d8d1f30b9   Changli Gao   net-next: remove ...
1827
1828
  	atomic_set(&rth->dst.__refcnt, 1);
  	rth->dst.flags= DST_HOST;
42f811b8b   Herbert Xu   [IPV4]: Convert I...
1829
  	if (IN_DEV_CONF_GET(in_dev, NOPOLICY))
d8d1f30b9   Changli Gao   net-next: remove ...
1830
  		rth->dst.flags |= DST_NOPOLICY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1831
1832
1833
  	rth->fl.fl4_dst	= daddr;
  	rth->rt_dst	= daddr;
  	rth->fl.fl4_tos	= tos;
47dcf0cb1   Thomas Graf   [NET]: Rethink ma...
1834
  	rth->fl.mark    = skb->mark;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1835
1836
1837
  	rth->fl.fl4_src	= saddr;
  	rth->rt_src	= saddr;
  #ifdef CONFIG_NET_CLS_ROUTE
d8d1f30b9   Changli Gao   net-next: remove ...
1838
  	rth->dst.tclassid = itag;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1839
1840
1841
  #endif
  	rth->rt_iif	=
  	rth->fl.iif	= dev->ifindex;
d8d1f30b9   Changli Gao   net-next: remove ...
1842
1843
1844
  	rth->dst.dev	= init_net.loopback_dev;
  	dev_hold(rth->dst.dev);
  	rth->idev	= in_dev_get(rth->dst.dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1845
1846
1847
  	rth->fl.oif	= 0;
  	rth->rt_gateway	= daddr;
  	rth->rt_spec_dst= spec_dst;
e84f84f27   Denis V. Lunev   netns: place rt_g...
1848
  	rth->rt_genid	= rt_genid(dev_net(dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1849
  	rth->rt_flags	= RTCF_MULTICAST;
29e75252d   Eric Dumazet   [IPV4] route cach...
1850
  	rth->rt_type	= RTN_MULTICAST;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1851
  	if (our) {
d8d1f30b9   Changli Gao   net-next: remove ...
1852
  		rth->dst.input= ip_local_deliver;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1853
1854
1855
1856
  		rth->rt_flags |= RTCF_LOCAL;
  	}
  
  #ifdef CONFIG_IP_MROUTE
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
1857
  	if (!ipv4_is_local_multicast(daddr) && IN_DEV_MFORWARD(in_dev))
d8d1f30b9   Changli Gao   net-next: remove ...
1858
  		rth->dst.input = ip_mr_input;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1859
1860
  #endif
  	RT_CACHE_STAT_INC(in_slow_mc);
e84f84f27   Denis V. Lunev   netns: place rt_g...
1861
  	hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev)));
6a2bad70d   Pavel Emelyanov   ipv4: Restart rt_...
1862
  	return rt_intern_hash(hash, rth, NULL, skb, dev->ifindex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1863
1864
  
  e_nobufs:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1865
  	return -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1866
  e_inval:
96d362202   Eric Dumazet   ipv4: RCU convers...
1867
  	return -EINVAL;
b5f7e7554   Eric Dumazet   ipv4: add LINUX_M...
1868
  e_err:
b5f7e7554   Eric Dumazet   ipv4: add LINUX_M...
1869
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1870
1871
1872
1873
1874
1875
  }
  
  
  static void ip_handle_martian_source(struct net_device *dev,
  				     struct in_device *in_dev,
  				     struct sk_buff *skb,
9e12bb22e   Al Viro   [IPV4]: ip_route_...
1876
1877
  				     __be32 daddr,
  				     __be32 saddr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1878
1879
1880
1881
1882
1883
1884
1885
  {
  	RT_CACHE_STAT_INC(in_martian_src);
  #ifdef CONFIG_IP_ROUTE_VERBOSE
  	if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) {
  		/*
  		 *	RFC1812 recommendation, if source is martian,
  		 *	the only hint is MAC header.
  		 */
673d57e72   Harvey Harrison   net: replace NIPQ...
1886
1887
1888
  		printk(KERN_WARNING "martian source %pI4 from %pI4, on dev %s
  ",
  			&daddr, &saddr, dev->name);
98e399f82   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1889
  		if (dev->hard_header_len && skb_mac_header_was_set(skb)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1890
  			int i;
98e399f82   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1891
  			const unsigned char *p = skb_mac_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
  			printk(KERN_WARNING "ll header: ");
  			for (i = 0; i < dev->hard_header_len; i++, p++) {
  				printk("%02x", *p);
  				if (i < (dev->hard_header_len - 1))
  					printk(":");
  			}
  			printk("
  ");
  		}
  	}
  #endif
  }
473602284   Eric Dumazet   ipv4: RCU changes...
1904
  /* called in rcu_read_lock() section */
5969f71d5   Stephen Hemminger   IPV4: route inlin...
1905
1906
1907
1908
1909
  static int __mkroute_input(struct sk_buff *skb,
  			   struct fib_result *res,
  			   struct in_device *in_dev,
  			   __be32 daddr, __be32 saddr, u32 tos,
  			   struct rtable **result)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1910
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1911
1912
1913
  	struct rtable *rth;
  	int err;
  	struct in_device *out_dev;
473602284   Eric Dumazet   ipv4: RCU changes...
1914
  	unsigned int flags = 0;
d9c9df8c9   Al Viro   [IPV4]: fib_valid...
1915
1916
  	__be32 spec_dst;
  	u32 itag;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1917
1918
  
  	/* get a working reference to the output device */
473602284   Eric Dumazet   ipv4: RCU changes...
1919
  	out_dev = __in_dev_get_rcu(FIB_RES_DEV(*res));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1920
1921
1922
1923
1924
1925
1926
  	if (out_dev == NULL) {
  		if (net_ratelimit())
  			printk(KERN_CRIT "Bug in ip_route_input" \
  			       "_slow(). Please, report
  ");
  		return -EINVAL;
  	}
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1927
  	err = fib_validate_source(saddr, daddr, tos, FIB_RES_OIF(*res),
b0c110ca8   jamal   net: Fix RPF to w...
1928
  				  in_dev->dev, &spec_dst, &itag, skb->mark);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1929
  	if (err < 0) {
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1930
  		ip_handle_martian_source(in_dev->dev, in_dev, skb, daddr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1931
  					 saddr);
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1932

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1933
1934
1935
1936
1937
  		goto cleanup;
  	}
  
  	if (err)
  		flags |= RTCF_DIRECTSRC;
51b77cae0   Thomas Graf   route: Mark unuse...
1938
  	if (out_dev == in_dev && err &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1939
1940
1941
1942
1943
1944
1945
  	    (IN_DEV_SHARED_MEDIA(out_dev) ||
  	     inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res))))
  		flags |= RTCF_DOREDIRECT;
  
  	if (skb->protocol != htons(ETH_P_IP)) {
  		/* Not IP (i.e. ARP). Do not create route, if it is
  		 * invalid for proxy arp. DNAT routes are always valid.
65324144b   Jesper Dangaard Brouer   net: RFC3069, pri...
1946
1947
1948
1949
  		 *
  		 * Proxy arp feature have been extended to allow, ARP
  		 * replies back to the same interface, to support
  		 * Private VLAN switch technologies. See arp.c.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1950
  		 */
65324144b   Jesper Dangaard Brouer   net: RFC3069, pri...
1951
1952
  		if (out_dev == in_dev &&
  		    IN_DEV_PROXY_ARP_PVLAN(in_dev) == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
  			err = -EINVAL;
  			goto cleanup;
  		}
  	}
  
  
  	rth = dst_alloc(&ipv4_dst_ops);
  	if (!rth) {
  		err = -ENOBUFS;
  		goto cleanup;
  	}
d8d1f30b9   Changli Gao   net-next: remove ...
1964
1965
  	atomic_set(&rth->dst.__refcnt, 1);
  	rth->dst.flags= DST_HOST;
42f811b8b   Herbert Xu   [IPV4]: Convert I...
1966
  	if (IN_DEV_CONF_GET(in_dev, NOPOLICY))
d8d1f30b9   Changli Gao   net-next: remove ...
1967
  		rth->dst.flags |= DST_NOPOLICY;
42f811b8b   Herbert Xu   [IPV4]: Convert I...
1968
  	if (IN_DEV_CONF_GET(out_dev, NOXFRM))
d8d1f30b9   Changli Gao   net-next: remove ...
1969
  		rth->dst.flags |= DST_NOXFRM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1970
1971
1972
  	rth->fl.fl4_dst	= daddr;
  	rth->rt_dst	= daddr;
  	rth->fl.fl4_tos	= tos;
47dcf0cb1   Thomas Graf   [NET]: Rethink ma...
1973
  	rth->fl.mark    = skb->mark;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1974
1975
1976
1977
1978
  	rth->fl.fl4_src	= saddr;
  	rth->rt_src	= saddr;
  	rth->rt_gateway	= daddr;
  	rth->rt_iif 	=
  		rth->fl.iif	= in_dev->dev->ifindex;
d8d1f30b9   Changli Gao   net-next: remove ...
1979
1980
1981
  	rth->dst.dev	= (out_dev)->dev;
  	dev_hold(rth->dst.dev);
  	rth->idev	= in_dev_get(rth->dst.dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1982
1983
  	rth->fl.oif 	= 0;
  	rth->rt_spec_dst= spec_dst;
d8d1f30b9   Changli Gao   net-next: remove ...
1984
1985
1986
1987
  	rth->dst.obsolete = -1;
  	rth->dst.input = ip_forward;
  	rth->dst.output = ip_output;
  	rth->rt_genid = rt_genid(dev_net(rth->dst.dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1988
1989
1990
1991
1992
1993
1994
1995
  
  	rt_set_nexthop(rth, res, itag);
  
  	rth->rt_flags = flags;
  
  	*result = rth;
  	err = 0;
   cleanup:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1996
  	return err;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1997
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1998

5969f71d5   Stephen Hemminger   IPV4: route inlin...
1999
2000
2001
2002
2003
  static int ip_mkroute_input(struct sk_buff *skb,
  			    struct fib_result *res,
  			    const struct flowi *fl,
  			    struct in_device *in_dev,
  			    __be32 daddr, __be32 saddr, u32 tos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2004
  {
7abaa27c1   Chuck Short   [IPV4]: Fix route...
2005
  	struct rtable* rth = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
  	int err;
  	unsigned hash;
  
  #ifdef CONFIG_IP_ROUTE_MULTIPATH
  	if (res->fi && res->fi->fib_nhs > 1 && fl->oif == 0)
  		fib_select_multipath(fl, res);
  #endif
  
  	/* create a routing cache entry */
  	err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos, &rth);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2018
2019
  
  	/* put it into the cache */
e84f84f27   Denis V. Lunev   netns: place rt_g...
2020
  	hash = rt_hash(daddr, saddr, fl->iif,
d8d1f30b9   Changli Gao   net-next: remove ...
2021
  		       rt_genid(dev_net(rth->dst.dev)));
6a2bad70d   Pavel Emelyanov   ipv4: Restart rt_...
2022
  	return rt_intern_hash(hash, rth, NULL, skb, fl->iif);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2023
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2024
2025
2026
2027
2028
2029
2030
2031
2032
  /*
   *	NOTE. We drop all the packets that has local source
   *	addresses, because every properly looped back packet
   *	must have correct destination already attached by output routine.
   *
   *	Such approach solves two big problems:
   *	1. Not simplex devices are handled properly.
   *	2. IP spoofing attempts are filtered with 100% of guarantee.
   */
9e12bb22e   Al Viro   [IPV4]: ip_route_...
2033
  static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2034
2035
2036
  			       u8 tos, struct net_device *dev)
  {
  	struct fib_result res;
96d362202   Eric Dumazet   ipv4: RCU convers...
2037
  	struct in_device *in_dev = __in_dev_get_rcu(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2038
2039
2040
2041
2042
  	struct flowi fl = { .nl_u = { .ip4_u =
  				      { .daddr = daddr,
  					.saddr = saddr,
  					.tos = tos,
  					.scope = RT_SCOPE_UNIVERSE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2043
  				      } },
47dcf0cb1   Thomas Graf   [NET]: Rethink ma...
2044
  			    .mark = skb->mark,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2045
2046
2047
2048
2049
  			    .iif = dev->ifindex };
  	unsigned	flags = 0;
  	u32		itag = 0;
  	struct rtable * rth;
  	unsigned	hash;
9e12bb22e   Al Viro   [IPV4]: ip_route_...
2050
  	__be32		spec_dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2051
2052
  	int		err = -EINVAL;
  	int		free_res = 0;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2053
  	struct net    * net = dev_net(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2054
2055
2056
2057
2058
2059
2060
2061
2062
  
  	/* IP on this device is disabled. */
  
  	if (!in_dev)
  		goto out;
  
  	/* Check for the most weird martians, which can be not detected
  	   by fib_lookup.
  	 */
1e637c74b   Jan Engelhardt   [IPV4]: Enable us...
2063
  	if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr) ||
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
2064
  	    ipv4_is_loopback(saddr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2065
  		goto martian_source;
e448515c7   Al Viro   [IPV4] net/ipv4/r...
2066
  	if (daddr == htonl(0xFFFFFFFF) || (saddr == 0 && daddr == 0))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2067
2068
2069
2070
2071
  		goto brd_input;
  
  	/* Accept zero addresses only to limited broadcast;
  	 * I even do not know to fix it or not. Waiting for complains :-)
  	 */
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
2072
  	if (ipv4_is_zeronet(saddr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2073
  		goto martian_source;
1e637c74b   Jan Engelhardt   [IPV4]: Enable us...
2074
  	if (ipv4_is_lbcast(daddr) || ipv4_is_zeronet(daddr) ||
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
2075
  	    ipv4_is_loopback(daddr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2076
2077
2078
2079
2080
  		goto martian_destination;
  
  	/*
  	 *	Now we are ready to route packet.
  	 */
84a885f44   Denis V. Lunev   [NETNS]: Pass cor...
2081
  	if ((err = fib_lookup(net, &fl, &res)) != 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2082
  		if (!IN_DEV_FORWARD(in_dev))
2c2910a40   Dietmar Eggemann   [IPV4]: Snmpv2 Mi...
2083
  			goto e_hostunreach;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
  		goto no_route;
  	}
  	free_res = 1;
  
  	RT_CACHE_STAT_INC(in_slow_tot);
  
  	if (res.type == RTN_BROADCAST)
  		goto brd_input;
  
  	if (res.type == RTN_LOCAL) {
b5f7e7554   Eric Dumazet   ipv4: add LINUX_M...
2094
  		err = fib_validate_source(saddr, daddr, tos,
84a885f44   Denis V. Lunev   [NETNS]: Pass cor...
2095
  					     net->loopback_dev->ifindex,
b0c110ca8   jamal   net: Fix RPF to w...
2096
  					     dev, &spec_dst, &itag, skb->mark);
b5f7e7554   Eric Dumazet   ipv4: add LINUX_M...
2097
2098
2099
  		if (err < 0)
  			goto martian_source_keep_err;
  		if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2100
2101
2102
2103
2104
2105
  			flags |= RTCF_DIRECTSRC;
  		spec_dst = daddr;
  		goto local_input;
  	}
  
  	if (!IN_DEV_FORWARD(in_dev))
2c2910a40   Dietmar Eggemann   [IPV4]: Snmpv2 Mi...
2106
  		goto e_hostunreach;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2107
2108
2109
2110
  	if (res.type != RTN_UNICAST)
  		goto martian_destination;
  
  	err = ip_mkroute_input(skb, &res, &fl, in_dev, daddr, saddr, tos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2111
  done:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2112
2113
2114
2115
2116
2117
2118
  	if (free_res)
  		fib_res_put(&res);
  out:	return err;
  
  brd_input:
  	if (skb->protocol != htons(ETH_P_IP))
  		goto e_inval;
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
2119
  	if (ipv4_is_zeronet(saddr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2120
2121
2122
  		spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
  	else {
  		err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst,
b0c110ca8   jamal   net: Fix RPF to w...
2123
  					  &itag, skb->mark);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2124
  		if (err < 0)
b5f7e7554   Eric Dumazet   ipv4: add LINUX_M...
2125
  			goto martian_source_keep_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
  		if (err)
  			flags |= RTCF_DIRECTSRC;
  	}
  	flags |= RTCF_BROADCAST;
  	res.type = RTN_BROADCAST;
  	RT_CACHE_STAT_INC(in_brd);
  
  local_input:
  	rth = dst_alloc(&ipv4_dst_ops);
  	if (!rth)
  		goto e_nobufs;
d8d1f30b9   Changli Gao   net-next: remove ...
2137
2138
  	rth->dst.output= ip_rt_bug;
  	rth->dst.obsolete = -1;
e84f84f27   Denis V. Lunev   netns: place rt_g...
2139
  	rth->rt_genid = rt_genid(net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2140

d8d1f30b9   Changli Gao   net-next: remove ...
2141
2142
  	atomic_set(&rth->dst.__refcnt, 1);
  	rth->dst.flags= DST_HOST;
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2143
  	if (IN_DEV_CONF_GET(in_dev, NOPOLICY))
d8d1f30b9   Changli Gao   net-next: remove ...
2144
  		rth->dst.flags |= DST_NOPOLICY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2145
2146
2147
  	rth->fl.fl4_dst	= daddr;
  	rth->rt_dst	= daddr;
  	rth->fl.fl4_tos	= tos;
47dcf0cb1   Thomas Graf   [NET]: Rethink ma...
2148
  	rth->fl.mark    = skb->mark;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2149
2150
2151
  	rth->fl.fl4_src	= saddr;
  	rth->rt_src	= saddr;
  #ifdef CONFIG_NET_CLS_ROUTE
d8d1f30b9   Changli Gao   net-next: remove ...
2152
  	rth->dst.tclassid = itag;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2153
2154
2155
  #endif
  	rth->rt_iif	=
  	rth->fl.iif	= dev->ifindex;
d8d1f30b9   Changli Gao   net-next: remove ...
2156
2157
2158
  	rth->dst.dev	= net->loopback_dev;
  	dev_hold(rth->dst.dev);
  	rth->idev	= in_dev_get(rth->dst.dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2159
2160
  	rth->rt_gateway	= daddr;
  	rth->rt_spec_dst= spec_dst;
d8d1f30b9   Changli Gao   net-next: remove ...
2161
  	rth->dst.input= ip_local_deliver;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2162
2163
  	rth->rt_flags 	= flags|RTCF_LOCAL;
  	if (res.type == RTN_UNREACHABLE) {
d8d1f30b9   Changli Gao   net-next: remove ...
2164
2165
  		rth->dst.input= ip_error;
  		rth->dst.error= -err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2166
2167
2168
  		rth->rt_flags 	&= ~RTCF_LOCAL;
  	}
  	rth->rt_type	= res.type;
e84f84f27   Denis V. Lunev   netns: place rt_g...
2169
  	hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net));
6a2bad70d   Pavel Emelyanov   ipv4: Restart rt_...
2170
  	err = rt_intern_hash(hash, rth, NULL, skb, fl.iif);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2171
2172
2173
2174
2175
2176
  	goto done;
  
  no_route:
  	RT_CACHE_STAT_INC(in_no_route);
  	spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
  	res.type = RTN_UNREACHABLE;
7f53878dc   Mitsuru Chinen   [IPv4]: Reply net...
2177
2178
  	if (err == -ESRCH)
  		err = -ENETUNREACH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2179
2180
2181
2182
2183
2184
2185
2186
2187
  	goto local_input;
  
  	/*
  	 *	Do not cache martian addresses: they should be logged (RFC1812)
  	 */
  martian_destination:
  	RT_CACHE_STAT_INC(in_martian_dst);
  #ifdef CONFIG_IP_ROUTE_VERBOSE
  	if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit())
673d57e72   Harvey Harrison   net: replace NIPQ...
2188
2189
2190
  		printk(KERN_WARNING "martian destination %pI4 from %pI4, dev %s
  ",
  			&daddr, &saddr, dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2191
  #endif
2c2910a40   Dietmar Eggemann   [IPV4]: Snmpv2 Mi...
2192
2193
  
  e_hostunreach:
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2194
2195
  	err = -EHOSTUNREACH;
  	goto done;
2c2910a40   Dietmar Eggemann   [IPV4]: Snmpv2 Mi...
2196

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2197
2198
2199
2200
2201
2202
2203
2204
2205
  e_inval:
  	err = -EINVAL;
  	goto done;
  
  e_nobufs:
  	err = -ENOBUFS;
  	goto done;
  
  martian_source:
b5f7e7554   Eric Dumazet   ipv4: add LINUX_M...
2206
2207
  	err = -EINVAL;
  martian_source_keep_err:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2208
  	ip_handle_martian_source(dev, in_dev, skb, daddr, saddr);
b5f7e7554   Eric Dumazet   ipv4: add LINUX_M...
2209
  	goto done;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2210
  }
407eadd99   Eric Dumazet   net: implements i...
2211
2212
  int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr,
  			   u8 tos, struct net_device *dev, bool noref)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2213
2214
2215
2216
  {
  	struct rtable * rth;
  	unsigned	hash;
  	int iif = dev->ifindex;
b5921910a   Denis V. Lunev   [NETNS]: Routing ...
2217
  	struct net *net;
96d362202   Eric Dumazet   ipv4: RCU convers...
2218
  	int res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2219

c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2220
  	net = dev_net(dev);
1080d709f   Neil Horman   net: implement em...
2221

96d362202   Eric Dumazet   ipv4: RCU convers...
2222
  	rcu_read_lock();
1080d709f   Neil Horman   net: implement em...
2223
2224
  	if (!rt_caching(net))
  		goto skip_cache;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2225
  	tos &= IPTOS_RT_MASK;
e84f84f27   Denis V. Lunev   netns: place rt_g...
2226
  	hash = rt_hash(daddr, saddr, iif, rt_genid(net));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2227

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2228
  	for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
d8d1f30b9   Changli Gao   net-next: remove ...
2229
  	     rth = rcu_dereference(rth->dst.rt_next)) {
0eae88f31   Eric Dumazet   net: Fix various ...
2230
2231
  		if ((((__force u32)rth->fl.fl4_dst ^ (__force u32)daddr) |
  		     ((__force u32)rth->fl.fl4_src ^ (__force u32)saddr) |
c0b8c32b1   Stephen Hemminger   IPV4: use xor rat...
2232
2233
2234
  		     (rth->fl.iif ^ iif) |
  		     rth->fl.oif |
  		     (rth->fl.fl4_tos ^ tos)) == 0 &&
47dcf0cb1   Thomas Graf   [NET]: Rethink ma...
2235
  		    rth->fl.mark == skb->mark &&
d8d1f30b9   Changli Gao   net-next: remove ...
2236
  		    net_eq(dev_net(rth->dst.dev), net) &&
e84f84f27   Denis V. Lunev   netns: place rt_g...
2237
  		    !rt_is_expired(rth)) {
407eadd99   Eric Dumazet   net: implements i...
2238
  			if (noref) {
d8d1f30b9   Changli Gao   net-next: remove ...
2239
2240
  				dst_use_noref(&rth->dst, jiffies);
  				skb_dst_set_noref(skb, &rth->dst);
407eadd99   Eric Dumazet   net: implements i...
2241
  			} else {
d8d1f30b9   Changli Gao   net-next: remove ...
2242
2243
  				dst_use(&rth->dst, jiffies);
  				skb_dst_set(skb, &rth->dst);
407eadd99   Eric Dumazet   net: implements i...
2244
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2245
2246
  			RT_CACHE_STAT_INC(in_hit);
  			rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2247
2248
2249
2250
  			return 0;
  		}
  		RT_CACHE_STAT_INC(in_hlist_search);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2251

1080d709f   Neil Horman   net: implement em...
2252
  skip_cache:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
  	/* Multicast recognition logic is moved from route cache to here.
  	   The problem was that too many Ethernet cards have broken/missing
  	   hardware multicast filters :-( As result the host on multicasting
  	   network acquires a lot of useless route cache entries, sort of
  	   SDR messages from all the world. Now we try to get rid of them.
  	   Really, provided software IP multicast filter is organized
  	   reasonably (at least, hashed), it does not result in a slowdown
  	   comparing with route cache reject entries.
  	   Note, that multicast routers are not affected, because
  	   route cache entry is created eventually.
  	 */
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
2264
  	if (ipv4_is_multicast(daddr)) {
96d362202   Eric Dumazet   ipv4: RCU convers...
2265
  		struct in_device *in_dev = __in_dev_get_rcu(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2266

96d362202   Eric Dumazet   ipv4: RCU convers...
2267
  		if (in_dev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2268
  			int our = ip_check_mc(in_dev, daddr, saddr,
96d362202   Eric Dumazet   ipv4: RCU convers...
2269
  					      ip_hdr(skb)->protocol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2270
2271
  			if (our
  #ifdef CONFIG_IP_MROUTE
9d4fb27db   Joe Perches   net/ipv4: Move &&...
2272
2273
2274
  				||
  			    (!ipv4_is_local_multicast(daddr) &&
  			     IN_DEV_MFORWARD(in_dev))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2275
  #endif
9d4fb27db   Joe Perches   net/ipv4: Move &&...
2276
  			   ) {
96d362202   Eric Dumazet   ipv4: RCU convers...
2277
2278
  				int res = ip_route_input_mc(skb, daddr, saddr,
  							    tos, dev, our);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2279
  				rcu_read_unlock();
96d362202   Eric Dumazet   ipv4: RCU convers...
2280
  				return res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2281
2282
2283
2284
2285
  			}
  		}
  		rcu_read_unlock();
  		return -EINVAL;
  	}
96d362202   Eric Dumazet   ipv4: RCU convers...
2286
2287
2288
  	res = ip_route_input_slow(skb, daddr, saddr, tos, dev);
  	rcu_read_unlock();
  	return res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2289
  }
407eadd99   Eric Dumazet   net: implements i...
2290
  EXPORT_SYMBOL(ip_route_input_common);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2291

5969f71d5   Stephen Hemminger   IPV4: route inlin...
2292
2293
2294
2295
2296
2297
  static int __mkroute_output(struct rtable **result,
  			    struct fib_result *res,
  			    const struct flowi *fl,
  			    const struct flowi *oldflp,
  			    struct net_device *dev_out,
  			    unsigned flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2298
2299
2300
2301
2302
  {
  	struct rtable *rth;
  	struct in_device *in_dev;
  	u32 tos = RT_FL_TOS(oldflp);
  	int err = 0;
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
2303
  	if (ipv4_is_loopback(fl->fl4_src) && !(dev_out->flags&IFF_LOOPBACK))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2304
  		return -EINVAL;
e448515c7   Al Viro   [IPV4] net/ipv4/r...
2305
  	if (fl->fl4_dst == htonl(0xFFFFFFFF))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2306
  		res->type = RTN_BROADCAST;
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
2307
  	else if (ipv4_is_multicast(fl->fl4_dst))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2308
  		res->type = RTN_MULTICAST;
1e637c74b   Jan Engelhardt   [IPV4]: Enable us...
2309
  	else if (ipv4_is_lbcast(fl->fl4_dst) || ipv4_is_zeronet(fl->fl4_dst))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
  		return -EINVAL;
  
  	if (dev_out->flags & IFF_LOOPBACK)
  		flags |= RTCF_LOCAL;
  
  	/* get work reference to inet device */
  	in_dev = in_dev_get(dev_out);
  	if (!in_dev)
  		return -EINVAL;
  
  	if (res->type == RTN_BROADCAST) {
  		flags |= RTCF_BROADCAST | RTCF_LOCAL;
  		if (res->fi) {
  			fib_info_put(res->fi);
  			res->fi = NULL;
  		}
  	} else if (res->type == RTN_MULTICAST) {
  		flags |= RTCF_MULTICAST|RTCF_LOCAL;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2328
  		if (!ip_check_mc(in_dev, oldflp->fl4_dst, oldflp->fl4_src,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
  				 oldflp->proto))
  			flags &= ~RTCF_LOCAL;
  		/* If multicast route do not exist use
  		   default one, but do not gateway in this case.
  		   Yes, it is hack.
  		 */
  		if (res->fi && res->prefixlen < 4) {
  			fib_info_put(res->fi);
  			res->fi = NULL;
  		}
  	}
  
  
  	rth = dst_alloc(&ipv4_dst_ops);
  	if (!rth) {
  		err = -ENOBUFS;
  		goto cleanup;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2346
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2347

d8d1f30b9   Changli Gao   net-next: remove ...
2348
2349
  	atomic_set(&rth->dst.__refcnt, 1);
  	rth->dst.flags= DST_HOST;
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2350
  	if (IN_DEV_CONF_GET(in_dev, NOXFRM))
d8d1f30b9   Changli Gao   net-next: remove ...
2351
  		rth->dst.flags |= DST_NOXFRM;
42f811b8b   Herbert Xu   [IPV4]: Convert I...
2352
  	if (IN_DEV_CONF_GET(in_dev, NOPOLICY))
d8d1f30b9   Changli Gao   net-next: remove ...
2353
  		rth->dst.flags |= DST_NOPOLICY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2354
2355
2356
2357
2358
  
  	rth->fl.fl4_dst	= oldflp->fl4_dst;
  	rth->fl.fl4_tos	= tos;
  	rth->fl.fl4_src	= oldflp->fl4_src;
  	rth->fl.oif	= oldflp->oif;
47dcf0cb1   Thomas Graf   [NET]: Rethink ma...
2359
  	rth->fl.mark    = oldflp->mark;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2360
2361
2362
  	rth->rt_dst	= fl->fl4_dst;
  	rth->rt_src	= fl->fl4_src;
  	rth->rt_iif	= oldflp->oif ? : dev_out->ifindex;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2363
  	/* get references to the devices that are to be hold by the routing
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2364
  	   cache entry */
d8d1f30b9   Changli Gao   net-next: remove ...
2365
  	rth->dst.dev	= dev_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2366
2367
2368
2369
  	dev_hold(dev_out);
  	rth->idev	= in_dev_get(dev_out);
  	rth->rt_gateway = fl->fl4_dst;
  	rth->rt_spec_dst= fl->fl4_src;
d8d1f30b9   Changli Gao   net-next: remove ...
2370
2371
  	rth->dst.output=ip_output;
  	rth->dst.obsolete = -1;
e84f84f27   Denis V. Lunev   netns: place rt_g...
2372
  	rth->rt_genid = rt_genid(dev_net(dev_out));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2373
2374
2375
2376
  
  	RT_CACHE_STAT_INC(out_slow_tot);
  
  	if (flags & RTCF_LOCAL) {
d8d1f30b9   Changli Gao   net-next: remove ...
2377
  		rth->dst.input = ip_local_deliver;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2378
2379
2380
2381
  		rth->rt_spec_dst = fl->fl4_dst;
  	}
  	if (flags & (RTCF_BROADCAST | RTCF_MULTICAST)) {
  		rth->rt_spec_dst = fl->fl4_src;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2382
  		if (flags & RTCF_LOCAL &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2383
  		    !(dev_out->flags & IFF_LOOPBACK)) {
d8d1f30b9   Changli Gao   net-next: remove ...
2384
  			rth->dst.output = ip_mc_output;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2385
2386
2387
2388
2389
  			RT_CACHE_STAT_INC(out_slow_mc);
  		}
  #ifdef CONFIG_IP_MROUTE
  		if (res->type == RTN_MULTICAST) {
  			if (IN_DEV_MFORWARD(in_dev) &&
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
2390
  			    !ipv4_is_local_multicast(oldflp->fl4_dst)) {
d8d1f30b9   Changli Gao   net-next: remove ...
2391
2392
  				rth->dst.input = ip_mr_input;
  				rth->dst.output = ip_mc_output;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
  			}
  		}
  #endif
  	}
  
  	rt_set_nexthop(rth, res, 0);
  
  	rth->rt_flags = flags;
  
  	*result = rth;
   cleanup:
  	/* release work reference to inet device */
  	in_dev_put(in_dev);
  
  	return err;
  }
5969f71d5   Stephen Hemminger   IPV4: route inlin...
2409
2410
2411
2412
2413
2414
  static int ip_mkroute_output(struct rtable **rp,
  			     struct fib_result *res,
  			     const struct flowi *fl,
  			     const struct flowi *oldflp,
  			     struct net_device *dev_out,
  			     unsigned flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2415
  {
7abaa27c1   Chuck Short   [IPV4]: Fix route...
2416
  	struct rtable *rth = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2417
2418
2419
  	int err = __mkroute_output(&rth, res, fl, oldflp, dev_out, flags);
  	unsigned hash;
  	if (err == 0) {
b00180def   Denis V. Lunev   ipv4: pass curren...
2420
  		hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif,
e84f84f27   Denis V. Lunev   netns: place rt_g...
2421
  			       rt_genid(dev_net(dev_out)));
6a2bad70d   Pavel Emelyanov   ipv4: Restart rt_...
2422
  		err = rt_intern_hash(hash, rth, rp, NULL, oldflp->oif);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2423
  	}
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2424

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2425
2426
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2427
2428
2429
  /*
   * Major route resolver routine.
   */
b40afd0e5   Denis V. Lunev   [NETNS]: Add name...
2430
2431
  static int ip_route_output_slow(struct net *net, struct rtable **rp,
  				const struct flowi *oldflp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2432
2433
2434
2435
2436
2437
2438
2439
2440
  {
  	u32 tos	= RT_FL_TOS(oldflp);
  	struct flowi fl = { .nl_u = { .ip4_u =
  				      { .daddr = oldflp->fl4_dst,
  					.saddr = oldflp->fl4_src,
  					.tos = tos & IPTOS_RT_MASK,
  					.scope = ((tos & RTO_ONLINK) ?
  						  RT_SCOPE_LINK :
  						  RT_SCOPE_UNIVERSE),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2441
  				      } },
47dcf0cb1   Thomas Graf   [NET]: Rethink ma...
2442
  			    .mark = oldflp->mark,
b40afd0e5   Denis V. Lunev   [NETNS]: Add name...
2443
  			    .iif = net->loopback_dev->ifindex,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
  			    .oif = oldflp->oif };
  	struct fib_result res;
  	unsigned flags = 0;
  	struct net_device *dev_out = NULL;
  	int free_res = 0;
  	int err;
  
  
  	res.fi		= NULL;
  #ifdef CONFIG_IP_MULTIPLE_TABLES
  	res.r		= NULL;
  #endif
  
  	if (oldflp->fl4_src) {
  		err = -EINVAL;
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
2459
  		if (ipv4_is_multicast(oldflp->fl4_src) ||
1e637c74b   Jan Engelhardt   [IPV4]: Enable us...
2460
  		    ipv4_is_lbcast(oldflp->fl4_src) ||
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
2461
  		    ipv4_is_zeronet(oldflp->fl4_src))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2462
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2463
2464
  		/* I removed check for oif == dev_out->oif here.
  		   It was wrong for two reasons:
1ab352768   Denis V. Lunev   [NETNS]: Add name...
2465
2466
  		   1. ip_dev_find(net, saddr) can return wrong iface, if saddr
  		      is assigned to multiple interfaces.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2467
2468
2469
  		   2. Moreover, we are allowed to send packets with saddr
  		      of another iface. --ANK
  		 */
9d4fb27db   Joe Perches   net/ipv4: Move &&...
2470
2471
2472
  		if (oldflp->oif == 0 &&
  		    (ipv4_is_multicast(oldflp->fl4_dst) ||
  		     oldflp->fl4_dst == htonl(0xFFFFFFFF))) {
a210d01ae   Julian Anastasov   ipv4: Loosen sour...
2473
2474
2475
2476
  			/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
  			dev_out = ip_dev_find(net, oldflp->fl4_src);
  			if (dev_out == NULL)
  				goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
  			/* Special hack: user can direct multicasts
  			   and limited broadcast via necessary interface
  			   without fiddling with IP_MULTICAST_IF or IP_PKTINFO.
  			   This hack is not just for fun, it allows
  			   vic,vat and friends to work.
  			   They bind socket to loopback, set ttl to zero
  			   and expect that it will work.
  			   From the viewpoint of routing cache they are broken,
  			   because we are not allowed to build multicast path
  			   with loopback source addr (look, routing cache
  			   cannot know, that ttl is zero, so that packet
  			   will not leave this host and route is valid).
  			   Luckily, this hack is good workaround.
  			 */
  
  			fl.oif = dev_out->ifindex;
  			goto make_route;
  		}
a210d01ae   Julian Anastasov   ipv4: Loosen sour...
2495
2496
2497
2498
2499
2500
  
  		if (!(oldflp->flags & FLOWI_FLAG_ANYSRC)) {
  			/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
  			dev_out = ip_dev_find(net, oldflp->fl4_src);
  			if (dev_out == NULL)
  				goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2501
  			dev_put(dev_out);
a210d01ae   Julian Anastasov   ipv4: Loosen sour...
2502
2503
  			dev_out = NULL;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2504
2505
2506
2507
  	}
  
  
  	if (oldflp->oif) {
b40afd0e5   Denis V. Lunev   [NETNS]: Add name...
2508
  		dev_out = dev_get_by_index(net, oldflp->oif);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2509
2510
2511
  		err = -ENODEV;
  		if (dev_out == NULL)
  			goto out;
e5ed63991   Herbert Xu   [IPV4]: Replace _...
2512
2513
2514
  
  		/* RACE: Check return value of inet_select_addr instead. */
  		if (__in_dev_get_rtnl(dev_out) == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2515
2516
2517
  			dev_put(dev_out);
  			goto out;	/* Wrong error code */
  		}
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
2518
2519
  		if (ipv4_is_local_multicast(oldflp->fl4_dst) ||
  		    oldflp->fl4_dst == htonl(0xFFFFFFFF)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2520
2521
2522
2523
2524
2525
  			if (!fl.fl4_src)
  				fl.fl4_src = inet_select_addr(dev_out, 0,
  							      RT_SCOPE_LINK);
  			goto make_route;
  		}
  		if (!fl.fl4_src) {
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
2526
  			if (ipv4_is_multicast(oldflp->fl4_dst))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
  				fl.fl4_src = inet_select_addr(dev_out, 0,
  							      fl.fl4_scope);
  			else if (!oldflp->fl4_dst)
  				fl.fl4_src = inet_select_addr(dev_out, 0,
  							      RT_SCOPE_HOST);
  		}
  	}
  
  	if (!fl.fl4_dst) {
  		fl.fl4_dst = fl.fl4_src;
  		if (!fl.fl4_dst)
  			fl.fl4_dst = fl.fl4_src = htonl(INADDR_LOOPBACK);
  		if (dev_out)
  			dev_put(dev_out);
b40afd0e5   Denis V. Lunev   [NETNS]: Add name...
2541
  		dev_out = net->loopback_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2542
  		dev_hold(dev_out);
b40afd0e5   Denis V. Lunev   [NETNS]: Add name...
2543
  		fl.oif = net->loopback_dev->ifindex;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2544
2545
2546
2547
  		res.type = RTN_LOCAL;
  		flags |= RTCF_LOCAL;
  		goto make_route;
  	}
b40afd0e5   Denis V. Lunev   [NETNS]: Add name...
2548
  	if (fib_lookup(net, &fl, &res)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
  		res.fi = NULL;
  		if (oldflp->oif) {
  			/* Apparently, routing tables are wrong. Assume,
  			   that the destination is on link.
  
  			   WHY? DW.
  			   Because we are allowed to send to iface
  			   even if it has NO routes and NO assigned
  			   addresses. When oif is specified, routing
  			   tables are looked up with only one purpose:
  			   to catch if destination is gatewayed, rather than
  			   direct. Moreover, if MSG_DONTROUTE is set,
  			   we send packet, ignoring both routing tables
  			   and ifaddr state. --ANK
  
  
  			   We could make it even if oif is unknown,
  			   likely IPv6, but we do not.
  			 */
  
  			if (fl.fl4_src == 0)
  				fl.fl4_src = inet_select_addr(dev_out, 0,
  							      RT_SCOPE_LINK);
  			res.type = RTN_UNICAST;
  			goto make_route;
  		}
  		if (dev_out)
  			dev_put(dev_out);
  		err = -ENETUNREACH;
  		goto out;
  	}
  	free_res = 1;
  
  	if (res.type == RTN_LOCAL) {
  		if (!fl.fl4_src)
  			fl.fl4_src = fl.fl4_dst;
  		if (dev_out)
  			dev_put(dev_out);
b40afd0e5   Denis V. Lunev   [NETNS]: Add name...
2587
  		dev_out = net->loopback_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
  		dev_hold(dev_out);
  		fl.oif = dev_out->ifindex;
  		if (res.fi)
  			fib_info_put(res.fi);
  		res.fi = NULL;
  		flags |= RTCF_LOCAL;
  		goto make_route;
  	}
  
  #ifdef CONFIG_IP_ROUTE_MULTIPATH
  	if (res.fi->fib_nhs > 1 && fl.oif == 0)
  		fib_select_multipath(&fl, &res);
  	else
  #endif
  	if (!res.prefixlen && res.type == RTN_UNICAST && !fl.oif)
b40afd0e5   Denis V. Lunev   [NETNS]: Add name...
2603
  		fib_select_default(net, &fl, &res);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
  
  	if (!fl.fl4_src)
  		fl.fl4_src = FIB_RES_PREFSRC(res);
  
  	if (dev_out)
  		dev_put(dev_out);
  	dev_out = FIB_RES_DEV(res);
  	dev_hold(dev_out);
  	fl.oif = dev_out->ifindex;
  
  
  make_route:
  	err = ip_mkroute_output(rp, &res, &fl, oldflp, dev_out, flags);
  
  
  	if (free_res)
  		fib_res_put(&res);
  	if (dev_out)
  		dev_put(dev_out);
  out:	return err;
  }
611c183eb   Denis V. Lunev   [NETNS]: Add name...
2625
2626
  int __ip_route_output_key(struct net *net, struct rtable **rp,
  			  const struct flowi *flp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2627
2628
2629
  {
  	unsigned hash;
  	struct rtable *rth;
1080d709f   Neil Horman   net: implement em...
2630
2631
  	if (!rt_caching(net))
  		goto slow_output;
e84f84f27   Denis V. Lunev   netns: place rt_g...
2632
  	hash = rt_hash(flp->fl4_dst, flp->fl4_src, flp->oif, rt_genid(net));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2633
2634
  
  	rcu_read_lock_bh();
a898def29   Paul E. McKenney   net: Add checking...
2635
  	for (rth = rcu_dereference_bh(rt_hash_table[hash].chain); rth;
d8d1f30b9   Changli Gao   net-next: remove ...
2636
  		rth = rcu_dereference_bh(rth->dst.rt_next)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2637
2638
2639
2640
  		if (rth->fl.fl4_dst == flp->fl4_dst &&
  		    rth->fl.fl4_src == flp->fl4_src &&
  		    rth->fl.iif == 0 &&
  		    rth->fl.oif == flp->oif &&
47dcf0cb1   Thomas Graf   [NET]: Rethink ma...
2641
  		    rth->fl.mark == flp->mark &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2642
  		    !((rth->fl.fl4_tos ^ flp->fl4_tos) &
b5921910a   Denis V. Lunev   [NETNS]: Routing ...
2643
  			    (IPTOS_RT_MASK | RTO_ONLINK)) &&
d8d1f30b9   Changli Gao   net-next: remove ...
2644
  		    net_eq(dev_net(rth->dst.dev), net) &&
e84f84f27   Denis V. Lunev   netns: place rt_g...
2645
  		    !rt_is_expired(rth)) {
d8d1f30b9   Changli Gao   net-next: remove ...
2646
  			dst_use(&rth->dst, jiffies);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2647
2648
2649
2650
2651
2652
2653
2654
  			RT_CACHE_STAT_INC(out_hit);
  			rcu_read_unlock_bh();
  			*rp = rth;
  			return 0;
  		}
  		RT_CACHE_STAT_INC(out_hlist_search);
  	}
  	rcu_read_unlock_bh();
1080d709f   Neil Horman   net: implement em...
2655
  slow_output:
611c183eb   Denis V. Lunev   [NETNS]: Add name...
2656
  	return ip_route_output_slow(net, rp, flp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2657
  }
d8c97a945   Arnaldo Carvalho de Melo   [NET]: Export sym...
2658
  EXPORT_SYMBOL_GPL(__ip_route_output_key);
14e50e57a   David S. Miller   [XFRM]: Allow pac...
2659
2660
2661
2662
2663
2664
  static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
  {
  }
  
  static struct dst_ops ipv4_dst_blackhole_ops = {
  	.family			=	AF_INET,
09640e636   Harvey Harrison   net: replace uses...
2665
  	.protocol		=	cpu_to_be16(ETH_P_IP),
14e50e57a   David S. Miller   [XFRM]: Allow pac...
2666
2667
2668
  	.destroy		=	ipv4_dst_destroy,
  	.check			=	ipv4_dst_check,
  	.update_pmtu		=	ipv4_rt_blackhole_update_pmtu,
e24229705   Eric Dumazet   [NET]: should exp...
2669
  	.entries		=	ATOMIC_INIT(0),
14e50e57a   David S. Miller   [XFRM]: Allow pac...
2670
  };
e84f84f27   Denis V. Lunev   netns: place rt_g...
2671
  static int ipv4_dst_blackhole(struct net *net, struct rtable **rp, struct flowi *flp)
14e50e57a   David S. Miller   [XFRM]: Allow pac...
2672
2673
2674
2675
2676
2677
  {
  	struct rtable *ort = *rp;
  	struct rtable *rt = (struct rtable *)
  		dst_alloc(&ipv4_dst_blackhole_ops);
  
  	if (rt) {
d8d1f30b9   Changli Gao   net-next: remove ...
2678
  		struct dst_entry *new = &rt->dst;
14e50e57a   David S. Miller   [XFRM]: Allow pac...
2679
2680
2681
  
  		atomic_set(&new->__refcnt, 1);
  		new->__use = 1;
352e512c3   Herbert Xu   [NET]: Eliminate ...
2682
2683
  		new->input = dst_discard;
  		new->output = dst_discard;
d8d1f30b9   Changli Gao   net-next: remove ...
2684
  		memcpy(new->metrics, ort->dst.metrics, RTAX_MAX*sizeof(u32));
14e50e57a   David S. Miller   [XFRM]: Allow pac...
2685

d8d1f30b9   Changli Gao   net-next: remove ...
2686
  		new->dev = ort->dst.dev;
14e50e57a   David S. Miller   [XFRM]: Allow pac...
2687
2688
2689
2690
2691
2692
2693
2694
  		if (new->dev)
  			dev_hold(new->dev);
  
  		rt->fl = ort->fl;
  
  		rt->idev = ort->idev;
  		if (rt->idev)
  			in_dev_hold(rt->idev);
e84f84f27   Denis V. Lunev   netns: place rt_g...
2695
  		rt->rt_genid = rt_genid(net);
14e50e57a   David S. Miller   [XFRM]: Allow pac...
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
  		rt->rt_flags = ort->rt_flags;
  		rt->rt_type = ort->rt_type;
  		rt->rt_dst = ort->rt_dst;
  		rt->rt_src = ort->rt_src;
  		rt->rt_iif = ort->rt_iif;
  		rt->rt_gateway = ort->rt_gateway;
  		rt->rt_spec_dst = ort->rt_spec_dst;
  		rt->peer = ort->peer;
  		if (rt->peer)
  			atomic_inc(&rt->peer->refcnt);
  
  		dst_free(new);
  	}
d8d1f30b9   Changli Gao   net-next: remove ...
2709
  	dst_release(&(*rp)->dst);
14e50e57a   David S. Miller   [XFRM]: Allow pac...
2710
2711
2712
  	*rp = rt;
  	return (rt ? 0 : -ENOMEM);
  }
f1b050bf7   Denis V. Lunev   [NETNS]: Add name...
2713
2714
  int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp,
  			 struct sock *sk, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2715
2716
  {
  	int err;
f1b050bf7   Denis V. Lunev   [NETNS]: Add name...
2717
  	if ((err = __ip_route_output_key(net, rp, flp)) != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2718
2719
2720
2721
2722
2723
2724
  		return err;
  
  	if (flp->proto) {
  		if (!flp->fl4_src)
  			flp->fl4_src = (*rp)->rt_src;
  		if (!flp->fl4_dst)
  			flp->fl4_dst = (*rp)->rt_dst;
52479b623   Alexey Dobriyan   netns xfrm: looku...
2725
  		err = __xfrm_lookup(net, (struct dst_entry **)rp, flp, sk,
bb72845e6   Herbert Xu   [IPSEC]: Make cal...
2726
  				    flags ? XFRM_LOOKUP_WAIT : 0);
14e50e57a   David S. Miller   [XFRM]: Allow pac...
2727
  		if (err == -EREMOTE)
e84f84f27   Denis V. Lunev   netns: place rt_g...
2728
  			err = ipv4_dst_blackhole(net, rp, flp);
14e50e57a   David S. Miller   [XFRM]: Allow pac...
2729
2730
  
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2731
2732
2733
2734
  	}
  
  	return 0;
  }
d8c97a945   Arnaldo Carvalho de Melo   [NET]: Export sym...
2735
  EXPORT_SYMBOL_GPL(ip_route_output_flow);
f206351a5   Denis V. Lunev   [NETNS]: Add name...
2736
  int ip_route_output_key(struct net *net, struct rtable **rp, struct flowi *flp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2737
  {
f206351a5   Denis V. Lunev   [NETNS]: Add name...
2738
  	return ip_route_output_flow(net, rp, flp, NULL, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2739
  }
4bc2f18ba   Eric Dumazet   net/ipv4: EXPORT_...
2740
  EXPORT_SYMBOL(ip_route_output_key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2741

4feb88e5c   Benjamin Thery   netns: ipmr: enab...
2742
2743
  static int rt_fill_info(struct net *net,
  			struct sk_buff *skb, u32 pid, u32 seq, int event,
b6544c0b4   Jamal Hadi Salim   [NETLINK]: Correc...
2744
  			int nowait, unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2745
  {
511c3f92a   Eric Dumazet   net: skb->rtable ...
2746
  	struct rtable *rt = skb_rtable(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2747
  	struct rtmsg *r;
be403ea18   Thomas Graf   [IPv4]: Convert F...
2748
  	struct nlmsghdr *nlh;
e3703b3de   Thomas Graf   [RTNETLINK]: Add ...
2749
2750
  	long expires;
  	u32 id = 0, ts = 0, tsage = 0, error;
be403ea18   Thomas Graf   [IPv4]: Convert F...
2751
2752
2753
  
  	nlh = nlmsg_put(skb, pid, seq, event, sizeof(*r), flags);
  	if (nlh == NULL)
26932566a   Patrick McHardy   [NETLINK]: Don't ...
2754
  		return -EMSGSIZE;
be403ea18   Thomas Graf   [IPv4]: Convert F...
2755
2756
  
  	r = nlmsg_data(nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2757
2758
2759
2760
2761
  	r->rtm_family	 = AF_INET;
  	r->rtm_dst_len	= 32;
  	r->rtm_src_len	= 0;
  	r->rtm_tos	= rt->fl.fl4_tos;
  	r->rtm_table	= RT_TABLE_MAIN;
be403ea18   Thomas Graf   [IPv4]: Convert F...
2762
  	NLA_PUT_U32(skb, RTA_TABLE, RT_TABLE_MAIN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2763
2764
2765
2766
2767
2768
  	r->rtm_type	= rt->rt_type;
  	r->rtm_scope	= RT_SCOPE_UNIVERSE;
  	r->rtm_protocol = RTPROT_UNSPEC;
  	r->rtm_flags	= (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED;
  	if (rt->rt_flags & RTCF_NOTIFY)
  		r->rtm_flags |= RTM_F_NOTIFY;
be403ea18   Thomas Graf   [IPv4]: Convert F...
2769

17fb2c643   Al Viro   [IPV4]: RTA_{DST,...
2770
  	NLA_PUT_BE32(skb, RTA_DST, rt->rt_dst);
be403ea18   Thomas Graf   [IPv4]: Convert F...
2771

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2772
2773
  	if (rt->fl.fl4_src) {
  		r->rtm_src_len = 32;
17fb2c643   Al Viro   [IPV4]: RTA_{DST,...
2774
  		NLA_PUT_BE32(skb, RTA_SRC, rt->fl.fl4_src);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2775
  	}
d8d1f30b9   Changli Gao   net-next: remove ...
2776
2777
  	if (rt->dst.dev)
  		NLA_PUT_U32(skb, RTA_OIF, rt->dst.dev->ifindex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2778
  #ifdef CONFIG_NET_CLS_ROUTE
d8d1f30b9   Changli Gao   net-next: remove ...
2779
2780
  	if (rt->dst.tclassid)
  		NLA_PUT_U32(skb, RTA_FLOW, rt->dst.tclassid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2781
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2782
  	if (rt->fl.iif)
17fb2c643   Al Viro   [IPV4]: RTA_{DST,...
2783
  		NLA_PUT_BE32(skb, RTA_PREFSRC, rt->rt_spec_dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2784
  	else if (rt->rt_src != rt->fl.fl4_src)
17fb2c643   Al Viro   [IPV4]: RTA_{DST,...
2785
  		NLA_PUT_BE32(skb, RTA_PREFSRC, rt->rt_src);
be403ea18   Thomas Graf   [IPv4]: Convert F...
2786

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2787
  	if (rt->rt_dst != rt->rt_gateway)
17fb2c643   Al Viro   [IPV4]: RTA_{DST,...
2788
  		NLA_PUT_BE32(skb, RTA_GATEWAY, rt->rt_gateway);
be403ea18   Thomas Graf   [IPv4]: Convert F...
2789

d8d1f30b9   Changli Gao   net-next: remove ...
2790
  	if (rtnetlink_put_metrics(skb, rt->dst.metrics) < 0)
be403ea18   Thomas Graf   [IPv4]: Convert F...
2791
  		goto nla_put_failure;
963bfeeee   Eric Dumazet   net: RTA_MARK add...
2792
2793
  	if (rt->fl.mark)
  		NLA_PUT_BE32(skb, RTA_MARK, rt->fl.mark);
d8d1f30b9   Changli Gao   net-next: remove ...
2794
2795
  	error = rt->dst.error;
  	expires = rt->dst.expires ? rt->dst.expires - jiffies : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2796
  	if (rt->peer) {
317fe0e6c   Eric Dumazet   inetpeer: restore...
2797
  		inet_peer_refcheck(rt->peer);
2c1409a0a   Eric Dumazet   inetpeer: Optimiz...
2798
  		id = atomic_read(&rt->peer->ip_id_count) & 0xffff;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2799
  		if (rt->peer->tcp_ts_stamp) {
e3703b3de   Thomas Graf   [RTNETLINK]: Add ...
2800
  			ts = rt->peer->tcp_ts;
9d729f72d   James Morris   [NET]: Convert xt...
2801
  			tsage = get_seconds() - rt->peer->tcp_ts_stamp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2802
2803
  		}
  	}
be403ea18   Thomas Graf   [IPv4]: Convert F...
2804

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2805
2806
  	if (rt->fl.iif) {
  #ifdef CONFIG_IP_MROUTE
e448515c7   Al Viro   [IPV4] net/ipv4/r...
2807
  		__be32 dst = rt->rt_dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2808

f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
2809
  		if (ipv4_is_multicast(dst) && !ipv4_is_local_multicast(dst) &&
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
2810
2811
  		    IPV4_DEVCONF_ALL(net, MC_FORWARDING)) {
  			int err = ipmr_get_route(net, skb, r, nowait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2812
2813
2814
2815
  			if (err <= 0) {
  				if (!nowait) {
  					if (err == 0)
  						return 0;
be403ea18   Thomas Graf   [IPv4]: Convert F...
2816
  					goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2817
2818
  				} else {
  					if (err == -EMSGSIZE)
be403ea18   Thomas Graf   [IPv4]: Convert F...
2819
  						goto nla_put_failure;
e3703b3de   Thomas Graf   [RTNETLINK]: Add ...
2820
  					error = err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2821
2822
2823
2824
  				}
  			}
  		} else
  #endif
be403ea18   Thomas Graf   [IPv4]: Convert F...
2825
  			NLA_PUT_U32(skb, RTA_IIF, rt->fl.iif);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2826
  	}
d8d1f30b9   Changli Gao   net-next: remove ...
2827
  	if (rtnl_put_cacheinfo(skb, &rt->dst, id, ts, tsage,
e3703b3de   Thomas Graf   [RTNETLINK]: Add ...
2828
2829
  			       expires, error) < 0)
  		goto nla_put_failure;
be403ea18   Thomas Graf   [IPv4]: Convert F...
2830
2831
  
  	return nlmsg_end(skb, nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2832

be403ea18   Thomas Graf   [IPv4]: Convert F...
2833
  nla_put_failure:
26932566a   Patrick McHardy   [NETLINK]: Don't ...
2834
2835
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2836
  }
63f3444fb   Thomas Graf   [IPv4]: Use rtnl ...
2837
  static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2838
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2839
  	struct net *net = sock_net(in_skb->sk);
d889ce3b2   Thomas Graf   [IPv4]: Convert r...
2840
2841
  	struct rtmsg *rtm;
  	struct nlattr *tb[RTA_MAX+1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2842
  	struct rtable *rt = NULL;
9e12bb22e   Al Viro   [IPV4]: ip_route_...
2843
2844
2845
  	__be32 dst = 0;
  	__be32 src = 0;
  	u32 iif;
d889ce3b2   Thomas Graf   [IPv4]: Convert r...
2846
  	int err;
963bfeeee   Eric Dumazet   net: RTA_MARK add...
2847
  	int mark;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2848
  	struct sk_buff *skb;
d889ce3b2   Thomas Graf   [IPv4]: Convert r...
2849
2850
2851
2852
2853
  	err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy);
  	if (err < 0)
  		goto errout;
  
  	rtm = nlmsg_data(nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2854
  	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
d889ce3b2   Thomas Graf   [IPv4]: Convert r...
2855
2856
2857
2858
  	if (skb == NULL) {
  		err = -ENOBUFS;
  		goto errout;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2859
2860
2861
2862
  
  	/* Reserve room for dummy headers, this skb can pass
  	   through good chunk of routing engine.
  	 */
459a98ed8   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
2863
  	skb_reset_mac_header(skb);
c1d2bbe1c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
2864
  	skb_reset_network_header(skb);
d2c962b85   Stephen Hemminger   [IPV4]: ip_route_...
2865
2866
  
  	/* Bugfix: need to give ip_route_input enough of an IP header to not gag. */
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
2867
  	ip_hdr(skb)->protocol = IPPROTO_ICMP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2868
  	skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr));
17fb2c643   Al Viro   [IPV4]: RTA_{DST,...
2869
2870
  	src = tb[RTA_SRC] ? nla_get_be32(tb[RTA_SRC]) : 0;
  	dst = tb[RTA_DST] ? nla_get_be32(tb[RTA_DST]) : 0;
d889ce3b2   Thomas Graf   [IPv4]: Convert r...
2871
  	iif = tb[RTA_IIF] ? nla_get_u32(tb[RTA_IIF]) : 0;
963bfeeee   Eric Dumazet   net: RTA_MARK add...
2872
  	mark = tb[RTA_MARK] ? nla_get_u32(tb[RTA_MARK]) : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2873
2874
  
  	if (iif) {
d889ce3b2   Thomas Graf   [IPv4]: Convert r...
2875
  		struct net_device *dev;
1937504dd   Denis V. Lunev   [NETNS]: Enable a...
2876
  		dev = __dev_get_by_index(net, iif);
d889ce3b2   Thomas Graf   [IPv4]: Convert r...
2877
2878
2879
2880
  		if (dev == NULL) {
  			err = -ENODEV;
  			goto errout_free;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2881
2882
  		skb->protocol	= htons(ETH_P_IP);
  		skb->dev	= dev;
963bfeeee   Eric Dumazet   net: RTA_MARK add...
2883
  		skb->mark	= mark;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2884
2885
2886
  		local_bh_disable();
  		err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev);
  		local_bh_enable();
d889ce3b2   Thomas Graf   [IPv4]: Convert r...
2887

511c3f92a   Eric Dumazet   net: skb->rtable ...
2888
  		rt = skb_rtable(skb);
d8d1f30b9   Changli Gao   net-next: remove ...
2889
2890
  		if (err == 0 && rt->dst.error)
  			err = -rt->dst.error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2891
  	} else {
d889ce3b2   Thomas Graf   [IPv4]: Convert r...
2892
2893
2894
2895
2896
2897
2898
2899
2900
  		struct flowi fl = {
  			.nl_u = {
  				.ip4_u = {
  					.daddr = dst,
  					.saddr = src,
  					.tos = rtm->rtm_tos,
  				},
  			},
  			.oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0,
963bfeeee   Eric Dumazet   net: RTA_MARK add...
2901
  			.mark = mark,
d889ce3b2   Thomas Graf   [IPv4]: Convert r...
2902
  		};
1937504dd   Denis V. Lunev   [NETNS]: Enable a...
2903
  		err = ip_route_output_key(net, &rt, &fl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2904
  	}
d889ce3b2   Thomas Graf   [IPv4]: Convert r...
2905

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2906
  	if (err)
d889ce3b2   Thomas Graf   [IPv4]: Convert r...
2907
  		goto errout_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2908

d8d1f30b9   Changli Gao   net-next: remove ...
2909
  	skb_dst_set(skb, &rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2910
2911
  	if (rtm->rtm_flags & RTM_F_NOTIFY)
  		rt->rt_flags |= RTCF_NOTIFY;
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
2912
  	err = rt_fill_info(net, skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq,
1937504dd   Denis V. Lunev   [NETNS]: Enable a...
2913
  			   RTM_NEWROUTE, 0, 0);
d889ce3b2   Thomas Graf   [IPv4]: Convert r...
2914
2915
  	if (err <= 0)
  		goto errout_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2916

1937504dd   Denis V. Lunev   [NETNS]: Enable a...
2917
  	err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid);
d889ce3b2   Thomas Graf   [IPv4]: Convert r...
2918
  errout:
2942e9005   Thomas Graf   [RTNETLINK]: Use ...
2919
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2920

d889ce3b2   Thomas Graf   [IPv4]: Convert r...
2921
  errout_free:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2922
  	kfree_skb(skb);
d889ce3b2   Thomas Graf   [IPv4]: Convert r...
2923
  	goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2924
2925
2926
2927
2928
2929
2930
  }
  
  int ip_rt_dump(struct sk_buff *skb,  struct netlink_callback *cb)
  {
  	struct rtable *rt;
  	int h, s_h;
  	int idx, s_idx;
1937504dd   Denis V. Lunev   [NETNS]: Enable a...
2931
  	struct net *net;
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2932
  	net = sock_net(skb->sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2933
2934
  
  	s_h = cb->args[0];
d8c928308   Eric Dumazet   [IPV4] ROUTE: ip_...
2935
2936
  	if (s_h < 0)
  		s_h = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2937
  	s_idx = idx = cb->args[1];
a62726657   Eric Dumazet   ip: speedup /proc...
2938
2939
2940
  	for (h = s_h; h <= rt_hash_mask; h++, s_idx = 0) {
  		if (!rt_hash_table[h].chain)
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2941
  		rcu_read_lock_bh();
a898def29   Paul E. McKenney   net: Add checking...
2942
  		for (rt = rcu_dereference_bh(rt_hash_table[h].chain), idx = 0; rt;
d8d1f30b9   Changli Gao   net-next: remove ...
2943
2944
  		     rt = rcu_dereference_bh(rt->dst.rt_next), idx++) {
  			if (!net_eq(dev_net(rt->dst.dev), net) || idx < s_idx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2945
  				continue;
e84f84f27   Denis V. Lunev   netns: place rt_g...
2946
  			if (rt_is_expired(rt))
29e75252d   Eric Dumazet   [IPV4] route cach...
2947
  				continue;
d8d1f30b9   Changli Gao   net-next: remove ...
2948
  			skb_dst_set_noref(skb, &rt->dst);
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
2949
  			if (rt_fill_info(net, skb, NETLINK_CB(cb->skb).pid,
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2950
  					 cb->nlh->nlmsg_seq, RTM_NEWROUTE,
b6544c0b4   Jamal Hadi Salim   [NETLINK]: Correc...
2951
  					 1, NLM_F_MULTI) <= 0) {
adf30907d   Eric Dumazet   net: skb->dst acc...
2952
  				skb_dst_drop(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2953
2954
2955
  				rcu_read_unlock_bh();
  				goto done;
  			}
adf30907d   Eric Dumazet   net: skb->dst acc...
2956
  			skb_dst_drop(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
  		}
  		rcu_read_unlock_bh();
  	}
  
  done:
  	cb->args[0] = h;
  	cb->args[1] = idx;
  	return skb->len;
  }
  
  void ip_rt_multicast_event(struct in_device *in_dev)
  {
76e6ebfb4   Denis V. Lunev   netns: add namesp...
2969
  	rt_cache_flush(dev_net(in_dev->dev), 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2970
2971
2972
  }
  
  #ifdef CONFIG_SYSCTL
81c684d12   Denis V. Lunev   ipv4: remove flus...
2973
  static int ipv4_sysctl_rtcache_flush(ctl_table *__ctl, int write,
8d65af789   Alexey Dobriyan   sysctl: remove "s...
2974
  					void __user *buffer,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2975
2976
2977
  					size_t *lenp, loff_t *ppos)
  {
  	if (write) {
639e104fa   Denis V. Lunev   ipv4: remove stat...
2978
  		int flush_delay;
81c684d12   Denis V. Lunev   ipv4: remove flus...
2979
  		ctl_table ctl;
39a23e750   Denis V. Lunev   netns: register n...
2980
  		struct net *net;
639e104fa   Denis V. Lunev   ipv4: remove stat...
2981

81c684d12   Denis V. Lunev   ipv4: remove flus...
2982
2983
  		memcpy(&ctl, __ctl, sizeof(ctl));
  		ctl.data = &flush_delay;
8d65af789   Alexey Dobriyan   sysctl: remove "s...
2984
  		proc_dointvec(&ctl, write, buffer, lenp, ppos);
639e104fa   Denis V. Lunev   ipv4: remove stat...
2985

81c684d12   Denis V. Lunev   ipv4: remove flus...
2986
  		net = (struct net *)__ctl->extra1;
39a23e750   Denis V. Lunev   netns: register n...
2987
  		rt_cache_flush(net, flush_delay);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2988
  		return 0;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2989
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2990
2991
2992
  
  	return -EINVAL;
  }
eeb61f719   Al Viro   missing bits of n...
2993
  static ctl_table ipv4_route_table[] = {
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2994
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2995
2996
2997
2998
  		.procname	= "gc_thresh",
  		.data		= &ipv4_dst_ops.gc_thresh,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2999
  		.proc_handler	= proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3000
3001
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3002
3003
3004
3005
  		.procname	= "max_size",
  		.data		= &ip_rt_max_size,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3006
  		.proc_handler	= proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3007
3008
3009
  	},
  	{
  		/*  Deprecated. Use gc_min_interval_ms */
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
3010

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3011
3012
3013
3014
  		.procname	= "gc_min_interval",
  		.data		= &ip_rt_gc_min_interval,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3015
  		.proc_handler	= proc_dointvec_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3016
3017
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3018
3019
3020
3021
  		.procname	= "gc_min_interval_ms",
  		.data		= &ip_rt_gc_min_interval,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3022
  		.proc_handler	= proc_dointvec_ms_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3023
3024
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3025
3026
3027
3028
  		.procname	= "gc_timeout",
  		.data		= &ip_rt_gc_timeout,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3029
  		.proc_handler	= proc_dointvec_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3030
3031
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3032
3033
3034
3035
  		.procname	= "gc_interval",
  		.data		= &ip_rt_gc_interval,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3036
  		.proc_handler	= proc_dointvec_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3037
3038
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3039
3040
3041
3042
  		.procname	= "redirect_load",
  		.data		= &ip_rt_redirect_load,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3043
  		.proc_handler	= proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3044
3045
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3046
3047
3048
3049
  		.procname	= "redirect_number",
  		.data		= &ip_rt_redirect_number,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3050
  		.proc_handler	= proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3051
3052
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3053
3054
3055
3056
  		.procname	= "redirect_silence",
  		.data		= &ip_rt_redirect_silence,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3057
  		.proc_handler	= proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3058
3059
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3060
3061
3062
3063
  		.procname	= "error_cost",
  		.data		= &ip_rt_error_cost,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3064
  		.proc_handler	= proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3065
3066
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3067
3068
3069
3070
  		.procname	= "error_burst",
  		.data		= &ip_rt_error_burst,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3071
  		.proc_handler	= proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3072
3073
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3074
3075
3076
3077
  		.procname	= "gc_elasticity",
  		.data		= &ip_rt_gc_elasticity,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3078
  		.proc_handler	= proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3079
3080
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3081
3082
3083
3084
  		.procname	= "mtu_expires",
  		.data		= &ip_rt_mtu_expires,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3085
  		.proc_handler	= proc_dointvec_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3086
3087
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3088
3089
3090
3091
  		.procname	= "min_pmtu",
  		.data		= &ip_rt_min_pmtu,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3092
  		.proc_handler	= proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3093
3094
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3095
3096
3097
3098
  		.procname	= "min_adv_mss",
  		.data		= &ip_rt_min_advmss,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3099
  		.proc_handler	= proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3100
  	},
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
3101
  	{ }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3102
  };
39a23e750   Denis V. Lunev   netns: register n...
3103

2f4520d35   Al Viro   ipv4: sysctl fixes
3104
3105
3106
3107
  static struct ctl_table empty[1];
  
  static struct ctl_table ipv4_skeleton[] =
  {
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
3108
  	{ .procname = "route", 
d994af0d5   Hugh Dickins   ipv4: mode 0555 i...
3109
  	  .mode = 0555, .child = ipv4_route_table},
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
3110
  	{ .procname = "neigh", 
d994af0d5   Hugh Dickins   ipv4: mode 0555 i...
3111
  	  .mode = 0555, .child = empty},
2f4520d35   Al Viro   ipv4: sysctl fixes
3112
3113
3114
3115
  	{ }
  };
  
  static __net_initdata struct ctl_path ipv4_path[] = {
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
3116
3117
  	{ .procname = "net", },
  	{ .procname = "ipv4", },
39a23e750   Denis V. Lunev   netns: register n...
3118
3119
  	{ },
  };
39a23e750   Denis V. Lunev   netns: register n...
3120
3121
  static struct ctl_table ipv4_route_flush_table[] = {
  	{
39a23e750   Denis V. Lunev   netns: register n...
3122
3123
3124
  		.procname	= "flush",
  		.maxlen		= sizeof(int),
  		.mode		= 0200,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3125
  		.proc_handler	= ipv4_sysctl_rtcache_flush,
39a23e750   Denis V. Lunev   netns: register n...
3126
  	},
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
3127
  	{ },
39a23e750   Denis V. Lunev   netns: register n...
3128
  };
2f4520d35   Al Viro   ipv4: sysctl fixes
3129
  static __net_initdata struct ctl_path ipv4_route_path[] = {
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
3130
3131
3132
  	{ .procname = "net", },
  	{ .procname = "ipv4", },
  	{ .procname = "route", },
2f4520d35   Al Viro   ipv4: sysctl fixes
3133
3134
  	{ },
  };
39a23e750   Denis V. Lunev   netns: register n...
3135
3136
3137
3138
3139
  static __net_init int sysctl_route_net_init(struct net *net)
  {
  	struct ctl_table *tbl;
  
  	tbl = ipv4_route_flush_table;
09ad9bc75   Octavian Purdila   net: use net_eq t...
3140
  	if (!net_eq(net, &init_net)) {
39a23e750   Denis V. Lunev   netns: register n...
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
  		tbl = kmemdup(tbl, sizeof(ipv4_route_flush_table), GFP_KERNEL);
  		if (tbl == NULL)
  			goto err_dup;
  	}
  	tbl[0].extra1 = net;
  
  	net->ipv4.route_hdr =
  		register_net_sysctl_table(net, ipv4_route_path, tbl);
  	if (net->ipv4.route_hdr == NULL)
  		goto err_reg;
  	return 0;
  
  err_reg:
  	if (tbl != ipv4_route_flush_table)
  		kfree(tbl);
  err_dup:
  	return -ENOMEM;
  }
  
  static __net_exit void sysctl_route_net_exit(struct net *net)
  {
  	struct ctl_table *tbl;
  
  	tbl = net->ipv4.route_hdr->ctl_table_arg;
  	unregister_net_sysctl_table(net->ipv4.route_hdr);
  	BUG_ON(tbl == ipv4_route_flush_table);
  	kfree(tbl);
  }
  
  static __net_initdata struct pernet_operations sysctl_route_ops = {
  	.init = sysctl_route_net_init,
  	.exit = sysctl_route_net_exit,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3174
  #endif
3ee943728   Neil Horman   ipv4: remove ip_r...
3175
  static __net_init int rt_genid_init(struct net *net)
9f5e97e53   Denis V. Lunev   netns: make rt_se...
3176
  {
3ee943728   Neil Horman   ipv4: remove ip_r...
3177
3178
  	get_random_bytes(&net->ipv4.rt_genid,
  			 sizeof(net->ipv4.rt_genid));
9f5e97e53   Denis V. Lunev   netns: make rt_se...
3179
3180
  	return 0;
  }
3ee943728   Neil Horman   ipv4: remove ip_r...
3181
3182
  static __net_initdata struct pernet_operations rt_genid_ops = {
  	.init = rt_genid_init,
9f5e97e53   Denis V. Lunev   netns: make rt_se...
3183
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3184
  #ifdef CONFIG_NET_CLS_ROUTE
7d720c3e4   Tejun Heo   percpu: add __per...
3185
  struct ip_rt_acct __percpu *ip_rt_acct __read_mostly;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
  #endif /* CONFIG_NET_CLS_ROUTE */
  
  static __initdata unsigned long rhash_entries;
  static int __init set_rhash_entries(char *str)
  {
  	if (!str)
  		return 0;
  	rhash_entries = simple_strtoul(str, &str, 0);
  	return 1;
  }
  __setup("rhash_entries=", set_rhash_entries);
  
  int __init ip_rt_init(void)
  {
424c4b70c   Eric Dumazet   [IPV4]: Use the f...
3200
  	int rc = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3201

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3202
  #ifdef CONFIG_NET_CLS_ROUTE
0dcec8c27   Ingo Molnar   alloc_percpu: add...
3203
  	ip_rt_acct = __alloc_percpu(256 * sizeof(struct ip_rt_acct), __alignof__(struct ip_rt_acct));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3204
3205
3206
  	if (!ip_rt_acct)
  		panic("IP: failed to allocate ip_rt_acct
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3207
  #endif
e5d679f33   Alexey Dobriyan   [NET]: Use SLAB_P...
3208
3209
  	ipv4_dst_ops.kmem_cachep =
  		kmem_cache_create("ip_dst_cache", sizeof(struct rtable), 0,
20c2df83d   Paul Mundt   mm: Remove slab d...
3210
  				  SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3211

14e50e57a   David S. Miller   [XFRM]: Allow pac...
3212
  	ipv4_dst_blackhole_ops.kmem_cachep = ipv4_dst_ops.kmem_cachep;
424c4b70c   Eric Dumazet   [IPV4]: Use the f...
3213
3214
3215
3216
  	rt_hash_table = (struct rt_hash_bucket *)
  		alloc_large_system_hash("IP route cache",
  					sizeof(struct rt_hash_bucket),
  					rhash_entries,
4481374ce   Jan Beulich   mm: replace vario...
3217
  					(totalram_pages >= 128 * 1024) ?
18955cfcb   Mike Stroyan   [IPV4] tcp/route:...
3218
  					15 : 17,
8d1502de2   Kirill Korotaev   [IPV4]: Limit rt ...
3219
  					0,
424c4b70c   Eric Dumazet   [IPV4]: Use the f...
3220
3221
  					&rt_hash_log,
  					&rt_hash_mask,
c9503e0fe   Anton Blanchard   ipv4: Limit size ...
3222
  					rhash_entries ? 0 : 512 * 1024);
22c047ccb   Eric Dumazet   [NET]: Hashed spi...
3223
3224
  	memset(rt_hash_table, 0, (rt_hash_mask + 1) * sizeof(struct rt_hash_bucket));
  	rt_hash_lock_init();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3225
3226
3227
  
  	ipv4_dst_ops.gc_thresh = (rt_hash_mask + 1);
  	ip_rt_max_size = (rt_hash_mask + 1) * 16;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3228
3229
  	devinet_init();
  	ip_fib_init();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3230
3231
3232
  	/* All the timers, started at system startup tend
  	   to synchronize. Perturb it a bit.
  	 */
125bb8f56   Eric Dumazet   net: use a deferr...
3233
3234
  	INIT_DELAYED_WORK_DEFERRABLE(&expires_work, rt_worker_func);
  	expires_ljiffies = jiffies;
39c90ece7   Eric Dumazet   [IPV4]: Convert r...
3235
3236
  	schedule_delayed_work(&expires_work,
  		net_random() % ip_rt_gc_interval + ip_rt_gc_interval);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3237

73b387116   Denis V. Lunev   [NETNS]: Register...
3238
  	if (ip_rt_proc_init())
107f16342   Pavel Emelyanov   [IPV4] ROUTE: Cle...
3239
3240
  		printk(KERN_ERR "Unable to create route proc files
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3241
3242
  #ifdef CONFIG_XFRM
  	xfrm_init();
a33bc5c15   Neil Horman   xfrm: select sane...
3243
  	xfrm4_init(ip_rt_max_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3244
  #endif
63f3444fb   Thomas Graf   [IPv4]: Use rtnl ...
3245
  	rtnl_register(PF_INET, RTM_GETROUTE, inet_rtm_getroute, NULL);
39a23e750   Denis V. Lunev   netns: register n...
3246
3247
3248
  #ifdef CONFIG_SYSCTL
  	register_pernet_subsys(&sysctl_route_ops);
  #endif
3ee943728   Neil Horman   ipv4: remove ip_r...
3249
  	register_pernet_subsys(&rt_genid_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3250
3251
  	return rc;
  }
a1bc6eb4b   Al Viro   [PATCH] ipv4_stat...
3252
  #ifdef CONFIG_SYSCTL
eeb61f719   Al Viro   missing bits of n...
3253
3254
3255
3256
3257
3258
  /*
   * We really need to sanitize the damn ipv4 init order, then all
   * this nonsense will go away.
   */
  void __init ip_static_sysctl_init(void)
  {
2f4520d35   Al Viro   ipv4: sysctl fixes
3259
  	register_sysctl_paths(ipv4_path, ipv4_skeleton);
eeb61f719   Al Viro   missing bits of n...
3260
  }
a1bc6eb4b   Al Viro   [PATCH] ipv4_stat...
3261
  #endif