Blame view

net/ipv6/route.c 103 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
   */
f32138319   Joe Perches   net: ipv6: Standa...
26
  #define pr_fmt(fmt) "IPv6: " fmt
4fc268d24   Randy Dunlap   [PATCH] capable/c...
27
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  #include <linux/errno.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
29
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
33
34
35
36
37
  #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...
38
  #include <linux/mroute6.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
  #include <linux/init.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
  #include <linux/if_arp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
  #include <linux/proc_fs.h>
  #include <linux/seq_file.h>
5b7c931df   Daniel Lezcano   [NETNS][IPV6] ip6...
43
  #include <linux/nsproxy.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
44
  #include <linux/slab.h>
457c4cbc5   Eric W. Biederman   [NET]: Make /proc...
45
  #include <net/net_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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>
904af04d3   Jiri Benc   ipv6: route: exte...
55
  #include <net/dst_metadata.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
  #include <net/xfrm.h>
8d71740c5   Tom Tucker   [NET]: Core net c...
57
  #include <net/netevent.h>
21713ebc4   Thomas Graf   [IPv6] route: Con...
58
  #include <net/netlink.h>
51ebd3181   Nicolas Dichtel   ipv6: add support...
59
  #include <net/nexthop.h>
19e42e451   Roopa Prabhu   ipv6: support for...
60
  #include <net/lwtunnel.h>
904af04d3   Jiri Benc   ipv6: route: exte...
61
  #include <net/ip_tunnels.h>
ca254490c   David Ahern   net: Add VRF supp...
62
  #include <net/l3mdev.h>
b811580d9   David Ahern   net: IPv6 fib loo...
63
  #include <trace/events/fib6.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64

7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
65
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
68
69
  
  #ifdef CONFIG_SYSCTL
  #include <linux/sysctl.h>
  #endif
afc154e97   Hannes Frederic Sowa   ipv6: fix route s...
70
  enum rt6_nud_state {
7e9805696   Jiri Benc   ipv6: router reac...
71
72
73
  	RT6_NUD_FAIL_HARD = -3,
  	RT6_NUD_FAIL_PROBE = -2,
  	RT6_NUD_FAIL_DO_RR = -1,
afc154e97   Hannes Frederic Sowa   ipv6: fix route s...
74
75
  	RT6_NUD_SUCCEED = 1
  };
83a09abd1   Martin KaFai Lau   ipv6: Break up ip...
76
  static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
  static struct dst_entry	*ip6_dst_check(struct dst_entry *dst, u32 cookie);
0dbaee3b3   David S. Miller   net: Abstract def...
78
  static unsigned int	 ip6_default_advmss(const struct dst_entry *dst);
ebb762f27   Steffen Klassert   net: Rename the d...
79
  static unsigned int	 ip6_mtu(const struct dst_entry *dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
81
82
83
  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:...
84
  static int		 ip6_dst_gc(struct dst_ops *ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
  
  static int		ip6_pkt_discard(struct sk_buff *skb);
ede2059db   Eric W. Biederman   dst: Pass net int...
87
  static int		ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb);
7150aede5   Kamala R   IPv6: Fixed suppo...
88
  static int		ip6_pkt_prohibit(struct sk_buff *skb);
ede2059db   Eric W. Biederman   dst: Pass net int...
89
  static int		ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
  static void		ip6_link_failure(struct sk_buff *skb);
6700c2709   David S. Miller   net: Pass optiona...
91
92
93
94
  static void		ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
  					   struct sk_buff *skb, u32 mtu);
  static void		rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
  					struct sk_buff *skb);
4b32b5ad3   Martin KaFai Lau   ipv6: Stop rt6_in...
95
  static void		rt6_dst_from_metrics_check(struct rt6_info *rt);
52bd4c0c1   Nicolas Dichtel   ipv6: fix ecmp lo...
96
  static int rt6_score_route(struct rt6_info *rt, int oif, int strict);
16a16cd35   David Ahern   net: ipv6: Change...
97
98
99
100
101
102
  static size_t rt6_nlmsg_size(struct rt6_info *rt);
  static int rt6_fill_node(struct net *net,
  			 struct sk_buff *skb, struct rt6_info *rt,
  			 struct in6_addr *dst, struct in6_addr *src,
  			 int iif, int type, u32 portid, u32 seq,
  			 unsigned int flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103

70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
104
  #ifdef CONFIG_IPV6_ROUTE_INFO
efa2cea0d   Daniel Lezcano   [NETNS][IPV6] rou...
105
  static struct rt6_info *rt6_add_route_info(struct net *net,
b71d1d426   Eric Dumazet   inet: constify ip...
106
  					   const struct in6_addr *prefix, int prefixlen,
830218c1a   David Ahern   net: ipv6: Fix pr...
107
108
  					   const struct in6_addr *gwaddr,
  					   struct net_device *dev,
95c961747   Eric Dumazet   net: cleanup unsi...
109
  					   unsigned int pref);
efa2cea0d   Daniel Lezcano   [NETNS][IPV6] rou...
110
  static struct rt6_info *rt6_get_route_info(struct net *net,
b71d1d426   Eric Dumazet   inet: constify ip...
111
  					   const struct in6_addr *prefix, int prefixlen,
830218c1a   David Ahern   net: ipv6: Fix pr...
112
113
  					   const struct in6_addr *gwaddr,
  					   struct net_device *dev);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
114
  #endif
8d0b94afd   Martin KaFai Lau   ipv6: Keep track ...
115
116
117
118
119
120
121
122
123
124
  struct uncached_list {
  	spinlock_t		lock;
  	struct list_head	head;
  };
  
  static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list);
  
  static void rt6_uncached_list_add(struct rt6_info *rt)
  {
  	struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);
8d0b94afd   Martin KaFai Lau   ipv6: Keep track ...
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
  	rt->rt6i_uncached_list = ul;
  
  	spin_lock_bh(&ul->lock);
  	list_add_tail(&rt->rt6i_uncached, &ul->head);
  	spin_unlock_bh(&ul->lock);
  }
  
  static void rt6_uncached_list_del(struct rt6_info *rt)
  {
  	if (!list_empty(&rt->rt6i_uncached)) {
  		struct uncached_list *ul = rt->rt6i_uncached_list;
  
  		spin_lock_bh(&ul->lock);
  		list_del(&rt->rt6i_uncached);
  		spin_unlock_bh(&ul->lock);
  	}
  }
  
  static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev)
  {
  	struct net_device *loopback_dev = net->loopback_dev;
  	int cpu;
e332bc67c   Eric W. Biederman   ipv6: Don't call ...
147
148
  	if (dev == loopback_dev)
  		return;
8d0b94afd   Martin KaFai Lau   ipv6: Keep track ...
149
150
151
152
153
154
155
156
  	for_each_possible_cpu(cpu) {
  		struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
  		struct rt6_info *rt;
  
  		spin_lock_bh(&ul->lock);
  		list_for_each_entry(rt, &ul->head, rt6i_uncached) {
  			struct inet6_dev *rt_idev = rt->rt6i_idev;
  			struct net_device *rt_dev = rt->dst.dev;
e332bc67c   Eric W. Biederman   ipv6: Don't call ...
157
  			if (rt_idev->dev == dev) {
8d0b94afd   Martin KaFai Lau   ipv6: Keep track ...
158
159
160
  				rt->rt6i_idev = in6_dev_get(loopback_dev);
  				in6_dev_put(rt_idev);
  			}
e332bc67c   Eric W. Biederman   ipv6: Don't call ...
161
  			if (rt_dev == dev) {
8d0b94afd   Martin KaFai Lau   ipv6: Keep track ...
162
163
164
165
166
167
168
169
  				rt->dst.dev = loopback_dev;
  				dev_hold(rt->dst.dev);
  				dev_put(rt_dev);
  			}
  		}
  		spin_unlock_bh(&ul->lock);
  	}
  }
d52d3997f   Martin KaFai Lau   ipv6: Create perc...
170
171
172
173
  static u32 *rt6_pcpu_cow_metrics(struct rt6_info *rt)
  {
  	return dst_metrics_write_ptr(rt->dst.from);
  }
065825402   David S. Miller   net: Store ipv4/i...
174
175
  static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
  {
4b32b5ad3   Martin KaFai Lau   ipv6: Stop rt6_in...
176
  	struct rt6_info *rt = (struct rt6_info *)dst;
065825402   David S. Miller   net: Store ipv4/i...
177

d52d3997f   Martin KaFai Lau   ipv6: Create perc...
178
179
180
  	if (rt->rt6i_flags & RTF_PCPU)
  		return rt6_pcpu_cow_metrics(rt);
  	else if (rt->rt6i_flags & RTF_CACHE)
4b32b5ad3   Martin KaFai Lau   ipv6: Stop rt6_in...
181
182
  		return NULL;
  	else
3b4711757   Martin KaFai Lau   ipv6: fix ipv6_co...
183
  		return dst_cow_metrics_generic(dst, old);
065825402   David S. Miller   net: Store ipv4/i...
184
  }
f894cbf84   David S. Miller   net: Add optional...
185
186
187
  static inline const void *choose_neigh_daddr(struct rt6_info *rt,
  					     struct sk_buff *skb,
  					     const void *daddr)
39232973b   David S. Miller   ipv4/ipv6: Prepar...
188
189
  {
  	struct in6_addr *p = &rt->rt6i_gateway;
a7563f342   David S. Miller   ipv6: Use ipv6_ad...
190
  	if (!ipv6_addr_any(p))
39232973b   David S. Miller   ipv4/ipv6: Prepar...
191
  		return (const void *) p;
f894cbf84   David S. Miller   net: Add optional...
192
193
  	else if (skb)
  		return &ipv6_hdr(skb)->daddr;
39232973b   David S. Miller   ipv4/ipv6: Prepar...
194
195
  	return daddr;
  }
f894cbf84   David S. Miller   net: Add optional...
196
197
198
  static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst,
  					  struct sk_buff *skb,
  					  const void *daddr)
d3aaeb38c   David S. Miller   net: Add ->neigh_...
199
  {
39232973b   David S. Miller   ipv4/ipv6: Prepar...
200
201
  	struct rt6_info *rt = (struct rt6_info *) dst;
  	struct neighbour *n;
f894cbf84   David S. Miller   net: Add optional...
202
  	daddr = choose_neigh_daddr(rt, skb, daddr);
8e022ee63   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Remove tbl...
203
  	n = __ipv6_neigh_lookup(dst->dev, daddr);
f83c7790d   David S. Miller   ipv6: Create fast...
204
205
206
207
  	if (n)
  		return n;
  	return neigh_create(&nd_tbl, daddr, dst->dev);
  }
63fca65d0   Julian Anastasov   net: add confirm_...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
  static void ip6_confirm_neigh(const struct dst_entry *dst, const void *daddr)
  {
  	struct net_device *dev = dst->dev;
  	struct rt6_info *rt = (struct rt6_info *)dst;
  
  	daddr = choose_neigh_daddr(rt, NULL, daddr);
  	if (!daddr)
  		return;
  	if (dev->flags & (IFF_NOARP | IFF_LOOPBACK))
  		return;
  	if (ipv6_addr_is_multicast((const struct in6_addr *)daddr))
  		return;
  	__ipv6_confirm_neigh(dev, daddr);
  }
9a7ec3a94   Daniel Lezcano   [NETNS][IPV6] rou...
222
  static struct dst_ops ip6_dst_ops_template = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
  	.family			=	AF_INET6,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
225
226
  	.gc			=	ip6_dst_gc,
  	.gc_thresh		=	1024,
  	.check			=	ip6_dst_check,
0dbaee3b3   David S. Miller   net: Abstract def...
227
  	.default_advmss		=	ip6_default_advmss,
ebb762f27   Steffen Klassert   net: Rename the d...
228
  	.mtu			=	ip6_mtu,
065825402   David S. Miller   net: Store ipv4/i...
229
  	.cow_metrics		=	ipv6_cow_metrics,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
231
232
233
234
  	.destroy		=	ip6_dst_destroy,
  	.ifdown			=	ip6_dst_ifdown,
  	.negative_advice	=	ip6_negative_advice,
  	.link_failure		=	ip6_link_failure,
  	.update_pmtu		=	ip6_rt_update_pmtu,
6e157b6ac   David S. Miller   ipv6: Pull main l...
235
  	.redirect		=	rt6_do_redirect,
9f8955cc4   Eric W. Biederman   ipv6: Merge __ip6...
236
  	.local_out		=	__ip6_local_out,
d3aaeb38c   David S. Miller   net: Add ->neigh_...
237
  	.neigh_lookup		=	ip6_neigh_lookup,
63fca65d0   Julian Anastasov   net: add confirm_...
238
  	.confirm_neigh		=	ip6_confirm_neigh,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
  };
ebb762f27   Steffen Klassert   net: Rename the d...
240
  static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
ec831ea72   Roland Dreier   net: Add default_...
241
  {
618f9bc74   Steffen Klassert   net: Move mtu han...
242
243
244
  	unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
  
  	return mtu ? : dst->dev->mtu;
ec831ea72   Roland Dreier   net: Add default_...
245
  }
6700c2709   David S. Miller   net: Pass optiona...
246
247
  static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
  					 struct sk_buff *skb, u32 mtu)
14e50e57a   David S. Miller   [XFRM]: Allow pac...
248
249
  {
  }
6700c2709   David S. Miller   net: Pass optiona...
250
251
  static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
  				      struct sk_buff *skb)
b587ee3ba   David S. Miller   net: Add dummy ds...
252
253
  {
  }
14e50e57a   David S. Miller   [XFRM]: Allow pac...
254
255
  static struct dst_ops ip6_dst_blackhole_ops = {
  	.family			=	AF_INET6,
14e50e57a   David S. Miller   [XFRM]: Allow pac...
256
257
  	.destroy		=	ip6_dst_destroy,
  	.check			=	ip6_dst_check,
ebb762f27   Steffen Klassert   net: Rename the d...
258
  	.mtu			=	ip6_blackhole_mtu,
214f45c91   Eric Dumazet   net: provide defa...
259
  	.default_advmss		=	ip6_default_advmss,
14e50e57a   David S. Miller   [XFRM]: Allow pac...
260
  	.update_pmtu		=	ip6_rt_blackhole_update_pmtu,
b587ee3ba   David S. Miller   net: Add dummy ds...
261
  	.redirect		=	ip6_rt_blackhole_redirect,
0a1f59620   Martin KaFai Lau   ipv6: Initialize ...
262
  	.cow_metrics		=	dst_cow_metrics_generic,
d3aaeb38c   David S. Miller   net: Add ->neigh_...
263
  	.neigh_lookup		=	ip6_neigh_lookup,
14e50e57a   David S. Miller   [XFRM]: Allow pac...
264
  };
62fa8a846   David S. Miller   net: Implement re...
265
  static const u32 ip6_template_metrics[RTAX_MAX] = {
14edd87dc   Li RongQing   ipv6: Set default...
266
  	[RTAX_HOPLIMIT - 1] = 0,
62fa8a846   David S. Miller   net: Implement re...
267
  };
fb0af4c74   Eric Dumazet   ipv6: route templ...
268
  static const struct rt6_info ip6_null_entry_template = {
d8d1f30b9   Changli Gao   net-next: remove ...
269
270
271
  	.dst = {
  		.__refcnt	= ATOMIC_INIT(1),
  		.__use		= 1,
2c20cbd7e   Nicolas Dichtel   ipv6: use DST_* m...
272
  		.obsolete	= DST_OBSOLETE_FORCE_CHK,
d8d1f30b9   Changli Gao   net-next: remove ...
273
  		.error		= -ENETUNREACH,
d8d1f30b9   Changli Gao   net-next: remove ...
274
275
  		.input		= ip6_pkt_discard,
  		.output		= ip6_pkt_discard_out,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
  	},
  	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
4f7242799   Jean-Mickael Guerin   IPv6: set RTPROT_...
278
  	.rt6i_protocol  = RTPROT_KERNEL,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
281
  	.rt6i_metric	= ~(u32) 0,
  	.rt6i_ref	= ATOMIC_INIT(1),
  };
101367c2f   Thomas Graf   [IPV6]: Policy Ro...
282
  #ifdef CONFIG_IPV6_MULTIPLE_TABLES
fb0af4c74   Eric Dumazet   ipv6: route templ...
283
  static const struct rt6_info ip6_prohibit_entry_template = {
d8d1f30b9   Changli Gao   net-next: remove ...
284
285
286
  	.dst = {
  		.__refcnt	= ATOMIC_INIT(1),
  		.__use		= 1,
2c20cbd7e   Nicolas Dichtel   ipv6: use DST_* m...
287
  		.obsolete	= DST_OBSOLETE_FORCE_CHK,
d8d1f30b9   Changli Gao   net-next: remove ...
288
  		.error		= -EACCES,
d8d1f30b9   Changli Gao   net-next: remove ...
289
290
  		.input		= ip6_pkt_prohibit,
  		.output		= ip6_pkt_prohibit_out,
101367c2f   Thomas Graf   [IPV6]: Policy Ro...
291
292
  	},
  	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
4f7242799   Jean-Mickael Guerin   IPv6: set RTPROT_...
293
  	.rt6i_protocol  = RTPROT_KERNEL,
101367c2f   Thomas Graf   [IPV6]: Policy Ro...
294
295
296
  	.rt6i_metric	= ~(u32) 0,
  	.rt6i_ref	= ATOMIC_INIT(1),
  };
fb0af4c74   Eric Dumazet   ipv6: route templ...
297
  static const struct rt6_info ip6_blk_hole_entry_template = {
d8d1f30b9   Changli Gao   net-next: remove ...
298
299
300
  	.dst = {
  		.__refcnt	= ATOMIC_INIT(1),
  		.__use		= 1,
2c20cbd7e   Nicolas Dichtel   ipv6: use DST_* m...
301
  		.obsolete	= DST_OBSOLETE_FORCE_CHK,
d8d1f30b9   Changli Gao   net-next: remove ...
302
  		.error		= -EINVAL,
d8d1f30b9   Changli Gao   net-next: remove ...
303
  		.input		= dst_discard,
ede2059db   Eric W. Biederman   dst: Pass net int...
304
  		.output		= dst_discard_out,
101367c2f   Thomas Graf   [IPV6]: Policy Ro...
305
306
  	},
  	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
4f7242799   Jean-Mickael Guerin   IPv6: set RTPROT_...
307
  	.rt6i_protocol  = RTPROT_KERNEL,
101367c2f   Thomas Graf   [IPV6]: Policy Ro...
308
309
310
311
312
  	.rt6i_metric	= ~(u32) 0,
  	.rt6i_ref	= ATOMIC_INIT(1),
  };
  
  #endif
ebfa45f0d   Martin KaFai Lau   ipv6: Move common...
313
314
315
316
317
318
319
320
  static void rt6_info_init(struct rt6_info *rt)
  {
  	struct dst_entry *dst = &rt->dst;
  
  	memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
  	INIT_LIST_HEAD(&rt->rt6i_siblings);
  	INIT_LIST_HEAD(&rt->rt6i_uncached);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
  /* allocate dst with ip6_dst_ops */
d52d3997f   Martin KaFai Lau   ipv6: Create perc...
322
323
  static struct rt6_info *__ip6_dst_alloc(struct net *net,
  					struct net_device *dev,
ad7068628   Martin KaFai Lau   ipv6: Remove un-u...
324
  					int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
  {
97bab73f9   David S. Miller   inet: Hide route ...
326
  	struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
b2a9c0ed7   Wei Wang   net: remove DST_N...
327
  					1, DST_OBSOLETE_FORCE_CHK, flags);
cf9116622   David S. Miller   net: Use non-zero...
328

ebfa45f0d   Martin KaFai Lau   ipv6: Move common...
329
330
  	if (rt)
  		rt6_info_init(rt);
8104891b8   Steffen Klassert   ipv6: Initialize ...
331

cf9116622   David S. Miller   net: Use non-zero...
332
  	return rt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
  }
9ab179d83   David Ahern   net: vrf: Fix dst...
334
335
336
  struct rt6_info *ip6_dst_alloc(struct net *net,
  			       struct net_device *dev,
  			       int flags)
d52d3997f   Martin KaFai Lau   ipv6: Create perc...
337
  {
ad7068628   Martin KaFai Lau   ipv6: Remove un-u...
338
  	struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags);
d52d3997f   Martin KaFai Lau   ipv6: Create perc...
339
340
341
342
343
344
345
346
347
348
349
350
351
352
  
  	if (rt) {
  		rt->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, GFP_ATOMIC);
  		if (rt->rt6i_pcpu) {
  			int cpu;
  
  			for_each_possible_cpu(cpu) {
  				struct rt6_info **p;
  
  				p = per_cpu_ptr(rt->rt6i_pcpu, cpu);
  				/* no one shares rt */
  				*p =  NULL;
  			}
  		} else {
587fea741   Wei Wang   ipv6: mark DST_NO...
353
  			dst_release_immediate(&rt->dst);
d52d3997f   Martin KaFai Lau   ipv6: Create perc...
354
355
356
357
358
359
  			return NULL;
  		}
  	}
  
  	return rt;
  }
9ab179d83   David Ahern   net: vrf: Fix dst...
360
  EXPORT_SYMBOL(ip6_dst_alloc);
d52d3997f   Martin KaFai Lau   ipv6: Create perc...
361

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
  static void ip6_dst_destroy(struct dst_entry *dst)
  {
  	struct rt6_info *rt = (struct rt6_info *)dst;
ecd988372   YOSHIFUJI Hideaki / 吉藤英明   ipv6: fix race co...
365
  	struct dst_entry *from = dst->from;
8d0b94afd   Martin KaFai Lau   ipv6: Keep track ...
366
  	struct inet6_dev *idev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367

4b32b5ad3   Martin KaFai Lau   ipv6: Stop rt6_in...
368
  	dst_destroy_metrics_generic(dst);
87775312a   Markus Elfring   net-ipv6: Delete ...
369
  	free_percpu(rt->rt6i_pcpu);
8d0b94afd   Martin KaFai Lau   ipv6: Keep track ...
370
371
372
  	rt6_uncached_list_del(rt);
  
  	idev = rt->rt6i_idev;
383084739   David S. Miller   ipv6: Various cle...
373
  	if (idev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
  		rt->rt6i_idev = NULL;
  		in6_dev_put(idev);
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
376
  	}
1716a9610   Gao feng   ipv6: fix problem...
377

ecd988372   YOSHIFUJI Hideaki / 吉藤英明   ipv6: fix race co...
378
379
  	dst->from = NULL;
  	dst_release(from);
b34193638   David S. Miller   ipv6: Add infrast...
380
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
383
384
385
  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...
386
  	struct net_device *loopback_dev =
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
387
  		dev_net(dev)->loopback_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388

e5645f51b   Wei Wang   ipv6: release rt6...
389
390
391
392
393
  	if (idev && idev->dev != loopback_dev) {
  		struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev);
  		if (loopback_idev) {
  			rt->rt6i_idev = loopback_idev;
  			in6_dev_put(idev);
97cac0821   David S. Miller   ipv6: Store route...
394
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
  	}
  }
5973fb1e2   Martin KaFai Lau   ipv6: Check expir...
397
398
399
400
401
402
403
  static bool __rt6_check_expired(const struct rt6_info *rt)
  {
  	if (rt->rt6i_flags & RTF_EXPIRES)
  		return time_after(jiffies, rt->dst.expires);
  	else
  		return false;
  }
a50feda54   Eric Dumazet   ipv6: bool/const ...
404
  static bool rt6_check_expired(const struct rt6_info *rt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
  {
1716a9610   Gao feng   ipv6: fix problem...
406
407
  	if (rt->rt6i_flags & RTF_EXPIRES) {
  		if (time_after(jiffies, rt->dst.expires))
a50feda54   Eric Dumazet   ipv6: bool/const ...
408
  			return true;
1716a9610   Gao feng   ipv6: fix problem...
409
  	} else if (rt->dst.from) {
1e2ea8ad3   Xin Long   ipv6: set dst.obs...
410
411
  		return rt->dst.obsolete != DST_OBSOLETE_FORCE_CHK ||
  		       rt6_check_expired((struct rt6_info *)rt->dst.from);
1716a9610   Gao feng   ipv6: fix problem...
412
  	}
a50feda54   Eric Dumazet   ipv6: bool/const ...
413
  	return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
  }
51ebd3181   Nicolas Dichtel   ipv6: add support...
415
  static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
52bd4c0c1   Nicolas Dichtel   ipv6: fix ecmp lo...
416
417
  					     struct flowi6 *fl6, int oif,
  					     int strict)
