Blame view

net/ipv6/route.c 72.2 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
  /*
   *	Linux INET6 implementation
   *	FIB front-end.
   *
   *	Authors:
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
6
   *	Pedro Roque		<roque@di.fc.ul.pt>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   *	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.
   */
  
  /*	Changes:
   *
   *	YOSHIFUJI Hideaki @USAGI
   *		reworked default router selection.
   *		- respect outgoing interface
   *		- select from (probably) reachable routers (i.e.
   *		routers in REACHABLE, STALE, DELAY or PROBE states).
   *		- always select the same router if it is (probably)
   *		reachable.  otherwise, round-robin the list.
c0bece9f2   YOSHIFUJI Hideaki   [IPV6] ROUTE: Add...
23
24
   *	Ville Nuorvala
   *		Fixed routing subtrees.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
   */
4fc268d24   Randy Dunlap   [PATCH] capable/c...
26
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
  #include <linux/errno.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
28
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
32
33
34
35
36
  #include <linux/types.h>
  #include <linux/times.h>
  #include <linux/socket.h>
  #include <linux/sockios.h>
  #include <linux/net.h>
  #include <linux/route.h>
  #include <linux/netdevice.h>
  #include <linux/in6.h>
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
37
  #include <linux/mroute6.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
  #include <linux/init.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
  #include <linux/if_arp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
  #include <linux/proc_fs.h>
  #include <linux/seq_file.h>
5b7c931df   Daniel Lezcano   [NETNS][IPV6] ip6...
42
  #include <linux/nsproxy.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
43
  #include <linux/slab.h>
457c4cbc5   Eric W. Biederman   [NET]: Make /proc...
44
  #include <net/net_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
48
49
50
51
52
53
54
  #include <net/snmp.h>
  #include <net/ipv6.h>
  #include <net/ip6_fib.h>
  #include <net/ip6_route.h>
  #include <net/ndisc.h>
  #include <net/addrconf.h>
  #include <net/tcp.h>
  #include <linux/rtnetlink.h>
  #include <net/dst.h>
  #include <net/xfrm.h>
8d71740c5   Tom Tucker   [NET]: Core net c...
55
  #include <net/netevent.h>
21713ebc4   Thomas Graf   [IPv6] route: Con...
56
  #include <net/netlink.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
60
61
62
  
  #include <asm/uaccess.h>
  
  #ifdef CONFIG_SYSCTL
  #include <linux/sysctl.h>
  #endif
21efcfa0f   Eric Dumazet   ipv6: unshare ine...
63
64
  static struct rt6_info *ip6_rt_copy(const struct rt6_info *ort,
  				    const struct in6_addr *dest);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
  static struct dst_entry	*ip6_dst_check(struct dst_entry *dst, u32 cookie);
0dbaee3b3   David S. Miller   net: Abstract def...
66
  static unsigned int	 ip6_default_advmss(const struct dst_entry *dst);
ebb762f27   Steffen Klassert   net: Rename the d...
67
  static unsigned int	 ip6_mtu(const struct dst_entry *dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
70
71
  static struct dst_entry *ip6_negative_advice(struct dst_entry *);
  static void		ip6_dst_destroy(struct dst_entry *);
  static void		ip6_dst_ifdown(struct dst_entry *,
  				       struct net_device *dev, int how);
569d36452   Daniel Lezcano   [NETNS][DST] dst:...
72
  static int		 ip6_dst_gc(struct dst_ops *ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
75
76
77
  
  static int		ip6_pkt_discard(struct sk_buff *skb);
  static int		ip6_pkt_discard_out(struct sk_buff *skb);
  static void		ip6_link_failure(struct sk_buff *skb);
  static void		ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
78
  #ifdef CONFIG_IPV6_ROUTE_INFO
efa2cea0d   Daniel Lezcano   [NETNS][IPV6] rou...
79
  static struct rt6_info *rt6_add_route_info(struct net *net,
b71d1d426   Eric Dumazet   inet: constify ip...
80
81
  					   const struct in6_addr *prefix, int prefixlen,
  					   const struct in6_addr *gwaddr, int ifindex,
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
82
  					   unsigned pref);
efa2cea0d   Daniel Lezcano   [NETNS][IPV6] rou...
83
  static struct rt6_info *rt6_get_route_info(struct net *net,
b71d1d426   Eric Dumazet   inet: constify ip...
84
85
  					   const struct in6_addr *prefix, int prefixlen,
  					   const struct in6_addr *gwaddr, int ifindex);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
86
  #endif
065825402   David S. Miller   net: Store ipv4/i...
87
88
89
90
91
  static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
  {
  	struct rt6_info *rt = (struct rt6_info *) dst;
  	struct inet_peer *peer;
  	u32 *p = NULL;
8e2ec6391   Yan, Zheng   ipv6: don't use i...
92
93
  	if (!(rt->dst.flags & DST_HOST))
  		return NULL;
065825402   David S. Miller   net: Store ipv4/i...
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
  	if (!rt->rt6i_peer)
  		rt6_bind_peer(rt, 1);
  
  	peer = rt->rt6i_peer;
  	if (peer) {
  		u32 *old_p = __DST_METRICS_PTR(old);
  		unsigned long prev, new;
  
  		p = peer->metrics;
  		if (inet_metrics_new(peer))
  			memcpy(p, old_p, sizeof(u32) * RTAX_MAX);
  
  		new = (unsigned long) p;
  		prev = cmpxchg(&dst->_metrics, old, new);
  
  		if (prev != old) {
  			p = __DST_METRICS_PTR(prev);
  			if (prev & DST_METRICS_READ_ONLY)
  				p = NULL;
  		}
  	}
  	return p;
  }
d3aaeb38c   David S. Miller   net: Add ->neigh_...
117
118
  static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst, const void *daddr)
  {
f83c7790d   David S. Miller   ipv6: Create fast...
119
120
121
122
123
  	struct neighbour *n = __ipv6_neigh_lookup(&nd_tbl, dst->dev, daddr);
  	if (n)
  		return n;
  	return neigh_create(&nd_tbl, daddr, dst->dev);
  }
8ade06c61   David S. Miller   ipv6: Fix neigh l...
124
  static int rt6_bind_neighbour(struct rt6_info *rt, struct net_device *dev)
f83c7790d   David S. Miller   ipv6: Create fast...
125
  {
8ade06c61   David S. Miller   ipv6: Fix neigh l...
126
127
128
129
130
131
  	struct neighbour *n = __ipv6_neigh_lookup(&nd_tbl, dev, &rt->rt6i_gateway);
  	if (!n) {
  		n = neigh_create(&nd_tbl, &rt->rt6i_gateway, dev);
  		if (IS_ERR(n))
  			return PTR_ERR(n);
  	}
f83c7790d   David S. Miller   ipv6: Create fast...
132
133
134
  	dst_set_neighbour(&rt->dst, n);
  
  	return 0;
d3aaeb38c   David S. Miller   net: Add ->neigh_...
135
  }
9a7ec3a94   Daniel Lezcano   [NETNS][IPV6] rou...
136
  static struct dst_ops ip6_dst_ops_template = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
  	.family			=	AF_INET6,
09640e636   Harvey Harrison   net: replace uses...
138
  	.protocol		=	cpu_to_be16(ETH_P_IPV6),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
140
141
  	.gc			=	ip6_dst_gc,
  	.gc_thresh		=	1024,
  	.check			=	ip6_dst_check,
0dbaee3b3   David S. Miller   net: Abstract def...
142
  	.default_advmss		=	ip6_default_advmss,
ebb762f27   Steffen Klassert   net: Rename the d...
143
  	.mtu			=	ip6_mtu,
065825402   David S. Miller   net: Store ipv4/i...
144
  	.cow_metrics		=	ipv6_cow_metrics,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
148
149
  	.destroy		=	ip6_dst_destroy,
  	.ifdown			=	ip6_dst_ifdown,
  	.negative_advice	=	ip6_negative_advice,
  	.link_failure		=	ip6_link_failure,
  	.update_pmtu		=	ip6_rt_update_pmtu,
1ac06e030   Herbert Xu   ipsec: Use the co...
150
  	.local_out		=	__ip6_local_out,
d3aaeb38c   David S. Miller   net: Add ->neigh_...
151
  	.neigh_lookup		=	ip6_neigh_lookup,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
  };
ebb762f27   Steffen Klassert   net: Rename the d...
153
  static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
ec831ea72   Roland Dreier   net: Add default_...
154
  {
618f9bc74   Steffen Klassert   net: Move mtu han...
155
156
157
  	unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
  
  	return mtu ? : dst->dev->mtu;
ec831ea72   Roland Dreier   net: Add default_...
158
  }
14e50e57a   David S. Miller   [XFRM]: Allow pac...
159
160
161
  static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
  {
  }
0972ddb23   Held Bernhard   net: provide cow_...
162
163
164
165
166
  static u32 *ip6_rt_blackhole_cow_metrics(struct dst_entry *dst,
  					 unsigned long old)
  {
  	return NULL;
  }
14e50e57a   David S. Miller   [XFRM]: Allow pac...
167
168
  static struct dst_ops ip6_dst_blackhole_ops = {
  	.family			=	AF_INET6,
09640e636   Harvey Harrison   net: replace uses...
169
  	.protocol		=	cpu_to_be16(ETH_P_IPV6),
14e50e57a   David S. Miller   [XFRM]: Allow pac...
170
171
  	.destroy		=	ip6_dst_destroy,
  	.check			=	ip6_dst_check,
ebb762f27   Steffen Klassert   net: Rename the d...
172
  	.mtu			=	ip6_blackhole_mtu,
214f45c91   Eric Dumazet   net: provide defa...
173
  	.default_advmss		=	ip6_default_advmss,
14e50e57a   David S. Miller   [XFRM]: Allow pac...
174
  	.update_pmtu		=	ip6_rt_blackhole_update_pmtu,
0972ddb23   Held Bernhard   net: provide cow_...
175
  	.cow_metrics		=	ip6_rt_blackhole_cow_metrics,
d3aaeb38c   David S. Miller   net: Add ->neigh_...
176
  	.neigh_lookup		=	ip6_neigh_lookup,
14e50e57a   David S. Miller   [XFRM]: Allow pac...
177
  };
62fa8a846   David S. Miller   net: Implement re...
178
179
180
  static const u32 ip6_template_metrics[RTAX_MAX] = {
  	[RTAX_HOPLIMIT - 1] = 255,
  };
bdb3289f7   Daniel Lezcano   [NETNS][IPV6] rt6...
181
  static struct rt6_info ip6_null_entry_template = {
d8d1f30b9   Changli Gao   net-next: remove ...
182
183
184
185
186
  	.dst = {
  		.__refcnt	= ATOMIC_INIT(1),
  		.__use		= 1,
  		.obsolete	= -1,
  		.error		= -ENETUNREACH,
d8d1f30b9   Changli Gao   net-next: remove ...
187
188
  		.input		= ip6_pkt_discard,
  		.output		= ip6_pkt_discard_out,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
  	},
  	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
4f7242799   Jean-Mickael Guerin   IPv6: set RTPROT_...
191
  	.rt6i_protocol  = RTPROT_KERNEL,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
193
194
  	.rt6i_metric	= ~(u32) 0,
  	.rt6i_ref	= ATOMIC_INIT(1),
  };
101367c2f   Thomas Graf   [IPV6]: Policy Ro...
195
  #ifdef CONFIG_IPV6_MULTIPLE_TABLES
6723ab549   David S. Miller   [IPV6]: Fix route...
196
197
  static int ip6_pkt_prohibit(struct sk_buff *skb);
  static int ip6_pkt_prohibit_out(struct sk_buff *skb);
6723ab549   David S. Miller   [IPV6]: Fix route...
198

280a34c87   Adrian Bunk   [IPV6]: Make stru...
199
  static struct rt6_info ip6_prohibit_entry_template = {
d8d1f30b9   Changli Gao   net-next: remove ...
200
201
202
203
204
  	.dst = {
  		.__refcnt	= ATOMIC_INIT(1),
  		.__use		= 1,
  		.obsolete	= -1,
  		.error		= -EACCES,
d8d1f30b9   Changli Gao   net-next: remove ...
205
206
  		.input		= ip6_pkt_prohibit,
  		.output		= ip6_pkt_prohibit_out,
101367c2f   Thomas Graf   [IPV6]: Policy Ro...
207
208
  	},
  	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
4f7242799   Jean-Mickael Guerin   IPv6: set RTPROT_...
209
  	.rt6i_protocol  = RTPROT_KERNEL,
101367c2f   Thomas Graf   [IPV6]: Policy Ro...
210
211
212
  	.rt6i_metric	= ~(u32) 0,
  	.rt6i_ref	= ATOMIC_INIT(1),
  };
bdb3289f7   Daniel Lezcano   [NETNS][IPV6] rt6...
213
  static struct rt6_info ip6_blk_hole_entry_template = {
d8d1f30b9   Changli Gao   net-next: remove ...
214
215
216
217
218
  	.dst = {
  		.__refcnt	= ATOMIC_INIT(1),
  		.__use		= 1,
  		.obsolete	= -1,
  		.error		= -EINVAL,
d8d1f30b9   Changli Gao   net-next: remove ...
219
220
  		.input		= dst_discard,
  		.output		= dst_discard,
101367c2f   Thomas Graf   [IPV6]: Policy Ro...
221
222
  	},
  	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
4f7242799   Jean-Mickael Guerin   IPv6: set RTPROT_...
223
  	.rt6i_protocol  = RTPROT_KERNEL,
101367c2f   Thomas Graf   [IPV6]: Policy Ro...
224
225
226
227
228
  	.rt6i_metric	= ~(u32) 0,
  	.rt6i_ref	= ATOMIC_INIT(1),
  };
  
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
  /* allocate dst with ip6_dst_ops */
5c1e6aa30   David S. Miller   net: Make dst_all...
230
  static inline struct rt6_info *ip6_dst_alloc(struct dst_ops *ops,
957c665f3   David S. Miller   ipv6: Don't put a...
231
232
  					     struct net_device *dev,
  					     int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
  {
957c665f3   David S. Miller   ipv6: Don't put a...
234
  	struct rt6_info *rt = dst_alloc(ops, dev, 0, 0, flags);
cf9116622   David S. Miller   net: Use non-zero...
235

383084739   David S. Miller   ipv6: Various cle...
236
  	if (rt)
fbe581869   Madalin Bucur   ipv6: check retur...
237
  		memset(&rt->rt6i_table, 0,
383084739   David S. Miller   ipv6: Various cle...
238
  		       sizeof(*rt) - sizeof(struct dst_entry));
cf9116622   David S. Miller   net: Use non-zero...
239
240
  
  	return rt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
242
243
244
245
246
  }
  
  static void ip6_dst_destroy(struct dst_entry *dst)
  {
  	struct rt6_info *rt = (struct rt6_info *)dst;
  	struct inet6_dev *idev = rt->rt6i_idev;
b34193638   David S. Miller   ipv6: Add infrast...
247
  	struct inet_peer *peer = rt->rt6i_peer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248

8e2ec6391   Yan, Zheng   ipv6: don't use i...
249
250
  	if (!(rt->dst.flags & DST_HOST))
  		dst_destroy_metrics_generic(dst);
383084739   David S. Miller   ipv6: Various cle...
251
  	if (idev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
  		rt->rt6i_idev = NULL;
  		in6_dev_put(idev);
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
254
  	}
b34193638   David S. Miller   ipv6: Add infrast...
255
  	if (peer) {
b34193638   David S. Miller   ipv6: Add infrast...
256
257
258
259
  		rt->rt6i_peer = NULL;
  		inet_putpeer(peer);
  	}
  }
6431cbc25   David S. Miller   inet: Create a me...
260
261
262
263
264
265
  static atomic_t __rt6_peer_genid = ATOMIC_INIT(0);
  
  static u32 rt6_peer_genid(void)
  {
  	return atomic_read(&__rt6_peer_genid);
  }
b34193638   David S. Miller   ipv6: Add infrast...
266
267
268
  void rt6_bind_peer(struct rt6_info *rt, int create)
  {
  	struct inet_peer *peer;
b34193638   David S. Miller   ipv6: Add infrast...
269
270
271
  	peer = inet_getpeer_v6(&rt->rt6i_dst.addr, create);
  	if (peer && cmpxchg(&rt->rt6i_peer, NULL, peer) != NULL)
  		inet_putpeer(peer);
6431cbc25   David S. Miller   inet: Create a me...
272
273
  	else
  		rt->rt6i_peer_genid = rt6_peer_genid();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
275
276
277
278
279
280
  }
  
  static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
  			   int how)
  {
  	struct rt6_info *rt = (struct rt6_info *)dst;
  	struct inet6_dev *idev = rt->rt6i_idev;
5a3e55d68   Denis V. Lunev   [NET]: Multiple n...
281
  	struct net_device *loopback_dev =
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
282
  		dev_net(dev)->loopback_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283

383084739   David S. Miller   ipv6: Various cle...
284
  	if (dev != loopback_dev && idev && idev->dev == dev) {
5a3e55d68   Denis V. Lunev   [NET]: Multiple n...
285
286
  		struct inet6_dev *loopback_idev =
  			in6_dev_get(loopback_dev);
383084739   David S. Miller   ipv6: Various cle...
287
  		if (loopback_idev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
290
291
292
293
294
295
  			rt->rt6i_idev = loopback_idev;
  			in6_dev_put(idev);
  		}
  	}
  }
  
  static __inline__ int rt6_check_expired(const struct rt6_info *rt)
  {
a02cec215   Eric Dumazet   net: return opera...
296
  	return (rt->rt6i_flags & RTF_EXPIRES) &&
d19185428   David S. Miller   ipv6: Kill rt6i_d...
297
  		time_after(jiffies, rt->dst.expires);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
  }
b71d1d426   Eric Dumazet   inet: constify ip...
299
  static inline int rt6_need_strict(const struct in6_addr *daddr)
