blob: d15586490cecaedcc29bc821163cd6c85544b0b8 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Linux INET6 implementation
3 * FIB front-end.
4 *
5 * Authors:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09006 * Pedro Roque <roque@di.fc.ul.pt>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
13
14/* Changes:
15 *
16 * YOSHIFUJI Hideaki @USAGI
17 * reworked default router selection.
18 * - respect outgoing interface
19 * - select from (probably) reachable routers (i.e.
20 * routers in REACHABLE, STALE, DELAY or PROBE states).
21 * - always select the same router if it is (probably)
22 * reachable. otherwise, round-robin the list.
YOSHIFUJI Hideakic0bece92006-08-23 17:23:25 -070023 * Ville Nuorvala
24 * Fixed routing subtrees.
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 */
26
Joe Perchesf3213832012-05-15 14:11:53 +000027#define pr_fmt(fmt) "IPv6: " fmt
28
Randy Dunlap4fc268d2006-01-11 12:17:47 -080029#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/errno.h>
Paul Gortmakerbc3b2d72011-07-15 11:47:34 -040031#include <linux/export.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/types.h>
33#include <linux/times.h>
34#include <linux/socket.h>
35#include <linux/sockios.h>
36#include <linux/net.h>
37#include <linux/route.h>
38#include <linux/netdevice.h>
39#include <linux/in6.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090040#include <linux/mroute6.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <linux/if_arp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/proc_fs.h>
44#include <linux/seq_file.h>
Daniel Lezcano5b7c9312008-03-03 23:28:58 -080045#include <linux/nsproxy.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090046#include <linux/slab.h>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020047#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <net/snmp.h>
49#include <net/ipv6.h>
50#include <net/ip6_fib.h>
51#include <net/ip6_route.h>
52#include <net/ndisc.h>
53#include <net/addrconf.h>
54#include <net/tcp.h>
55#include <linux/rtnetlink.h>
56#include <net/dst.h>
57#include <net/xfrm.h>
Tom Tucker8d717402006-07-30 20:43:36 -070058#include <net/netevent.h>
Thomas Graf21713eb2006-08-15 00:35:24 -070059#include <net/netlink.h>
Nicolas Dichtel51ebd312012-10-22 03:42:09 +000060#include <net/nexthop.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
62#include <asm/uaccess.h>
63
64#ifdef CONFIG_SYSCTL
65#include <linux/sysctl.h>
66#endif
67
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +020068enum rt6_nud_state {
Jiri Benc7e980562013-12-11 13:48:20 +010069 RT6_NUD_FAIL_HARD = -3,
70 RT6_NUD_FAIL_PROBE = -2,
71 RT6_NUD_FAIL_DO_RR = -1,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +020072 RT6_NUD_SUCCEED = 1
73};
74
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -070075static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort);
Linus Torvalds1da177e2005-04-16 15:20:36 -070076static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
David S. Miller0dbaee32010-12-13 12:52:14 -080077static unsigned int ip6_default_advmss(const struct dst_entry *dst);
Steffen Klassertebb762f2011-11-23 02:12:51 +000078static unsigned int ip6_mtu(const struct dst_entry *dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079static struct dst_entry *ip6_negative_advice(struct dst_entry *);
80static void ip6_dst_destroy(struct dst_entry *);
81static void ip6_dst_ifdown(struct dst_entry *,
82 struct net_device *dev, int how);
Daniel Lezcano569d3642008-01-18 03:56:57 -080083static int ip6_dst_gc(struct dst_ops *ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
85static int ip6_pkt_discard(struct sk_buff *skb);
Eric Dumazetaad88722014-04-15 13:47:15 -040086static int ip6_pkt_discard_out(struct sock *sk, struct sk_buff *skb);
Kamala R7150aed2013-12-02 19:55:21 +053087static int ip6_pkt_prohibit(struct sk_buff *skb);
Eric Dumazetaad88722014-04-15 13:47:15 -040088static int ip6_pkt_prohibit_out(struct sock *sk, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089static void ip6_link_failure(struct sk_buff *skb);
David S. Miller6700c272012-07-17 03:29:28 -070090static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
91 struct sk_buff *skb, u32 mtu);
92static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
93 struct sk_buff *skb);
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -070094static void rt6_dst_from_metrics_check(struct rt6_info *rt);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +020095static int rt6_score_route(struct rt6_info *rt, int oif, int strict);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -080097#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -080098static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +000099 const struct in6_addr *prefix, int prefixlen,
100 const struct in6_addr *gwaddr, int ifindex,
Eric Dumazet95c96172012-04-15 05:58:06 +0000101 unsigned int pref);
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800102static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000103 const struct in6_addr *prefix, int prefixlen,
104 const struct in6_addr *gwaddr, int ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800105#endif
106
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700107struct uncached_list {
108 spinlock_t lock;
109 struct list_head head;
110};
111
112static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list);
113
114static void rt6_uncached_list_add(struct rt6_info *rt)
115{
116 struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);
117
118 rt->dst.flags |= DST_NOCACHE;
119 rt->rt6i_uncached_list = ul;
120
121 spin_lock_bh(&ul->lock);
122 list_add_tail(&rt->rt6i_uncached, &ul->head);
123 spin_unlock_bh(&ul->lock);
124}
125
126static void rt6_uncached_list_del(struct rt6_info *rt)
127{
128 if (!list_empty(&rt->rt6i_uncached)) {
129 struct uncached_list *ul = rt->rt6i_uncached_list;
130
131 spin_lock_bh(&ul->lock);
132 list_del(&rt->rt6i_uncached);
133 spin_unlock_bh(&ul->lock);
134 }
135}
136
137static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev)
138{
139 struct net_device *loopback_dev = net->loopback_dev;
140 int cpu;
141
142 for_each_possible_cpu(cpu) {
143 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
144 struct rt6_info *rt;
145
146 spin_lock_bh(&ul->lock);
147 list_for_each_entry(rt, &ul->head, rt6i_uncached) {
148 struct inet6_dev *rt_idev = rt->rt6i_idev;
149 struct net_device *rt_dev = rt->dst.dev;
150
151 if (rt_idev && (rt_idev->dev == dev || !dev) &&
152 rt_idev->dev != loopback_dev) {
153 rt->rt6i_idev = in6_dev_get(loopback_dev);
154 in6_dev_put(rt_idev);
155 }
156
157 if (rt_dev && (rt_dev == dev || !dev) &&
158 rt_dev != loopback_dev) {
159 rt->dst.dev = loopback_dev;
160 dev_hold(rt->dst.dev);
161 dev_put(rt_dev);
162 }
163 }
164 spin_unlock_bh(&ul->lock);
165 }
166}
167
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700168static u32 *rt6_pcpu_cow_metrics(struct rt6_info *rt)
169{
170 return dst_metrics_write_ptr(rt->dst.from);
171}
172
David S. Miller06582542011-01-27 14:58:42 -0800173static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
174{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700175 struct rt6_info *rt = (struct rt6_info *)dst;
David S. Miller06582542011-01-27 14:58:42 -0800176
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700177 if (rt->rt6i_flags & RTF_PCPU)
178 return rt6_pcpu_cow_metrics(rt);
179 else if (rt->rt6i_flags & RTF_CACHE)
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700180 return NULL;
181 else
Martin KaFai Lau3b471172015-02-12 16:14:08 -0800182 return dst_cow_metrics_generic(dst, old);
David S. Miller06582542011-01-27 14:58:42 -0800183}
184
David S. Millerf894cbf2012-07-02 21:52:24 -0700185static inline const void *choose_neigh_daddr(struct rt6_info *rt,
186 struct sk_buff *skb,
187 const void *daddr)
David S. Miller39232972012-01-26 15:22:32 -0500188{
189 struct in6_addr *p = &rt->rt6i_gateway;
190
David S. Millera7563f32012-01-26 16:29:16 -0500191 if (!ipv6_addr_any(p))
David S. Miller39232972012-01-26 15:22:32 -0500192 return (const void *) p;
David S. Millerf894cbf2012-07-02 21:52:24 -0700193 else if (skb)
194 return &ipv6_hdr(skb)->daddr;
David S. Miller39232972012-01-26 15:22:32 -0500195 return daddr;
196}
197
David S. Millerf894cbf2012-07-02 21:52:24 -0700198static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst,
199 struct sk_buff *skb,
200 const void *daddr)
David S. Millerd3aaeb32011-07-18 00:40:17 -0700201{
David S. Miller39232972012-01-26 15:22:32 -0500202 struct rt6_info *rt = (struct rt6_info *) dst;
203 struct neighbour *n;
204
David S. Millerf894cbf2012-07-02 21:52:24 -0700205 daddr = choose_neigh_daddr(rt, skb, daddr);
YOSHIFUJI Hideaki / 吉藤英明8e022ee2013-01-17 12:53:09 +0000206 n = __ipv6_neigh_lookup(dst->dev, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500207 if (n)
208 return n;
209 return neigh_create(&nd_tbl, daddr, dst->dev);
210}
211
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -0800212static struct dst_ops ip6_dst_ops_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 .family = AF_INET6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 .gc = ip6_dst_gc,
215 .gc_thresh = 1024,
216 .check = ip6_dst_check,
David S. Miller0dbaee32010-12-13 12:52:14 -0800217 .default_advmss = ip6_default_advmss,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000218 .mtu = ip6_mtu,
David S. Miller06582542011-01-27 14:58:42 -0800219 .cow_metrics = ipv6_cow_metrics,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 .destroy = ip6_dst_destroy,
221 .ifdown = ip6_dst_ifdown,
222 .negative_advice = ip6_negative_advice,
223 .link_failure = ip6_link_failure,
224 .update_pmtu = ip6_rt_update_pmtu,
David S. Miller6e157b62012-07-12 00:05:02 -0700225 .redirect = rt6_do_redirect,
Herbert Xu1ac06e02008-05-20 14:32:14 -0700226 .local_out = __ip6_local_out,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700227 .neigh_lookup = ip6_neigh_lookup,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228};
229
Steffen Klassertebb762f2011-11-23 02:12:51 +0000230static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
Roland Dreierec831ea2011-01-31 13:16:00 -0800231{
Steffen Klassert618f9bc2011-11-23 02:13:31 +0000232 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
233
234 return mtu ? : dst->dev->mtu;
Roland Dreierec831ea2011-01-31 13:16:00 -0800235}
236
David S. Miller6700c272012-07-17 03:29:28 -0700237static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
238 struct sk_buff *skb, u32 mtu)
David S. Miller14e50e52007-05-24 18:17:54 -0700239{
240}
241
David S. Miller6700c272012-07-17 03:29:28 -0700242static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
243 struct sk_buff *skb)
David S. Millerb587ee32012-07-12 00:39:24 -0700244{
245}
246
Held Bernhard0972ddb2011-04-24 22:07:32 +0000247static u32 *ip6_rt_blackhole_cow_metrics(struct dst_entry *dst,
248 unsigned long old)
249{
250 return NULL;
251}
252
David S. Miller14e50e52007-05-24 18:17:54 -0700253static struct dst_ops ip6_dst_blackhole_ops = {
254 .family = AF_INET6,
David S. Miller14e50e52007-05-24 18:17:54 -0700255 .destroy = ip6_dst_destroy,
256 .check = ip6_dst_check,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000257 .mtu = ip6_blackhole_mtu,
Eric Dumazet214f45c2011-02-18 11:39:01 -0800258 .default_advmss = ip6_default_advmss,
David S. Miller14e50e52007-05-24 18:17:54 -0700259 .update_pmtu = ip6_rt_blackhole_update_pmtu,
David S. Millerb587ee32012-07-12 00:39:24 -0700260 .redirect = ip6_rt_blackhole_redirect,
Held Bernhard0972ddb2011-04-24 22:07:32 +0000261 .cow_metrics = ip6_rt_blackhole_cow_metrics,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700262 .neigh_lookup = ip6_neigh_lookup,
David S. Miller14e50e52007-05-24 18:17:54 -0700263};
264
David S. Miller62fa8a82011-01-26 20:51:05 -0800265static const u32 ip6_template_metrics[RTAX_MAX] = {
Li RongQing14edd872012-10-24 14:01:18 +0800266 [RTAX_HOPLIMIT - 1] = 0,
David S. Miller62fa8a82011-01-26 20:51:05 -0800267};
268
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000269static const struct rt6_info ip6_null_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700270 .dst = {
271 .__refcnt = ATOMIC_INIT(1),
272 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000273 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700274 .error = -ENETUNREACH,
Changli Gaod8d1f302010-06-10 23:31:35 -0700275 .input = ip6_pkt_discard,
276 .output = ip6_pkt_discard_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 },
278 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700279 .rt6i_protocol = RTPROT_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 .rt6i_metric = ~(u32) 0,
281 .rt6i_ref = ATOMIC_INIT(1),
282};
283
Thomas Graf101367c2006-08-04 03:39:02 -0700284#ifdef CONFIG_IPV6_MULTIPLE_TABLES
285
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000286static const struct rt6_info ip6_prohibit_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700287 .dst = {
288 .__refcnt = ATOMIC_INIT(1),
289 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000290 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700291 .error = -EACCES,
Changli Gaod8d1f302010-06-10 23:31:35 -0700292 .input = ip6_pkt_prohibit,
293 .output = ip6_pkt_prohibit_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700294 },
295 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700296 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700297 .rt6i_metric = ~(u32) 0,
298 .rt6i_ref = ATOMIC_INIT(1),
299};
300
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000301static const struct rt6_info ip6_blk_hole_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700302 .dst = {
303 .__refcnt = ATOMIC_INIT(1),
304 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000305 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700306 .error = -EINVAL,
Changli Gaod8d1f302010-06-10 23:31:35 -0700307 .input = dst_discard,
Eric Dumazetaad88722014-04-15 13:47:15 -0400308 .output = dst_discard_sk,
Thomas Graf101367c2006-08-04 03:39:02 -0700309 },
310 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700311 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700312 .rt6i_metric = ~(u32) 0,
313 .rt6i_ref = ATOMIC_INIT(1),
314};
315
316#endif
317
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318/* allocate dst with ip6_dst_ops */
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700319static struct rt6_info *__ip6_dst_alloc(struct net *net,
320 struct net_device *dev,
Martin KaFai Lauad706862015-08-14 11:05:52 -0700321 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322{
David S. Miller97bab732012-06-09 22:36:36 -0700323 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +0000324 0, DST_OBSOLETE_FORCE_CHK, flags);
David S. Millercf911662011-04-28 14:31:47 -0700325
David S. Miller97bab732012-06-09 22:36:36 -0700326 if (rt) {
Steffen Klassert81048912012-07-05 23:37:09 +0000327 struct dst_entry *dst = &rt->dst;
328
329 memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000330 INIT_LIST_HEAD(&rt->rt6i_siblings);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700331 INIT_LIST_HEAD(&rt->rt6i_uncached);
David S. Miller97bab732012-06-09 22:36:36 -0700332 }
David S. Millercf911662011-04-28 14:31:47 -0700333 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334}
335
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700336static struct rt6_info *ip6_dst_alloc(struct net *net,
337 struct net_device *dev,
Martin KaFai Lauad706862015-08-14 11:05:52 -0700338 int flags)
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700339{
Martin KaFai Lauad706862015-08-14 11:05:52 -0700340 struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700341
342 if (rt) {
343 rt->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, GFP_ATOMIC);
344 if (rt->rt6i_pcpu) {
345 int cpu;
346
347 for_each_possible_cpu(cpu) {
348 struct rt6_info **p;
349
350 p = per_cpu_ptr(rt->rt6i_pcpu, cpu);
351 /* no one shares rt */
352 *p = NULL;
353 }
354 } else {
355 dst_destroy((struct dst_entry *)rt);
356 return NULL;
357 }
358 }
359
360 return rt;
361}
362
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363static void ip6_dst_destroy(struct dst_entry *dst)
364{
365 struct rt6_info *rt = (struct rt6_info *)dst;
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000366 struct dst_entry *from = dst->from;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700367 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700369 dst_destroy_metrics_generic(dst);
Markus Elfring87775312015-07-02 16:30:24 +0200370 free_percpu(rt->rt6i_pcpu);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700371 rt6_uncached_list_del(rt);
372
373 idev = rt->rt6i_idev;
David S. Miller38308472011-12-03 18:02:47 -0500374 if (idev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 rt->rt6i_idev = NULL;
376 in6_dev_put(idev);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900377 }
Gao feng1716a962012-04-06 00:13:10 +0000378
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000379 dst->from = NULL;
380 dst_release(from);
David S. Millerb3419362010-11-30 12:27:11 -0800381}
382
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
384 int how)
385{
386 struct rt6_info *rt = (struct rt6_info *)dst;
387 struct inet6_dev *idev = rt->rt6i_idev;
Denis V. Lunev5a3e55d2007-12-07 00:38:10 -0800388 struct net_device *loopback_dev =
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900389 dev_net(dev)->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
David S. Miller97cac082012-07-02 22:43:47 -0700391 if (dev != loopback_dev) {
392 if (idev && idev->dev == dev) {
393 struct inet6_dev *loopback_idev =
394 in6_dev_get(loopback_dev);
395 if (loopback_idev) {
396 rt->rt6i_idev = loopback_idev;
397 in6_dev_put(idev);
398 }
399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 }
401}
402
Eric Dumazeta50feda2012-05-18 18:57:34 +0000403static bool rt6_check_expired(const struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404{
Gao feng1716a962012-04-06 00:13:10 +0000405 if (rt->rt6i_flags & RTF_EXPIRES) {
406 if (time_after(jiffies, rt->dst.expires))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000407 return true;
Gao feng1716a962012-04-06 00:13:10 +0000408 } else if (rt->dst.from) {
Li RongQing3fd91fb2012-09-13 19:54:57 +0000409 return rt6_check_expired((struct rt6_info *) rt->dst.from);
Gao feng1716a962012-04-06 00:13:10 +0000410 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000411 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412}
413
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000414/* Multipath route selection:
415 * Hash based function using packet header and flowlabel.
416 * Adapted from fib_info_hashfn()
417 */
418static int rt6_info_hash_nhsfn(unsigned int candidate_count,
419 const struct flowi6 *fl6)
420{
421 unsigned int val = fl6->flowi6_proto;
422
YOSHIFUJI Hideaki / 吉藤英明c08977b2013-01-13 05:02:29 +0000423 val ^= ipv6_addr_hash(&fl6->daddr);
424 val ^= ipv6_addr_hash(&fl6->saddr);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000425
426 /* Work only if this not encapsulated */
427 switch (fl6->flowi6_proto) {
428 case IPPROTO_UDP:
429 case IPPROTO_TCP:
430 case IPPROTO_SCTP:
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000431 val ^= (__force u16)fl6->fl6_sport;
432 val ^= (__force u16)fl6->fl6_dport;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000433 break;
434
435 case IPPROTO_ICMPV6:
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000436 val ^= (__force u16)fl6->fl6_icmp_type;
437 val ^= (__force u16)fl6->fl6_icmp_code;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000438 break;
439 }
440 /* RFC6438 recommands to use flowlabel */
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000441 val ^= (__force u32)fl6->flowlabel;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000442
443 /* Perhaps, we need to tune, this function? */
444 val = val ^ (val >> 7) ^ (val >> 12);
445 return val % candidate_count;
446}
447
448static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200449 struct flowi6 *fl6, int oif,
450 int strict)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000451{
452 struct rt6_info *sibling, *next_sibling;
453 int route_choosen;
454
455 route_choosen = rt6_info_hash_nhsfn(match->rt6i_nsiblings + 1, fl6);
456 /* Don't change the route, if route_choosen == 0
457 * (siblings does not include ourself)
458 */
459 if (route_choosen)
460 list_for_each_entry_safe(sibling, next_sibling,
461 &match->rt6i_siblings, rt6i_siblings) {
462 route_choosen--;
463 if (route_choosen == 0) {
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200464 if (rt6_score_route(sibling, oif, strict) < 0)
465 break;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000466 match = sibling;
467 break;
468 }
469 }
470 return match;
471}
472
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473/*
Thomas Grafc71099a2006-08-04 23:20:06 -0700474 * Route lookup. Any table->tb6_lock is implied.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 */
476
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800477static inline struct rt6_info *rt6_device_match(struct net *net,
478 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000479 const struct in6_addr *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 int oif,
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700481 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
483 struct rt6_info *local = NULL;
484 struct rt6_info *sprt;
485
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900486 if (!oif && ipv6_addr_any(saddr))
487 goto out;
488
Changli Gaod8d1f302010-06-10 23:31:35 -0700489 for (sprt = rt; sprt; sprt = sprt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -0500490 struct net_device *dev = sprt->dst.dev;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900491
492 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 if (dev->ifindex == oif)
494 return sprt;
495 if (dev->flags & IFF_LOOPBACK) {
David S. Miller38308472011-12-03 18:02:47 -0500496 if (!sprt->rt6i_idev ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 sprt->rt6i_idev->dev->ifindex != oif) {
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700498 if (flags & RT6_LOOKUP_F_IFACE && oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 continue;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900500 if (local && (!oif ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 local->rt6i_idev->dev->ifindex == oif))
502 continue;
503 }
504 local = sprt;
505 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900506 } else {
507 if (ipv6_chk_addr(net, saddr, dev,
508 flags & RT6_LOOKUP_F_IFACE))
509 return sprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900511 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900513 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 if (local)
515 return local;
516
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700517 if (flags & RT6_LOOKUP_F_IFACE)
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800518 return net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900520out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 return rt;
522}
523
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800524#ifdef CONFIG_IPV6_ROUTER_PREF
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200525struct __rt6_probe_work {
526 struct work_struct work;
527 struct in6_addr target;
528 struct net_device *dev;
529};
530
531static void rt6_probe_deferred(struct work_struct *w)
532{
533 struct in6_addr mcaddr;
534 struct __rt6_probe_work *work =
535 container_of(w, struct __rt6_probe_work, work);
536
537 addrconf_addr_solict_mult(&work->target, &mcaddr);
538 ndisc_send_ns(work->dev, NULL, &work->target, &mcaddr, NULL);
539 dev_put(work->dev);
Michael Büsch662f5532015-02-08 10:14:07 +0100540 kfree(work);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200541}
542
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800543static void rt6_probe(struct rt6_info *rt)
544{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000545 struct neighbour *neigh;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800546 /*
547 * Okay, this does not seem to be appropriate
548 * for now, however, we need to check if it
549 * is really so; aka Router Reachability Probing.
550 *
551 * Router Reachability Probe MUST be rate-limited
552 * to no more than one per minute.
553 */
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000554 if (!rt || !(rt->rt6i_flags & RTF_GATEWAY))
Amerigo Wangfdd66812012-09-10 02:48:44 +0000555 return;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000556 rcu_read_lock_bh();
557 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
558 if (neigh) {
559 write_lock(&neigh->lock);
560 if (neigh->nud_state & NUD_VALID)
561 goto out;
YOSHIFUJI Hideaki / 吉藤英明7ff74a52013-01-17 12:53:02 +0000562 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000563
564 if (!neigh ||
YOSHIFUJI Hideaki52e16352006-03-20 17:05:47 -0800565 time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) {
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200566 struct __rt6_probe_work *work;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800567
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200568 work = kmalloc(sizeof(*work), GFP_ATOMIC);
569
570 if (neigh && work)
Jiri Benc7e980562013-12-11 13:48:20 +0100571 __neigh_set_probe_once(neigh);
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000572
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200573 if (neigh)
574 write_unlock(&neigh->lock);
575
576 if (work) {
577 INIT_WORK(&work->work, rt6_probe_deferred);
578 work->target = rt->rt6i_gateway;
579 dev_hold(rt->dst.dev);
580 work->dev = rt->dst.dev;
581 schedule_work(&work->work);
582 }
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000583 } else {
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000584out:
585 write_unlock(&neigh->lock);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000586 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000587 rcu_read_unlock_bh();
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800588}
589#else
590static inline void rt6_probe(struct rt6_info *rt)
591{
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800592}
593#endif
594
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595/*
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800596 * Default Router Selection (RFC 2461 6.3.6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 */
Dave Jonesb6f99a22007-03-22 12:27:49 -0700598static inline int rt6_check_dev(struct rt6_info *rt, int oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599{
David S. Millerd1918542011-12-28 20:19:20 -0500600 struct net_device *dev = rt->dst.dev;
David S. Miller161980f2007-04-06 11:42:27 -0700601 if (!oif || dev->ifindex == oif)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800602 return 2;
David S. Miller161980f2007-04-06 11:42:27 -0700603 if ((dev->flags & IFF_LOOPBACK) &&
604 rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
605 return 1;
606 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607}
608
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200609static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000611 struct neighbour *neigh;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200612 enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000613
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700614 if (rt->rt6i_flags & RTF_NONEXTHOP ||
615 !(rt->rt6i_flags & RTF_GATEWAY))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200616 return RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000617
618 rcu_read_lock_bh();
619 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
620 if (neigh) {
621 read_lock(&neigh->lock);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800622 if (neigh->nud_state & NUD_VALID)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200623 ret = RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800624#ifdef CONFIG_IPV6_ROUTER_PREF
Paul Marksa5a81f02012-12-03 10:26:54 +0000625 else if (!(neigh->nud_state & NUD_FAILED))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200626 ret = RT6_NUD_SUCCEED;
Jiri Benc7e980562013-12-11 13:48:20 +0100627 else
628 ret = RT6_NUD_FAIL_PROBE;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800629#endif
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000630 read_unlock(&neigh->lock);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200631 } else {
632 ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
Jiri Benc7e980562013-12-11 13:48:20 +0100633 RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR;
Paul Marksa5a81f02012-12-03 10:26:54 +0000634 }
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000635 rcu_read_unlock_bh();
636
Paul Marksa5a81f02012-12-03 10:26:54 +0000637 return ret;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800638}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800640static int rt6_score_route(struct rt6_info *rt, int oif,
641 int strict)
642{
Paul Marksa5a81f02012-12-03 10:26:54 +0000643 int m;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900644
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700645 m = rt6_check_dev(rt, oif);
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700646 if (!m && (strict & RT6_LOOKUP_F_IFACE))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200647 return RT6_NUD_FAIL_HARD;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800648#ifdef CONFIG_IPV6_ROUTER_PREF
649 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
650#endif
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200651 if (strict & RT6_LOOKUP_F_REACHABLE) {
652 int n = rt6_check_neigh(rt);
653 if (n < 0)
654 return n;
655 }
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800656 return m;
657}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
David S. Millerf11e6652007-03-24 20:36:25 -0700659static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200660 int *mpri, struct rt6_info *match,
661 bool *do_rr)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800662{
David S. Millerf11e6652007-03-24 20:36:25 -0700663 int m;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200664 bool match_do_rr = false;
David S. Millerf11e6652007-03-24 20:36:25 -0700665
666 if (rt6_check_expired(rt))
667 goto out;
668
669 m = rt6_score_route(rt, oif, strict);
Jiri Benc7e980562013-12-11 13:48:20 +0100670 if (m == RT6_NUD_FAIL_DO_RR) {
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200671 match_do_rr = true;
672 m = 0; /* lowest valid score */
Jiri Benc7e980562013-12-11 13:48:20 +0100673 } else if (m == RT6_NUD_FAIL_HARD) {
David S. Millerf11e6652007-03-24 20:36:25 -0700674 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700675 }
676
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200677 if (strict & RT6_LOOKUP_F_REACHABLE)
678 rt6_probe(rt);
679
Jiri Benc7e980562013-12-11 13:48:20 +0100680 /* note that m can be RT6_NUD_FAIL_PROBE at this point */
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200681 if (m > *mpri) {
682 *do_rr = match_do_rr;
683 *mpri = m;
684 match = rt;
685 }
David S. Millerf11e6652007-03-24 20:36:25 -0700686out:
687 return match;
688}
689
690static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
691 struct rt6_info *rr_head,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200692 u32 metric, int oif, int strict,
693 bool *do_rr)
David S. Millerf11e6652007-03-24 20:36:25 -0700694{
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700695 struct rt6_info *rt, *match, *cont;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800696 int mpri = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
David S. Millerf11e6652007-03-24 20:36:25 -0700698 match = NULL;
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700699 cont = NULL;
700 for (rt = rr_head; rt; rt = rt->dst.rt6_next) {
701 if (rt->rt6i_metric != metric) {
702 cont = rt;
703 break;
704 }
705
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200706 match = find_match(rt, oif, strict, &mpri, match, do_rr);
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700707 }
708
709 for (rt = fn->leaf; rt && rt != rr_head; rt = rt->dst.rt6_next) {
710 if (rt->rt6i_metric != metric) {
711 cont = rt;
712 break;
713 }
714
715 match = find_match(rt, oif, strict, &mpri, match, do_rr);
716 }
717
718 if (match || !cont)
719 return match;
720
721 for (rt = cont; rt; rt = rt->dst.rt6_next)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200722 match = find_match(rt, oif, strict, &mpri, match, do_rr);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800723
David S. Millerf11e6652007-03-24 20:36:25 -0700724 return match;
725}
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800726
David S. Millerf11e6652007-03-24 20:36:25 -0700727static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
728{
729 struct rt6_info *match, *rt0;
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800730 struct net *net;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200731 bool do_rr = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
David S. Millerf11e6652007-03-24 20:36:25 -0700733 rt0 = fn->rr_ptr;
734 if (!rt0)
735 fn->rr_ptr = rt0 = fn->leaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200737 match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict,
738 &do_rr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200740 if (do_rr) {
Changli Gaod8d1f302010-06-10 23:31:35 -0700741 struct rt6_info *next = rt0->dst.rt6_next;
David S. Millerf11e6652007-03-24 20:36:25 -0700742
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800743 /* no entries matched; do round-robin */
David S. Millerf11e6652007-03-24 20:36:25 -0700744 if (!next || next->rt6i_metric != rt0->rt6i_metric)
745 next = fn->leaf;
746
747 if (next != rt0)
748 fn->rr_ptr = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 }
750
David S. Millerd1918542011-12-28 20:19:20 -0500751 net = dev_net(rt0->dst.dev);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000752 return match ? match : net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753}
754
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700755static bool rt6_is_gw_or_nonexthop(const struct rt6_info *rt)
756{
757 return (rt->rt6i_flags & (RTF_NONEXTHOP | RTF_GATEWAY));
758}
759
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800760#ifdef CONFIG_IPV6_ROUTE_INFO
761int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000762 const struct in6_addr *gwaddr)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800763{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900764 struct net *net = dev_net(dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800765 struct route_info *rinfo = (struct route_info *) opt;
766 struct in6_addr prefix_buf, *prefix;
767 unsigned int pref;
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900768 unsigned long lifetime;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800769 struct rt6_info *rt;
770
771 if (len < sizeof(struct route_info)) {
772 return -EINVAL;
773 }
774
775 /* Sanity check for prefix_len and length */
776 if (rinfo->length > 3) {
777 return -EINVAL;
778 } else if (rinfo->prefix_len > 128) {
779 return -EINVAL;
780 } else if (rinfo->prefix_len > 64) {
781 if (rinfo->length < 2) {
782 return -EINVAL;
783 }
784 } else if (rinfo->prefix_len > 0) {
785 if (rinfo->length < 1) {
786 return -EINVAL;
787 }
788 }
789
790 pref = rinfo->route_pref;
791 if (pref == ICMPV6_ROUTER_PREF_INVALID)
Jens Rosenboom3933fc92009-09-10 06:25:11 +0000792 return -EINVAL;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800793
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900794 lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800795
796 if (rinfo->length == 3)
797 prefix = (struct in6_addr *)rinfo->prefix;
798 else {
799 /* this function is safe */
800 ipv6_addr_prefix(&prefix_buf,
801 (struct in6_addr *)rinfo->prefix,
802 rinfo->prefix_len);
803 prefix = &prefix_buf;
804 }
805
Duan Jiongf104a562013-11-08 09:56:53 +0800806 if (rinfo->prefix_len == 0)
807 rt = rt6_get_dflt_router(gwaddr, dev);
808 else
809 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len,
810 gwaddr, dev->ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800811
812 if (rt && !lifetime) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -0700813 ip6_del_rt(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800814 rt = NULL;
815 }
816
817 if (!rt && lifetime)
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800818 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800819 pref);
820 else if (rt)
821 rt->rt6i_flags = RTF_ROUTEINFO |
822 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
823
824 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +0000825 if (!addrconf_finite_timeout(lifetime))
826 rt6_clean_expires(rt);
827 else
828 rt6_set_expires(rt, jiffies + HZ * lifetime);
829
Amerigo Wang94e187c2012-10-29 00:13:19 +0000830 ip6_rt_put(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800831 }
832 return 0;
833}
834#endif
835
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700836static struct fib6_node* fib6_backtrack(struct fib6_node *fn,
837 struct in6_addr *saddr)
838{
839 struct fib6_node *pn;
840 while (1) {
841 if (fn->fn_flags & RTN_TL_ROOT)
842 return NULL;
843 pn = fn->parent;
844 if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn)
845 fn = fib6_lookup(FIB6_SUBTREE(pn), NULL, saddr);
846 else
847 fn = pn;
848 if (fn->fn_flags & RTN_RTINFO)
849 return fn;
850 }
851}
Thomas Grafc71099a2006-08-04 23:20:06 -0700852
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800853static struct rt6_info *ip6_pol_route_lookup(struct net *net,
854 struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500855 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856{
857 struct fib6_node *fn;
858 struct rt6_info *rt;
859
Thomas Grafc71099a2006-08-04 23:20:06 -0700860 read_lock_bh(&table->tb6_lock);
David S. Miller4c9483b2011-03-12 16:22:43 -0500861 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -0700862restart:
863 rt = fn->leaf;
David S. Miller4c9483b2011-03-12 16:22:43 -0500864 rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000865 if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0)
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200866 rt = rt6_multipath_select(rt, fl6, fl6->flowi6_oif, flags);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700867 if (rt == net->ipv6.ip6_null_entry) {
868 fn = fib6_backtrack(fn, &fl6->saddr);
869 if (fn)
870 goto restart;
871 }
Changli Gaod8d1f302010-06-10 23:31:35 -0700872 dst_use(&rt->dst, jiffies);
Thomas Grafc71099a2006-08-04 23:20:06 -0700873 read_unlock_bh(&table->tb6_lock);
Thomas Grafc71099a2006-08-04 23:20:06 -0700874 return rt;
875
876}
877
Ian Morris67ba4152014-08-24 21:53:10 +0100878struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
Florian Westphalea6e5742011-09-05 16:05:44 +0200879 int flags)
880{
881 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup);
882}
883EXPORT_SYMBOL_GPL(ip6_route_lookup);
884
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900885struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
886 const struct in6_addr *saddr, int oif, int strict)
Thomas Grafc71099a2006-08-04 23:20:06 -0700887{
David S. Miller4c9483b2011-03-12 16:22:43 -0500888 struct flowi6 fl6 = {
889 .flowi6_oif = oif,
890 .daddr = *daddr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700891 };
892 struct dst_entry *dst;
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700893 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
Thomas Grafc71099a2006-08-04 23:20:06 -0700894
Thomas Grafadaa70b2006-10-13 15:01:03 -0700895 if (saddr) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500896 memcpy(&fl6.saddr, saddr, sizeof(*saddr));
Thomas Grafadaa70b2006-10-13 15:01:03 -0700897 flags |= RT6_LOOKUP_F_HAS_SADDR;
898 }
899
David S. Miller4c9483b2011-03-12 16:22:43 -0500900 dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup);
Thomas Grafc71099a2006-08-04 23:20:06 -0700901 if (dst->error == 0)
902 return (struct rt6_info *) dst;
903
904 dst_release(dst);
905
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 return NULL;
907}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900908EXPORT_SYMBOL(rt6_lookup);
909
Thomas Grafc71099a2006-08-04 23:20:06 -0700910/* ip6_ins_rt is called with FREE table->tb6_lock.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 It takes new route entry, the addition fails by any reason the
912 route is freed. In any case, if caller does not hold it, it may
913 be destroyed.
914 */
915
Michal Kubečeke5fd3872014-03-27 13:04:08 +0100916static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info,
Florian Westphale715b6d2015-01-05 23:57:44 +0100917 struct mx6_config *mxc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918{
919 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -0700920 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921
Thomas Grafc71099a2006-08-04 23:20:06 -0700922 table = rt->rt6i_table;
923 write_lock_bh(&table->tb6_lock);
Florian Westphale715b6d2015-01-05 23:57:44 +0100924 err = fib6_add(&table->tb6_root, rt, info, mxc);
Thomas Grafc71099a2006-08-04 23:20:06 -0700925 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
927 return err;
928}
929
Thomas Graf40e22e82006-08-22 00:00:45 -0700930int ip6_ins_rt(struct rt6_info *rt)
931{
Florian Westphale715b6d2015-01-05 23:57:44 +0100932 struct nl_info info = { .nl_net = dev_net(rt->dst.dev), };
933 struct mx6_config mxc = { .mx = NULL, };
934
935 return __ip6_ins_rt(rt, &info, &mxc);
Thomas Graf40e22e82006-08-22 00:00:45 -0700936}
937
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700938static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort,
939 const struct in6_addr *daddr,
940 const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 struct rt6_info *rt;
943
944 /*
945 * Clone the route.
946 */
947
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700948 if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU))
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700949 ort = (struct rt6_info *)ort->dst.from;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
Martin KaFai Lauad706862015-08-14 11:05:52 -0700951 rt = __ip6_dst_alloc(dev_net(ort->dst.dev), ort->dst.dev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700953 if (!rt)
954 return NULL;
955
956 ip6_rt_copy_init(rt, ort);
957 rt->rt6i_flags |= RTF_CACHE;
958 rt->rt6i_metric = 0;
959 rt->dst.flags |= DST_HOST;
960 rt->rt6i_dst.addr = *daddr;
961 rt->rt6i_dst.plen = 128;
962
963 if (!rt6_is_gw_or_nonexthop(ort)) {
964 if (ort->rt6i_dst.plen != 128 &&
965 ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
966 rt->rt6i_flags |= RTF_ANYCAST;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700968 if (rt->rt6i_src.plen && saddr) {
969 rt->rt6i_src.addr = *saddr;
970 rt->rt6i_src.plen = 128;
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700971 }
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700972#endif
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800973 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800975 return rt;
976}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700978static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt)
979{
980 struct rt6_info *pcpu_rt;
981
982 pcpu_rt = __ip6_dst_alloc(dev_net(rt->dst.dev),
Martin KaFai Lauad706862015-08-14 11:05:52 -0700983 rt->dst.dev, rt->dst.flags);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700984
985 if (!pcpu_rt)
986 return NULL;
987 ip6_rt_copy_init(pcpu_rt, rt);
988 pcpu_rt->rt6i_protocol = rt->rt6i_protocol;
989 pcpu_rt->rt6i_flags |= RTF_PCPU;
990 return pcpu_rt;
991}
992
993/* It should be called with read_lock_bh(&tb6_lock) acquired */
994static struct rt6_info *rt6_get_pcpu_route(struct rt6_info *rt)
995{
Martin KaFai Laua73e4192015-08-14 11:05:53 -0700996 struct rt6_info *pcpu_rt, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700997
998 p = this_cpu_ptr(rt->rt6i_pcpu);
999 pcpu_rt = *p;
1000
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001001 if (pcpu_rt) {
1002 dst_hold(&pcpu_rt->dst);
1003 rt6_dst_from_metrics_check(pcpu_rt);
1004 }
1005 return pcpu_rt;
1006}
1007
1008static struct rt6_info *rt6_make_pcpu_route(struct rt6_info *rt)
1009{
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001010 struct fib6_table *table = rt->rt6i_table;
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001011 struct rt6_info *pcpu_rt, *prev, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001012
1013 pcpu_rt = ip6_rt_pcpu_alloc(rt);
1014 if (!pcpu_rt) {
1015 struct net *net = dev_net(rt->dst.dev);
1016
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001017 dst_hold(&net->ipv6.ip6_null_entry->dst);
1018 return net->ipv6.ip6_null_entry;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001019 }
1020
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001021 read_lock_bh(&table->tb6_lock);
1022 if (rt->rt6i_pcpu) {
1023 p = this_cpu_ptr(rt->rt6i_pcpu);
1024 prev = cmpxchg(p, NULL, pcpu_rt);
1025 if (prev) {
1026 /* If someone did it before us, return prev instead */
1027 dst_destroy(&pcpu_rt->dst);
1028 pcpu_rt = prev;
1029 }
1030 } else {
1031 /* rt has been removed from the fib6 tree
1032 * before we have a chance to acquire the read_lock.
1033 * In this case, don't brother to create a pcpu rt
1034 * since rt is going away anyway. The next
1035 * dst_check() will trigger a re-lookup.
1036 */
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001037 dst_destroy(&pcpu_rt->dst);
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001038 pcpu_rt = rt;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001039 }
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001040 dst_hold(&pcpu_rt->dst);
1041 rt6_dst_from_metrics_check(pcpu_rt);
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001042 read_unlock_bh(&table->tb6_lock);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001043 return pcpu_rt;
1044}
1045
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001046static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif,
David S. Miller4c9483b2011-03-12 16:22:43 -05001047 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048{
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001049 struct fib6_node *fn, *saved_fn;
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001050 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001051 int strict = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001053 strict |= flags & RT6_LOOKUP_F_IFACE;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001054 if (net->ipv6.devconf_all->forwarding == 0)
1055 strict |= RT6_LOOKUP_F_REACHABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056
Thomas Grafc71099a2006-08-04 23:20:06 -07001057 read_lock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058
David S. Miller4c9483b2011-03-12 16:22:43 -05001059 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001060 saved_fn = fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001062redo_rt6_select:
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001063 rt = rt6_select(fn, oif, strict);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +02001064 if (rt->rt6i_nsiblings)
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001065 rt = rt6_multipath_select(rt, fl6, oif, strict);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001066 if (rt == net->ipv6.ip6_null_entry) {
1067 fn = fib6_backtrack(fn, &fl6->saddr);
1068 if (fn)
1069 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001070 else if (strict & RT6_LOOKUP_F_REACHABLE) {
1071 /* also consider unreachable route */
1072 strict &= ~RT6_LOOKUP_F_REACHABLE;
1073 fn = saved_fn;
1074 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001075 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001076 }
1077
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -08001078
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001079 if (rt == net->ipv6.ip6_null_entry || (rt->rt6i_flags & RTF_CACHE)) {
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001080 dst_use(&rt->dst, jiffies);
1081 read_unlock_bh(&table->tb6_lock);
1082
1083 rt6_dst_from_metrics_check(rt);
1084 return rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001085 } else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) &&
1086 !(rt->rt6i_flags & RTF_GATEWAY))) {
1087 /* Create a RTF_CACHE clone which will not be
1088 * owned by the fib6 tree. It is for the special case where
1089 * the daddr in the skb during the neighbor look-up is different
1090 * from the fl6->daddr used to look-up route here.
1091 */
Thomas Grafc71099a2006-08-04 23:20:06 -07001092
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001093 struct rt6_info *uncached_rt;
1094
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001095 dst_use(&rt->dst, jiffies);
1096 read_unlock_bh(&table->tb6_lock);
1097
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001098 uncached_rt = ip6_rt_cache_alloc(rt, &fl6->daddr, NULL);
1099 dst_release(&rt->dst);
1100
1101 if (uncached_rt)
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07001102 rt6_uncached_list_add(uncached_rt);
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001103 else
1104 uncached_rt = net->ipv6.ip6_null_entry;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001105
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001106 dst_hold(&uncached_rt->dst);
1107 return uncached_rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001108
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001109 } else {
1110 /* Get a percpu copy */
1111
1112 struct rt6_info *pcpu_rt;
1113
1114 rt->dst.lastuse = jiffies;
1115 rt->dst.__use++;
1116 pcpu_rt = rt6_get_pcpu_route(rt);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001117
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001118 if (pcpu_rt) {
1119 read_unlock_bh(&table->tb6_lock);
1120 } else {
1121 /* We have to do the read_unlock first
1122 * because rt6_make_pcpu_route() may trigger
1123 * ip6_dst_gc() which will take the write_lock.
1124 */
1125 dst_hold(&rt->dst);
1126 read_unlock_bh(&table->tb6_lock);
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001127 pcpu_rt = rt6_make_pcpu_route(rt);
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001128 dst_release(&rt->dst);
1129 }
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001130
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001131 return pcpu_rt;
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001132
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001133 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001134}
1135
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001136static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -05001137 struct flowi6 *fl6, int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001138{
David S. Miller4c9483b2011-03-12 16:22:43 -05001139 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001140}
1141
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001142static struct dst_entry *ip6_route_input_lookup(struct net *net,
1143 struct net_device *dev,
1144 struct flowi6 *fl6, int flags)
1145{
1146 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
1147 flags |= RT6_LOOKUP_F_IFACE;
1148
1149 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_input);
1150}
1151
Thomas Grafc71099a2006-08-04 23:20:06 -07001152void ip6_route_input(struct sk_buff *skb)
1153{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001154 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001155 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001156 int flags = RT6_LOOKUP_F_HAS_SADDR;
David S. Miller4c9483b2011-03-12 16:22:43 -05001157 struct flowi6 fl6 = {
1158 .flowi6_iif = skb->dev->ifindex,
1159 .daddr = iph->daddr,
1160 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001161 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -05001162 .flowi6_mark = skb->mark,
1163 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -07001164 };
Thomas Grafadaa70b2006-10-13 15:01:03 -07001165
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001166 skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -07001167}
1168
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001169static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -05001170 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07001171{
David S. Miller4c9483b2011-03-12 16:22:43 -05001172 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -07001173}
1174
Ian Morris67ba4152014-08-24 21:53:10 +01001175struct dst_entry *ip6_route_output(struct net *net, const struct sock *sk,
David S. Miller4c9483b2011-03-12 16:22:43 -05001176 struct flowi6 *fl6)
Thomas Grafc71099a2006-08-04 23:20:06 -07001177{
1178 int flags = 0;
1179
Pavel Emelyanov1fb94892012-08-08 21:53:36 +00001180 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +00001181
David S. Miller4c9483b2011-03-12 16:22:43 -05001182 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001183 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -07001184
David S. Miller4c9483b2011-03-12 16:22:43 -05001185 if (!ipv6_addr_any(&fl6->saddr))
Thomas Grafadaa70b2006-10-13 15:01:03 -07001186 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +00001187 else if (sk)
1188 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001189
David S. Miller4c9483b2011-03-12 16:22:43 -05001190 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +09001192EXPORT_SYMBOL(ip6_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193
David S. Miller2774c132011-03-01 14:59:04 -08001194struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -07001195{
David S. Miller5c1e6aa2011-04-28 14:13:38 -07001196 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
David S. Miller14e50e52007-05-24 18:17:54 -07001197 struct dst_entry *new = NULL;
1198
David S. Millerf5b0a872012-07-19 12:31:33 -07001199 rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, DST_OBSOLETE_NONE, 0);
David S. Miller14e50e52007-05-24 18:17:54 -07001200 if (rt) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001201 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -07001202
Steffen Klassert81048912012-07-05 23:37:09 +00001203 memset(new + 1, 0, sizeof(*rt) - sizeof(*new));
Steffen Klassert81048912012-07-05 23:37:09 +00001204
David S. Miller14e50e52007-05-24 18:17:54 -07001205 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08001206 new->input = dst_discard;
Eric Dumazetaad88722014-04-15 13:47:15 -04001207 new->output = dst_discard_sk;
David S. Miller14e50e52007-05-24 18:17:54 -07001208
Eric Dumazet21efcfa2011-07-19 20:18:36 +00001209 if (dst_metrics_read_only(&ort->dst))
1210 new->_metrics = ort->dst._metrics;
1211 else
1212 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07001213 rt->rt6i_idev = ort->rt6i_idev;
1214 if (rt->rt6i_idev)
1215 in6_dev_hold(rt->rt6i_idev);
David S. Miller14e50e52007-05-24 18:17:54 -07001216
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001217 rt->rt6i_gateway = ort->rt6i_gateway;
Gao feng1716a962012-04-06 00:13:10 +00001218 rt->rt6i_flags = ort->rt6i_flags;
David S. Miller14e50e52007-05-24 18:17:54 -07001219 rt->rt6i_metric = 0;
1220
1221 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
1222#ifdef CONFIG_IPV6_SUBTREES
1223 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1224#endif
1225
1226 dst_free(new);
1227 }
1228
David S. Miller69ead7a2011-03-01 14:45:33 -08001229 dst_release(dst_orig);
1230 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07001231}
David S. Miller14e50e52007-05-24 18:17:54 -07001232
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233/*
1234 * Destination cache support functions
1235 */
1236
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001237static void rt6_dst_from_metrics_check(struct rt6_info *rt)
1238{
1239 if (rt->dst.from &&
1240 dst_metrics_ptr(&rt->dst) != dst_metrics_ptr(rt->dst.from))
1241 dst_init_metrics(&rt->dst, dst_metrics_ptr(rt->dst.from), true);
1242}
1243
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001244static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie)
1245{
1246 if (!rt->rt6i_node || (rt->rt6i_node->fn_sernum != cookie))
1247 return NULL;
1248
1249 if (rt6_check_expired(rt))
1250 return NULL;
1251
1252 return &rt->dst;
1253}
1254
1255static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, u32 cookie)
1256{
1257 if (rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
1258 rt6_check((struct rt6_info *)(rt->dst.from), cookie))
1259 return &rt->dst;
1260 else
1261 return NULL;
1262}
1263
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
1265{
1266 struct rt6_info *rt;
1267
1268 rt = (struct rt6_info *) dst;
1269
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00001270 /* All IPV6 dsts are created with ->obsolete set to the value
1271 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
1272 * into this function always.
1273 */
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02001274
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001275 rt6_dst_from_metrics_check(rt);
1276
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001277 if ((rt->rt6i_flags & RTF_PCPU) || unlikely(dst->flags & DST_NOCACHE))
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001278 return rt6_dst_from_check(rt, cookie);
1279 else
1280 return rt6_check(rt, cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281}
1282
1283static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
1284{
1285 struct rt6_info *rt = (struct rt6_info *) dst;
1286
1287 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001288 if (rt->rt6i_flags & RTF_CACHE) {
1289 if (rt6_check_expired(rt)) {
1290 ip6_del_rt(rt);
1291 dst = NULL;
1292 }
1293 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001295 dst = NULL;
1296 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001298 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299}
1300
1301static void ip6_link_failure(struct sk_buff *skb)
1302{
1303 struct rt6_info *rt;
1304
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00001305 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306
Eric Dumazetadf30902009-06-02 05:19:30 +00001307 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 if (rt) {
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001309 if (rt->rt6i_flags & RTF_CACHE) {
1310 dst_hold(&rt->dst);
1311 if (ip6_del_rt(rt))
1312 dst_free(&rt->dst);
1313 } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 rt->rt6i_node->fn_sernum = -1;
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001315 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 }
1317}
1318
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001319static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
1320{
1321 struct net *net = dev_net(rt->dst.dev);
1322
1323 rt->rt6i_flags |= RTF_MODIFIED;
1324 rt->rt6i_pmtu = mtu;
1325 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
1326}
1327
1328static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
1329 const struct ipv6hdr *iph, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330{
Ian Morris67ba4152014-08-24 21:53:10 +01001331 struct rt6_info *rt6 = (struct rt6_info *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001333 if (rt6->rt6i_flags & RTF_LOCAL)
1334 return;
1335
David S. Miller81aded22012-06-15 14:54:11 -07001336 dst_confirm(dst);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001337 mtu = max_t(u32, mtu, IPV6_MIN_MTU);
1338 if (mtu >= dst_mtu(dst))
1339 return;
David S. Miller81aded22012-06-15 14:54:11 -07001340
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001341 if (rt6->rt6i_flags & RTF_CACHE) {
1342 rt6_do_update_pmtu(rt6, mtu);
1343 } else {
1344 const struct in6_addr *daddr, *saddr;
1345 struct rt6_info *nrt6;
Hagen Paul Pfeifer9d289712015-01-15 22:34:25 +01001346
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001347 if (iph) {
1348 daddr = &iph->daddr;
1349 saddr = &iph->saddr;
1350 } else if (sk) {
1351 daddr = &sk->sk_v6_daddr;
1352 saddr = &inet6_sk(sk)->saddr;
1353 } else {
1354 return;
1355 }
1356 nrt6 = ip6_rt_cache_alloc(rt6, daddr, saddr);
1357 if (nrt6) {
1358 rt6_do_update_pmtu(nrt6, mtu);
1359
1360 /* ip6_ins_rt(nrt6) will bump the
1361 * rt6->rt6i_node->fn_sernum
1362 * which will fail the next rt6_check() and
1363 * invalidate the sk->sk_dst_cache.
1364 */
1365 ip6_ins_rt(nrt6);
1366 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 }
1368}
1369
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001370static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
1371 struct sk_buff *skb, u32 mtu)
1372{
1373 __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu);
1374}
1375
David S. Miller42ae66c2012-06-15 20:01:57 -07001376void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
1377 int oif, u32 mark)
David S. Miller81aded22012-06-15 14:54:11 -07001378{
1379 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1380 struct dst_entry *dst;
1381 struct flowi6 fl6;
1382
1383 memset(&fl6, 0, sizeof(fl6));
1384 fl6.flowi6_oif = oif;
Lorenzo Colitti1b3c61d2014-05-13 10:17:34 -07001385 fl6.flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark);
David S. Miller81aded22012-06-15 14:54:11 -07001386 fl6.daddr = iph->daddr;
1387 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001388 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller81aded22012-06-15 14:54:11 -07001389
1390 dst = ip6_route_output(net, NULL, &fl6);
1391 if (!dst->error)
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001392 __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07001393 dst_release(dst);
1394}
1395EXPORT_SYMBOL_GPL(ip6_update_pmtu);
1396
1397void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
1398{
1399 ip6_update_pmtu(skb, sock_net(sk), mtu,
1400 sk->sk_bound_dev_if, sk->sk_mark);
1401}
1402EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
1403
Duan Jiongb55b76b2013-09-04 19:44:21 +08001404/* Handle redirects */
1405struct ip6rd_flowi {
1406 struct flowi6 fl6;
1407 struct in6_addr gateway;
1408};
1409
1410static struct rt6_info *__ip6_route_redirect(struct net *net,
1411 struct fib6_table *table,
1412 struct flowi6 *fl6,
1413 int flags)
1414{
1415 struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
1416 struct rt6_info *rt;
1417 struct fib6_node *fn;
1418
1419 /* Get the "current" route for this destination and
1420 * check if the redirect has come from approriate router.
1421 *
1422 * RFC 4861 specifies that redirects should only be
1423 * accepted if they come from the nexthop to the target.
1424 * Due to the way the routes are chosen, this notion
1425 * is a bit fuzzy and one might need to check all possible
1426 * routes.
1427 */
1428
1429 read_lock_bh(&table->tb6_lock);
1430 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
1431restart:
1432 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
1433 if (rt6_check_expired(rt))
1434 continue;
1435 if (rt->dst.error)
1436 break;
1437 if (!(rt->rt6i_flags & RTF_GATEWAY))
1438 continue;
1439 if (fl6->flowi6_oif != rt->dst.dev->ifindex)
1440 continue;
1441 if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway))
1442 continue;
1443 break;
1444 }
1445
1446 if (!rt)
1447 rt = net->ipv6.ip6_null_entry;
1448 else if (rt->dst.error) {
1449 rt = net->ipv6.ip6_null_entry;
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001450 goto out;
1451 }
1452
1453 if (rt == net->ipv6.ip6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001454 fn = fib6_backtrack(fn, &fl6->saddr);
1455 if (fn)
1456 goto restart;
Duan Jiongb55b76b2013-09-04 19:44:21 +08001457 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001458
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001459out:
Duan Jiongb55b76b2013-09-04 19:44:21 +08001460 dst_hold(&rt->dst);
1461
1462 read_unlock_bh(&table->tb6_lock);
1463
1464 return rt;
1465};
1466
1467static struct dst_entry *ip6_route_redirect(struct net *net,
1468 const struct flowi6 *fl6,
1469 const struct in6_addr *gateway)
1470{
1471 int flags = RT6_LOOKUP_F_HAS_SADDR;
1472 struct ip6rd_flowi rdfl;
1473
1474 rdfl.fl6 = *fl6;
1475 rdfl.gateway = *gateway;
1476
1477 return fib6_rule_lookup(net, &rdfl.fl6,
1478 flags, __ip6_route_redirect);
1479}
1480
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001481void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark)
1482{
1483 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1484 struct dst_entry *dst;
1485 struct flowi6 fl6;
1486
1487 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001488 fl6.flowi6_iif = LOOPBACK_IFINDEX;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001489 fl6.flowi6_oif = oif;
1490 fl6.flowi6_mark = mark;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001491 fl6.daddr = iph->daddr;
1492 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001493 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001494
Duan Jiongb55b76b2013-09-04 19:44:21 +08001495 dst = ip6_route_redirect(net, &fl6, &ipv6_hdr(skb)->saddr);
1496 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001497 dst_release(dst);
1498}
1499EXPORT_SYMBOL_GPL(ip6_redirect);
1500
Duan Jiongc92a59e2013-08-22 12:07:35 +08001501void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
1502 u32 mark)
1503{
1504 const struct ipv6hdr *iph = ipv6_hdr(skb);
1505 const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
1506 struct dst_entry *dst;
1507 struct flowi6 fl6;
1508
1509 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001510 fl6.flowi6_iif = LOOPBACK_IFINDEX;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001511 fl6.flowi6_oif = oif;
1512 fl6.flowi6_mark = mark;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001513 fl6.daddr = msg->dest;
1514 fl6.saddr = iph->daddr;
1515
Duan Jiongb55b76b2013-09-04 19:44:21 +08001516 dst = ip6_route_redirect(net, &fl6, &iph->saddr);
1517 rt6_do_redirect(dst, NULL, skb);
Duan Jiongc92a59e2013-08-22 12:07:35 +08001518 dst_release(dst);
1519}
1520
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001521void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
1522{
1523 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark);
1524}
1525EXPORT_SYMBOL_GPL(ip6_sk_redirect);
1526
David S. Miller0dbaee32010-12-13 12:52:14 -08001527static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528{
David S. Miller0dbaee32010-12-13 12:52:14 -08001529 struct net_device *dev = dst->dev;
1530 unsigned int mtu = dst_mtu(dst);
1531 struct net *net = dev_net(dev);
1532
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
1534
Daniel Lezcano55786892008-03-04 13:47:47 -08001535 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
1536 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537
1538 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001539 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
1540 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
1541 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 * rely only on pmtu discovery"
1543 */
1544 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
1545 mtu = IPV6_MAXPLEN;
1546 return mtu;
1547}
1548
Steffen Klassertebb762f2011-11-23 02:12:51 +00001549static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08001550{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001551 const struct rt6_info *rt = (const struct rt6_info *)dst;
1552 unsigned int mtu = rt->rt6i_pmtu;
David S. Millerd33e4552010-12-14 13:01:14 -08001553 struct inet6_dev *idev;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001554
1555 if (mtu)
Eric Dumazet30f78d82014-04-10 21:23:36 -07001556 goto out;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001557
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001558 mtu = dst_metric_raw(dst, RTAX_MTU);
1559 if (mtu)
1560 goto out;
1561
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001562 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08001563
1564 rcu_read_lock();
1565 idev = __in6_dev_get(dst->dev);
1566 if (idev)
1567 mtu = idev->cnf.mtu6;
1568 rcu_read_unlock();
1569
Eric Dumazet30f78d82014-04-10 21:23:36 -07001570out:
1571 return min_t(unsigned int, mtu, IP6_MAX_MTU);
David S. Millerd33e4552010-12-14 13:01:14 -08001572}
1573
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001574static struct dst_entry *icmp6_dst_gc_list;
1575static DEFINE_SPINLOCK(icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001576
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001577struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05001578 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579{
David S. Miller87a11572011-12-06 17:04:13 -05001580 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 struct rt6_info *rt;
1582 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001583 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584
David S. Miller38308472011-12-03 18:02:47 -05001585 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00001586 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587
Martin KaFai Lauad706862015-08-14 11:05:52 -07001588 rt = ip6_dst_alloc(net, dev, 0);
David S. Miller38308472011-12-03 18:02:47 -05001589 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05001591 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 goto out;
1593 }
1594
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001595 rt->dst.flags |= DST_HOST;
1596 rt->dst.output = ip6_output;
Changli Gaod8d1f302010-06-10 23:31:35 -07001597 atomic_set(&rt->dst.__refcnt, 1);
Julian Anastasov550bab42013-10-20 15:43:04 +03001598 rt->rt6i_gateway = fl6->daddr;
David S. Miller87a11572011-12-06 17:04:13 -05001599 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001600 rt->rt6i_dst.plen = 128;
1601 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08001602 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001604 spin_lock_bh(&icmp6_dst_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001605 rt->dst.next = icmp6_dst_gc_list;
1606 icmp6_dst_gc_list = &rt->dst;
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001607 spin_unlock_bh(&icmp6_dst_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608
Daniel Lezcano55786892008-03-04 13:47:47 -08001609 fib6_force_start_gc(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610
David S. Miller87a11572011-12-06 17:04:13 -05001611 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
1612
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613out:
David S. Miller87a11572011-12-06 17:04:13 -05001614 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615}
1616
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001617int icmp6_dst_gc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618{
Hagen Paul Pfeifere9476e92011-02-25 05:45:19 +00001619 struct dst_entry *dst, **pprev;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001620 int more = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001622 spin_lock_bh(&icmp6_dst_lock);
1623 pprev = &icmp6_dst_gc_list;
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001624
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 while ((dst = *pprev) != NULL) {
1626 if (!atomic_read(&dst->__refcnt)) {
1627 *pprev = dst->next;
1628 dst_free(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 } else {
1630 pprev = &dst->next;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001631 ++more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 }
1633 }
1634
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001635 spin_unlock_bh(&icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001636
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001637 return more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638}
1639
David S. Miller1e493d12008-09-10 17:27:15 -07001640static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg),
1641 void *arg)
1642{
1643 struct dst_entry *dst, **pprev;
1644
1645 spin_lock_bh(&icmp6_dst_lock);
1646 pprev = &icmp6_dst_gc_list;
1647 while ((dst = *pprev) != NULL) {
1648 struct rt6_info *rt = (struct rt6_info *) dst;
1649 if (func(rt, arg)) {
1650 *pprev = dst->next;
1651 dst_free(dst);
1652 } else {
1653 pprev = &dst->next;
1654 }
1655 }
1656 spin_unlock_bh(&icmp6_dst_lock);
1657}
1658
Daniel Lezcano569d3642008-01-18 03:56:57 -08001659static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660{
Alexey Dobriyan86393e52009-08-29 01:34:49 +00001661 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08001662 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
1663 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
1664 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
1665 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
1666 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001667 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668
Eric Dumazetfc66f952010-10-08 06:37:34 +00001669 entries = dst_entries_get_fast(ops);
Michal Kubeček49a18d82013-08-01 10:04:24 +02001670 if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00001671 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 goto out;
1673
Benjamin Thery6891a342008-03-04 13:49:47 -08001674 net->ipv6.ip6_rt_gc_expire++;
Li RongQing14956642014-05-19 17:30:28 +08001675 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
Eric Dumazetfc66f952010-10-08 06:37:34 +00001676 entries = dst_entries_get_slow(ops);
1677 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08001678 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08001680 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001681 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682}
1683
Florian Westphale715b6d2015-01-05 23:57:44 +01001684static int ip6_convert_metrics(struct mx6_config *mxc,
1685 const struct fib6_config *cfg)
1686{
1687 struct nlattr *nla;
1688 int remaining;
1689 u32 *mp;
1690
Ian Morris63159f22015-03-29 14:00:04 +01001691 if (!cfg->fc_mx)
Florian Westphale715b6d2015-01-05 23:57:44 +01001692 return 0;
1693
1694 mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
1695 if (unlikely(!mp))
1696 return -ENOMEM;
1697
1698 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
1699 int type = nla_type(nla);
1700
1701 if (type) {
Daniel Borkmannea697632015-01-05 23:57:47 +01001702 u32 val;
1703
Florian Westphale715b6d2015-01-05 23:57:44 +01001704 if (unlikely(type > RTAX_MAX))
1705 goto err;
Daniel Borkmannea697632015-01-05 23:57:47 +01001706 if (type == RTAX_CC_ALGO) {
1707 char tmp[TCP_CA_NAME_MAX];
Florian Westphale715b6d2015-01-05 23:57:44 +01001708
Daniel Borkmannea697632015-01-05 23:57:47 +01001709 nla_strlcpy(tmp, nla, sizeof(tmp));
1710 val = tcp_ca_get_key_by_name(tmp);
1711 if (val == TCP_CA_UNSPEC)
1712 goto err;
1713 } else {
1714 val = nla_get_u32(nla);
1715 }
1716
1717 mp[type - 1] = val;
Florian Westphale715b6d2015-01-05 23:57:44 +01001718 __set_bit(type - 1, mxc->mx_valid);
1719 }
1720 }
1721
1722 mxc->mx = mp;
1723
1724 return 0;
1725 err:
1726 kfree(mp);
1727 return -EINVAL;
1728}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729
Thomas Graf86872cb2006-08-22 00:01:08 -07001730int ip6_route_add(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731{
1732 int err;
Daniel Lezcano55786892008-03-04 13:47:47 -08001733 struct net *net = cfg->fc_nlinfo.nl_net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 struct rt6_info *rt = NULL;
1735 struct net_device *dev = NULL;
1736 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001737 struct fib6_table *table;
Florian Westphale715b6d2015-01-05 23:57:44 +01001738 struct mx6_config mxc = { .mx = NULL, };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 int addr_type;
1740
Thomas Graf86872cb2006-08-22 00:01:08 -07001741 if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 return -EINVAL;
1743#ifndef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001744 if (cfg->fc_src_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 return -EINVAL;
1746#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07001747 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08001749 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 if (!dev)
1751 goto out;
1752 idev = in6_dev_get(dev);
1753 if (!idev)
1754 goto out;
1755 }
1756
Thomas Graf86872cb2006-08-22 00:01:08 -07001757 if (cfg->fc_metric == 0)
1758 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759
Matti Vaittinend71314b2011-11-14 00:14:49 +00001760 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05001761 if (cfg->fc_nlinfo.nlh &&
1762 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00001763 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001764 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00001765 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00001766 table = fib6_new_table(net, cfg->fc_table);
1767 }
1768 } else {
1769 table = fib6_new_table(net, cfg->fc_table);
1770 }
David S. Miller38308472011-12-03 18:02:47 -05001771
1772 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001773 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07001774
Martin KaFai Lauad706862015-08-14 11:05:52 -07001775 rt = ip6_dst_alloc(net, NULL,
1776 (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777
David S. Miller38308472011-12-03 18:02:47 -05001778 if (!rt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 err = -ENOMEM;
1780 goto out;
1781 }
1782
Gao feng1716a962012-04-06 00:13:10 +00001783 if (cfg->fc_flags & RTF_EXPIRES)
1784 rt6_set_expires(rt, jiffies +
1785 clock_t_to_jiffies(cfg->fc_expires));
1786 else
1787 rt6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788
Thomas Graf86872cb2006-08-22 00:01:08 -07001789 if (cfg->fc_protocol == RTPROT_UNSPEC)
1790 cfg->fc_protocol = RTPROT_BOOT;
1791 rt->rt6i_protocol = cfg->fc_protocol;
1792
1793 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794
1795 if (addr_type & IPV6_ADDR_MULTICAST)
Changli Gaod8d1f302010-06-10 23:31:35 -07001796 rt->dst.input = ip6_mc_input;
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00001797 else if (cfg->fc_flags & RTF_LOCAL)
1798 rt->dst.input = ip6_input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 else
Changli Gaod8d1f302010-06-10 23:31:35 -07001800 rt->dst.input = ip6_forward;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801
Changli Gaod8d1f302010-06-10 23:31:35 -07001802 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803
Thomas Graf86872cb2006-08-22 00:01:08 -07001804 ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
1805 rt->rt6i_dst.plen = cfg->fc_dst_len;
Martin KaFai Lauafc4eef2015-04-28 13:03:07 -07001806 if (rt->rt6i_dst.plen == 128)
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001807 rt->dst.flags |= DST_HOST;
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001808
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809#ifdef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001810 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
1811 rt->rt6i_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812#endif
1813
Thomas Graf86872cb2006-08-22 00:01:08 -07001814 rt->rt6i_metric = cfg->fc_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815
1816 /* We cannot add true routes via loopback here,
1817 they would result in kernel looping; promote them to reject routes
1818 */
Thomas Graf86872cb2006-08-22 00:01:08 -07001819 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05001820 (dev && (dev->flags & IFF_LOOPBACK) &&
1821 !(addr_type & IPV6_ADDR_LOOPBACK) &&
1822 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08001824 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 if (dev) {
1826 dev_put(dev);
1827 in6_dev_put(idev);
1828 }
Daniel Lezcano55786892008-03-04 13:47:47 -08001829 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 dev_hold(dev);
1831 idev = in6_dev_get(dev);
1832 if (!idev) {
1833 err = -ENODEV;
1834 goto out;
1835 }
1836 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001838 switch (cfg->fc_type) {
1839 case RTN_BLACKHOLE:
1840 rt->dst.error = -EINVAL;
Eric Dumazetaad88722014-04-15 13:47:15 -04001841 rt->dst.output = dst_discard_sk;
Kamala R7150aed2013-12-02 19:55:21 +05301842 rt->dst.input = dst_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001843 break;
1844 case RTN_PROHIBIT:
1845 rt->dst.error = -EACCES;
Kamala R7150aed2013-12-02 19:55:21 +05301846 rt->dst.output = ip6_pkt_prohibit_out;
1847 rt->dst.input = ip6_pkt_prohibit;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001848 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00001849 case RTN_THROW:
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001850 default:
Kamala R7150aed2013-12-02 19:55:21 +05301851 rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN
1852 : -ENETUNREACH;
1853 rt->dst.output = ip6_pkt_discard_out;
1854 rt->dst.input = ip6_pkt_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001855 break;
1856 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 goto install_route;
1858 }
1859
Thomas Graf86872cb2006-08-22 00:01:08 -07001860 if (cfg->fc_flags & RTF_GATEWAY) {
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001861 const struct in6_addr *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 int gwa_type;
1863
Thomas Graf86872cb2006-08-22 00:01:08 -07001864 gw_addr = &cfg->fc_gateway;
Florian Westphal330567b2015-08-07 10:54:28 +02001865 gwa_type = ipv6_addr_type(gw_addr);
Florian Westphal48ed7b22015-05-21 00:25:41 +02001866
1867 /* if gw_addr is local we will fail to detect this in case
1868 * address is still TENTATIVE (DAD in progress). rt6_lookup()
1869 * will return already-added prefix route via interface that
1870 * prefix route was assigned to, which might be non-loopback.
1871 */
1872 err = -EINVAL;
Florian Westphal330567b2015-08-07 10:54:28 +02001873 if (ipv6_chk_addr_and_flags(net, gw_addr,
1874 gwa_type & IPV6_ADDR_LINKLOCAL ?
1875 dev : NULL, 0, 0))
Florian Westphal48ed7b22015-05-21 00:25:41 +02001876 goto out;
1877
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001878 rt->rt6i_gateway = *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879
1880 if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
1881 struct rt6_info *grt;
1882
1883 /* IPv6 strictly inhibits using not link-local
1884 addresses as nexthop address.
1885 Otherwise, router will not able to send redirects.
1886 It is very good, but in some (rare!) circumstances
1887 (SIT, PtP, NBMA NOARP links) it is handy to allow
1888 some exceptions. --ANK
1889 */
David S. Miller38308472011-12-03 18:02:47 -05001890 if (!(gwa_type & IPV6_ADDR_UNICAST))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 goto out;
1892
Daniel Lezcano55786892008-03-04 13:47:47 -08001893 grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894
1895 err = -EHOSTUNREACH;
David S. Miller38308472011-12-03 18:02:47 -05001896 if (!grt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 goto out;
1898 if (dev) {
David S. Millerd1918542011-12-28 20:19:20 -05001899 if (dev != grt->dst.dev) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00001900 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 goto out;
1902 }
1903 } else {
David S. Millerd1918542011-12-28 20:19:20 -05001904 dev = grt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 idev = grt->rt6i_idev;
1906 dev_hold(dev);
1907 in6_dev_hold(grt->rt6i_idev);
1908 }
David S. Miller38308472011-12-03 18:02:47 -05001909 if (!(grt->rt6i_flags & RTF_GATEWAY))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 err = 0;
Amerigo Wang94e187c2012-10-29 00:13:19 +00001911 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912
1913 if (err)
1914 goto out;
1915 }
1916 err = -EINVAL;
David S. Miller38308472011-12-03 18:02:47 -05001917 if (!dev || (dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 goto out;
1919 }
1920
1921 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05001922 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 goto out;
1924
Daniel Walterc3968a82011-04-13 21:10:57 +00001925 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
1926 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
1927 err = -EINVAL;
1928 goto out;
1929 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001930 rt->rt6i_prefsrc.addr = cfg->fc_prefsrc;
Daniel Walterc3968a82011-04-13 21:10:57 +00001931 rt->rt6i_prefsrc.plen = 128;
1932 } else
1933 rt->rt6i_prefsrc.plen = 0;
1934
Thomas Graf86872cb2006-08-22 00:01:08 -07001935 rt->rt6i_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936
1937install_route:
Changli Gaod8d1f302010-06-10 23:31:35 -07001938 rt->dst.dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 rt->rt6i_idev = idev;
Thomas Grafc71099a2006-08-04 23:20:06 -07001940 rt->rt6i_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001941
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001942 cfg->fc_nlinfo.nl_net = dev_net(dev);
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001943
Florian Westphale715b6d2015-01-05 23:57:44 +01001944 err = ip6_convert_metrics(&mxc, cfg);
1945 if (err)
1946 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947
Florian Westphale715b6d2015-01-05 23:57:44 +01001948 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, &mxc);
1949
1950 kfree(mxc.mx);
1951 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952out:
1953 if (dev)
1954 dev_put(dev);
1955 if (idev)
1956 in6_dev_put(idev);
1957 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07001958 dst_free(&rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 return err;
1960}
1961
Thomas Graf86872cb2006-08-22 00:01:08 -07001962static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963{
1964 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07001965 struct fib6_table *table;
David S. Millerd1918542011-12-28 20:19:20 -05001966 struct net *net = dev_net(rt->dst.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967
Gao feng6825a262012-09-19 19:25:34 +00001968 if (rt == net->ipv6.ip6_null_entry) {
1969 err = -ENOENT;
1970 goto out;
1971 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07001972
Thomas Grafc71099a2006-08-04 23:20:06 -07001973 table = rt->rt6i_table;
1974 write_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07001975 err = fib6_del(rt, info);
Thomas Grafc71099a2006-08-04 23:20:06 -07001976 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977
Gao feng6825a262012-09-19 19:25:34 +00001978out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00001979 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 return err;
1981}
1982
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001983int ip6_del_rt(struct rt6_info *rt)
1984{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08001985 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -05001986 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08001987 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08001988 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001989}
1990
Thomas Graf86872cb2006-08-22 00:01:08 -07001991static int ip6_route_del(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992{
Thomas Grafc71099a2006-08-04 23:20:06 -07001993 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 struct fib6_node *fn;
1995 struct rt6_info *rt;
1996 int err = -ESRCH;
1997
Daniel Lezcano55786892008-03-04 13:47:47 -08001998 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001999 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002000 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001
Thomas Grafc71099a2006-08-04 23:20:06 -07002002 read_lock_bh(&table->tb6_lock);
2003
2004 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07002005 &cfg->fc_dst, cfg->fc_dst_len,
2006 &cfg->fc_src, cfg->fc_src_len);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002007
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 if (fn) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002009 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
Martin KaFai Lau1f56a012015-04-28 13:03:03 -07002010 if ((rt->rt6i_flags & RTF_CACHE) &&
2011 !(cfg->fc_flags & RTF_CACHE))
2012 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002013 if (cfg->fc_ifindex &&
David S. Millerd1918542011-12-28 20:19:20 -05002014 (!rt->dst.dev ||
2015 rt->dst.dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002017 if (cfg->fc_flags & RTF_GATEWAY &&
2018 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002020 if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07002022 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07002023 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024
Thomas Graf86872cb2006-08-22 00:01:08 -07002025 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 }
2027 }
Thomas Grafc71099a2006-08-04 23:20:06 -07002028 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029
2030 return err;
2031}
2032
David S. Miller6700c272012-07-17 03:29:28 -07002033static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07002034{
David S. Millere8599ff2012-07-11 23:43:53 -07002035 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07002036 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07002037 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07002038 struct ndisc_options ndopts;
2039 struct inet6_dev *in6_dev;
2040 struct neighbour *neigh;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002041 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07002042 int optlen, on_link;
2043 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07002044
Simon Horman29a3cad2013-05-28 20:34:26 +00002045 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002046 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07002047
2048 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07002049 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002050 return;
2051 }
2052
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002053 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07002054
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002055 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07002056 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002057 return;
2058 }
2059
David S. Miller6e157b62012-07-12 00:05:02 -07002060 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002061 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07002062 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002063 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07002064 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07002065 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002066 return;
2067 }
2068
2069 in6_dev = __in6_dev_get(skb->dev);
2070 if (!in6_dev)
2071 return;
2072 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
2073 return;
2074
2075 /* RFC2461 8.1:
2076 * The IP source address of the Redirect MUST be the same as the current
2077 * first-hop router for the specified ICMP Destination Address.
2078 */
2079
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002080 if (!ndisc_parse_options(msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07002081 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
2082 return;
2083 }
David S. Miller6e157b62012-07-12 00:05:02 -07002084
2085 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07002086 if (ndopts.nd_opts_tgt_lladdr) {
2087 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
2088 skb->dev);
2089 if (!lladdr) {
2090 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
2091 return;
2092 }
2093 }
2094
David S. Miller6e157b62012-07-12 00:05:02 -07002095 rt = (struct rt6_info *) dst;
2096 if (rt == net->ipv6.ip6_null_entry) {
2097 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
2098 return;
2099 }
2100
2101 /* Redirect received -> path was valid.
2102 * Look, redirects are sent only in response to data packets,
2103 * so that this nexthop apparently is reachable. --ANK
2104 */
2105 dst_confirm(&rt->dst);
2106
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002107 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07002108 if (!neigh)
2109 return;
2110
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 /*
2112 * We have finally decided to accept it.
2113 */
2114
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002115 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 NEIGH_UPDATE_F_WEAK_OVERRIDE|
2117 NEIGH_UPDATE_F_OVERRIDE|
2118 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
2119 NEIGH_UPDATE_F_ISROUTER))
2120 );
2121
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002122 nrt = ip6_rt_cache_alloc(rt, &msg->dest, NULL);
David S. Miller38308472011-12-03 18:02:47 -05002123 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 goto out;
2125
2126 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
2127 if (on_link)
2128 nrt->rt6i_flags &= ~RTF_GATEWAY;
2129
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002130 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131
Thomas Graf40e22e82006-08-22 00:00:45 -07002132 if (ip6_ins_rt(nrt))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 goto out;
2134
Changli Gaod8d1f302010-06-10 23:31:35 -07002135 netevent.old = &rt->dst;
2136 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002137 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00002138 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07002139 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
2140
David S. Miller38308472011-12-03 18:02:47 -05002141 if (rt->rt6i_flags & RTF_CACHE) {
David S. Miller6e157b62012-07-12 00:05:02 -07002142 rt = (struct rt6_info *) dst_clone(&rt->dst);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002143 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 }
2145
2146out:
David S. Millere8599ff2012-07-11 23:43:53 -07002147 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07002148}
2149
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 * Misc support functions
2152 */
2153
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002154static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from)
2155{
2156 BUG_ON(from->dst.from);
2157
2158 rt->rt6i_flags &= ~RTF_EXPIRES;
2159 dst_hold(&from->dst);
2160 rt->dst.from = &from->dst;
2161 dst_init_metrics(&rt->dst, dst_metrics_ptr(&from->dst), true);
2162}
2163
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002164static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165{
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002166 rt->dst.input = ort->dst.input;
2167 rt->dst.output = ort->dst.output;
2168 rt->rt6i_dst = ort->rt6i_dst;
2169 rt->dst.error = ort->dst.error;
2170 rt->rt6i_idev = ort->rt6i_idev;
2171 if (rt->rt6i_idev)
2172 in6_dev_hold(rt->rt6i_idev);
2173 rt->dst.lastuse = jiffies;
2174 rt->rt6i_gateway = ort->rt6i_gateway;
2175 rt->rt6i_flags = ort->rt6i_flags;
2176 rt6_set_from(rt, ort);
2177 rt->rt6i_metric = ort->rt6i_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002179 rt->rt6i_src = ort->rt6i_src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180#endif
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002181 rt->rt6i_prefsrc = ort->rt6i_prefsrc;
2182 rt->rt6i_table = ort->rt6i_table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183}
2184
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002185#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002186static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002187 const struct in6_addr *prefix, int prefixlen,
2188 const struct in6_addr *gwaddr, int ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002189{
2190 struct fib6_node *fn;
2191 struct rt6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07002192 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002193
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002194 table = fib6_get_table(net, RT6_TABLE_INFO);
David S. Miller38308472011-12-03 18:02:47 -05002195 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002196 return NULL;
2197
Li RongQing5744dd92012-09-11 21:59:01 +00002198 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01002199 fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002200 if (!fn)
2201 goto out;
2202
Changli Gaod8d1f302010-06-10 23:31:35 -07002203 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05002204 if (rt->dst.dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002205 continue;
2206 if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
2207 continue;
2208 if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
2209 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07002210 dst_hold(&rt->dst);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002211 break;
2212 }
2213out:
Li RongQing5744dd92012-09-11 21:59:01 +00002214 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002215 return rt;
2216}
2217
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002218static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002219 const struct in6_addr *prefix, int prefixlen,
2220 const struct in6_addr *gwaddr, int ifindex,
Eric Dumazet95c96172012-04-15 05:58:06 +00002221 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002222{
Thomas Graf86872cb2006-08-22 00:01:08 -07002223 struct fib6_config cfg = {
2224 .fc_table = RT6_TABLE_INFO,
Rami Rosen238fc7e2008-02-09 23:43:11 -08002225 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07002226 .fc_ifindex = ifindex,
2227 .fc_dst_len = prefixlen,
2228 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
2229 RTF_UP | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00002230 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002231 .fc_nlinfo.nlh = NULL,
2232 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07002233 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002234
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002235 cfg.fc_dst = *prefix;
2236 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07002237
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08002238 /* We should treat it as a default route if prefix length is 0. */
2239 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07002240 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002241
Thomas Graf86872cb2006-08-22 00:01:08 -07002242 ip6_route_add(&cfg);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002243
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002244 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002245}
2246#endif
2247
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002248struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002249{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07002251 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002253 table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05002254 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002255 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256
Li RongQing5744dd92012-09-11 21:59:01 +00002257 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01002258 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05002259 if (dev == rt->dst.dev &&
YOSHIFUJI Hideaki045927f2006-03-20 17:00:48 -08002260 ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 ipv6_addr_equal(&rt->rt6i_gateway, addr))
2262 break;
2263 }
2264 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07002265 dst_hold(&rt->dst);
Li RongQing5744dd92012-09-11 21:59:01 +00002266 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 return rt;
2268}
2269
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002270struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08002271 struct net_device *dev,
2272 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273{
Thomas Graf86872cb2006-08-22 00:01:08 -07002274 struct fib6_config cfg = {
2275 .fc_table = RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08002276 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07002277 .fc_ifindex = dev->ifindex,
2278 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
2279 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00002280 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08002281 .fc_nlinfo.nlh = NULL,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002282 .fc_nlinfo.nl_net = dev_net(dev),
Thomas Graf86872cb2006-08-22 00:01:08 -07002283 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002285 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286
Thomas Graf86872cb2006-08-22 00:01:08 -07002287 ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 return rt6_get_dflt_router(gwaddr, dev);
2290}
2291
Daniel Lezcano7b4da532008-03-04 13:47:14 -08002292void rt6_purge_dflt_routers(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293{
2294 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07002295 struct fib6_table *table;
2296
2297 /* NOTE: Keep consistent with rt6_get_dflt_router */
Daniel Lezcano7b4da532008-03-04 13:47:14 -08002298 table = fib6_get_table(net, RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05002299 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002300 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301
2302restart:
Thomas Grafc71099a2006-08-04 23:20:06 -07002303 read_lock_bh(&table->tb6_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07002304 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
Lorenzo Colitti3e8b0ac2013-03-03 20:46:46 +00002305 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
2306 (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002307 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07002308 read_unlock_bh(&table->tb6_lock);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002309 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 goto restart;
2311 }
2312 }
Thomas Grafc71099a2006-08-04 23:20:06 -07002313 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314}
2315
Daniel Lezcano55786892008-03-04 13:47:47 -08002316static void rtmsg_to_fib6_config(struct net *net,
2317 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07002318 struct fib6_config *cfg)
2319{
2320 memset(cfg, 0, sizeof(*cfg));
2321
2322 cfg->fc_table = RT6_TABLE_MAIN;
2323 cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
2324 cfg->fc_metric = rtmsg->rtmsg_metric;
2325 cfg->fc_expires = rtmsg->rtmsg_info;
2326 cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
2327 cfg->fc_src_len = rtmsg->rtmsg_src_len;
2328 cfg->fc_flags = rtmsg->rtmsg_flags;
2329
Daniel Lezcano55786892008-03-04 13:47:47 -08002330 cfg->fc_nlinfo.nl_net = net;
Benjamin Theryf1243c22008-02-26 18:10:03 -08002331
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002332 cfg->fc_dst = rtmsg->rtmsg_dst;
2333 cfg->fc_src = rtmsg->rtmsg_src;
2334 cfg->fc_gateway = rtmsg->rtmsg_gateway;
Thomas Graf86872cb2006-08-22 00:01:08 -07002335}
2336
Daniel Lezcano55786892008-03-04 13:47:47 -08002337int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338{
Thomas Graf86872cb2006-08-22 00:01:08 -07002339 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 struct in6_rtmsg rtmsg;
2341 int err;
2342
Ian Morris67ba4152014-08-24 21:53:10 +01002343 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344 case SIOCADDRT: /* Add a route */
2345 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00002346 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347 return -EPERM;
2348 err = copy_from_user(&rtmsg, arg,
2349 sizeof(struct in6_rtmsg));
2350 if (err)
2351 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07002352
Daniel Lezcano55786892008-03-04 13:47:47 -08002353 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07002354
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 rtnl_lock();
2356 switch (cmd) {
2357 case SIOCADDRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07002358 err = ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 break;
2360 case SIOCDELRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07002361 err = ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 break;
2363 default:
2364 err = -EINVAL;
2365 }
2366 rtnl_unlock();
2367
2368 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07002369 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370
2371 return -EINVAL;
2372}
2373
2374/*
2375 * Drop the packet on the floor
2376 */
2377
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07002378static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002380 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00002381 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002382 switch (ipstats_mib_noroutes) {
2383 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07002384 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00002385 if (type == IPV6_ADDR_ANY) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002386 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2387 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002388 break;
2389 }
2390 /* FALLTHROUGH */
2391 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002392 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2393 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002394 break;
2395 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002396 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 kfree_skb(skb);
2398 return 0;
2399}
2400
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002401static int ip6_pkt_discard(struct sk_buff *skb)
2402{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002403 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002404}
2405
Eric Dumazetaad88722014-04-15 13:47:15 -04002406static int ip6_pkt_discard_out(struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407{
Eric Dumazetadf30902009-06-02 05:19:30 +00002408 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002409 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410}
2411
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002412static int ip6_pkt_prohibit(struct sk_buff *skb)
2413{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002414 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002415}
2416
Eric Dumazetaad88722014-04-15 13:47:15 -04002417static int ip6_pkt_prohibit_out(struct sock *sk, struct sk_buff *skb)
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002418{
Eric Dumazetadf30902009-06-02 05:19:30 +00002419 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002420 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002421}
2422
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423/*
2424 * Allocate a dst for local (unicast / anycast) address.
2425 */
2426
2427struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
2428 const struct in6_addr *addr,
David S. Miller8f031512011-12-06 16:48:14 -05002429 bool anycast)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002431 struct net *net = dev_net(idev->dev);
Hannes Frederic Sowaa3300ef2013-12-07 03:33:45 +01002432 struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev,
Martin KaFai Lauad706862015-08-14 11:05:52 -07002433 DST_NOCOUNT);
Hannes Frederic Sowaa3300ef2013-12-07 03:33:45 +01002434 if (!rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 return ERR_PTR(-ENOMEM);
2436
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 in6_dev_hold(idev);
2438
David S. Miller11d53b42011-06-24 15:23:34 -07002439 rt->dst.flags |= DST_HOST;
Changli Gaod8d1f302010-06-10 23:31:35 -07002440 rt->dst.input = ip6_input;
2441 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 rt->rt6i_idev = idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443
2444 rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +09002445 if (anycast)
2446 rt->rt6i_flags |= RTF_ANYCAST;
2447 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 rt->rt6i_flags |= RTF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449
Julian Anastasov550bab42013-10-20 15:43:04 +03002450 rt->rt6i_gateway = *addr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002451 rt->rt6i_dst.addr = *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 rt->rt6i_dst.plen = 128;
Daniel Lezcano55786892008-03-04 13:47:47 -08002453 rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454
Changli Gaod8d1f302010-06-10 23:31:35 -07002455 atomic_set(&rt->dst.__refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456
2457 return rt;
2458}
2459
Daniel Walterc3968a82011-04-13 21:10:57 +00002460int ip6_route_get_saddr(struct net *net,
2461 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002462 const struct in6_addr *daddr,
Daniel Walterc3968a82011-04-13 21:10:57 +00002463 unsigned int prefs,
2464 struct in6_addr *saddr)
2465{
Markus Stenberge16e8882015-05-05 13:36:59 +03002466 struct inet6_dev *idev =
2467 rt ? ip6_dst_idev((struct dst_entry *)rt) : NULL;
Daniel Walterc3968a82011-04-13 21:10:57 +00002468 int err = 0;
Markus Stenberge16e8882015-05-05 13:36:59 +03002469 if (rt && rt->rt6i_prefsrc.plen)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002470 *saddr = rt->rt6i_prefsrc.addr;
Daniel Walterc3968a82011-04-13 21:10:57 +00002471 else
2472 err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
2473 daddr, prefs, saddr);
2474 return err;
2475}
2476
2477/* remove deleted ip from prefsrc entries */
2478struct arg_dev_net_ip {
2479 struct net_device *dev;
2480 struct net *net;
2481 struct in6_addr *addr;
2482};
2483
2484static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
2485{
2486 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
2487 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
2488 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
2489
David S. Millerd1918542011-12-28 20:19:20 -05002490 if (((void *)rt->dst.dev == dev || !dev) &&
Daniel Walterc3968a82011-04-13 21:10:57 +00002491 rt != net->ipv6.ip6_null_entry &&
2492 ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
2493 /* remove prefsrc entry */
2494 rt->rt6i_prefsrc.plen = 0;
2495 }
2496 return 0;
2497}
2498
2499void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
2500{
2501 struct net *net = dev_net(ifp->idev->dev);
2502 struct arg_dev_net_ip adni = {
2503 .dev = ifp->idev->dev,
2504 .net = net,
2505 .addr = &ifp->addr,
2506 };
Li RongQing0c3584d2013-12-27 16:32:38 +08002507 fib6_clean_all(net, fib6_remove_prefsrc, &adni);
Daniel Walterc3968a82011-04-13 21:10:57 +00002508}
2509
Duan Jiongbe7a0102014-05-15 15:56:14 +08002510#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY)
2511#define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE)
2512
2513/* Remove routers and update dst entries when gateway turn into host. */
2514static int fib6_clean_tohost(struct rt6_info *rt, void *arg)
2515{
2516 struct in6_addr *gateway = (struct in6_addr *)arg;
2517
2518 if ((((rt->rt6i_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) ||
2519 ((rt->rt6i_flags & RTF_CACHE_GATEWAY) == RTF_CACHE_GATEWAY)) &&
2520 ipv6_addr_equal(gateway, &rt->rt6i_gateway)) {
2521 return -1;
2522 }
2523 return 0;
2524}
2525
2526void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
2527{
2528 fib6_clean_all(net, fib6_clean_tohost, gateway);
2529}
2530
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002531struct arg_dev_net {
2532 struct net_device *dev;
2533 struct net *net;
2534};
2535
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536static int fib6_ifdown(struct rt6_info *rt, void *arg)
2537{
stephen hemmingerbc3ef662010-12-16 17:42:40 +00002538 const struct arg_dev_net *adn = arg;
2539 const struct net_device *dev = adn->dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002540
David S. Millerd1918542011-12-28 20:19:20 -05002541 if ((rt->dst.dev == dev || !dev) &&
David S. Millerc159d302011-12-26 15:24:36 -05002542 rt != adn->net->ipv6.ip6_null_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 return -1;
David S. Millerc159d302011-12-26 15:24:36 -05002544
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 return 0;
2546}
2547
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002548void rt6_ifdown(struct net *net, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002550 struct arg_dev_net adn = {
2551 .dev = dev,
2552 .net = net,
2553 };
2554
Li RongQing0c3584d2013-12-27 16:32:38 +08002555 fib6_clean_all(net, fib6_ifdown, &adn);
David S. Miller1e493d12008-09-10 17:27:15 -07002556 icmp6_clean_all(fib6_ifdown, &adn);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07002557 rt6_uncached_list_flush_dev(net, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558}
2559
Eric Dumazet95c96172012-04-15 05:58:06 +00002560struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00002562 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563};
2564
2565static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
2566{
2567 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
2568 struct inet6_dev *idev;
2569
2570 /* In IPv6 pmtu discovery is not optional,
2571 so that RTAX_MTU lock cannot disable it.
2572 We still use this lock to block changes
2573 caused by addrconf/ndisc.
2574 */
2575
2576 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05002577 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 return 0;
2579
2580 /* For administrative MTU increase, there is no way to discover
2581 IPv6 PMTU increase, so PMTU increase should be updated here.
2582 Since RFC 1981 doesn't include administrative MTU increase
2583 update PMTU increase is a MUST. (i.e. jumbo frame)
2584 */
2585 /*
2586 If new MTU is less than route PMTU, this new MTU will be the
2587 lowest MTU in the path, update the route PMTU to reflect PMTU
2588 decreases; if new MTU is greater than route PMTU, and the
2589 old MTU is the lowest MTU in the path, update the route PMTU
2590 to reflect the increase. In this case if the other nodes' MTU
2591 also have the lowest MTU, TOO BIG MESSAGE will be lead to
2592 PMTU discouvery.
2593 */
David S. Millerd1918542011-12-28 20:19:20 -05002594 if (rt->dst.dev == arg->dev &&
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002595 !dst_metric_locked(&rt->dst, RTAX_MTU)) {
2596 if (rt->rt6i_flags & RTF_CACHE) {
2597 /* For RTF_CACHE with rt6i_pmtu == 0
2598 * (i.e. a redirected route),
2599 * the metrics of its rt->dst.from has already
2600 * been updated.
2601 */
2602 if (rt->rt6i_pmtu && rt->rt6i_pmtu > arg->mtu)
2603 rt->rt6i_pmtu = arg->mtu;
2604 } else if (dst_mtu(&rt->dst) >= arg->mtu ||
2605 (dst_mtu(&rt->dst) < arg->mtu &&
2606 dst_mtu(&rt->dst) == idev->cnf.mtu6)) {
2607 dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu);
2608 }
Simon Arlott566cfd82007-07-26 00:09:55 -07002609 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 return 0;
2611}
2612
Eric Dumazet95c96172012-04-15 05:58:06 +00002613void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614{
Thomas Grafc71099a2006-08-04 23:20:06 -07002615 struct rt6_mtu_change_arg arg = {
2616 .dev = dev,
2617 .mtu = mtu,
2618 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619
Li RongQing0c3584d2013-12-27 16:32:38 +08002620 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621}
2622
Patrick McHardyef7c79e2007-06-05 12:38:30 -07002623static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07002624 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07002625 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07002626 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002627 [RTA_PRIORITY] = { .type = NLA_U32 },
2628 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002629 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002630 [RTA_PREF] = { .type = NLA_U8 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002631};
2632
2633static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
2634 struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635{
Thomas Graf86872cb2006-08-22 00:01:08 -07002636 struct rtmsg *rtm;
2637 struct nlattr *tb[RTA_MAX+1];
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002638 unsigned int pref;
Thomas Graf86872cb2006-08-22 00:01:08 -07002639 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640
Thomas Graf86872cb2006-08-22 00:01:08 -07002641 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2642 if (err < 0)
2643 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644
Thomas Graf86872cb2006-08-22 00:01:08 -07002645 err = -EINVAL;
2646 rtm = nlmsg_data(nlh);
2647 memset(cfg, 0, sizeof(*cfg));
2648
2649 cfg->fc_table = rtm->rtm_table;
2650 cfg->fc_dst_len = rtm->rtm_dst_len;
2651 cfg->fc_src_len = rtm->rtm_src_len;
2652 cfg->fc_flags = RTF_UP;
2653 cfg->fc_protocol = rtm->rtm_protocol;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002654 cfg->fc_type = rtm->rtm_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07002655
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002656 if (rtm->rtm_type == RTN_UNREACHABLE ||
2657 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002658 rtm->rtm_type == RTN_PROHIBIT ||
2659 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07002660 cfg->fc_flags |= RTF_REJECT;
2661
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002662 if (rtm->rtm_type == RTN_LOCAL)
2663 cfg->fc_flags |= RTF_LOCAL;
2664
Martin KaFai Lau1f56a012015-04-28 13:03:03 -07002665 if (rtm->rtm_flags & RTM_F_CLONED)
2666 cfg->fc_flags |= RTF_CACHE;
2667
Eric W. Biederman15e47302012-09-07 20:12:54 +00002668 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
Thomas Graf86872cb2006-08-22 00:01:08 -07002669 cfg->fc_nlinfo.nlh = nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002670 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
Thomas Graf86872cb2006-08-22 00:01:08 -07002671
2672 if (tb[RTA_GATEWAY]) {
Jiri Benc67b61f62015-03-29 16:59:26 +02002673 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
Thomas Graf86872cb2006-08-22 00:01:08 -07002674 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002676
2677 if (tb[RTA_DST]) {
2678 int plen = (rtm->rtm_dst_len + 7) >> 3;
2679
2680 if (nla_len(tb[RTA_DST]) < plen)
2681 goto errout;
2682
2683 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002685
2686 if (tb[RTA_SRC]) {
2687 int plen = (rtm->rtm_src_len + 7) >> 3;
2688
2689 if (nla_len(tb[RTA_SRC]) < plen)
2690 goto errout;
2691
2692 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002694
Daniel Walterc3968a82011-04-13 21:10:57 +00002695 if (tb[RTA_PREFSRC])
Jiri Benc67b61f62015-03-29 16:59:26 +02002696 cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]);
Daniel Walterc3968a82011-04-13 21:10:57 +00002697
Thomas Graf86872cb2006-08-22 00:01:08 -07002698 if (tb[RTA_OIF])
2699 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
2700
2701 if (tb[RTA_PRIORITY])
2702 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
2703
2704 if (tb[RTA_METRICS]) {
2705 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
2706 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002708
2709 if (tb[RTA_TABLE])
2710 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
2711
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002712 if (tb[RTA_MULTIPATH]) {
2713 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
2714 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
2715 }
2716
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002717 if (tb[RTA_PREF]) {
2718 pref = nla_get_u8(tb[RTA_PREF]);
2719 if (pref != ICMPV6_ROUTER_PREF_LOW &&
2720 pref != ICMPV6_ROUTER_PREF_HIGH)
2721 pref = ICMPV6_ROUTER_PREF_MEDIUM;
2722 cfg->fc_flags |= RTF_PREF(pref);
2723 }
2724
Thomas Graf86872cb2006-08-22 00:01:08 -07002725 err = 0;
2726errout:
2727 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728}
2729
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002730static int ip6_route_multipath(struct fib6_config *cfg, int add)
2731{
2732 struct fib6_config r_cfg;
2733 struct rtnexthop *rtnh;
2734 int remaining;
2735 int attrlen;
2736 int err = 0, last_err = 0;
2737
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02002738 remaining = cfg->fc_mp_len;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002739beginning:
2740 rtnh = (struct rtnexthop *)cfg->fc_mp;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002741
2742 /* Parse a Multipath Entry */
2743 while (rtnh_ok(rtnh, remaining)) {
2744 memcpy(&r_cfg, cfg, sizeof(*cfg));
2745 if (rtnh->rtnh_ifindex)
2746 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
2747
2748 attrlen = rtnh_attrlen(rtnh);
2749 if (attrlen > 0) {
2750 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
2751
2752 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
2753 if (nla) {
Jiri Benc67b61f62015-03-29 16:59:26 +02002754 r_cfg.fc_gateway = nla_get_in6_addr(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002755 r_cfg.fc_flags |= RTF_GATEWAY;
2756 }
2757 }
2758 err = add ? ip6_route_add(&r_cfg) : ip6_route_del(&r_cfg);
2759 if (err) {
2760 last_err = err;
2761 /* If we are trying to remove a route, do not stop the
2762 * loop when ip6_route_del() fails (because next hop is
2763 * already gone), we should try to remove all next hops.
2764 */
2765 if (add) {
2766 /* If add fails, we should try to delete all
2767 * next hops that have been already added.
2768 */
2769 add = 0;
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02002770 remaining = cfg->fc_mp_len - remaining;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002771 goto beginning;
2772 }
2773 }
Nicolas Dichtel1a724182012-11-01 22:58:22 +00002774 /* Because each route is added like a single route we remove
Michal Kubeček27596472015-05-18 20:54:00 +02002775 * these flags after the first nexthop: if there is a collision,
2776 * we have already failed to add the first nexthop:
2777 * fib6_add_rt2node() has rejected it; when replacing, old
2778 * nexthops have been replaced by first new, the rest should
2779 * be added to it.
Nicolas Dichtel1a724182012-11-01 22:58:22 +00002780 */
Michal Kubeček27596472015-05-18 20:54:00 +02002781 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
2782 NLM_F_REPLACE);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002783 rtnh = rtnh_next(rtnh, &remaining);
2784 }
2785
2786 return last_err;
2787}
2788
Ian Morris67ba4152014-08-24 21:53:10 +01002789static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790{
Thomas Graf86872cb2006-08-22 00:01:08 -07002791 struct fib6_config cfg;
2792 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793
Thomas Graf86872cb2006-08-22 00:01:08 -07002794 err = rtm_to_fib6_config(skb, nlh, &cfg);
2795 if (err < 0)
2796 return err;
2797
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002798 if (cfg.fc_mp)
2799 return ip6_route_multipath(&cfg, 0);
2800 else
2801 return ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802}
2803
Ian Morris67ba4152014-08-24 21:53:10 +01002804static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805{
Thomas Graf86872cb2006-08-22 00:01:08 -07002806 struct fib6_config cfg;
2807 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808
Thomas Graf86872cb2006-08-22 00:01:08 -07002809 err = rtm_to_fib6_config(skb, nlh, &cfg);
2810 if (err < 0)
2811 return err;
2812
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002813 if (cfg.fc_mp)
2814 return ip6_route_multipath(&cfg, 1);
2815 else
2816 return ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817}
2818
Thomas Graf339bf982006-11-10 14:10:15 -08002819static inline size_t rt6_nlmsg_size(void)
2820{
2821 return NLMSG_ALIGN(sizeof(struct rtmsg))
2822 + nla_total_size(16) /* RTA_SRC */
2823 + nla_total_size(16) /* RTA_DST */
2824 + nla_total_size(16) /* RTA_GATEWAY */
2825 + nla_total_size(16) /* RTA_PREFSRC */
2826 + nla_total_size(4) /* RTA_TABLE */
2827 + nla_total_size(4) /* RTA_IIF */
2828 + nla_total_size(4) /* RTA_OIF */
2829 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08002830 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Daniel Borkmannea697632015-01-05 23:57:47 +01002831 + nla_total_size(sizeof(struct rta_cacheinfo))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002832 + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
2833 + nla_total_size(1); /* RTA_PREF */
Thomas Graf339bf982006-11-10 14:10:15 -08002834}
2835
Brian Haley191cd582008-08-14 15:33:21 -07002836static int rt6_fill_node(struct net *net,
2837 struct sk_buff *skb, struct rt6_info *rt,
Jamal Hadi Salim0d51aa82005-06-21 13:51:04 -07002838 struct in6_addr *dst, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002839 int iif, int type, u32 portid, u32 seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002840 int prefix, int nowait, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002842 u32 metrics[RTAX_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 struct rtmsg *rtm;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002844 struct nlmsghdr *nlh;
Thomas Grafe3703b32006-11-27 09:27:07 -08002845 long expires;
Patrick McHardy9e762a42006-08-10 23:09:48 -07002846 u32 table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847
2848 if (prefix) { /* user wants prefix routes only */
2849 if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
2850 /* success since this is not a prefix route */
2851 return 1;
2852 }
2853 }
2854
Eric W. Biederman15e47302012-09-07 20:12:54 +00002855 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05002856 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08002857 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002858
2859 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 rtm->rtm_family = AF_INET6;
2861 rtm->rtm_dst_len = rt->rt6i_dst.plen;
2862 rtm->rtm_src_len = rt->rt6i_src.plen;
2863 rtm->rtm_tos = 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07002864 if (rt->rt6i_table)
Patrick McHardy9e762a42006-08-10 23:09:48 -07002865 table = rt->rt6i_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07002866 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07002867 table = RT6_TABLE_UNSPEC;
2868 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04002869 if (nla_put_u32(skb, RTA_TABLE, table))
2870 goto nla_put_failure;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002871 if (rt->rt6i_flags & RTF_REJECT) {
2872 switch (rt->dst.error) {
2873 case -EINVAL:
2874 rtm->rtm_type = RTN_BLACKHOLE;
2875 break;
2876 case -EACCES:
2877 rtm->rtm_type = RTN_PROHIBIT;
2878 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002879 case -EAGAIN:
2880 rtm->rtm_type = RTN_THROW;
2881 break;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002882 default:
2883 rtm->rtm_type = RTN_UNREACHABLE;
2884 break;
2885 }
2886 }
David S. Miller38308472011-12-03 18:02:47 -05002887 else if (rt->rt6i_flags & RTF_LOCAL)
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002888 rtm->rtm_type = RTN_LOCAL;
David S. Millerd1918542011-12-28 20:19:20 -05002889 else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 rtm->rtm_type = RTN_LOCAL;
2891 else
2892 rtm->rtm_type = RTN_UNICAST;
2893 rtm->rtm_flags = 0;
2894 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
2895 rtm->rtm_protocol = rt->rt6i_protocol;
David S. Miller38308472011-12-03 18:02:47 -05002896 if (rt->rt6i_flags & RTF_DYNAMIC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 rtm->rtm_protocol = RTPROT_REDIRECT;
Denis Ovsienkof0396f602012-07-10 04:45:50 +00002898 else if (rt->rt6i_flags & RTF_ADDRCONF) {
2899 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ROUTEINFO))
2900 rtm->rtm_protocol = RTPROT_RA;
2901 else
2902 rtm->rtm_protocol = RTPROT_KERNEL;
2903 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904
David S. Miller38308472011-12-03 18:02:47 -05002905 if (rt->rt6i_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 rtm->rtm_flags |= RTM_F_CLONED;
2907
2908 if (dst) {
Jiri Benc930345e2015-03-29 16:59:25 +02002909 if (nla_put_in6_addr(skb, RTA_DST, dst))
David S. Millerc78679e2012-04-01 20:27:33 -04002910 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002911 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 } else if (rtm->rtm_dst_len)
Jiri Benc930345e2015-03-29 16:59:25 +02002913 if (nla_put_in6_addr(skb, RTA_DST, &rt->rt6i_dst.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04002914 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915#ifdef CONFIG_IPV6_SUBTREES
2916 if (src) {
Jiri Benc930345e2015-03-29 16:59:25 +02002917 if (nla_put_in6_addr(skb, RTA_SRC, src))
David S. Millerc78679e2012-04-01 20:27:33 -04002918 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002919 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04002920 } else if (rtm->rtm_src_len &&
Jiri Benc930345e2015-03-29 16:59:25 +02002921 nla_put_in6_addr(skb, RTA_SRC, &rt->rt6i_src.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04002922 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002924 if (iif) {
2925#ifdef CONFIG_IPV6_MROUTE
2926 if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
Benjamin Thery8229efd2008-12-10 16:30:15 -08002927 int err = ip6mr_get_route(net, skb, rtm, nowait);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002928 if (err <= 0) {
2929 if (!nowait) {
2930 if (err == 0)
2931 return 0;
2932 goto nla_put_failure;
2933 } else {
2934 if (err == -EMSGSIZE)
2935 goto nla_put_failure;
2936 }
2937 }
2938 } else
2939#endif
David S. Millerc78679e2012-04-01 20:27:33 -04002940 if (nla_put_u32(skb, RTA_IIF, iif))
2941 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002942 } else if (dst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 struct in6_addr saddr_buf;
David S. Millerc78679e2012-04-01 20:27:33 -04002944 if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0 &&
Jiri Benc930345e2015-03-29 16:59:25 +02002945 nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04002946 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07002948
Daniel Walterc3968a82011-04-13 21:10:57 +00002949 if (rt->rt6i_prefsrc.plen) {
2950 struct in6_addr saddr_buf;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002951 saddr_buf = rt->rt6i_prefsrc.addr;
Jiri Benc930345e2015-03-29 16:59:25 +02002952 if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04002953 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00002954 }
2955
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002956 memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics));
2957 if (rt->rt6i_pmtu)
2958 metrics[RTAX_MTU - 1] = rt->rt6i_pmtu;
2959 if (rtnetlink_put_metrics(skb, metrics) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07002960 goto nla_put_failure;
2961
YOSHIFUJI Hideaki / 吉藤英明dd0cbf22013-01-17 12:53:15 +00002962 if (rt->rt6i_flags & RTF_GATEWAY) {
Jiri Benc930345e2015-03-29 16:59:25 +02002963 if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->rt6i_gateway) < 0)
Eric Dumazet94f826b2012-03-27 09:53:52 +00002964 goto nla_put_failure;
Eric Dumazet94f826b2012-03-27 09:53:52 +00002965 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07002966
David S. Millerc78679e2012-04-01 20:27:33 -04002967 if (rt->dst.dev &&
2968 nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex))
2969 goto nla_put_failure;
2970 if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric))
2971 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00002972
2973 expires = (rt->rt6i_flags & RTF_EXPIRES) ? rt->dst.expires - jiffies : 0;
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07002974
David S. Miller87a50692012-07-10 05:06:14 -07002975 if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, rt->dst.error) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08002976 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002978 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags)))
2979 goto nla_put_failure;
2980
Johannes Berg053c0952015-01-16 22:09:00 +01002981 nlmsg_end(skb, nlh);
2982 return 0;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002983
2984nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002985 nlmsg_cancel(skb, nlh);
2986 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987}
2988
Patrick McHardy1b43af52006-08-10 23:11:17 -07002989int rt6_dump_route(struct rt6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990{
2991 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
2992 int prefix;
2993
Thomas Graf2d7202b2006-08-22 00:01:27 -07002994 if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
2995 struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0;
2997 } else
2998 prefix = 0;
2999
Brian Haley191cd582008-08-14 15:33:21 -07003000 return rt6_fill_node(arg->net,
3001 arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003002 NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003003 prefix, 0, NLM_F_MULTI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004}
3005
Ian Morris67ba4152014-08-24 21:53:10 +01003006static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09003008 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07003009 struct nlattr *tb[RTA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07003011 struct sk_buff *skb;
3012 struct rtmsg *rtm;
David S. Miller4c9483b2011-03-12 16:22:43 -05003013 struct flowi6 fl6;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003014 int err, iif = 0, oif = 0;
Thomas Grafab364a62006-08-22 00:01:47 -07003015
3016 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
3017 if (err < 0)
3018 goto errout;
3019
3020 err = -EINVAL;
David S. Miller4c9483b2011-03-12 16:22:43 -05003021 memset(&fl6, 0, sizeof(fl6));
Thomas Grafab364a62006-08-22 00:01:47 -07003022
3023 if (tb[RTA_SRC]) {
3024 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
3025 goto errout;
3026
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003027 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07003028 }
3029
3030 if (tb[RTA_DST]) {
3031 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
3032 goto errout;
3033
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003034 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07003035 }
3036
3037 if (tb[RTA_IIF])
3038 iif = nla_get_u32(tb[RTA_IIF]);
3039
3040 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003041 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07003042
Lorenzo Colitti2e47b292014-05-15 16:38:41 -07003043 if (tb[RTA_MARK])
3044 fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
3045
Thomas Grafab364a62006-08-22 00:01:47 -07003046 if (iif) {
3047 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003048 int flags = 0;
3049
Daniel Lezcano55786892008-03-04 13:47:47 -08003050 dev = __dev_get_by_index(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07003051 if (!dev) {
3052 err = -ENODEV;
3053 goto errout;
3054 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003055
3056 fl6.flowi6_iif = iif;
3057
3058 if (!ipv6_addr_any(&fl6.saddr))
3059 flags |= RT6_LOOKUP_F_HAS_SADDR;
3060
3061 rt = (struct rt6_info *)ip6_route_input_lookup(net, dev, &fl6,
3062 flags);
3063 } else {
3064 fl6.flowi6_oif = oif;
3065
3066 rt = (struct rt6_info *)ip6_route_output(net, NULL, &fl6);
Thomas Grafab364a62006-08-22 00:01:47 -07003067 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068
3069 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05003070 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00003071 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07003072 err = -ENOBUFS;
3073 goto errout;
3074 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075
3076 /* Reserve room for dummy headers, this skb can pass
3077 through good chunk of routing engine.
3078 */
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07003079 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
3081
Changli Gaod8d1f302010-06-10 23:31:35 -07003082 skb_dst_set(skb, &rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083
David S. Miller4c9483b2011-03-12 16:22:43 -05003084 err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003085 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003086 nlh->nlmsg_seq, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07003088 kfree_skb(skb);
3089 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 }
3091
Eric W. Biederman15e47302012-09-07 20:12:54 +00003092 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07003093errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095}
3096
Thomas Graf86872cb2006-08-22 00:01:08 -07003097void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098{
3099 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08003100 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003101 u32 seq;
3102 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003104 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05003105 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07003106
Thomas Graf339bf982006-11-10 14:10:15 -08003107 skb = nlmsg_new(rt6_nlmsg_size(), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05003108 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07003109 goto errout;
3110
Brian Haley191cd582008-08-14 15:33:21 -07003111 err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003112 event, info->portid, seq, 0, 0, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08003113 if (err < 0) {
3114 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
3115 WARN_ON(err == -EMSGSIZE);
3116 kfree_skb(skb);
3117 goto errout;
3118 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00003119 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08003120 info->nlh, gfp_any());
3121 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07003122errout:
3123 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08003124 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125}
3126
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003127static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00003128 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003129{
Jiri Pirko351638e2013-05-28 01:30:21 +00003130 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09003131 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003132
3133 if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07003134 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003135 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
3136#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07003137 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003138 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07003139 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003140 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
3141#endif
3142 }
3143
3144 return NOTIFY_OK;
3145}
3146
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147/*
3148 * /proc
3149 */
3150
3151#ifdef CONFIG_PROC_FS
3152
Alexey Dobriyan33120b32007-11-06 05:27:11 -08003153static const struct file_operations ipv6_route_proc_fops = {
3154 .owner = THIS_MODULE,
3155 .open = ipv6_route_open,
3156 .read = seq_read,
3157 .llseek = seq_lseek,
Hannes Frederic Sowa8d2ca1d2013-09-21 16:55:59 +02003158 .release = seq_release_net,
Alexey Dobriyan33120b32007-11-06 05:27:11 -08003159};
3160
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161static int rt6_stats_seq_show(struct seq_file *seq, void *v)
3162{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003163 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003165 net->ipv6.rt6_stats->fib_nodes,
3166 net->ipv6.rt6_stats->fib_route_nodes,
3167 net->ipv6.rt6_stats->fib_rt_alloc,
3168 net->ipv6.rt6_stats->fib_rt_entries,
3169 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00003170 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003171 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172
3173 return 0;
3174}
3175
3176static int rt6_stats_seq_open(struct inode *inode, struct file *file)
3177{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07003178 return single_open_net(inode, file, rt6_stats_seq_show);
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003179}
3180
Arjan van de Ven9a321442007-02-12 00:55:35 -08003181static const struct file_operations rt6_stats_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 .owner = THIS_MODULE,
3183 .open = rt6_stats_seq_open,
3184 .read = seq_read,
3185 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07003186 .release = single_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187};
3188#endif /* CONFIG_PROC_FS */
3189
3190#ifdef CONFIG_SYSCTL
3191
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192static
Joe Perchesfe2c6332013-06-11 23:04:25 -07003193int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 void __user *buffer, size_t *lenp, loff_t *ppos)
3195{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003196 struct net *net;
3197 int delay;
3198 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003200
3201 net = (struct net *)ctl->extra1;
3202 delay = net->ipv6.sysctl.flush_delay;
3203 proc_dointvec(ctl, write, buffer, lenp, ppos);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02003204 fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003205 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206}
3207
Joe Perchesfe2c6332013-06-11 23:04:25 -07003208struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003209 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08003211 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07003213 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003214 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215 },
3216 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003218 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219 .maxlen = sizeof(int),
3220 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003221 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 },
3223 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08003225 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 .maxlen = sizeof(int),
3227 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003228 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229 },
3230 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08003232 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233 .maxlen = sizeof(int),
3234 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003235 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 },
3237 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08003239 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 .maxlen = sizeof(int),
3241 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003242 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243 },
3244 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08003246 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 .maxlen = sizeof(int),
3248 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003249 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 },
3251 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08003253 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 .maxlen = sizeof(int),
3255 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003256 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257 },
3258 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08003260 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261 .maxlen = sizeof(int),
3262 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003263 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 },
3265 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08003267 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268 .maxlen = sizeof(int),
3269 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003270 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 },
3272 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08003274 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 .maxlen = sizeof(int),
3276 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003277 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08003279 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280};
3281
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003282struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003283{
3284 struct ctl_table *table;
3285
3286 table = kmemdup(ipv6_route_table_template,
3287 sizeof(ipv6_route_table_template),
3288 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003289
3290 if (table) {
3291 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003292 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003293 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003294 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
3295 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
3296 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
3297 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
3298 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
3299 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
3300 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08003301 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
Eric W. Biederman464dc802012-11-16 03:02:59 +00003302
3303 /* Don't export sysctls to unprivileged users */
3304 if (net->user_ns != &init_user_ns)
3305 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003306 }
3307
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003308 return table;
3309}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310#endif
3311
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003312static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003313{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07003314 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003315
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003316 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
3317 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003318
Eric Dumazetfc66f952010-10-08 06:37:34 +00003319 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
3320 goto out_ip6_dst_ops;
3321
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003322 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
3323 sizeof(*net->ipv6.ip6_null_entry),
3324 GFP_KERNEL);
3325 if (!net->ipv6.ip6_null_entry)
Eric Dumazetfc66f952010-10-08 06:37:34 +00003326 goto out_ip6_dst_entries;
Changli Gaod8d1f302010-06-10 23:31:35 -07003327 net->ipv6.ip6_null_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003328 (struct dst_entry *)net->ipv6.ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003329 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003330 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
3331 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003332
3333#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3334 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
3335 sizeof(*net->ipv6.ip6_prohibit_entry),
3336 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003337 if (!net->ipv6.ip6_prohibit_entry)
3338 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003339 net->ipv6.ip6_prohibit_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003340 (struct dst_entry *)net->ipv6.ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003341 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003342 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
3343 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003344
3345 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
3346 sizeof(*net->ipv6.ip6_blk_hole_entry),
3347 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003348 if (!net->ipv6.ip6_blk_hole_entry)
3349 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003350 net->ipv6.ip6_blk_hole_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003351 (struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003352 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003353 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
3354 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003355#endif
3356
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07003357 net->ipv6.sysctl.flush_delay = 0;
3358 net->ipv6.sysctl.ip6_rt_max_size = 4096;
3359 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
3360 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
3361 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
3362 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
3363 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
3364 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
3365
Benjamin Thery6891a342008-03-04 13:49:47 -08003366 net->ipv6.ip6_rt_gc_expire = 30*HZ;
3367
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003368 ret = 0;
3369out:
3370 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003371
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003372#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3373out_ip6_prohibit_entry:
3374 kfree(net->ipv6.ip6_prohibit_entry);
3375out_ip6_null_entry:
3376 kfree(net->ipv6.ip6_null_entry);
3377#endif
Eric Dumazetfc66f952010-10-08 06:37:34 +00003378out_ip6_dst_entries:
3379 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003380out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003381 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003382}
3383
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003384static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003385{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003386 kfree(net->ipv6.ip6_null_entry);
3387#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3388 kfree(net->ipv6.ip6_prohibit_entry);
3389 kfree(net->ipv6.ip6_blk_hole_entry);
3390#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003391 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003392}
3393
Thomas Grafd1896342012-06-18 12:08:33 +00003394static int __net_init ip6_route_net_init_late(struct net *net)
3395{
3396#ifdef CONFIG_PROC_FS
Gao fengd4beaa62013-02-18 01:34:54 +00003397 proc_create("ipv6_route", 0, net->proc_net, &ipv6_route_proc_fops);
3398 proc_create("rt6_stats", S_IRUGO, net->proc_net, &rt6_stats_seq_fops);
Thomas Grafd1896342012-06-18 12:08:33 +00003399#endif
3400 return 0;
3401}
3402
3403static void __net_exit ip6_route_net_exit_late(struct net *net)
3404{
3405#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00003406 remove_proc_entry("ipv6_route", net->proc_net);
3407 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00003408#endif
3409}
3410
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003411static struct pernet_operations ip6_route_net_ops = {
3412 .init = ip6_route_net_init,
3413 .exit = ip6_route_net_exit,
3414};
3415
David S. Millerc3426b42012-06-09 16:27:05 -07003416static int __net_init ipv6_inetpeer_init(struct net *net)
3417{
3418 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
3419
3420 if (!bp)
3421 return -ENOMEM;
3422 inet_peer_base_init(bp);
3423 net->ipv6.peers = bp;
3424 return 0;
3425}
3426
3427static void __net_exit ipv6_inetpeer_exit(struct net *net)
3428{
3429 struct inet_peer_base *bp = net->ipv6.peers;
3430
3431 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07003432 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07003433 kfree(bp);
3434}
3435
David S. Miller2b823f72012-06-09 19:00:16 -07003436static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07003437 .init = ipv6_inetpeer_init,
3438 .exit = ipv6_inetpeer_exit,
3439};
3440
Thomas Grafd1896342012-06-18 12:08:33 +00003441static struct pernet_operations ip6_route_net_late_ops = {
3442 .init = ip6_route_net_init_late,
3443 .exit = ip6_route_net_exit_late,
3444};
3445
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003446static struct notifier_block ip6_route_dev_notifier = {
3447 .notifier_call = ip6_route_dev_notify,
3448 .priority = 0,
3449};
3450
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003451int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003453 int ret;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07003454 int cpu;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003455
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003456 ret = -ENOMEM;
3457 ip6_dst_ops_template.kmem_cachep =
3458 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
3459 SLAB_HWCACHE_ALIGN, NULL);
3460 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08003461 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07003462
Eric Dumazetfc66f952010-10-08 06:37:34 +00003463 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003464 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003465 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003466
David S. Millerc3426b42012-06-09 16:27:05 -07003467 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
3468 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003469 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00003470
David S. Miller7e52b332012-06-15 15:51:55 -07003471 ret = register_pernet_subsys(&ip6_route_net_ops);
3472 if (ret)
3473 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07003474
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07003475 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
3476
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003477 /* Registering of the loopback is done before this portion of code,
3478 * the loopback reference in rt6_info will not be taken, do it
3479 * manually for init_net */
Changli Gaod8d1f302010-06-10 23:31:35 -07003480 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003481 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3482 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07003483 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003484 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07003485 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003486 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3487 #endif
David S. Millere8803b62012-06-16 01:12:19 -07003488 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003489 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003490 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003491
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003492 ret = xfrm6_init();
3493 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003494 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08003495
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003496 ret = fib6_rules_init();
3497 if (ret)
3498 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08003499
Thomas Grafd1896342012-06-18 12:08:33 +00003500 ret = register_pernet_subsys(&ip6_route_net_late_ops);
3501 if (ret)
3502 goto fib6_rules_init;
3503
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003504 ret = -ENOBUFS;
Greg Rosec7ac8672011-06-10 01:27:09 +00003505 if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) ||
3506 __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) ||
3507 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL))
Thomas Grafd1896342012-06-18 12:08:33 +00003508 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003509
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003510 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003511 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00003512 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003513
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07003514 for_each_possible_cpu(cpu) {
3515 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
3516
3517 INIT_LIST_HEAD(&ul->head);
3518 spin_lock_init(&ul->lock);
3519 }
3520
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003521out:
3522 return ret;
3523
Thomas Grafd1896342012-06-18 12:08:33 +00003524out_register_late_subsys:
3525 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003526fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003527 fib6_rules_cleanup();
3528xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003529 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00003530out_fib6_init:
3531 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003532out_register_subsys:
3533 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07003534out_register_inetpeer:
3535 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00003536out_dst_entries:
3537 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003538out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003539 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003540 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541}
3542
3543void ip6_route_cleanup(void)
3544{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003545 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00003546 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07003547 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07003550 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003551 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003552 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003553 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554}