51ebd3181   Nicolas Dichtel   ipv6: add support...
418
419
420
  {
  	struct rt6_info *sibling, *next_sibling;
  	int route_choosen;
b673d6cce   Jakub Sitnicki   ipv6: Use multipa...
421
422
423
424
425
426
427
  	/* We might have already computed the hash for ICMPv6 errors. In such
  	 * case it will always be non-zero. Otherwise now is the time to do it.
  	 */
  	if (!fl6->mp_hash)
  		fl6->mp_hash = rt6_multipath_hash(fl6, NULL);
  
  	route_choosen = fl6->mp_hash % (match->rt6i_nsiblings + 1);
51ebd3181   Nicolas Dichtel   ipv6: add support...
428
429
430
431
432
433
434
435
  	/* Don't change the route, if route_choosen == 0
  	 * (siblings does not include ourself)
  	 */
  	if (route_choosen)
  		list_for_each_entry_safe(sibling, next_sibling,
  				&match->rt6i_siblings, rt6i_siblings) {
  			route_choosen--;
  			if (route_choosen == 0) {
52bd4c0c1   Nicolas Dichtel   ipv6: fix ecmp lo...
436
437
  				if (rt6_score_route(sibling, oif, strict) < 0)
  					break;
51ebd3181   Nicolas Dichtel   ipv6: add support...
438
439
440
441
442
443
  				match = sibling;
  				break;
  			}
  		}
  	return match;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
  /*
c71099acc   Thomas Graf   [IPV6]: Multiple ...
445
   *	Route lookup. Any table->tb6_lock is implied.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
   */
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
447
448
  static inline struct rt6_info *rt6_device_match(struct net *net,
  						    struct rt6_info *rt,
b71d1d426   Eric Dumazet   inet: constify ip...
449
  						    const struct in6_addr *saddr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
  						    int oif,
d420895ef   YOSHIFUJI Hideaki   ipv6 route: Conve...
451
  						    int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
453
454
  {
  	struct rt6_info *local = NULL;
  	struct rt6_info *sprt;
dd3abc4ef   YOSHIFUJI Hideaki   ipv6 route: Prefe...
455
456
  	if (!oif && ipv6_addr_any(saddr))
  		goto out;
d8d1f30b9   Changli Gao   net-next: remove ...
457
  	for (sprt = rt; sprt; sprt = sprt->dst.rt6_next) {
d19185428   David S. Miller   ipv6: Kill rt6i_d...
458
  		struct net_device *dev = sprt->dst.dev;
dd3abc4ef   YOSHIFUJI Hideaki   ipv6 route: Prefe...
459
460
  
  		if (oif) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
462
463
  			if (dev->ifindex == oif)
  				return sprt;
  			if (dev->flags & IFF_LOOPBACK) {
383084739   David S. Miller   ipv6: Various cle...
464
  				if (!sprt->rt6i_idev ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
  				    sprt->rt6i_idev->dev->ifindex != oif) {
17fb0b2b9   David Ahern   net: Remove redun...
466
  					if (flags & RT6_LOOKUP_F_IFACE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
  						continue;
17fb0b2b9   David Ahern   net: Remove redun...
468
469
  					if (local &&
  					    local->rt6i_idev->dev->ifindex == oif)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
471
472
473
  						continue;
  				}
  				local = sprt;
  			}
dd3abc4ef   YOSHIFUJI Hideaki   ipv6 route: Prefe...
474
475
476
477
  		} else {
  			if (ipv6_chk_addr(net, saddr, dev,
  					  flags & RT6_LOOKUP_F_IFACE))
  				return sprt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478
  		}
dd3abc4ef   YOSHIFUJI Hideaki   ipv6 route: Prefe...
479
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480

dd3abc4ef   YOSHIFUJI Hideaki   ipv6 route: Prefe...
481
  	if (oif) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
  		if (local)
  			return local;
d420895ef   YOSHIFUJI Hideaki   ipv6 route: Conve...
484
  		if (flags & RT6_LOOKUP_F_IFACE)
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
485
  			return net->ipv6.ip6_null_entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
  	}
dd3abc4ef   YOSHIFUJI Hideaki   ipv6 route: Prefe...
487
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
489
  	return rt;
  }
270972554   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
490
  #ifdef CONFIG_IPV6_ROUTER_PREF
c2f17e827   Hannes Frederic Sowa   ipv6: probe route...
491
492
493
494
495
496
497
498
499
500
501
502
503
  struct __rt6_probe_work {
  	struct work_struct work;
  	struct in6_addr target;
  	struct net_device *dev;
  };
  
  static void rt6_probe_deferred(struct work_struct *w)
  {
  	struct in6_addr mcaddr;
  	struct __rt6_probe_work *work =
  		container_of(w, struct __rt6_probe_work, work);
  
  	addrconf_addr_solict_mult(&work->target, &mcaddr);
adc176c54   Erik Nordmark   ipv6 addrconf: Im...
504
  	ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL, 0);
c2f17e827   Hannes Frederic Sowa   ipv6: probe route...
505
  	dev_put(work->dev);
662f5533c   Michael Buesch   rt6_probe_deferre...
506
  	kfree(work);
c2f17e827   Hannes Frederic Sowa   ipv6: probe route...
507
  }
270972554   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
508
509
  static void rt6_probe(struct rt6_info *rt)
  {
990edb428   Martin KaFai Lau   ipv6: Re-arrange ...
510
  	struct __rt6_probe_work *work;
f2c31e32b   Eric Dumazet   net: fix NULL der...
511
  	struct neighbour *neigh;
270972554   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
512
513
514
515
516
517
518
519
  	/*
  	 * 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.
  	 */
2152caea7   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Do not depe...
520
  	if (!rt || !(rt->rt6i_flags & RTF_GATEWAY))
7ff74a596   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Update nei...
521
  		return;
2152caea7   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Do not depe...
522
523
524
  	rcu_read_lock_bh();
  	neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
  	if (neigh) {
8d6c31bf5   Martin KaFai Lau   ipv6: Avoid rt6_p...
525
526
  		if (neigh->nud_state & NUD_VALID)
  			goto out;
990edb428   Martin KaFai Lau   ipv6: Re-arrange ...
527
  		work = NULL;
2152caea7   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Do not depe...
528
  		write_lock(&neigh->lock);
990edb428   Martin KaFai Lau   ipv6: Re-arrange ...
529
530
531
532
533
534
535
  		if (!(neigh->nud_state & NUD_VALID) &&
  		    time_after(jiffies,
  			       neigh->updated +
  			       rt->rt6i_idev->cnf.rtr_probe_interval)) {
  			work = kmalloc(sizeof(*work), GFP_ATOMIC);
  			if (work)
  				__neigh_set_probe_once(neigh);
c2f17e827   Hannes Frederic Sowa   ipv6: probe route...
536
  		}
2152caea7   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Do not depe...
537
  		write_unlock(&neigh->lock);
990edb428   Martin KaFai Lau   ipv6: Re-arrange ...
538
539
  	} else {
  		work = kmalloc(sizeof(*work), GFP_ATOMIC);
f2c31e32b   Eric Dumazet   net: fix NULL der...
540
  	}
990edb428   Martin KaFai Lau   ipv6: Re-arrange ...
541
542
543
544
545
546
547
548
  
  	if (work) {
  		INIT_WORK(&work->work, rt6_probe_deferred);
  		work->target = rt->rt6i_gateway;
  		dev_hold(rt->dst.dev);
  		work->dev = rt->dst.dev;
  		schedule_work(&work->work);
  	}
8d6c31bf5   Martin KaFai Lau   ipv6: Avoid rt6_p...
549
  out:
2152caea7   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Do not depe...
550
  	rcu_read_unlock_bh();
270972554   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
551
552
553
554
  }
  #else
  static inline void rt6_probe(struct rt6_info *rt)
  {
270972554   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
555
556
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
  /*
554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
558
   * Default Router Selection (RFC 2461 6.3.6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
   */
b6f99a211   Dave Jones   [NET]: fix up mis...
560
  static inline int rt6_check_dev(struct rt6_info *rt, int oif)
554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
561
  {
d19185428   David S. Miller   ipv6: Kill rt6i_d...
562
  	struct net_device *dev = rt->dst.dev;
161980f4c   David S. Miller   [IPV6]: Revert re...
563
  	if (!oif || dev->ifindex == oif)
554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
564
  		return 2;
161980f4c   David S. Miller   [IPV6]: Revert re...
565
566
567
568
  	if ((dev->flags & IFF_LOOPBACK) &&
  	    rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
  		return 1;
  	return 0;
554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
569
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570

afc154e97   Hannes Frederic Sowa   ipv6: fix route s...
571
  static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
  {
f2c31e32b   Eric Dumazet   net: fix NULL der...
573
  	struct neighbour *neigh;
afc154e97   Hannes Frederic Sowa   ipv6: fix route s...
574
  	enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
f2c31e32b   Eric Dumazet   net: fix NULL der...
575

4d0c59116   YOSHIFUJI Hideaki   [IPV6] ROUTE: Don...
576
577
  	if (rt->rt6i_flags & RTF_NONEXTHOP ||
  	    !(rt->rt6i_flags & RTF_GATEWAY))
afc154e97   Hannes Frederic Sowa   ipv6: fix route s...
578
  		return RT6_NUD_SUCCEED;
145a36217   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Do not depe...
579
580
581
582
583
  
  	rcu_read_lock_bh();
  	neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
  	if (neigh) {
  		read_lock(&neigh->lock);
554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
584
  		if (neigh->nud_state & NUD_VALID)
afc154e97   Hannes Frederic Sowa   ipv6: fix route s...
585
  			ret = RT6_NUD_SUCCEED;
398bcbebb   YOSHIFUJI Hideaki   [IPV6] ROUTE: Mak...
586
  #ifdef CONFIG_IPV6_ROUTER_PREF
a5a81f0b9   Paul Marks   ipv6: Fix default...
587
  		else if (!(neigh->nud_state & NUD_FAILED))
afc154e97   Hannes Frederic Sowa   ipv6: fix route s...
588
  			ret = RT6_NUD_SUCCEED;
7e9805696   Jiri Benc   ipv6: router reac...
589
590
  		else
  			ret = RT6_NUD_FAIL_PROBE;
398bcbebb   YOSHIFUJI Hideaki   [IPV6] ROUTE: Mak...
591
  #endif
145a36217   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Do not depe...
592
  		read_unlock(&neigh->lock);
afc154e97   Hannes Frederic Sowa   ipv6: fix route s...
593
594
  	} else {
  		ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
7e9805696   Jiri Benc   ipv6: router reac...
595
  		      RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR;
a5a81f0b9   Paul Marks   ipv6: Fix default...
596
  	}
145a36217   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Do not depe...
597
  	rcu_read_unlock_bh();
a5a81f0b9   Paul Marks   ipv6: Fix default...
598
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
  }
554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
600
601
  static int rt6_score_route(struct rt6_info *rt, int oif,
  			   int strict)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
  {
a5a81f0b9   Paul Marks   ipv6: Fix default...
603
  	int m;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
604

4d0c59116   YOSHIFUJI Hideaki   [IPV6] ROUTE: Don...
605
  	m = rt6_check_dev(rt, oif);
77d16f450   YOSHIFUJI Hideaki   [IPV6] ROUTE: Uni...
606
  	if (!m && (strict & RT6_LOOKUP_F_IFACE))
afc154e97   Hannes Frederic Sowa   ipv6: fix route s...
607
  		return RT6_NUD_FAIL_HARD;
ebacaaa0f   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
608
609
610
  #ifdef CONFIG_IPV6_ROUTER_PREF
  	m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
  #endif
afc154e97   Hannes Frederic Sowa   ipv6: fix route s...
611
612
613
614
615
  	if (strict & RT6_LOOKUP_F_REACHABLE) {
  		int n = rt6_check_neigh(rt);
  		if (n < 0)
  			return n;
  	}
554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
616
617
  	return m;
  }
f11e6659c   David S. Miller   [IPV6]: Fix routi...
618
  static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
afc154e97   Hannes Frederic Sowa   ipv6: fix route s...
619
620
  				   int *mpri, struct rt6_info *match,
  				   bool *do_rr)
554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
621
  {
f11e6659c   David S. Miller   [IPV6]: Fix routi...
622
  	int m;
afc154e97   Hannes Frederic Sowa   ipv6: fix route s...
623
  	bool match_do_rr = false;
35103d111   Andy Gospodarek   net: ipv6 sysctl ...
624
625
626
627
  	struct inet6_dev *idev = rt->rt6i_idev;
  	struct net_device *dev = rt->dst.dev;
  
  	if (dev && !netif_carrier_ok(dev) &&
d5d32e4b7   David Ahern   net: ipv6: Do not...
628
629
  	    idev->cnf.ignore_routes_with_linkdown &&
  	    !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE))
35103d111   Andy Gospodarek   net: ipv6 sysctl ...
630
  		goto out;
f11e6659c   David S. Miller   [IPV6]: Fix routi...
631
632
633
634
635
  
  	if (rt6_check_expired(rt))
  		goto out;
  
  	m = rt6_score_route(rt, oif, strict);
7e9805696   Jiri Benc   ipv6: router reac...
636
  	if (m == RT6_NUD_FAIL_DO_RR) {
afc154e97   Hannes Frederic Sowa   ipv6: fix route s...
637
638
  		match_do_rr = true;
  		m = 0; /* lowest valid score */
7e9805696   Jiri Benc   ipv6: router reac...
639
  	} else if (m == RT6_NUD_FAIL_HARD) {
f11e6659c   David S. Miller   [IPV6]: Fix routi...
640
  		goto out;
afc154e97   Hannes Frederic Sowa   ipv6: fix route s...
641
642
643
644
  	}
  
  	if (strict & RT6_LOOKUP_F_REACHABLE)
  		rt6_probe(rt);
f11e6659c   David S. Miller   [IPV6]: Fix routi...
645

7e9805696   Jiri Benc   ipv6: router reac...
646
  	/* note that m can be RT6_NUD_FAIL_PROBE at this point */
f11e6659c   David S. Miller   [IPV6]: Fix routi...
647
  	if (m > *mpri) {
afc154e97   Hannes Frederic Sowa   ipv6: fix route s...
648
  		*do_rr = match_do_rr;
f11e6659c   David S. Miller   [IPV6]: Fix routi...
649
650
  		*mpri = m;
  		match = rt;
f11e6659c   David S. Miller   [IPV6]: Fix routi...
651
  	}
f11e6659c   David S. Miller   [IPV6]: Fix routi...
652
653
654
655
656
657
  out:
  	return match;
  }
  
  static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
  				     struct rt6_info *rr_head,
afc154e97   Hannes Frederic Sowa   ipv6: fix route s...
658
659
  				     u32 metric, int oif, int strict,
  				     bool *do_rr)
f11e6659c   David S. Miller   [IPV6]: Fix routi...
660
  {
9fbdcfaf9   Steffen Klassert   ipv6: Extend the ...
661
  	struct rt6_info *rt, *match, *cont;
554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
662
  	int mpri = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663

f11e6659c   David S. Miller   [IPV6]: Fix routi...
664
  	match = NULL;
9fbdcfaf9   Steffen Klassert   ipv6: Extend the ...
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
  	cont = NULL;
  	for (rt = rr_head; rt; rt = rt->dst.rt6_next) {
  		if (rt->rt6i_metric != metric) {
  			cont = rt;
  			break;
  		}
  
  		match = find_match(rt, oif, strict, &mpri, match, do_rr);
  	}
  
  	for (rt = fn->leaf; rt && rt != rr_head; rt = rt->dst.rt6_next) {
  		if (rt->rt6i_metric != metric) {
  			cont = rt;
  			break;
  		}
afc154e97   Hannes Frederic Sowa   ipv6: fix route s...
680
  		match = find_match(rt, oif, strict, &mpri, match, do_rr);
9fbdcfaf9   Steffen Klassert   ipv6: Extend the ...
681
682
683
684
685
686
  	}
  
  	if (match || !cont)
  		return match;
  
  	for (rt = cont; rt; rt = rt->dst.rt6_next)
afc154e97   Hannes Frederic Sowa   ipv6: fix route s...
687
  		match = find_match(rt, oif, strict, &mpri, match, do_rr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688

f11e6659c   David S. Miller   [IPV6]: Fix routi...
689
690
  	return match;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
691

f11e6659c   David S. Miller   [IPV6]: Fix routi...
692
693
694
  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...
695
  	struct net *net;
afc154e97   Hannes Frederic Sowa   ipv6: fix route s...
696
  	bool do_rr = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697

f11e6659c   David S. Miller   [IPV6]: Fix routi...
698
699
700
  	rt0 = fn->rr_ptr;
  	if (!rt0)
  		fn->rr_ptr = rt0 = fn->leaf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701

afc154e97   Hannes Frederic Sowa   ipv6: fix route s...
702
703
  	match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict,
  			     &do_rr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704

afc154e97   Hannes Frederic Sowa   ipv6: fix route s...
705
  	if (do_rr) {
d8d1f30b9   Changli Gao   net-next: remove ...
706
  		struct rt6_info *next = rt0->dst.rt6_next;
f11e6659c   David S. Miller   [IPV6]: Fix routi...
707

554cfb7ee   YOSHIFUJI Hideaki   [IPV6]: ROUTE: El...
708
  		/* no entries matched; do round-robin */
f11e6659c   David S. Miller   [IPV6]: Fix routi...
709
710
711
712
713
  		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
714
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715

d19185428   David S. Miller   ipv6: Kill rt6i_d...
716
  	net = dev_net(rt0->dst.dev);
a02cec215   Eric Dumazet   net: return opera...
717
  	return match ? match : net->ipv6.ip6_null_entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
718
  }
8b9df2657   Martin KaFai Lau   ipv6: Combine rt6...
719
720
721
722
  static bool rt6_is_gw_or_nonexthop(const struct rt6_info *rt)
  {
  	return (rt->rt6i_flags & (RTF_NONEXTHOP | RTF_GATEWAY));
  }
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
723
724
  #ifdef CONFIG_IPV6_ROUTE_INFO
  int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
b71d1d426   Eric Dumazet   inet: constify ip...
725
  		  const struct in6_addr *gwaddr)
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
726
  {
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
727
  	struct net *net = dev_net(dev);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
728
729
730
  	struct route_info *rinfo = (struct route_info *) opt;
  	struct in6_addr prefix_buf, *prefix;
  	unsigned int pref;
4bed72e4f   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
731
  	unsigned long lifetime;
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
  	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...
755
  		return -EINVAL;
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
756

4bed72e4f   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
757
  	lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
758
759
760
761
762
763
764
765
766
767
  
  	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;
  	}
f104a567e   Duan Jiong   ipv6: use rt6_get...
768
769
770
771
  	if (rinfo->prefix_len == 0)
  		rt = rt6_get_dflt_router(gwaddr, dev);
  	else
  		rt = rt6_get_route_info(net, prefix, rinfo->prefix_len,
830218c1a   David Ahern   net: ipv6: Fix pr...
772
  					gwaddr, dev);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
773
774
  
  	if (rt && !lifetime) {
e0a1ad73d   Thomas Graf   [IPv6] route: Sim...
775
  		ip6_del_rt(rt);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
776
777
778
779
  		rt = NULL;
  	}
  
  	if (!rt && lifetime)
830218c1a   David Ahern   net: ipv6: Fix pr...
780
781
  		rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr,
  					dev, pref);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
782
783
784
785
786
  	else if (rt)
  		rt->rt6i_flags = RTF_ROUTEINFO |
  				 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
  
  	if (rt) {
1716a9610   Gao feng   ipv6: fix problem...
787
788
789
790
  		if (!addrconf_finite_timeout(lifetime))
  			rt6_clean_expires(rt);
  		else
  			rt6_set_expires(rt, jiffies + HZ * lifetime);
94e187c01   Amerigo Wang   ipv6: introduce i...
791
  		ip6_rt_put(rt);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
792
793
794
795
  	}
  	return 0;
  }
  #endif
a3c00e46e   Martin KaFai Lau   ipv6: Remove BACK...
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
  static struct fib6_node* fib6_backtrack(struct fib6_node *fn,
  					struct in6_addr *saddr)
  {
  	struct fib6_node *pn;
  	while (1) {
  		if (fn->fn_flags & RTN_TL_ROOT)
  			return NULL;
  		pn = fn->parent;
  		if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn)
  			fn = fib6_lookup(FIB6_SUBTREE(pn), NULL, saddr);
  		else
  			fn = pn;
  		if (fn->fn_flags & RTN_RTINFO)
  			return fn;
  	}
  }
c71099acc   Thomas Graf   [IPV6]: Multiple ...
812

8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
813
814
  static struct rt6_info *ip6_pol_route_lookup(struct net *net,
  					     struct fib6_table *table,
4c9483b2f   David S. Miller   ipv6: Convert to ...
815
  					     struct flowi6 *fl6, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
816
817
818
  {
  	struct fib6_node *fn;
  	struct rt6_info *rt;
d1b820bd9   David Ahern   net/ipv6: Fix rou...
819
820
  	if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
  		flags &= ~RT6_LOOKUP_F_IFACE;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
821
  	read_lock_bh(&table->tb6_lock);
4c9483b2f   David S. Miller   ipv6: Convert to ...
822
  	fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
823
824
  restart:
  	rt = fn->leaf;
4c9483b2f   David S. Miller   ipv6: Convert to ...
825
  	rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags);
51ebd3181   Nicolas Dichtel   ipv6: add support...
826
  	if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0)
52bd4c0c1   Nicolas Dichtel   ipv6: fix ecmp lo...
827
  		rt = rt6_multipath_select(rt, fl6, fl6->flowi6_oif, flags);
a3c00e46e   Martin KaFai Lau   ipv6: Remove BACK...
828
829
830
831
832
  	if (rt == net->ipv6.ip6_null_entry) {
  		fn = fib6_backtrack(fn, &fl6->saddr);
  		if (fn)
  			goto restart;
  	}
d8d1f30b9   Changli Gao   net-next: remove ...
833
  	dst_use(&rt->dst, jiffies);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
834
  	read_unlock_bh(&table->tb6_lock);
b811580d9   David Ahern   net: IPv6 fib loo...
835
836
  
  	trace_fib6_table_lookup(net, rt, table->tb6_id, fl6);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
837
838
839
  	return rt;
  
  }
67ba4152e   Ian Morris   ipv6: White-space...
840
  struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
ea6e574e3   Florian Westphal   ipv6: add ip6_rou...
841
842
843
844
845
  				    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...
846
847
  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 ...
848
  {
4c9483b2f   David S. Miller   ipv6: Convert to ...
849
850
851
  	struct flowi6 fl6 = {
  		.flowi6_oif = oif,
  		.daddr = *daddr,
c71099acc   Thomas Graf   [IPV6]: Multiple ...
852
853
  	};
  	struct dst_entry *dst;
77d16f450   YOSHIFUJI Hideaki   [IPV6] ROUTE: Uni...
854
  	int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
855

adaa70bbd   Thomas Graf   [IPv6] rules: Use...
856
  	if (saddr) {
4c9483b2f   David S. Miller   ipv6: Convert to ...
857
  		memcpy(&fl6.saddr, saddr, sizeof(*saddr));
adaa70bbd   Thomas Graf   [IPv6] rules: Use...
858
859
  		flags |= RT6_LOOKUP_F_HAS_SADDR;
  	}
4c9483b2f   David S. Miller   ipv6: Convert to ...
860
  	dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
861
862
863
864
  	if (dst->error == 0)
  		return (struct rt6_info *) dst;
  
  	dst_release(dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865
866
  	return NULL;
  }
7159039a1   YOSHIFUJI Hideaki   [IPV6]: Decentral...
867
  EXPORT_SYMBOL(rt6_lookup);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
868
  /* ip6_ins_rt is called with FREE table->tb6_lock.
1cfb71eeb   Wei Wang   ipv6: take dst->_...
869
870
871
   * It takes new route entry, the addition fails by any reason the
   * route is released.
   * Caller must hold dst before calling it.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
   */
e5fd387ad   Michal Kubeček   ipv6: do not over...
873
  static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info,
333c43016   David Ahern   net: ipv6: Plumb ...
874
875
  			struct mx6_config *mxc,
  			struct netlink_ext_ack *extack)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
877
  {
  	int err;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
878
  	struct fib6_table *table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
879

c71099acc   Thomas Graf   [IPV6]: Multiple ...
880
881
  	table = rt->rt6i_table;
  	write_lock_bh(&table->tb6_lock);
333c43016   David Ahern   net: ipv6: Plumb ...
882
  	err = fib6_add(&table->tb6_root, rt, info, mxc, extack);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
883
  	write_unlock_bh(&table->tb6_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
884
885
886
  
  	return err;
  }
40e22e8f3   Thomas Graf   [IPv6] route: Sim...
887
888
  int ip6_ins_rt(struct rt6_info *rt)
  {
e715b6d3a   Florian Westphal   net: fib6: conver...
889
890
  	struct nl_info info = {	.nl_net = dev_net(rt->dst.dev), };
  	struct mx6_config mxc = { .mx = NULL, };
1cfb71eeb   Wei Wang   ipv6: take dst->_...
891
892
  	/* Hold dst to account for the reference from the fib6 tree */
  	dst_hold(&rt->dst);
333c43016   David Ahern   net: ipv6: Plumb ...
893
  	return __ip6_ins_rt(rt, &info, &mxc, NULL);
40e22e8f3   Thomas Graf   [IPv6] route: Sim...
894
  }
4832c30d5   David Ahern   net: ipv6: put ho...
895
896
897
898
  /* called with rcu_lock held */
  static struct net_device *ip6_rt_get_dev_rcu(struct rt6_info *rt)
  {
  	struct net_device *dev = rt->dst.dev;
7afe2e668   David Ahern   net: ipv6: Fixup ...
899
  	if (rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) {
4832c30d5   David Ahern   net: ipv6: put ho...
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
  		/* for copies of local routes, dst->dev needs to be the
  		 * device if it is a master device, the master device if
  		 * device is enslaved, and the loopback as the default
  		 */
  		if (netif_is_l3_slave(dev) &&
  		    !rt6_need_strict(&rt->rt6i_dst.addr))
  			dev = l3mdev_master_dev_rcu(dev);
  		else if (!netif_is_l3_master(dev))
  			dev = dev_net(dev)->loopback_dev;
  		/* last case is netif_is_l3_master(dev) is true in which
  		 * case we want dev returned to be dev
  		 */
  	}
  
  	return dev;
  }
8b9df2657   Martin KaFai Lau   ipv6: Combine rt6...
916
917
918
  static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort,
  					   const struct in6_addr *daddr,
  					   const struct in6_addr *saddr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
919
  {
4832c30d5   David Ahern   net: ipv6: put ho...
920
  	struct net_device *dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
921
922
923
924
925
  	struct rt6_info *rt;
  
  	/*
  	 *	Clone the route.
  	 */
d52d3997f   Martin KaFai Lau   ipv6: Create perc...
926
  	if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU))
83a09abd1   Martin KaFai Lau   ipv6: Break up ip...
927
  		ort = (struct rt6_info *)ort->dst.from;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928

4832c30d5   David Ahern   net: ipv6: put ho...
929
930
931
932
  	rcu_read_lock();
  	dev = ip6_rt_get_dev_rcu(ort);
  	rt = __ip6_dst_alloc(dev_net(dev), dev, 0);
  	rcu_read_unlock();
83a09abd1   Martin KaFai Lau   ipv6: Break up ip...
933
934
935
936
937
938
939
940
941
  	if (!rt)
  		return NULL;
  
  	ip6_rt_copy_init(rt, ort);
  	rt->rt6i_flags |= RTF_CACHE;
  	rt->rt6i_metric = 0;
  	rt->dst.flags |= DST_HOST;
  	rt->rt6i_dst.addr = *daddr;
  	rt->rt6i_dst.plen = 128;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
942