c71099acc   Thomas Graf   [IPV6]: Multiple ...
300
  {
a02cec215   Eric Dumazet   net: return opera...
301
302
  	return ipv6_addr_type(daddr) &
  		(IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
303
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
  /*
c71099acc   Thomas Graf   [IPV6]: Multiple ...
305
   *	Route lookup. Any table->tb6_lock is implied.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
   */
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
307
308
  static inline struct rt6_info *rt6_device_match(struct net *net,
  						    struct rt6_info *rt,
b71d1d426   Eric Dumazet   inet: constify ip...
309
  						    const struct in6_addr *saddr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
  						    int oif,
d420895ef   YOSHIFUJI Hideaki   ipv6 route: Conve...
311
  						    int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
313
314
  {
  	struct rt6_info *local = NULL;
  	struct rt6_info *sprt;
dd3abc4ef   YOSHIFUJI Hideaki   ipv6 route: Prefe...
315
316
  	if (!oif && ipv6_addr_any(saddr))
  		goto out;
d8d1f30b9   Changli Gao   net-next: remove ...
317
  	for (sprt = rt; sprt; sprt = sprt->dst.rt6_next) {
d19185428   David S. Miller   ipv6: Kill rt6i_d...
318
  		struct net_device *dev = sprt->dst.dev;
dd3abc4ef   YOSHIFUJI Hideaki   ipv6 route: Prefe...
319
320
  
  		if (oif) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
322
323
  			if (dev->ifindex == oif)
  				return sprt;
  			if (dev->flags & IFF_LOOPBACK) {
383084739   David S. Miller   ipv6: Various cle...
324
  				if (!sprt->rt6i_idev ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
  				    sprt->rt6i_idev->dev->ifindex != oif) {
d420895ef   YOSHIFUJI Hideaki   ipv6 route: Conve...
326
  					if (flags & RT6_LOOKUP_F_IFACE && oif)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
  						continue;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
328
  					if (local && (!oif ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
330
331
332
333
  						      local->rt6i_idev->dev->ifindex == oif))
  						continue;
  				}
  				local = sprt;
  			}
dd3abc4ef   YOSHIFUJI Hideaki   ipv6 route: Prefe...
334
335
336
337
  		} else {
  			if (ipv6_chk_addr(net, saddr, dev,
  					  flags & RT6_LOOKUP_F_IFACE))
  				return sprt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
  		}
dd3abc4ef   YOSHIFUJI Hideaki   ipv6 route: Prefe...
339
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340

dd3abc4ef   YOSHIFUJI Hideaki   ipv6 route: Prefe...
341
  	if (oif) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
343
  		if (local)
  			return local;
d420895ef   YOSHIFUJI Hideaki   ipv6 route: Conve...
344
  		if (flags & RT6_LOOKUP_F_IFACE)
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
345
  			return net->ipv6.ip6_null_entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
  	}
dd3abc4ef   YOSHIFUJI Hideaki   ipv6 route: Prefe...
347
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
349
  	return rt;
  }
270972554   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
350
351
352
  #ifdef CONFIG_IPV6_ROUTER_PREF
  static void rt6_probe(struct rt6_info *rt)
  {
f2c31e32b   Eric Dumazet   net: fix NULL der...
353
  	struct neighbour *neigh;
270972554   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
354
355
356
357
358
359
360
361
  	/*
  	 * Okay, this does not seem to be appropriate
  	 * for now, however, we need to check if it
  	 * is really so; aka Router Reachability Probing.
  	 *
  	 * Router Reachability Probe MUST be rate-limited
  	 * to no more than one per minute.
  	 */
f2c31e32b   Eric Dumazet   net: fix NULL der...
362
  	rcu_read_lock();
272174550   David Miller   net: Rename dst_g...
363
  	neigh = rt ? dst_get_neighbour_noref(&rt->dst) : NULL;
270972554   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
364
  	if (!neigh || (neigh->nud_state & NUD_VALID))
f2c31e32b   Eric Dumazet   net: fix NULL der...
365
  		goto out;
270972554   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
366
367
  	read_lock_bh(&neigh->lock);
  	if (!(neigh->nud_state & NUD_VALID) &&
52e163563   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
368
  	    time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) {
270972554   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
369
370
371
372
373
374
375
376
  		struct in6_addr mcaddr;
  		struct in6_addr *target;
  
  		neigh->updated = jiffies;
  		read_unlock_bh(&neigh->lock);
  
  		target = (struct in6_addr *)&neigh->primary_key;
  		addrconf_addr_solict_mult(target, &mcaddr);
d19185428   David S. Miller   ipv6: Kill rt6i_d...
377
  		ndisc_send_ns(rt->dst.dev, NULL, target, &mcaddr, NULL);
f2c31e32b   Eric Dumazet   net: fix NULL der...
378
  	} else {
270972554   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
379
  		read_unlock_bh(&neigh->lock);
f2c31e32b   Eric Dumazet   net: fix NULL der...
380
381
382
  	}
  out:
  	rcu_read_unlock();
270972554   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
383
384
385
386
  }
  #else
  static inline void rt6_probe(struct rt6_info *rt)
  {
270972554   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
387
388
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
  /*
554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
390
   * Default Router Selection (RFC 2461 6.3.6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
   */
b6f99a211   Dave Jones   [NET]: fix up mis...
392
  static inline int rt6_check_dev(struct rt6_info *rt, int oif)
554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
393
  {
d19185428   David S. Miller   ipv6: Kill rt6i_d...
394
  	struct net_device *dev = rt->dst.dev;
161980f4c   David S. Miller   [IPV6]: Revert re...
395
  	if (!oif || dev->ifindex == oif)
554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
396
  		return 2;
161980f4c   David S. Miller   [IPV6]: Revert re...
397
398
399
400
  	if ((dev->flags & IFF_LOOPBACK) &&
  	    rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
  		return 1;
  	return 0;
554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
401
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402

b6f99a211   Dave Jones   [NET]: fix up mis...
403
  static inline int rt6_check_neigh(struct rt6_info *rt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
  {
f2c31e32b   Eric Dumazet   net: fix NULL der...
405
  	struct neighbour *neigh;
398bcbebb   YOSHIFUJI Hideaki   [IPV6] ROUTE: Mak...
406
  	int m;
f2c31e32b   Eric Dumazet   net: fix NULL der...
407
408
  
  	rcu_read_lock();
272174550   David Miller   net: Rename dst_g...
409
  	neigh = dst_get_neighbour_noref(&rt->dst);
4d0c59116   YOSHIFUJI Hideaki   [IPV6] ROUTE: Don...
410
411
412
413
  	if (rt->rt6i_flags & RTF_NONEXTHOP ||
  	    !(rt->rt6i_flags & RTF_GATEWAY))
  		m = 1;
  	else if (neigh) {
554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
414
415
  		read_lock_bh(&neigh->lock);
  		if (neigh->nud_state & NUD_VALID)
4d0c59116   YOSHIFUJI Hideaki   [IPV6] ROUTE: Don...
416
  			m = 2;
398bcbebb   YOSHIFUJI Hideaki   [IPV6] ROUTE: Mak...
417
418
419
420
421
  #ifdef CONFIG_IPV6_ROUTER_PREF
  		else if (neigh->nud_state & NUD_FAILED)
  			m = 0;
  #endif
  		else
ea73ee23c   YOSHIFUJI Hideaki   [IPV6] ROUTE: Try...
422
  			m = 1;
554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
423
  		read_unlock_bh(&neigh->lock);
398bcbebb   YOSHIFUJI Hideaki   [IPV6] ROUTE: Mak...
424
425
  	} else
  		m = 0;
f2c31e32b   Eric Dumazet   net: fix NULL der...
426
  	rcu_read_unlock();
554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
427
  	return m;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
  }
554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
429
430
  static int rt6_score_route(struct rt6_info *rt, int oif,
  			   int strict)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
  {
4d0c59116   YOSHIFUJI Hideaki   [IPV6] ROUTE: Don...
432
  	int m, n;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
433

4d0c59116   YOSHIFUJI Hideaki   [IPV6] ROUTE: Don...
434
  	m = rt6_check_dev(rt, oif);
77d16f450   YOSHIFUJI Hideaki   [IPV6] ROUTE: Uni...
435
  	if (!m && (strict & RT6_LOOKUP_F_IFACE))
554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
436
  		return -1;
ebacaaa0f   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
437
438
439
  #ifdef CONFIG_IPV6_ROUTER_PREF
  	m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
  #endif
4d0c59116   YOSHIFUJI Hideaki   [IPV6] ROUTE: Don...
440
  	n = rt6_check_neigh(rt);
557e92efd   YOSHIFUJI Hideaki   [IPV6] ROUTE: Pre...
441
  	if (!n && (strict & RT6_LOOKUP_F_REACHABLE))
554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
442
443
444
  		return -1;
  	return m;
  }
f11e6659c   David S. Miller   [IPV6]: Fix routi...
445
446
  static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
  				   int *mpri, struct rt6_info *match)
554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
447
  {
f11e6659c   David S. Miller   [IPV6]: Fix routi...
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
  	int m;
  
  	if (rt6_check_expired(rt))
  		goto out;
  
  	m = rt6_score_route(rt, oif, strict);
  	if (m < 0)
  		goto out;
  
  	if (m > *mpri) {
  		if (strict & RT6_LOOKUP_F_REACHABLE)
  			rt6_probe(match);
  		*mpri = m;
  		match = rt;
  	} else if (strict & RT6_LOOKUP_F_REACHABLE) {
  		rt6_probe(rt);
  	}
  
  out:
  	return match;
  }
  
  static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
  				     struct rt6_info *rr_head,
  				     u32 metric, int oif, int strict)
  {
  	struct rt6_info *rt, *match;
554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
475
  	int mpri = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476

f11e6659c   David S. Miller   [IPV6]: Fix routi...
477
478
  	match = NULL;
  	for (rt = rr_head; rt && rt->rt6i_metric == metric;
d8d1f30b9   Changli Gao   net-next: remove ...
479
  	     rt = rt->dst.rt6_next)
f11e6659c   David S. Miller   [IPV6]: Fix routi...
480
481
  		match = find_match(rt, oif, strict, &mpri, match);
  	for (rt = fn->leaf; rt && rt != rr_head && rt->rt6i_metric == metric;
d8d1f30b9   Changli Gao   net-next: remove ...
482
  	     rt = rt->dst.rt6_next)
f11e6659c   David S. Miller   [IPV6]: Fix routi...
483
  		match = find_match(rt, oif, strict, &mpri, match);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484

f11e6659c   David S. Miller   [IPV6]: Fix routi...
485
486
  	return match;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487

f11e6659c   David S. Miller   [IPV6]: Fix routi...
488
489
490
  static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
  {
  	struct rt6_info *match, *rt0;
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
491
  	struct net *net;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492

f11e6659c   David S. Miller   [IPV6]: Fix routi...
493
494
495
  	rt0 = fn->rr_ptr;
  	if (!rt0)
  		fn->rr_ptr = rt0 = fn->leaf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496

f11e6659c   David S. Miller   [IPV6]: Fix routi...
497
  	match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498

554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
499
  	if (!match &&
f11e6659c   David S. Miller   [IPV6]: Fix routi...
500
  	    (strict & RT6_LOOKUP_F_REACHABLE)) {
d8d1f30b9   Changli Gao   net-next: remove ...
501
  		struct rt6_info *next = rt0->dst.rt6_next;
f11e6659c   David S. Miller   [IPV6]: Fix routi...
502

554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
503
  		/* no entries matched; do round-robin */
f11e6659c   David S. Miller   [IPV6]: Fix routi...
504
505
506
507
508
  		if (!next || next->rt6i_metric != rt0->rt6i_metric)
  			next = fn->leaf;
  
  		if (next != rt0)
  			fn->rr_ptr = next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510

d19185428   David S. Miller   ipv6: Kill rt6i_d...
511
  	net = dev_net(rt0->dst.dev);
a02cec215   Eric Dumazet   net: return opera...
512
  	return match ? match : net->ipv6.ip6_null_entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
  }
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
514
515
  #ifdef CONFIG_IPV6_ROUTE_INFO
  int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
b71d1d426   Eric Dumazet   inet: constify ip...
516
  		  const struct in6_addr *gwaddr)
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
517
  {
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
518
  	struct net *net = dev_net(dev);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
519
520
521
  	struct route_info *rinfo = (struct route_info *) opt;
  	struct in6_addr prefix_buf, *prefix;
  	unsigned int pref;
4bed72e4f   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
522
  	unsigned long lifetime;
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
  	struct rt6_info *rt;
  
  	if (len < sizeof(struct route_info)) {
  		return -EINVAL;
  	}
  
  	/* Sanity check for prefix_len and length */
  	if (rinfo->length > 3) {
  		return -EINVAL;
  	} else if (rinfo->prefix_len > 128) {
  		return -EINVAL;
  	} else if (rinfo->prefix_len > 64) {
  		if (rinfo->length < 2) {
  			return -EINVAL;
  		}
  	} else if (rinfo->prefix_len > 0) {
  		if (rinfo->length < 1) {
  			return -EINVAL;
  		}
  	}
  
  	pref = rinfo->route_pref;
  	if (pref == ICMPV6_ROUTER_PREF_INVALID)
3933fc952   Jens Rosenboom   ipv6: Ignore rout...
546
  		return -EINVAL;
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
547

4bed72e4f   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
548
  	lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
549
550
551
552
553
554
555
556
557
558
  
  	if (rinfo->length == 3)
  		prefix = (struct in6_addr *)rinfo->prefix;
  	else {
  		/* this function is safe */
  		ipv6_addr_prefix(&prefix_buf,
  				 (struct in6_addr *)rinfo->prefix,
  				 rinfo->prefix_len);
  		prefix = &prefix_buf;
  	}
efa2cea0d   Daniel Lezcano   [NETNS][IPV6] rou...
559
560
  	rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, gwaddr,
  				dev->ifindex);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
561
562
  
  	if (rt && !lifetime) {
e0a1ad73d   Thomas Graf   [IPv6] route: Sim...
563
  		ip6_del_rt(rt);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
564
565
566
567
  		rt = NULL;
  	}
  
  	if (!rt && lifetime)
efa2cea0d   Daniel Lezcano   [NETNS][IPV6] rou...
568
  		rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
569
570
571
572
573
574
  					pref);
  	else if (rt)
  		rt->rt6i_flags = RTF_ROUTEINFO |
  				 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
  
  	if (rt) {
4bed72e4f   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
575
  		if (!addrconf_finite_timeout(lifetime)) {
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
576
577
  			rt->rt6i_flags &= ~RTF_EXPIRES;
  		} else {
d19185428   David S. Miller   ipv6: Kill rt6i_d...
578
  			rt->dst.expires = jiffies + HZ * lifetime;
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
579
580
  			rt->rt6i_flags |= RTF_EXPIRES;
  		}
d8d1f30b9   Changli Gao   net-next: remove ...
581
  		dst_release(&rt->dst);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
582
583
584
585
  	}
  	return 0;
  }
  #endif
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
586
  #define BACKTRACK(__net, saddr)			\
982f56f3a   YOSHIFUJI Hideaki   [IPV6] ROUTE: Sea...
587
  do { \
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
588
  	if (rt == __net->ipv6.ip6_null_entry) {	\
982f56f3a   YOSHIFUJI Hideaki   [IPV6] ROUTE: Sea...
589
  		struct fib6_node *pn; \
e0eda7bba   Ville Nuorvala   [IPV6]: Clean up ...
590
  		while (1) { \
982f56f3a   YOSHIFUJI Hideaki   [IPV6] ROUTE: Sea...
591
592
593
594
  			if (fn->fn_flags & RTN_TL_ROOT) \
  				goto out; \
  			pn = fn->parent; \
  			if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn) \
8bce65b95   Kim Nordlund   [IPV6]: Make fib6...
595
  				fn = fib6_lookup(FIB6_SUBTREE(pn), NULL, saddr); \
982f56f3a   YOSHIFUJI Hideaki   [IPV6] ROUTE: Sea...
596
597
598
599
  			else \
  				fn = pn; \
  			if (fn->fn_flags & RTN_RTINFO) \
  				goto restart; \
c71099acc   Thomas Graf   [IPV6]: Multiple ...
600
  		} \
c71099acc   Thomas Graf   [IPV6]: Multiple ...
601
  	} \
383084739   David S. Miller   ipv6: Various cle...
602
  } while (0)
c71099acc   Thomas Graf   [IPV6]: Multiple ...
603

8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
604
605
  static struct rt6_info *ip6_pol_route_lookup(struct net *net,
  					     struct fib6_table *table,
4c9483b2f   David S. Miller   ipv6: Convert to ...
606
  					     struct flowi6 *fl6, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607
608
609
  {
  	struct fib6_node *fn;
  	struct rt6_info *rt;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
610
  	read_lock_bh(&table->tb6_lock);
4c9483b2f   David S. Miller   ipv6: Convert to ...
611
  	fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
612
613
  restart:
  	rt = fn->leaf;
4c9483b2f   David S. Miller   ipv6: Convert to ...
614
615
  	rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags);
  	BACKTRACK(net, &fl6->saddr);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
616
  out:
d8d1f30b9   Changli Gao   net-next: remove ...
617
  	dst_use(&rt->dst, jiffies);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
618
  	read_unlock_bh(&table->tb6_lock);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
619
620
621
  	return rt;
  
  }
ea6e574e3   Florian Westphal   ipv6: add ip6_rou...
622
623
624
625
626
627
  struct dst_entry * ip6_route_lookup(struct net *net, struct flowi6 *fl6,
  				    int flags)
  {
  	return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup);
  }
  EXPORT_SYMBOL_GPL(ip6_route_lookup);
9acd9f3ae   YOSHIFUJI Hideaki   [IPV6]: Make addr...
628
629
  struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
  			    const struct in6_addr *saddr, int oif, int strict)