83a09abd1   Martin KaFai Lau   ipv6: Break up ip...
943
944
945
946
  	if (!rt6_is_gw_or_nonexthop(ort)) {
  		if (ort->rt6i_dst.plen != 128 &&
  		    ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
  			rt->rt6i_flags |= RTF_ANYCAST;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947
  #ifdef CONFIG_IPV6_SUBTREES
83a09abd1   Martin KaFai Lau   ipv6: Break up ip...
948
949
950
  		if (rt->rt6i_src.plen && saddr) {
  			rt->rt6i_src.addr = *saddr;
  			rt->rt6i_src.plen = 128;
8b9df2657   Martin KaFai Lau   ipv6: Combine rt6...
951
  		}
83a09abd1   Martin KaFai Lau   ipv6: Break up ip...
952
  #endif
95a9a5ba0   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Sp...
953
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
954

95a9a5ba0   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Sp...
955
956
  	return rt;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957

d52d3997f   Martin KaFai Lau   ipv6: Create perc...
958
959
  static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt)
  {
4832c30d5   David Ahern   net: ipv6: put ho...
960
  	struct net_device *dev;
d52d3997f   Martin KaFai Lau   ipv6: Create perc...
961
  	struct rt6_info *pcpu_rt;
4832c30d5   David Ahern   net: ipv6: put ho...
962
963
964
965
  	rcu_read_lock();
  	dev = ip6_rt_get_dev_rcu(rt);
  	pcpu_rt = __ip6_dst_alloc(dev_net(dev), dev, rt->dst.flags);
  	rcu_read_unlock();
d52d3997f   Martin KaFai Lau   ipv6: Create perc...
966
967
968
969
970
971
972
973
974
975
976
  	if (!pcpu_rt)
  		return NULL;
  	ip6_rt_copy_init(pcpu_rt, rt);
  	pcpu_rt->rt6i_protocol = rt->rt6i_protocol;
  	pcpu_rt->rt6i_flags |= RTF_PCPU;
  	return pcpu_rt;
  }
  
  /* It should be called with read_lock_bh(&tb6_lock) acquired */
  static struct rt6_info *rt6_get_pcpu_route(struct rt6_info *rt)
  {
a73e41956   Martin KaFai Lau   ipv6: Add rt6_mak...
977
  	struct rt6_info *pcpu_rt, **p;
d52d3997f   Martin KaFai Lau   ipv6: Create perc...
978
979
980
  
  	p = this_cpu_ptr(rt->rt6i_pcpu);
  	pcpu_rt = *p;
a73e41956   Martin KaFai Lau   ipv6: Add rt6_mak...
981
982
983
984
985
986
987
988
989
  	if (pcpu_rt) {
  		dst_hold(&pcpu_rt->dst);
  		rt6_dst_from_metrics_check(pcpu_rt);
  	}
  	return pcpu_rt;
  }
  
  static struct rt6_info *rt6_make_pcpu_route(struct rt6_info *rt)
  {
add9f2a47   Greg Kroah-Hartman   Revert "ipv6: gra...
990
  	struct fib6_table *table = rt->rt6i_table;
a73e41956   Martin KaFai Lau   ipv6: Add rt6_mak...
991
  	struct rt6_info *pcpu_rt, *prev, **p;
d52d3997f   Martin KaFai Lau   ipv6: Create perc...
992
993
994
995
  
  	pcpu_rt = ip6_rt_pcpu_alloc(rt);
  	if (!pcpu_rt) {
  		struct net *net = dev_net(rt->dst.dev);
9c7370a16   Martin KaFai Lau   ipv6: Fix a poten...
996
997
  		dst_hold(&net->ipv6.ip6_null_entry->dst);
  		return net->ipv6.ip6_null_entry;
d52d3997f   Martin KaFai Lau   ipv6: Create perc...
998
  	}
add9f2a47   Greg Kroah-Hartman   Revert "ipv6: gra...
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
  	read_lock_bh(&table->tb6_lock);
  	if (rt->rt6i_pcpu) {
  		p = this_cpu_ptr(rt->rt6i_pcpu);
  		prev = cmpxchg(p, NULL, pcpu_rt);
  		if (prev) {
  			/* If someone did it before us, return prev instead */
  			dst_release_immediate(&pcpu_rt->dst);
  			pcpu_rt = prev;
  		}
  	} else {
  		/* rt has been removed from the fib6 tree
  		 * before we have a chance to acquire the read_lock.
  		 * In this case, don't brother to create a pcpu rt
  		 * since rt is going away anyway.  The next
  		 * dst_check() will trigger a re-lookup.
  		 */
587fea741   Wei Wang   ipv6: mark DST_NO...
1015
  		dst_release_immediate(&pcpu_rt->dst);
add9f2a47   Greg Kroah-Hartman   Revert "ipv6: gra...
1016
  		pcpu_rt = rt;
d52d3997f   Martin KaFai Lau   ipv6: Create perc...
1017
  	}
add9f2a47   Greg Kroah-Hartman   Revert "ipv6: gra...
1018
  	dst_hold(&pcpu_rt->dst);
d52d3997f   Martin KaFai Lau   ipv6: Create perc...
1019
  	rt6_dst_from_metrics_check(pcpu_rt);
add9f2a47   Greg Kroah-Hartman   Revert "ipv6: gra...
1020
  	read_unlock_bh(&table->tb6_lock);
d52d3997f   Martin KaFai Lau   ipv6: Create perc...
1021
1022
  	return pcpu_rt;
  }
9ff743846   David Ahern   net: vrf: Handle ...
1023
1024
  struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
  			       int oif, struct flowi6 *fl6, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1025
  {
367efcb93   Martin KaFai Lau   ipv6: Avoid redoi...
1026
  	struct fib6_node *fn, *saved_fn;
45e4fd266   Martin KaFai Lau   ipv6: Only create...
1027
  	struct rt6_info *rt;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1028
  	int strict = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1029

77d16f450   YOSHIFUJI Hideaki   [IPV6] ROUTE: Uni...
1030
  	strict |= flags & RT6_LOOKUP_F_IFACE;
d5d32e4b7   David Ahern   net: ipv6: Do not...
1031
  	strict |= flags & RT6_LOOKUP_F_IGNORE_LINKSTATE;
367efcb93   Martin KaFai Lau   ipv6: Avoid redoi...
1032
1033
  	if (net->ipv6.devconf_all->forwarding == 0)
  		strict |= RT6_LOOKUP_F_REACHABLE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1034

c71099acc   Thomas Graf   [IPV6]: Multiple ...
1035
  	read_lock_bh(&table->tb6_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1036

4c9483b2f   David S. Miller   ipv6: Convert to ...
1037
  	fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
367efcb93   Martin KaFai Lau   ipv6: Avoid redoi...
1038
  	saved_fn = fn;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1039

ca254490c   David Ahern   net: Add VRF supp...
1040
1041
  	if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
  		oif = 0;
a3c00e46e   Martin KaFai Lau   ipv6: Remove BACK...
1042
  redo_rt6_select:
367efcb93   Martin KaFai Lau   ipv6: Avoid redoi...
1043
  	rt = rt6_select(fn, oif, strict);
52bd4c0c1   Nicolas Dichtel   ipv6: fix ecmp lo...
1044
  	if (rt->rt6i_nsiblings)
367efcb93   Martin KaFai Lau   ipv6: Avoid redoi...
1045
  		rt = rt6_multipath_select(rt, fl6, oif, strict);
a3c00e46e   Martin KaFai Lau   ipv6: Remove BACK...
1046
1047
1048
1049
  	if (rt == net->ipv6.ip6_null_entry) {
  		fn = fib6_backtrack(fn, &fl6->saddr);
  		if (fn)
  			goto redo_rt6_select;
367efcb93   Martin KaFai Lau   ipv6: Avoid redoi...
1050
1051
1052
1053
1054
  		else if (strict & RT6_LOOKUP_F_REACHABLE) {
  			/* also consider unreachable route */
  			strict &= ~RT6_LOOKUP_F_REACHABLE;
  			fn = saved_fn;
  			goto redo_rt6_select;
367efcb93   Martin KaFai Lau   ipv6: Avoid redoi...
1055
  		}
a3c00e46e   Martin KaFai Lau   ipv6: Remove BACK...
1056
  	}
fb9de91ea   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Cl...
1057

3da59bd94   Martin KaFai Lau   ipv6: Create RTF_...
1058
  	if (rt == net->ipv6.ip6_null_entry || (rt->rt6i_flags & RTF_CACHE)) {
d52d3997f   Martin KaFai Lau   ipv6: Create perc...
1059
1060
1061
1062
  		dst_use(&rt->dst, jiffies);
  		read_unlock_bh(&table->tb6_lock);
  
  		rt6_dst_from_metrics_check(rt);
b811580d9   David Ahern   net: IPv6 fib loo...
1063
1064
  
  		trace_fib6_table_lookup(net, rt, table->tb6_id, fl6);
d52d3997f   Martin KaFai Lau   ipv6: Create perc...
1065
  		return rt;
3da59bd94   Martin KaFai Lau   ipv6: Create RTF_...
1066
1067
1068
1069
1070
1071
1072
1073
1074
  	} else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) &&
  			    !(rt->rt6i_flags & RTF_GATEWAY))) {
  		/* Create a RTF_CACHE clone which will not be
  		 * owned by the fib6 tree.  It is for the special case where
  		 * the daddr in the skb during the neighbor look-up is different
  		 * from the fl6->daddr used to look-up route here.
  		 */
  
  		struct rt6_info *uncached_rt;
d52d3997f   Martin KaFai Lau   ipv6: Create perc...
1075
1076
  		dst_use(&rt->dst, jiffies);
  		read_unlock_bh(&table->tb6_lock);
3da59bd94   Martin KaFai Lau   ipv6: Create RTF_...
1077
1078
  		uncached_rt = ip6_rt_cache_alloc(rt, &fl6->daddr, NULL);
  		dst_release(&rt->dst);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1079

1cfb71eeb   Wei Wang   ipv6: take dst->_...
1080
1081
1082
1083
  		if (uncached_rt) {
  			/* Uncached_rt's refcnt is taken during ip6_rt_cache_alloc()
  			 * No need for another dst_hold()
  			 */
8d0b94afd   Martin KaFai Lau   ipv6: Keep track ...
1084
  			rt6_uncached_list_add(uncached_rt);
1cfb71eeb   Wei Wang   ipv6: take dst->_...
1085
  		} else {
3da59bd94   Martin KaFai Lau   ipv6: Create RTF_...
1086
  			uncached_rt = net->ipv6.ip6_null_entry;
1cfb71eeb   Wei Wang   ipv6: take dst->_...
1087
1088
  			dst_hold(&uncached_rt->dst);
  		}
b811580d9   David Ahern   net: IPv6 fib loo...
1089
1090
  
  		trace_fib6_table_lookup(net, uncached_rt, table->tb6_id, fl6);
3da59bd94   Martin KaFai Lau   ipv6: Create RTF_...
1091
  		return uncached_rt;
3da59bd94   Martin KaFai Lau   ipv6: Create RTF_...
1092

d52d3997f   Martin KaFai Lau   ipv6: Create perc...
1093
1094
1095
1096
1097
1098
1099
1100
  	} else {
  		/* Get a percpu copy */
  
  		struct rt6_info *pcpu_rt;
  
  		rt->dst.lastuse = jiffies;
  		rt->dst.__use++;
  		pcpu_rt = rt6_get_pcpu_route(rt);
d52d3997f   Martin KaFai Lau   ipv6: Create perc...
1101

9c7370a16   Martin KaFai Lau   ipv6: Fix a poten...
1102
1103
1104
  		if (pcpu_rt) {
  			read_unlock_bh(&table->tb6_lock);
  		} else {
add9f2a47   Greg Kroah-Hartman   Revert "ipv6: gra...
1105
1106
1107
1108
1109
1110
1111
1112
  			/* We have to do the read_unlock first
  			 * because rt6_make_pcpu_route() may trigger
  			 * ip6_dst_gc() which will take the write_lock.
  			 */
  			dst_hold(&rt->dst);
  			read_unlock_bh(&table->tb6_lock);
  			pcpu_rt = rt6_make_pcpu_route(rt);
  			dst_release(&rt->dst);
9c7370a16   Martin KaFai Lau   ipv6: Fix a poten...
1113
  		}
d52d3997f   Martin KaFai Lau   ipv6: Create perc...
1114

b811580d9   David Ahern   net: IPv6 fib loo...
1115
  		trace_fib6_table_lookup(net, pcpu_rt, table->tb6_id, fl6);
d52d3997f   Martin KaFai Lau   ipv6: Create perc...
1116
  		return pcpu_rt;
add9f2a47   Greg Kroah-Hartman   Revert "ipv6: gra...
1117

d52d3997f   Martin KaFai Lau   ipv6: Create perc...
1118
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1119
  }
9ff743846   David Ahern   net: vrf: Handle ...
1120
  EXPORT_SYMBOL_GPL(ip6_pol_route);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1121

8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
1122
  static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
4c9483b2f   David S. Miller   ipv6: Convert to ...
1123
  					    struct flowi6 *fl6, int flags)
4acad72de   Pavel Emelyanov   [IPV6]: Consolida...
1124
  {
4c9483b2f   David S. Miller   ipv6: Convert to ...
1125
  	return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags);
4acad72de   Pavel Emelyanov   [IPV6]: Consolida...
1126
  }
d409b8476   Mahesh Bandewar   ipv6: Export p6_r...
1127
1128
1129
  struct dst_entry *ip6_route_input_lookup(struct net *net,
  					 struct net_device *dev,
  					 struct flowi6 *fl6, int flags)
72331bc0c   Shmulik Ladkani   ipv6: Fix RTM_GET...
1130
1131
1132
1133
1134
1135
  {
  	if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
  		flags |= RT6_LOOKUP_F_IFACE;
  
  	return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_input);
  }
d409b8476   Mahesh Bandewar   ipv6: Export p6_r...
1136
  EXPORT_SYMBOL_GPL(ip6_route_input_lookup);
72331bc0c   Shmulik Ladkani   ipv6: Fix RTM_GET...
1137

23aebdacb   Jakub Sitnicki   ipv6: Compute mul...
1138
1139
1140
1141
1142
1143
1144
1145
  static void ip6_multipath_l3_keys(const struct sk_buff *skb,
  				  struct flow_keys *keys)
  {
  	const struct ipv6hdr *outer_iph = ipv6_hdr(skb);
  	const struct ipv6hdr *key_iph = outer_iph;
  	const struct ipv6hdr *inner_iph;
  	const struct icmp6hdr *icmph;
  	struct ipv6hdr _inner_iph;
cb9e5a081   Eric Dumazet   ipv6: fix uninit-...
1146
  	struct icmp6hdr _icmph;
23aebdacb   Jakub Sitnicki   ipv6: Compute mul...
1147
1148
1149
  
  	if (likely(outer_iph->nexthdr != IPPROTO_ICMPV6))
  		goto out;
cb9e5a081   Eric Dumazet   ipv6: fix uninit-...
1150
1151
1152
1153
  	icmph = skb_header_pointer(skb, skb_transport_offset(skb),
  				   sizeof(_icmph), &_icmph);
  	if (!icmph)
  		goto out;
23aebdacb   Jakub Sitnicki   ipv6: Compute mul...
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
  	if (icmph->icmp6_type != ICMPV6_DEST_UNREACH &&
  	    icmph->icmp6_type != ICMPV6_PKT_TOOBIG &&
  	    icmph->icmp6_type != ICMPV6_TIME_EXCEED &&
  	    icmph->icmp6_type != ICMPV6_PARAMPROB)
  		goto out;
  
  	inner_iph = skb_header_pointer(skb,
  				       skb_transport_offset(skb) + sizeof(*icmph),
  				       sizeof(_inner_iph), &_inner_iph);
  	if (!inner_iph)
  		goto out;
  
  	key_iph = inner_iph;
  out:
  	memset(keys, 0, sizeof(*keys));
  	keys->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
  	keys->addrs.v6addrs.src = key_iph->saddr;
  	keys->addrs.v6addrs.dst = key_iph->daddr;
3f8f52c5f   Michal Kubecek   ipv6: omit traffi...
1172
  	keys->tags.flow_label = ip6_flowlabel(key_iph);
23aebdacb   Jakub Sitnicki   ipv6: Compute mul...
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
  	keys->basic.ip_proto = key_iph->nexthdr;
  }
  
  /* if skb is set it will be used and fl6 can be NULL */
  u32 rt6_multipath_hash(const struct flowi6 *fl6, const struct sk_buff *skb)
  {
  	struct flow_keys hash_keys;
  
  	if (skb) {
  		ip6_multipath_l3_keys(skb, &hash_keys);
  		return flow_hash_from_keys(&hash_keys);
  	}
  
  	return get_hash_from_flowi6(fl6);
  }
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1188
1189
  void ip6_route_input(struct sk_buff *skb)
  {
b71d1d426   Eric Dumazet   inet: constify ip...
1190
  	const struct ipv6hdr *iph = ipv6_hdr(skb);
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1191
  	struct net *net = dev_net(skb->dev);
adaa70bbd   Thomas Graf   [IPv6] rules: Use...
1192
  	int flags = RT6_LOOKUP_F_HAS_SADDR;
904af04d3   Jiri Benc   ipv6: route: exte...
1193
  	struct ip_tunnel_info *tun_info;
4c9483b2f   David S. Miller   ipv6: Convert to ...
1194
  	struct flowi6 fl6 = {
e0d56fdd7   David Ahern   net: l3mdev: remo...
1195
  		.flowi6_iif = skb->dev->ifindex,
4c9483b2f   David S. Miller   ipv6: Convert to ...
1196
1197
  		.daddr = iph->daddr,
  		.saddr = iph->saddr,
6502ca527   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Introduce i...
1198
  		.flowlabel = ip6_flowinfo(iph),
4c9483b2f   David S. Miller   ipv6: Convert to ...
1199
1200
  		.flowi6_mark = skb->mark,
  		.flowi6_proto = iph->nexthdr,
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1201
  	};
adaa70bbd   Thomas Graf   [IPv6] rules: Use...
1202

904af04d3   Jiri Benc   ipv6: route: exte...
1203
  	tun_info = skb_tunnel_info(skb);
46fa062ad   Jiri Benc   ip_tunnels: conve...
1204
  	if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX))
904af04d3   Jiri Benc   ipv6: route: exte...
1205
  		fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id;
23aebdacb   Jakub Sitnicki   ipv6: Compute mul...
1206
1207
  	if (unlikely(fl6.flowi6_proto == IPPROTO_ICMPV6))
  		fl6.mp_hash = rt6_multipath_hash(&fl6, skb);
06e9d040b   Jiri Benc   ipv6: drop metada...
1208
  	skb_dst_drop(skb);
72331bc0c   Shmulik Ladkani   ipv6: Fix RTM_GET...
1209
  	skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1210
  }
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
1211
  static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
4c9483b2f   David S. Miller   ipv6: Convert to ...
1212
  					     struct flowi6 *fl6, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1213
  {
4c9483b2f   David S. Miller   ipv6: Convert to ...
1214
  	return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1215
  }
6f21c96a7   Paolo Abeni   ipv6: enforce flo...
1216
1217
  struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk,
  					 struct flowi6 *fl6, int flags)
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1218
  {
d46a9d678   David Ahern   net: ipv6: Dont a...
1219
  	bool any_src;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1220

4c1feac58   David Ahern   net: vrf: Flip IP...
1221
1222
1223
1224
1225
1226
1227
  	if (rt6_need_strict(&fl6->daddr)) {
  		struct dst_entry *dst;
  
  		dst = l3mdev_link_scope_lookup(net, fl6);
  		if (dst)
  			return dst;
  	}
ca254490c   David Ahern   net: Add VRF supp...
1228

1fb9489bf   Pavel Emelyanov   net: Loopback ifi...
1229
  	fl6->flowi6_iif = LOOPBACK_IFINDEX;
4dc27d1cf   David McCullough   net/ipv6/route.c:...
1230

d46a9d678   David Ahern   net: ipv6: Dont a...
1231
  	any_src = ipv6_addr_any(&fl6->saddr);
741a11d9e   David Ahern   net: ipv6: Add RT...
1232
  	if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) ||
d46a9d678   David Ahern   net: ipv6: Dont a...
1233
  	    (fl6->flowi6_oif && any_src))
77d16f450   YOSHIFUJI Hideaki   [IPV6] ROUTE: Uni...
1234
  		flags |= RT6_LOOKUP_F_IFACE;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1235

d46a9d678   David Ahern   net: ipv6: Dont a...
1236
  	if (!any_src)
adaa70bbd   Thomas Graf   [IPv6] rules: Use...
1237
  		flags |= RT6_LOOKUP_F_HAS_SADDR;
0c9a2ac1f   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Optmize tra...
1238
1239
  	else if (sk)
  		flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
adaa70bbd   Thomas Graf   [IPv6] rules: Use...
1240

4c9483b2f   David S. Miller   ipv6: Convert to ...
1241
  	return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1242
  }
6f21c96a7   Paolo Abeni   ipv6: enforce flo...
1243
  EXPORT_SYMBOL_GPL(ip6_route_output_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1244

2774c131b   David S. Miller   xfrm: Handle blac...
1245
  struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
14e50e57a   David S. Miller   [XFRM]: Allow pac...
1246
  {
5c1e6aa30   David S. Miller   net: Make dst_all...
1247
  	struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
1dbe32525   Wei Wang   net: use loopback...
1248
  	struct net_device *loopback_dev = net->loopback_dev;
14e50e57a   David S. Miller   [XFRM]: Allow pac...
1249
  	struct dst_entry *new = NULL;
1dbe32525   Wei Wang   net: use loopback...
1250
  	rt = dst_alloc(&ip6_dst_blackhole_ops, loopback_dev, 1,
62cf27e52   Steffen Klassert   ipv6: Fix traffic...
1251
  		       DST_OBSOLETE_DEAD, 0);
14e50e57a   David S. Miller   [XFRM]: Allow pac...
1252
  	if (rt) {
0a1f59620   Martin KaFai Lau   ipv6: Initialize ...
1253
  		rt6_info_init(rt);
8104891b8   Steffen Klassert   ipv6: Initialize ...
1254

0a1f59620   Martin KaFai Lau   ipv6: Initialize ...
1255
  		new = &rt->dst;
14e50e57a   David S. Miller   [XFRM]: Allow pac...
1256
  		new->__use = 1;
352e512c3   Herbert Xu   [NET]: Eliminate ...
1257
  		new->input = dst_discard;
ede2059db   Eric W. Biederman   dst: Pass net int...
1258
  		new->output = dst_discard_out;
14e50e57a   David S. Miller   [XFRM]: Allow pac...
1259

0a1f59620   Martin KaFai Lau   ipv6: Initialize ...
1260
  		dst_copy_metrics(new, &ort->dst);
14e50e57a   David S. Miller   [XFRM]: Allow pac...
1261

1dbe32525   Wei Wang   net: use loopback...
1262
  		rt->rt6i_idev = in6_dev_get(loopback_dev);
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1263
  		rt->rt6i_gateway = ort->rt6i_gateway;
0a1f59620   Martin KaFai Lau   ipv6: Initialize ...
1264
  		rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU;
14e50e57a   David S. Miller   [XFRM]: Allow pac...
1265
1266
1267
1268
1269
1270
  		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
14e50e57a   David S. Miller   [XFRM]: Allow pac...
1271
  	}
69ead7afd   David S. Miller   ipv6: Normalize a...
1272
1273
  	dst_release(dst_orig);
  	return new ? new : ERR_PTR(-ENOMEM);
14e50e57a   David S. Miller   [XFRM]: Allow pac...
1274
  }
14e50e57a   David S. Miller   [XFRM]: Allow pac...
1275

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1276
1277
1278
  /*
   *	Destination cache support functions
   */
4b32b5ad3   Martin KaFai Lau   ipv6: Stop rt6_in...
1279
1280
1281
1282
1283
1284
  static void rt6_dst_from_metrics_check(struct rt6_info *rt)
  {
  	if (rt->dst.from &&
  	    dst_metrics_ptr(&rt->dst) != dst_metrics_ptr(rt->dst.from))
  		dst_init_metrics(&rt->dst, dst_metrics_ptr(rt->dst.from), true);
  }
3da59bd94   Martin KaFai Lau   ipv6: Create RTF_...
1285
1286
  static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie)
  {
361436452   Steffen Klassert   ipv6: Fix may be ...
1287
  	u32 rt_cookie = 0;
c5cff8561   Wei Wang   ipv6: add rcu gra...
1288
1289
  
  	if (!rt6_get_cookie_safe(rt, &rt_cookie) || rt_cookie != cookie)
3da59bd94   Martin KaFai Lau   ipv6: Create RTF_...
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
  		return NULL;
  
  	if (rt6_check_expired(rt))
  		return NULL;
  
  	return &rt->dst;
  }
  
  static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, u32 cookie)
  {
5973fb1e2   Martin KaFai Lau   ipv6: Check expir...
1300
1301
  	if (!__rt6_check_expired(rt) &&
  	    rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
3da59bd94   Martin KaFai Lau   ipv6: Create RTF_...
1302
1303
1304
1305
1306
  	    rt6_check((struct rt6_info *)(rt->dst.from), cookie))
  		return &rt->dst;
  	else
  		return NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1307
1308
1309
1310
1311
  static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
  {
  	struct rt6_info *rt;
  
  	rt = (struct rt6_info *) dst;
6f3118b57   Nicolas Dichtel   ipv6: use net->rt...
1312
1313
1314
1315
  	/* All IPV6 dsts are created with ->obsolete set to the value
  	 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
  	 * into this function always.
  	 */
e3bc10bd9   Hannes Frederic Sowa   ipv6: ip6_dst_che...
1316

4b32b5ad3   Martin KaFai Lau   ipv6: Stop rt6_in...
1317
  	rt6_dst_from_metrics_check(rt);
02bcf4e08   Martin KaFai Lau   ipv6: Check rt->d...
1318
  	if (rt->rt6i_flags & RTF_PCPU ||
a4c2fd7f7   Wei Wang   net: remove DST_N...
1319
  	    (unlikely(!list_empty(&rt->rt6i_uncached)) && rt->dst.from))
3da59bd94   Martin KaFai Lau   ipv6: Create RTF_...
1320
1321
1322
  		return rt6_dst_from_check(rt, cookie);
  	else
  		return rt6_check(rt, cookie);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1323
1324
1325
1326
1327
1328
1329
  }
  
  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 ...
1330
1331
1332
1333
1334
1335
  		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
1336
  			dst_release(dst);
54c1a859e   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Don't drop ...
1337
1338
  			dst = NULL;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1339
  	}
54c1a859e   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Don't drop ...
1340
  	return dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1341
1342
1343
1344
1345
  }
  
  static void ip6_link_failure(struct sk_buff *skb)
  {
  	struct rt6_info *rt;
3ffe533c8   Alexey Dobriyan   ipv6: drop unused...
1346
  	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1347

adf30907d   Eric Dumazet   net: skb->dst acc...
1348
  	rt = (struct rt6_info *) skb_dst(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1349
  	if (rt) {
1eb4f7582   Hannes Frederic Sowa   ipv6: in case of ...
1350
  		if (rt->rt6i_flags & RTF_CACHE) {
ad65a2f05   Wei Wang   ipv6: call dst_ho...
1351
1352
  			if (dst_hold_safe(&rt->dst))
  				ip6_del_rt(rt);
c5cff8561   Wei Wang   ipv6: add rcu gra...
1353
1354
1355
1356
1357
1358
1359
1360
  		} else {
  			struct fib6_node *fn;
  
  			rcu_read_lock();
  			fn = rcu_dereference(rt->rt6i_node);
  			if (fn && (rt->rt6i_flags & RTF_DEFAULT))
  				fn->fn_sernum = -1;
  			rcu_read_unlock();
1eb4f7582   Hannes Frederic Sowa   ipv6: in case of ...
1361
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1362
1363
  	}
  }
45e4fd266   Martin KaFai Lau   ipv6: Only create...
1364
1365
1366
1367
1368
1369
1370
1371
  static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
  {
  	struct net *net = dev_net(rt->dst.dev);
  
  	rt->rt6i_flags |= RTF_MODIFIED;
  	rt->rt6i_pmtu = mtu;
  	rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
  }
0d3f6d297   Martin KaFai Lau   ipv6: Avoid creat...
1372
1373
1374
  static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
  {
  	return !(rt->rt6i_flags & RTF_CACHE) &&
4e587ea71   Wei Wang   ipv6: fix sparse ...
1375
1376
  		(rt->rt6i_flags & RTF_PCPU ||
  		 rcu_access_pointer(rt->rt6i_node));
0d3f6d297   Martin KaFai Lau   ipv6: Avoid creat...
1377
  }
45e4fd266   Martin KaFai Lau   ipv6: Only create...
1378
1379
  static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
  				 const struct ipv6hdr *iph, u32 mtu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1380
  {
0dec879f6   Julian Anastasov   net: use dst_conf...
1381
  	const struct in6_addr *daddr, *saddr;
67ba4152e   Ian Morris   ipv6: White-space...
1382
  	struct rt6_info *rt6 = (struct rt6_info *)dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1383

19bda36c4   Xin Long   ipv6: add mtu loc...
1384
1385
  	if (dst_metric_locked(dst, RTAX_MTU))
  		return;
0dec879f6   Julian Anastasov   net: use dst_conf...
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
  	if (iph) {
  		daddr = &iph->daddr;
  		saddr = &iph->saddr;
  	} else if (sk) {
  		daddr = &sk->sk_v6_daddr;
  		saddr = &inet6_sk(sk)->saddr;
  	} else {
  		daddr = NULL;
  		saddr = NULL;
  	}
  	dst_confirm_neigh(dst, daddr);
45e4fd266   Martin KaFai Lau   ipv6: Only create...
1397
1398
1399
  	mtu = max_t(u32, mtu, IPV6_MIN_MTU);
  	if (mtu >= dst_mtu(dst))
  		return;
9d289715e   Hagen Paul Pfeifer   ipv6: stop sendin...
1400

0d3f6d297   Martin KaFai Lau   ipv6: Avoid creat...
1401
  	if (!rt6_cache_allowed_for_pmtu(rt6)) {
45e4fd266   Martin KaFai Lau   ipv6: Only create...
1402
  		rt6_do_update_pmtu(rt6, mtu);
0dec879f6   Julian Anastasov   net: use dst_conf...
1403
  	} else if (daddr) {
45e4fd266   Martin KaFai Lau   ipv6: Only create...
1404
  		struct rt6_info *nrt6;
45e4fd266   Martin KaFai Lau   ipv6: Only create...
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
  		nrt6 = ip6_rt_cache_alloc(rt6, daddr, saddr);
  		if (nrt6) {
  			rt6_do_update_pmtu(nrt6, mtu);
  
  			/* ip6_ins_rt(nrt6) will bump the
  			 * rt6->rt6i_node->fn_sernum
  			 * which will fail the next rt6_check() and
  			 * invalidate the sk->sk_dst_cache.
  			 */
  			ip6_ins_rt(nrt6);
1cfb71eeb   Wei Wang   ipv6: take dst->_...
1415
1416
1417
1418
  			/* Release the reference taken in
  			 * ip6_rt_cache_alloc()
  			 */
  			dst_release(&nrt6->dst);
45e4fd266   Martin KaFai Lau   ipv6: Only create...
1419
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1420
1421
  	}
  }
45e4fd266   Martin KaFai Lau   ipv6: Only create...
1422
1423
1424
1425
1426
  static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
  			       struct sk_buff *skb, u32 mtu)
  {
  	__ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu);
  }
42ae66c80   David S. Miller   ipv6: Fix types o...
1427
  void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
e2d118a1c   Lorenzo Colitti   net: inet: Suppor...
1428
  		     int oif, u32 mark, kuid_t uid)
81aded246   David S. Miller   ipv6: Handle PMTU...
1429
1430
1431
1432
1433
1434
1435
  {
  	const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
  	struct dst_entry *dst;
  	struct flowi6 fl6;
  
  	memset(&fl6, 0, sizeof(fl6));
  	fl6.flowi6_oif = oif;
1b3c61dc1   Lorenzo Colitti   net: Use fwmark r...
1436
  	fl6.flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark);
81aded246   David S. Miller   ipv6: Handle PMTU...
1437
1438
  	fl6.daddr = iph->daddr;
  	fl6.saddr = iph->saddr;
6502ca527   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Introduce i...
1439
  	fl6.flowlabel = ip6_flowinfo(iph);
e2d118a1c   Lorenzo Colitti   net: inet: Suppor...
1440
  	fl6.flowi6_uid = uid;
81aded246   David S. Miller   ipv6: Handle PMTU...
1441
1442
1443
  
  	dst = ip6_route_output(net, NULL, &fl6);
  	if (!dst->error)
45e4fd266   Martin KaFai Lau   ipv6: Only create...
1444
  		__ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
81aded246   David S. Miller   ipv6: Handle PMTU...
1445
1446
1447
1448
1449
1450
  	dst_release(dst);
  }
  EXPORT_SYMBOL_GPL(ip6_update_pmtu);
  
  void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
  {
590f89a7e   David Ahern   ipv6: Fix PMTU up...
1451
  	int oif = sk->sk_bound_dev_if;
33c162a98   Martin KaFai Lau   ipv6: datagram: U...
1452
  	struct dst_entry *dst;
590f89a7e   David Ahern   ipv6: Fix PMTU up...
1453
1454
1455
1456
  	if (!oif && skb->dev)
  		oif = l3mdev_master_ifindex(skb->dev);
  
  	ip6_update_pmtu(skb, sock_net(sk), mtu, oif, sk->sk_mark, sk->sk_uid);
33c162a98   Martin KaFai Lau   ipv6: datagram: U...
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
  
  	dst = __sk_dst_get(sk);
  	if (!dst || !dst->obsolete ||
  	    dst->ops->check(dst, inet6_sk(sk)->dst_cookie))
  		return;
  
  	bh_lock_sock(sk);
  	if (!sock_owned_by_user(sk) && !ipv6_addr_v4mapped(&sk->sk_v6_daddr))
  		ip6_datagram_dst_update(sk, false);
  	bh_unlock_sock(sk);
81aded246   David S. Miller   ipv6: Handle PMTU...
1467
1468
  }
  EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
b55b76b22   Duan Jiong   ipv6:introduce fu...
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
  /* Handle redirects */
  struct ip6rd_flowi {
  	struct flowi6 fl6;
  	struct in6_addr gateway;
  };
  
  static struct rt6_info *__ip6_route_redirect(struct net *net,
  					     struct fib6_table *table,
  					     struct flowi6 *fl6,
  					     int flags)
  {
  	struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
  	struct rt6_info *rt;
  	struct fib6_node *fn;
  
  	/* Get the "current" route for this destination and
67c408cfa   Alexander Alemayhu   ipv6: fix typos
1485
  	 * check if the redirect has come from appropriate router.
b55b76b22   Duan Jiong   ipv6:introduce fu...
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
  	 *
  	 * RFC 4861 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.
  	 */
  
  	read_lock_bh(&table->tb6_lock);
  	fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
  restart:
  	for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
  		if (rt6_check_expired(rt))
  			continue;
  		if (rt->dst.error)
  			break;
  		if (!(rt->rt6i_flags & RTF_GATEWAY))
  			continue;
  		if (fl6->flowi6_oif != rt->dst.dev->ifindex)
  			continue;
  		if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway))
  			continue;
  		break;
  	}
  
  	if (!rt)
  		rt = net->ipv6.ip6_null_entry;
  	else if (rt->dst.error) {
  		rt = net->ipv6.ip6_null_entry;
b0a1ba599   Martin KaFai Lau   ipv6: Fix __ip6_r...
1515
1516
1517
1518
  		goto out;
  	}
  
  	if (rt == net->ipv6.ip6_null_entry) {
a3c00e46e   Martin KaFai Lau   ipv6: Remove BACK...
1519
1520
1521
  		fn = fib6_backtrack(fn, &fl6->saddr);
  		if (fn)
  			goto restart;
b55b76b22   Duan Jiong   ipv6:introduce fu...
1522
  	}
a3c00e46e   Martin KaFai Lau   ipv6: Remove BACK...
1523

b0a1ba599   Martin KaFai Lau   ipv6: Fix __ip6_r...
1524
  out:
b55b76b22   Duan Jiong   ipv6:introduce fu...
1525
1526
1527
  	dst_hold(&rt->dst);
  
  	read_unlock_bh(&table->tb6_lock);
b811580d9   David Ahern   net: IPv6 fib loo...
1528
  	trace_fib6_table_lookup(net, rt, table->tb6_id, fl6);
b55b76b22   Duan Jiong   ipv6:introduce fu...
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
  	return rt;
  };
  
  static struct dst_entry *ip6_route_redirect(struct net *net,
  					const struct flowi6 *fl6,
  					const struct in6_addr *gateway)
  {
  	int flags = RT6_LOOKUP_F_HAS_SADDR;
  	struct ip6rd_flowi rdfl;
  
  	rdfl.fl6 = *fl6;
  	rdfl.gateway = *gateway;
  
  	return fib6_rule_lookup(net, &rdfl.fl6,
  				flags, __ip6_route_redirect);
  }
e2d118a1c   Lorenzo Colitti   net: inet: Suppor...
1545
1546
  void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark,
  		  kuid_t uid)
3a5ad2ee5   David S. Miller   ipv6: Add ip6_red...
1547
1548
1549
1550
1551
1552
  {
  	const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
  	struct dst_entry *dst;
  	struct flowi6 fl6;
  
  	memset(&fl6, 0, sizeof(fl6));
e374c618b   Julian Anastasov   net: ipv6: more p...
1553
  	fl6.flowi6_iif = LOOPBACK_IFINDEX;
3a5ad2ee5   David S. Miller   ipv6: Add ip6_red...
1554
1555
  	fl6.flowi6_oif = oif;
  	fl6.flowi6_mark = mark;
3a5ad2ee5   David S. Miller   ipv6: Add ip6_red...
1556
1557
  	fl6.daddr = iph->daddr;
  	fl6.saddr = iph->saddr;
6502ca527   YOSHIFUJI Hideaki / 吉藤英明   ipv6: Introduce i...
1558
  	fl6.flowlabel = ip6_flowinfo(iph);
e2d118a1c   Lorenzo Colitti   net: inet: Suppor...
1559
  	fl6.flowi6_uid = uid;
3a5ad2ee5   David S. Miller   ipv6: Add ip6_red...
1560

b55b76b22   Duan Jiong   ipv6:introduce fu...
1561
1562
  	dst = ip6_route_redirect(net, &fl6, &ipv6_hdr(skb)->saddr);
  	rt6_do_redirect(dst, NULL, skb);
3a5ad2ee5   David S. Miller   ipv6: Add ip6_red...
1563
1564
1565
  	dst_release(dst);
  }
  EXPORT_SYMBOL_GPL(ip6_redirect);
c92a59eca   Duan Jiong   ipv6: handle Redi...
1566
1567
1568
1569
1570
1571
1572
1573
1574
  void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
  			    u32 mark)
  {
  	const struct ipv6hdr *iph = ipv6_hdr(skb);
  	const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
  	struct dst_entry *dst;
  	struct flowi6 fl6;
  
  	memset(&fl6, 0, sizeof(fl6));
e374c618b   Julian Anastasov   net: ipv6: more p...
1575
  	fl6.flowi6_iif = LOOPBACK_IFINDEX;
c92a59eca   Duan Jiong   ipv6: handle Redi...
1576
1577
  	fl6.flowi6_oif = oif;
  	fl6.flowi6_mark = mark;
c92a59eca   Duan Jiong   ipv6: handle Redi...
1578
1579
  	fl6.daddr = msg->dest;
  	fl6.saddr = iph->daddr;
e2d118a1c   Lorenzo Colitti   net: inet: Suppor...
1580
  	fl6.flowi6_uid = sock_net_uid(net, NULL);
c92a59eca   Duan Jiong   ipv6: handle Redi...
1581

b55b76b22   Duan Jiong   ipv6:introduce fu...
1582
1583
  	dst = ip6_route_redirect(net, &fl6, &iph->saddr);
  	rt6_do_redirect(dst, NULL, skb);
c92a59eca   Duan Jiong   ipv6: handle Redi...
1584
1585
  	dst_release(dst);
  }
3a5ad2ee5   David S. Miller   ipv6: Add ip6_red...
1586
1587
  void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
  {
e2d118a1c   Lorenzo Colitti   net: inet: Suppor...
1588
1589
  	ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark,
  		     sk->sk_uid);
3a5ad2ee5   David S. Miller   ipv6: Add ip6_red...
1590
1591
  }
  EXPORT_SYMBOL_GPL(ip6_sk_redirect);
0dbaee3b3   David S. Miller   net: Abstract def...
1592
  static unsigned int ip6_default_advmss(const struct dst_entry *dst)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1593
  {
0dbaee3b3   David S. Miller   net: Abstract def...
1594
1595
1596
  	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
1597
  	mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
1598
1599
  	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
1600
1601
  
  	/*
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1602
1603
1604
  	 * 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
1605
1606
1607
1608
1609
1610
  	 * rely only on pmtu discovery"
  	 */
  	if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
  		mtu = IPV6_MAXPLEN;
  	return mtu;
  }
ebb762f27   Steffen Klassert   net: Rename the d...
1611
  static unsigned int ip6_mtu(const struct dst_entry *dst)
d33e45533   David S. Miller   net: Abstract def...
1612
  {
4b32b5ad3   Martin KaFai Lau   ipv6: Stop rt6_in...
1613
1614
  	const struct rt6_info *rt = (const struct rt6_info *)dst;
  	unsigned int mtu = rt->rt6i_pmtu;
d33e45533   David S. Miller   net: Abstract def...
1615
  	struct inet6_dev *idev;
618f9bc74   Steffen Klassert   net: Move mtu han...
1616
1617
  
  	if (mtu)
30f78d8eb   Eric Dumazet   ipv6: Limit mtu t...
1618
  		goto out;
618f9bc74   Steffen Klassert   net: Move mtu han...
1619

4b32b5ad3   Martin KaFai Lau   ipv6: Stop rt6_in...
1620
1621
1622
  	mtu = dst_metric_raw(dst, RTAX_MTU);
  	if (mtu)
  		goto out;
618f9bc74   Steffen Klassert   net: Move mtu han...
1623
  	mtu = IPV6_MIN_MTU;
d33e45533   David S. Miller   net: Abstract def...
1624
1625
1626
1627
1628
1629
  
  	rcu_read_lock();
  	idev = __in6_dev_get(dst->dev);
  	if (idev)
  		mtu = idev->cnf.mtu6;
  	rcu_read_unlock();
30f78d8eb   Eric Dumazet   ipv6: Limit mtu t...
1630
  out:
14972cbd3   Roopa Prabhu   net: lwtunnel: Ha...
1631
1632
1633
  	mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
  
  	return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
d33e45533   David S. Miller   net: Abstract def...
1634
  }
3b00944c5   YOSHIFUJI Hideaki   [IPV6]: Make ndis...
1635
  struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
87a115783   David S. Miller   ipv6: Move xfrm_l...
1636
  				  struct flowi6 *fl6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1637
  {
87a115783   David S. Miller   ipv6: Move xfrm_l...
1638
  	struct dst_entry *dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1639
1640
  	struct rt6_info *rt;
  	struct inet6_dev *idev = in6_dev_get(dev);
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1641
  	struct net *net = dev_net(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1642

383084739   David S. Miller   ipv6: Various cle...
1643
  	if (unlikely(!idev))
122bdf67f   Eric Dumazet   ipv6: fix icmp6_d...
1644
  		return ERR_PTR(-ENODEV);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1645

ad7068628   Martin KaFai Lau   ipv6: Remove un-u...
1646
  	rt = ip6_dst_alloc(net, dev, 0);
383084739   David S. Miller   ipv6: Various cle...
1647
  	if (unlikely(!rt)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1648
  		in6_dev_put(idev);
87a115783   David S. Miller   ipv6: Move xfrm_l...
1649
  		dst = ERR_PTR(-ENOMEM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1650
1651
  		goto out;
  	}
8e2ec6391   Yan, Zheng   ipv6: don't use i...
1652
  	rt->dst.flags |= DST_HOST;
4b2e0f099   Brendan McGrath   ipv6: icmp6: Allo...
1653
  	rt->dst.input = ip6_input;
8e2ec6391   Yan, Zheng   ipv6: don't use i...
1654
  	rt->dst.output  = ip6_output;
550bab42f   Julian Anastasov   ipv6: fill rt6i_g...
1655
  	rt->rt6i_gateway  = fl6->daddr;
87a115783   David S. Miller   ipv6: Move xfrm_l...
1656
  	rt->rt6i_dst.addr = fl6->daddr;
8e2ec6391   Yan, Zheng   ipv6: don't use i...
1657
1658
  	rt->rt6i_dst.plen = 128;
  	rt->rt6i_idev     = idev;
14edd87dc   Li RongQing   ipv6: Set default...
1659
  	dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1660

587fea741   Wei Wang   ipv6: mark DST_NO...
1661
1662
1663
1664
  	/* Add this dst into uncached_list so that rt6_ifdown() can
  	 * do proper release of the net_device
  	 */
  	rt6_uncached_list_add(rt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1665

87a115783   David S. Miller   ipv6: Move xfrm_l...
1666
  	dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1667
  out:
87a115783   David S. Miller   ipv6: Move xfrm_l...
1668
  	return dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1669
  }
569d36452   Daniel Lezcano   [NETNS][DST] dst:...
1670
  static int ip6_dst_gc(struct dst_ops *ops)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1671
  {
86393e52c   Alexey Dobriyan   netns: embed ip6_...
1672
  	struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
7019b78e1   Daniel Lezcano   [NETNS][IPV6] rou...
1673
1674
1675
1676
1677
  	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...
1678
  	int entries;
7019b78e1   Daniel Lezcano   [NETNS][IPV6] rou...
1679

fc66f95c6   Eric Dumazet   net dst: use a pe...
1680
  	entries = dst_entries_get_fast(ops);
49a18d86f   Michal Kubeček   ipv6: update ip6_...
1681
  	if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
fc66f95c6   Eric Dumazet   net dst: use a pe...
1682
  	    entries <= rt_max_size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1683
  		goto out;
6891a346c   Benjamin Thery   [NETNS][IPV6] rou...
1684
  	net->ipv6.ip6_rt_gc_expire++;
149566435   Li RongQing   ipv6: slight opti...
1685
  	fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
fc66f95c6   Eric Dumazet   net dst: use a pe...
1686
1687
  	entries = dst_entries_get_slow(ops);
  	if (entries < ops->gc_thresh)
7019b78e1   Daniel Lezcano   [NETNS][IPV6] rou...
1688
  		net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1689
  out:
7019b78e1   Daniel Lezcano   [NETNS][IPV6] rou...
1690
  	net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
fc66f95c6   Eric Dumazet   net dst: use a pe...
1691
  	return entries > rt_max_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1692
  }
e715b6d3a   Florian Westphal   net: fib6: conver...
1693
1694
1695
  static int ip6_convert_metrics(struct mx6_config *mxc,
  			       const struct fib6_config *cfg)
  {
c3a8d9474   Daniel Borkmann   tcp: use dctcp if...
1696
  	bool ecn_ca = false;
e715b6d3a   Florian Westphal   net: fib6: conver...
1697
1698
1699
  	struct nlattr *nla;
  	int remaining;
  	u32 *mp;
63159f29b   Ian Morris   ipv6: coding styl...
1700
  	if (!cfg->fc_mx)
e715b6d3a   Florian Westphal   net: fib6: conver...
1701
1702
1703
1704
1705
1706
1707
1708
  		return 0;
  
  	mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
  	if (unlikely(!mp))
  		return -ENOMEM;
  
  	nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
  		int type = nla_type(nla);
1bb14807b   Daniel Borkmann   net: fib6: reduce...
1709
  		u32 val;
e715b6d3a   Florian Westphal   net: fib6: conver...
1710

1bb14807b   Daniel Borkmann   net: fib6: reduce...
1711
1712
1713
1714
  		if (!type)
  			continue;
  		if (unlikely(type > RTAX_MAX))
  			goto err;
ea6976399   Daniel Borkmann   net: tcp: add RTA...
1715

1bb14807b   Daniel Borkmann   net: fib6: reduce...
1716
1717
  		if (type == RTAX_CC_ALGO) {
  			char tmp[TCP_CA_NAME_MAX];
e715b6d3a   Florian Westphal   net: fib6: conver...
1718

1bb14807b   Daniel Borkmann   net: fib6: reduce...
1719
  			nla_strlcpy(tmp, nla, sizeof(tmp));
c3a8d9474   Daniel Borkmann   tcp: use dctcp if...
1720
  			val = tcp_ca_get_key_by_name(tmp, &ecn_ca);
1bb14807b   Daniel Borkmann   net: fib6: reduce...
1721
1722
1723
1724
  			if (val == TCP_CA_UNSPEC)
  				goto err;
  		} else {
  			val = nla_get_u32(nla);
e715b6d3a   Florian Westphal   net: fib6: conver...
1725
  		}
626abd59e   Paolo Abeni   net/route: enforc...
1726
1727
  		if (type == RTAX_HOPLIMIT && val > 255)
  			val = 255;
b8d3e4163   Daniel Borkmann   fib, fib6: reject...
1728
1729
  		if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK))
  			goto err;
1bb14807b   Daniel Borkmann   net: fib6: reduce...
1730
1731
1732
  
  		mp[type - 1] = val;
  		__set_bit(type - 1, mxc->mx_valid);
e715b6d3a   Florian Westphal   net: fib6: conver...
1733
  	}
c3a8d9474   Daniel Borkmann   tcp: use dctcp if...
1734
1735
1736
1737
  	if (ecn_ca) {
  		__set_bit(RTAX_FEATURES - 1, mxc->mx_valid);
  		mp[RTAX_FEATURES - 1] |= DST_FEATURE_ECN_CA;
  	}
e715b6d3a   Florian Westphal   net: fib6: conver...
1738

c3a8d9474   Daniel Borkmann   tcp: use dctcp if...
1739
  	mxc->mx = mp;
e715b6d3a   Florian Westphal   net: fib6: conver...
1740
1741
1742
1743
1744
  	return 0;
   err:
  	kfree(mp);
  	return -EINVAL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1745

8c14586fc   David Ahern   net: ipv6: Use pa...
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
  static struct rt6_info *ip6_nh_lookup_table(struct net *net,
  					    struct fib6_config *cfg,
  					    const struct in6_addr *gw_addr)
  {
  	struct flowi6 fl6 = {
  		.flowi6_oif = cfg->fc_ifindex,
  		.daddr = *gw_addr,
  		.saddr = cfg->fc_prefsrc,
  	};
  	struct fib6_table *table;
  	struct rt6_info *rt;
d5d32e4b7   David Ahern   net: ipv6: Do not...
1757
  	int flags = RT6_LOOKUP_F_IFACE | RT6_LOOKUP_F_IGNORE_LINKSTATE;
8c14586fc   David Ahern   net: ipv6: Use pa...
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
  
  	table = fib6_get_table(net, cfg->fc_table);
  	if (!table)
  		return NULL;
  
  	if (!ipv6_addr_any(&cfg->fc_prefsrc))
  		flags |= RT6_LOOKUP_F_HAS_SADDR;
  
  	rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, flags);
  
  	/* if table lookup failed, fall back to full lookup */
  	if (rt == net->ipv6.ip6_null_entry) {
  		ip6_rt_put(rt);
  		rt = NULL;
  	}
  
  	return rt;
  }