c71099acc   Thomas Graf   [IPV6]: Multiple ...
630
  {
4c9483b2f   David S. Miller   ipv6: Convert to ...
631
632
633
  	struct flowi6 fl6 = {
  		.flowi6_oif = oif,
  		.daddr = *daddr,
c71099acc   Thomas Graf   [IPV6]: Multiple ...
634
635
  	};
  	struct dst_entry *dst;
77d16f450   YOSHIFUJI Hideaki   [IPV6] ROUTE: Uni...
636
  	int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
637

adaa70bbd   Thomas Graf   [IPv6] rules: Use...
638
  	if (saddr) {
4c9483b2f   David S. Miller   ipv6: Convert to ...
639
  		memcpy(&fl6.saddr, saddr, sizeof(*saddr));
adaa70bbd   Thomas Graf   [IPv6] rules: Use...
640
641
  		flags |= RT6_LOOKUP_F_HAS_SADDR;
  	}
4c9483b2f   David S. Miller   ipv6: Convert to ...
642
  	dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
643
644
645
646
  	if (dst->error == 0)
  		return (struct rt6_info *) dst;
  
  	dst_release(dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
648
  	return NULL;
  }
7159039a1   YOSHIFUJI Hideaki   [IPV6]: Decentral...
649
  EXPORT_SYMBOL(rt6_lookup);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
650
  /* ip6_ins_rt is called with FREE table->tb6_lock.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
652
653
654
     It takes new route entry, the addition fails by any reason the
     route is freed. In any case, if caller does not hold it, it may
     be destroyed.
   */
86872cb57   Thomas Graf   [IPv6] route: FIB...
655
  static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
657
  {
  	int err;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
658
  	struct fib6_table *table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659

c71099acc   Thomas Graf   [IPV6]: Multiple ...
660
661
  	table = rt->rt6i_table;
  	write_lock_bh(&table->tb6_lock);
86872cb57   Thomas Graf   [IPv6] route: FIB...
662
  	err = fib6_add(&table->tb6_root, rt, info);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
663
  	write_unlock_bh(&table->tb6_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
665
666
  
  	return err;
  }
40e22e8f3   Thomas Graf   [IPv6] route: Sim...
667
668
  int ip6_ins_rt(struct rt6_info *rt)
  {
4d1169c1e   Denis V. Lunev   [NETNS]: Add netn...
669
  	struct nl_info info = {
d19185428   David S. Miller   ipv6: Kill rt6i_d...
670
  		.nl_net = dev_net(rt->dst.dev),
4d1169c1e   Denis V. Lunev   [NETNS]: Add netn...
671
  	};
528c4ceb4   Denis V. Lunev   [IPV6]: Always pa...
672
  	return __ip6_ins_rt(rt, &info);
40e22e8f3   Thomas Graf   [IPv6] route: Sim...
673
  }
21efcfa0f   Eric Dumazet   ipv6: unshare ine...
674
675
  static struct rt6_info *rt6_alloc_cow(const struct rt6_info *ort,
  				      const struct in6_addr *daddr,
b71d1d426   Eric Dumazet   inet: constify ip...
676
  				      const struct in6_addr *saddr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
679
680
681
682
  	struct rt6_info *rt;
  
  	/*
  	 *	Clone the route.
  	 */
21efcfa0f   Eric Dumazet   ipv6: unshare ine...
683
  	rt = ip6_rt_copy(ort, daddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684
685
  
  	if (rt) {
14deae415   David S. Miller   ipv6: Fix sporadi...
686
  		int attempts = !in_softirq();
383084739   David S. Miller   ipv6: Various cle...
687
  		if (!(rt->rt6i_flags & RTF_GATEWAY)) {
bb3c36863   David S. Miller   ipv6: Check dest ...
688
  			if (ort->rt6i_dst.plen != 128 &&
21efcfa0f   Eric Dumazet   ipv6: unshare ine...
689
  			    ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
58c4fb86e   YOSHIFUJI Hideaki   [IPV6]: Flag RTF_...
690
  				rt->rt6i_flags |= RTF_ANYCAST;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
691
  			rt->rt6i_gateway = *daddr;
58c4fb86e   YOSHIFUJI Hideaki   [IPV6]: Flag RTF_...
692
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694
  		rt->rt6i_flags |= RTF_CACHE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
696
697
  
  #ifdef CONFIG_IPV6_SUBTREES
  		if (rt->rt6i_src.plen && saddr) {
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
698
  			rt->rt6i_src.addr = *saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
700
701
  			rt->rt6i_src.plen = 128;
  		}
  #endif
14deae415   David S. Miller   ipv6: Fix sporadi...
702
  	retry:
8ade06c61   David S. Miller   ipv6: Fix neigh l...
703
  		if (rt6_bind_neighbour(rt, rt->dst.dev)) {
d19185428   David S. Miller   ipv6: Kill rt6i_d...
704
  			struct net *net = dev_net(rt->dst.dev);
14deae415   David S. Miller   ipv6: Fix sporadi...
705
706
707
708
709
710
711
712
  			int saved_rt_min_interval =
  				net->ipv6.sysctl.ip6_rt_gc_min_interval;
  			int saved_rt_elasticity =
  				net->ipv6.sysctl.ip6_rt_gc_elasticity;
  
  			if (attempts-- > 0) {
  				net->ipv6.sysctl.ip6_rt_gc_elasticity = 1;
  				net->ipv6.sysctl.ip6_rt_gc_min_interval = 0;
86393e52c   Alexey Dobriyan   netns: embed ip6_...
713
  				ip6_dst_gc(&net->ipv6.ip6_dst_ops);
14deae415   David S. Miller   ipv6: Fix sporadi...
714
715
716
717
718
719
720
721
722
723
  
  				net->ipv6.sysctl.ip6_rt_gc_elasticity =
  					saved_rt_elasticity;
  				net->ipv6.sysctl.ip6_rt_gc_min_interval =
  					saved_rt_min_interval;
  				goto retry;
  			}
  
  			if (net_ratelimit())
  				printk(KERN_WARNING
7e1b33e5e   Ulrich Weber   ipv6: add IPv6 to...
724
725
  				       "ipv6: Neighbour table overflow.
  ");
d8d1f30b9   Changli Gao   net-next: remove ...
726
  			dst_free(&rt->dst);
14deae415   David S. Miller   ipv6: Fix sporadi...
727
728
  			return NULL;
  		}
95a9a5ba0   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Sp...
729
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730

95a9a5ba0   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Sp...
731
732
  	return rt;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733

21efcfa0f   Eric Dumazet   ipv6: unshare ine...
734
735
  static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort,
  					const struct in6_addr *daddr)
299d99390   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
736
  {
21efcfa0f   Eric Dumazet   ipv6: unshare ine...
737
  	struct rt6_info *rt = ip6_rt_copy(ort, daddr);
299d99390   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
738
  	if (rt) {
299d99390   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
739
  		rt->rt6i_flags |= RTF_CACHE;
272174550   David Miller   net: Rename dst_g...
740
  		dst_set_neighbour(&rt->dst, neigh_clone(dst_get_neighbour_noref_raw(&ort->dst)));
299d99390   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
741
742
743
  	}
  	return rt;
  }
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
744
  static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif,
4c9483b2f   David S. Miller   ipv6: Convert to ...
745
  				      struct flowi6 *fl6, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
747
  {
  	struct fib6_node *fn;
519fbd871   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Cl...
748
  	struct rt6_info *rt, *nrt;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
749
  	int strict = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
  	int attempts = 3;
519fbd871   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Cl...
751
  	int err;
53b7997fd   YOSHIFUJI Hideaki   ipv6 netns: Make ...
752
  	int reachable = net->ipv6.devconf_all->forwarding ? 0 : RT6_LOOKUP_F_REACHABLE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753

77d16f450   YOSHIFUJI Hideaki   [IPV6] ROUTE: Uni...
754
  	strict |= flags & RT6_LOOKUP_F_IFACE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
756
  
  relookup:
c71099acc   Thomas Graf   [IPV6]: Multiple ...
757
  	read_lock_bh(&table->tb6_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758

8238dd069   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ha...
759
  restart_2:
4c9483b2f   David S. Miller   ipv6: Convert to ...
760
  	fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
761
762
  
  restart:
4acad72de   Pavel Emelyanov   [IPV6]: Consolida...
763
  	rt = rt6_select(fn, oif, strict | reachable);
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
764

4c9483b2f   David S. Miller   ipv6: Convert to ...
765
  	BACKTRACK(net, &fl6->saddr);
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
766
  	if (rt == net->ipv6.ip6_null_entry ||
8238dd069   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ha...
767
  	    rt->rt6i_flags & RTF_CACHE)
1ddef044e   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Cl...
768
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769

d8d1f30b9   Changli Gao   net-next: remove ...
770
  	dst_hold(&rt->dst);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
771
  	read_unlock_bh(&table->tb6_lock);
fb9de91ea   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Cl...
772

272174550   David Miller   net: Rename dst_g...
773
  	if (!dst_get_neighbour_noref_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP))
4c9483b2f   David S. Miller   ipv6: Convert to ...
774
  		nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr);
7343ff31e   David S. Miller   ipv6: Don't creat...
775
  	else if (!(rt->dst.flags & DST_HOST))
4c9483b2f   David S. Miller   ipv6: Convert to ...
776
  		nrt = rt6_alloc_clone(rt, &fl6->daddr);
7343ff31e   David S. Miller   ipv6: Don't creat...
777
778
  	else
  		goto out2;
e40cf3533   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Co...
779

d8d1f30b9   Changli Gao   net-next: remove ...
780
  	dst_release(&rt->dst);
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
781
  	rt = nrt ? : net->ipv6.ip6_null_entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
782

d8d1f30b9   Changli Gao   net-next: remove ...
783
  	dst_hold(&rt->dst);
519fbd871   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Cl...
784
  	if (nrt) {
40e22e8f3   Thomas Graf   [IPv6] route: Sim...
785
  		err = ip6_ins_rt(nrt);
519fbd871   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Cl...
786
  		if (!err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
787
  			goto out2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789

519fbd871   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Cl...
790
791
792
793
  	if (--attempts <= 0)
  		goto out2;
  
  	/*
c71099acc   Thomas Graf   [IPV6]: Multiple ...
794
  	 * Race condition! In the gap, when table->tb6_lock was
519fbd871   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Cl...
795
796
  	 * released someone could insert this route.  Relookup.
  	 */
d8d1f30b9   Changli Gao   net-next: remove ...
797
  	dst_release(&rt->dst);
519fbd871   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Cl...
798
799
800
  	goto relookup;
  
  out:
8238dd069   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ha...
801
802
803
804
  	if (reachable) {
  		reachable = 0;
  		goto restart_2;
  	}
d8d1f30b9   Changli Gao   net-next: remove ...
805
  	dst_hold(&rt->dst);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
806
  	read_unlock_bh(&table->tb6_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
  out2:
d8d1f30b9   Changli Gao   net-next: remove ...
808
809
  	rt->dst.lastuse = jiffies;
  	rt->dst.__use++;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
810
811
  
  	return rt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
812
  }
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
813
  static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
4c9483b2f   David S. Miller   ipv6: Convert to ...
814
  					    struct flowi6 *fl6, int flags)
4acad72de   Pavel Emelyanov   [IPV6]: Consolida...
815
  {
4c9483b2f   David S. Miller   ipv6: Convert to ...
816
  	return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags);
4acad72de   Pavel Emelyanov   [IPV6]: Consolida...
817
  }
c71099acc   Thomas Graf   [IPV6]: Multiple ...
818
819
  void ip6_route_input(struct sk_buff *skb)
  {
b71d1d426   Eric Dumazet   inet: constify ip...
820
  	const struct ipv6hdr *iph = ipv6_hdr(skb);
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
821
  	struct net *net = dev_net(skb->dev);
adaa70bbd   Thomas Graf   [IPv6] rules: Use...
822
  	int flags = RT6_LOOKUP_F_HAS_SADDR;
4c9483b2f   David S. Miller   ipv6: Convert to ...
823
824
825
826
  	struct flowi6 fl6 = {
  		.flowi6_iif = skb->dev->ifindex,
  		.daddr = iph->daddr,
  		.saddr = iph->saddr,
383084739   David S. Miller   ipv6: Various cle...
827
  		.flowlabel = (* (__be32 *) iph) & IPV6_FLOWINFO_MASK,
4c9483b2f   David S. Miller   ipv6: Convert to ...
828
829
  		.flowi6_mark = skb->mark,
  		.flowi6_proto = iph->nexthdr,
c71099acc   Thomas Graf   [IPV6]: Multiple ...
830
  	};
adaa70bbd   Thomas Graf   [IPv6] rules: Use...
831

1d6e55f19   Thomas Goff   IPv6: Fix multica...
832
  	if (rt6_need_strict(&iph->daddr) && skb->dev->type != ARPHRD_PIMREG)
adaa70bbd   Thomas Graf   [IPv6] rules: Use...
833
  		flags |= RT6_LOOKUP_F_IFACE;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
834

4c9483b2f   David S. Miller   ipv6: Convert to ...
835
  	skb_dst_set(skb, fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_input));
c71099acc   Thomas Graf   [IPV6]: Multiple ...
836
  }
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
837
  static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
4c9483b2f   David S. Miller   ipv6: Convert to ...
838
  					     struct flowi6 *fl6, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
839
  {
4c9483b2f   David S. Miller   ipv6: Convert to ...
840
  	return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
841
  }
9c7a4f9ce   Florian Westphal   ipv6: ip6_route_o...
842
  struct dst_entry * ip6_route_output(struct net *net, const struct sock *sk,
4c9483b2f   David S. Miller   ipv6: Convert to ...
843
  				    struct flowi6 *fl6)
c71099acc   Thomas Graf   [IPV6]: Multiple ...
844
845
  {
  	int flags = 0;
4c9483b2f   David S. Miller   ipv6: Convert to ...
846
  	if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr))
77d16f450   YOSHIFUJI Hideaki   [IPV6] ROUTE: Uni...
847
  		flags |= RT6_LOOKUP_F_IFACE;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
848

4c9483b2f   David S. Miller   ipv6: Convert to ...
849
  	if (!ipv6_addr_any(&fl6->saddr))
adaa70bbd   Thomas Graf   [IPv6] rules: Use...
850
  		flags |= RT6_LOOKUP_F_HAS_SADDR;
0c9a2ac1f   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Optmize tra...
851
852
  	else if (sk)
  		flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
adaa70bbd   Thomas Graf   [IPv6] rules: Use...
853

4c9483b2f   David S. Miller   ipv6: Convert to ...
854
  	return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
855
  }
7159039a1   YOSHIFUJI Hideaki   [IPV6]: Decentral...
856
  EXPORT_SYMBOL(ip6_route_output);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
857

2774c131b   David S. Miller   xfrm: Handle blac...
858
  struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
14e50e57a   David S. Miller   [XFRM]: Allow pac...
859
  {
5c1e6aa30   David S. Miller   net: Make dst_all...
860
  	struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
14e50e57a   David S. Miller   [XFRM]: Allow pac...
861
  	struct dst_entry *new = NULL;
5c1e6aa30   David S. Miller   net: Make dst_all...
862
  	rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, 0, 0);
14e50e57a   David S. Miller   [XFRM]: Allow pac...
863
  	if (rt) {
cf9116622   David S. Miller   net: Use non-zero...
864
  		memset(&rt->rt6i_table, 0, sizeof(*rt) - sizeof(struct dst_entry));
d8d1f30b9   Changli Gao   net-next: remove ...
865
  		new = &rt->dst;
14e50e57a   David S. Miller   [XFRM]: Allow pac...
866

14e50e57a   David S. Miller   [XFRM]: Allow pac...
867
  		new->__use = 1;
352e512c3   Herbert Xu   [NET]: Eliminate ...
868
869
  		new->input = dst_discard;
  		new->output = dst_discard;
14e50e57a   David S. Miller   [XFRM]: Allow pac...
870

21efcfa0f   Eric Dumazet   ipv6: unshare ine...
871
872
873
874
  		if (dst_metrics_read_only(&ort->dst))
  			new->_metrics = ort->dst._metrics;
  		else
  			dst_copy_metrics(new, &ort->dst);
14e50e57a   David S. Miller   [XFRM]: Allow pac...
875
876
877
  		rt->rt6i_idev = ort->rt6i_idev;
  		if (rt->rt6i_idev)
  			in6_dev_hold(rt->rt6i_idev);
d19185428   David S. Miller   ipv6: Kill rt6i_d...
878
  		rt->dst.expires = 0;
14e50e57a   David S. Miller   [XFRM]: Allow pac...
879

4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
880
  		rt->rt6i_gateway = ort->rt6i_gateway;
14e50e57a   David S. Miller   [XFRM]: Allow pac...
881
882
883
884
885
886
887
888
889
890
  		rt->rt6i_flags = ort->rt6i_flags & ~RTF_EXPIRES;
  		rt->rt6i_metric = 0;
  
  		memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
  #ifdef CONFIG_IPV6_SUBTREES
  		memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
  #endif
  
  		dst_free(new);
  	}
69ead7afd   David S. Miller   ipv6: Normalize a...
891
892
  	dst_release(dst_orig);
  	return new ? new : ERR_PTR(-ENOMEM);
14e50e57a   David S. Miller   [XFRM]: Allow pac...
893
  }
14e50e57a   David S. Miller   [XFRM]: Allow pac...
894

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
896
897
898
899
900
901
902
903
  /*
   *	Destination cache support functions
   */
  
  static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
  {
  	struct rt6_info *rt;
  
  	rt = (struct rt6_info *) dst;
6431cbc25   David S. Miller   inet: Create a me...
904
905
906
907
908
909
  	if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) {
  		if (rt->rt6i_peer_genid != rt6_peer_genid()) {
  			if (!rt->rt6i_peer)
  				rt6_bind_peer(rt, 0);
  			rt->rt6i_peer_genid = rt6_peer_genid();
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910
  		return dst;
6431cbc25   David S. Miller   inet: Create a me...
911
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
913
914
915
916
917
918
919
  	return NULL;
  }
  
  static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
  {
  	struct rt6_info *rt = (struct rt6_info *) dst;
  
  	if (rt) {
54c1a859e   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Don't drop ...
920
921
922
923
924
925
  		if (rt->rt6i_flags & RTF_CACHE) {
  			if (rt6_check_expired(rt)) {
  				ip6_del_rt(rt);
  				dst = NULL;
  			}
  		} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
926
  			dst_release(dst);
54c1a859e   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Don't drop ...
927
928
  			dst = NULL;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929
  	}
54c1a859e   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Don't drop ...
930
  	return dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
931
932
933
934
935
  }
  
  static void ip6_link_failure(struct sk_buff *skb)
  {
  	struct rt6_info *rt;
3ffe533c8   Alexey Dobriyan   ipv6: drop unused...
936
  	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
937

adf30907d   Eric Dumazet   net: skb->dst acc...
938
  	rt = (struct rt6_info *) skb_dst(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
  	if (rt) {
383084739   David S. Miller   ipv6: Various cle...
940
  		if (rt->rt6i_flags & RTF_CACHE) {
d8d1f30b9   Changli Gao   net-next: remove ...
941
  			dst_set_expires(&rt->dst, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
942
943
944
945
946
947
948
949
950
951
952
953
954
  			rt->rt6i_flags |= RTF_EXPIRES;
  		} else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT))
  			rt->rt6i_node->fn_sernum = -1;
  	}
  }
  
  static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
  {
  	struct rt6_info *rt6 = (struct rt6_info*)dst;
  
  	if (mtu < dst_mtu(dst) && rt6->rt6i_dst.plen == 128) {
  		rt6->rt6i_flags |= RTF_MODIFIED;
  		if (mtu < IPV6_MIN_MTU) {
defb3519a   David S. Miller   net: Abstract awa...
955
  			u32 features = dst_metric(dst, RTAX_FEATURES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
956
  			mtu = IPV6_MIN_MTU;
defb3519a   David S. Miller   net: Abstract awa...
957
958
  			features |= RTAX_FEATURE_ALLFRAG;
  			dst_metric_set(dst, RTAX_FEATURES, features);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
959
  		}
defb3519a   David S. Miller   net: Abstract awa...
960
  		dst_metric_set(dst, RTAX_MTU, mtu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
961
962
  	}
  }
0dbaee3b3   David S. Miller   net: Abstract def...
963
  static unsigned int ip6_default_advmss(const struct dst_entry *dst)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
964
  {
0dbaee3b3   David S. Miller   net: Abstract def...
965
966
967
  	struct net_device *dev = dst->dev;
  	unsigned int mtu = dst_mtu(dst);
  	struct net *net = dev_net(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
968
  	mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
969
970
  	if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
  		mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
971
972
  
  	/*
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
973
974
975
  	 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
  	 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
  	 * IPV6_MAXPLEN is also valid and means: "any MSS,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976
977
978
979
980
981
  	 * rely only on pmtu discovery"
  	 */
  	if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
  		mtu = IPV6_MAXPLEN;
  	return mtu;
  }
ebb762f27   Steffen Klassert   net: Rename the d...
982
  static unsigned int ip6_mtu(const struct dst_entry *dst)
d33e45533   David S. Miller   net: Abstract def...
983
  {
d33e45533   David S. Miller   net: Abstract def...
984
  	struct inet6_dev *idev;
618f9bc74   Steffen Klassert   net: Move mtu han...
985
986
987
988
989
990
  	unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
  
  	if (mtu)
  		return mtu;
  
  	mtu = IPV6_MIN_MTU;
d33e45533   David S. Miller   net: Abstract def...
991
992
993
994
995
996
997
998
999
  
  	rcu_read_lock();
  	idev = __in6_dev_get(dst->dev);
  	if (idev)
  		mtu = idev->cnf.mtu6;
  	rcu_read_unlock();
  
  	return mtu;
  }
3b00944c5   YOSHIFUJI Hideaki   [IPV6]: Make ndis...
1000
1001
  static struct dst_entry *icmp6_dst_gc_list;
  static DEFINE_SPINLOCK(icmp6_dst_lock);
5d0bbeeb1   Thomas Graf   [IPV6]: Remove nd...
1002

3b00944c5   YOSHIFUJI Hideaki   [IPV6]: Make ndis...
1003
  struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1004
  				  struct neighbour *neigh,
87a115783   David S. Miller   ipv6: Move xfrm_l...
1005
  				  struct flowi6 *fl6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006
  {
87a115783   David S. Miller   ipv6: Move xfrm_l...
1007
  	struct dst_entry *dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1008
1009
  	struct rt6_info *rt;
  	struct inet6_dev *idev = in6_dev_get(dev);
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1010
  	struct net *net = dev_net(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1011

383084739   David S. Miller   ipv6: Various cle...
1012
  	if (unlikely(!idev))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1013
  		return NULL;
957c665f3   David S. Miller   ipv6: Don't put a...
1014
  	rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, dev, 0);
383084739   David S. Miller   ipv6: Various cle...
1015
  	if (unlikely(!rt)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1016
  		in6_dev_put(idev);
87a115783   David S. Miller   ipv6: Move xfrm_l...
1017
  		dst = ERR_PTR(-ENOMEM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1018
1019
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1020
1021
  	if (neigh)
  		neigh_hold(neigh);
14deae415   David S. Miller   ipv6: Fix sporadi...
1022
  	else {
f83c7790d   David S. Miller   ipv6: Create fast...
1023
  		neigh = ip6_neigh_lookup(&rt->dst, &fl6->daddr);
b43faac69   David S. Miller   ipv6: If neigh lo...
1024
1025
1026
1027
  		if (IS_ERR(neigh)) {
  			dst_free(&rt->dst);
  			return ERR_CAST(neigh);
  		}
14deae415   David S. Miller   ipv6: Fix sporadi...
1028
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1029

8e2ec6391   Yan, Zheng   ipv6: don't use i...
1030
1031
  	rt->dst.flags |= DST_HOST;
  	rt->dst.output  = ip6_output;
69cce1d14   David S. Miller   net: Abstract dst...
1032
  	dst_set_neighbour(&rt->dst, neigh);
d8d1f30b9   Changli Gao   net-next: remove ...
1033
  	atomic_set(&rt->dst.__refcnt, 1);
87a115783   David S. Miller   ipv6: Move xfrm_l...
1034
  	rt->rt6i_dst.addr = fl6->daddr;
8e2ec6391   Yan, Zheng   ipv6: don't use i...
1035
1036
  	rt->rt6i_dst.plen = 128;
  	rt->rt6i_idev     = idev;
7011687f0   Gao feng   ipv6: fix route e...
1037
  	dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1038

3b00944c5   YOSHIFUJI Hideaki   [IPV6]: Make ndis...
1039
  	spin_lock_bh(&icmp6_dst_lock);
d8d1f30b9   Changli Gao   net-next: remove ...
1040
1041
  	rt->dst.next = icmp6_dst_gc_list;
  	icmp6_dst_gc_list = &rt->dst;
3b00944c5   YOSHIFUJI Hideaki   [IPV6]: Make ndis...
1042
  	spin_unlock_bh(&icmp6_dst_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1043

5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
1044
  	fib6_force_start_gc(net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1045

87a115783   David S. Miller   ipv6: Move xfrm_l...
1046
  	dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1047
  out:
87a115783   David S. Miller   ipv6: Move xfrm_l...
1048
  	return dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1049
  }
3d0f24a74   Stephen Hemminger   ipv6: icmp6_dst_g...
1050
  int icmp6_dst_gc(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1051
  {
e9476e95d   Hagen Paul Pfeifer   ipv6: variable ne...
1052
  	struct dst_entry *dst, **pprev;
3d0f24a74   Stephen Hemminger   ipv6: icmp6_dst_g...
1053
  	int more = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1054

3b00944c5   YOSHIFUJI Hideaki   [IPV6]: Make ndis...
1055
1056
  	spin_lock_bh(&icmp6_dst_lock);
  	pprev = &icmp6_dst_gc_list;
5d0bbeeb1   Thomas Graf   [IPV6]: Remove nd...
1057

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1058
1059
1060
1061
  	while ((dst = *pprev) != NULL) {
  		if (!atomic_read(&dst->__refcnt)) {
  			*pprev = dst->next;
  			dst_free(dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1062
1063
  		} else {
  			pprev = &dst->next;
3d0f24a74   Stephen Hemminger   ipv6: icmp6_dst_g...
1064
  			++more;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1065
1066
  		}
  	}
3b00944c5   YOSHIFUJI Hideaki   [IPV6]: Make ndis...
1067
  	spin_unlock_bh(&icmp6_dst_lock);
5d0bbeeb1   Thomas Graf   [IPV6]: Remove nd...
1068

3d0f24a74   Stephen Hemminger   ipv6: icmp6_dst_g...
1069
  	return more;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1070
  }
1e493d194   David S. Miller   ipv6: On interfac...
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
  static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg),
  			    void *arg)
  {
  	struct dst_entry *dst, **pprev;
  
  	spin_lock_bh(&icmp6_dst_lock);
  	pprev = &icmp6_dst_gc_list;
  	while ((dst = *pprev) != NULL) {
  		struct rt6_info *rt = (struct rt6_info *) dst;
  		if (func(rt, arg)) {
  			*pprev = dst->next;
  			dst_free(dst);
  		} else {
  			pprev = &dst->next;
  		}
  	}
  	spin_unlock_bh(&icmp6_dst_lock);
  }
569d36452   Daniel Lezcano   [NETNS][DST] dst:...
1089
  static int ip6_dst_gc(struct dst_ops *ops)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1090
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1091
  	unsigned long now = jiffies;
86393e52c   Alexey Dobriyan   netns: embed ip6_...
1092
  	struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
7019b78e1   Daniel Lezcano   [NETNS][IPV6] rou...
1093
1094
1095
1096
1097
  	int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
  	int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
  	int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
  	int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
  	unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
fc66f95c6   Eric Dumazet   net dst: use a pe...
1098
  	int entries;
7019b78e1   Daniel Lezcano   [NETNS][IPV6] rou...
1099

fc66f95c6   Eric Dumazet   net dst: use a pe...
1100
  	entries = dst_entries_get_fast(ops);
7019b78e1   Daniel Lezcano   [NETNS][IPV6] rou...
1101
  	if (time_after(rt_last_gc + rt_min_interval, now) &&
fc66f95c6   Eric Dumazet   net dst: use a pe...
1102
  	    entries <= rt_max_size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1103
  		goto out;
6891a346c   Benjamin Thery   [NETNS][IPV6] rou...
1104
1105
1106
  	net->ipv6.ip6_rt_gc_expire++;
  	fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net);
  	net->ipv6.ip6_rt_last_gc = now;
fc66f95c6   Eric Dumazet   net dst: use a pe...
1107
1108
  	entries = dst_entries_get_slow(ops);
  	if (entries < ops->gc_thresh)
7019b78e1   Daniel Lezcano   [NETNS][IPV6] rou...
1109
  		net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1110
  out:
7019b78e1   Daniel Lezcano   [NETNS][IPV6] rou...
1111
  	net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
fc66f95c6   Eric Dumazet   net dst: use a pe...
1112
  	return entries > rt_max_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1113
1114
1115
1116
1117
1118
1119
  }
  
  /* Clean host part of a prefix. Not necessary in radix tree,
     but results in cleaner routing tables.
  
     Remove it only when all the things will work!
   */
6b75d0908   YOSHIFUJI Hideaki   [IPV6]: Optimize ...
1120
  int ip6_dst_hoplimit(struct dst_entry *dst)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1121
  {
5170ae824   David S. Miller   net: Abstract RTA...
1122
  	int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT);
a02e4b7da   David S. Miller   ipv6: Demark defa...
1123
  	if (hoplimit == 0) {
6b75d0908   YOSHIFUJI Hideaki   [IPV6]: Optimize ...
1124
  		struct net_device *dev = dst->dev;
c68f24cc3   Eric Dumazet   ipv6: RCU changes...
1125
1126
1127
1128
1129
  		struct inet6_dev *idev;
  
  		rcu_read_lock();
  		idev = __in6_dev_get(dev);
  		if (idev)
6b75d0908   YOSHIFUJI Hideaki   [IPV6]: Optimize ...
1130
  			hoplimit = idev->cnf.hop_limit;
c68f24cc3   Eric Dumazet   ipv6: RCU changes...
1131
  		else
53b7997fd   YOSHIFUJI Hideaki   ipv6 netns: Make ...
1132
  			hoplimit = dev_net(dev)->ipv6.devconf_all->hop_limit;
c68f24cc3   Eric Dumazet   ipv6: RCU changes...
1133
  		rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1134
1135
1136
  	}
  	return hoplimit;
  }
abbf46ae0   David S. Miller   ipv6: Use ip6_dst...
1137
  EXPORT_SYMBOL(ip6_dst_hoplimit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1138
1139
1140
1141
  
  /*
   *
   */
86872cb57   Thomas Graf   [IPv6] route: FIB...
1142
  int ip6_route_add(struct fib6_config *cfg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1143
1144
  {
  	int err;
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
1145
  	struct net *net = cfg->fc_nlinfo.nl_net;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1146
1147
1148
  	struct rt6_info *rt = NULL;
  	struct net_device *dev = NULL;
  	struct inet6_dev *idev = NULL;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1149
  	struct fib6_table *table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150
  	int addr_type;
86872cb57   Thomas Graf   [IPv6] route: FIB...
1151
  	if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1152
1153
  		return -EINVAL;
  #ifndef CONFIG_IPV6_SUBTREES
86872cb57   Thomas Graf   [IPv6] route: FIB...
1154
  	if (cfg->fc_src_len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1155
1156
  		return -EINVAL;
  #endif
86872cb57   Thomas Graf   [IPv6] route: FIB...
1157
  	if (cfg->fc_ifindex) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1158
  		err = -ENODEV;
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
1159
  		dev = dev_get_by_index(net, cfg->fc_ifindex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1160
1161
1162
1163
1164
1165
  		if (!dev)
  			goto out;
  		idev = in6_dev_get(dev);
  		if (!idev)
  			goto out;
  	}
86872cb57   Thomas Graf   [IPv6] route: FIB...
1166
1167
  	if (cfg->fc_metric == 0)
  		cfg->fc_metric = IP6_RT_PRIO_USER;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1168

d71314b4a   Matti Vaittinen   IPv6 routing, NLM...
1169
  	err = -ENOBUFS;
383084739   David S. Miller   ipv6: Various cle...
1170
1171
  	if (cfg->fc_nlinfo.nlh &&
  	    !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
d71314b4a   Matti Vaittinen   IPv6 routing, NLM...
1172
  		table = fib6_get_table(net, cfg->fc_table);
383084739   David S. Miller   ipv6: Various cle...
1173
  		if (!table) {
d71314b4a   Matti Vaittinen   IPv6 routing, NLM...
1174
1175
1176
1177
1178
1179
1180
  			printk(KERN_WARNING "IPv6: NLM_F_CREATE should be specified when creating new route
  ");
  			table = fib6_new_table(net, cfg->fc_table);
  		}
  	} else {
  		table = fib6_new_table(net, cfg->fc_table);
  	}
383084739   David S. Miller   ipv6: Various cle...
1181
1182
  
  	if (!table)
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1183
  		goto out;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1184

957c665f3   David S. Miller   ipv6: Don't put a...
1185
  	rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, NULL, DST_NOCOUNT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1186

383084739   David S. Miller   ipv6: Various cle...
1187
  	if (!rt) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1188
1189
1190
  		err = -ENOMEM;
  		goto out;
  	}
d8d1f30b9   Changli Gao   net-next: remove ...
1191
  	rt->dst.obsolete = -1;
d19185428   David S. Miller   ipv6: Kill rt6i_d...
1192
  	rt->dst.expires = (cfg->fc_flags & RTF_EXPIRES) ?
6f704992d   YOSHIFUJI Hideaki   ipv6 addrconf: Al...
1193
1194
  				jiffies + clock_t_to_jiffies(cfg->fc_expires) :
  				0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1195

86872cb57   Thomas Graf   [IPv6] route: FIB...
1196
1197
1198
1199
1200
  	if (cfg->fc_protocol == RTPROT_UNSPEC)
  		cfg->fc_protocol = RTPROT_BOOT;
  	rt->rt6i_protocol = cfg->fc_protocol;
  
  	addr_type = ipv6_addr_type(&cfg->fc_dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1201
1202
  
  	if (addr_type & IPV6_ADDR_MULTICAST)
d8d1f30b9   Changli Gao   net-next: remove ...
1203
  		rt->dst.input = ip6_mc_input;
ab79ad14a   Maciej Żenczykowski   ipv6: Implement A...
1204
1205
  	else if (cfg->fc_flags & RTF_LOCAL)
  		rt->dst.input = ip6_input;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1206
  	else
d8d1f30b9   Changli Gao   net-next: remove ...
1207
  		rt->dst.input = ip6_forward;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1208

d8d1f30b9   Changli Gao   net-next: remove ...
1209
  	rt->dst.output = ip6_output;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1210

86872cb57   Thomas Graf   [IPv6] route: FIB...
1211
1212
  	ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
  	rt->rt6i_dst.plen = cfg->fc_dst_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1213
  	if (rt->rt6i_dst.plen == 128)
11d53b499   David S. Miller   ipv6: Don't chang...
1214
  	       rt->dst.flags |= DST_HOST;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1215

8e2ec6391   Yan, Zheng   ipv6: don't use i...
1216
1217
1218
1219
1220
1221
1222
1223
  	if (!(rt->dst.flags & DST_HOST) && cfg->fc_mx) {
  		u32 *metrics = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
  		if (!metrics) {
  			err = -ENOMEM;
  			goto out;
  		}
  		dst_init_metrics(&rt->dst, metrics, 0);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1224
  #ifdef CONFIG_IPV6_SUBTREES
86872cb57   Thomas Graf   [IPv6] route: FIB...
1225
1226
  	ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
  	rt->rt6i_src.plen = cfg->fc_src_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1227
  #endif
86872cb57   Thomas Graf   [IPv6] route: FIB...
1228
  	rt->rt6i_metric = cfg->fc_metric;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1229
1230
1231
1232
  
  	/* We cannot add true routes via loopback here,
  	   they would result in kernel looping; promote them to reject routes
  	 */
86872cb57   Thomas Graf   [IPv6] route: FIB...
1233
  	if ((cfg->fc_flags & RTF_REJECT) ||
383084739   David S. Miller   ipv6: Various cle...
1234
1235
1236
  	    (dev && (dev->flags & IFF_LOOPBACK) &&
  	     !(addr_type & IPV6_ADDR_LOOPBACK) &&
  	     !(cfg->fc_flags & RTF_LOCAL))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1237
  		/* hold loopback dev/idev if we haven't done so. */
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
1238
  		if (dev != net->loopback_dev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1239
1240
1241
1242
  			if (dev) {
  				dev_put(dev);
  				in6_dev_put(idev);
  			}
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
1243
  			dev = net->loopback_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1244
1245
1246
1247
1248
1249
1250
  			dev_hold(dev);
  			idev = in6_dev_get(dev);
  			if (!idev) {
  				err = -ENODEV;
  				goto out;
  			}
  		}
d8d1f30b9   Changli Gao   net-next: remove ...
1251
1252
1253
  		rt->dst.output = ip6_pkt_discard_out;
  		rt->dst.input = ip6_pkt_discard;
  		rt->dst.error = -ENETUNREACH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1254
1255
1256
  		rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
  		goto install_route;
  	}
86872cb57   Thomas Graf   [IPv6] route: FIB...
1257
  	if (cfg->fc_flags & RTF_GATEWAY) {
b71d1d426   Eric Dumazet   inet: constify ip...
1258
  		const struct in6_addr *gw_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1259
  		int gwa_type;
86872cb57   Thomas Graf   [IPv6] route: FIB...
1260
  		gw_addr = &cfg->fc_gateway;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1261
  		rt->rt6i_gateway = *gw_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
  		gwa_type = ipv6_addr_type(gw_addr);
  
  		if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
  			struct rt6_info *grt;
  
  			/* IPv6 strictly inhibits using not link-local
  			   addresses as nexthop address.
  			   Otherwise, router will not able to send redirects.
  			   It is very good, but in some (rare!) circumstances
  			   (SIT, PtP, NBMA NOARP links) it is handy to allow
  			   some exceptions. --ANK
  			 */
  			err = -EINVAL;
383084739   David S. Miller   ipv6: Various cle...
1275
  			if (!(gwa_type & IPV6_ADDR_UNICAST))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1276
  				goto out;
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
1277
  			grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1278
1279
  
  			err = -EHOSTUNREACH;
383084739   David S. Miller   ipv6: Various cle...
1280
  			if (!grt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1281
1282
  				goto out;
  			if (dev) {
d19185428   David S. Miller   ipv6: Kill rt6i_d...
1283
  				if (dev != grt->dst.dev) {
d8d1f30b9   Changli Gao   net-next: remove ...
1284
  					dst_release(&grt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1285
1286
1287
  					goto out;
  				}
  			} else {
d19185428   David S. Miller   ipv6: Kill rt6i_d...
1288
  				dev = grt->dst.dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1289
1290
1291
1292
  				idev = grt->rt6i_idev;
  				dev_hold(dev);
  				in6_dev_hold(grt->rt6i_idev);
  			}
383084739   David S. Miller   ipv6: Various cle...
1293
  			if (!(grt->rt6i_flags & RTF_GATEWAY))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1294
  				err = 0;
d8d1f30b9   Changli Gao   net-next: remove ...
1295
  			dst_release(&grt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1296
1297
1298
1299
1300
  
  			if (err)
  				goto out;
  		}
  		err = -EINVAL;
383084739   David S. Miller   ipv6: Various cle...
1301
  		if (!dev || (dev->flags & IFF_LOOPBACK))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1302
1303
1304
1305
  			goto out;
  	}
  
  	err = -ENODEV;
383084739   David S. Miller   ipv6: Various cle...
1306
  	if (!dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1307
  		goto out;
c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
1308
1309
1310
1311
1312
  	if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
  		if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
  			err = -EINVAL;
  			goto out;
  		}
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1313
  		rt->rt6i_prefsrc.addr = cfg->fc_prefsrc;
c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
1314
1315
1316
  		rt->rt6i_prefsrc.plen = 128;
  	} else
  		rt->rt6i_prefsrc.plen = 0;
86872cb57   Thomas Graf   [IPv6] route: FIB...
1317
  	if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) {
8ade06c61   David S. Miller   ipv6: Fix neigh l...
1318
  		err = rt6_bind_neighbour(rt, dev);
f83c7790d   David S. Miller   ipv6: Create fast...
1319
  		if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1320
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1321
  	}
86872cb57   Thomas Graf   [IPv6] route: FIB...
1322
  	rt->rt6i_flags = cfg->fc_flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1323
1324
  
  install_route:
86872cb57   Thomas Graf   [IPv6] route: FIB...
1325
1326
1327
1328
1329
  	if (cfg->fc_mx) {
  		struct nlattr *nla;
  		int remaining;
  
  		nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
8f4c1f9b0   Thomas Graf   [NETLINK]: Introd...
1330
  			int type = nla_type(nla);
86872cb57   Thomas Graf   [IPv6] route: FIB...
1331
1332
1333
  
  			if (type) {
  				if (type > RTAX_MAX) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1334
1335
1336
  					err = -EINVAL;
  					goto out;
  				}
86872cb57   Thomas Graf   [IPv6] route: FIB...
1337

defb3519a   David S. Miller   net: Abstract awa...
1338
  				dst_metric_set(&rt->dst, type, nla_get_u32(nla));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1339
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1340
1341
  		}
  	}
d8d1f30b9   Changli Gao   net-next: remove ...
1342
  	rt->dst.dev = dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1343
  	rt->rt6i_idev = idev;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1344
  	rt->rt6i_table = table;
63152fc0d   Daniel Lezcano   [NETNS][IPV6] ip6...
1345

c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1346
  	cfg->fc_nlinfo.nl_net = dev_net(dev);
63152fc0d   Daniel Lezcano   [NETNS][IPV6] ip6...
1347

86872cb57   Thomas Graf   [IPv6] route: FIB...
1348
  	return __ip6_ins_rt(rt, &cfg->fc_nlinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1349
1350
1351
1352
1353
1354
1355
  
  out:
  	if (dev)
  		dev_put(dev);
  	if (idev)
  		in6_dev_put(idev);
  	if (rt)
d8d1f30b9   Changli Gao   net-next: remove ...
1356
  		dst_free(&rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1357
1358
  	return err;
  }
86872cb57   Thomas Graf   [IPv6] route: FIB...
1359
  static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1360
1361
  {
  	int err;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1362
  	struct fib6_table *table;
d19185428   David S. Miller   ipv6: Kill rt6i_d...
1363
  	struct net *net = dev_net(rt->dst.dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1364

8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
1365
  	if (rt == net->ipv6.ip6_null_entry)
6c813a729   Patrick McHardy   [IPV6]: Fix crash...
1366
  		return -ENOENT;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1367
1368
  	table = rt->rt6i_table;
  	write_lock_bh(&table->tb6_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1369

86872cb57   Thomas Graf   [IPv6] route: FIB...
1370
  	err = fib6_del(rt, info);
d8d1f30b9   Changli Gao   net-next: remove ...
1371
  	dst_release(&rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1372

c71099acc   Thomas Graf   [IPV6]: Multiple ...
1373
  	write_unlock_bh(&table->tb6_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1374
1375
1376
  
  	return err;
  }
e0a1ad73d   Thomas Graf   [IPv6] route: Sim...
1377
1378
  int ip6_del_rt(struct rt6_info *rt)
  {
4d1169c1e   Denis V. Lunev   [NETNS]: Add netn...
1379
  	struct nl_info info = {
d19185428   David S. Miller   ipv6: Kill rt6i_d...
1380
  		.nl_net = dev_net(rt->dst.dev),
4d1169c1e   Denis V. Lunev   [NETNS]: Add netn...
1381
  	};
528c4ceb4   Denis V. Lunev   [IPV6]: Always pa...
1382
  	return __ip6_del_rt(rt, &info);
e0a1ad73d   Thomas Graf   [IPv6] route: Sim...
1383
  }
86872cb57   Thomas Graf   [IPv6] route: FIB...
1384
  static int ip6_route_del(struct fib6_config *cfg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1385
  {
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1386
  	struct fib6_table *table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1387
1388
1389
  	struct fib6_node *fn;
  	struct rt6_info *rt;
  	int err = -ESRCH;
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
1390
  	table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
383084739   David S. Miller   ipv6: Various cle...
1391
  	if (!table)
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1392
1393
1394
  		return err;
  
  	read_lock_bh(&table->tb6_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1395

c71099acc   Thomas Graf   [IPV6]: Multiple ...
1396
  	fn = fib6_locate(&table->tb6_root,
86872cb57   Thomas Graf   [IPv6] route: FIB...
1397
1398
  			 &cfg->fc_dst, cfg->fc_dst_len,
  			 &cfg->fc_src, cfg->fc_src_len);
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1399

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1400
  	if (fn) {
d8d1f30b9   Changli Gao   net-next: remove ...
1401
  		for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
86872cb57   Thomas Graf   [IPv6] route: FIB...
1402
  			if (cfg->fc_ifindex &&
d19185428   David S. Miller   ipv6: Kill rt6i_d...
1403
1404
  			    (!rt->dst.dev ||
  			     rt->dst.dev->ifindex != cfg->fc_ifindex))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1405
  				continue;
86872cb57   Thomas Graf   [IPv6] route: FIB...
1406
1407
  			if (cfg->fc_flags & RTF_GATEWAY &&
  			    !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1408
  				continue;
86872cb57   Thomas Graf   [IPv6] route: FIB...
1409
  			if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1410
  				continue;
d8d1f30b9   Changli Gao   net-next: remove ...
1411
  			dst_hold(&rt->dst);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1412
  			read_unlock_bh(&table->tb6_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1413

86872cb57   Thomas Graf   [IPv6] route: FIB...
1414
  			return __ip6_del_rt(rt, &cfg->fc_nlinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1415
1416
  		}
  	}
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1417
  	read_unlock_bh(&table->tb6_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1418
1419
1420
1421
1422
1423
1424
  
  	return err;
  }
  
  /*
   *	Handle redirects
   */
a6279458c   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
1425
  struct ip6rd_flowi {
4c9483b2f   David S. Miller   ipv6: Convert to ...
1426
  	struct flowi6 fl6;
a6279458c   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
1427
1428
  	struct in6_addr gateway;
  };
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
1429
1430
  static struct rt6_info *__ip6_route_redirect(struct net *net,
  					     struct fib6_table *table,
4c9483b2f   David S. Miller   ipv6: Convert to ...
1431
  					     struct flowi6 *fl6,
a6279458c   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
1432
  					     int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1433
  {
4c9483b2f   David S. Miller   ipv6: Convert to ...
1434
  	struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
a6279458c   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
1435
  	struct rt6_info *rt;
e843b9e1b   YOSHIFUJI Hideaki   [IPV6]: ROUTE: En...
1436
  	struct fib6_node *fn;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1437

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1438
  	/*
e843b9e1b   YOSHIFUJI Hideaki   [IPV6]: ROUTE: En...
1439
1440
1441
1442
1443
1444
1445
1446
  	 * Get the "current" route for this destination and
  	 * check if the redirect has come from approriate router.
  	 *
  	 * RFC 2461 specifies that redirects should only be
  	 * accepted if they come from the nexthop to the target.
  	 * Due to the way the routes are chosen, this notion
  	 * is a bit fuzzy and one might need to check all possible
  	 * routes.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1447
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1448

c71099acc   Thomas Graf   [IPV6]: Multiple ...
1449
  	read_lock_bh(&table->tb6_lock);
4c9483b2f   David S. Miller   ipv6: Convert to ...
1450
  	fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
e843b9e1b   YOSHIFUJI Hideaki   [IPV6]: ROUTE: En...
1451
  restart:
d8d1f30b9   Changli Gao   net-next: remove ...
1452
  	for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
e843b9e1b   YOSHIFUJI Hideaki   [IPV6]: ROUTE: En...
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
  		/*
  		 * Current route is on-link; redirect is always invalid.
  		 *
  		 * Seems, previous statement is not true. It could
  		 * be node, which looks for us as on-link (f.e. proxy ndisc)
  		 * But then router serving it might decide, that we should
  		 * know truth 8)8) --ANK (980726).
  		 */
  		if (rt6_check_expired(rt))
  			continue;
  		if (!(rt->rt6i_flags & RTF_GATEWAY))
  			continue;
d19185428   David S. Miller   ipv6: Kill rt6i_d...
1465
  		if (fl6->flowi6_oif != rt->dst.dev->ifindex)
e843b9e1b   YOSHIFUJI Hideaki   [IPV6]: ROUTE: En...
1466
  			continue;
a6279458c   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
1467
  		if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway))
e843b9e1b   YOSHIFUJI Hideaki   [IPV6]: ROUTE: En...
1468
1469
1470
  			continue;
  		break;
  	}
a6279458c   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
1471

cb15d9c22   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
1472
  	if (!rt)
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
1473
  		rt = net->ipv6.ip6_null_entry;
4c9483b2f   David S. Miller   ipv6: Convert to ...
1474
  	BACKTRACK(net, &fl6->saddr);
cb15d9c22   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
1475
  out:
d8d1f30b9   Changli Gao   net-next: remove ...
1476
  	dst_hold(&rt->dst);
a6279458c   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
1477

c71099acc   Thomas Graf   [IPV6]: Multiple ...
1478
  	read_unlock_bh(&table->tb6_lock);
e843b9e1b   YOSHIFUJI Hideaki   [IPV6]: ROUTE: En...
1479

a6279458c   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
1480
1481
  	return rt;
  };
b71d1d426   Eric Dumazet   inet: constify ip...
1482
1483
1484
  static struct rt6_info *ip6_route_redirect(const struct in6_addr *dest,
  					   const struct in6_addr *src,
  					   const struct in6_addr *gateway,
a6279458c   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
1485
1486
  					   struct net_device *dev)
  {
adaa70bbd   Thomas Graf   [IPv6] rules: Use...
1487
  	int flags = RT6_LOOKUP_F_HAS_SADDR;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1488
  	struct net *net = dev_net(dev);
a6279458c   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
1489
  	struct ip6rd_flowi rdfl = {
4c9483b2f   David S. Miller   ipv6: Convert to ...
1490
1491
1492
1493
  		.fl6 = {
  			.flowi6_oif = dev->ifindex,
  			.daddr = *dest,
  			.saddr = *src,
a6279458c   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
1494
  		},
a6279458c   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
1495
  	};
adaa70bbd   Thomas Graf   [IPv6] rules: Use...
1496

4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1497
  	rdfl.gateway = *gateway;
86c36ce45   Brian Haley   IPv6: use ipv6_ad...
1498

adaa70bbd   Thomas Graf   [IPv6] rules: Use...
1499
1500
  	if (rt6_need_strict(dest))
  		flags |= RT6_LOOKUP_F_IFACE;
a6279458c   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
1501

4c9483b2f   David S. Miller   ipv6: Convert to ...
1502
  	return (struct rt6_info *)fib6_rule_lookup(net, &rdfl.fl6,
58f09b78b   Daniel Lezcano   [NETNS][IPV6] ip6...
1503
  						   flags, __ip6_route_redirect);
a6279458c   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
1504
  }
b71d1d426   Eric Dumazet   inet: constify ip...
1505
1506
  void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src,
  		  const struct in6_addr *saddr,
a6279458c   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
1507
1508
1509
1510
  		  struct neighbour *neigh, u8 *lladdr, int on_link)
  {
  	struct rt6_info *rt, *nrt = NULL;
  	struct netevent_redirect netevent;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1511
  	struct net *net = dev_net(neigh->dev);
a6279458c   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
1512
1513
  
  	rt = ip6_route_redirect(dest, src, saddr, neigh->dev);
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
1514
  	if (rt == net->ipv6.ip6_null_entry) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1515
1516
1517
1518
  		if (net_ratelimit())
  			printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop "
  			       "for redirect target
  ");
a6279458c   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
1519
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1520
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1521
1522
1523
  	/*
  	 *	We have finally decided to accept it.
  	 */
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1524
  	neigh_update(neigh, lladdr, NUD_STALE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
  		     NEIGH_UPDATE_F_WEAK_OVERRIDE|
  		     NEIGH_UPDATE_F_OVERRIDE|
  		     (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
  				     NEIGH_UPDATE_F_ISROUTER))
  		     );
  
  	/*
  	 * Redirect received -> path was valid.
  	 * Look, redirects are sent only in response to data packets,
  	 * so that this nexthop apparently is reachable. --ANK
  	 */
d8d1f30b9   Changli Gao   net-next: remove ...
1536
  	dst_confirm(&rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1537
1538
  
  	/* Duplicate redirect: silently ignore. */
272174550   David Miller   net: Rename dst_g...
1539
  	if (neigh == dst_get_neighbour_noref_raw(&rt->dst))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1540
  		goto out;
21efcfa0f   Eric Dumazet   ipv6: unshare ine...
1541
  	nrt = ip6_rt_copy(rt, dest);
383084739   David S. Miller   ipv6: Various cle...
1542
  	if (!nrt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1543
1544
1545
1546
1547
  		goto out;
  
  	nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
  	if (on_link)
  		nrt->rt6i_flags &= ~RTF_GATEWAY;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1548
  	nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
69cce1d14   David S. Miller   net: Abstract dst...
1549
  	dst_set_neighbour(&nrt->dst, neigh_clone(neigh));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1550

40e22e8f3   Thomas Graf   [IPv6] route: Sim...
1551
  	if (ip6_ins_rt(nrt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1552
  		goto out;
d8d1f30b9   Changli Gao   net-next: remove ...
1553
1554
  	netevent.old = &rt->dst;
  	netevent.new = &nrt->dst;
8d71740c5   Tom Tucker   [NET]: Core net c...
1555
  	call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
383084739   David S. Miller   ipv6: Various cle...
1556
  	if (rt->rt6i_flags & RTF_CACHE) {
e0a1ad73d   Thomas Graf   [IPv6] route: Sim...
1557
  		ip6_del_rt(rt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1558
1559
1560
1561
  		return;
  	}
  
  out:
d8d1f30b9   Changli Gao   net-next: remove ...
1562
  	dst_release(&rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1563
1564
1565
1566
1567
1568
  }
  
  /*
   *	Handle ICMP "packet too big" messages
   *	i.e. Path MTU discovery
   */
b71d1d426   Eric Dumazet   inet: constify ip...
1569
  static void rt6_do_pmtu_disc(const struct in6_addr *daddr, const struct in6_addr *saddr,
ae878ae28   Maciej Żenczykowski   net: Fix IPv6 PMT...
1570
  			     struct net *net, u32 pmtu, int ifindex)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1571
1572
1573
  {
  	struct rt6_info *rt, *nrt;
  	int allfrag = 0;
d3052b557   Andrey Vagin   ipv6: delete expi...
1574
  again:
ae878ae28   Maciej Żenczykowski   net: Fix IPv6 PMT...
1575
  	rt = rt6_lookup(net, daddr, saddr, ifindex, 0);
383084739   David S. Miller   ipv6: Various cle...
1576
  	if (!rt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1577
  		return;
d3052b557   Andrey Vagin   ipv6: delete expi...
1578
1579
1580
1581
  	if (rt6_check_expired(rt)) {
  		ip6_del_rt(rt);
  		goto again;
  	}
d8d1f30b9   Changli Gao   net-next: remove ...
1582
  	if (pmtu >= dst_mtu(&rt->dst))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1583
1584
1585
1586
  		goto out;
  
  	if (pmtu < IPV6_MIN_MTU) {
  		/*
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1587
  		 * According to RFC2460, PMTU is set to the IPv6 Minimum Link
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
  		 * MTU (1280) and a fragment header should always be included
  		 * after a node receiving Too Big message reporting PMTU is
  		 * less than the IPv6 Minimum Link MTU.
  		 */
  		pmtu = IPV6_MIN_MTU;
  		allfrag = 1;
  	}
  
  	/* New mtu received -> path was valid.
  	   They are sent only in response to data packets,
  	   so that this nexthop apparently is reachable. --ANK
  	 */
d8d1f30b9   Changli Gao   net-next: remove ...
1600
  	dst_confirm(&rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1601
1602
1603
1604
1605
1606
1607
  
  	/* Host route. If it is static, it would be better
  	   not to override it, but add new one, so that
  	   when cache entry will expire old pmtu
  	   would return automatically.
  	 */
  	if (rt->rt6i_flags & RTF_CACHE) {
defb3519a   David S. Miller   net: Abstract awa...
1608
1609
1610
1611
1612
1613
  		dst_metric_set(&rt->dst, RTAX_MTU, pmtu);
  		if (allfrag) {
  			u32 features = dst_metric(&rt->dst, RTAX_FEATURES);
  			features |= RTAX_FEATURE_ALLFRAG;
  			dst_metric_set(&rt->dst, RTAX_FEATURES, features);
  		}
d8d1f30b9   Changli Gao   net-next: remove ...
1614
  		dst_set_expires(&rt->dst, net->ipv6.sysctl.ip6_rt_mtu_expires);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1615
1616
1617
1618
1619
1620
1621
1622
1623
  		rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES;
  		goto out;
  	}
  
  	/* Network route.
  	   Two cases are possible:
  	   1. It is connected route. Action: COW
  	   2. It is gatewayed route or NONEXTHOP route. Action: clone it.
  	 */
272174550   David Miller   net: Rename dst_g...
1624
  	if (!dst_get_neighbour_noref_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP))
a1e783634   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Se...
1625
  		nrt = rt6_alloc_cow(rt, daddr, saddr);
d5315b500   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Un...
1626
1627
  	else
  		nrt = rt6_alloc_clone(rt, daddr);
a1e783634   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Se...
1628

d5315b500   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Un...
1629
  	if (nrt) {
defb3519a   David S. Miller   net: Abstract awa...
1630
1631
1632
1633
1634
1635
  		dst_metric_set(&nrt->dst, RTAX_MTU, pmtu);
  		if (allfrag) {
  			u32 features = dst_metric(&nrt->dst, RTAX_FEATURES);
  			features |= RTAX_FEATURE_ALLFRAG;
  			dst_metric_set(&nrt->dst, RTAX_FEATURES, features);
  		}
a1e783634   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Se...
1636
1637
1638
1639
1640
1641
1642
  
  		/* According to RFC 1981, detecting PMTU increase shouldn't be
  		 * happened within 5 mins, the recommended timer is 10 mins.
  		 * Here this route expiration time is set to ip6_rt_mtu_expires
  		 * which is 10 mins. After 10 mins the decreased pmtu is expired
  		 * and detecting PMTU increase will be automatically happened.
  		 */
d8d1f30b9   Changli Gao   net-next: remove ...
1643
  		dst_set_expires(&nrt->dst, net->ipv6.sysctl.ip6_rt_mtu_expires);
a1e783634   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Se...
1644
  		nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES;
40e22e8f3   Thomas Graf   [IPv6] route: Sim...
1645
  		ip6_ins_rt(nrt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1646
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1647
  out:
d8d1f30b9   Changli Gao   net-next: remove ...
1648
  	dst_release(&rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1649
  }
b71d1d426   Eric Dumazet   inet: constify ip...
1650
  void rt6_pmtu_discovery(const struct in6_addr *daddr, const struct in6_addr *saddr,
ae878ae28   Maciej Żenczykowski   net: Fix IPv6 PMT...
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
  			struct net_device *dev, u32 pmtu)
  {
  	struct net *net = dev_net(dev);
  
  	/*
  	 * RFC 1981 states that a node "MUST reduce the size of the packets it
  	 * is sending along the path" that caused the Packet Too Big message.
  	 * Since it's not possible in the general case to determine which
  	 * interface was used to send the original packet, we update the MTU
  	 * on the interface that will be used to send future packets. We also
  	 * update the MTU on the interface that received the Packet Too Big in
  	 * case the original packet was forced out that interface with
  	 * SO_BINDTODEVICE or similar. This is the next best thing to the
  	 * correct behaviour, which would be to update the MTU on all
  	 * interfaces.
  	 */
  	rt6_do_pmtu_disc(daddr, saddr, net, pmtu, 0);
  	rt6_do_pmtu_disc(daddr, saddr, net, pmtu, dev->ifindex);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1670
1671
1672
  /*
   *	Misc support functions
   */
21efcfa0f   Eric Dumazet   ipv6: unshare ine...
1673
1674
  static struct rt6_info *ip6_rt_copy(const struct rt6_info *ort,
  				    const struct in6_addr *dest)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1675
  {
d19185428   David S. Miller   ipv6: Kill rt6i_d...
1676
  	struct net *net = dev_net(ort->dst.dev);
5c1e6aa30   David S. Miller   net: Make dst_all...
1677
  	struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops,
957c665f3   David S. Miller   ipv6: Don't put a...
1678
  					    ort->dst.dev, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1679
1680
  
  	if (rt) {
d8d1f30b9   Changli Gao   net-next: remove ...
1681
1682
  		rt->dst.input = ort->dst.input;
  		rt->dst.output = ort->dst.output;
8e2ec6391   Yan, Zheng   ipv6: don't use i...
1683
  		rt->dst.flags |= DST_HOST;
d8d1f30b9   Changli Gao   net-next: remove ...
1684

4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1685
  		rt->rt6i_dst.addr = *dest;
8e2ec6391   Yan, Zheng   ipv6: don't use i...
1686
  		rt->rt6i_dst.plen = 128;
defb3519a   David S. Miller   net: Abstract awa...
1687
  		dst_copy_metrics(&rt->dst, &ort->dst);
d8d1f30b9   Changli Gao   net-next: remove ...
1688
  		rt->dst.error = ort->dst.error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1689
1690
1691
  		rt->rt6i_idev = ort->rt6i_idev;
  		if (rt->rt6i_idev)
  			in6_dev_hold(rt->rt6i_idev);
d8d1f30b9   Changli Gao   net-next: remove ...
1692
  		rt->dst.lastuse = jiffies;
d19185428   David S. Miller   ipv6: Kill rt6i_d...
1693
  		rt->dst.expires = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1694

4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1695
  		rt->rt6i_gateway = ort->rt6i_gateway;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1696
1697
  		rt->rt6i_flags = ort->rt6i_flags & ~RTF_EXPIRES;
  		rt->rt6i_metric = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1698
1699
1700
  #ifdef CONFIG_IPV6_SUBTREES
  		memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
  #endif
0f6c6392d   Florian Westphal   ipv6: copy prefsr...
1701
  		memcpy(&rt->rt6i_prefsrc, &ort->rt6i_prefsrc, sizeof(struct rt6key));
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1702
  		rt->rt6i_table = ort->rt6i_table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1703
1704
1705
  	}
  	return rt;
  }
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1706
  #ifdef CONFIG_IPV6_ROUTE_INFO
efa2cea0d   Daniel Lezcano   [NETNS][IPV6] rou...
1707
  static struct rt6_info *rt6_get_route_info(struct net *net,
b71d1d426   Eric Dumazet   inet: constify ip...
1708
1709
  					   const struct in6_addr *prefix, int prefixlen,
  					   const struct in6_addr *gwaddr, int ifindex)
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1710
1711
1712
  {
  	struct fib6_node *fn;
  	struct rt6_info *rt = NULL;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1713
  	struct fib6_table *table;
efa2cea0d   Daniel Lezcano   [NETNS][IPV6] rou...
1714
  	table = fib6_get_table(net, RT6_TABLE_INFO);
383084739   David S. Miller   ipv6: Various cle...
1715
  	if (!table)
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1716
  		return NULL;
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1717

c71099acc   Thomas Graf   [IPV6]: Multiple ...
1718
1719
  	write_lock_bh(&table->tb6_lock);
  	fn = fib6_locate(&table->tb6_root, prefix ,prefixlen, NULL, 0);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1720
1721
  	if (!fn)
  		goto out;
d8d1f30b9   Changli Gao   net-next: remove ...
1722
  	for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
d19185428   David S. Miller   ipv6: Kill rt6i_d...
1723
  		if (rt->dst.dev->ifindex != ifindex)
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1724
1725
1726
1727
1728
  			continue;
  		if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
  			continue;
  		if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
  			continue;
d8d1f30b9   Changli Gao   net-next: remove ...
1729
  		dst_hold(&rt->dst);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1730
1731
1732
  		break;
  	}
  out:
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1733
  	write_unlock_bh(&table->tb6_lock);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1734
1735
  	return rt;
  }
efa2cea0d   Daniel Lezcano   [NETNS][IPV6] rou...
1736
  static struct rt6_info *rt6_add_route_info(struct net *net,
b71d1d426   Eric Dumazet   inet: constify ip...
1737
1738
  					   const struct in6_addr *prefix, int prefixlen,
  					   const struct in6_addr *gwaddr, int ifindex,
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1739
1740
  					   unsigned pref)
  {
86872cb57   Thomas Graf   [IPv6] route: FIB...
1741
1742
  	struct fib6_config cfg = {
  		.fc_table	= RT6_TABLE_INFO,
238fc7eac   Rami Rosen   [IPV6]: Replace u...
1743
  		.fc_metric	= IP6_RT_PRIO_USER,
86872cb57   Thomas Graf   [IPv6] route: FIB...
1744
1745
1746
1747
  		.fc_ifindex	= ifindex,
  		.fc_dst_len	= prefixlen,
  		.fc_flags	= RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
  				  RTF_UP | RTF_PREF(pref),
efa2cea0d   Daniel Lezcano   [NETNS][IPV6] rou...
1748
1749
1750
  		.fc_nlinfo.pid = 0,
  		.fc_nlinfo.nlh = NULL,
  		.fc_nlinfo.nl_net = net,
86872cb57   Thomas Graf   [IPv6] route: FIB...
1751
  	};
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1752
1753
  	cfg.fc_dst = *prefix;
  	cfg.fc_gateway = *gwaddr;
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1754

e317da962   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Fl...
1755
1756
  	/* We should treat it as a default route if prefix length is 0. */
  	if (!prefixlen)
86872cb57   Thomas Graf   [IPv6] route: FIB...
1757
  		cfg.fc_flags |= RTF_DEFAULT;
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1758

86872cb57   Thomas Graf   [IPv6] route: FIB...
1759
  	ip6_route_add(&cfg);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1760

efa2cea0d   Daniel Lezcano   [NETNS][IPV6] rou...
1761
  	return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1762
1763
  }
  #endif
b71d1d426   Eric Dumazet   inet: constify ip...
1764
  struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1765
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1766
  	struct rt6_info *rt;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1767
  	struct fib6_table *table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1768

c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1769
  	table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT);
383084739   David S. Miller   ipv6: Various cle...
1770
  	if (!table)
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1771
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1772

c71099acc   Thomas Graf   [IPV6]: Multiple ...
1773
  	write_lock_bh(&table->tb6_lock);
d8d1f30b9   Changli Gao   net-next: remove ...
1774
  	for (rt = table->tb6_root.leaf; rt; rt=rt->dst.rt6_next) {
d19185428   David S. Miller   ipv6: Kill rt6i_d...
1775
  		if (dev == rt->dst.dev &&
045927ff8   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Mo...
1776
  		    ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1777
1778
1779
1780
  		    ipv6_addr_equal(&rt->rt6i_gateway, addr))
  			break;
  	}
  	if (rt)
d8d1f30b9   Changli Gao   net-next: remove ...
1781
  		dst_hold(&rt->dst);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1782
  	write_unlock_bh(&table->tb6_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1783
1784
  	return rt;
  }
b71d1d426   Eric Dumazet   inet: constify ip...
1785
  struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
ebacaaa0f   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
1786
1787
  				     struct net_device *dev,
  				     unsigned int pref)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1788
  {
86872cb57   Thomas Graf   [IPv6] route: FIB...
1789
1790
  	struct fib6_config cfg = {
  		.fc_table	= RT6_TABLE_DFLT,
238fc7eac   Rami Rosen   [IPV6]: Replace u...
1791
  		.fc_metric	= IP6_RT_PRIO_USER,
86872cb57   Thomas Graf   [IPv6] route: FIB...
1792
1793
1794
  		.fc_ifindex	= dev->ifindex,
  		.fc_flags	= RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
  				  RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
1795
1796
  		.fc_nlinfo.pid = 0,
  		.fc_nlinfo.nlh = NULL,
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1797
  		.fc_nlinfo.nl_net = dev_net(dev),
86872cb57   Thomas Graf   [IPv6] route: FIB...
1798
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1799

4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1800
  	cfg.fc_gateway = *gwaddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1801

86872cb57   Thomas Graf   [IPv6] route: FIB...
1802
  	ip6_route_add(&cfg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1803

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1804
1805
  	return rt6_get_dflt_router(gwaddr, dev);
  }
7b4da5322   Daniel Lezcano   [NETNS][IPV6] rou...
1806
  void rt6_purge_dflt_routers(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1807
1808
  {
  	struct rt6_info *rt;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1809
1810
1811
  	struct fib6_table *table;
  
  	/* NOTE: Keep consistent with rt6_get_dflt_router */
7b4da5322   Daniel Lezcano   [NETNS][IPV6] rou...
1812
  	table = fib6_get_table(net, RT6_TABLE_DFLT);
383084739   David S. Miller   ipv6: Various cle...
1813
  	if (!table)
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1814
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1815
1816
  
  restart:
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1817
  	read_lock_bh(&table->tb6_lock);
d8d1f30b9   Changli Gao   net-next: remove ...
1818
  	for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1819
  		if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) {
d8d1f30b9   Changli Gao   net-next: remove ...
1820
  			dst_hold(&rt->dst);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1821
  			read_unlock_bh(&table->tb6_lock);
e0a1ad73d   Thomas Graf   [IPv6] route: Sim...
1822
  			ip6_del_rt(rt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1823
1824
1825
  			goto restart;
  		}
  	}
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1826
  	read_unlock_bh(&table->tb6_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1827
  }
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
1828
1829
  static void rtmsg_to_fib6_config(struct net *net,
  				 struct in6_rtmsg *rtmsg,
86872cb57   Thomas Graf   [IPv6] route: FIB...
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
  				 struct fib6_config *cfg)
  {
  	memset(cfg, 0, sizeof(*cfg));
  
  	cfg->fc_table = RT6_TABLE_MAIN;
  	cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
  	cfg->fc_metric = rtmsg->rtmsg_metric;
  	cfg->fc_expires = rtmsg->rtmsg_info;
  	cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
  	cfg->fc_src_len = rtmsg->rtmsg_src_len;
  	cfg->fc_flags = rtmsg->rtmsg_flags;
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
1841
  	cfg->fc_nlinfo.nl_net = net;
f1243c2db   Benjamin Thery   [IPV6]: Add missi...
1842

4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1843
1844
1845
  	cfg->fc_dst = rtmsg->rtmsg_dst;
  	cfg->fc_src = rtmsg->rtmsg_src;
  	cfg->fc_gateway = rtmsg->rtmsg_gateway;
86872cb57   Thomas Graf   [IPv6] route: FIB...
1846
  }
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
1847
  int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1848
  {
86872cb57   Thomas Graf   [IPv6] route: FIB...
1849
  	struct fib6_config cfg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
  	struct in6_rtmsg rtmsg;
  	int err;
  
  	switch(cmd) {
  	case SIOCADDRT:		/* Add a route */
  	case SIOCDELRT:		/* Delete a route */
  		if (!capable(CAP_NET_ADMIN))
  			return -EPERM;
  		err = copy_from_user(&rtmsg, arg,
  				     sizeof(struct in6_rtmsg));
  		if (err)
  			return -EFAULT;
86872cb57   Thomas Graf   [IPv6] route: FIB...
1862

5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
1863
  		rtmsg_to_fib6_config(net, &rtmsg, &cfg);
86872cb57   Thomas Graf   [IPv6] route: FIB...
1864

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1865
1866
1867
  		rtnl_lock();
  		switch (cmd) {
  		case SIOCADDRT:
86872cb57   Thomas Graf   [IPv6] route: FIB...
1868
  			err = ip6_route_add(&cfg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1869
1870
  			break;
  		case SIOCDELRT:
86872cb57   Thomas Graf   [IPv6] route: FIB...
1871
  			err = ip6_route_del(&cfg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1872
1873
1874
1875
1876
1877
1878
  			break;
  		default:
  			err = -EINVAL;
  		}
  		rtnl_unlock();
  
  		return err;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
1879
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1880
1881
1882
1883
1884
1885
1886
  
  	return -EINVAL;
  }
  
  /*
   *	Drop the packet on the floor
   */
d5fdd6bab   Brian Haley   ipv6: Use correct...
1887
  static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1888
  {
612f09e84   YOSHIFUJI Hideaki   [IPV6] SNMP: Fix ...
1889
  	int type;
adf30907d   Eric Dumazet   net: skb->dst acc...
1890
  	struct dst_entry *dst = skb_dst(skb);
612f09e84   YOSHIFUJI Hideaki   [IPV6] SNMP: Fix ...
1891
1892
  	switch (ipstats_mib_noroutes) {
  	case IPSTATS_MIB_INNOROUTES:
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1893
  		type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
45bb00609   Ulrich Weber   ipv6: Remove IPV6...
1894
  		if (type == IPV6_ADDR_ANY) {
3bd653c84   Denis V. Lunev   netns: add net pa...
1895
1896
  			IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
  				      IPSTATS_MIB_INADDRERRORS);
612f09e84   YOSHIFUJI Hideaki   [IPV6] SNMP: Fix ...
1897
1898
1899
1900
  			break;
  		}
  		/* FALLTHROUGH */
  	case IPSTATS_MIB_OUTNOROUTES:
3bd653c84   Denis V. Lunev   netns: add net pa...
1901
1902
  		IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
  			      ipstats_mib_noroutes);
612f09e84   YOSHIFUJI Hideaki   [IPV6] SNMP: Fix ...
1903
1904
  		break;
  	}
3ffe533c8   Alexey Dobriyan   ipv6: drop unused...
1905
  	icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1906
1907
1908
  	kfree_skb(skb);
  	return 0;
  }
9ce8ade01   Thomas Graf   [IPv6] route: Fix...
1909
1910
  static int ip6_pkt_discard(struct sk_buff *skb)
  {
612f09e84   YOSHIFUJI Hideaki   [IPV6] SNMP: Fix ...
1911
  	return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
9ce8ade01   Thomas Graf   [IPv6] route: Fix...
1912
  }
20380731b   Arnaldo Carvalho de Melo   [NET]: Fix sparse...
1913
  static int ip6_pkt_discard_out(struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1914
  {
adf30907d   Eric Dumazet   net: skb->dst acc...
1915
  	skb->dev = skb_dst(skb)->dev;
612f09e84   YOSHIFUJI Hideaki   [IPV6] SNMP: Fix ...
1916
  	return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1917
  }
6723ab549   David S. Miller   [IPV6]: Fix route...
1918
  #ifdef CONFIG_IPV6_MULTIPLE_TABLES
9ce8ade01   Thomas Graf   [IPv6] route: Fix...
1919
1920
  static int ip6_pkt_prohibit(struct sk_buff *skb)
  {
612f09e84   YOSHIFUJI Hideaki   [IPV6] SNMP: Fix ...
1921
  	return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
9ce8ade01   Thomas Graf   [IPv6] route: Fix...
1922
1923
1924
1925
  }
  
  static int ip6_pkt_prohibit_out(struct sk_buff *skb)
  {
adf30907d   Eric Dumazet   net: skb->dst acc...
1926
  	skb->dev = skb_dst(skb)->dev;
612f09e84   YOSHIFUJI Hideaki   [IPV6] SNMP: Fix ...
1927
  	return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
9ce8ade01   Thomas Graf   [IPv6] route: Fix...
1928
  }
6723ab549   David S. Miller   [IPV6]: Fix route...
1929
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1930
1931
1932
1933
1934
1935
  /*
   *	Allocate a dst for local (unicast / anycast) address.
   */
  
  struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
  				    const struct in6_addr *addr,
8f0315190   David S. Miller   ipv6: Make third ...
1936
  				    bool anycast)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1937
  {
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1938
  	struct net *net = dev_net(idev->dev);
5c1e6aa30   David S. Miller   net: Make dst_all...
1939
  	struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops,
957c665f3   David S. Miller   ipv6: Don't put a...
1940
  					    net->loopback_dev, 0);
f83c7790d   David S. Miller   ipv6: Create fast...
1941
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1942

383084739   David S. Miller   ipv6: Various cle...
1943
  	if (!rt) {
403856532   Ben Greear   ipv6: Warn users ...
1944
1945
1946
1947
  		if (net_ratelimit())
  			pr_warning("IPv6:  Maximum number of routes reached,"
  				   " consider increasing route/max_size.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1948
  		return ERR_PTR(-ENOMEM);
403856532   Ben Greear   ipv6: Warn users ...
1949
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1950

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1951
  	in6_dev_hold(idev);
11d53b499   David S. Miller   ipv6: Don't chang...
1952
  	rt->dst.flags |= DST_HOST;
d8d1f30b9   Changli Gao   net-next: remove ...
1953
1954
  	rt->dst.input = ip6_input;
  	rt->dst.output = ip6_output;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1955
  	rt->rt6i_idev = idev;
d8d1f30b9   Changli Gao   net-next: remove ...
1956
  	rt->dst.obsolete = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1957
1958
  
  	rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
58c4fb86e   YOSHIFUJI Hideaki   [IPV6]: Flag RTF_...
1959
1960
1961
  	if (anycast)
  		rt->rt6i_flags |= RTF_ANYCAST;
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1962
  		rt->rt6i_flags |= RTF_LOCAL;
8ade06c61   David S. Miller   ipv6: Fix neigh l...
1963
  	err = rt6_bind_neighbour(rt, rt->dst.dev);
f83c7790d   David S. Miller   ipv6: Create fast...
1964
  	if (err) {
d8d1f30b9   Changli Gao   net-next: remove ...
1965
  		dst_free(&rt->dst);
f83c7790d   David S. Miller   ipv6: Create fast...
1966
  		return ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1967
  	}
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1968
  	rt->rt6i_dst.addr = *addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1969
  	rt->rt6i_dst.plen = 128;
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
1970
  	rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1971

d8d1f30b9   Changli Gao   net-next: remove ...
1972
  	atomic_set(&rt->dst.__refcnt, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1973
1974
1975
  
  	return rt;
  }
c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
1976
1977
  int ip6_route_get_saddr(struct net *net,
  			struct rt6_info *rt,
b71d1d426   Eric Dumazet   inet: constify ip...
1978
  			const struct in6_addr *daddr,
c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
1979
1980
1981
1982
1983
1984
  			unsigned int prefs,
  			struct in6_addr *saddr)
  {
  	struct inet6_dev *idev = ip6_dst_idev((struct dst_entry*)rt);
  	int err = 0;
  	if (rt->rt6i_prefsrc.plen)
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1985
  		*saddr = rt->rt6i_prefsrc.addr;
c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
  	else
  		err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
  					 daddr, prefs, saddr);
  	return err;
  }
  
  /* remove deleted ip from prefsrc entries */
  struct arg_dev_net_ip {
  	struct net_device *dev;
  	struct net *net;
  	struct in6_addr *addr;
  };
  
  static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
  {
  	struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
  	struct net *net = ((struct arg_dev_net_ip *)arg)->net;
  	struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
d19185428   David S. Miller   ipv6: Kill rt6i_d...
2004
  	if (((void *)rt->dst.dev == dev || !dev) &&
c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
  	    rt != net->ipv6.ip6_null_entry &&
  	    ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
  		/* remove prefsrc entry */
  		rt->rt6i_prefsrc.plen = 0;
  	}
  	return 0;
  }
  
  void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
  {
  	struct net *net = dev_net(ifp->idev->dev);
  	struct arg_dev_net_ip adni = {
  		.dev = ifp->idev->dev,
  		.net = net,
  		.addr = &ifp->addr,
  	};
  	fib6_clean_all(net, fib6_remove_prefsrc, 0, &adni);
  }
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2023
2024
2025
2026
  struct arg_dev_net {
  	struct net_device *dev;
  	struct net *net;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2027
2028
  static int fib6_ifdown(struct rt6_info *rt, void *arg)
  {
bc3ef6605   stephen hemminger   ipv6: fib6_ifdown...
2029
2030
  	const struct arg_dev_net *adn = arg;
  	const struct net_device *dev = adn->dev;
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2031

d19185428   David S. Miller   ipv6: Kill rt6i_d...
2032
  	if ((rt->dst.dev == dev || !dev) &&
c159d30c5   David S. Miller   ipv6: Kill useles...
2033
  	    rt != adn->net->ipv6.ip6_null_entry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2034
  		return -1;
c159d30c5   David S. Miller   ipv6: Kill useles...
2035

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2036
2037
  	return 0;
  }
f3db48517   Daniel Lezcano   [NETNS][IPV6] ip6...
2038
  void rt6_ifdown(struct net *net, struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2039
  {
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2040
2041
2042
2043
2044
2045
  	struct arg_dev_net adn = {
  		.dev = dev,
  		.net = net,
  	};
  
  	fib6_clean_all(net, fib6_ifdown, 0, &adn);
1e493d194   David S. Miller   ipv6: On interfac...
2046
  	icmp6_clean_all(fib6_ifdown, &adn);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
  }
  
  struct rt6_mtu_change_arg
  {
  	struct net_device *dev;
  	unsigned mtu;
  };
  
  static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
  {
  	struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
  	struct inet6_dev *idev;
  
  	/* In IPv6 pmtu discovery is not optional,
  	   so that RTAX_MTU lock cannot disable it.
  	   We still use this lock to block changes
  	   caused by addrconf/ndisc.
  	*/
  
  	idev = __in6_dev_get(arg->dev);
383084739   David S. Miller   ipv6: Various cle...
2067
  	if (!idev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
  		return 0;
  
  	/* For administrative MTU increase, there is no way to discover
  	   IPv6 PMTU increase, so PMTU increase should be updated here.
  	   Since RFC 1981 doesn't include administrative MTU increase
  	   update PMTU increase is a MUST. (i.e. jumbo frame)
  	 */
  	/*
  	   If new MTU is less than route PMTU, this new MTU will be the
  	   lowest MTU in the path, update the route PMTU to reflect PMTU
  	   decreases; if new MTU is greater than route PMTU, and the
  	   old MTU is the lowest MTU in the path, update the route PMTU
  	   to reflect the increase. In this case if the other nodes' MTU
  	   also have the lowest MTU, TOO BIG MESSAGE will be lead to
  	   PMTU discouvery.
  	 */
d19185428   David S. Miller   ipv6: Kill rt6i_d...
2084
  	if (rt->dst.dev == arg->dev &&
d8d1f30b9   Changli Gao   net-next: remove ...
2085
2086
2087
2088
  	    !dst_metric_locked(&rt->dst, RTAX_MTU) &&
  	    (dst_mtu(&rt->dst) >= arg->mtu ||
  	     (dst_mtu(&rt->dst) < arg->mtu &&
  	      dst_mtu(&rt->dst) == idev->cnf.mtu6))) {
defb3519a   David S. Miller   net: Abstract awa...
2089
  		dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu);
566cfd8f0   Simon Arlott   [IPV6]: Don't upd...
2090
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2091
2092
2093
2094
2095
  	return 0;
  }
  
  void rt6_mtu_change(struct net_device *dev, unsigned mtu)
  {
c71099acc   Thomas Graf   [IPV6]: Multiple ...
2096
2097
2098
2099
  	struct rt6_mtu_change_arg arg = {
  		.dev = dev,
  		.mtu = mtu,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2100

c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2101
  	fib6_clean_all(dev_net(dev), rt6_mtu_change_route, 0, &arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2102
  }
ef7c79ed6   Patrick McHardy   [NETLINK]: Mark n...
2103
  static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
5176f91ea   Thomas Graf   [NETLINK]: Make u...
2104
  	[RTA_GATEWAY]           = { .len = sizeof(struct in6_addr) },
86872cb57   Thomas Graf   [IPv6] route: FIB...
2105
  	[RTA_OIF]               = { .type = NLA_U32 },
ab364a6f9   Thomas Graf   [IPv6] route: Con...
2106
  	[RTA_IIF]		= { .type = NLA_U32 },
86872cb57   Thomas Graf   [IPv6] route: FIB...
2107
2108
2109
2110
2111
2112
  	[RTA_PRIORITY]          = { .type = NLA_U32 },
  	[RTA_METRICS]           = { .type = NLA_NESTED },
  };
  
  static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
  			      struct fib6_config *cfg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2113
  {
86872cb57   Thomas Graf   [IPv6] route: FIB...
2114
2115
2116
  	struct rtmsg *rtm;
  	struct nlattr *tb[RTA_MAX+1];
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2117

86872cb57   Thomas Graf   [IPv6] route: FIB...
2118
2119
2120
  	err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
  	if (err < 0)
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2121

86872cb57   Thomas Graf   [IPv6] route: FIB...
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
  	err = -EINVAL;
  	rtm = nlmsg_data(nlh);
  	memset(cfg, 0, sizeof(*cfg));
  
  	cfg->fc_table = rtm->rtm_table;
  	cfg->fc_dst_len = rtm->rtm_dst_len;
  	cfg->fc_src_len = rtm->rtm_src_len;
  	cfg->fc_flags = RTF_UP;
  	cfg->fc_protocol = rtm->rtm_protocol;
  
  	if (rtm->rtm_type == RTN_UNREACHABLE)
  		cfg->fc_flags |= RTF_REJECT;
ab79ad14a   Maciej Żenczykowski   ipv6: Implement A...
2134
2135
  	if (rtm->rtm_type == RTN_LOCAL)
  		cfg->fc_flags |= RTF_LOCAL;
86872cb57   Thomas Graf   [IPv6] route: FIB...
2136
2137
  	cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid;
  	cfg->fc_nlinfo.nlh = nlh;
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2138
  	cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
86872cb57   Thomas Graf   [IPv6] route: FIB...
2139
2140
2141
2142
  
  	if (tb[RTA_GATEWAY]) {
  		nla_memcpy(&cfg->fc_gateway, tb[RTA_GATEWAY], 16);
  		cfg->fc_flags |= RTF_GATEWAY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2143
  	}
86872cb57   Thomas Graf   [IPv6] route: FIB...
2144
2145
2146
2147
2148
2149
2150
2151
  
  	if (tb[RTA_DST]) {
  		int plen = (rtm->rtm_dst_len + 7) >> 3;
  
  		if (nla_len(tb[RTA_DST]) < plen)
  			goto errout;
  
  		nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2152
  	}
86872cb57   Thomas Graf   [IPv6] route: FIB...
2153
2154
2155
2156
2157
2158
2159
2160
  
  	if (tb[RTA_SRC]) {
  		int plen = (rtm->rtm_src_len + 7) >> 3;
  
  		if (nla_len(tb[RTA_SRC]) < plen)
  			goto errout;
  
  		nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2161
  	}
86872cb57   Thomas Graf   [IPv6] route: FIB...
2162

c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
2163
2164
  	if (tb[RTA_PREFSRC])
  		nla_memcpy(&cfg->fc_prefsrc, tb[RTA_PREFSRC], 16);
86872cb57   Thomas Graf   [IPv6] route: FIB...
2165
2166
2167
2168
2169
2170
2171
2172
2173
  	if (tb[RTA_OIF])
  		cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
  
  	if (tb[RTA_PRIORITY])
  		cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
  
  	if (tb[RTA_METRICS]) {
  		cfg->fc_mx = nla_data(tb[RTA_METRICS]);
  		cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2174
  	}
86872cb57   Thomas Graf   [IPv6] route: FIB...
2175
2176
2177
2178
2179
2180
2181
  
  	if (tb[RTA_TABLE])
  		cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
  
  	err = 0;
  errout:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2182
  }
c127ea2c4   Thomas Graf   [IPv6]: Use rtnl ...
2183
  static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2184
  {
86872cb57   Thomas Graf   [IPv6] route: FIB...
2185
2186
  	struct fib6_config cfg;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2187

86872cb57   Thomas Graf   [IPv6] route: FIB...
2188
2189
2190
2191
2192
  	err = rtm_to_fib6_config(skb, nlh, &cfg);
  	if (err < 0)
  		return err;
  
  	return ip6_route_del(&cfg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2193
  }
c127ea2c4   Thomas Graf   [IPv6]: Use rtnl ...
2194
  static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2195
  {
86872cb57   Thomas Graf   [IPv6] route: FIB...
2196
2197
  	struct fib6_config cfg;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2198

86872cb57   Thomas Graf   [IPv6] route: FIB...
2199
2200
2201
2202
2203
  	err = rtm_to_fib6_config(skb, nlh, &cfg);
  	if (err < 0)
  		return err;
  
  	return ip6_route_add(&cfg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2204
  }
339bf98ff   Thomas Graf   [NETLINK]: Do pre...
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
  static inline size_t rt6_nlmsg_size(void)
  {
  	return NLMSG_ALIGN(sizeof(struct rtmsg))
  	       + nla_total_size(16) /* RTA_SRC */
  	       + nla_total_size(16) /* RTA_DST */
  	       + nla_total_size(16) /* RTA_GATEWAY */
  	       + nla_total_size(16) /* RTA_PREFSRC */
  	       + nla_total_size(4) /* RTA_TABLE */
  	       + nla_total_size(4) /* RTA_IIF */
  	       + nla_total_size(4) /* RTA_OIF */
  	       + nla_total_size(4) /* RTA_PRIORITY */
6a2b9ce0a   Noriaki TAKAMIYA   [IPV6]: Fixed the...
2216
  	       + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
339bf98ff   Thomas Graf   [NETLINK]: Do pre...
2217
2218
  	       + nla_total_size(sizeof(struct rta_cacheinfo));
  }
191cd5825   Brian Haley   netns: Add networ...
2219
2220
  static int rt6_fill_node(struct net *net,
  			 struct sk_buff *skb, struct rt6_info *rt,
0d51aa80a   Jamal Hadi Salim   [IPV6]: V6 route ...
2221
2222
  			 struct in6_addr *dst, struct in6_addr *src,
  			 int iif, int type, u32 pid, u32 seq,
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2223
  			 int prefix, int nowait, unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2224
  {
346f870b8   David S. Miller   ipv6: Report TCP ...
2225
  	const struct inet_peer *peer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2226
  	struct rtmsg *rtm;
2d7202bfd   Thomas Graf   [IPv6] route: Con...
2227
  	struct nlmsghdr *nlh;
e3703b3de   Thomas Graf   [RTNETLINK]: Add ...
2228
  	long expires;
9e762a4a8   Patrick McHardy   [NET]: Introduce ...
2229
  	u32 table;
f2c31e32b   Eric Dumazet   net: fix NULL der...
2230
  	struct neighbour *n;
346f870b8   David S. Miller   ipv6: Report TCP ...
2231
  	u32 ts, tsage;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2232
2233
2234
2235
2236
2237
2238
  
  	if (prefix) {	/* user wants prefix routes only */
  		if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
  			/* success since this is not a prefix route */
  			return 1;
  		}
  	}
2d7202bfd   Thomas Graf   [IPv6] route: Con...
2239
  	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*rtm), flags);
383084739   David S. Miller   ipv6: Various cle...
2240
  	if (!nlh)
26932566a   Patrick McHardy   [NETLINK]: Don't ...
2241
  		return -EMSGSIZE;
2d7202bfd   Thomas Graf   [IPv6] route: Con...
2242
2243
  
  	rtm = nlmsg_data(nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2244
2245
2246
2247
  	rtm->rtm_family = AF_INET6;
  	rtm->rtm_dst_len = rt->rt6i_dst.plen;
  	rtm->rtm_src_len = rt->rt6i_src.plen;
  	rtm->rtm_tos = 0;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
2248
  	if (rt->rt6i_table)
9e762a4a8   Patrick McHardy   [NET]: Introduce ...
2249
  		table = rt->rt6i_table->tb6_id;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
2250
  	else
9e762a4a8   Patrick McHardy   [NET]: Introduce ...
2251
2252
  		table = RT6_TABLE_UNSPEC;
  	rtm->rtm_table = table;
2d7202bfd   Thomas Graf   [IPv6] route: Con...
2253
  	NLA_PUT_U32(skb, RTA_TABLE, table);
383084739   David S. Miller   ipv6: Various cle...
2254
  	if (rt->rt6i_flags & RTF_REJECT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2255
  		rtm->rtm_type = RTN_UNREACHABLE;
383084739   David S. Miller   ipv6: Various cle...
2256
  	else if (rt->rt6i_flags & RTF_LOCAL)
ab79ad14a   Maciej Żenczykowski   ipv6: Implement A...
2257
  		rtm->rtm_type = RTN_LOCAL;
d19185428   David S. Miller   ipv6: Kill rt6i_d...
2258
  	else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2259
2260
2261
2262
2263
2264
  		rtm->rtm_type = RTN_LOCAL;
  	else
  		rtm->rtm_type = RTN_UNICAST;
  	rtm->rtm_flags = 0;
  	rtm->rtm_scope = RT_SCOPE_UNIVERSE;
  	rtm->rtm_protocol = rt->rt6i_protocol;
383084739   David S. Miller   ipv6: Various cle...
2265
  	if (rt->rt6i_flags & RTF_DYNAMIC)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2266
2267
2268
  		rtm->rtm_protocol = RTPROT_REDIRECT;
  	else if (rt->rt6i_flags & RTF_ADDRCONF)
  		rtm->rtm_protocol = RTPROT_KERNEL;
383084739   David S. Miller   ipv6: Various cle...
2269
  	else if (rt->rt6i_flags & RTF_DEFAULT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2270
  		rtm->rtm_protocol = RTPROT_RA;
383084739   David S. Miller   ipv6: Various cle...
2271
  	if (rt->rt6i_flags & RTF_CACHE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2272
2273
2274
  		rtm->rtm_flags |= RTM_F_CLONED;
  
  	if (dst) {
2d7202bfd   Thomas Graf   [IPv6] route: Con...
2275
  		NLA_PUT(skb, RTA_DST, 16, dst);
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
2276
  		rtm->rtm_dst_len = 128;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2277
  	} else if (rtm->rtm_dst_len)
2d7202bfd   Thomas Graf   [IPv6] route: Con...
2278
  		NLA_PUT(skb, RTA_DST, 16, &rt->rt6i_dst.addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2279
2280
  #ifdef CONFIG_IPV6_SUBTREES
  	if (src) {
2d7202bfd   Thomas Graf   [IPv6] route: Con...
2281
  		NLA_PUT(skb, RTA_SRC, 16, src);
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
2282
  		rtm->rtm_src_len = 128;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2283
  	} else if (rtm->rtm_src_len)
2d7202bfd   Thomas Graf   [IPv6] route: Con...
2284
  		NLA_PUT(skb, RTA_SRC, 16, &rt->rt6i_src.addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2285
  #endif
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2286
2287
2288
  	if (iif) {
  #ifdef CONFIG_IPV6_MROUTE
  		if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
8229efdae   Benjamin Thery   netns: ip6mr: ena...
2289
  			int err = ip6mr_get_route(net, skb, rtm, nowait);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
  			if (err <= 0) {
  				if (!nowait) {
  					if (err == 0)
  						return 0;
  					goto nla_put_failure;
  				} else {
  					if (err == -EMSGSIZE)
  						goto nla_put_failure;
  				}
  			}
  		} else
  #endif
  			NLA_PUT_U32(skb, RTA_IIF, iif);
  	} else if (dst) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2304
  		struct in6_addr saddr_buf;
c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
2305
  		if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0)
2d7202bfd   Thomas Graf   [IPv6] route: Con...
2306
  			NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2307
  	}
2d7202bfd   Thomas Graf   [IPv6] route: Con...
2308

c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
2309
2310
  	if (rt->rt6i_prefsrc.plen) {
  		struct in6_addr saddr_buf;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
2311
  		saddr_buf = rt->rt6i_prefsrc.addr;
c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
2312
2313
  		NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
  	}
defb3519a   David S. Miller   net: Abstract awa...
2314
  	if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
2d7202bfd   Thomas Graf   [IPv6] route: Con...
2315
  		goto nla_put_failure;
f2c31e32b   Eric Dumazet   net: fix NULL der...
2316
  	rcu_read_lock();
272174550   David Miller   net: Rename dst_g...
2317
  	n = dst_get_neighbour_noref(&rt->dst);
f2c31e32b   Eric Dumazet   net: fix NULL der...
2318
2319
2320
  	if (n)
  		NLA_PUT(skb, RTA_GATEWAY, 16, &n->primary_key);
  	rcu_read_unlock();
2d7202bfd   Thomas Graf   [IPv6] route: Con...
2321

d8d1f30b9   Changli Gao   net-next: remove ...
2322
  	if (rt->dst.dev)
d19185428   David S. Miller   ipv6: Kill rt6i_d...
2323
  		NLA_PUT_U32(skb, RTA_OIF, rt->dst.dev->ifindex);
2d7202bfd   Thomas Graf   [IPv6] route: Con...
2324
2325
  
  	NLA_PUT_U32(skb, RTA_PRIORITY, rt->rt6i_metric);
e3703b3de   Thomas Graf   [RTNETLINK]: Add ...
2326

36e3deae8   YOSHIFUJI Hideaki   ipv6 route: Fix r...
2327
2328
  	if (!(rt->rt6i_flags & RTF_EXPIRES))
  		expires = 0;
d19185428   David S. Miller   ipv6: Kill rt6i_d...
2329
2330
  	else if (rt->dst.expires - jiffies < INT_MAX)
  		expires = rt->dst.expires - jiffies;
36e3deae8   YOSHIFUJI Hideaki   ipv6 route: Fix r...
2331
2332
  	else
  		expires = INT_MAX;
69cdf8f92   YOSHIFUJI Hideaki   ipv6 route: Fix l...
2333

346f870b8   David S. Miller   ipv6: Report TCP ...
2334
2335
2336
2337
2338
2339
2340
2341
  	peer = rt->rt6i_peer;
  	ts = tsage = 0;
  	if (peer && peer->tcp_ts_stamp) {
  		ts = peer->tcp_ts;
  		tsage = get_seconds() - peer->tcp_ts_stamp;
  	}
  
  	if (rtnl_put_cacheinfo(skb, &rt->dst, 0, ts, tsage,
d8d1f30b9   Changli Gao   net-next: remove ...
2342
  			       expires, rt->dst.error) < 0)
e3703b3de   Thomas Graf   [RTNETLINK]: Add ...
2343
  		goto nla_put_failure;
2d7202bfd   Thomas Graf   [IPv6] route: Con...
2344
2345
2346
2347
  
  	return nlmsg_end(skb, nlh);
  
  nla_put_failure:
26932566a   Patrick McHardy   [NETLINK]: Don't ...
2348
2349
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2350
  }
1b43af548   Patrick McHardy   [IPV6]: Increase ...
2351
  int rt6_dump_route(struct rt6_info *rt, void *p_arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2352
2353
2354
  {
  	struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
  	int prefix;
2d7202bfd   Thomas Graf   [IPv6] route: Con...
2355
2356
  	if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
  		struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2357
2358
2359
  		prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0;
  	} else
  		prefix = 0;
191cd5825   Brian Haley   netns: Add networ...
2360
2361
  	return rt6_fill_node(arg->net,
  		     arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2362
  		     NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq,
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2363
  		     prefix, 0, NLM_F_MULTI);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2364
  }
c127ea2c4   Thomas Graf   [IPv6]: Use rtnl ...
2365
  static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2366
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2367
  	struct net *net = sock_net(in_skb->sk);
ab364a6f9   Thomas Graf   [IPv6] route: Con...
2368
2369
  	struct nlattr *tb[RTA_MAX+1];
  	struct rt6_info *rt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2370
  	struct sk_buff *skb;
ab364a6f9   Thomas Graf   [IPv6] route: Con...
2371
  	struct rtmsg *rtm;
4c9483b2f   David S. Miller   ipv6: Convert to ...
2372
  	struct flowi6 fl6;
ab364a6f9   Thomas Graf   [IPv6] route: Con...
2373
  	int err, iif = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2374

ab364a6f9   Thomas Graf   [IPv6] route: Con...
2375
2376
2377
  	err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
  	if (err < 0)
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2378

ab364a6f9   Thomas Graf   [IPv6] route: Con...
2379
  	err = -EINVAL;
4c9483b2f   David S. Miller   ipv6: Convert to ...
2380
  	memset(&fl6, 0, sizeof(fl6));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2381

ab364a6f9   Thomas Graf   [IPv6] route: Con...
2382
2383
2384
  	if (tb[RTA_SRC]) {
  		if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
  			goto errout;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
2385
  		fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
ab364a6f9   Thomas Graf   [IPv6] route: Con...
2386
2387
2388
2389
2390
  	}
  
  	if (tb[RTA_DST]) {
  		if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
  			goto errout;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
2391
  		fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
ab364a6f9   Thomas Graf   [IPv6] route: Con...
2392
2393
2394
2395
2396
2397
  	}
  
  	if (tb[RTA_IIF])
  		iif = nla_get_u32(tb[RTA_IIF]);
  
  	if (tb[RTA_OIF])
4c9483b2f   David S. Miller   ipv6: Convert to ...
2398
  		fl6.flowi6_oif = nla_get_u32(tb[RTA_OIF]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2399
2400
2401
  
  	if (iif) {
  		struct net_device *dev;
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
2402
  		dev = __dev_get_by_index(net, iif);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2403
2404
  		if (!dev) {
  			err = -ENODEV;
ab364a6f9   Thomas Graf   [IPv6] route: Con...
2405
  			goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2406
2407
  		}
  	}
ab364a6f9   Thomas Graf   [IPv6] route: Con...
2408
  	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
383084739   David S. Miller   ipv6: Various cle...
2409
  	if (!skb) {
ab364a6f9   Thomas Graf   [IPv6] route: Con...
2410
2411
2412
  		err = -ENOBUFS;
  		goto errout;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2413

ab364a6f9   Thomas Graf   [IPv6] route: Con...
2414
2415
2416
  	/* Reserve room for dummy headers, this skb can pass
  	   through good chunk of routing engine.
  	 */
459a98ed8   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
2417
  	skb_reset_mac_header(skb);
ab364a6f9   Thomas Graf   [IPv6] route: Con...
2418
  	skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2419

4c9483b2f   David S. Miller   ipv6: Convert to ...
2420
  	rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl6);
d8d1f30b9   Changli Gao   net-next: remove ...
2421
  	skb_dst_set(skb, &rt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2422

4c9483b2f   David S. Miller   ipv6: Convert to ...
2423
  	err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2424
  			    RTM_NEWROUTE, NETLINK_CB(in_skb).pid,
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2425
  			    nlh->nlmsg_seq, 0, 0, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2426
  	if (err < 0) {
ab364a6f9   Thomas Graf   [IPv6] route: Con...
2427
2428
  		kfree_skb(skb);
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2429
  	}
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
2430
  	err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid);
ab364a6f9   Thomas Graf   [IPv6] route: Con...
2431
  errout:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2432
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2433
  }
86872cb57   Thomas Graf   [IPv6] route: FIB...
2434
  void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2435
2436
  {
  	struct sk_buff *skb;
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
2437
  	struct net *net = info->nl_net;
528c4ceb4   Denis V. Lunev   [IPV6]: Always pa...
2438
2439
2440
2441
  	u32 seq;
  	int err;
  
  	err = -ENOBUFS;
383084739   David S. Miller   ipv6: Various cle...
2442
  	seq = info->nlh ? info->nlh->nlmsg_seq : 0;
86872cb57   Thomas Graf   [IPv6] route: FIB...
2443

339bf98ff   Thomas Graf   [NETLINK]: Do pre...
2444
  	skb = nlmsg_new(rt6_nlmsg_size(), gfp_any());
383084739   David S. Miller   ipv6: Various cle...
2445
  	if (!skb)
21713ebc4   Thomas Graf   [IPv6] route: Con...
2446
  		goto errout;
191cd5825   Brian Haley   netns: Add networ...
2447
  	err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2448
  				event, info->pid, seq, 0, 0, 0);
26932566a   Patrick McHardy   [NETLINK]: Don't ...
2449
2450
2451
2452
2453
2454
  	if (err < 0) {
  		/* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
  		WARN_ON(err == -EMSGSIZE);
  		kfree_skb(skb);
  		goto errout;
  	}
1ce85fe40   Pablo Neira Ayuso   netlink: change n...
2455
2456
2457
  	rtnl_notify(skb, net, info->pid, RTNLGRP_IPV6_ROUTE,
  		    info->nlh, gfp_any());
  	return;
21713ebc4   Thomas Graf   [IPv6] route: Con...
2458
2459
  errout:
  	if (err < 0)
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
2460
  		rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2461
  }
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2462
2463
2464
2465
  static int ip6_route_dev_notify(struct notifier_block *this,
  				unsigned long event, void *data)
  {
  	struct net_device *dev = (struct net_device *)data;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2466
  	struct net *net = dev_net(dev);
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2467
2468
  
  	if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
d8d1f30b9   Changli Gao   net-next: remove ...
2469
  		net->ipv6.ip6_null_entry->dst.dev = dev;
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2470
2471
  		net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
  #ifdef CONFIG_IPV6_MULTIPLE_TABLES
d8d1f30b9   Changli Gao   net-next: remove ...
2472
  		net->ipv6.ip6_prohibit_entry->dst.dev = dev;
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2473
  		net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
d8d1f30b9   Changli Gao   net-next: remove ...
2474
  		net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2475
2476
2477
2478
2479
2480
  		net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
  #endif
  	}
  
  	return NOTIFY_OK;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2481
2482
2483
2484
2485
  /*
   *	/proc
   */
  
  #ifdef CONFIG_PROC_FS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
  struct rt6_proc_arg
  {
  	char *buffer;
  	int offset;
  	int length;
  	int skip;
  	int len;
  };
  
  static int rt6_info_route(struct rt6_info *rt, void *p_arg)
  {
33120b30c   Alexey Dobriyan   [IPV6]: Convert /...
2497
  	struct seq_file *m = p_arg;
69cce1d14   David S. Miller   net: Abstract dst...
2498
  	struct neighbour *n;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2499

4b7a4274c   Harvey Harrison   net: replace %#p6...
2500
  	seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2501
2502
  
  #ifdef CONFIG_IPV6_SUBTREES
4b7a4274c   Harvey Harrison   net: replace %#p6...
2503
  	seq_printf(m, "%pi6 %02x ", &rt->rt6i_src.addr, rt->rt6i_src.plen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2504
  #else
33120b30c   Alexey Dobriyan   [IPV6]: Convert /...
2505
  	seq_puts(m, "00000000000000000000000000000000 00 ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2506
  #endif
f2c31e32b   Eric Dumazet   net: fix NULL der...
2507
  	rcu_read_lock();
272174550   David Miller   net: Rename dst_g...
2508
  	n = dst_get_neighbour_noref(&rt->dst);
69cce1d14   David S. Miller   net: Abstract dst...
2509
2510
  	if (n) {
  		seq_printf(m, "%pi6", n->primary_key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2511
  	} else {
33120b30c   Alexey Dobriyan   [IPV6]: Convert /...
2512
  		seq_puts(m, "00000000000000000000000000000000");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2513
  	}
f2c31e32b   Eric Dumazet   net: fix NULL der...
2514
  	rcu_read_unlock();
33120b30c   Alexey Dobriyan   [IPV6]: Convert /...
2515
2516
  	seq_printf(m, " %08x %08x %08x %08x %8s
  ",
d8d1f30b9   Changli Gao   net-next: remove ...
2517
2518
  		   rt->rt6i_metric, atomic_read(&rt->dst.__refcnt),
  		   rt->dst.__use, rt->rt6i_flags,
d19185428   David S. Miller   ipv6: Kill rt6i_d...
2519
  		   rt->dst.dev ? rt->dst.dev->name : "");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2520
2521
  	return 0;
  }
33120b30c   Alexey Dobriyan   [IPV6]: Convert /...
2522
  static int ipv6_route_show(struct seq_file *m, void *v)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2523
  {
f3db48517   Daniel Lezcano   [NETNS][IPV6] ip6...
2524
  	struct net *net = (struct net *)m->private;
32b293a53   Josh Hunt   IPv6: Avoid takin...
2525
  	fib6_clean_all_ro(net, rt6_info_route, 0, m);
33120b30c   Alexey Dobriyan   [IPV6]: Convert /...
2526
2527
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2528

33120b30c   Alexey Dobriyan   [IPV6]: Convert /...
2529
2530
  static int ipv6_route_open(struct inode *inode, struct file *file)
  {
de05c557b   Pavel Emelyanov   proc: consolidate...
2531
  	return single_open_net(inode, file, ipv6_route_show);
f3db48517   Daniel Lezcano   [NETNS][IPV6] ip6...
2532
  }
33120b30c   Alexey Dobriyan   [IPV6]: Convert /...
2533
2534
2535
2536
2537
  static const struct file_operations ipv6_route_proc_fops = {
  	.owner		= THIS_MODULE,
  	.open		= ipv6_route_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
b6fcbdb4f   Pavel Emelyanov   proc: consolidate...
2538
  	.release	= single_release_net,
33120b30c   Alexey Dobriyan   [IPV6]: Convert /...
2539
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2540
2541
  static int rt6_stats_seq_show(struct seq_file *seq, void *v)
  {
69ddb8056   Daniel Lezcano   [NETNS][IPV6] rou...
2542
  	struct net *net = (struct net *)seq->private;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2543
2544
  	seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x
  ",
69ddb8056   Daniel Lezcano   [NETNS][IPV6] rou...
2545
2546
2547
2548
2549
  		   net->ipv6.rt6_stats->fib_nodes,
  		   net->ipv6.rt6_stats->fib_route_nodes,
  		   net->ipv6.rt6_stats->fib_rt_alloc,
  		   net->ipv6.rt6_stats->fib_rt_entries,
  		   net->ipv6.rt6_stats->fib_rt_cache,
fc66f95c6   Eric Dumazet   net dst: use a pe...
2550
  		   dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
69ddb8056   Daniel Lezcano   [NETNS][IPV6] rou...
2551
  		   net->ipv6.rt6_stats->fib_discarded_routes);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2552
2553
2554
2555
2556
2557
  
  	return 0;
  }
  
  static int rt6_stats_seq_open(struct inode *inode, struct file *file)
  {
de05c557b   Pavel Emelyanov   proc: consolidate...
2558
  	return single_open_net(inode, file, rt6_stats_seq_show);
69ddb8056   Daniel Lezcano   [NETNS][IPV6] rou...
2559
  }
9a32144e9   Arjan van de Ven   [PATCH] mark stru...
2560
  static const struct file_operations rt6_stats_seq_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2561
2562
2563
2564
  	.owner	 = THIS_MODULE,
  	.open	 = rt6_stats_seq_open,
  	.read	 = seq_read,
  	.llseek	 = seq_lseek,
b6fcbdb4f   Pavel Emelyanov   proc: consolidate...
2565
  	.release = single_release_net,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2566
2567
2568
2569
  };
  #endif	/* CONFIG_PROC_FS */
  
  #ifdef CONFIG_SYSCTL
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2570
  static
8d65af789   Alexey Dobriyan   sysctl: remove "s...
2571
  int ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2572
2573
  			      void __user *buffer, size_t *lenp, loff_t *ppos)
  {
c486da343   Lucian Adrian Grijincu   sysctl: ipv6: use...
2574
2575
2576
  	struct net *net;
  	int delay;
  	if (!write)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2577
  		return -EINVAL;
c486da343   Lucian Adrian Grijincu   sysctl: ipv6: use...
2578
2579
2580
2581
2582
2583
  
  	net = (struct net *)ctl->extra1;
  	delay = net->ipv6.sysctl.flush_delay;
  	proc_dointvec(ctl, write, buffer, lenp, ppos);
  	fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2584
  }
760f2d018   Daniel Lezcano   [NETNS][IPV6]: Ma...
2585
  ctl_table ipv6_route_table_template[] = {
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
2586
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2587
  		.procname	=	"flush",
4990509f1   Daniel Lezcano   [NETNS][IPV6]: Ma...
2588
  		.data		=	&init_net.ipv6.sysctl.flush_delay,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2589
  		.maxlen		=	sizeof(int),
89c8b3a11   Dave Jones   [IPV6]: Incorrect...
2590
  		.mode		=	0200,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2591
  		.proc_handler	=	ipv6_sysctl_rtcache_flush
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2592
2593
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2594
  		.procname	=	"gc_thresh",
9a7ec3a94   Daniel Lezcano   [NETNS][IPV6] rou...
2595
  		.data		=	&ip6_dst_ops_template.gc_thresh,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2596
2597
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2598
  		.proc_handler	=	proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2599
2600
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2601
  		.procname	=	"max_size",
4990509f1   Daniel Lezcano   [NETNS][IPV6]: Ma...
2602
  		.data		=	&init_net.ipv6.sysctl.ip6_rt_max_size,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2603
2604
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2605
  		.proc_handler	=	proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2606
2607
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2608
  		.procname	=	"gc_min_interval",
4990509f1   Daniel Lezcano   [NETNS][IPV6]: Ma...
2609
  		.data		=	&init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2610
2611
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2612
  		.proc_handler	=	proc_dointvec_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2613
2614
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2615
  		.procname	=	"gc_timeout",
4990509f1   Daniel Lezcano   [NETNS][IPV6]: Ma...
2616
  		.data		=	&init_net.ipv6.sysctl.ip6_rt_gc_timeout,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2617
2618
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2619
  		.proc_handler	=	proc_dointvec_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2620
2621
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2622
  		.procname	=	"gc_interval",
4990509f1   Daniel Lezcano   [NETNS][IPV6]: Ma...
2623
  		.data		=	&init_net.ipv6.sysctl.ip6_rt_gc_interval,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2624
2625
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2626
  		.proc_handler	=	proc_dointvec_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2627
2628
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2629
  		.procname	=	"gc_elasticity",
4990509f1   Daniel Lezcano   [NETNS][IPV6]: Ma...
2630
  		.data		=	&init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2631
2632
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
f3d3f616e   Min Zhang   ipv6: remove sysc...
2633
  		.proc_handler	=	proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2634
2635
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2636
  		.procname	=	"mtu_expires",
4990509f1   Daniel Lezcano   [NETNS][IPV6]: Ma...
2637
  		.data		=	&init_net.ipv6.sysctl.ip6_rt_mtu_expires,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2638
2639
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2640
  		.proc_handler	=	proc_dointvec_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2641
2642
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2643
  		.procname	=	"min_adv_mss",
4990509f1   Daniel Lezcano   [NETNS][IPV6]: Ma...
2644
  		.data		=	&init_net.ipv6.sysctl.ip6_rt_min_advmss,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2645
2646
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
f3d3f616e   Min Zhang   ipv6: remove sysc...
2647
  		.proc_handler	=	proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2648
2649
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2650
  		.procname	=	"gc_min_interval_ms",
4990509f1   Daniel Lezcano   [NETNS][IPV6]: Ma...
2651
  		.data		=	&init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2652
2653
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2654
  		.proc_handler	=	proc_dointvec_ms_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2655
  	},
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
2656
  	{ }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2657
  };
2c8c1e729   Alexey Dobriyan   net: spread __net...
2658
  struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
760f2d018   Daniel Lezcano   [NETNS][IPV6]: Ma...
2659
2660
2661
2662
2663
2664
  {
  	struct ctl_table *table;
  
  	table = kmemdup(ipv6_route_table_template,
  			sizeof(ipv6_route_table_template),
  			GFP_KERNEL);
5ee091050   YOSHIFUJI Hideaki   [IPV6] SYSCTL: co...
2665
2666
2667
  
  	if (table) {
  		table[0].data = &net->ipv6.sysctl.flush_delay;
c486da343   Lucian Adrian Grijincu   sysctl: ipv6: use...
2668
  		table[0].extra1 = net;
86393e52c   Alexey Dobriyan   netns: embed ip6_...
2669
  		table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
5ee091050   YOSHIFUJI Hideaki   [IPV6] SYSCTL: co...
2670
2671
2672
2673
2674
2675
2676
  		table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
  		table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
  		table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
  		table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
  		table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
  		table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
  		table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
9c69fabe7   Alexey Dobriyan   netns: fix net.ip...
2677
  		table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
5ee091050   YOSHIFUJI Hideaki   [IPV6] SYSCTL: co...
2678
  	}
760f2d018   Daniel Lezcano   [NETNS][IPV6]: Ma...
2679
2680
  	return table;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2681
  #endif
2c8c1e729   Alexey Dobriyan   net: spread __net...
2682
  static int __net_init ip6_route_net_init(struct net *net)
cdb187619   Daniel Lezcano   [NETNS][IPV6] rou...
2683
  {
633d424bf   Pavel Emelyanov   [NETNS]: Don't in...
2684
  	int ret = -ENOMEM;
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2685

86393e52c   Alexey Dobriyan   netns: embed ip6_...
2686
2687
  	memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
  	       sizeof(net->ipv6.ip6_dst_ops));
f2fc6a545   Benjamin Thery   [NETNS][IPV6] rou...
2688

fc66f95c6   Eric Dumazet   net dst: use a pe...
2689
2690
  	if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
  		goto out_ip6_dst_ops;
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2691
2692
2693
2694
  	net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
  					   sizeof(*net->ipv6.ip6_null_entry),
  					   GFP_KERNEL);
  	if (!net->ipv6.ip6_null_entry)
fc66f95c6   Eric Dumazet   net dst: use a pe...
2695
  		goto out_ip6_dst_entries;
d8d1f30b9   Changli Gao   net-next: remove ...
2696
  	net->ipv6.ip6_null_entry->dst.path =
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2697
  		(struct dst_entry *)net->ipv6.ip6_null_entry;
d8d1f30b9   Changli Gao   net-next: remove ...
2698
  	net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
62fa8a846   David S. Miller   net: Implement re...
2699
2700
  	dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
  			 ip6_template_metrics, true);
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2701
2702
2703
2704
2705
  
  #ifdef CONFIG_IPV6_MULTIPLE_TABLES
  	net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
  					       sizeof(*net->ipv6.ip6_prohibit_entry),
  					       GFP_KERNEL);
68fffc679   Peter Zijlstra   ipv6: clean up ip...
2706
2707
  	if (!net->ipv6.ip6_prohibit_entry)
  		goto out_ip6_null_entry;
d8d1f30b9   Changli Gao   net-next: remove ...
2708
  	net->ipv6.ip6_prohibit_entry->dst.path =
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2709
  		(struct dst_entry *)net->ipv6.ip6_prohibit_entry;
d8d1f30b9   Changli Gao   net-next: remove ...
2710
  	net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
62fa8a846   David S. Miller   net: Implement re...
2711
2712
  	dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
  			 ip6_template_metrics, true);
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2713
2714
2715
2716
  
  	net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
  					       sizeof(*net->ipv6.ip6_blk_hole_entry),
  					       GFP_KERNEL);
68fffc679   Peter Zijlstra   ipv6: clean up ip...
2717
2718
  	if (!net->ipv6.ip6_blk_hole_entry)
  		goto out_ip6_prohibit_entry;
d8d1f30b9   Changli Gao   net-next: remove ...
2719
  	net->ipv6.ip6_blk_hole_entry->dst.path =
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2720
  		(struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
d8d1f30b9   Changli Gao   net-next: remove ...
2721
  	net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
62fa8a846   David S. Miller   net: Implement re...
2722
2723
  	dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
  			 ip6_template_metrics, true);
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2724
  #endif
b339a47c3   Peter Zijlstra   ipv6: initialize ...
2725
2726
2727
2728
2729
2730
2731
2732
  	net->ipv6.sysctl.flush_delay = 0;
  	net->ipv6.sysctl.ip6_rt_max_size = 4096;
  	net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
  	net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
  	net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
  	net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
  	net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
  	net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
cdb187619   Daniel Lezcano   [NETNS][IPV6] rou...
2733
2734
2735
2736
  #ifdef CONFIG_PROC_FS
  	proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops);
  	proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops);
  #endif
6891a346c   Benjamin Thery   [NETNS][IPV6] rou...
2737
  	net->ipv6.ip6_rt_gc_expire = 30*HZ;
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2738
2739
2740
  	ret = 0;
  out:
  	return ret;
f2fc6a545   Benjamin Thery   [NETNS][IPV6] rou...
2741

68fffc679   Peter Zijlstra   ipv6: clean up ip...
2742
2743
2744
2745
2746
2747
  #ifdef CONFIG_IPV6_MULTIPLE_TABLES
  out_ip6_prohibit_entry:
  	kfree(net->ipv6.ip6_prohibit_entry);
  out_ip6_null_entry:
  	kfree(net->ipv6.ip6_null_entry);
  #endif
fc66f95c6   Eric Dumazet   net dst: use a pe...
2748
2749
  out_ip6_dst_entries:
  	dst_entries_destroy(&net->ipv6.ip6_dst_ops);
f2fc6a545   Benjamin Thery   [NETNS][IPV6] rou...
2750
  out_ip6_dst_ops:
f2fc6a545   Benjamin Thery   [NETNS][IPV6] rou...
2751
  	goto out;
cdb187619   Daniel Lezcano   [NETNS][IPV6] rou...
2752
  }
2c8c1e729   Alexey Dobriyan   net: spread __net...
2753
  static void __net_exit ip6_route_net_exit(struct net *net)
cdb187619   Daniel Lezcano   [NETNS][IPV6] rou...
2754
2755
2756
2757
2758
  {
  #ifdef CONFIG_PROC_FS
  	proc_net_remove(net, "ipv6_route");
  	proc_net_remove(net, "rt6_stats");
  #endif
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2759
2760
2761
2762
2763
  	kfree(net->ipv6.ip6_null_entry);
  #ifdef CONFIG_IPV6_MULTIPLE_TABLES
  	kfree(net->ipv6.ip6_prohibit_entry);
  	kfree(net->ipv6.ip6_blk_hole_entry);
  #endif
41bb78b4b   Xiaotian Feng   net dst: fix perc...
2764
  	dst_entries_destroy(&net->ipv6.ip6_dst_ops);
cdb187619   Daniel Lezcano   [NETNS][IPV6] rou...
2765
2766
2767
2768
2769
2770
  }
  
  static struct pernet_operations ip6_route_net_ops = {
  	.init = ip6_route_net_init,
  	.exit = ip6_route_net_exit,
  };
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2771
2772
2773
2774
  static struct notifier_block ip6_route_dev_notifier = {
  	.notifier_call = ip6_route_dev_notify,
  	.priority = 0,
  };
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
2775
  int __init ip6_route_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2776
  {
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
2777
  	int ret;
9a7ec3a94   Daniel Lezcano   [NETNS][IPV6] rou...
2778
2779
  	ret = -ENOMEM;
  	ip6_dst_ops_template.kmem_cachep =
e5d679f33   Alexey Dobriyan   [NET]: Use SLAB_P...
2780
  		kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
f845ab6b7   Daniel Lezcano   [IPV6] route6/fib...
2781
  				  SLAB_HWCACHE_ALIGN, NULL);
9a7ec3a94   Daniel Lezcano   [NETNS][IPV6] rou...
2782
  	if (!ip6_dst_ops_template.kmem_cachep)
c19a28e11   Fernando Carrijo   remove lots of do...
2783
  		goto out;
14e50e57a   David S. Miller   [XFRM]: Allow pac...
2784

fc66f95c6   Eric Dumazet   net dst: use a pe...
2785
  	ret = dst_entries_init(&ip6_dst_blackhole_ops);
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2786
  	if (ret)
bdb3289f7   Daniel Lezcano   [NETNS][IPV6] rt6...
2787
  		goto out_kmem_cache;
bdb3289f7   Daniel Lezcano   [NETNS][IPV6] rt6...
2788

fc66f95c6   Eric Dumazet   net dst: use a pe...
2789
2790
2791
  	ret = register_pernet_subsys(&ip6_route_net_ops);
  	if (ret)
  		goto out_dst_entries;
5dc121e9a   Arnaud Ebalard   XFRM,IPv6: initia...
2792
  	ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2793
2794
2795
  	/* Registering of the loopback is done before this portion of code,
  	 * the loopback reference in rt6_info will not be taken, do it
  	 * manually for init_net */
d8d1f30b9   Changli Gao   net-next: remove ...
2796
  	init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2797
2798
  	init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
    #ifdef CONFIG_IPV6_MULTIPLE_TABLES
d8d1f30b9   Changli Gao   net-next: remove ...
2799
  	init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2800
  	init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
d8d1f30b9   Changli Gao   net-next: remove ...
2801
  	init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2802
2803
  	init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
    #endif
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
2804
2805
  	ret = fib6_init();
  	if (ret)
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2806
  		goto out_register_subsys;
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
2807

433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
2808
2809
  	ret = xfrm6_init();
  	if (ret)
cdb187619   Daniel Lezcano   [NETNS][IPV6] rou...
2810
  		goto out_fib6_init;
c35b7e72c   Daniel Lezcano   [IPV6]: remove if...
2811

433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
2812
2813
2814
  	ret = fib6_rules_init();
  	if (ret)
  		goto xfrm6_init;
7e5449c21   Daniel Lezcano   [IPV6]: route6 re...
2815

433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
2816
  	ret = -ENOBUFS;
c7ac8679b   Greg Rose   rtnetlink: Comput...
2817
2818
2819
  	if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) ||
  	    __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) ||
  	    __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL))
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
2820
  		goto fib6_rules_init;
c127ea2c4   Thomas Graf   [IPv6]: Use rtnl ...
2821

8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2822
  	ret = register_netdevice_notifier(&ip6_route_dev_notifier);
cdb187619   Daniel Lezcano   [NETNS][IPV6] rou...
2823
2824
  	if (ret)
  		goto fib6_rules_init;
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2825

433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
2826
2827
2828
2829
  out:
  	return ret;
  
  fib6_rules_init:
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
2830
2831
  	fib6_rules_cleanup();
  xfrm6_init:
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
2832
  	xfrm6_fini();
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
2833
  out_fib6_init:
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
2834
  	fib6_gc_cleanup();
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2835
2836
  out_register_subsys:
  	unregister_pernet_subsys(&ip6_route_net_ops);
fc66f95c6   Eric Dumazet   net dst: use a pe...
2837
2838
  out_dst_entries:
  	dst_entries_destroy(&ip6_dst_blackhole_ops);
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
2839
  out_kmem_cache:
f2fc6a545   Benjamin Thery   [NETNS][IPV6] rou...
2840
  	kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
2841
  	goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2842
2843
2844
2845
  }
  
  void ip6_route_cleanup(void)
  {
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2846
  	unregister_netdevice_notifier(&ip6_route_dev_notifier);
101367c2f   Thomas Graf   [IPV6]: Policy Ro...
2847
  	fib6_rules_cleanup();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2848
  	xfrm6_fini();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2849
  	fib6_gc_cleanup();
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2850
  	unregister_pernet_subsys(&ip6_route_net_ops);
41bb78b4b   Xiaotian Feng   net dst: fix perc...
2851
  	dst_entries_destroy(&ip6_dst_blackhole_ops);
f2fc6a545   Benjamin Thery   [NETNS][IPV6] rou...
2852
  	kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2853
  }