333c43016   David Ahern   net: ipv6: Plumb ...
1776
1777
  static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
  					      struct netlink_ext_ack *extack)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1778
  {
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
1779
  	struct net *net = cfg->fc_nlinfo.nl_net;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1780
1781
1782
  	struct rt6_info *rt = NULL;
  	struct net_device *dev = NULL;
  	struct inet6_dev *idev = NULL;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1783
  	struct fib6_table *table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1784
  	int addr_type;
8c5b83f0f   Roopa Prabhu   ipv6 route: use e...
1785
  	int err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1786

557c44be9   David Ahern   net: ipv6: RTF_PC...
1787
  	/* RTF_PCPU is an internal flag; can not be set by userspace */
d5d531cb5   David Ahern   net: ipv6: Add ex...
1788
1789
  	if (cfg->fc_flags & RTF_PCPU) {
  		NL_SET_ERR_MSG(extack, "Userspace can not set RTF_PCPU");
557c44be9   David Ahern   net: ipv6: RTF_PC...
1790
  		goto out;
d5d531cb5   David Ahern   net: ipv6: Add ex...
1791
  	}
557c44be9   David Ahern   net: ipv6: RTF_PC...
1792

d5d531cb5   David Ahern   net: ipv6: Add ex...
1793
1794
1795
1796
1797
1798
  	if (cfg->fc_dst_len > 128) {
  		NL_SET_ERR_MSG(extack, "Invalid prefix length");
  		goto out;
  	}
  	if (cfg->fc_src_len > 128) {
  		NL_SET_ERR_MSG(extack, "Invalid source address length");
8c5b83f0f   Roopa Prabhu   ipv6 route: use e...
1799
  		goto out;
d5d531cb5   David Ahern   net: ipv6: Add ex...
1800
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1801
  #ifndef CONFIG_IPV6_SUBTREES
d5d531cb5   David Ahern   net: ipv6: Add ex...
1802
1803
1804
  	if (cfg->fc_src_len) {
  		NL_SET_ERR_MSG(extack,
  			       "Specifying source address requires IPV6_SUBTREES to be enabled");
8c5b83f0f   Roopa Prabhu   ipv6 route: use e...
1805
  		goto out;
d5d531cb5   David Ahern   net: ipv6: Add ex...
1806
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1807
  #endif
86872cb57   Thomas Graf   [IPv6] route: FIB...
1808
  	if (cfg->fc_ifindex) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1809
  		err = -ENODEV;
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
1810
  		dev = dev_get_by_index(net, cfg->fc_ifindex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1811
1812
1813
1814
1815
1816
  		if (!dev)
  			goto out;
  		idev = in6_dev_get(dev);
  		if (!idev)
  			goto out;
  	}
86872cb57   Thomas Graf   [IPv6] route: FIB...
1817
1818
  	if (cfg->fc_metric == 0)
  		cfg->fc_metric = IP6_RT_PRIO_USER;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1819

d71314b4a   Matti Vaittinen   IPv6 routing, NLM...
1820
  	err = -ENOBUFS;
383084739   David S. Miller   ipv6: Various cle...
1821
1822
  	if (cfg->fc_nlinfo.nlh &&
  	    !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
d71314b4a   Matti Vaittinen   IPv6 routing, NLM...
1823
  		table = fib6_get_table(net, cfg->fc_table);
383084739   David S. Miller   ipv6: Various cle...
1824
  		if (!table) {
f32138319   Joe Perches   net: ipv6: Standa...
1825
1826
  			pr_warn("NLM_F_CREATE should be specified when creating new route
  ");
d71314b4a   Matti Vaittinen   IPv6 routing, NLM...
1827
1828
1829
1830
1831
  			table = fib6_new_table(net, cfg->fc_table);
  		}
  	} else {
  		table = fib6_new_table(net, cfg->fc_table);
  	}
383084739   David S. Miller   ipv6: Various cle...
1832
1833
  
  	if (!table)
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1834
  		goto out;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
1835

ad7068628   Martin KaFai Lau   ipv6: Remove un-u...
1836
1837
  	rt = ip6_dst_alloc(net, NULL,
  			   (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1838

383084739   David S. Miller   ipv6: Various cle...
1839
  	if (!rt) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1840
1841
1842
  		err = -ENOMEM;
  		goto out;
  	}
1716a9610   Gao feng   ipv6: fix problem...
1843
1844
1845
1846
1847
  	if (cfg->fc_flags & RTF_EXPIRES)
  		rt6_set_expires(rt, jiffies +
  				clock_t_to_jiffies(cfg->fc_expires));
  	else
  		rt6_clean_expires(rt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1848

86872cb57   Thomas Graf   [IPv6] route: FIB...
1849
1850
1851
1852
1853
  	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
1854
1855
  
  	if (addr_type & IPV6_ADDR_MULTICAST)
d8d1f30b9   Changli Gao   net-next: remove ...
1856
  		rt->dst.input = ip6_mc_input;
ab79ad14a   Maciej Żenczykowski   ipv6: Implement A...
1857
1858
  	else if (cfg->fc_flags & RTF_LOCAL)
  		rt->dst.input = ip6_input;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1859
  	else
d8d1f30b9   Changli Gao   net-next: remove ...
1860
  		rt->dst.input = ip6_forward;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1861

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

19e42e451   Roopa Prabhu   ipv6: support for...
1864
1865
  	if (cfg->fc_encap) {
  		struct lwtunnel_state *lwtstate;
30357d7d8   David Ahern   lwtunnel: remove ...
1866
  		err = lwtunnel_build_state(cfg->fc_encap_type,
127eb7cd3   Tom Herbert   lwt: Add cfg argu...
1867
  					   cfg->fc_encap, AF_INET6, cfg,
9ae287274   David Ahern   net: add extack a...
1868
  					   &lwtstate, extack);
19e42e451   Roopa Prabhu   ipv6: support for...
1869
1870
  		if (err)
  			goto out;
61adedf3e   Jiri Benc   route: move lwtun...
1871
1872
1873
1874
  		rt->dst.lwtstate = lwtstate_get(lwtstate);
  		if (lwtunnel_output_redirect(rt->dst.lwtstate)) {
  			rt->dst.lwtstate->orig_output = rt->dst.output;
  			rt->dst.output = lwtunnel_output;
253686231   Tom Herbert   lwt: Add support ...
1875
  		}
61adedf3e   Jiri Benc   route: move lwtun...
1876
1877
1878
  		if (lwtunnel_input_redirect(rt->dst.lwtstate)) {
  			rt->dst.lwtstate->orig_input = rt->dst.input;
  			rt->dst.input = lwtunnel_input;
253686231   Tom Herbert   lwt: Add support ...
1879
  		}
19e42e451   Roopa Prabhu   ipv6: support for...
1880
  	}
86872cb57   Thomas Graf   [IPv6] route: FIB...
1881
1882
  	ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
  	rt->rt6i_dst.plen = cfg->fc_dst_len;
afc4eef80   Martin KaFai Lau   ipv6: Remove DST_...
1883
  	if (rt->rt6i_dst.plen == 128)
e5fd387ad   Michal Kubeček   ipv6: do not over...
1884
  		rt->dst.flags |= DST_HOST;
e5fd387ad   Michal Kubeček   ipv6: do not over...
1885

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1886
  #ifdef CONFIG_IPV6_SUBTREES
86872cb57   Thomas Graf   [IPv6] route: FIB...
1887
1888
  	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
1889
  #endif
86872cb57   Thomas Graf   [IPv6] route: FIB...
1890
  	rt->rt6i_metric = cfg->fc_metric;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1891
1892
1893
1894
  
  	/* 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...
1895
  	if ((cfg->fc_flags & RTF_REJECT) ||
383084739   David S. Miller   ipv6: Various cle...
1896
1897
1898
  	    (dev && (dev->flags & IFF_LOOPBACK) &&
  	     !(addr_type & IPV6_ADDR_LOOPBACK) &&
  	     !(cfg->fc_flags & RTF_LOCAL))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1899
  		/* hold loopback dev/idev if we haven't done so. */
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
1900
  		if (dev != net->loopback_dev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1901
1902
1903
1904
  			if (dev) {
  				dev_put(dev);
  				in6_dev_put(idev);
  			}
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
1905
  			dev = net->loopback_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1906
1907
1908
1909
1910
1911
1912
  			dev_hold(dev);
  			idev = in6_dev_get(dev);
  			if (!idev) {
  				err = -ENODEV;
  				goto out;
  			}
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1913
  		rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
ef2c7d7b5   Nicolas Dichtel   ipv6: fix handlin...
1914
1915
1916
  		switch (cfg->fc_type) {
  		case RTN_BLACKHOLE:
  			rt->dst.error = -EINVAL;
ede2059db   Eric W. Biederman   dst: Pass net int...
1917
  			rt->dst.output = dst_discard_out;
7150aede5   Kamala R   IPv6: Fixed suppo...
1918
  			rt->dst.input = dst_discard;
ef2c7d7b5   Nicolas Dichtel   ipv6: fix handlin...
1919
1920
1921
  			break;
  		case RTN_PROHIBIT:
  			rt->dst.error = -EACCES;
7150aede5   Kamala R   IPv6: Fixed suppo...
1922
1923
  			rt->dst.output = ip6_pkt_prohibit_out;
  			rt->dst.input = ip6_pkt_prohibit;
ef2c7d7b5   Nicolas Dichtel   ipv6: fix handlin...
1924
  			break;
b4949ab26   Nicolas Dichtel   ipv6: fix handlin...
1925
  		case RTN_THROW:
0315e3827   Nikola Forró   net: Fix behaviou...
1926
  		case RTN_UNREACHABLE:
ef2c7d7b5   Nicolas Dichtel   ipv6: fix handlin...
1927
  		default:
7150aede5   Kamala R   IPv6: Fixed suppo...
1928
  			rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN
0315e3827   Nikola Forró   net: Fix behaviou...
1929
1930
  					: (cfg->fc_type == RTN_UNREACHABLE)
  					? -EHOSTUNREACH : -ENETUNREACH;
7150aede5   Kamala R   IPv6: Fixed suppo...
1931
1932
  			rt->dst.output = ip6_pkt_discard_out;
  			rt->dst.input = ip6_pkt_discard;
ef2c7d7b5   Nicolas Dichtel   ipv6: fix handlin...
1933
1934
  			break;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1935
1936
  		goto install_route;
  	}
86872cb57   Thomas Graf   [IPv6] route: FIB...
1937
  	if (cfg->fc_flags & RTF_GATEWAY) {
b71d1d426   Eric Dumazet   inet: constify ip...
1938
  		const struct in6_addr *gw_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1939
  		int gwa_type;
86872cb57   Thomas Graf   [IPv6] route: FIB...
1940
  		gw_addr = &cfg->fc_gateway;
330567b71   Florian Westphal   ipv6: don't rejec...
1941
  		gwa_type = ipv6_addr_type(gw_addr);
48ed7b26f   Florian Westphal   ipv6: reject loca...
1942
1943
1944
1945
1946
1947
1948
  
  		/* if gw_addr is local we will fail to detect this in case
  		 * address is still TENTATIVE (DAD in progress). rt6_lookup()
  		 * will return already-added prefix route via interface that
  		 * prefix route was assigned to, which might be non-loopback.
  		 */
  		err = -EINVAL;
330567b71   Florian Westphal   ipv6: don't rejec...
1949
1950
  		if (ipv6_chk_addr_and_flags(net, gw_addr,
  					    gwa_type & IPV6_ADDR_LINKLOCAL ?
d5d531cb5   David Ahern   net: ipv6: Add ex...
1951
1952
  					    dev : NULL, 0, 0)) {
  			NL_SET_ERR_MSG(extack, "Invalid gateway address");
48ed7b26f   Florian Westphal   ipv6: reject loca...
1953
  			goto out;
d5d531cb5   David Ahern   net: ipv6: Add ex...
1954
  		}
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1955
  		rt->rt6i_gateway = *gw_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1956
1957
  
  		if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
8c14586fc   David Ahern   net: ipv6: Use pa...
1958
  			struct rt6_info *grt = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1959
1960
1961
1962
1963
1964
1965
  
  			/* 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
96d5822c1   Erik Nordmark   ipv6: Allow IPv4-...
1966
1967
  			   We allow IPv4-mapped nexthops to support RFC4798-type
  			   addressing
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1968
  			 */
96d5822c1   Erik Nordmark   ipv6: Allow IPv4-...
1969
  			if (!(gwa_type & (IPV6_ADDR_UNICAST |
d5d531cb5   David Ahern   net: ipv6: Add ex...
1970
1971
1972
  					  IPV6_ADDR_MAPPED))) {
  				NL_SET_ERR_MSG(extack,
  					       "Invalid gateway address");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1973
  				goto out;
d5d531cb5   David Ahern   net: ipv6: Add ex...
1974
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1975

a435a07f9   Vincent Bernat   net: ipv6: fallba...
1976
  			if (cfg->fc_table) {
8c14586fc   David Ahern   net: ipv6: Use pa...
1977
  				grt = ip6_nh_lookup_table(net, cfg, gw_addr);
a435a07f9   Vincent Bernat   net: ipv6: fallba...
1978
1979
1980
1981
1982
1983
1984
1985
  				if (grt) {
  					if (grt->rt6i_flags & RTF_GATEWAY ||
  					    (dev && dev != grt->dst.dev)) {
  						ip6_rt_put(grt);
  						grt = NULL;
  					}
  				}
  			}
8c14586fc   David Ahern   net: ipv6: Use pa...
1986
1987
1988
  			if (!grt)
  				grt = rt6_lookup(net, gw_addr, NULL,
  						 cfg->fc_ifindex, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1989
1990
  
  			err = -EHOSTUNREACH;
383084739   David S. Miller   ipv6: Various cle...
1991
  			if (!grt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1992
1993
  				goto out;
  			if (dev) {
d19185428   David S. Miller   ipv6: Kill rt6i_d...
1994
  				if (dev != grt->dst.dev) {
94e187c01   Amerigo Wang   ipv6: introduce i...
1995
  					ip6_rt_put(grt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1996
1997
1998
  					goto out;
  				}
  			} else {
d19185428   David S. Miller   ipv6: Kill rt6i_d...
1999
  				dev = grt->dst.dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2000
2001
2002
2003
  				idev = grt->rt6i_idev;
  				dev_hold(dev);
  				in6_dev_hold(grt->rt6i_idev);
  			}
383084739   David S. Miller   ipv6: Various cle...
2004
  			if (!(grt->rt6i_flags & RTF_GATEWAY))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2005
  				err = 0;
94e187c01   Amerigo Wang   ipv6: introduce i...
2006
  			ip6_rt_put(grt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2007
2008
2009
2010
2011
  
  			if (err)
  				goto out;
  		}
  		err = -EINVAL;
d5d531cb5   David Ahern   net: ipv6: Add ex...
2012
2013
2014
2015
2016
2017
  		if (!dev) {
  			NL_SET_ERR_MSG(extack, "Egress device not specified");
  			goto out;
  		} else if (dev->flags & IFF_LOOPBACK) {
  			NL_SET_ERR_MSG(extack,
  				       "Egress device can not be loopback device for this route");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2018
  			goto out;
d5d531cb5   David Ahern   net: ipv6: Add ex...
2019
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2020
2021
2022
  	}
  
  	err = -ENODEV;
383084739   David S. Miller   ipv6: Various cle...
2023
  	if (!dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2024
  		goto out;
c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
2025
2026
  	if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
  		if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
d5d531cb5   David Ahern   net: ipv6: Add ex...
2027
  			NL_SET_ERR_MSG(extack, "Invalid source address");
c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
2028
2029
2030
  			err = -EINVAL;
  			goto out;
  		}
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
2031
  		rt->rt6i_prefsrc.addr = cfg->fc_prefsrc;
c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
2032
2033
2034
  		rt->rt6i_prefsrc.plen = 128;
  	} else
  		rt->rt6i_prefsrc.plen = 0;
86872cb57   Thomas Graf   [IPv6] route: FIB...
2035
  	rt->rt6i_flags = cfg->fc_flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2036
2037
  
  install_route:
d8d1f30b9   Changli Gao   net-next: remove ...
2038
  	rt->dst.dev = dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2039
  	rt->rt6i_idev = idev;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
2040
  	rt->rt6i_table = table;
63152fc0d   Daniel Lezcano   [NETNS][IPV6] ip6...
2041

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

8c5b83f0f   Roopa Prabhu   ipv6 route: use e...
2044
  	return rt;
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
2045
2046
2047
2048
2049
  out:
  	if (dev)
  		dev_put(dev);
  	if (idev)
  		in6_dev_put(idev);
587fea741   Wei Wang   ipv6: mark DST_NO...
2050
2051
  	if (rt)
  		dst_release_immediate(&rt->dst);
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
2052

8c5b83f0f   Roopa Prabhu   ipv6 route: use e...
2053
  	return ERR_PTR(err);
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
2054
  }
333c43016   David Ahern   net: ipv6: Plumb ...
2055
2056
  int ip6_route_add(struct fib6_config *cfg,
  		  struct netlink_ext_ack *extack)
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
2057
2058
  {
  	struct mx6_config mxc = { .mx = NULL, };
8c5b83f0f   Roopa Prabhu   ipv6 route: use e...
2059
  	struct rt6_info *rt;
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
2060
  	int err;
333c43016   David Ahern   net: ipv6: Plumb ...
2061
  	rt = ip6_route_info_create(cfg, extack);
8c5b83f0f   Roopa Prabhu   ipv6 route: use e...
2062
2063
2064
  	if (IS_ERR(rt)) {
  		err = PTR_ERR(rt);
  		rt = NULL;
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
2065
  		goto out;
8c5b83f0f   Roopa Prabhu   ipv6 route: use e...
2066
  	}
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
2067

e715b6d3a   Florian Westphal   net: fib6: conver...
2068
2069
2070
  	err = ip6_convert_metrics(&mxc, cfg);
  	if (err)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2071

333c43016   David Ahern   net: ipv6: Plumb ...
2072
  	err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, &mxc, extack);
e715b6d3a   Florian Westphal   net: fib6: conver...
2073
2074
  
  	kfree(mxc.mx);
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
2075

e715b6d3a   Florian Westphal   net: fib6: conver...
2076
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2077
  out:
587fea741   Wei Wang   ipv6: mark DST_NO...
2078
2079
  	if (rt)
  		dst_release_immediate(&rt->dst);
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
2080

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2081
2082
  	return err;
  }
86872cb57   Thomas Graf   [IPv6] route: FIB...
2083
  static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2084
2085
  {
  	int err;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
2086
  	struct fib6_table *table;
d19185428   David S. Miller   ipv6: Kill rt6i_d...
2087
  	struct net *net = dev_net(rt->dst.dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2088

a4c2fd7f7   Wei Wang   net: remove DST_N...
2089
  	if (rt == net->ipv6.ip6_null_entry) {
6825a26c2   Gao feng   ipv6: release ref...
2090
2091
2092
  		err = -ENOENT;
  		goto out;
  	}
6c813a729   Patrick McHardy   [IPV6]: Fix crash...
2093

c71099acc   Thomas Graf   [IPV6]: Multiple ...
2094
2095
  	table = rt->rt6i_table;
  	write_lock_bh(&table->tb6_lock);
86872cb57   Thomas Graf   [IPv6] route: FIB...
2096
  	err = fib6_del(rt, info);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
2097
  	write_unlock_bh(&table->tb6_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2098

6825a26c2   Gao feng   ipv6: release ref...
2099
  out:
94e187c01   Amerigo Wang   ipv6: introduce i...
2100
  	ip6_rt_put(rt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2101
2102
  	return err;
  }
e0a1ad73d   Thomas Graf   [IPv6] route: Sim...
2103
2104
  int ip6_del_rt(struct rt6_info *rt)
  {
4d1169c1e   Denis V. Lunev   [NETNS]: Add netn...
2105
  	struct nl_info info = {
d19185428   David S. Miller   ipv6: Kill rt6i_d...
2106
  		.nl_net = dev_net(rt->dst.dev),
4d1169c1e   Denis V. Lunev   [NETNS]: Add netn...
2107
  	};
528c4ceb4   Denis V. Lunev   [IPV6]: Always pa...
2108
  	return __ip6_del_rt(rt, &info);
e0a1ad73d   Thomas Graf   [IPv6] route: Sim...
2109
  }
0ae813358   David Ahern   net: ipv6: Allow ...
2110
2111
2112
  static int __ip6_del_rt_siblings(struct rt6_info *rt, struct fib6_config *cfg)
  {
  	struct nl_info *info = &cfg->fc_nlinfo;
e3330039e   WANG Cong   ipv6: check for i...
2113
  	struct net *net = info->nl_net;
16a16cd35   David Ahern   net: ipv6: Change...
2114
  	struct sk_buff *skb = NULL;
0ae813358   David Ahern   net: ipv6: Allow ...
2115
  	struct fib6_table *table;
e3330039e   WANG Cong   ipv6: check for i...
2116
  	int err = -ENOENT;
0ae813358   David Ahern   net: ipv6: Allow ...
2117

e3330039e   WANG Cong   ipv6: check for i...
2118
2119
  	if (rt == net->ipv6.ip6_null_entry)
  		goto out_put;
0ae813358   David Ahern   net: ipv6: Allow ...
2120
2121
2122
2123
2124
  	table = rt->rt6i_table;
  	write_lock_bh(&table->tb6_lock);
  
  	if (rt->rt6i_nsiblings && cfg->fc_delete_all_nh) {
  		struct rt6_info *sibling, *next_sibling;
16a16cd35   David Ahern   net: ipv6: Change...
2125
2126
2127
2128
  		/* prefer to send a single notification with all hops */
  		skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
  		if (skb) {
  			u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
e3330039e   WANG Cong   ipv6: check for i...
2129
  			if (rt6_fill_node(net, skb, rt,
16a16cd35   David Ahern   net: ipv6: Change...
2130
2131
2132
2133
2134
2135
2136
  					  NULL, NULL, 0, RTM_DELROUTE,
  					  info->portid, seq, 0) < 0) {
  				kfree_skb(skb);
  				skb = NULL;
  			} else
  				info->skip_notify = 1;
  		}
0ae813358   David Ahern   net: ipv6: Allow ...
2137
2138
2139
2140
2141
  		list_for_each_entry_safe(sibling, next_sibling,
  					 &rt->rt6i_siblings,
  					 rt6i_siblings) {
  			err = fib6_del(sibling, info);
  			if (err)
e3330039e   WANG Cong   ipv6: check for i...
2142
  				goto out_unlock;
0ae813358   David Ahern   net: ipv6: Allow ...
2143
2144
2145
2146
  		}
  	}
  
  	err = fib6_del(rt, info);
e3330039e   WANG Cong   ipv6: check for i...
2147
  out_unlock:
0ae813358   David Ahern   net: ipv6: Allow ...
2148
  	write_unlock_bh(&table->tb6_lock);
e3330039e   WANG Cong   ipv6: check for i...
2149
  out_put:
0ae813358   David Ahern   net: ipv6: Allow ...
2150
  	ip6_rt_put(rt);
16a16cd35   David Ahern   net: ipv6: Change...
2151
2152
  
  	if (skb) {
e3330039e   WANG Cong   ipv6: check for i...
2153
  		rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
16a16cd35   David Ahern   net: ipv6: Change...
2154
2155
  			    info->nlh, gfp_any());
  	}
0ae813358   David Ahern   net: ipv6: Allow ...
2156
2157
  	return err;
  }
333c43016   David Ahern   net: ipv6: Plumb ...
2158
2159
  static int ip6_route_del(struct fib6_config *cfg,
  			 struct netlink_ext_ack *extack)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2160
  {
c71099acc   Thomas Graf   [IPV6]: Multiple ...
2161
  	struct fib6_table *table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2162
2163
2164
  	struct fib6_node *fn;
  	struct rt6_info *rt;
  	int err = -ESRCH;
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
2165
  	table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
d5d531cb5   David Ahern   net: ipv6: Add ex...
2166
2167
  	if (!table) {
  		NL_SET_ERR_MSG(extack, "FIB table does not exist");
c71099acc   Thomas Graf   [IPV6]: Multiple ...
2168
  		return err;
d5d531cb5   David Ahern   net: ipv6: Add ex...
2169
  	}
c71099acc   Thomas Graf   [IPV6]: Multiple ...
2170
2171
  
  	read_lock_bh(&table->tb6_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2172

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2177
  	if (fn) {
d8d1f30b9   Changli Gao   net-next: remove ...
2178
  		for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
1f56a01f4   Martin KaFai Lau   ipv6: Consider RT...
2179
2180
2181
  			if ((rt->rt6i_flags & RTF_CACHE) &&
  			    !(cfg->fc_flags & RTF_CACHE))
  				continue;
86872cb57   Thomas Graf   [IPv6] route: FIB...
2182
  			if (cfg->fc_ifindex &&
d19185428   David S. Miller   ipv6: Kill rt6i_d...
2183
2184
  			    (!rt->dst.dev ||
  			     rt->dst.dev->ifindex != cfg->fc_ifindex))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2185
  				continue;
86872cb57   Thomas Graf   [IPv6] route: FIB...
2186
2187
  			if (cfg->fc_flags & RTF_GATEWAY &&
  			    !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2188
  				continue;
86872cb57   Thomas Graf   [IPv6] route: FIB...
2189
  			if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2190
  				continue;
c2ed1880f   Mantas M   net: ipv6: check ...
2191
2192
  			if (cfg->fc_protocol && cfg->fc_protocol != rt->rt6i_protocol)
  				continue;
d8d1f30b9   Changli Gao   net-next: remove ...
2193
  			dst_hold(&rt->dst);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
2194
  			read_unlock_bh(&table->tb6_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2195

0ae813358   David Ahern   net: ipv6: Allow ...
2196
2197
2198
2199
2200
  			/* if gateway was specified only delete the one hop */
  			if (cfg->fc_flags & RTF_GATEWAY)
  				return __ip6_del_rt(rt, &cfg->fc_nlinfo);
  
  			return __ip6_del_rt_siblings(rt, cfg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2201
2202
  		}
  	}
c71099acc   Thomas Graf   [IPV6]: Multiple ...
2203
  	read_unlock_bh(&table->tb6_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2204
2205
2206
  
  	return err;
  }
6700c2709   David S. Miller   net: Pass optiona...
2207
  static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
a6279458c   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
2208
  {
a6279458c   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
2209
  	struct netevent_redirect netevent;
e8599ff4b   David S. Miller   ipv6: Move bulk o...
2210
  	struct rt6_info *rt, *nrt = NULL;
e8599ff4b   David S. Miller   ipv6: Move bulk o...
2211
2212
2213
  	struct ndisc_options ndopts;
  	struct inet6_dev *in6_dev;
  	struct neighbour *neigh;
71bcdba06   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Use struct...
2214
  	struct rd_msg *msg;
6e157b6ac   David S. Miller   ipv6: Pull main l...
2215
2216
  	int optlen, on_link;
  	u8 *lladdr;
e8599ff4b   David S. Miller   ipv6: Move bulk o...
2217

29a3cad5c   Simon Horman   ipv6: Correct com...
2218
  	optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
71bcdba06   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Use struct...
2219
  	optlen -= sizeof(*msg);
e8599ff4b   David S. Miller   ipv6: Move bulk o...
2220
2221
  
  	if (optlen < 0) {
6e157b6ac   David S. Miller   ipv6: Pull main l...
2222
2223
  		net_dbg_ratelimited("rt6_do_redirect: packet too short
  ");
e8599ff4b   David S. Miller   ipv6: Move bulk o...
2224
2225
  		return;
  	}
71bcdba06   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Use struct...
2226
  	msg = (struct rd_msg *)icmp6_hdr(skb);
e8599ff4b   David S. Miller   ipv6: Move bulk o...
2227

71bcdba06   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Use struct...
2228
  	if (ipv6_addr_is_multicast(&msg->dest)) {
6e157b6ac   David S. Miller   ipv6: Pull main l...
2229
2230
  		net_dbg_ratelimited("rt6_do_redirect: destination address is multicast
  ");
e8599ff4b   David S. Miller   ipv6: Move bulk o...
2231
2232
  		return;
  	}
6e157b6ac   David S. Miller   ipv6: Pull main l...
2233
  	on_link = 0;
71bcdba06   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Use struct...
2234
  	if (ipv6_addr_equal(&msg->dest, &msg->target)) {
e8599ff4b   David S. Miller   ipv6: Move bulk o...
2235
  		on_link = 1;
71bcdba06   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Use struct...
2236
  	} else if (ipv6_addr_type(&msg->target) !=
e8599ff4b   David S. Miller   ipv6: Move bulk o...
2237
  		   (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
6e157b6ac   David S. Miller   ipv6: Pull main l...
2238
2239
  		net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast
  ");
e8599ff4b   David S. Miller   ipv6: Move bulk o...
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
  		return;
  	}
  
  	in6_dev = __in6_dev_get(skb->dev);
  	if (!in6_dev)
  		return;
  	if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
  		return;
  
  	/* RFC2461 8.1:
  	 *	The IP source address of the Redirect MUST be the same as the current
  	 *	first-hop router for the specified ICMP Destination Address.
  	 */
f997c55c1   Alexander Aring   ipv6: introduce n...
2253
  	if (!ndisc_parse_options(skb->dev, msg->opt, optlen, &ndopts)) {
e8599ff4b   David S. Miller   ipv6: Move bulk o...
2254
2255
2256
2257
  		net_dbg_ratelimited("rt6_redirect: invalid ND options
  ");
  		return;
  	}
6e157b6ac   David S. Miller   ipv6: Pull main l...
2258
2259
  
  	lladdr = NULL;
e8599ff4b   David S. Miller   ipv6: Move bulk o...
2260
2261
2262
2263
2264
2265
2266
2267
2268
  	if (ndopts.nd_opts_tgt_lladdr) {
  		lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
  					     skb->dev);
  		if (!lladdr) {
  			net_dbg_ratelimited("rt6_redirect: invalid link-layer address length
  ");
  			return;
  		}
  	}
6e157b6ac   David S. Miller   ipv6: Pull main l...
2269
  	rt = (struct rt6_info *) dst;
ec13ad1d7   Matthias Schiffer   ipv6: fix crash o...
2270
  	if (rt->rt6i_flags & RTF_REJECT) {
6e157b6ac   David S. Miller   ipv6: Pull main l...
2271
2272
  		net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target
  ");
e8599ff4b   David S. Miller   ipv6: Move bulk o...
2273
  		return;
6e157b6ac   David S. Miller   ipv6: Pull main l...
2274
  	}
e8599ff4b   David S. Miller   ipv6: Move bulk o...
2275

6e157b6ac   David S. Miller   ipv6: Pull main l...
2276
2277
2278
2279
  	/* Redirect received -> path was valid.
  	 * Look, redirects are sent only in response to data packets,
  	 * so that this nexthop apparently is reachable. --ANK
  	 */
0dec879f6   Julian Anastasov   net: use dst_conf...
2280
  	dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
a6279458c   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
2281

71bcdba06   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Use struct...
2282
  	neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
6e157b6ac   David S. Miller   ipv6: Pull main l...
2283
2284
  	if (!neigh)
  		return;
a6279458c   YOSHIFUJI Hideaki   [IPV6] NDISC: Sea...
2285

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2286
2287
2288
  	/*
  	 *	We have finally decided to accept it.
  	 */
f997c55c1   Alexander Aring   ipv6: introduce n...
2289
  	ndisc_update(skb->dev, neigh, lladdr, NUD_STALE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2290
2291
2292
  		     NEIGH_UPDATE_F_WEAK_OVERRIDE|
  		     NEIGH_UPDATE_F_OVERRIDE|
  		     (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
f997c55c1   Alexander Aring   ipv6: introduce n...
2293
2294
  				     NEIGH_UPDATE_F_ISROUTER)),
  		     NDISC_REDIRECT, &ndopts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2295

83a09abd1   Martin KaFai Lau   ipv6: Break up ip...
2296
  	nrt = ip6_rt_cache_alloc(rt, &msg->dest, NULL);
383084739   David S. Miller   ipv6: Various cle...
2297
  	if (!nrt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2298
2299
2300
2301
2302
  		goto out;
  
  	nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
  	if (on_link)
  		nrt->rt6i_flags &= ~RTF_GATEWAY;
b91d53292   Xin Long   ipv6: set rt6i_pr...
2303
  	nrt->rt6i_protocol = RTPROT_REDIRECT;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
2304
  	nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2305

40e22e8f3   Thomas Graf   [IPv6] route: Sim...
2306
  	if (ip6_ins_rt(nrt))
1cfb71eeb   Wei Wang   ipv6: take dst->_...
2307
  		goto out_release;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2308

d8d1f30b9   Changli Gao   net-next: remove ...
2309
2310
  	netevent.old = &rt->dst;
  	netevent.new = &nrt->dst;
71bcdba06   YOSHIFUJI Hideaki / 吉藤英明   ndisc: Use struct...
2311
  	netevent.daddr = &msg->dest;
605928337   YOSHIFUJI Hideaki / 吉藤英明   ipv6 netevent: Re...
2312
  	netevent.neigh = neigh;
8d71740c5   Tom Tucker   [NET]: Core net c...
2313
  	call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
383084739   David S. Miller   ipv6: Various cle...
2314
  	if (rt->rt6i_flags & RTF_CACHE) {
6e157b6ac   David S. Miller   ipv6: Pull main l...
2315
  		rt = (struct rt6_info *) dst_clone(&rt->dst);
e0a1ad73d   Thomas Graf   [IPv6] route: Sim...
2316
  		ip6_del_rt(rt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2317
  	}
1cfb71eeb   Wei Wang   ipv6: take dst->_...
2318
2319
2320
2321
2322
  out_release:
  	/* Release the reference taken in
  	 * ip6_rt_cache_alloc()
  	 */
  	dst_release(&nrt->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2323
  out:
e8599ff4b   David S. Miller   ipv6: Move bulk o...
2324
  	neigh_release(neigh);
6e157b6ac   David S. Miller   ipv6: Pull main l...
2325
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2326
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2327
2328
   *	Misc support functions
   */
4b32b5ad3   Martin KaFai Lau   ipv6: Stop rt6_in...
2329
2330
2331
2332
2333
2334
2335
2336
2337
  static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from)
  {
  	BUG_ON(from->dst.from);
  
  	rt->rt6i_flags &= ~RTF_EXPIRES;
  	dst_hold(&from->dst);
  	rt->dst.from = &from->dst;
  	dst_init_metrics(&rt->dst, dst_metrics_ptr(&from->dst), true);
  }
83a09abd1   Martin KaFai Lau   ipv6: Break up ip...
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
  static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort)
  {
  	rt->dst.input = ort->dst.input;
  	rt->dst.output = ort->dst.output;
  	rt->rt6i_dst = ort->rt6i_dst;
  	rt->dst.error = ort->dst.error;
  	rt->rt6i_idev = ort->rt6i_idev;
  	if (rt->rt6i_idev)
  		in6_dev_hold(rt->rt6i_idev);
  	rt->dst.lastuse = jiffies;
  	rt->rt6i_gateway = ort->rt6i_gateway;
  	rt->rt6i_flags = ort->rt6i_flags;
  	rt6_set_from(rt, ort);
  	rt->rt6i_metric = ort->rt6i_metric;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2352
  #ifdef CONFIG_IPV6_SUBTREES
83a09abd1   Martin KaFai Lau   ipv6: Break up ip...
2353
  	rt->rt6i_src = ort->rt6i_src;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2354
  #endif
83a09abd1   Martin KaFai Lau   ipv6: Break up ip...
2355
2356
  	rt->rt6i_prefsrc = ort->rt6i_prefsrc;
  	rt->rt6i_table = ort->rt6i_table;
61adedf3e   Jiri Benc   route: move lwtun...
2357
  	rt->dst.lwtstate = lwtstate_get(ort->dst.lwtstate);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2358
  }
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
2359
  #ifdef CONFIG_IPV6_ROUTE_INFO
efa2cea0d   Daniel Lezcano   [NETNS][IPV6] rou...
2360
  static struct rt6_info *rt6_get_route_info(struct net *net,
b71d1d426   Eric Dumazet   inet: constify ip...
2361
  					   const struct in6_addr *prefix, int prefixlen,
830218c1a   David Ahern   net: ipv6: Fix pr...
2362
2363
  					   const struct in6_addr *gwaddr,
  					   struct net_device *dev)
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
2364
  {
830218c1a   David Ahern   net: ipv6: Fix pr...
2365
2366
  	u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO;
  	int ifindex = dev->ifindex;
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
2367
2368
  	struct fib6_node *fn;
  	struct rt6_info *rt = NULL;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
2369
  	struct fib6_table *table;
830218c1a   David Ahern   net: ipv6: Fix pr...
2370
  	table = fib6_get_table(net, tb_id);
383084739   David S. Miller   ipv6: Various cle...
2371
  	if (!table)
c71099acc   Thomas Graf   [IPV6]: Multiple ...
2372
  		return NULL;
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
2373

5744dd9b7   Li RongQing   ipv6: replace wri...
2374
  	read_lock_bh(&table->tb6_lock);
67ba4152e   Ian Morris   ipv6: White-space...
2375
  	fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
2376
2377
  	if (!fn)
  		goto out;
d8d1f30b9   Changli Gao   net-next: remove ...
2378
  	for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
d19185428   David S. Miller   ipv6: Kill rt6i_d...
2379
  		if (rt->dst.dev->ifindex != ifindex)
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
2380
2381
2382
2383
2384
  			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 ...
2385
  		dst_hold(&rt->dst);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
2386
2387
2388
  		break;
  	}
  out:
5744dd9b7   Li RongQing   ipv6: replace wri...
2389
  	read_unlock_bh(&table->tb6_lock);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
2390
2391
  	return rt;
  }
efa2cea0d   Daniel Lezcano   [NETNS][IPV6] rou...
2392
  static struct rt6_info *rt6_add_route_info(struct net *net,
b71d1d426   Eric Dumazet   inet: constify ip...
2393
  					   const struct in6_addr *prefix, int prefixlen,
830218c1a   David Ahern   net: ipv6: Fix pr...
2394
2395
  					   const struct in6_addr *gwaddr,
  					   struct net_device *dev,
95c961747   Eric Dumazet   net: cleanup unsi...
2396
  					   unsigned int pref)
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
2397
  {
86872cb57   Thomas Graf   [IPv6] route: FIB...
2398
  	struct fib6_config cfg = {
238fc7eac   Rami Rosen   [IPV6]: Replace u...
2399
  		.fc_metric	= IP6_RT_PRIO_USER,
830218c1a   David Ahern   net: ipv6: Fix pr...
2400
  		.fc_ifindex	= dev->ifindex,
86872cb57   Thomas Graf   [IPv6] route: FIB...
2401
2402
2403
  		.fc_dst_len	= prefixlen,
  		.fc_flags	= RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
  				  RTF_UP | RTF_PREF(pref),
b91d53292   Xin Long   ipv6: set rt6i_pr...
2404
  		.fc_protocol = RTPROT_RA,
15e473046   Eric W. Biederman   netlink: Rename p...
2405
  		.fc_nlinfo.portid = 0,
efa2cea0d   Daniel Lezcano   [NETNS][IPV6] rou...
2406
2407
  		.fc_nlinfo.nlh = NULL,
  		.fc_nlinfo.nl_net = net,
86872cb57   Thomas Graf   [IPv6] route: FIB...
2408
  	};
830218c1a   David Ahern   net: ipv6: Fix pr...
2409
  	cfg.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO,
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
2410
2411
  	cfg.fc_dst = *prefix;
  	cfg.fc_gateway = *gwaddr;
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
2412

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

333c43016   David Ahern   net: ipv6: Plumb ...
2417
  	ip6_route_add(&cfg, NULL);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
2418

830218c1a   David Ahern   net: ipv6: Fix pr...
2419
  	return rt6_get_route_info(net, prefix, prefixlen, gwaddr, dev);
70ceb4f53   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
2420
2421
  }
  #endif
b71d1d426   Eric Dumazet   inet: constify ip...
2422
  struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
2423
  {
830218c1a   David Ahern   net: ipv6: Fix pr...
2424
  	u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2425
  	struct rt6_info *rt;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
2426
  	struct fib6_table *table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2427

830218c1a   David Ahern   net: ipv6: Fix pr...
2428
  	table = fib6_get_table(dev_net(dev), tb_id);
383084739   David S. Miller   ipv6: Various cle...
2429
  	if (!table)
c71099acc   Thomas Graf   [IPV6]: Multiple ...
2430
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2431

5744dd9b7   Li RongQing   ipv6: replace wri...
2432
  	read_lock_bh(&table->tb6_lock);
67ba4152e   Ian Morris   ipv6: White-space...
2433
  	for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
d19185428   David S. Miller   ipv6: Kill rt6i_d...
2434
  		if (dev == rt->dst.dev &&
045927ff8   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Mo...
2435
  		    ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2436
2437
2438
2439
  		    ipv6_addr_equal(&rt->rt6i_gateway, addr))
  			break;
  	}
  	if (rt)
d8d1f30b9   Changli Gao   net-next: remove ...
2440
  		dst_hold(&rt->dst);
5744dd9b7   Li RongQing   ipv6: replace wri...
2441
  	read_unlock_bh(&table->tb6_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2442
2443
  	return rt;
  }
b71d1d426   Eric Dumazet   inet: constify ip...
2444
  struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
ebacaaa0f   YOSHIFUJI Hideaki   [IPV6]: ROUTE: Ad...
2445
2446
  				     struct net_device *dev,
  				     unsigned int pref)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2447
  {
86872cb57   Thomas Graf   [IPv6] route: FIB...
2448
  	struct fib6_config cfg = {
ca254490c   David Ahern   net: Add VRF supp...
2449
  		.fc_table	= l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT,
238fc7eac   Rami Rosen   [IPV6]: Replace u...
2450
  		.fc_metric	= IP6_RT_PRIO_USER,
86872cb57   Thomas Graf   [IPv6] route: FIB...
2451
2452
2453
  		.fc_ifindex	= dev->ifindex,
  		.fc_flags	= RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
  				  RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
b91d53292   Xin Long   ipv6: set rt6i_pr...
2454
  		.fc_protocol = RTPROT_RA,
15e473046   Eric W. Biederman   netlink: Rename p...
2455
  		.fc_nlinfo.portid = 0,
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
2456
  		.fc_nlinfo.nlh = NULL,
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2457
  		.fc_nlinfo.nl_net = dev_net(dev),
86872cb57   Thomas Graf   [IPv6] route: FIB...
2458
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2459

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

333c43016   David Ahern   net: ipv6: Plumb ...
2462
  	if (!ip6_route_add(&cfg, NULL)) {
830218c1a   David Ahern   net: ipv6: Fix pr...
2463
2464
2465
2466
2467
2468
  		struct fib6_table *table;
  
  		table = fib6_get_table(dev_net(dev), cfg.fc_table);
  		if (table)
  			table->flags |= RT6_TABLE_HAS_DFLT_ROUTER;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2469

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2470
2471
  	return rt6_get_dflt_router(gwaddr, dev);
  }
830218c1a   David Ahern   net: ipv6: Fix pr...
2472
  static void __rt6_purge_dflt_routers(struct fib6_table *table)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2473
2474
2475
2476
  {
  	struct rt6_info *rt;
  
  restart:
c71099acc   Thomas Graf   [IPV6]: Multiple ...
2477
  	read_lock_bh(&table->tb6_lock);
d8d1f30b9   Changli Gao   net-next: remove ...
2478
  	for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
3e8b0ac3e   Lorenzo Colitti   net: ipv6: Don't ...
2479
2480
  		if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
  		    (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) {
d8d1f30b9   Changli Gao   net-next: remove ...
2481
  			dst_hold(&rt->dst);
c71099acc   Thomas Graf   [IPV6]: Multiple ...
2482
  			read_unlock_bh(&table->tb6_lock);
e0a1ad73d   Thomas Graf   [IPv6] route: Sim...
2483
  			ip6_del_rt(rt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2484
2485
2486
  			goto restart;
  		}
  	}
c71099acc   Thomas Graf   [IPV6]: Multiple ...
2487
  	read_unlock_bh(&table->tb6_lock);
830218c1a   David Ahern   net: ipv6: Fix pr...
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
  
  	table->flags &= ~RT6_TABLE_HAS_DFLT_ROUTER;
  }
  
  void rt6_purge_dflt_routers(struct net *net)
  {
  	struct fib6_table *table;
  	struct hlist_head *head;
  	unsigned int h;
  
  	rcu_read_lock();
  
  	for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
  		head = &net->ipv6.fib_table_hash[h];
  		hlist_for_each_entry_rcu(table, head, tb6_hlist) {
  			if (table->flags & RT6_TABLE_HAS_DFLT_ROUTER)
  				__rt6_purge_dflt_routers(table);
  		}
  	}
  
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2509
  }
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
2510
2511
  static void rtmsg_to_fib6_config(struct net *net,
  				 struct in6_rtmsg *rtmsg,
86872cb57   Thomas Graf   [IPv6] route: FIB...
2512
2513
2514
  				 struct fib6_config *cfg)
  {
  	memset(cfg, 0, sizeof(*cfg));
ca254490c   David Ahern   net: Add VRF supp...
2515
2516
  	cfg->fc_table = l3mdev_fib_table_by_index(net, rtmsg->rtmsg_ifindex) ?
  			 : RT6_TABLE_MAIN;
86872cb57   Thomas Graf   [IPv6] route: FIB...
2517
2518
2519
2520
2521
2522
  	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...
2523
  	cfg->fc_nlinfo.nl_net = net;
f1243c2db   Benjamin Thery   [IPV6]: Add missi...
2524

4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
2525
2526
2527
  	cfg->fc_dst = rtmsg->rtmsg_dst;
  	cfg->fc_src = rtmsg->rtmsg_src;
  	cfg->fc_gateway = rtmsg->rtmsg_gateway;
86872cb57   Thomas Graf   [IPv6] route: FIB...
2528
  }
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
2529
  int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2530
  {
86872cb57   Thomas Graf   [IPv6] route: FIB...
2531
  	struct fib6_config cfg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2532
2533
  	struct in6_rtmsg rtmsg;
  	int err;
67ba4152e   Ian Morris   ipv6: White-space...
2534
  	switch (cmd) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2535
2536
  	case SIOCADDRT:		/* Add a route */
  	case SIOCDELRT:		/* Delete a route */
af31f412c   Eric W. Biederman   net: Allow userns...
2537
  		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2538
2539
2540
2541
2542
  			return -EPERM;
  		err = copy_from_user(&rtmsg, arg,
  				     sizeof(struct in6_rtmsg));
  		if (err)
  			return -EFAULT;
86872cb57   Thomas Graf   [IPv6] route: FIB...
2543

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2546
2547
2548
  		rtnl_lock();
  		switch (cmd) {
  		case SIOCADDRT:
333c43016   David Ahern   net: ipv6: Plumb ...
2549
  			err = ip6_route_add(&cfg, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2550
2551
  			break;
  		case SIOCDELRT:
333c43016   David Ahern   net: ipv6: Plumb ...
2552
  			err = ip6_route_del(&cfg, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2553
2554
2555
2556
2557
2558
2559
  			break;
  		default:
  			err = -EINVAL;
  		}
  		rtnl_unlock();
  
  		return err;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
2560
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2561
2562
2563
2564
2565
2566
2567
  
  	return -EINVAL;
  }
  
  /*
   *	Drop the packet on the floor
   */
d5fdd6bab   Brian Haley   ipv6: Use correct...
2568
  static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2569
  {
612f09e84   YOSHIFUJI Hideaki   [IPV6] SNMP: Fix ...
2570
  	int type;
adf30907d   Eric Dumazet   net: skb->dst acc...
2571
  	struct dst_entry *dst = skb_dst(skb);
612f09e84   YOSHIFUJI Hideaki   [IPV6] SNMP: Fix ...
2572
2573
  	switch (ipstats_mib_noroutes) {
  	case IPSTATS_MIB_INNOROUTES:
0660e03f6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
2574
  		type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
45bb00609   Ulrich Weber   ipv6: Remove IPV6...
2575
  		if (type == IPV6_ADDR_ANY) {
3bd653c84   Denis V. Lunev   netns: add net pa...
2576
2577
  			IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
  				      IPSTATS_MIB_INADDRERRORS);
612f09e84   YOSHIFUJI Hideaki   [IPV6] SNMP: Fix ...
2578
2579
2580
2581
  			break;
  		}
  		/* FALLTHROUGH */
  	case IPSTATS_MIB_OUTNOROUTES:
3bd653c84   Denis V. Lunev   netns: add net pa...
2582
2583
  		IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
  			      ipstats_mib_noroutes);
612f09e84   YOSHIFUJI Hideaki   [IPV6] SNMP: Fix ...
2584
2585
  		break;
  	}
3ffe533c8   Alexey Dobriyan   ipv6: drop unused...
2586
  	icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2587
2588
2589
  	kfree_skb(skb);
  	return 0;
  }
9ce8ade01   Thomas Graf   [IPv6] route: Fix...
2590
2591
  static int ip6_pkt_discard(struct sk_buff *skb)
  {
612f09e84   YOSHIFUJI Hideaki   [IPV6] SNMP: Fix ...
2592
  	return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
9ce8ade01   Thomas Graf   [IPv6] route: Fix...
2593
  }
ede2059db   Eric W. Biederman   dst: Pass net int...
2594
  static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2595
  {
adf30907d   Eric Dumazet   net: skb->dst acc...
2596
  	skb->dev = skb_dst(skb)->dev;
612f09e84   YOSHIFUJI Hideaki   [IPV6] SNMP: Fix ...
2597
  	return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2598
  }
9ce8ade01   Thomas Graf   [IPv6] route: Fix...
2599
2600
  static int ip6_pkt_prohibit(struct sk_buff *skb)
  {
612f09e84   YOSHIFUJI Hideaki   [IPV6] SNMP: Fix ...
2601
  	return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
9ce8ade01   Thomas Graf   [IPv6] route: Fix...
2602
  }
ede2059db   Eric W. Biederman   dst: Pass net int...
2603
  static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb)
9ce8ade01   Thomas Graf   [IPv6] route: Fix...
2604
  {
adf30907d   Eric Dumazet   net: skb->dst acc...
2605
  	skb->dev = skb_dst(skb)->dev;
612f09e84   YOSHIFUJI Hideaki   [IPV6] SNMP: Fix ...
2606
  	return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
9ce8ade01   Thomas Graf   [IPv6] route: Fix...
2607
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2608
2609
2610
2611
2612
2613
  /*
   *	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 ...
2614
  				    bool anycast)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2615
  {
ca254490c   David Ahern   net: Add VRF supp...
2616
  	u32 tb_id;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2617
  	struct net *net = dev_net(idev->dev);
4832c30d5   David Ahern   net: ipv6: put ho...
2618
  	struct net_device *dev = idev->dev;
5f02ce24c   David Ahern   net: l3mdev: Allo...
2619
  	struct rt6_info *rt;
5f02ce24c   David Ahern   net: l3mdev: Allo...
2620
  	rt = ip6_dst_alloc(net, dev, DST_NOCOUNT);
a3300ef4b   Hannes Frederic Sowa   ipv6: don't count...
2621
  	if (!rt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2622
  		return ERR_PTR(-ENOMEM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2623
  	in6_dev_hold(idev);
11d53b499   David S. Miller   ipv6: Don't chang...
2624
  	rt->dst.flags |= DST_HOST;
d8d1f30b9   Changli Gao   net-next: remove ...
2625
2626
  	rt->dst.input = ip6_input;
  	rt->dst.output = ip6_output;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2627
  	rt->rt6i_idev = idev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2628

94b5e0f97   David Ahern   net: ipv6: Set pr...
2629
  	rt->rt6i_protocol = RTPROT_KERNEL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2630
  	rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
58c4fb86e   YOSHIFUJI Hideaki   [IPV6]: Flag RTF_...
2631
2632
2633
  	if (anycast)
  		rt->rt6i_flags |= RTF_ANYCAST;
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2634
  		rt->rt6i_flags |= RTF_LOCAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2635

550bab42f   Julian Anastasov   ipv6: fill rt6i_g...
2636
  	rt->rt6i_gateway  = *addr;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
2637
  	rt->rt6i_dst.addr = *addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2638
  	rt->rt6i_dst.plen = 128;
ca254490c   David Ahern   net: Add VRF supp...
2639
2640
  	tb_id = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL;
  	rt->rt6i_table = fib6_get_table(net, tb_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2641

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2642
2643
  	return rt;
  }
c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
  /* 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...
2656
  	if (((void *)rt->dst.dev == dev || !dev) &&
c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
  	    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,
  	};
0c3584d58   Li RongQing   ipv6: remove prun...
2673
  	fib6_clean_all(net, fib6_remove_prefsrc, &adni);
c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
2674
  }
be7a010d6   Duan Jiong   ipv6: update Dest...
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
  #define RTF_RA_ROUTER		(RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY)
  #define RTF_CACHE_GATEWAY	(RTF_GATEWAY | RTF_CACHE)
  
  /* Remove routers and update dst entries when gateway turn into host. */
  static int fib6_clean_tohost(struct rt6_info *rt, void *arg)
  {
  	struct in6_addr *gateway = (struct in6_addr *)arg;
  
  	if ((((rt->rt6i_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) ||
  	     ((rt->rt6i_flags & RTF_CACHE_GATEWAY) == RTF_CACHE_GATEWAY)) &&
  	     ipv6_addr_equal(gateway, &rt->rt6i_gateway)) {
  		return -1;
  	}
  	return 0;
  }
  
  void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
  {
  	fib6_clean_all(net, fib6_clean_tohost, gateway);
  }
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2695
2696
2697
2698
  struct arg_dev_net {
  	struct net_device *dev;
  	struct net *net;
  };
a1a22c120   David Ahern   net: ipv6: Keep n...
2699
  /* called with write lock held for table with rt */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2700
2701
  static int fib6_ifdown(struct rt6_info *rt, void *arg)
  {
bc3ef6605   stephen hemminger   ipv6: fib6_ifdown...
2702
2703
  	const struct arg_dev_net *adn = arg;
  	const struct net_device *dev = adn->dev;
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2704

d19185428   David S. Miller   ipv6: Kill rt6i_d...
2705
  	if ((rt->dst.dev == dev || !dev) &&
a1a22c120   David Ahern   net: ipv6: Keep n...
2706
2707
  	    rt != adn->net->ipv6.ip6_null_entry &&
  	    (rt->rt6i_nsiblings == 0 ||
8397ed36b   David Ahern   net: ipv6: Releas...
2708
  	     (dev && netdev_unregistering(dev)) ||
a1a22c120   David Ahern   net: ipv6: Keep n...
2709
  	     !rt->rt6i_idev->cnf.ignore_routes_with_linkdown))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2710
  		return -1;
c159d30c5   David S. Miller   ipv6: Kill useles...
2711

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2712
2713
  	return 0;
  }
f3db48517   Daniel Lezcano   [NETNS][IPV6] ip6...
2714
  void rt6_ifdown(struct net *net, struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2715
  {
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
2716
2717
2718
2719
  	struct arg_dev_net adn = {
  		.dev = dev,
  		.net = net,
  	};
0c3584d58   Li RongQing   ipv6: remove prun...
2720
  	fib6_clean_all(net, fib6_ifdown, &adn);
e332bc67c   Eric W. Biederman   ipv6: Don't call ...
2721
2722
  	if (dev)
  		rt6_uncached_list_flush_dev(net, dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2723
  }
95c961747   Eric Dumazet   net: cleanup unsi...
2724
  struct rt6_mtu_change_arg {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2725
  	struct net_device *dev;
95c961747   Eric Dumazet   net: cleanup unsi...
2726
  	unsigned int mtu;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
  };
  
  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...
2741
  	if (!idev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
  		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
67c408cfa   Alexander Alemayhu   ipv6: fix typos
2756
  	   PMTU discovery.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2757
  	 */
d19185428   David S. Miller   ipv6: Kill rt6i_d...
2758
  	if (rt->dst.dev == arg->dev &&
fb56be83e   Maciej Żenczykowski   net-ipv6: on devi...
2759
  	    dst_metric_raw(&rt->dst, RTAX_MTU) &&
4b32b5ad3   Martin KaFai Lau   ipv6: Stop rt6_in...
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
  	    !dst_metric_locked(&rt->dst, RTAX_MTU)) {
  		if (rt->rt6i_flags & RTF_CACHE) {
  			/* For RTF_CACHE with rt6i_pmtu == 0
  			 * (i.e. a redirected route),
  			 * the metrics of its rt->dst.from has already
  			 * been updated.
  			 */
  			if (rt->rt6i_pmtu && rt->rt6i_pmtu > arg->mtu)
  				rt->rt6i_pmtu = arg->mtu;
  		} else if (dst_mtu(&rt->dst) >= arg->mtu ||
  			   (dst_mtu(&rt->dst) < arg->mtu &&
  			    dst_mtu(&rt->dst) == idev->cnf.mtu6)) {
  			dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu);
  		}
566cfd8f0   Simon Arlott   [IPV6]: Don't upd...
2774
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2775
2776
  	return 0;
  }
95c961747   Eric Dumazet   net: cleanup unsi...
2777
  void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2778
  {
c71099acc   Thomas Graf   [IPV6]: Multiple ...
2779
2780
2781
2782
  	struct rt6_mtu_change_arg arg = {
  		.dev = dev,
  		.mtu = mtu,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2783

0c3584d58   Li RongQing   ipv6: remove prun...
2784
  	fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2785
  }
ef7c79ed6   Patrick McHardy   [NETLINK]: Mark n...
2786
  static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
5176f91ea   Thomas Graf   [NETLINK]: Make u...
2787
  	[RTA_GATEWAY]           = { .len = sizeof(struct in6_addr) },
8d34c6773   Eric Dumazet   ipv6: add RTA_TAB...
2788
  	[RTA_PREFSRC]		= { .len = sizeof(struct in6_addr) },
86872cb57   Thomas Graf   [IPv6] route: FIB...
2789
  	[RTA_OIF]               = { .type = NLA_U32 },
ab364a6f9   Thomas Graf   [IPv6] route: Con...
2790
  	[RTA_IIF]		= { .type = NLA_U32 },
86872cb57   Thomas Graf   [IPv6] route: FIB...
2791
2792
  	[RTA_PRIORITY]          = { .type = NLA_U32 },
  	[RTA_METRICS]           = { .type = NLA_NESTED },
51ebd3181   Nicolas Dichtel   ipv6: add support...
2793
  	[RTA_MULTIPATH]		= { .len = sizeof(struct rtnexthop) },
c78ba6d64   Lubomir Rintel   ipv6: expose RFC4...
2794
  	[RTA_PREF]              = { .type = NLA_U8 },
19e42e451   Roopa Prabhu   ipv6: support for...
2795
2796
  	[RTA_ENCAP_TYPE]	= { .type = NLA_U16 },
  	[RTA_ENCAP]		= { .type = NLA_NESTED },
32bc201e1   Xin Long   ipv6: allow route...
2797
  	[RTA_EXPIRES]		= { .type = NLA_U32 },
622ec2c9d   Lorenzo Colitti   net: core: add UI...
2798
  	[RTA_UID]		= { .type = NLA_U32 },
3b45a4106   Liping Zhang   net: route: add m...
2799
  	[RTA_MARK]		= { .type = NLA_U32 },
8d34c6773   Eric Dumazet   ipv6: add RTA_TAB...
2800
  	[RTA_TABLE]		= { .type = NLA_U32 },
86872cb57   Thomas Graf   [IPv6] route: FIB...
2801
2802
2803
  };
  
  static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
333c43016   David Ahern   net: ipv6: Plumb ...
2804
2805
  			      struct fib6_config *cfg,
  			      struct netlink_ext_ack *extack)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2806
  {
86872cb57   Thomas Graf   [IPv6] route: FIB...
2807
2808
  	struct rtmsg *rtm;
  	struct nlattr *tb[RTA_MAX+1];
c78ba6d64   Lubomir Rintel   ipv6: expose RFC4...
2809
  	unsigned int pref;
86872cb57   Thomas Graf   [IPv6] route: FIB...
2810
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2811

fceb6435e   Johannes Berg   netlink: pass ext...
2812
2813
  	err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
  			  NULL);
86872cb57   Thomas Graf   [IPv6] route: FIB...
2814
2815
  	if (err < 0)
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2816

86872cb57   Thomas Graf   [IPv6] route: FIB...
2817
2818
2819
2820
2821
2822
2823
2824
2825
  	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;
ef2c7d7b5   Nicolas Dichtel   ipv6: fix handlin...
2826
  	cfg->fc_type = rtm->rtm_type;
86872cb57   Thomas Graf   [IPv6] route: FIB...
2827

ef2c7d7b5   Nicolas Dichtel   ipv6: fix handlin...
2828
2829
  	if (rtm->rtm_type == RTN_UNREACHABLE ||
  	    rtm->rtm_type == RTN_BLACKHOLE ||
b4949ab26   Nicolas Dichtel   ipv6: fix handlin...
2830
2831
  	    rtm->rtm_type == RTN_PROHIBIT ||
  	    rtm->rtm_type == RTN_THROW)
86872cb57   Thomas Graf   [IPv6] route: FIB...
2832
  		cfg->fc_flags |= RTF_REJECT;
ab79ad14a   Maciej Żenczykowski   ipv6: Implement A...
2833
2834
  	if (rtm->rtm_type == RTN_LOCAL)
  		cfg->fc_flags |= RTF_LOCAL;
1f56a01f4   Martin KaFai Lau   ipv6: Consider RT...
2835
2836
  	if (rtm->rtm_flags & RTM_F_CLONED)
  		cfg->fc_flags |= RTF_CACHE;
15e473046   Eric W. Biederman   netlink: Rename p...
2837
  	cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
86872cb57   Thomas Graf   [IPv6] route: FIB...
2838
  	cfg->fc_nlinfo.nlh = nlh;
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2839
  	cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
86872cb57   Thomas Graf   [IPv6] route: FIB...
2840
2841
  
  	if (tb[RTA_GATEWAY]) {
67b61f6c1   Jiri Benc   netlink: implemen...
2842
  		cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
86872cb57   Thomas Graf   [IPv6] route: FIB...
2843
  		cfg->fc_flags |= RTF_GATEWAY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2844
  	}
86872cb57   Thomas Graf   [IPv6] route: FIB...
2845
2846
2847
2848
2849
2850
2851
2852
  
  	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
2853
  	}
86872cb57   Thomas Graf   [IPv6] route: FIB...
2854
2855
2856
2857
2858
2859
2860
2861
  
  	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
2862
  	}
86872cb57   Thomas Graf   [IPv6] route: FIB...
2863

c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
2864
  	if (tb[RTA_PREFSRC])
67b61f6c1   Jiri Benc   netlink: implemen...
2865
  		cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]);
c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
2866

86872cb57   Thomas Graf   [IPv6] route: FIB...
2867
2868
2869
2870
2871
2872
2873
2874
2875
  	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
2876
  	}
86872cb57   Thomas Graf   [IPv6] route: FIB...
2877
2878
2879
  
  	if (tb[RTA_TABLE])
  		cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
51ebd3181   Nicolas Dichtel   ipv6: add support...
2880
2881
2882
  	if (tb[RTA_MULTIPATH]) {
  		cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
  		cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
9ed59592e   David Ahern   lwtunnel: fix aut...
2883
2884
  
  		err = lwtunnel_valid_encap_type_attr(cfg->fc_mp,
c255bd681   David Ahern   net: lwtunnel: Ad...
2885
  						     cfg->fc_mp_len, extack);
9ed59592e   David Ahern   lwtunnel: fix aut...
2886
2887
  		if (err < 0)
  			goto errout;
51ebd3181   Nicolas Dichtel   ipv6: add support...
2888
  	}
c78ba6d64   Lubomir Rintel   ipv6: expose RFC4...
2889
2890
2891
2892
2893
2894
2895
  	if (tb[RTA_PREF]) {
  		pref = nla_get_u8(tb[RTA_PREF]);
  		if (pref != ICMPV6_ROUTER_PREF_LOW &&
  		    pref != ICMPV6_ROUTER_PREF_HIGH)
  			pref = ICMPV6_ROUTER_PREF_MEDIUM;
  		cfg->fc_flags |= RTF_PREF(pref);
  	}
19e42e451   Roopa Prabhu   ipv6: support for...
2896
2897
  	if (tb[RTA_ENCAP])
  		cfg->fc_encap = tb[RTA_ENCAP];
9ed59592e   David Ahern   lwtunnel: fix aut...
2898
  	if (tb[RTA_ENCAP_TYPE]) {
19e42e451   Roopa Prabhu   ipv6: support for...
2899
  		cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]);
c255bd681   David Ahern   net: lwtunnel: Ad...
2900
  		err = lwtunnel_valid_encap_type(cfg->fc_encap_type, extack);
9ed59592e   David Ahern   lwtunnel: fix aut...
2901
2902
2903
  		if (err < 0)
  			goto errout;
  	}
32bc201e1   Xin Long   ipv6: allow route...
2904
2905
2906
2907
2908
2909
2910
2911
  	if (tb[RTA_EXPIRES]) {
  		unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ);
  
  		if (addrconf_finite_timeout(timeout)) {
  			cfg->fc_expires = jiffies_to_clock_t(timeout * HZ);
  			cfg->fc_flags |= RTF_EXPIRES;
  		}
  	}
86872cb57   Thomas Graf   [IPv6] route: FIB...
2912
2913
2914
  	err = 0;
  errout:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2915
  }
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
  struct rt6_nh {
  	struct rt6_info *rt6_info;
  	struct fib6_config r_cfg;
  	struct mx6_config mxc;
  	struct list_head next;
  };
  
  static void ip6_print_replace_route_err(struct list_head *rt6_nh_list)
  {
  	struct rt6_nh *nh;
  
  	list_for_each_entry(nh, rt6_nh_list, next) {
7d4d5065e   David Ahern   net: ipv6: Use co...
2928
2929
  		pr_warn("IPV6: multipath route replace failed (check consistency of installed routes): %pI6c nexthop %pI6c ifi %d
  ",
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
2930
2931
2932
2933
2934
2935
2936
2937
2938
  		        &nh->r_cfg.fc_dst, &nh->r_cfg.fc_gateway,
  		        nh->r_cfg.fc_ifindex);
  	}
  }
  
  static int ip6_route_info_append(struct list_head *rt6_nh_list,
  				 struct rt6_info *rt, struct fib6_config *r_cfg)
  {
  	struct rt6_nh *nh;
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
2939
2940
2941
2942
  	int err = -EEXIST;
  
  	list_for_each_entry(nh, rt6_nh_list, next) {
  		/* check if rt6_info already exists */
f06b7549b   David Ahern   net: ipv6: Compar...
2943
  		if (rt6_duplicate_nexthop(nh->rt6_info, rt))
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
  			return err;
  	}
  
  	nh = kzalloc(sizeof(*nh), GFP_KERNEL);
  	if (!nh)
  		return -ENOMEM;
  	nh->rt6_info = rt;
  	err = ip6_convert_metrics(&nh->mxc, r_cfg);
  	if (err) {
  		kfree(nh);
  		return err;
  	}
  	memcpy(&nh->r_cfg, r_cfg, sizeof(*r_cfg));
  	list_add_tail(&nh->next, rt6_nh_list);
  
  	return 0;
  }
3b1137fe7   David Ahern   net: ipv6: Change...
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
  static void ip6_route_mpath_notify(struct rt6_info *rt,
  				   struct rt6_info *rt_last,
  				   struct nl_info *info,
  				   __u16 nlflags)
  {
  	/* if this is an APPEND route, then rt points to the first route
  	 * inserted and rt_last points to last route inserted. Userspace
  	 * wants a consistent dump of the route which starts at the first
  	 * nexthop. Since sibling routes are always added at the end of
  	 * the list, find the first sibling of the last route appended
  	 */
  	if ((nlflags & NLM_F_APPEND) && rt_last && rt_last->rt6i_nsiblings) {
  		rt = list_first_entry(&rt_last->rt6i_siblings,
  				      struct rt6_info,
  				      rt6i_siblings);
  	}
  
  	if (rt)
  		inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
  }
333c43016   David Ahern   net: ipv6: Plumb ...
2981
2982
  static int ip6_route_multipath_add(struct fib6_config *cfg,
  				   struct netlink_ext_ack *extack)
51ebd3181   Nicolas Dichtel   ipv6: add support...
2983
  {
3b1137fe7   David Ahern   net: ipv6: Change...
2984
2985
  	struct rt6_info *rt_notif = NULL, *rt_last = NULL;
  	struct nl_info *info = &cfg->fc_nlinfo;
51ebd3181   Nicolas Dichtel   ipv6: add support...
2986
2987
  	struct fib6_config r_cfg;
  	struct rtnexthop *rtnh;
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
2988
2989
2990
  	struct rt6_info *rt;
  	struct rt6_nh *err_nh;
  	struct rt6_nh *nh, *nh_safe;
3b1137fe7   David Ahern   net: ipv6: Change...
2991
  	__u16 nlflags;
51ebd3181   Nicolas Dichtel   ipv6: add support...
2992
2993
  	int remaining;
  	int attrlen;
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
2994
2995
2996
2997
2998
  	int err = 1;
  	int nhn = 0;
  	int replace = (cfg->fc_nlinfo.nlh &&
  		       (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE));
  	LIST_HEAD(rt6_nh_list);
51ebd3181   Nicolas Dichtel   ipv6: add support...
2999

3b1137fe7   David Ahern   net: ipv6: Change...
3000
3001
3002
  	nlflags = replace ? NLM_F_REPLACE : NLM_F_CREATE;
  	if (info->nlh && info->nlh->nlmsg_flags & NLM_F_APPEND)
  		nlflags |= NLM_F_APPEND;
35f1b4e96   Michal Kubeček   ipv6: do not dele...
3003
  	remaining = cfg->fc_mp_len;
51ebd3181   Nicolas Dichtel   ipv6: add support...
3004
  	rtnh = (struct rtnexthop *)cfg->fc_mp;
51ebd3181   Nicolas Dichtel   ipv6: add support...
3005

6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
3006
3007
3008
  	/* Parse a Multipath Entry and build a list (rt6_nh_list) of
  	 * rt6_info structs per nexthop
  	 */
51ebd3181   Nicolas Dichtel   ipv6: add support...
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
  	while (rtnh_ok(rtnh, remaining)) {
  		memcpy(&r_cfg, cfg, sizeof(*cfg));
  		if (rtnh->rtnh_ifindex)
  			r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
  
  		attrlen = rtnh_attrlen(rtnh);
  		if (attrlen > 0) {
  			struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
  
  			nla = nla_find(attrs, attrlen, RTA_GATEWAY);
  			if (nla) {
67b61f6c1   Jiri Benc   netlink: implemen...
3020
  				r_cfg.fc_gateway = nla_get_in6_addr(nla);
51ebd3181   Nicolas Dichtel   ipv6: add support...
3021
3022
  				r_cfg.fc_flags |= RTF_GATEWAY;
  			}
19e42e451   Roopa Prabhu   ipv6: support for...
3023
3024
3025
3026
  			r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
  			nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
  			if (nla)
  				r_cfg.fc_encap_type = nla_get_u16(nla);
51ebd3181   Nicolas Dichtel   ipv6: add support...
3027
  		}
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
3028

333c43016   David Ahern   net: ipv6: Plumb ...
3029
  		rt = ip6_route_info_create(&r_cfg, extack);
8c5b83f0f   Roopa Prabhu   ipv6 route: use e...
3030
3031
3032
  		if (IS_ERR(rt)) {
  			err = PTR_ERR(rt);
  			rt = NULL;
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
3033
  			goto cleanup;
8c5b83f0f   Roopa Prabhu   ipv6 route: use e...
3034
  		}
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
3035
3036
  
  		err = ip6_route_info_append(&rt6_nh_list, rt, &r_cfg);
51ebd3181   Nicolas Dichtel   ipv6: add support...
3037
  		if (err) {
587fea741   Wei Wang   ipv6: mark DST_NO...
3038
  			dst_release_immediate(&rt->dst);
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
3039
3040
3041
3042
3043
  			goto cleanup;
  		}
  
  		rtnh = rtnh_next(rtnh, &remaining);
  	}
3b1137fe7   David Ahern   net: ipv6: Change...
3044
3045
3046
3047
3048
  	/* for add and replace send one notification with all nexthops.
  	 * Skip the notification in fib6_add_rt2node and send one with
  	 * the full route when done
  	 */
  	info->skip_notify = 1;
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
3049
3050
  	err_nh = NULL;
  	list_for_each_entry(nh, &rt6_nh_list, next) {
333c43016   David Ahern   net: ipv6: Plumb ...
3051
  		err = __ip6_ins_rt(nh->rt6_info, info, &nh->mxc, extack);
57d6f87ac   David Ahern   net/ipv6: prevent...
3052
3053
3054
3055
3056
3057
3058
3059
3060
  
  		if (!err) {
  			/* save reference to last route successfully inserted */
  			rt_last = nh->rt6_info;
  
  			/* save reference to first route for notification */
  			if (!rt_notif)
  				rt_notif = nh->rt6_info;
  		}
3b1137fe7   David Ahern   net: ipv6: Change...
3061

6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
3062
3063
3064
3065
3066
3067
3068
  		/* nh->rt6_info is used or freed at this point, reset to NULL*/
  		nh->rt6_info = NULL;
  		if (err) {
  			if (replace && nhn)
  				ip6_print_replace_route_err(&rt6_nh_list);
  			err_nh = nh;
  			goto add_errout;
51ebd3181   Nicolas Dichtel   ipv6: add support...
3069
  		}
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
3070

1a72418bd   Nicolas Dichtel   ipv6/multipath: r...
3071
  		/* Because each route is added like a single route we remove
275964724   Michal Kubeček   ipv6: fix ECMP ro...
3072
3073
3074
3075
3076
  		 * these flags after the first nexthop: if there is a collision,
  		 * we have already failed to add the first nexthop:
  		 * fib6_add_rt2node() has rejected it; when replacing, old
  		 * nexthops have been replaced by first new, the rest should
  		 * be added to it.
1a72418bd   Nicolas Dichtel   ipv6/multipath: r...
3077
  		 */
275964724   Michal Kubeček   ipv6: fix ECMP ro...
3078
3079
  		cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
  						     NLM_F_REPLACE);
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
3080
3081
  		nhn++;
  	}
3b1137fe7   David Ahern   net: ipv6: Change...
3082
3083
  	/* success ... tell user about new route */
  	ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
3084
3085
3086
  	goto cleanup;
  
  add_errout:
3b1137fe7   David Ahern   net: ipv6: Change...
3087
3088
3089
3090
3091
3092
  	/* send notification for routes that were added so that
  	 * the delete notifications sent by ip6_route_del are
  	 * coherent
  	 */
  	if (rt_notif)
  		ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
3093
3094
3095
3096
  	/* Delete routes that were already added */
  	list_for_each_entry(nh, &rt6_nh_list, next) {
  		if (err_nh == nh)
  			break;
333c43016   David Ahern   net: ipv6: Plumb ...
3097
  		ip6_route_del(&nh->r_cfg, extack);
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
3098
3099
3100
3101
  	}
  
  cleanup:
  	list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) {
587fea741   Wei Wang   ipv6: mark DST_NO...
3102
3103
  		if (nh->rt6_info)
  			dst_release_immediate(&nh->rt6_info->dst);
52fe51f85   Wu Fengguang   ipv6: fix ifnullf...
3104
  		kfree(nh->mxc.mx);
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
3105
3106
3107
3108
3109
3110
  		list_del(&nh->next);
  		kfree(nh);
  	}
  
  	return err;
  }
333c43016   David Ahern   net: ipv6: Plumb ...
3111
3112
  static int ip6_route_multipath_del(struct fib6_config *cfg,
  				   struct netlink_ext_ack *extack)
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
  {
  	struct fib6_config r_cfg;
  	struct rtnexthop *rtnh;
  	int remaining;
  	int attrlen;
  	int err = 1, last_err = 0;
  
  	remaining = cfg->fc_mp_len;
  	rtnh = (struct rtnexthop *)cfg->fc_mp;
  
  	/* Parse a Multipath Entry */
  	while (rtnh_ok(rtnh, remaining)) {
  		memcpy(&r_cfg, cfg, sizeof(*cfg));
  		if (rtnh->rtnh_ifindex)
  			r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
  
  		attrlen = rtnh_attrlen(rtnh);
  		if (attrlen > 0) {
  			struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
  
  			nla = nla_find(attrs, attrlen, RTA_GATEWAY);
  			if (nla) {
  				nla_memcpy(&r_cfg.fc_gateway, nla, 16);
  				r_cfg.fc_flags |= RTF_GATEWAY;
  			}
  		}
333c43016   David Ahern   net: ipv6: Plumb ...
3139
  		err = ip6_route_del(&r_cfg, extack);
6b9ea5a64   Roopa Prabhu   ipv6: fix multipa...
3140
3141
  		if (err)
  			last_err = err;
51ebd3181   Nicolas Dichtel   ipv6: add support...
3142
3143
3144
3145
3146
  		rtnh = rtnh_next(rtnh, &remaining);
  	}
  
  	return last_err;
  }
c21ef3e34   David Ahern   net: rtnetlink: p...
3147
3148
  static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
  			      struct netlink_ext_ack *extack)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3149
  {
86872cb57   Thomas Graf   [IPv6] route: FIB...
3150
3151
  	struct fib6_config cfg;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3152

333c43016   David Ahern   net: ipv6: Plumb ...
3153
  	err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
86872cb57   Thomas Graf   [IPv6] route: FIB...
3154
3155
  	if (err < 0)
  		return err;
51ebd3181   Nicolas Dichtel   ipv6: add support...
3156
  	if (cfg.fc_mp)
333c43016   David Ahern   net: ipv6: Plumb ...
3157
  		return ip6_route_multipath_del(&cfg, extack);
0ae813358   David Ahern   net: ipv6: Allow ...
3158
3159
  	else {
  		cfg.fc_delete_all_nh = 1;
333c43016   David Ahern   net: ipv6: Plumb ...
3160
  		return ip6_route_del(&cfg, extack);
0ae813358   David Ahern   net: ipv6: Allow ...
3161
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3162
  }
c21ef3e34   David Ahern   net: rtnetlink: p...
3163
3164
  static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
  			      struct netlink_ext_ack *extack)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3165
  {
86872cb57   Thomas Graf   [IPv6] route: FIB...
3166
3167
  	struct fib6_config cfg;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3168

333c43016   David Ahern   net: ipv6: Plumb ...
3169
  	err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
86872cb57   Thomas Graf   [IPv6] route: FIB...
3170
3171
  	if (err < 0)
  		return err;
51ebd3181   Nicolas Dichtel   ipv6: add support...
3172
  	if (cfg.fc_mp)
333c43016   David Ahern   net: ipv6: Plumb ...
3173
  		return ip6_route_multipath_add(&cfg, extack);
51ebd3181   Nicolas Dichtel   ipv6: add support...
3174
  	else
333c43016   David Ahern   net: ipv6: Plumb ...
3175
  		return ip6_route_add(&cfg, extack);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3176
  }
beb1afac5   David Ahern   net: ipv6: Add su...
3177
  static size_t rt6_nlmsg_size(struct rt6_info *rt)
339bf98ff   Thomas Graf   [NETLINK]: Do pre...
3178
  {
beb1afac5   David Ahern   net: ipv6: Add su...
3179
3180
3181
3182
3183
3184
  	int nexthop_len = 0;
  
  	if (rt->rt6i_nsiblings) {
  		nexthop_len = nla_total_size(0)	 /* RTA_MULTIPATH */
  			    + NLA_ALIGN(sizeof(struct rtnexthop))
  			    + nla_total_size(16) /* RTA_GATEWAY */
beb1afac5   David Ahern   net: ipv6: Add su...
3185
3186
3187
3188
  			    + lwtunnel_get_encap_size(rt->dst.lwtstate);
  
  		nexthop_len *= rt->rt6i_nsiblings;
  	}
339bf98ff   Thomas Graf   [NETLINK]: Do pre...
3189
3190
3191
3192
3193
3194
3195
3196
3197
  	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...
3198
  	       + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
ea6976399   Daniel Borkmann   net: tcp: add RTA...
3199
  	       + nla_total_size(sizeof(struct rta_cacheinfo))
c78ba6d64   Lubomir Rintel   ipv6: expose RFC4...
3200
  	       + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
19e42e451   Roopa Prabhu   ipv6: support for...
3201
  	       + nla_total_size(1) /* RTA_PREF */
beb1afac5   David Ahern   net: ipv6: Add su...
3202
3203
3204
3205
3206
  	       + lwtunnel_get_encap_size(rt->dst.lwtstate)
  	       + nexthop_len;
  }
  
  static int rt6_nexthop_info(struct sk_buff *skb, struct rt6_info *rt,
5be083ced   David Ahern   net: ipv6: Remove...
3207
  			    unsigned int *flags, bool skip_oif)
beb1afac5   David Ahern   net: ipv6: Add su...
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
  {
  	if (!netif_running(rt->dst.dev) || !netif_carrier_ok(rt->dst.dev)) {
  		*flags |= RTNH_F_LINKDOWN;
  		if (rt->rt6i_idev->cnf.ignore_routes_with_linkdown)
  			*flags |= RTNH_F_DEAD;
  	}
  
  	if (rt->rt6i_flags & RTF_GATEWAY) {
  		if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->rt6i_gateway) < 0)
  			goto nla_put_failure;
  	}
fe4007999   Ido Schimmel   ipv6: fib: Provid...
3219
  	if (rt->rt6i_nh_flags & RTNH_F_OFFLOAD)
61e4d01e1   Ido Schimmel   ipv6: fib: Add of...
3220
  		*flags |= RTNH_F_OFFLOAD;
5be083ced   David Ahern   net: ipv6: Remove...
3221
3222
  	/* not needed for multipath encoding b/c it has a rtnexthop struct */
  	if (!skip_oif && rt->dst.dev &&
beb1afac5   David Ahern   net: ipv6: Add su...
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
  	    nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex))
  		goto nla_put_failure;
  
  	if (rt->dst.lwtstate &&
  	    lwtunnel_fill_encap(skb, rt->dst.lwtstate) < 0)
  		goto nla_put_failure;
  
  	return 0;
  
  nla_put_failure:
  	return -EMSGSIZE;
  }
5be083ced   David Ahern   net: ipv6: Remove...
3235
  /* add multipath next hop */
beb1afac5   David Ahern   net: ipv6: Add su...
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
  static int rt6_add_nexthop(struct sk_buff *skb, struct rt6_info *rt)
  {
  	struct rtnexthop *rtnh;
  	unsigned int flags = 0;
  
  	rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh));
  	if (!rtnh)
  		goto nla_put_failure;
  
  	rtnh->rtnh_hops = 0;
  	rtnh->rtnh_ifindex = rt->dst.dev ? rt->dst.dev->ifindex : 0;
5be083ced   David Ahern   net: ipv6: Remove...
3247
  	if (rt6_nexthop_info(skb, rt, &flags, true) < 0)
beb1afac5   David Ahern   net: ipv6: Add su...
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
  		goto nla_put_failure;
  
  	rtnh->rtnh_flags = flags;
  
  	/* length of rtnetlink header + attributes */
  	rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *)rtnh;
  
  	return 0;
  
  nla_put_failure:
  	return -EMSGSIZE;
339bf98ff   Thomas Graf   [NETLINK]: Do pre...
3259
  }
191cd5825   Brian Haley   netns: Add networ...
3260
3261
  static int rt6_fill_node(struct net *net,
  			 struct sk_buff *skb, struct rt6_info *rt,
0d51aa80a   Jamal Hadi Salim   [IPV6]: V6 route ...
3262
  			 struct in6_addr *dst, struct in6_addr *src,
15e473046   Eric W. Biederman   netlink: Rename p...
3263
  			 int iif, int type, u32 portid, u32 seq,
f8cfe2ceb   David Ahern   net: ipv6: remove...
3264
  			 unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3265
  {
4b32b5ad3   Martin KaFai Lau   ipv6: Stop rt6_in...
3266
  	u32 metrics[RTAX_MAX];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3267
  	struct rtmsg *rtm;
2d7202bfd   Thomas Graf   [IPv6] route: Con...
3268
  	struct nlmsghdr *nlh;
e3703b3de   Thomas Graf   [RTNETLINK]: Add ...
3269
  	long expires;
9e762a4a8   Patrick McHardy   [NET]: Introduce ...
3270
  	u32 table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3271

15e473046   Eric W. Biederman   netlink: Rename p...
3272
  	nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
383084739   David S. Miller   ipv6: Various cle...
3273
  	if (!nlh)
26932566a   Patrick McHardy   [NETLINK]: Don't ...
3274
  		return -EMSGSIZE;
2d7202bfd   Thomas Graf   [IPv6] route: Con...
3275
3276
  
  	rtm = nlmsg_data(nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3277
3278
3279
3280
  	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 ...
3281
  	if (rt->rt6i_table)
9e762a4a8   Patrick McHardy   [NET]: Introduce ...
3282
  		table = rt->rt6i_table->tb6_id;
c71099acc   Thomas Graf   [IPV6]: Multiple ...
3283
  	else
9e762a4a8   Patrick McHardy   [NET]: Introduce ...
3284
3285
  		table = RT6_TABLE_UNSPEC;
  	rtm->rtm_table = table;
c78679e8f   David S. Miller   ipv6: Stop using ...
3286
3287
  	if (nla_put_u32(skb, RTA_TABLE, table))
  		goto nla_put_failure;
ef2c7d7b5   Nicolas Dichtel   ipv6: fix handlin...
3288
3289
3290
3291
3292
3293
3294
3295
  	if (rt->rt6i_flags & RTF_REJECT) {
  		switch (rt->dst.error) {
  		case -EINVAL:
  			rtm->rtm_type = RTN_BLACKHOLE;
  			break;
  		case -EACCES:
  			rtm->rtm_type = RTN_PROHIBIT;
  			break;
b4949ab26   Nicolas Dichtel   ipv6: fix handlin...
3296
3297
3298
  		case -EAGAIN:
  			rtm->rtm_type = RTN_THROW;
  			break;
ef2c7d7b5   Nicolas Dichtel   ipv6: fix handlin...
3299
3300
3301
3302
3303
  		default:
  			rtm->rtm_type = RTN_UNREACHABLE;
  			break;
  		}
  	}
383084739   David S. Miller   ipv6: Various cle...
3304
  	else if (rt->rt6i_flags & RTF_LOCAL)
ab79ad14a   Maciej Żenczykowski   ipv6: Implement A...
3305
  		rtm->rtm_type = RTN_LOCAL;
4ee39733f   David Ahern   net: ipv6: set ro...
3306
3307
  	else if (rt->rt6i_flags & RTF_ANYCAST)
  		rtm->rtm_type = RTN_ANYCAST;
d19185428   David S. Miller   ipv6: Kill rt6i_d...
3308
  	else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3309
3310
3311
3312
3313
3314
  		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;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3315

383084739   David S. Miller   ipv6: Various cle...
3316
  	if (rt->rt6i_flags & RTF_CACHE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3317
3318
3319
  		rtm->rtm_flags |= RTM_F_CLONED;
  
  	if (dst) {
930345ea6   Jiri Benc   netlink: implemen...
3320
  		if (nla_put_in6_addr(skb, RTA_DST, dst))
c78679e8f   David S. Miller   ipv6: Stop using ...
3321
  			goto nla_put_failure;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
3322
  		rtm->rtm_dst_len = 128;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3323
  	} else if (rtm->rtm_dst_len)
930345ea6   Jiri Benc   netlink: implemen...
3324
  		if (nla_put_in6_addr(skb, RTA_DST, &rt->rt6i_dst.addr))
c78679e8f   David S. Miller   ipv6: Stop using ...
3325
  			goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3326
3327
  #ifdef CONFIG_IPV6_SUBTREES
  	if (src) {
930345ea6   Jiri Benc   netlink: implemen...
3328
  		if (nla_put_in6_addr(skb, RTA_SRC, src))
c78679e8f   David S. Miller   ipv6: Stop using ...
3329
  			goto nla_put_failure;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
3330
  		rtm->rtm_src_len = 128;
c78679e8f   David S. Miller   ipv6: Stop using ...
3331
  	} else if (rtm->rtm_src_len &&
930345ea6   Jiri Benc   netlink: implemen...
3332
  		   nla_put_in6_addr(skb, RTA_SRC, &rt->rt6i_src.addr))
c78679e8f   David S. Miller   ipv6: Stop using ...
3333
  		goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3334
  #endif
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
3335
3336
3337
  	if (iif) {
  #ifdef CONFIG_IPV6_MROUTE
  		if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
fd61c6ba3   David Ahern   net: ipv6: remove...
3338
3339
3340
3341
3342
3343
  			int err = ip6mr_get_route(net, skb, rtm, portid);
  
  			if (err == 0)
  				return 0;
  			if (err < 0)
  				goto nla_put_failure;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
3344
3345
  		} else
  #endif
c78679e8f   David S. Miller   ipv6: Stop using ...
3346
3347
  			if (nla_put_u32(skb, RTA_IIF, iif))
  				goto nla_put_failure;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
3348
  	} else if (dst) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3349
  		struct in6_addr saddr_buf;
c78679e8f   David S. Miller   ipv6: Stop using ...
3350
  		if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0 &&
930345ea6   Jiri Benc   netlink: implemen...
3351
  		    nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
c78679e8f   David S. Miller   ipv6: Stop using ...
3352
  			goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3353
  	}
2d7202bfd   Thomas Graf   [IPv6] route: Con...
3354

c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
3355
3356
  	if (rt->rt6i_prefsrc.plen) {
  		struct in6_addr saddr_buf;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
3357
  		saddr_buf = rt->rt6i_prefsrc.addr;
930345ea6   Jiri Benc   netlink: implemen...
3358
  		if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
c78679e8f   David S. Miller   ipv6: Stop using ...
3359
  			goto nla_put_failure;
c3968a857   Daniel Walter   ipv6: RTA_PREFSRC...
3360
  	}
4b32b5ad3   Martin KaFai Lau   ipv6: Stop rt6_in...
3361
3362
3363
3364
  	memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics));
  	if (rt->rt6i_pmtu)
  		metrics[RTAX_MTU - 1] = rt->rt6i_pmtu;
  	if (rtnetlink_put_metrics(skb, metrics) < 0)
2d7202bfd   Thomas Graf   [IPv6] route: Con...
3365
  		goto nla_put_failure;
c78679e8f   David S. Miller   ipv6: Stop using ...
3366
3367
  	if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric))
  		goto nla_put_failure;
8253947e2   Li Wei   ipv6: fix incorre...
3368

beb1afac5   David Ahern   net: ipv6: Add su...
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
  	/* For multipath routes, walk the siblings list and add
  	 * each as a nexthop within RTA_MULTIPATH.
  	 */
  	if (rt->rt6i_nsiblings) {
  		struct rt6_info *sibling, *next_sibling;
  		struct nlattr *mp;
  
  		mp = nla_nest_start(skb, RTA_MULTIPATH);
  		if (!mp)
  			goto nla_put_failure;
  
  		if (rt6_add_nexthop(skb, rt) < 0)
  			goto nla_put_failure;
  
  		list_for_each_entry_safe(sibling, next_sibling,
  					 &rt->rt6i_siblings, rt6i_siblings) {
  			if (rt6_add_nexthop(skb, sibling) < 0)
  				goto nla_put_failure;
  		}
  
  		nla_nest_end(skb, mp);
  	} else {
5be083ced   David Ahern   net: ipv6: Remove...
3391
  		if (rt6_nexthop_info(skb, rt, &rtm->rtm_flags, false) < 0)
beb1afac5   David Ahern   net: ipv6: Add su...
3392
3393
  			goto nla_put_failure;
  	}
8253947e2   Li Wei   ipv6: fix incorre...
3394
  	expires = (rt->rt6i_flags & RTF_EXPIRES) ? rt->dst.expires - jiffies : 0;
69cdf8f92   YOSHIFUJI Hideaki   ipv6 route: Fix l...
3395

87a50699c   David S. Miller   rtnetlink: Remove...
3396
  	if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, rt->dst.error) < 0)
e3703b3de   Thomas Graf   [RTNETLINK]: Add ...
3397
  		goto nla_put_failure;
2d7202bfd   Thomas Graf   [IPv6] route: Con...
3398

c78ba6d64   Lubomir Rintel   ipv6: expose RFC4...
3399
3400
  	if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags)))
  		goto nla_put_failure;
19e42e451   Roopa Prabhu   ipv6: support for...
3401

053c095a8   Johannes Berg   netlink: make nlm...
3402
3403
  	nlmsg_end(skb, nlh);
  	return 0;
2d7202bfd   Thomas Graf   [IPv6] route: Con...
3404
3405
  
  nla_put_failure:
26932566a   Patrick McHardy   [NETLINK]: Don't ...
3406
3407
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3408
  }
1b43af548   Patrick McHardy   [IPV6]: Increase ...
3409
  int rt6_dump_route(struct rt6_info *rt, void *p_arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3410
3411
  {
  	struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
1f17e2f2c   David Ahern   net: ipv6: ignore...
3412
3413
3414
3415
  	struct net *net = arg->net;
  
  	if (rt == net->ipv6.ip6_null_entry)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3416

2d7202bfd   Thomas Graf   [IPv6] route: Con...
3417
3418
  	if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
  		struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
f8cfe2ceb   David Ahern   net: ipv6: remove...
3419
3420
3421
3422
3423
3424
3425
3426
  
  		/* user wants prefix routes only */
  		if (rtm->rtm_flags & RTM_F_PREFIX &&
  		    !(rt->rt6i_flags & RTF_PREFIX_RT)) {
  			/* success since this is not a prefix route */
  			return 1;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3427

1f17e2f2c   David Ahern   net: ipv6: ignore...
3428
  	return rt6_fill_node(net,
191cd5825   Brian Haley   netns: Add networ...
3429
  		     arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
15e473046   Eric W. Biederman   netlink: Rename p...
3430
  		     NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq,
f8cfe2ceb   David Ahern   net: ipv6: remove...
3431
  		     NLM_F_MULTI);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3432
  }
c21ef3e34   David Ahern   net: rtnetlink: p...
3433
3434
  static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
  			      struct netlink_ext_ack *extack)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3435
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
3436
  	struct net *net = sock_net(in_skb->sk);
ab364a6f9   Thomas Graf   [IPv6] route: Con...
3437
  	struct nlattr *tb[RTA_MAX+1];
18c3a61c4   Roopa Prabhu   net: ipv6: RTM_GE...
3438
3439
  	int err, iif = 0, oif = 0;
  	struct dst_entry *dst;
ab364a6f9   Thomas Graf   [IPv6] route: Con...
3440
  	struct rt6_info *rt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3441
  	struct sk_buff *skb;
ab364a6f9   Thomas Graf   [IPv6] route: Con...
3442
  	struct rtmsg *rtm;
4c9483b2f   David S. Miller   ipv6: Convert to ...
3443
  	struct flowi6 fl6;
18c3a61c4   Roopa Prabhu   net: ipv6: RTM_GE...
3444
  	bool fibmatch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3445

fceb6435e   Johannes Berg   netlink: pass ext...
3446
  	err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
c21ef3e34   David Ahern   net: rtnetlink: p...
3447
  			  extack);
ab364a6f9   Thomas Graf   [IPv6] route: Con...
3448
3449
  	if (err < 0)
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3450

ab364a6f9   Thomas Graf   [IPv6] route: Con...
3451
  	err = -EINVAL;
4c9483b2f   David S. Miller   ipv6: Convert to ...
3452
  	memset(&fl6, 0, sizeof(fl6));
38b7097b5   Hannes Frederic Sowa   ipv6: use TOS mar...
3453
3454
  	rtm = nlmsg_data(nlh);
  	fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0);
18c3a61c4   Roopa Prabhu   net: ipv6: RTM_GE...
3455
  	fibmatch = !!(rtm->rtm_flags & RTM_F_FIB_MATCH);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3456

ab364a6f9   Thomas Graf   [IPv6] route: Con...
3457
3458
3459
  	if (tb[RTA_SRC]) {
  		if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
  			goto errout;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
3460
  		fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
ab364a6f9   Thomas Graf   [IPv6] route: Con...
3461
3462
3463
3464
3465
  	}
  
  	if (tb[RTA_DST]) {
  		if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
  			goto errout;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
3466
  		fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
ab364a6f9   Thomas Graf   [IPv6] route: Con...
3467
3468
3469
3470
3471
3472
  	}
  
  	if (tb[RTA_IIF])
  		iif = nla_get_u32(tb[RTA_IIF]);
  
  	if (tb[RTA_OIF])
72331bc0c   Shmulik Ladkani   ipv6: Fix RTM_GET...
3473
  		oif = nla_get_u32(tb[RTA_OIF]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3474

2e47b2919   Lorenzo Colitti   net: ipv6: make "...
3475
3476
  	if (tb[RTA_MARK])
  		fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
622ec2c9d   Lorenzo Colitti   net: core: add UI...
3477
3478
3479
3480
3481
  	if (tb[RTA_UID])
  		fl6.flowi6_uid = make_kuid(current_user_ns(),
  					   nla_get_u32(tb[RTA_UID]));
  	else
  		fl6.flowi6_uid = iif ? INVALID_UID : current_uid();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3482
3483
  	if (iif) {
  		struct net_device *dev;
72331bc0c   Shmulik Ladkani   ipv6: Fix RTM_GET...
3484
  		int flags = 0;
121622dba   Florian Westphal   ipv6: route: make...
3485
3486
3487
  		rcu_read_lock();
  
  		dev = dev_get_by_index_rcu(net, iif);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3488
  		if (!dev) {
121622dba   Florian Westphal   ipv6: route: make...
3489
  			rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3490
  			err = -ENODEV;
ab364a6f9   Thomas Graf   [IPv6] route: Con...
3491
  			goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3492
  		}
72331bc0c   Shmulik Ladkani   ipv6: Fix RTM_GET...
3493
3494
3495
3496
3497
  
  		fl6.flowi6_iif = iif;
  
  		if (!ipv6_addr_any(&fl6.saddr))
  			flags |= RT6_LOOKUP_F_HAS_SADDR;
333921964   Ido Schimmel   ipv6: Honor speci...
3498
  		dst = ip6_route_input_lookup(net, dev, &fl6, flags);
121622dba   Florian Westphal   ipv6: route: make...
3499
3500
  
  		rcu_read_unlock();
72331bc0c   Shmulik Ladkani   ipv6: Fix RTM_GET...
3501
3502
  	} else {
  		fl6.flowi6_oif = oif;
333921964   Ido Schimmel   ipv6: Honor speci...
3503
  		dst = ip6_route_output(net, NULL, &fl6);
18c3a61c4   Roopa Prabhu   net: ipv6: RTM_GE...
3504
  	}
18c3a61c4   Roopa Prabhu   net: ipv6: RTM_GE...
3505
3506
3507
3508
3509
3510
  
  	rt = container_of(dst, struct rt6_info, dst);
  	if (rt->dst.error) {
  		err = rt->dst.error;
  		ip6_rt_put(rt);
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3511
  	}
9d6acb3bc   WANG Cong   ipv6: ignore null...
3512
3513
3514
3515
3516
  	if (rt == net->ipv6.ip6_null_entry) {
  		err = rt->dst.error;
  		ip6_rt_put(rt);
  		goto errout;
  	}
333921964   Ido Schimmel   ipv6: Honor speci...
3517
3518
3519
3520
3521
3522
3523
3524
  	if (fibmatch && rt->dst.from) {
  		struct rt6_info *ort = container_of(rt->dst.from,
  						    struct rt6_info, dst);
  
  		dst_hold(&ort->dst);
  		ip6_rt_put(rt);
  		rt = ort;
  	}
ab364a6f9   Thomas Graf   [IPv6] route: Con...
3525
  	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
383084739   David S. Miller   ipv6: Various cle...
3526
  	if (!skb) {
94e187c01   Amerigo Wang   ipv6: introduce i...
3527
  		ip6_rt_put(rt);
ab364a6f9   Thomas Graf   [IPv6] route: Con...
3528
3529
3530
  		err = -ENOBUFS;
  		goto errout;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3531

d8d1f30b9   Changli Gao   net-next: remove ...
3532
  	skb_dst_set(skb, &rt->dst);
18c3a61c4   Roopa Prabhu   net: ipv6: RTM_GE...
3533
3534
3535
3536
3537
3538
3539
3540
  	if (fibmatch)
  		err = rt6_fill_node(net, skb, rt, NULL, NULL, iif,
  				    RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
  				    nlh->nlmsg_seq, 0);
  	else
  		err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
  				    RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
  				    nlh->nlmsg_seq, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3541
  	if (err < 0) {
ab364a6f9   Thomas Graf   [IPv6] route: Con...
3542
3543
  		kfree_skb(skb);
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3544
  	}
15e473046   Eric W. Biederman   netlink: Rename p...
3545
  	err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
ab364a6f9   Thomas Graf   [IPv6] route: Con...
3546
  errout:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3547
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3548
  }
37a1d3611   Roopa Prabhu   ipv6: include NLM...
3549
3550
  void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info,
  		     unsigned int nlm_flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3551
3552
  {
  	struct sk_buff *skb;
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
3553
  	struct net *net = info->nl_net;
528c4ceb4   Denis V. Lunev   [IPV6]: Always pa...
3554
3555
3556
3557
  	u32 seq;
  	int err;
  
  	err = -ENOBUFS;
383084739   David S. Miller   ipv6: Various cle...
3558
  	seq = info->nlh ? info->nlh->nlmsg_seq : 0;
86872cb57   Thomas Graf   [IPv6] route: FIB...
3559

19e42e451   Roopa Prabhu   ipv6: support for...
3560
  	skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
383084739   David S. Miller   ipv6: Various cle...
3561
  	if (!skb)
21713ebc4   Thomas Graf   [IPv6] route: Con...
3562
  		goto errout;
191cd5825   Brian Haley   netns: Add networ...
3563
  	err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
f8cfe2ceb   David Ahern   net: ipv6: remove...
3564
  				event, info->portid, seq, nlm_flags);
26932566a   Patrick McHardy   [NETLINK]: Don't ...
3565
3566
3567
3568
3569
3570
  	if (err < 0) {
  		/* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
  		WARN_ON(err == -EMSGSIZE);
  		kfree_skb(skb);
  		goto errout;
  	}
15e473046   Eric W. Biederman   netlink: Rename p...
3571
  	rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
1ce85fe40   Pablo Neira Ayuso   netlink: change n...
3572
3573
  		    info->nlh, gfp_any());
  	return;
21713ebc4   Thomas Graf   [IPv6] route: Con...
3574
3575
  errout:
  	if (err < 0)
5578689a4   Daniel Lezcano   [NETNS][IPV6] rou...
3576
  		rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3577
  }
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3578
  static int ip6_route_dev_notify(struct notifier_block *this,
351638e7d   Jiri Pirko   net: pass info st...
3579
  				unsigned long event, void *ptr)
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3580
  {
351638e7d   Jiri Pirko   net: pass info st...
3581
  	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
3582
  	struct net *net = dev_net(dev);
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3583

242d3a49a   WANG Cong   ipv6: reorder ip6...
3584
3585
3586
3587
  	if (!(dev->flags & IFF_LOOPBACK))
  		return NOTIFY_OK;
  
  	if (event == NETDEV_REGISTER) {
d8d1f30b9   Changli Gao   net-next: remove ...
3588
  		net->ipv6.ip6_null_entry->dst.dev = dev;
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3589
3590
  		net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
  #ifdef CONFIG_IPV6_MULTIPLE_TABLES
d8d1f30b9   Changli Gao   net-next: remove ...
3591
  		net->ipv6.ip6_prohibit_entry->dst.dev = dev;
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3592
  		net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
d8d1f30b9   Changli Gao   net-next: remove ...
3593
  		net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3594
3595
  		net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
  #endif
76da07045   WANG Cong   ipv6: only call i...
3596
3597
3598
3599
3600
  	 } else if (event == NETDEV_UNREGISTER &&
  		    dev->reg_state != NETREG_UNREGISTERED) {
  		/* NETDEV_UNREGISTER could be fired for multiple times by
  		 * netdev_wait_allrefs(). Make sure we only call this once.
  		 */
12d94a804   Eric Dumazet   ipv6: fix NULL de...
3601
  		in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev);
242d3a49a   WANG Cong   ipv6: reorder ip6...
3602
  #ifdef CONFIG_IPV6_MULTIPLE_TABLES
12d94a804   Eric Dumazet   ipv6: fix NULL de...
3603
3604
  		in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev);
  		in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev);
242d3a49a   WANG Cong   ipv6: reorder ip6...
3605
  #endif
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3606
3607
3608
3609
  	}
  
  	return NOTIFY_OK;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3610
3611
3612
3613
3614
  /*
   *	/proc
   */
  
  #ifdef CONFIG_PROC_FS
33120b30c   Alexey Dobriyan   [IPV6]: Convert /...
3615
3616
3617
3618
3619
  static const struct file_operations ipv6_route_proc_fops = {
  	.owner		= THIS_MODULE,
  	.open		= ipv6_route_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
8d2ca1d7b   Hannes Frederic Sowa   ipv6: avoid high ...
3620
  	.release	= seq_release_net,
33120b30c   Alexey Dobriyan   [IPV6]: Convert /...
3621
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3622
3623
  static int rt6_stats_seq_show(struct seq_file *seq, void *v)
  {
69ddb8056   Daniel Lezcano   [NETNS][IPV6] rou...
3624
  	struct net *net = (struct net *)seq->private;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3625
3626
  	seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x
  ",
69ddb8056   Daniel Lezcano   [NETNS][IPV6] rou...
3627
3628
3629
3630
3631
  		   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...
3632
  		   dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
69ddb8056   Daniel Lezcano   [NETNS][IPV6] rou...
3633
  		   net->ipv6.rt6_stats->fib_discarded_routes);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3634
3635
3636
3637
3638
3639
  
  	return 0;
  }
  
  static int rt6_stats_seq_open(struct inode *inode, struct file *file)
  {
de05c557b   Pavel Emelyanov   proc: consolidate...
3640
  	return single_open_net(inode, file, rt6_stats_seq_show);
69ddb8056   Daniel Lezcano   [NETNS][IPV6] rou...
3641
  }
9a32144e9   Arjan van de Ven   [PATCH] mark stru...
3642
  static const struct file_operations rt6_stats_seq_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3643
3644
3645
3646
  	.owner	 = THIS_MODULE,
  	.open	 = rt6_stats_seq_open,
  	.read	 = seq_read,
  	.llseek	 = seq_lseek,
b6fcbdb4f   Pavel Emelyanov   proc: consolidate...
3647
  	.release = single_release_net,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3648
3649
3650
3651
  };
  #endif	/* CONFIG_PROC_FS */
  
  #ifdef CONFIG_SYSCTL
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3652
  static
fe2c6338f   Joe Perches   net: Convert uses...
3653
  int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3654
3655
  			      void __user *buffer, size_t *lenp, loff_t *ppos)
  {
c486da343   Lucian Adrian Grijincu   sysctl: ipv6: use...
3656
3657
3658
  	struct net *net;
  	int delay;
  	if (!write)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3659
  		return -EINVAL;
c486da343   Lucian Adrian Grijincu   sysctl: ipv6: use...
3660
3661
3662
3663
  
  	net = (struct net *)ctl->extra1;
  	delay = net->ipv6.sysctl.flush_delay;
  	proc_dointvec(ctl, write, buffer, lenp, ppos);
2ac3ac8f8   Michal Kubeček   ipv6: prevent fib...
3664
  	fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
c486da343   Lucian Adrian Grijincu   sysctl: ipv6: use...
3665
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3666
  }
fe2c6338f   Joe Perches   net: Convert uses...
3667
  struct ctl_table ipv6_route_table_template[] = {
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
3668
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3669
  		.procname	=	"flush",
4990509f1   Daniel Lezcano   [NETNS][IPV6]: Ma...
3670
  		.data		=	&init_net.ipv6.sysctl.flush_delay,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3671
  		.maxlen		=	sizeof(int),
89c8b3a11   Dave Jones   [IPV6]: Incorrect...
3672
  		.mode		=	0200,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3673
  		.proc_handler	=	ipv6_sysctl_rtcache_flush
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3674
3675
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3676
  		.procname	=	"gc_thresh",
9a7ec3a94   Daniel Lezcano   [NETNS][IPV6] rou...
3677
  		.data		=	&ip6_dst_ops_template.gc_thresh,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3678
3679
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3680
  		.proc_handler	=	proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3681
3682
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3683
  		.procname	=	"max_size",
4990509f1   Daniel Lezcano   [NETNS][IPV6]: Ma...
3684
  		.data		=	&init_net.ipv6.sysctl.ip6_rt_max_size,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3685
3686
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3687
  		.proc_handler	=	proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3688
3689
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3690
  		.procname	=	"gc_min_interval",
4990509f1   Daniel Lezcano   [NETNS][IPV6]: Ma...
3691
  		.data		=	&init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3692
3693
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3694
  		.proc_handler	=	proc_dointvec_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3695
3696
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3697
  		.procname	=	"gc_timeout",
4990509f1   Daniel Lezcano   [NETNS][IPV6]: Ma...
3698
  		.data		=	&init_net.ipv6.sysctl.ip6_rt_gc_timeout,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3699
3700
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3701
  		.proc_handler	=	proc_dointvec_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3702
3703
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3704
  		.procname	=	"gc_interval",
4990509f1   Daniel Lezcano   [NETNS][IPV6]: Ma...
3705
  		.data		=	&init_net.ipv6.sysctl.ip6_rt_gc_interval,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3706
3707
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3708
  		.proc_handler	=	proc_dointvec_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3709
3710
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3711
  		.procname	=	"gc_elasticity",
4990509f1   Daniel Lezcano   [NETNS][IPV6]: Ma...
3712
  		.data		=	&init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3713
3714
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
f3d3f616e   Min Zhang   ipv6: remove sysc...
3715
  		.proc_handler	=	proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3716
3717
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3718
  		.procname	=	"mtu_expires",
4990509f1   Daniel Lezcano   [NETNS][IPV6]: Ma...
3719
  		.data		=	&init_net.ipv6.sysctl.ip6_rt_mtu_expires,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3720
3721
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3722
  		.proc_handler	=	proc_dointvec_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3723
3724
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3725
  		.procname	=	"min_adv_mss",
4990509f1   Daniel Lezcano   [NETNS][IPV6]: Ma...
3726
  		.data		=	&init_net.ipv6.sysctl.ip6_rt_min_advmss,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3727
3728
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
f3d3f616e   Min Zhang   ipv6: remove sysc...
3729
  		.proc_handler	=	proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3730
3731
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3732
  		.procname	=	"gc_min_interval_ms",
4990509f1   Daniel Lezcano   [NETNS][IPV6]: Ma...
3733
  		.data		=	&init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3734
3735
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3736
  		.proc_handler	=	proc_dointvec_ms_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3737
  	},
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
3738
  	{ }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3739
  };
2c8c1e729   Alexey Dobriyan   net: spread __net...
3740
  struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
760f2d018   Daniel Lezcano   [NETNS][IPV6]: Ma...
3741
3742
3743
3744
3745
3746
  {
  	struct ctl_table *table;
  
  	table = kmemdup(ipv6_route_table_template,
  			sizeof(ipv6_route_table_template),
  			GFP_KERNEL);
5ee091050   YOSHIFUJI Hideaki   [IPV6] SYSCTL: co...
3747
3748
3749
  
  	if (table) {
  		table[0].data = &net->ipv6.sysctl.flush_delay;
c486da343   Lucian Adrian Grijincu   sysctl: ipv6: use...
3750
  		table[0].extra1 = net;
86393e52c   Alexey Dobriyan   netns: embed ip6_...
3751
  		table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
5ee091050   YOSHIFUJI Hideaki   [IPV6] SYSCTL: co...
3752
3753
3754
3755
3756
3757
3758
  		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...
3759
  		table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
464dc801c   Eric W. Biederman   net: Don't export...
3760
3761
3762
3763
  
  		/* Don't export sysctls to unprivileged users */
  		if (net->user_ns != &init_user_ns)
  			table[0].procname = NULL;
5ee091050   YOSHIFUJI Hideaki   [IPV6] SYSCTL: co...
3764
  	}
760f2d018   Daniel Lezcano   [NETNS][IPV6]: Ma...
3765
3766
  	return table;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3767
  #endif
2c8c1e729   Alexey Dobriyan   net: spread __net...
3768
  static int __net_init ip6_route_net_init(struct net *net)
cdb187619   Daniel Lezcano   [NETNS][IPV6] rou...
3769
  {
633d424bf   Pavel Emelyanov   [NETNS]: Don't in...
3770
  	int ret = -ENOMEM;
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3771

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

fc66f95c6   Eric Dumazet   net dst: use a pe...
3775
3776
  	if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
  		goto out_ip6_dst_ops;
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3777
3778
3779
3780
  	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...
3781
  		goto out_ip6_dst_entries;
d8d1f30b9   Changli Gao   net-next: remove ...
3782
  	net->ipv6.ip6_null_entry->dst.path =
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3783
  		(struct dst_entry *)net->ipv6.ip6_null_entry;
d8d1f30b9   Changli Gao   net-next: remove ...
3784
  	net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
62fa8a846   David S. Miller   net: Implement re...
3785
3786
  	dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
  			 ip6_template_metrics, true);
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3787
3788
  
  #ifdef CONFIG_IPV6_MULTIPLE_TABLES
feca7d8c1   Vincent Bernat   net: ipv6: avoid ...
3789
  	net->ipv6.fib6_has_custom_rules = false;
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3790
3791
3792
  	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...
3793
3794
  	if (!net->ipv6.ip6_prohibit_entry)
  		goto out_ip6_null_entry;
d8d1f30b9   Changli Gao   net-next: remove ...
3795
  	net->ipv6.ip6_prohibit_entry->dst.path =
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3796
  		(struct dst_entry *)net->ipv6.ip6_prohibit_entry;
d8d1f30b9   Changli Gao   net-next: remove ...
3797
  	net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
62fa8a846   David S. Miller   net: Implement re...
3798
3799
  	dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
  			 ip6_template_metrics, true);
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3800
3801
3802
3803
  
  	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...
3804
3805
  	if (!net->ipv6.ip6_blk_hole_entry)
  		goto out_ip6_prohibit_entry;
d8d1f30b9   Changli Gao   net-next: remove ...
3806
  	net->ipv6.ip6_blk_hole_entry->dst.path =
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3807
  		(struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
d8d1f30b9   Changli Gao   net-next: remove ...
3808
  	net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
62fa8a846   David S. Miller   net: Implement re...
3809
3810
  	dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
  			 ip6_template_metrics, true);
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3811
  #endif
b339a47c3   Peter Zijlstra   ipv6: initialize ...
3812
3813
3814
3815
3816
3817
3818
3819
  	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;
6891a346c   Benjamin Thery   [NETNS][IPV6] rou...
3820
  	net->ipv6.ip6_rt_gc_expire = 30*HZ;
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3821
3822
3823
  	ret = 0;
  out:
  	return ret;
f2fc6a545   Benjamin Thery   [NETNS][IPV6] rou...
3824

68fffc679   Peter Zijlstra   ipv6: clean up ip...
3825
3826
3827
3828
3829
3830
  #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...
3831
3832
  out_ip6_dst_entries:
  	dst_entries_destroy(&net->ipv6.ip6_dst_ops);
f2fc6a545   Benjamin Thery   [NETNS][IPV6] rou...
3833
  out_ip6_dst_ops:
f2fc6a545   Benjamin Thery   [NETNS][IPV6] rou...
3834
  	goto out;
cdb187619   Daniel Lezcano   [NETNS][IPV6] rou...
3835
  }
2c8c1e729   Alexey Dobriyan   net: spread __net...
3836
  static void __net_exit ip6_route_net_exit(struct net *net)
cdb187619   Daniel Lezcano   [NETNS][IPV6] rou...
3837
  {
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3838
3839
3840
3841
3842
  	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...
3843
  	dst_entries_destroy(&net->ipv6.ip6_dst_ops);
cdb187619   Daniel Lezcano   [NETNS][IPV6] rou...
3844
  }
d189634ec   Thomas Graf   ipv6: Move ipv6 p...
3845
3846
3847
  static int __net_init ip6_route_net_init_late(struct net *net)
  {
  #ifdef CONFIG_PROC_FS
d4beaa66a   Gao feng   net: proc: change...
3848
3849
  	proc_create("ipv6_route", 0, net->proc_net, &ipv6_route_proc_fops);
  	proc_create("rt6_stats", S_IRUGO, net->proc_net, &rt6_stats_seq_fops);
d189634ec   Thomas Graf   ipv6: Move ipv6 p...
3850
3851
3852
3853
3854
3855
3856
  #endif
  	return 0;
  }
  
  static void __net_exit ip6_route_net_exit_late(struct net *net)
  {
  #ifdef CONFIG_PROC_FS
ece31ffd5   Gao feng   net: proc: change...
3857
3858
  	remove_proc_entry("ipv6_route", net->proc_net);
  	remove_proc_entry("rt6_stats", net->proc_net);
d189634ec   Thomas Graf   ipv6: Move ipv6 p...
3859
3860
  #endif
  }
cdb187619   Daniel Lezcano   [NETNS][IPV6] rou...
3861
3862
3863
3864
  static struct pernet_operations ip6_route_net_ops = {
  	.init = ip6_route_net_init,
  	.exit = ip6_route_net_exit,
  };
c3426b471   David S. Miller   inet: Initialize ...
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
  static int __net_init ipv6_inetpeer_init(struct net *net)
  {
  	struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
  
  	if (!bp)
  		return -ENOMEM;
  	inet_peer_base_init(bp);
  	net->ipv6.peers = bp;
  	return 0;
  }
  
  static void __net_exit ipv6_inetpeer_exit(struct net *net)
  {
  	struct inet_peer_base *bp = net->ipv6.peers;
  
  	net->ipv6.peers = NULL;
56a6b248e   David S. Miller   inet: Consolidate...
3881
  	inetpeer_invalidate_tree(bp);
c3426b471   David S. Miller   inet: Initialize ...
3882
3883
  	kfree(bp);
  }
2b823f725   David S. Miller   ipv6: Do not mark...
3884
  static struct pernet_operations ipv6_inetpeer_ops = {
c3426b471   David S. Miller   inet: Initialize ...
3885
3886
3887
  	.init	=	ipv6_inetpeer_init,
  	.exit	=	ipv6_inetpeer_exit,
  };
d189634ec   Thomas Graf   ipv6: Move ipv6 p...
3888
3889
3890
3891
  static struct pernet_operations ip6_route_net_late_ops = {
  	.init = ip6_route_net_init_late,
  	.exit = ip6_route_net_exit_late,
  };
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3892
3893
  static struct notifier_block ip6_route_dev_notifier = {
  	.notifier_call = ip6_route_dev_notify,
242d3a49a   WANG Cong   ipv6: reorder ip6...
3894
  	.priority = ADDRCONF_NOTIFY_PRIORITY - 10,
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3895
  };
2f460933f   WANG Cong   ipv6: initialize ...
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
  void __init ip6_route_init_special_entries(void)
  {
  	/* 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 */
  	init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
  	init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
    #ifdef CONFIG_IPV6_MULTIPLE_TABLES
  	init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
  	init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
  	init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
  	init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
    #endif
  }
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
3910
  int __init ip6_route_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3911
  {
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
3912
  	int ret;
8d0b94afd   Martin KaFai Lau   ipv6: Keep track ...
3913
  	int cpu;
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
3914

9a7ec3a94   Daniel Lezcano   [NETNS][IPV6] rou...
3915
3916
  	ret = -ENOMEM;
  	ip6_dst_ops_template.kmem_cachep =
e5d679f33   Alexey Dobriyan   [NET]: Use SLAB_P...
3917
  		kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
f845ab6b7   Daniel Lezcano   [IPV6] route6/fib...
3918
  				  SLAB_HWCACHE_ALIGN, NULL);
9a7ec3a94   Daniel Lezcano   [NETNS][IPV6] rou...
3919
  	if (!ip6_dst_ops_template.kmem_cachep)
c19a28e11   Fernando Carrijo   remove lots of do...
3920
  		goto out;
14e50e57a   David S. Miller   [XFRM]: Allow pac...
3921

fc66f95c6   Eric Dumazet   net dst: use a pe...
3922
  	ret = dst_entries_init(&ip6_dst_blackhole_ops);
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3923
  	if (ret)
bdb3289f7   Daniel Lezcano   [NETNS][IPV6] rt6...
3924
  		goto out_kmem_cache;
bdb3289f7   Daniel Lezcano   [NETNS][IPV6] rt6...
3925

c3426b471   David S. Miller   inet: Initialize ...
3926
3927
  	ret = register_pernet_subsys(&ipv6_inetpeer_ops);
  	if (ret)
e8803b6c3   David S. Miller   Revert "ipv6: Pre...
3928
  		goto out_dst_entries;
2a0c451ad   Thomas Graf   ipv6: Prevent acc...
3929

7e52b33bd   David S. Miller   Merge git://git.k...
3930
3931
3932
  	ret = register_pernet_subsys(&ip6_route_net_ops);
  	if (ret)
  		goto out_register_inetpeer;
c3426b471   David S. Miller   inet: Initialize ...
3933

5dc121e9a   Arnaud Ebalard   XFRM,IPv6: initia...
3934
  	ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
e8803b6c3   David S. Miller   Revert "ipv6: Pre...
3935
  	ret = fib6_init();
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
3936
  	if (ret)
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3937
  		goto out_register_subsys;
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
3938

433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
3939
3940
  	ret = xfrm6_init();
  	if (ret)
e8803b6c3   David S. Miller   Revert "ipv6: Pre...
3941
  		goto out_fib6_init;
c35b7e72c   Daniel Lezcano   [IPV6]: remove if...
3942

433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
3943
3944
3945
  	ret = fib6_rules_init();
  	if (ret)
  		goto xfrm6_init;
7e5449c21   Daniel Lezcano   [IPV6]: route6 re...
3946

d189634ec   Thomas Graf   ipv6: Move ipv6 p...
3947
3948
3949
  	ret = register_pernet_subsys(&ip6_route_net_late_ops);
  	if (ret)
  		goto fib6_rules_init;
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
3950
  	ret = -ENOBUFS;
b97bac64a   Florian Westphal   rtnetlink: make r...
3951
3952
  	if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, 0) ||
  	    __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, 0) ||
e3a22b7f5   Florian Westphal   ipv6: route: set ...
3953
3954
  	    __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL,
  			    RTNL_FLAG_DOIT_UNLOCKED))
d189634ec   Thomas Graf   ipv6: Move ipv6 p...
3955
  		goto out_register_late_subsys;
c127ea2c4   Thomas Graf   [IPv6]: Use rtnl ...
3956

8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3957
  	ret = register_netdevice_notifier(&ip6_route_dev_notifier);
cdb187619   Daniel Lezcano   [NETNS][IPV6] rou...
3958
  	if (ret)
d189634ec   Thomas Graf   ipv6: Move ipv6 p...
3959
  		goto out_register_late_subsys;
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3960

8d0b94afd   Martin KaFai Lau   ipv6: Keep track ...
3961
3962
3963
3964
3965
3966
  	for_each_possible_cpu(cpu) {
  		struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
  
  		INIT_LIST_HEAD(&ul->head);
  		spin_lock_init(&ul->lock);
  	}
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
3967
3968
  out:
  	return ret;
d189634ec   Thomas Graf   ipv6: Move ipv6 p...
3969
3970
  out_register_late_subsys:
  	unregister_pernet_subsys(&ip6_route_net_late_ops);
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
3971
  fib6_rules_init:
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
3972
3973
  	fib6_rules_cleanup();
  xfrm6_init:
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
3974
  	xfrm6_fini();
2a0c451ad   Thomas Graf   ipv6: Prevent acc...
3975
3976
  out_fib6_init:
  	fib6_gc_cleanup();
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3977
3978
  out_register_subsys:
  	unregister_pernet_subsys(&ip6_route_net_ops);
7e52b33bd   David S. Miller   Merge git://git.k...
3979
3980
  out_register_inetpeer:
  	unregister_pernet_subsys(&ipv6_inetpeer_ops);
fc66f95c6   Eric Dumazet   net dst: use a pe...
3981
3982
  out_dst_entries:
  	dst_entries_destroy(&ip6_dst_blackhole_ops);
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
3983
  out_kmem_cache:
f2fc6a545   Benjamin Thery   [NETNS][IPV6] rou...
3984
  	kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
433d49c3b   Daniel Lezcano   [IPV6]: Make ip6_...
3985
  	goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3986
3987
3988
3989
  }
  
  void ip6_route_cleanup(void)
  {
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3990
  	unregister_netdevice_notifier(&ip6_route_dev_notifier);
d189634ec   Thomas Graf   ipv6: Move ipv6 p...
3991
  	unregister_pernet_subsys(&ip6_route_net_late_ops);
101367c2f   Thomas Graf   [IPV6]: Policy Ro...
3992
  	fib6_rules_cleanup();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3993
  	xfrm6_fini();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3994
  	fib6_gc_cleanup();
c3426b471   David S. Miller   inet: Initialize ...
3995
  	unregister_pernet_subsys(&ipv6_inetpeer_ops);
8ed677896   Daniel Lezcano   [NETNS][IPV6] rt6...
3996
  	unregister_pernet_subsys(&ip6_route_net_ops);
41bb78b4b   Xiaotian Feng   net dst: fix perc...
3997
  	dst_entries_destroy(&ip6_dst_blackhole_ops);
f2fc6a545   Benjamin Thery   [NETNS][IPV6] rou...
3998
  	kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3999
  }