blob: 4d24f0fa01782d5194e7c1e6b2e73e3dee4ca53e [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>
Jiri Benc904af042015-08-20 13:56:31 +020057#include <net/dst_metadata.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#include <net/xfrm.h>
Tom Tucker8d717402006-07-30 20:43:36 -070059#include <net/netevent.h>
Thomas Graf21713eb2006-08-15 00:35:24 -070060#include <net/netlink.h>
Nicolas Dichtel51ebd312012-10-22 03:42:09 +000061#include <net/nexthop.h>
Roopa Prabhu19e42e42015-07-21 10:43:48 +020062#include <net/lwtunnel.h>
Jiri Benc904af042015-08-20 13:56:31 +020063#include <net/ip_tunnels.h>
David Ahernca254492015-10-12 11:47:10 -070064#include <net/l3mdev.h>
David Ahernb8115802015-11-19 12:24:22 -080065#include <trace/events/fib6.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67#include <asm/uaccess.h>
68
69#ifdef CONFIG_SYSCTL
70#include <linux/sysctl.h>
71#endif
72
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +020073enum rt6_nud_state {
Jiri Benc7e980562013-12-11 13:48:20 +010074 RT6_NUD_FAIL_HARD = -3,
75 RT6_NUD_FAIL_PROBE = -2,
76 RT6_NUD_FAIL_DO_RR = -1,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +020077 RT6_NUD_SUCCEED = 1
78};
79
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -070080static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort);
Linus Torvalds1da177e2005-04-16 15:20:36 -070081static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
David S. Miller0dbaee32010-12-13 12:52:14 -080082static unsigned int ip6_default_advmss(const struct dst_entry *dst);
Steffen Klassertebb762f2011-11-23 02:12:51 +000083static unsigned int ip6_mtu(const struct dst_entry *dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084static struct dst_entry *ip6_negative_advice(struct dst_entry *);
85static void ip6_dst_destroy(struct dst_entry *);
86static void ip6_dst_ifdown(struct dst_entry *,
87 struct net_device *dev, int how);
Daniel Lezcano569d3642008-01-18 03:56:57 -080088static int ip6_dst_gc(struct dst_ops *ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90static int ip6_pkt_discard(struct sk_buff *skb);
Eric W. Biedermanede20592015-10-07 16:48:47 -050091static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb);
Kamala R7150aed2013-12-02 19:55:21 +053092static int ip6_pkt_prohibit(struct sk_buff *skb);
Eric W. Biedermanede20592015-10-07 16:48:47 -050093static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070094static void ip6_link_failure(struct sk_buff *skb);
David S. Miller6700c272012-07-17 03:29:28 -070095static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
96 struct sk_buff *skb, u32 mtu);
97static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
98 struct sk_buff *skb);
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -070099static void rt6_dst_from_metrics_check(struct rt6_info *rt);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200100static int rt6_score_route(struct rt6_info *rt, int oif, int strict);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800102#ifdef CONFIG_IPV6_ROUTE_INFO
Lorenzo Colitti9fcb87d2014-03-26 19:35:41 +0900103static struct rt6_info *rt6_add_route_info(struct net_device *dev,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000104 const struct in6_addr *prefix, int prefixlen,
Lorenzo Colitti9fcb87d2014-03-26 19:35:41 +0900105 const struct in6_addr *gwaddr, unsigned int pref);
106static struct rt6_info *rt6_get_route_info(struct net_device *dev,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000107 const struct in6_addr *prefix, int prefixlen,
Lorenzo Colitti9fcb87d2014-03-26 19:35:41 +0900108 const struct in6_addr *gwaddr);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800109#endif
110
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700111struct uncached_list {
112 spinlock_t lock;
113 struct list_head head;
114};
115
116static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list);
117
118static void rt6_uncached_list_add(struct rt6_info *rt)
119{
120 struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);
121
122 rt->dst.flags |= DST_NOCACHE;
123 rt->rt6i_uncached_list = ul;
124
125 spin_lock_bh(&ul->lock);
126 list_add_tail(&rt->rt6i_uncached, &ul->head);
127 spin_unlock_bh(&ul->lock);
128}
129
130static void rt6_uncached_list_del(struct rt6_info *rt)
131{
132 if (!list_empty(&rt->rt6i_uncached)) {
133 struct uncached_list *ul = rt->rt6i_uncached_list;
134
135 spin_lock_bh(&ul->lock);
136 list_del(&rt->rt6i_uncached);
137 spin_unlock_bh(&ul->lock);
138 }
139}
140
141static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev)
142{
143 struct net_device *loopback_dev = net->loopback_dev;
144 int cpu;
145
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500146 if (dev == loopback_dev)
147 return;
148
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700149 for_each_possible_cpu(cpu) {
150 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
151 struct rt6_info *rt;
152
153 spin_lock_bh(&ul->lock);
154 list_for_each_entry(rt, &ul->head, rt6i_uncached) {
155 struct inet6_dev *rt_idev = rt->rt6i_idev;
156 struct net_device *rt_dev = rt->dst.dev;
157
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500158 if (rt_idev->dev == dev) {
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700159 rt->rt6i_idev = in6_dev_get(loopback_dev);
160 in6_dev_put(rt_idev);
161 }
162
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500163 if (rt_dev == dev) {
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700164 rt->dst.dev = loopback_dev;
165 dev_hold(rt->dst.dev);
166 dev_put(rt_dev);
167 }
168 }
169 spin_unlock_bh(&ul->lock);
170 }
171}
172
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700173static u32 *rt6_pcpu_cow_metrics(struct rt6_info *rt)
174{
175 return dst_metrics_write_ptr(rt->dst.from);
176}
177
David S. Miller06582542011-01-27 14:58:42 -0800178static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
179{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700180 struct rt6_info *rt = (struct rt6_info *)dst;
David S. Miller06582542011-01-27 14:58:42 -0800181
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700182 if (rt->rt6i_flags & RTF_PCPU)
183 return rt6_pcpu_cow_metrics(rt);
184 else if (rt->rt6i_flags & RTF_CACHE)
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700185 return NULL;
186 else
Martin KaFai Lau3b471172015-02-12 16:14:08 -0800187 return dst_cow_metrics_generic(dst, old);
David S. Miller06582542011-01-27 14:58:42 -0800188}
189
David S. Millerf894cbf2012-07-02 21:52:24 -0700190static inline const void *choose_neigh_daddr(struct rt6_info *rt,
191 struct sk_buff *skb,
192 const void *daddr)
David S. Miller39232972012-01-26 15:22:32 -0500193{
194 struct in6_addr *p = &rt->rt6i_gateway;
195
David S. Millera7563f32012-01-26 16:29:16 -0500196 if (!ipv6_addr_any(p))
David S. Miller39232972012-01-26 15:22:32 -0500197 return (const void *) p;
David S. Millerf894cbf2012-07-02 21:52:24 -0700198 else if (skb)
199 return &ipv6_hdr(skb)->daddr;
David S. Miller39232972012-01-26 15:22:32 -0500200 return daddr;
201}
202
David S. Millerf894cbf2012-07-02 21:52:24 -0700203static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst,
204 struct sk_buff *skb,
205 const void *daddr)
David S. Millerd3aaeb32011-07-18 00:40:17 -0700206{
David S. Miller39232972012-01-26 15:22:32 -0500207 struct rt6_info *rt = (struct rt6_info *) dst;
208 struct neighbour *n;
209
David S. Millerf894cbf2012-07-02 21:52:24 -0700210 daddr = choose_neigh_daddr(rt, skb, daddr);
YOSHIFUJI Hideaki / 吉藤英明8e022ee2013-01-17 12:53:09 +0000211 n = __ipv6_neigh_lookup(dst->dev, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500212 if (n)
213 return n;
214 return neigh_create(&nd_tbl, daddr, dst->dev);
215}
216
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -0800217static struct dst_ops ip6_dst_ops_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 .family = AF_INET6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 .gc = ip6_dst_gc,
220 .gc_thresh = 1024,
221 .check = ip6_dst_check,
David S. Miller0dbaee32010-12-13 12:52:14 -0800222 .default_advmss = ip6_default_advmss,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000223 .mtu = ip6_mtu,
David S. Miller06582542011-01-27 14:58:42 -0800224 .cow_metrics = ipv6_cow_metrics,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 .destroy = ip6_dst_destroy,
226 .ifdown = ip6_dst_ifdown,
227 .negative_advice = ip6_negative_advice,
228 .link_failure = ip6_link_failure,
229 .update_pmtu = ip6_rt_update_pmtu,
David S. Miller6e157b62012-07-12 00:05:02 -0700230 .redirect = rt6_do_redirect,
Eric W. Biederman9f8955c2015-10-07 16:48:39 -0500231 .local_out = __ip6_local_out,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700232 .neigh_lookup = ip6_neigh_lookup,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233};
234
Steffen Klassertebb762f2011-11-23 02:12:51 +0000235static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
Roland Dreierec831ea2011-01-31 13:16:00 -0800236{
Steffen Klassert618f9bc2011-11-23 02:13:31 +0000237 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
238
239 return mtu ? : dst->dev->mtu;
Roland Dreierec831ea2011-01-31 13:16:00 -0800240}
241
David S. Miller6700c272012-07-17 03:29:28 -0700242static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
243 struct sk_buff *skb, u32 mtu)
David S. Miller14e50e52007-05-24 18:17:54 -0700244{
245}
246
David S. Miller6700c272012-07-17 03:29:28 -0700247static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
248 struct sk_buff *skb)
David S. Millerb587ee32012-07-12 00:39:24 -0700249{
250}
251
David S. Miller14e50e52007-05-24 18:17:54 -0700252static struct dst_ops ip6_dst_blackhole_ops = {
253 .family = AF_INET6,
David S. Miller14e50e52007-05-24 18:17:54 -0700254 .destroy = ip6_dst_destroy,
255 .check = ip6_dst_check,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000256 .mtu = ip6_blackhole_mtu,
Eric Dumazet214f45c2011-02-18 11:39:01 -0800257 .default_advmss = ip6_default_advmss,
David S. Miller14e50e52007-05-24 18:17:54 -0700258 .update_pmtu = ip6_rt_blackhole_update_pmtu,
David S. Millerb587ee32012-07-12 00:39:24 -0700259 .redirect = ip6_rt_blackhole_redirect,
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -0700260 .cow_metrics = dst_cow_metrics_generic,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700261 .neigh_lookup = ip6_neigh_lookup,
David S. Miller14e50e52007-05-24 18:17:54 -0700262};
263
David S. Miller62fa8a82011-01-26 20:51:05 -0800264static const u32 ip6_template_metrics[RTAX_MAX] = {
Li RongQing14edd872012-10-24 14:01:18 +0800265 [RTAX_HOPLIMIT - 1] = 0,
David S. Miller62fa8a82011-01-26 20:51:05 -0800266};
267
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000268static const struct rt6_info ip6_null_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700269 .dst = {
270 .__refcnt = ATOMIC_INIT(1),
271 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000272 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700273 .error = -ENETUNREACH,
Changli Gaod8d1f302010-06-10 23:31:35 -0700274 .input = ip6_pkt_discard,
275 .output = ip6_pkt_discard_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 },
277 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700278 .rt6i_protocol = RTPROT_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 .rt6i_metric = ~(u32) 0,
280 .rt6i_ref = ATOMIC_INIT(1),
281};
282
Thomas Graf101367c2006-08-04 03:39:02 -0700283#ifdef CONFIG_IPV6_MULTIPLE_TABLES
284
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000285static const struct rt6_info ip6_prohibit_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700286 .dst = {
287 .__refcnt = ATOMIC_INIT(1),
288 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000289 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700290 .error = -EACCES,
Changli Gaod8d1f302010-06-10 23:31:35 -0700291 .input = ip6_pkt_prohibit,
292 .output = ip6_pkt_prohibit_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700293 },
294 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700295 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700296 .rt6i_metric = ~(u32) 0,
297 .rt6i_ref = ATOMIC_INIT(1),
298};
299
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000300static const struct rt6_info ip6_blk_hole_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700301 .dst = {
302 .__refcnt = ATOMIC_INIT(1),
303 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000304 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700305 .error = -EINVAL,
Changli Gaod8d1f302010-06-10 23:31:35 -0700306 .input = dst_discard,
Eric W. Biedermanede20592015-10-07 16:48:47 -0500307 .output = dst_discard_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700308 },
309 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700310 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700311 .rt6i_metric = ~(u32) 0,
312 .rt6i_ref = ATOMIC_INIT(1),
313};
314
315#endif
316
Martin KaFai Lauebfa45f2015-10-15 16:39:57 -0700317static void rt6_info_init(struct rt6_info *rt)
318{
319 struct dst_entry *dst = &rt->dst;
320
321 memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
322 INIT_LIST_HEAD(&rt->rt6i_siblings);
323 INIT_LIST_HEAD(&rt->rt6i_uncached);
324}
325
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326/* allocate dst with ip6_dst_ops */
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700327static struct rt6_info *__ip6_dst_alloc(struct net *net,
328 struct net_device *dev,
Martin KaFai Lauad706862015-08-14 11:05:52 -0700329 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330{
David S. Miller97bab732012-06-09 22:36:36 -0700331 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +0000332 0, DST_OBSOLETE_FORCE_CHK, flags);
David S. Millercf911662011-04-28 14:31:47 -0700333
Martin KaFai Lauebfa45f2015-10-15 16:39:57 -0700334 if (rt)
335 rt6_info_init(rt);
Steffen Klassert81048912012-07-05 23:37:09 +0000336
David S. Millercf911662011-04-28 14:31:47 -0700337 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338}
339
David Ahern9ab179d2016-04-07 11:10:06 -0700340struct rt6_info *ip6_dst_alloc(struct net *net,
341 struct net_device *dev,
342 int flags)
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700343{
Martin KaFai Lauad706862015-08-14 11:05:52 -0700344 struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700345
346 if (rt) {
347 rt->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, GFP_ATOMIC);
348 if (rt->rt6i_pcpu) {
349 int cpu;
350
351 for_each_possible_cpu(cpu) {
352 struct rt6_info **p;
353
354 p = per_cpu_ptr(rt->rt6i_pcpu, cpu);
355 /* no one shares rt */
356 *p = NULL;
357 }
358 } else {
359 dst_destroy((struct dst_entry *)rt);
360 return NULL;
361 }
362 }
363
364 return rt;
365}
David Ahern9ab179d2016-04-07 11:10:06 -0700366EXPORT_SYMBOL(ip6_dst_alloc);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700367
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368static void ip6_dst_destroy(struct dst_entry *dst)
369{
370 struct rt6_info *rt = (struct rt6_info *)dst;
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000371 struct dst_entry *from = dst->from;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700372 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700374 dst_destroy_metrics_generic(dst);
Markus Elfring87775312015-07-02 16:30:24 +0200375 free_percpu(rt->rt6i_pcpu);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700376 rt6_uncached_list_del(rt);
377
378 idev = rt->rt6i_idev;
David S. Miller38308472011-12-03 18:02:47 -0500379 if (idev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 rt->rt6i_idev = NULL;
381 in6_dev_put(idev);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900382 }
Gao feng1716a962012-04-06 00:13:10 +0000383
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000384 dst->from = NULL;
385 dst_release(from);
David S. Millerb3419362010-11-30 12:27:11 -0800386}
387
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
389 int how)
390{
391 struct rt6_info *rt = (struct rt6_info *)dst;
392 struct inet6_dev *idev = rt->rt6i_idev;
Denis V. Lunev5a3e55d2007-12-07 00:38:10 -0800393 struct net_device *loopback_dev =
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900394 dev_net(dev)->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395
David S. Miller97cac082012-07-02 22:43:47 -0700396 if (dev != loopback_dev) {
397 if (idev && idev->dev == dev) {
398 struct inet6_dev *loopback_idev =
399 in6_dev_get(loopback_dev);
400 if (loopback_idev) {
401 rt->rt6i_idev = loopback_idev;
402 in6_dev_put(idev);
403 }
404 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 }
406}
407
Martin KaFai Lau5973fb12015-11-11 11:51:07 -0800408static bool __rt6_check_expired(const struct rt6_info *rt)
409{
410 if (rt->rt6i_flags & RTF_EXPIRES)
411 return time_after(jiffies, rt->dst.expires);
412 else
413 return false;
414}
415
Eric Dumazeta50feda2012-05-18 18:57:34 +0000416static bool rt6_check_expired(const struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417{
Gao feng1716a962012-04-06 00:13:10 +0000418 if (rt->rt6i_flags & RTF_EXPIRES) {
419 if (time_after(jiffies, rt->dst.expires))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000420 return true;
Gao feng1716a962012-04-06 00:13:10 +0000421 } else if (rt->dst.from) {
Li RongQing3fd91fb2012-09-13 19:54:57 +0000422 return rt6_check_expired((struct rt6_info *) rt->dst.from);
Gao feng1716a962012-04-06 00:13:10 +0000423 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000424 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425}
426
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000427/* Multipath route selection:
428 * Hash based function using packet header and flowlabel.
429 * Adapted from fib_info_hashfn()
430 */
431static int rt6_info_hash_nhsfn(unsigned int candidate_count,
432 const struct flowi6 *fl6)
433{
Tom Herbert644d0e62015-09-23 14:13:35 -0700434 return get_hash_from_flowi6(fl6) % candidate_count;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000435}
436
437static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200438 struct flowi6 *fl6, int oif,
439 int strict)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000440{
441 struct rt6_info *sibling, *next_sibling;
442 int route_choosen;
443
444 route_choosen = rt6_info_hash_nhsfn(match->rt6i_nsiblings + 1, fl6);
445 /* Don't change the route, if route_choosen == 0
446 * (siblings does not include ourself)
447 */
448 if (route_choosen)
449 list_for_each_entry_safe(sibling, next_sibling,
450 &match->rt6i_siblings, rt6i_siblings) {
451 route_choosen--;
452 if (route_choosen == 0) {
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200453 if (rt6_score_route(sibling, oif, strict) < 0)
454 break;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000455 match = sibling;
456 break;
457 }
458 }
459 return match;
460}
461
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462/*
Thomas Grafc71099a2006-08-04 23:20:06 -0700463 * Route lookup. Any table->tb6_lock is implied.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 */
465
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800466static inline struct rt6_info *rt6_device_match(struct net *net,
467 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000468 const struct in6_addr *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 int oif,
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700470 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471{
472 struct rt6_info *local = NULL;
473 struct rt6_info *sprt;
474
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900475 if (!oif && ipv6_addr_any(saddr))
476 goto out;
477
Changli Gaod8d1f302010-06-10 23:31:35 -0700478 for (sprt = rt; sprt; sprt = sprt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -0500479 struct net_device *dev = sprt->dst.dev;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900480
481 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 if (dev->ifindex == oif)
483 return sprt;
484 if (dev->flags & IFF_LOOPBACK) {
David S. Miller38308472011-12-03 18:02:47 -0500485 if (!sprt->rt6i_idev ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 sprt->rt6i_idev->dev->ifindex != oif) {
David Ahern17fb0b22015-09-25 15:22:54 -0600487 if (flags & RT6_LOOKUP_F_IFACE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 continue;
David Ahern17fb0b22015-09-25 15:22:54 -0600489 if (local &&
490 local->rt6i_idev->dev->ifindex == oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 continue;
492 }
493 local = sprt;
494 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900495 } else {
496 if (ipv6_chk_addr(net, saddr, dev,
497 flags & RT6_LOOKUP_F_IFACE))
498 return sprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900502 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 if (local)
504 return local;
505
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700506 if (flags & RT6_LOOKUP_F_IFACE)
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800507 return net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900509out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 return rt;
511}
512
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800513#ifdef CONFIG_IPV6_ROUTER_PREF
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200514struct __rt6_probe_work {
515 struct work_struct work;
516 struct in6_addr target;
517 struct net_device *dev;
518};
519
520static void rt6_probe_deferred(struct work_struct *w)
521{
522 struct in6_addr mcaddr;
523 struct __rt6_probe_work *work =
524 container_of(w, struct __rt6_probe_work, work);
525
526 addrconf_addr_solict_mult(&work->target, &mcaddr);
Nicolas Dichtel304d8882015-11-27 18:17:05 +0100527 ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200528 dev_put(work->dev);
Michael Büsch662f5532015-02-08 10:14:07 +0100529 kfree(work);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200530}
531
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800532static void rt6_probe(struct rt6_info *rt)
533{
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700534 struct __rt6_probe_work *work;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000535 struct neighbour *neigh;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800536 /*
537 * Okay, this does not seem to be appropriate
538 * for now, however, we need to check if it
539 * is really so; aka Router Reachability Probing.
540 *
541 * Router Reachability Probe MUST be rate-limited
542 * to no more than one per minute.
543 */
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000544 if (!rt || !(rt->rt6i_flags & RTF_GATEWAY))
Amerigo Wangfdd66812012-09-10 02:48:44 +0000545 return;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000546 rcu_read_lock_bh();
547 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
548 if (neigh) {
Martin KaFai Lau8d6c31b2015-07-24 09:57:43 -0700549 if (neigh->nud_state & NUD_VALID)
550 goto out;
551
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700552 work = NULL;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000553 write_lock(&neigh->lock);
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700554 if (!(neigh->nud_state & NUD_VALID) &&
555 time_after(jiffies,
556 neigh->updated +
557 rt->rt6i_idev->cnf.rtr_probe_interval)) {
558 work = kmalloc(sizeof(*work), GFP_ATOMIC);
559 if (work)
560 __neigh_set_probe_once(neigh);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200561 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000562 write_unlock(&neigh->lock);
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700563 } else {
564 work = kmalloc(sizeof(*work), GFP_ATOMIC);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000565 }
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700566
567 if (work) {
568 INIT_WORK(&work->work, rt6_probe_deferred);
569 work->target = rt->rt6i_gateway;
570 dev_hold(rt->dst.dev);
571 work->dev = rt->dst.dev;
572 schedule_work(&work->work);
573 }
574
Martin KaFai Lau8d6c31b2015-07-24 09:57:43 -0700575out:
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000576 rcu_read_unlock_bh();
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800577}
578#else
579static inline void rt6_probe(struct rt6_info *rt)
580{
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800581}
582#endif
583
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584/*
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800585 * Default Router Selection (RFC 2461 6.3.6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 */
Dave Jonesb6f99a22007-03-22 12:27:49 -0700587static inline int rt6_check_dev(struct rt6_info *rt, int oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588{
David S. Millerd1918542011-12-28 20:19:20 -0500589 struct net_device *dev = rt->dst.dev;
David S. Miller161980f2007-04-06 11:42:27 -0700590 if (!oif || dev->ifindex == oif)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800591 return 2;
David S. Miller161980f2007-04-06 11:42:27 -0700592 if ((dev->flags & IFF_LOOPBACK) &&
593 rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
594 return 1;
595 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596}
597
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200598static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000600 struct neighbour *neigh;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200601 enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000602
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700603 if (rt->rt6i_flags & RTF_NONEXTHOP ||
604 !(rt->rt6i_flags & RTF_GATEWAY))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200605 return RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000606
607 rcu_read_lock_bh();
608 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
609 if (neigh) {
610 read_lock(&neigh->lock);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800611 if (neigh->nud_state & NUD_VALID)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200612 ret = RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800613#ifdef CONFIG_IPV6_ROUTER_PREF
Paul Marksa5a81f02012-12-03 10:26:54 +0000614 else if (!(neigh->nud_state & NUD_FAILED))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200615 ret = RT6_NUD_SUCCEED;
Jiri Benc7e980562013-12-11 13:48:20 +0100616 else
617 ret = RT6_NUD_FAIL_PROBE;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800618#endif
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000619 read_unlock(&neigh->lock);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200620 } else {
621 ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
Jiri Benc7e980562013-12-11 13:48:20 +0100622 RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR;
Paul Marksa5a81f02012-12-03 10:26:54 +0000623 }
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000624 rcu_read_unlock_bh();
625
Paul Marksa5a81f02012-12-03 10:26:54 +0000626 return ret;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800627}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800629static int rt6_score_route(struct rt6_info *rt, int oif,
630 int strict)
631{
Paul Marksa5a81f02012-12-03 10:26:54 +0000632 int m;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900633
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700634 m = rt6_check_dev(rt, oif);
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700635 if (!m && (strict & RT6_LOOKUP_F_IFACE))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200636 return RT6_NUD_FAIL_HARD;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800637#ifdef CONFIG_IPV6_ROUTER_PREF
638 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
639#endif
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200640 if (strict & RT6_LOOKUP_F_REACHABLE) {
641 int n = rt6_check_neigh(rt);
642 if (n < 0)
643 return n;
644 }
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800645 return m;
646}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
David S. Millerf11e6652007-03-24 20:36:25 -0700648static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200649 int *mpri, struct rt6_info *match,
650 bool *do_rr)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800651{
David S. Millerf11e6652007-03-24 20:36:25 -0700652 int m;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200653 bool match_do_rr = false;
Andy Gospodarek35103d12015-08-13 10:39:01 -0400654 struct inet6_dev *idev = rt->rt6i_idev;
655 struct net_device *dev = rt->dst.dev;
656
657 if (dev && !netif_carrier_ok(dev) &&
658 idev->cnf.ignore_routes_with_linkdown)
659 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700660
661 if (rt6_check_expired(rt))
662 goto out;
663
664 m = rt6_score_route(rt, oif, strict);
Jiri Benc7e980562013-12-11 13:48:20 +0100665 if (m == RT6_NUD_FAIL_DO_RR) {
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200666 match_do_rr = true;
667 m = 0; /* lowest valid score */
Jiri Benc7e980562013-12-11 13:48:20 +0100668 } else if (m == RT6_NUD_FAIL_HARD) {
David S. Millerf11e6652007-03-24 20:36:25 -0700669 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700670 }
671
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200672 if (strict & RT6_LOOKUP_F_REACHABLE)
673 rt6_probe(rt);
674
Jiri Benc7e980562013-12-11 13:48:20 +0100675 /* note that m can be RT6_NUD_FAIL_PROBE at this point */
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200676 if (m > *mpri) {
677 *do_rr = match_do_rr;
678 *mpri = m;
679 match = rt;
680 }
David S. Millerf11e6652007-03-24 20:36:25 -0700681out:
682 return match;
683}
684
685static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
686 struct rt6_info *rr_head,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200687 u32 metric, int oif, int strict,
688 bool *do_rr)
David S. Millerf11e6652007-03-24 20:36:25 -0700689{
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700690 struct rt6_info *rt, *match, *cont;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800691 int mpri = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
David S. Millerf11e6652007-03-24 20:36:25 -0700693 match = NULL;
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700694 cont = NULL;
695 for (rt = rr_head; rt; rt = rt->dst.rt6_next) {
696 if (rt->rt6i_metric != metric) {
697 cont = rt;
698 break;
699 }
700
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200701 match = find_match(rt, oif, strict, &mpri, match, do_rr);
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700702 }
703
704 for (rt = fn->leaf; rt && rt != rr_head; rt = rt->dst.rt6_next) {
705 if (rt->rt6i_metric != metric) {
706 cont = rt;
707 break;
708 }
709
710 match = find_match(rt, oif, strict, &mpri, match, do_rr);
711 }
712
713 if (match || !cont)
714 return match;
715
716 for (rt = cont; rt; rt = rt->dst.rt6_next)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200717 match = find_match(rt, oif, strict, &mpri, match, do_rr);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800718
David S. Millerf11e6652007-03-24 20:36:25 -0700719 return match;
720}
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800721
David S. Millerf11e6652007-03-24 20:36:25 -0700722static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
723{
724 struct rt6_info *match, *rt0;
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800725 struct net *net;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200726 bool do_rr = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727
David S. Millerf11e6652007-03-24 20:36:25 -0700728 rt0 = fn->rr_ptr;
729 if (!rt0)
730 fn->rr_ptr = rt0 = fn->leaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200732 match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict,
733 &do_rr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200735 if (do_rr) {
Changli Gaod8d1f302010-06-10 23:31:35 -0700736 struct rt6_info *next = rt0->dst.rt6_next;
David S. Millerf11e6652007-03-24 20:36:25 -0700737
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800738 /* no entries matched; do round-robin */
David S. Millerf11e6652007-03-24 20:36:25 -0700739 if (!next || next->rt6i_metric != rt0->rt6i_metric)
740 next = fn->leaf;
741
742 if (next != rt0)
743 fn->rr_ptr = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 }
745
David S. Millerd1918542011-12-28 20:19:20 -0500746 net = dev_net(rt0->dst.dev);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000747 return match ? match : net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748}
749
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700750static bool rt6_is_gw_or_nonexthop(const struct rt6_info *rt)
751{
752 return (rt->rt6i_flags & (RTF_NONEXTHOP | RTF_GATEWAY));
753}
754
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800755#ifdef CONFIG_IPV6_ROUTE_INFO
756int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000757 const struct in6_addr *gwaddr)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800758{
759 struct route_info *rinfo = (struct route_info *) opt;
760 struct in6_addr prefix_buf, *prefix;
761 unsigned int pref;
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900762 unsigned long lifetime;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800763 struct rt6_info *rt;
764
765 if (len < sizeof(struct route_info)) {
766 return -EINVAL;
767 }
768
769 /* Sanity check for prefix_len and length */
770 if (rinfo->length > 3) {
771 return -EINVAL;
772 } else if (rinfo->prefix_len > 128) {
773 return -EINVAL;
774 } else if (rinfo->prefix_len > 64) {
775 if (rinfo->length < 2) {
776 return -EINVAL;
777 }
778 } else if (rinfo->prefix_len > 0) {
779 if (rinfo->length < 1) {
780 return -EINVAL;
781 }
782 }
783
784 pref = rinfo->route_pref;
785 if (pref == ICMPV6_ROUTER_PREF_INVALID)
Jens Rosenboom3933fc92009-09-10 06:25:11 +0000786 return -EINVAL;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800787
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900788 lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800789
790 if (rinfo->length == 3)
791 prefix = (struct in6_addr *)rinfo->prefix;
792 else {
793 /* this function is safe */
794 ipv6_addr_prefix(&prefix_buf,
795 (struct in6_addr *)rinfo->prefix,
796 rinfo->prefix_len);
797 prefix = &prefix_buf;
798 }
799
Duan Jiongf104a562013-11-08 09:56:53 +0800800 if (rinfo->prefix_len == 0)
801 rt = rt6_get_dflt_router(gwaddr, dev);
802 else
Amit Pundir4cab8a32015-03-25 04:29:14 +0530803 rt = rt6_get_route_info(dev, prefix, rinfo->prefix_len, gwaddr);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800804
805 if (rt && !lifetime) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -0700806 ip6_del_rt(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800807 rt = NULL;
808 }
809
810 if (!rt && lifetime)
Lorenzo Colitti9fcb87d2014-03-26 19:35:41 +0900811 rt = rt6_add_route_info(dev, prefix, rinfo->prefix_len, gwaddr, pref);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800812 else if (rt)
813 rt->rt6i_flags = RTF_ROUTEINFO |
814 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
815
816 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +0000817 if (!addrconf_finite_timeout(lifetime))
818 rt6_clean_expires(rt);
819 else
820 rt6_set_expires(rt, jiffies + HZ * lifetime);
821
Amerigo Wang94e187c2012-10-29 00:13:19 +0000822 ip6_rt_put(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800823 }
824 return 0;
825}
826#endif
827
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700828static struct fib6_node* fib6_backtrack(struct fib6_node *fn,
829 struct in6_addr *saddr)
830{
831 struct fib6_node *pn;
832 while (1) {
833 if (fn->fn_flags & RTN_TL_ROOT)
834 return NULL;
835 pn = fn->parent;
836 if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn)
837 fn = fib6_lookup(FIB6_SUBTREE(pn), NULL, saddr);
838 else
839 fn = pn;
840 if (fn->fn_flags & RTN_RTINFO)
841 return fn;
842 }
843}
Thomas Grafc71099a2006-08-04 23:20:06 -0700844
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800845static struct rt6_info *ip6_pol_route_lookup(struct net *net,
846 struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500847 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848{
849 struct fib6_node *fn;
850 struct rt6_info *rt;
851
Thomas Grafc71099a2006-08-04 23:20:06 -0700852 read_lock_bh(&table->tb6_lock);
David S. Miller4c9483b2011-03-12 16:22:43 -0500853 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -0700854restart:
855 rt = fn->leaf;
David S. Miller4c9483b2011-03-12 16:22:43 -0500856 rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000857 if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0)
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200858 rt = rt6_multipath_select(rt, fl6, fl6->flowi6_oif, flags);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700859 if (rt == net->ipv6.ip6_null_entry) {
860 fn = fib6_backtrack(fn, &fl6->saddr);
861 if (fn)
862 goto restart;
863 }
Changli Gaod8d1f302010-06-10 23:31:35 -0700864 dst_use(&rt->dst, jiffies);
Thomas Grafc71099a2006-08-04 23:20:06 -0700865 read_unlock_bh(&table->tb6_lock);
David Ahernb8115802015-11-19 12:24:22 -0800866
867 trace_fib6_table_lookup(net, rt, table->tb6_id, fl6);
868
Thomas Grafc71099a2006-08-04 23:20:06 -0700869 return rt;
870
871}
872
Ian Morris67ba4152014-08-24 21:53:10 +0100873struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
Florian Westphalea6e5742011-09-05 16:05:44 +0200874 int flags)
875{
876 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup);
877}
878EXPORT_SYMBOL_GPL(ip6_route_lookup);
879
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900880struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
881 const struct in6_addr *saddr, int oif, int strict)
Thomas Grafc71099a2006-08-04 23:20:06 -0700882{
David S. Miller4c9483b2011-03-12 16:22:43 -0500883 struct flowi6 fl6 = {
884 .flowi6_oif = oif,
885 .daddr = *daddr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700886 };
887 struct dst_entry *dst;
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700888 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
Thomas Grafc71099a2006-08-04 23:20:06 -0700889
Thomas Grafadaa70b2006-10-13 15:01:03 -0700890 if (saddr) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500891 memcpy(&fl6.saddr, saddr, sizeof(*saddr));
Thomas Grafadaa70b2006-10-13 15:01:03 -0700892 flags |= RT6_LOOKUP_F_HAS_SADDR;
893 }
894
David S. Miller4c9483b2011-03-12 16:22:43 -0500895 dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup);
Thomas Grafc71099a2006-08-04 23:20:06 -0700896 if (dst->error == 0)
897 return (struct rt6_info *) dst;
898
899 dst_release(dst);
900
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 return NULL;
902}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900903EXPORT_SYMBOL(rt6_lookup);
904
Thomas Grafc71099a2006-08-04 23:20:06 -0700905/* ip6_ins_rt is called with FREE table->tb6_lock.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 It takes new route entry, the addition fails by any reason the
907 route is freed. In any case, if caller does not hold it, it may
908 be destroyed.
909 */
910
Michal Kubečeke5fd3872014-03-27 13:04:08 +0100911static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info,
Florian Westphale715b6d2015-01-05 23:57:44 +0100912 struct mx6_config *mxc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913{
914 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -0700915 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
Thomas Grafc71099a2006-08-04 23:20:06 -0700917 table = rt->rt6i_table;
918 write_lock_bh(&table->tb6_lock);
Florian Westphale715b6d2015-01-05 23:57:44 +0100919 err = fib6_add(&table->tb6_root, rt, info, mxc);
Thomas Grafc71099a2006-08-04 23:20:06 -0700920 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921
922 return err;
923}
924
Thomas Graf40e22e82006-08-22 00:00:45 -0700925int ip6_ins_rt(struct rt6_info *rt)
926{
Florian Westphale715b6d2015-01-05 23:57:44 +0100927 struct nl_info info = { .nl_net = dev_net(rt->dst.dev), };
928 struct mx6_config mxc = { .mx = NULL, };
929
930 return __ip6_ins_rt(rt, &info, &mxc);
Thomas Graf40e22e82006-08-22 00:00:45 -0700931}
932
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700933static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort,
934 const struct in6_addr *daddr,
935 const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 struct rt6_info *rt;
938
939 /*
940 * Clone the route.
941 */
942
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700943 if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU))
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700944 ort = (struct rt6_info *)ort->dst.from;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
Martin KaFai Lauad706862015-08-14 11:05:52 -0700946 rt = __ip6_dst_alloc(dev_net(ort->dst.dev), ort->dst.dev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700948 if (!rt)
949 return NULL;
950
951 ip6_rt_copy_init(rt, ort);
952 rt->rt6i_flags |= RTF_CACHE;
953 rt->rt6i_metric = 0;
954 rt->dst.flags |= DST_HOST;
955 rt->rt6i_dst.addr = *daddr;
956 rt->rt6i_dst.plen = 128;
957
958 if (!rt6_is_gw_or_nonexthop(ort)) {
959 if (ort->rt6i_dst.plen != 128 &&
960 ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
961 rt->rt6i_flags |= RTF_ANYCAST;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700963 if (rt->rt6i_src.plen && saddr) {
964 rt->rt6i_src.addr = *saddr;
965 rt->rt6i_src.plen = 128;
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700966 }
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700967#endif
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800968 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800970 return rt;
971}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700973static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt)
974{
975 struct rt6_info *pcpu_rt;
976
977 pcpu_rt = __ip6_dst_alloc(dev_net(rt->dst.dev),
Martin KaFai Lauad706862015-08-14 11:05:52 -0700978 rt->dst.dev, rt->dst.flags);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700979
980 if (!pcpu_rt)
981 return NULL;
982 ip6_rt_copy_init(pcpu_rt, rt);
983 pcpu_rt->rt6i_protocol = rt->rt6i_protocol;
984 pcpu_rt->rt6i_flags |= RTF_PCPU;
985 return pcpu_rt;
986}
987
988/* It should be called with read_lock_bh(&tb6_lock) acquired */
989static struct rt6_info *rt6_get_pcpu_route(struct rt6_info *rt)
990{
Martin KaFai Laua73e4192015-08-14 11:05:53 -0700991 struct rt6_info *pcpu_rt, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700992
993 p = this_cpu_ptr(rt->rt6i_pcpu);
994 pcpu_rt = *p;
995
Martin KaFai Laua73e4192015-08-14 11:05:53 -0700996 if (pcpu_rt) {
997 dst_hold(&pcpu_rt->dst);
998 rt6_dst_from_metrics_check(pcpu_rt);
999 }
1000 return pcpu_rt;
1001}
1002
1003static struct rt6_info *rt6_make_pcpu_route(struct rt6_info *rt)
1004{
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001005 struct fib6_table *table = rt->rt6i_table;
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001006 struct rt6_info *pcpu_rt, *prev, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001007
1008 pcpu_rt = ip6_rt_pcpu_alloc(rt);
1009 if (!pcpu_rt) {
1010 struct net *net = dev_net(rt->dst.dev);
1011
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001012 dst_hold(&net->ipv6.ip6_null_entry->dst);
1013 return net->ipv6.ip6_null_entry;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001014 }
1015
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001016 read_lock_bh(&table->tb6_lock);
1017 if (rt->rt6i_pcpu) {
1018 p = this_cpu_ptr(rt->rt6i_pcpu);
1019 prev = cmpxchg(p, NULL, pcpu_rt);
1020 if (prev) {
1021 /* If someone did it before us, return prev instead */
1022 dst_destroy(&pcpu_rt->dst);
1023 pcpu_rt = prev;
1024 }
1025 } else {
1026 /* rt has been removed from the fib6 tree
1027 * before we have a chance to acquire the read_lock.
1028 * In this case, don't brother to create a pcpu rt
1029 * since rt is going away anyway. The next
1030 * dst_check() will trigger a re-lookup.
1031 */
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001032 dst_destroy(&pcpu_rt->dst);
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001033 pcpu_rt = rt;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001034 }
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001035 dst_hold(&pcpu_rt->dst);
1036 rt6_dst_from_metrics_check(pcpu_rt);
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001037 read_unlock_bh(&table->tb6_lock);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001038 return pcpu_rt;
1039}
1040
David Ahern9ff74382016-06-13 13:44:19 -07001041struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
1042 int oif, struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043{
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001044 struct fib6_node *fn, *saved_fn;
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001045 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001046 int strict = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001048 strict |= flags & RT6_LOOKUP_F_IFACE;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001049 if (net->ipv6.devconf_all->forwarding == 0)
1050 strict |= RT6_LOOKUP_F_REACHABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051
Thomas Grafc71099a2006-08-04 23:20:06 -07001052 read_lock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053
David S. Miller4c9483b2011-03-12 16:22:43 -05001054 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001055 saved_fn = fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056
David Ahernca254492015-10-12 11:47:10 -07001057 if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
1058 oif = 0;
1059
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001060redo_rt6_select:
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001061 rt = rt6_select(fn, oif, strict);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +02001062 if (rt->rt6i_nsiblings)
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001063 rt = rt6_multipath_select(rt, fl6, oif, strict);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001064 if (rt == net->ipv6.ip6_null_entry) {
1065 fn = fib6_backtrack(fn, &fl6->saddr);
1066 if (fn)
1067 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001068 else if (strict & RT6_LOOKUP_F_REACHABLE) {
1069 /* also consider unreachable route */
1070 strict &= ~RT6_LOOKUP_F_REACHABLE;
1071 fn = saved_fn;
1072 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001073 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001074 }
1075
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -08001076
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001077 if (rt == net->ipv6.ip6_null_entry || (rt->rt6i_flags & RTF_CACHE)) {
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001078 dst_use(&rt->dst, jiffies);
1079 read_unlock_bh(&table->tb6_lock);
1080
1081 rt6_dst_from_metrics_check(rt);
David Ahernb8115802015-11-19 12:24:22 -08001082
1083 trace_fib6_table_lookup(net, rt, table->tb6_id, fl6);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001084 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);
David Ahernb8115802015-11-19 12:24:22 -08001107
1108 trace_fib6_table_lookup(net, uncached_rt, table->tb6_id, fl6);
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001109 return uncached_rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001110
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001111 } else {
1112 /* Get a percpu copy */
1113
1114 struct rt6_info *pcpu_rt;
1115
1116 rt->dst.lastuse = jiffies;
1117 rt->dst.__use++;
1118 pcpu_rt = rt6_get_pcpu_route(rt);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001119
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001120 if (pcpu_rt) {
1121 read_unlock_bh(&table->tb6_lock);
1122 } else {
1123 /* We have to do the read_unlock first
1124 * because rt6_make_pcpu_route() may trigger
1125 * ip6_dst_gc() which will take the write_lock.
1126 */
1127 dst_hold(&rt->dst);
1128 read_unlock_bh(&table->tb6_lock);
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001129 pcpu_rt = rt6_make_pcpu_route(rt);
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001130 dst_release(&rt->dst);
1131 }
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001132
David Ahernb8115802015-11-19 12:24:22 -08001133 trace_fib6_table_lookup(net, pcpu_rt, table->tb6_id, fl6);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001134 return pcpu_rt;
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001135
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001136 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001137}
David Ahern9ff74382016-06-13 13:44:19 -07001138EXPORT_SYMBOL_GPL(ip6_pol_route);
Thomas Grafc71099a2006-08-04 23:20:06 -07001139
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001140static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -05001141 struct flowi6 *fl6, int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001142{
David S. Miller4c9483b2011-03-12 16:22:43 -05001143 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001144}
1145
Mahesh Bandeward409b842016-09-16 12:59:08 -07001146struct dst_entry *ip6_route_input_lookup(struct net *net,
1147 struct net_device *dev,
1148 struct flowi6 *fl6, int flags)
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001149{
1150 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
1151 flags |= RT6_LOOKUP_F_IFACE;
1152
1153 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_input);
1154}
Mahesh Bandeward409b842016-09-16 12:59:08 -07001155EXPORT_SYMBOL_GPL(ip6_route_input_lookup);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001156
Thomas Grafc71099a2006-08-04 23:20:06 -07001157void ip6_route_input(struct sk_buff *skb)
1158{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001159 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001160 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001161 int flags = RT6_LOOKUP_F_HAS_SADDR;
Jiri Benc904af042015-08-20 13:56:31 +02001162 struct ip_tunnel_info *tun_info;
David S. Miller4c9483b2011-03-12 16:22:43 -05001163 struct flowi6 fl6 = {
David Aherne0d56fd2016-09-10 12:09:57 -07001164 .flowi6_iif = skb->dev->ifindex,
David S. Miller4c9483b2011-03-12 16:22:43 -05001165 .daddr = iph->daddr,
1166 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001167 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -05001168 .flowi6_mark = skb->mark,
1169 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -07001170 };
Thomas Grafadaa70b2006-10-13 15:01:03 -07001171
Jiri Benc904af042015-08-20 13:56:31 +02001172 tun_info = skb_tunnel_info(skb);
Jiri Benc46fa0622015-08-28 20:48:19 +02001173 if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX))
Jiri Benc904af042015-08-20 13:56:31 +02001174 fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id;
Jiri Benc06e9d042015-08-20 13:56:26 +02001175 skb_dst_drop(skb);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001176 skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -07001177}
1178
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001179static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -05001180 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07001181{
David S. Miller4c9483b2011-03-12 16:22:43 -05001182 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -07001183}
1184
Paolo Abeni6f21c962016-01-29 12:30:19 +01001185struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk,
1186 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07001187{
David Ahernd46a9d62015-10-21 08:42:22 -07001188 bool any_src;
Thomas Grafc71099a2006-08-04 23:20:06 -07001189
David Ahern4c1feac2016-09-10 12:09:56 -07001190 if (rt6_need_strict(&fl6->daddr)) {
1191 struct dst_entry *dst;
1192
1193 dst = l3mdev_link_scope_lookup(net, fl6);
1194 if (dst)
1195 return dst;
1196 }
David Ahernca254492015-10-12 11:47:10 -07001197
Pavel Emelyanov1fb94892012-08-08 21:53:36 +00001198 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +00001199
David Ahernd46a9d62015-10-21 08:42:22 -07001200 any_src = ipv6_addr_any(&fl6->saddr);
David Ahern741a11d2015-09-28 10:12:13 -07001201 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) ||
David Ahernd46a9d62015-10-21 08:42:22 -07001202 (fl6->flowi6_oif && any_src))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001203 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -07001204
David Ahernd46a9d62015-10-21 08:42:22 -07001205 if (!any_src)
Thomas Grafadaa70b2006-10-13 15:01:03 -07001206 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +00001207 else if (sk)
1208 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001209
David S. Miller4c9483b2011-03-12 16:22:43 -05001210 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211}
Paolo Abeni6f21c962016-01-29 12:30:19 +01001212EXPORT_SYMBOL_GPL(ip6_route_output_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213
David S. Miller2774c132011-03-01 14:59:04 -08001214struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -07001215{
David S. Miller5c1e6aa2011-04-28 14:13:38 -07001216 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
David S. Miller14e50e52007-05-24 18:17:54 -07001217 struct dst_entry *new = NULL;
1218
David S. Millerf5b0a872012-07-19 12:31:33 -07001219 rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, DST_OBSOLETE_NONE, 0);
David S. Miller14e50e52007-05-24 18:17:54 -07001220 if (rt) {
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07001221 rt6_info_init(rt);
1222
Changli Gaod8d1f302010-06-10 23:31:35 -07001223 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -07001224 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08001225 new->input = dst_discard;
Eric W. Biedermanede20592015-10-07 16:48:47 -05001226 new->output = dst_discard_out;
David S. Miller14e50e52007-05-24 18:17:54 -07001227
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07001228 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07001229 rt->rt6i_idev = ort->rt6i_idev;
1230 if (rt->rt6i_idev)
1231 in6_dev_hold(rt->rt6i_idev);
David S. Miller14e50e52007-05-24 18:17:54 -07001232
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001233 rt->rt6i_gateway = ort->rt6i_gateway;
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07001234 rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU;
David S. Miller14e50e52007-05-24 18:17:54 -07001235 rt->rt6i_metric = 0;
1236
1237 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
1238#ifdef CONFIG_IPV6_SUBTREES
1239 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1240#endif
1241
1242 dst_free(new);
1243 }
1244
David S. Miller69ead7a2011-03-01 14:45:33 -08001245 dst_release(dst_orig);
1246 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07001247}
David S. Miller14e50e52007-05-24 18:17:54 -07001248
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249/*
1250 * Destination cache support functions
1251 */
1252
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001253static void rt6_dst_from_metrics_check(struct rt6_info *rt)
1254{
1255 if (rt->dst.from &&
1256 dst_metrics_ptr(&rt->dst) != dst_metrics_ptr(rt->dst.from))
1257 dst_init_metrics(&rt->dst, dst_metrics_ptr(rt->dst.from), true);
1258}
1259
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001260static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie)
1261{
1262 if (!rt->rt6i_node || (rt->rt6i_node->fn_sernum != cookie))
1263 return NULL;
1264
1265 if (rt6_check_expired(rt))
1266 return NULL;
1267
1268 return &rt->dst;
1269}
1270
1271static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, u32 cookie)
1272{
Martin KaFai Lau5973fb12015-11-11 11:51:07 -08001273 if (!__rt6_check_expired(rt) &&
1274 rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001275 rt6_check((struct rt6_info *)(rt->dst.from), cookie))
1276 return &rt->dst;
1277 else
1278 return NULL;
1279}
1280
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
1282{
1283 struct rt6_info *rt;
1284
1285 rt = (struct rt6_info *) dst;
1286
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00001287 /* All IPV6 dsts are created with ->obsolete set to the value
1288 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
1289 * into this function always.
1290 */
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02001291
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001292 rt6_dst_from_metrics_check(rt);
1293
Martin KaFai Lau02bcf4e2015-11-11 11:51:08 -08001294 if (rt->rt6i_flags & RTF_PCPU ||
1295 (unlikely(dst->flags & DST_NOCACHE) && rt->dst.from))
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001296 return rt6_dst_from_check(rt, cookie);
1297 else
1298 return rt6_check(rt, cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299}
1300
1301static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
1302{
1303 struct rt6_info *rt = (struct rt6_info *) dst;
1304
1305 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001306 if (rt->rt6i_flags & RTF_CACHE) {
1307 if (rt6_check_expired(rt)) {
1308 ip6_del_rt(rt);
1309 dst = NULL;
1310 }
1311 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001313 dst = NULL;
1314 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001316 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317}
1318
1319static void ip6_link_failure(struct sk_buff *skb)
1320{
1321 struct rt6_info *rt;
1322
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00001323 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324
Eric Dumazetadf30902009-06-02 05:19:30 +00001325 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 if (rt) {
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001327 if (rt->rt6i_flags & RTF_CACHE) {
1328 dst_hold(&rt->dst);
Martin KaFai Lau8e3d5be2015-09-15 14:30:08 -07001329 ip6_del_rt(rt);
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001330 } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 rt->rt6i_node->fn_sernum = -1;
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001332 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 }
1334}
1335
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001336static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
1337{
1338 struct net *net = dev_net(rt->dst.dev);
1339
1340 rt->rt6i_flags |= RTF_MODIFIED;
1341 rt->rt6i_pmtu = mtu;
1342 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
1343}
1344
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08001345static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
1346{
1347 return !(rt->rt6i_flags & RTF_CACHE) &&
1348 (rt->rt6i_flags & RTF_PCPU || rt->rt6i_node);
1349}
1350
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001351static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
1352 const struct ipv6hdr *iph, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353{
Ian Morris67ba4152014-08-24 21:53:10 +01001354 struct rt6_info *rt6 = (struct rt6_info *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001356 if (rt6->rt6i_flags & RTF_LOCAL)
1357 return;
1358
David S. Miller81aded22012-06-15 14:54:11 -07001359 dst_confirm(dst);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001360 mtu = max_t(u32, mtu, IPV6_MIN_MTU);
1361 if (mtu >= dst_mtu(dst))
1362 return;
David S. Miller81aded22012-06-15 14:54:11 -07001363
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08001364 if (!rt6_cache_allowed_for_pmtu(rt6)) {
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001365 rt6_do_update_pmtu(rt6, mtu);
1366 } else {
1367 const struct in6_addr *daddr, *saddr;
1368 struct rt6_info *nrt6;
Hagen Paul Pfeifer9d289712015-01-15 22:34:25 +01001369
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001370 if (iph) {
1371 daddr = &iph->daddr;
1372 saddr = &iph->saddr;
1373 } else if (sk) {
1374 daddr = &sk->sk_v6_daddr;
1375 saddr = &inet6_sk(sk)->saddr;
1376 } else {
1377 return;
1378 }
1379 nrt6 = ip6_rt_cache_alloc(rt6, daddr, saddr);
1380 if (nrt6) {
1381 rt6_do_update_pmtu(nrt6, mtu);
1382
1383 /* ip6_ins_rt(nrt6) will bump the
1384 * rt6->rt6i_node->fn_sernum
1385 * which will fail the next rt6_check() and
1386 * invalidate the sk->sk_dst_cache.
1387 */
1388 ip6_ins_rt(nrt6);
1389 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 }
1391}
1392
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001393static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
1394 struct sk_buff *skb, u32 mtu)
1395{
1396 __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu);
1397}
1398
David S. Miller42ae66c2012-06-15 20:01:57 -07001399void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
Lorenzo Colitti3b824972014-03-31 16:23:51 +09001400 int oif, u32 mark, kuid_t uid)
David S. Miller81aded22012-06-15 14:54:11 -07001401{
1402 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1403 struct dst_entry *dst;
1404 struct flowi6 fl6;
1405
1406 memset(&fl6, 0, sizeof(fl6));
1407 fl6.flowi6_oif = oif;
Lorenzo Colitti1b3c61d2014-05-13 10:17:34 -07001408 fl6.flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark);
David S. Miller81aded22012-06-15 14:54:11 -07001409 fl6.daddr = iph->daddr;
1410 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001411 fl6.flowlabel = ip6_flowinfo(iph);
Lorenzo Colitti3b824972014-03-31 16:23:51 +09001412 fl6.flowi6_uid = uid;
David S. Miller81aded22012-06-15 14:54:11 -07001413
1414 dst = ip6_route_output(net, NULL, &fl6);
1415 if (!dst->error)
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001416 __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07001417 dst_release(dst);
1418}
1419EXPORT_SYMBOL_GPL(ip6_update_pmtu);
1420
1421void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
1422{
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07001423 struct dst_entry *dst;
1424
David S. Miller81aded22012-06-15 14:54:11 -07001425 ip6_update_pmtu(skb, sock_net(sk), mtu,
Lorenzo Colitti3b824972014-03-31 16:23:51 +09001426 sk->sk_bound_dev_if, sk->sk_mark, sock_i_uid(sk));
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07001427
1428 dst = __sk_dst_get(sk);
1429 if (!dst || !dst->obsolete ||
1430 dst->ops->check(dst, inet6_sk(sk)->dst_cookie))
1431 return;
1432
1433 bh_lock_sock(sk);
1434 if (!sock_owned_by_user(sk) && !ipv6_addr_v4mapped(&sk->sk_v6_daddr))
1435 ip6_datagram_dst_update(sk, false);
1436 bh_unlock_sock(sk);
David S. Miller81aded22012-06-15 14:54:11 -07001437}
1438EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
1439
Duan Jiongb55b76b2013-09-04 19:44:21 +08001440/* Handle redirects */
1441struct ip6rd_flowi {
1442 struct flowi6 fl6;
1443 struct in6_addr gateway;
1444};
1445
1446static struct rt6_info *__ip6_route_redirect(struct net *net,
1447 struct fib6_table *table,
1448 struct flowi6 *fl6,
1449 int flags)
1450{
1451 struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
1452 struct rt6_info *rt;
1453 struct fib6_node *fn;
1454
1455 /* Get the "current" route for this destination and
1456 * check if the redirect has come from approriate router.
1457 *
1458 * RFC 4861 specifies that redirects should only be
1459 * accepted if they come from the nexthop to the target.
1460 * Due to the way the routes are chosen, this notion
1461 * is a bit fuzzy and one might need to check all possible
1462 * routes.
1463 */
1464
1465 read_lock_bh(&table->tb6_lock);
1466 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
1467restart:
1468 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
1469 if (rt6_check_expired(rt))
1470 continue;
1471 if (rt->dst.error)
1472 break;
1473 if (!(rt->rt6i_flags & RTF_GATEWAY))
1474 continue;
1475 if (fl6->flowi6_oif != rt->dst.dev->ifindex)
1476 continue;
1477 if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway))
1478 continue;
1479 break;
1480 }
1481
1482 if (!rt)
1483 rt = net->ipv6.ip6_null_entry;
1484 else if (rt->dst.error) {
1485 rt = net->ipv6.ip6_null_entry;
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001486 goto out;
1487 }
1488
1489 if (rt == net->ipv6.ip6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001490 fn = fib6_backtrack(fn, &fl6->saddr);
1491 if (fn)
1492 goto restart;
Duan Jiongb55b76b2013-09-04 19:44:21 +08001493 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001494
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001495out:
Duan Jiongb55b76b2013-09-04 19:44:21 +08001496 dst_hold(&rt->dst);
1497
1498 read_unlock_bh(&table->tb6_lock);
1499
David Ahernb8115802015-11-19 12:24:22 -08001500 trace_fib6_table_lookup(net, rt, table->tb6_id, fl6);
Duan Jiongb55b76b2013-09-04 19:44:21 +08001501 return rt;
1502};
1503
1504static struct dst_entry *ip6_route_redirect(struct net *net,
1505 const struct flowi6 *fl6,
1506 const struct in6_addr *gateway)
1507{
1508 int flags = RT6_LOOKUP_F_HAS_SADDR;
1509 struct ip6rd_flowi rdfl;
1510
1511 rdfl.fl6 = *fl6;
1512 rdfl.gateway = *gateway;
1513
1514 return fib6_rule_lookup(net, &rdfl.fl6,
1515 flags, __ip6_route_redirect);
1516}
1517
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001518void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark)
1519{
1520 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1521 struct dst_entry *dst;
1522 struct flowi6 fl6;
1523
1524 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001525 fl6.flowi6_iif = LOOPBACK_IFINDEX;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001526 fl6.flowi6_oif = oif;
1527 fl6.flowi6_mark = mark;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001528 fl6.daddr = iph->daddr;
1529 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001530 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001531
Duan Jiongb55b76b2013-09-04 19:44:21 +08001532 dst = ip6_route_redirect(net, &fl6, &ipv6_hdr(skb)->saddr);
1533 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001534 dst_release(dst);
1535}
1536EXPORT_SYMBOL_GPL(ip6_redirect);
1537
Duan Jiongc92a59e2013-08-22 12:07:35 +08001538void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
1539 u32 mark)
1540{
1541 const struct ipv6hdr *iph = ipv6_hdr(skb);
1542 const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
1543 struct dst_entry *dst;
1544 struct flowi6 fl6;
1545
1546 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001547 fl6.flowi6_iif = LOOPBACK_IFINDEX;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001548 fl6.flowi6_oif = oif;
1549 fl6.flowi6_mark = mark;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001550 fl6.daddr = msg->dest;
1551 fl6.saddr = iph->daddr;
1552
Duan Jiongb55b76b2013-09-04 19:44:21 +08001553 dst = ip6_route_redirect(net, &fl6, &iph->saddr);
1554 rt6_do_redirect(dst, NULL, skb);
Duan Jiongc92a59e2013-08-22 12:07:35 +08001555 dst_release(dst);
1556}
1557
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001558void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
1559{
1560 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark);
1561}
1562EXPORT_SYMBOL_GPL(ip6_sk_redirect);
1563
David S. Miller0dbaee32010-12-13 12:52:14 -08001564static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565{
David S. Miller0dbaee32010-12-13 12:52:14 -08001566 struct net_device *dev = dst->dev;
1567 unsigned int mtu = dst_mtu(dst);
1568 struct net *net = dev_net(dev);
1569
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
1571
Daniel Lezcano55786892008-03-04 13:47:47 -08001572 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
1573 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
1575 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001576 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
1577 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
1578 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 * rely only on pmtu discovery"
1580 */
1581 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
1582 mtu = IPV6_MAXPLEN;
1583 return mtu;
1584}
1585
Steffen Klassertebb762f2011-11-23 02:12:51 +00001586static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08001587{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001588 const struct rt6_info *rt = (const struct rt6_info *)dst;
1589 unsigned int mtu = rt->rt6i_pmtu;
David S. Millerd33e4552010-12-14 13:01:14 -08001590 struct inet6_dev *idev;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001591
1592 if (mtu)
Eric Dumazet30f78d82014-04-10 21:23:36 -07001593 goto out;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001594
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001595 mtu = dst_metric_raw(dst, RTAX_MTU);
1596 if (mtu)
1597 goto out;
1598
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001599 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08001600
1601 rcu_read_lock();
1602 idev = __in6_dev_get(dst->dev);
1603 if (idev)
1604 mtu = idev->cnf.mtu6;
1605 rcu_read_unlock();
1606
Eric Dumazet30f78d82014-04-10 21:23:36 -07001607out:
Roopa Prabhu14972cb2016-08-24 20:10:43 -07001608 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
1609
1610 return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
David S. Millerd33e4552010-12-14 13:01:14 -08001611}
1612
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001613static struct dst_entry *icmp6_dst_gc_list;
1614static DEFINE_SPINLOCK(icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001615
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001616struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05001617 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618{
David S. Miller87a11572011-12-06 17:04:13 -05001619 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 struct rt6_info *rt;
1621 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001622 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623
David S. Miller38308472011-12-03 18:02:47 -05001624 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00001625 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626
Martin KaFai Lauad706862015-08-14 11:05:52 -07001627 rt = ip6_dst_alloc(net, dev, 0);
David S. Miller38308472011-12-03 18:02:47 -05001628 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05001630 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 goto out;
1632 }
1633
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001634 rt->dst.flags |= DST_HOST;
1635 rt->dst.output = ip6_output;
Changli Gaod8d1f302010-06-10 23:31:35 -07001636 atomic_set(&rt->dst.__refcnt, 1);
Julian Anastasov550bab42013-10-20 15:43:04 +03001637 rt->rt6i_gateway = fl6->daddr;
David S. Miller87a11572011-12-06 17:04:13 -05001638 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001639 rt->rt6i_dst.plen = 128;
1640 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08001641 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001643 spin_lock_bh(&icmp6_dst_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001644 rt->dst.next = icmp6_dst_gc_list;
1645 icmp6_dst_gc_list = &rt->dst;
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001646 spin_unlock_bh(&icmp6_dst_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647
Daniel Lezcano55786892008-03-04 13:47:47 -08001648 fib6_force_start_gc(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649
David S. Miller87a11572011-12-06 17:04:13 -05001650 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
1651
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652out:
David S. Miller87a11572011-12-06 17:04:13 -05001653 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654}
1655
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001656int icmp6_dst_gc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657{
Hagen Paul Pfeifere9476e92011-02-25 05:45:19 +00001658 struct dst_entry *dst, **pprev;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001659 int more = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001661 spin_lock_bh(&icmp6_dst_lock);
1662 pprev = &icmp6_dst_gc_list;
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001663
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 while ((dst = *pprev) != NULL) {
1665 if (!atomic_read(&dst->__refcnt)) {
1666 *pprev = dst->next;
1667 dst_free(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 } else {
1669 pprev = &dst->next;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001670 ++more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 }
1672 }
1673
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001674 spin_unlock_bh(&icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001675
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001676 return more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677}
1678
David S. Miller1e493d12008-09-10 17:27:15 -07001679static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg),
1680 void *arg)
1681{
1682 struct dst_entry *dst, **pprev;
1683
1684 spin_lock_bh(&icmp6_dst_lock);
1685 pprev = &icmp6_dst_gc_list;
1686 while ((dst = *pprev) != NULL) {
1687 struct rt6_info *rt = (struct rt6_info *) dst;
1688 if (func(rt, arg)) {
1689 *pprev = dst->next;
1690 dst_free(dst);
1691 } else {
1692 pprev = &dst->next;
1693 }
1694 }
1695 spin_unlock_bh(&icmp6_dst_lock);
1696}
1697
Daniel Lezcano569d3642008-01-18 03:56:57 -08001698static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699{
Alexey Dobriyan86393e52009-08-29 01:34:49 +00001700 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08001701 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
1702 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
1703 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
1704 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
1705 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001706 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707
Eric Dumazetfc66f952010-10-08 06:37:34 +00001708 entries = dst_entries_get_fast(ops);
Michal Kubeček49a18d82013-08-01 10:04:24 +02001709 if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00001710 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 goto out;
1712
Benjamin Thery6891a342008-03-04 13:49:47 -08001713 net->ipv6.ip6_rt_gc_expire++;
Li RongQing14956642014-05-19 17:30:28 +08001714 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
Eric Dumazetfc66f952010-10-08 06:37:34 +00001715 entries = dst_entries_get_slow(ops);
1716 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08001717 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08001719 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001720 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721}
1722
Florian Westphale715b6d2015-01-05 23:57:44 +01001723static int ip6_convert_metrics(struct mx6_config *mxc,
1724 const struct fib6_config *cfg)
1725{
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001726 bool ecn_ca = false;
Florian Westphale715b6d2015-01-05 23:57:44 +01001727 struct nlattr *nla;
1728 int remaining;
1729 u32 *mp;
1730
Ian Morris63159f22015-03-29 14:00:04 +01001731 if (!cfg->fc_mx)
Florian Westphale715b6d2015-01-05 23:57:44 +01001732 return 0;
1733
1734 mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
1735 if (unlikely(!mp))
1736 return -ENOMEM;
1737
1738 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
1739 int type = nla_type(nla);
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001740 u32 val;
Florian Westphale715b6d2015-01-05 23:57:44 +01001741
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001742 if (!type)
1743 continue;
1744 if (unlikely(type > RTAX_MAX))
1745 goto err;
Daniel Borkmannea697632015-01-05 23:57:47 +01001746
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001747 if (type == RTAX_CC_ALGO) {
1748 char tmp[TCP_CA_NAME_MAX];
1749
1750 nla_strlcpy(tmp, nla, sizeof(tmp));
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001751 val = tcp_ca_get_key_by_name(tmp, &ecn_ca);
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001752 if (val == TCP_CA_UNSPEC)
Florian Westphale715b6d2015-01-05 23:57:44 +01001753 goto err;
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001754 } else {
1755 val = nla_get_u32(nla);
Florian Westphale715b6d2015-01-05 23:57:44 +01001756 }
Paolo Abeni626abd52016-05-13 18:33:41 +02001757 if (type == RTAX_HOPLIMIT && val > 255)
1758 val = 255;
Daniel Borkmannb8d3e412015-08-31 15:58:46 +02001759 if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK))
1760 goto err;
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001761
1762 mp[type - 1] = val;
1763 __set_bit(type - 1, mxc->mx_valid);
Florian Westphale715b6d2015-01-05 23:57:44 +01001764 }
1765
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001766 if (ecn_ca) {
1767 __set_bit(RTAX_FEATURES - 1, mxc->mx_valid);
1768 mp[RTAX_FEATURES - 1] |= DST_FEATURE_ECN_CA;
1769 }
Florian Westphale715b6d2015-01-05 23:57:44 +01001770
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001771 mxc->mx = mp;
Florian Westphale715b6d2015-01-05 23:57:44 +01001772 return 0;
1773 err:
1774 kfree(mp);
1775 return -EINVAL;
1776}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777
David Ahern8c145862016-04-24 21:26:04 -07001778static struct rt6_info *ip6_nh_lookup_table(struct net *net,
1779 struct fib6_config *cfg,
1780 const struct in6_addr *gw_addr)
1781{
1782 struct flowi6 fl6 = {
1783 .flowi6_oif = cfg->fc_ifindex,
1784 .daddr = *gw_addr,
1785 .saddr = cfg->fc_prefsrc,
1786 };
1787 struct fib6_table *table;
1788 struct rt6_info *rt;
Paolo Abeni48f1dcb2016-06-23 15:25:09 +02001789 int flags = RT6_LOOKUP_F_IFACE;
David Ahern8c145862016-04-24 21:26:04 -07001790
1791 table = fib6_get_table(net, cfg->fc_table);
1792 if (!table)
1793 return NULL;
1794
1795 if (!ipv6_addr_any(&cfg->fc_prefsrc))
1796 flags |= RT6_LOOKUP_F_HAS_SADDR;
1797
1798 rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, flags);
1799
1800 /* if table lookup failed, fall back to full lookup */
1801 if (rt == net->ipv6.ip6_null_entry) {
1802 ip6_rt_put(rt);
1803 rt = NULL;
1804 }
1805
1806 return rt;
1807}
1808
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07001809static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810{
Daniel Lezcano55786892008-03-04 13:47:47 -08001811 struct net *net = cfg->fc_nlinfo.nl_net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 struct rt6_info *rt = NULL;
1813 struct net_device *dev = NULL;
1814 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001815 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 int addr_type;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07001817 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818
Thomas Graf86872cb2006-08-22 00:01:08 -07001819 if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128)
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07001820 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821#ifndef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001822 if (cfg->fc_src_len)
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07001823 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07001825 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08001827 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 if (!dev)
1829 goto out;
1830 idev = in6_dev_get(dev);
1831 if (!idev)
1832 goto out;
1833 }
1834
Thomas Graf86872cb2006-08-22 00:01:08 -07001835 if (cfg->fc_metric == 0)
1836 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837
Matti Vaittinend71314b2011-11-14 00:14:49 +00001838 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05001839 if (cfg->fc_nlinfo.nlh &&
1840 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00001841 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001842 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00001843 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00001844 table = fib6_new_table(net, cfg->fc_table);
1845 }
1846 } else {
1847 table = fib6_new_table(net, cfg->fc_table);
1848 }
David S. Miller38308472011-12-03 18:02:47 -05001849
1850 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001851 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07001852
Martin KaFai Lauad706862015-08-14 11:05:52 -07001853 rt = ip6_dst_alloc(net, NULL,
1854 (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855
David S. Miller38308472011-12-03 18:02:47 -05001856 if (!rt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 err = -ENOMEM;
1858 goto out;
1859 }
1860
Gao feng1716a962012-04-06 00:13:10 +00001861 if (cfg->fc_flags & RTF_EXPIRES)
1862 rt6_set_expires(rt, jiffies +
1863 clock_t_to_jiffies(cfg->fc_expires));
1864 else
1865 rt6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866
Thomas Graf86872cb2006-08-22 00:01:08 -07001867 if (cfg->fc_protocol == RTPROT_UNSPEC)
1868 cfg->fc_protocol = RTPROT_BOOT;
1869 rt->rt6i_protocol = cfg->fc_protocol;
1870
1871 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872
1873 if (addr_type & IPV6_ADDR_MULTICAST)
Changli Gaod8d1f302010-06-10 23:31:35 -07001874 rt->dst.input = ip6_mc_input;
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00001875 else if (cfg->fc_flags & RTF_LOCAL)
1876 rt->dst.input = ip6_input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 else
Changli Gaod8d1f302010-06-10 23:31:35 -07001878 rt->dst.input = ip6_forward;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879
Changli Gaod8d1f302010-06-10 23:31:35 -07001880 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
Roopa Prabhu19e42e42015-07-21 10:43:48 +02001882 if (cfg->fc_encap) {
1883 struct lwtunnel_state *lwtstate;
1884
1885 err = lwtunnel_build_state(dev, cfg->fc_encap_type,
Tom Herbert127eb7c2015-08-24 09:45:41 -07001886 cfg->fc_encap, AF_INET6, cfg,
1887 &lwtstate);
Roopa Prabhu19e42e42015-07-21 10:43:48 +02001888 if (err)
1889 goto out;
Jiri Benc61adedf2015-08-20 13:56:25 +02001890 rt->dst.lwtstate = lwtstate_get(lwtstate);
1891 if (lwtunnel_output_redirect(rt->dst.lwtstate)) {
1892 rt->dst.lwtstate->orig_output = rt->dst.output;
1893 rt->dst.output = lwtunnel_output;
Tom Herbert25368622015-08-17 13:42:24 -07001894 }
Jiri Benc61adedf2015-08-20 13:56:25 +02001895 if (lwtunnel_input_redirect(rt->dst.lwtstate)) {
1896 rt->dst.lwtstate->orig_input = rt->dst.input;
1897 rt->dst.input = lwtunnel_input;
Tom Herbert25368622015-08-17 13:42:24 -07001898 }
Roopa Prabhu19e42e42015-07-21 10:43:48 +02001899 }
1900
Thomas Graf86872cb2006-08-22 00:01:08 -07001901 ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
1902 rt->rt6i_dst.plen = cfg->fc_dst_len;
Martin KaFai Lauafc4eef2015-04-28 13:03:07 -07001903 if (rt->rt6i_dst.plen == 128)
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001904 rt->dst.flags |= DST_HOST;
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001905
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906#ifdef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001907 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
1908 rt->rt6i_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909#endif
1910
Thomas Graf86872cb2006-08-22 00:01:08 -07001911 rt->rt6i_metric = cfg->fc_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912
1913 /* We cannot add true routes via loopback here,
1914 they would result in kernel looping; promote them to reject routes
1915 */
Thomas Graf86872cb2006-08-22 00:01:08 -07001916 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05001917 (dev && (dev->flags & IFF_LOOPBACK) &&
1918 !(addr_type & IPV6_ADDR_LOOPBACK) &&
1919 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08001921 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 if (dev) {
1923 dev_put(dev);
1924 in6_dev_put(idev);
1925 }
Daniel Lezcano55786892008-03-04 13:47:47 -08001926 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 dev_hold(dev);
1928 idev = in6_dev_get(dev);
1929 if (!idev) {
1930 err = -ENODEV;
1931 goto out;
1932 }
1933 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001935 switch (cfg->fc_type) {
1936 case RTN_BLACKHOLE:
1937 rt->dst.error = -EINVAL;
Eric W. Biedermanede20592015-10-07 16:48:47 -05001938 rt->dst.output = dst_discard_out;
Kamala R7150aed2013-12-02 19:55:21 +05301939 rt->dst.input = dst_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001940 break;
1941 case RTN_PROHIBIT:
1942 rt->dst.error = -EACCES;
Kamala R7150aed2013-12-02 19:55:21 +05301943 rt->dst.output = ip6_pkt_prohibit_out;
1944 rt->dst.input = ip6_pkt_prohibit;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001945 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00001946 case RTN_THROW:
Nikola Forró0315e382015-09-17 16:01:32 +02001947 case RTN_UNREACHABLE:
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001948 default:
Kamala R7150aed2013-12-02 19:55:21 +05301949 rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN
Nikola Forró0315e382015-09-17 16:01:32 +02001950 : (cfg->fc_type == RTN_UNREACHABLE)
1951 ? -EHOSTUNREACH : -ENETUNREACH;
Kamala R7150aed2013-12-02 19:55:21 +05301952 rt->dst.output = ip6_pkt_discard_out;
1953 rt->dst.input = ip6_pkt_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001954 break;
1955 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 goto install_route;
1957 }
1958
Thomas Graf86872cb2006-08-22 00:01:08 -07001959 if (cfg->fc_flags & RTF_GATEWAY) {
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001960 const struct in6_addr *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 int gwa_type;
1962
Thomas Graf86872cb2006-08-22 00:01:08 -07001963 gw_addr = &cfg->fc_gateway;
Florian Westphal330567b2015-08-07 10:54:28 +02001964 gwa_type = ipv6_addr_type(gw_addr);
Florian Westphal48ed7b22015-05-21 00:25:41 +02001965
1966 /* if gw_addr is local we will fail to detect this in case
1967 * address is still TENTATIVE (DAD in progress). rt6_lookup()
1968 * will return already-added prefix route via interface that
1969 * prefix route was assigned to, which might be non-loopback.
1970 */
1971 err = -EINVAL;
Florian Westphal330567b2015-08-07 10:54:28 +02001972 if (ipv6_chk_addr_and_flags(net, gw_addr,
1973 gwa_type & IPV6_ADDR_LINKLOCAL ?
1974 dev : NULL, 0, 0))
Florian Westphal48ed7b22015-05-21 00:25:41 +02001975 goto out;
1976
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001977 rt->rt6i_gateway = *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978
1979 if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
David Ahern8c145862016-04-24 21:26:04 -07001980 struct rt6_info *grt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981
1982 /* IPv6 strictly inhibits using not link-local
1983 addresses as nexthop address.
1984 Otherwise, router will not able to send redirects.
1985 It is very good, but in some (rare!) circumstances
1986 (SIT, PtP, NBMA NOARP links) it is handy to allow
1987 some exceptions. --ANK
1988 */
David S. Miller38308472011-12-03 18:02:47 -05001989 if (!(gwa_type & IPV6_ADDR_UNICAST))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 goto out;
1991
Vincent Bernata435a072016-09-18 17:46:07 +02001992 if (cfg->fc_table) {
David Ahern8c145862016-04-24 21:26:04 -07001993 grt = ip6_nh_lookup_table(net, cfg, gw_addr);
1994
Vincent Bernata435a072016-09-18 17:46:07 +02001995 if (grt) {
1996 if (grt->rt6i_flags & RTF_GATEWAY ||
1997 (dev && dev != grt->dst.dev)) {
1998 ip6_rt_put(grt);
1999 grt = NULL;
2000 }
2001 }
2002 }
2003
David Ahern8c145862016-04-24 21:26:04 -07002004 if (!grt)
2005 grt = rt6_lookup(net, gw_addr, NULL,
2006 cfg->fc_ifindex, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007
2008 err = -EHOSTUNREACH;
David S. Miller38308472011-12-03 18:02:47 -05002009 if (!grt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 goto out;
2011 if (dev) {
David S. Millerd1918542011-12-28 20:19:20 -05002012 if (dev != grt->dst.dev) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00002013 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 goto out;
2015 }
2016 } else {
David S. Millerd1918542011-12-28 20:19:20 -05002017 dev = grt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 idev = grt->rt6i_idev;
2019 dev_hold(dev);
2020 in6_dev_hold(grt->rt6i_idev);
2021 }
David S. Miller38308472011-12-03 18:02:47 -05002022 if (!(grt->rt6i_flags & RTF_GATEWAY))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 err = 0;
Amerigo Wang94e187c2012-10-29 00:13:19 +00002024 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025
2026 if (err)
2027 goto out;
2028 }
2029 err = -EINVAL;
David S. Miller38308472011-12-03 18:02:47 -05002030 if (!dev || (dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 goto out;
2032 }
2033
2034 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05002035 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 goto out;
2037
Daniel Walterc3968a82011-04-13 21:10:57 +00002038 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
2039 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
2040 err = -EINVAL;
2041 goto out;
2042 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002043 rt->rt6i_prefsrc.addr = cfg->fc_prefsrc;
Daniel Walterc3968a82011-04-13 21:10:57 +00002044 rt->rt6i_prefsrc.plen = 128;
2045 } else
2046 rt->rt6i_prefsrc.plen = 0;
2047
Thomas Graf86872cb2006-08-22 00:01:08 -07002048 rt->rt6i_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049
2050install_route:
Changli Gaod8d1f302010-06-10 23:31:35 -07002051 rt->dst.dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 rt->rt6i_idev = idev;
Thomas Grafc71099a2006-08-04 23:20:06 -07002053 rt->rt6i_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08002054
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002055 cfg->fc_nlinfo.nl_net = dev_net(dev);
Daniel Lezcano63152fc2008-03-03 23:31:11 -08002056
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002057 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058out:
2059 if (dev)
2060 dev_put(dev);
2061 if (idev)
2062 in6_dev_put(idev);
2063 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07002064 dst_free(&rt->dst);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002065
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002066 return ERR_PTR(err);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002067}
2068
2069int ip6_route_add(struct fib6_config *cfg)
2070{
2071 struct mx6_config mxc = { .mx = NULL, };
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002072 struct rt6_info *rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002073 int err;
2074
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002075 rt = ip6_route_info_create(cfg);
2076 if (IS_ERR(rt)) {
2077 err = PTR_ERR(rt);
2078 rt = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002079 goto out;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002080 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002081
2082 err = ip6_convert_metrics(&mxc, cfg);
2083 if (err)
2084 goto out;
2085
2086 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, &mxc);
2087
2088 kfree(mxc.mx);
2089
2090 return err;
2091out:
2092 if (rt)
2093 dst_free(&rt->dst);
2094
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 return err;
2096}
2097
Thomas Graf86872cb2006-08-22 00:01:08 -07002098static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099{
2100 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07002101 struct fib6_table *table;
David S. Millerd1918542011-12-28 20:19:20 -05002102 struct net *net = dev_net(rt->dst.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103
Martin KaFai Lau8e3d5be2015-09-15 14:30:08 -07002104 if (rt == net->ipv6.ip6_null_entry ||
2105 rt->dst.flags & DST_NOCACHE) {
Gao feng6825a262012-09-19 19:25:34 +00002106 err = -ENOENT;
2107 goto out;
2108 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07002109
Thomas Grafc71099a2006-08-04 23:20:06 -07002110 table = rt->rt6i_table;
2111 write_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07002112 err = fib6_del(rt, info);
Thomas Grafc71099a2006-08-04 23:20:06 -07002113 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114
Gao feng6825a262012-09-19 19:25:34 +00002115out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00002116 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 return err;
2118}
2119
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002120int ip6_del_rt(struct rt6_info *rt)
2121{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08002122 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -05002123 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08002124 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002125 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002126}
2127
Thomas Graf86872cb2006-08-22 00:01:08 -07002128static int ip6_route_del(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129{
Thomas Grafc71099a2006-08-04 23:20:06 -07002130 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 struct fib6_node *fn;
2132 struct rt6_info *rt;
2133 int err = -ESRCH;
2134
Daniel Lezcano55786892008-03-04 13:47:47 -08002135 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05002136 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002137 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138
Thomas Grafc71099a2006-08-04 23:20:06 -07002139 read_lock_bh(&table->tb6_lock);
2140
2141 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07002142 &cfg->fc_dst, cfg->fc_dst_len,
2143 &cfg->fc_src, cfg->fc_src_len);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002144
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 if (fn) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002146 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
Martin KaFai Lau1f56a012015-04-28 13:03:03 -07002147 if ((rt->rt6i_flags & RTF_CACHE) &&
2148 !(cfg->fc_flags & RTF_CACHE))
2149 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002150 if (cfg->fc_ifindex &&
David S. Millerd1918542011-12-28 20:19:20 -05002151 (!rt->dst.dev ||
2152 rt->dst.dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002154 if (cfg->fc_flags & RTF_GATEWAY &&
2155 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002157 if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07002159 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07002160 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161
Thomas Graf86872cb2006-08-22 00:01:08 -07002162 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 }
2164 }
Thomas Grafc71099a2006-08-04 23:20:06 -07002165 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166
2167 return err;
2168}
2169
David S. Miller6700c272012-07-17 03:29:28 -07002170static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07002171{
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07002172 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07002173 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07002174 struct ndisc_options ndopts;
2175 struct inet6_dev *in6_dev;
2176 struct neighbour *neigh;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002177 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07002178 int optlen, on_link;
2179 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07002180
Simon Horman29a3cad2013-05-28 20:34:26 +00002181 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002182 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07002183
2184 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07002185 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002186 return;
2187 }
2188
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002189 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07002190
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002191 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07002192 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002193 return;
2194 }
2195
David S. Miller6e157b62012-07-12 00:05:02 -07002196 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002197 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07002198 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002199 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07002200 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07002201 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002202 return;
2203 }
2204
2205 in6_dev = __in6_dev_get(skb->dev);
2206 if (!in6_dev)
2207 return;
2208 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
2209 return;
2210
2211 /* RFC2461 8.1:
2212 * The IP source address of the Redirect MUST be the same as the current
2213 * first-hop router for the specified ICMP Destination Address.
2214 */
2215
Alexander Aringf997c552016-06-15 21:20:23 +02002216 if (!ndisc_parse_options(skb->dev, msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07002217 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
2218 return;
2219 }
David S. Miller6e157b62012-07-12 00:05:02 -07002220
2221 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07002222 if (ndopts.nd_opts_tgt_lladdr) {
2223 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
2224 skb->dev);
2225 if (!lladdr) {
2226 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
2227 return;
2228 }
2229 }
2230
David S. Miller6e157b62012-07-12 00:05:02 -07002231 rt = (struct rt6_info *) dst;
Matthias Schifferec13ad12015-11-02 01:24:38 +01002232 if (rt->rt6i_flags & RTF_REJECT) {
David S. Miller6e157b62012-07-12 00:05:02 -07002233 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
2234 return;
2235 }
2236
2237 /* Redirect received -> path was valid.
2238 * Look, redirects are sent only in response to data packets,
2239 * so that this nexthop apparently is reachable. --ANK
2240 */
2241 dst_confirm(&rt->dst);
2242
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002243 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07002244 if (!neigh)
2245 return;
2246
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 /*
2248 * We have finally decided to accept it.
2249 */
2250
Alexander Aringf997c552016-06-15 21:20:23 +02002251 ndisc_update(skb->dev, neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 NEIGH_UPDATE_F_WEAK_OVERRIDE|
2253 NEIGH_UPDATE_F_OVERRIDE|
2254 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
Alexander Aringf997c552016-06-15 21:20:23 +02002255 NEIGH_UPDATE_F_ISROUTER)),
2256 NDISC_REDIRECT, &ndopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002258 nrt = ip6_rt_cache_alloc(rt, &msg->dest, NULL);
David S. Miller38308472011-12-03 18:02:47 -05002259 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 goto out;
2261
2262 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
2263 if (on_link)
2264 nrt->rt6i_flags &= ~RTF_GATEWAY;
2265
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002266 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267
Thomas Graf40e22e82006-08-22 00:00:45 -07002268 if (ip6_ins_rt(nrt))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 goto out;
2270
Changli Gaod8d1f302010-06-10 23:31:35 -07002271 netevent.old = &rt->dst;
2272 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002273 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00002274 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07002275 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
2276
David S. Miller38308472011-12-03 18:02:47 -05002277 if (rt->rt6i_flags & RTF_CACHE) {
David S. Miller6e157b62012-07-12 00:05:02 -07002278 rt = (struct rt6_info *) dst_clone(&rt->dst);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002279 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 }
2281
2282out:
David S. Millere8599ff2012-07-11 23:43:53 -07002283 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07002284}
2285
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 * Misc support functions
2288 */
2289
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002290static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from)
2291{
2292 BUG_ON(from->dst.from);
2293
2294 rt->rt6i_flags &= ~RTF_EXPIRES;
2295 dst_hold(&from->dst);
2296 rt->dst.from = &from->dst;
2297 dst_init_metrics(&rt->dst, dst_metrics_ptr(&from->dst), true);
2298}
2299
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002300static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301{
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002302 rt->dst.input = ort->dst.input;
2303 rt->dst.output = ort->dst.output;
2304 rt->rt6i_dst = ort->rt6i_dst;
2305 rt->dst.error = ort->dst.error;
2306 rt->rt6i_idev = ort->rt6i_idev;
2307 if (rt->rt6i_idev)
2308 in6_dev_hold(rt->rt6i_idev);
2309 rt->dst.lastuse = jiffies;
2310 rt->rt6i_gateway = ort->rt6i_gateway;
2311 rt->rt6i_flags = ort->rt6i_flags;
2312 rt6_set_from(rt, ort);
2313 rt->rt6i_metric = ort->rt6i_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002315 rt->rt6i_src = ort->rt6i_src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316#endif
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002317 rt->rt6i_prefsrc = ort->rt6i_prefsrc;
2318 rt->rt6i_table = ort->rt6i_table;
Jiri Benc61adedf2015-08-20 13:56:25 +02002319 rt->dst.lwtstate = lwtstate_get(ort->dst.lwtstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320}
2321
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002322#ifdef CONFIG_IPV6_ROUTE_INFO
Lorenzo Colitti9fcb87d2014-03-26 19:35:41 +09002323static struct rt6_info *rt6_get_route_info(struct net_device *dev,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002324 const struct in6_addr *prefix, int prefixlen,
Lorenzo Colitti9fcb87d2014-03-26 19:35:41 +09002325 const struct in6_addr *gwaddr)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002326{
2327 struct fib6_node *fn;
2328 struct rt6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07002329 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002330
Lorenzo Colitti9fcb87d2014-03-26 19:35:41 +09002331 table = fib6_get_table(dev_net(dev),
2332 addrconf_rt_table(dev, RT6_TABLE_INFO));
David S. Miller38308472011-12-03 18:02:47 -05002333 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002334 return NULL;
2335
Li RongQing5744dd92012-09-11 21:59:01 +00002336 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01002337 fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002338 if (!fn)
2339 goto out;
2340
Changli Gaod8d1f302010-06-10 23:31:35 -07002341 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
Lorenzo Colitti9fcb87d2014-03-26 19:35:41 +09002342 if (rt->dst.dev->ifindex != dev->ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002343 continue;
2344 if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
2345 continue;
2346 if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
2347 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07002348 dst_hold(&rt->dst);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002349 break;
2350 }
2351out:
Li RongQing5744dd92012-09-11 21:59:01 +00002352 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002353 return rt;
2354}
2355
Lorenzo Colitti9fcb87d2014-03-26 19:35:41 +09002356static struct rt6_info *rt6_add_route_info(struct net_device *dev,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002357 const struct in6_addr *prefix, int prefixlen,
Lorenzo Colitti9fcb87d2014-03-26 19:35:41 +09002358 const struct in6_addr *gwaddr, unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002359{
Thomas Graf86872cb2006-08-22 00:01:08 -07002360 struct fib6_config cfg = {
Rami Rosen238fc7e2008-02-09 23:43:11 -08002361 .fc_metric = IP6_RT_PRIO_USER,
Lorenzo Colitti9fcb87d2014-03-26 19:35:41 +09002362 .fc_ifindex = dev->ifindex,
Thomas Graf86872cb2006-08-22 00:01:08 -07002363 .fc_dst_len = prefixlen,
2364 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
2365 RTF_UP | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00002366 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002367 .fc_nlinfo.nlh = NULL,
Lorenzo Colitti9fcb87d2014-03-26 19:35:41 +09002368 .fc_nlinfo.nl_net = dev_net(dev),
Thomas Graf86872cb2006-08-22 00:01:08 -07002369 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002370
Lorenzo Colitti9fcb87d2014-03-26 19:35:41 +09002371 cfg.fc_table = l3mdev_fib_table_by_index(dev_net(dev), dev->ifindex) ? : addrconf_rt_table(dev, RT6_TABLE_INFO);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002372 cfg.fc_dst = *prefix;
2373 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07002374
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08002375 /* We should treat it as a default route if prefix length is 0. */
2376 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07002377 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002378
Thomas Graf86872cb2006-08-22 00:01:08 -07002379 ip6_route_add(&cfg);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002380
Lorenzo Colitti9fcb87d2014-03-26 19:35:41 +09002381 return rt6_get_route_info(dev, prefix, prefixlen, gwaddr);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002382}
2383#endif
2384
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002385struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002386{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07002388 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389
Lorenzo Colitti9fcb87d2014-03-26 19:35:41 +09002390 table = fib6_get_table(dev_net(dev),
2391 addrconf_rt_table(dev, RT6_TABLE_MAIN));
David S. Miller38308472011-12-03 18:02:47 -05002392 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002393 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394
Li RongQing5744dd92012-09-11 21:59:01 +00002395 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01002396 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05002397 if (dev == rt->dst.dev &&
YOSHIFUJI Hideaki045927f2006-03-20 17:00:48 -08002398 ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 ipv6_addr_equal(&rt->rt6i_gateway, addr))
2400 break;
2401 }
2402 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07002403 dst_hold(&rt->dst);
Li RongQing5744dd92012-09-11 21:59:01 +00002404 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 return rt;
2406}
2407
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002408struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08002409 struct net_device *dev,
2410 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411{
Thomas Graf86872cb2006-08-22 00:01:08 -07002412 struct fib6_config cfg = {
Lorenzo Colitti9fcb87d2014-03-26 19:35:41 +09002413 .fc_table = l3mdev_fib_table(dev) ? : addrconf_rt_table(dev, RT6_TABLE_DFLT),
Rami Rosen238fc7e2008-02-09 23:43:11 -08002414 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07002415 .fc_ifindex = dev->ifindex,
2416 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
2417 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00002418 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08002419 .fc_nlinfo.nlh = NULL,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002420 .fc_nlinfo.nl_net = dev_net(dev),
Thomas Graf86872cb2006-08-22 00:01:08 -07002421 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002423 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424
Thomas Graf86872cb2006-08-22 00:01:08 -07002425 ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 return rt6_get_dflt_router(gwaddr, dev);
2428}
2429
Lorenzo Colitti9fcb87d2014-03-26 19:35:41 +09002430
2431int rt6_addrconf_purge(struct rt6_info *rt, void *arg) {
2432 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
2433 (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2))
2434 return -1;
2435 return 0;
2436}
2437
Daniel Lezcano7b4da532008-03-04 13:47:14 -08002438void rt6_purge_dflt_routers(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439{
Lorenzo Colitti9fcb87d2014-03-26 19:35:41 +09002440 fib6_clean_all(net, rt6_addrconf_purge, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441}
2442
Daniel Lezcano55786892008-03-04 13:47:47 -08002443static void rtmsg_to_fib6_config(struct net *net,
2444 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07002445 struct fib6_config *cfg)
2446{
2447 memset(cfg, 0, sizeof(*cfg));
2448
David Ahernca254492015-10-12 11:47:10 -07002449 cfg->fc_table = l3mdev_fib_table_by_index(net, rtmsg->rtmsg_ifindex) ?
2450 : RT6_TABLE_MAIN;
Thomas Graf86872cb2006-08-22 00:01:08 -07002451 cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
2452 cfg->fc_metric = rtmsg->rtmsg_metric;
2453 cfg->fc_expires = rtmsg->rtmsg_info;
2454 cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
2455 cfg->fc_src_len = rtmsg->rtmsg_src_len;
2456 cfg->fc_flags = rtmsg->rtmsg_flags;
2457
Daniel Lezcano55786892008-03-04 13:47:47 -08002458 cfg->fc_nlinfo.nl_net = net;
Benjamin Theryf1243c22008-02-26 18:10:03 -08002459
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002460 cfg->fc_dst = rtmsg->rtmsg_dst;
2461 cfg->fc_src = rtmsg->rtmsg_src;
2462 cfg->fc_gateway = rtmsg->rtmsg_gateway;
Thomas Graf86872cb2006-08-22 00:01:08 -07002463}
2464
Daniel Lezcano55786892008-03-04 13:47:47 -08002465int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466{
Thomas Graf86872cb2006-08-22 00:01:08 -07002467 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 struct in6_rtmsg rtmsg;
2469 int err;
2470
Ian Morris67ba4152014-08-24 21:53:10 +01002471 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 case SIOCADDRT: /* Add a route */
2473 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00002474 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 return -EPERM;
2476 err = copy_from_user(&rtmsg, arg,
2477 sizeof(struct in6_rtmsg));
2478 if (err)
2479 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07002480
Daniel Lezcano55786892008-03-04 13:47:47 -08002481 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07002482
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 rtnl_lock();
2484 switch (cmd) {
2485 case SIOCADDRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07002486 err = ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 break;
2488 case SIOCDELRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07002489 err = ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 break;
2491 default:
2492 err = -EINVAL;
2493 }
2494 rtnl_unlock();
2495
2496 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07002497 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498
2499 return -EINVAL;
2500}
2501
2502/*
2503 * Drop the packet on the floor
2504 */
2505
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07002506static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002508 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00002509 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002510 switch (ipstats_mib_noroutes) {
2511 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07002512 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00002513 if (type == IPV6_ADDR_ANY) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002514 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2515 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002516 break;
2517 }
2518 /* FALLTHROUGH */
2519 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002520 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2521 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002522 break;
2523 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002524 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 kfree_skb(skb);
2526 return 0;
2527}
2528
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002529static int ip6_pkt_discard(struct sk_buff *skb)
2530{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002531 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002532}
2533
Eric W. Biedermanede20592015-10-07 16:48:47 -05002534static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535{
Eric Dumazetadf30902009-06-02 05:19:30 +00002536 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002537 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538}
2539
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002540static int ip6_pkt_prohibit(struct sk_buff *skb)
2541{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002542 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002543}
2544
Eric W. Biedermanede20592015-10-07 16:48:47 -05002545static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002546{
Eric Dumazetadf30902009-06-02 05:19:30 +00002547 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002548 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002549}
2550
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551/*
2552 * Allocate a dst for local (unicast / anycast) address.
2553 */
2554
2555struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
2556 const struct in6_addr *addr,
David S. Miller8f031512011-12-06 16:48:14 -05002557 bool anycast)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558{
David Ahernca254492015-10-12 11:47:10 -07002559 u32 tb_id;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002560 struct net *net = dev_net(idev->dev);
David Ahern5f02ce242016-09-10 12:09:54 -07002561 struct net_device *dev = net->loopback_dev;
2562 struct rt6_info *rt;
2563
2564 /* use L3 Master device as loopback for host routes if device
2565 * is enslaved and address is not link local or multicast
2566 */
2567 if (!rt6_need_strict(addr))
2568 dev = l3mdev_master_dev_rcu(idev->dev) ? : dev;
2569
2570 rt = ip6_dst_alloc(net, dev, DST_NOCOUNT);
Hannes Frederic Sowaa3300ef2013-12-07 03:33:45 +01002571 if (!rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 return ERR_PTR(-ENOMEM);
2573
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 in6_dev_hold(idev);
2575
David S. Miller11d53b42011-06-24 15:23:34 -07002576 rt->dst.flags |= DST_HOST;
Changli Gaod8d1f302010-06-10 23:31:35 -07002577 rt->dst.input = ip6_input;
2578 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579 rt->rt6i_idev = idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580
2581 rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +09002582 if (anycast)
2583 rt->rt6i_flags |= RTF_ANYCAST;
2584 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 rt->rt6i_flags |= RTF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586
Julian Anastasov550bab42013-10-20 15:43:04 +03002587 rt->rt6i_gateway = *addr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002588 rt->rt6i_dst.addr = *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 rt->rt6i_dst.plen = 128;
David Ahernca254492015-10-12 11:47:10 -07002590 tb_id = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL;
2591 rt->rt6i_table = fib6_get_table(net, tb_id);
Martin KaFai Lau8e3d5be2015-09-15 14:30:08 -07002592 rt->dst.flags |= DST_NOCACHE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593
Changli Gaod8d1f302010-06-10 23:31:35 -07002594 atomic_set(&rt->dst.__refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595
2596 return rt;
2597}
2598
Daniel Walterc3968a82011-04-13 21:10:57 +00002599/* remove deleted ip from prefsrc entries */
2600struct arg_dev_net_ip {
2601 struct net_device *dev;
2602 struct net *net;
2603 struct in6_addr *addr;
2604};
2605
2606static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
2607{
2608 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
2609 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
2610 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
2611
David S. Millerd1918542011-12-28 20:19:20 -05002612 if (((void *)rt->dst.dev == dev || !dev) &&
Daniel Walterc3968a82011-04-13 21:10:57 +00002613 rt != net->ipv6.ip6_null_entry &&
2614 ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
2615 /* remove prefsrc entry */
2616 rt->rt6i_prefsrc.plen = 0;
2617 }
2618 return 0;
2619}
2620
2621void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
2622{
2623 struct net *net = dev_net(ifp->idev->dev);
2624 struct arg_dev_net_ip adni = {
2625 .dev = ifp->idev->dev,
2626 .net = net,
2627 .addr = &ifp->addr,
2628 };
Li RongQing0c3584d2013-12-27 16:32:38 +08002629 fib6_clean_all(net, fib6_remove_prefsrc, &adni);
Daniel Walterc3968a82011-04-13 21:10:57 +00002630}
2631
Duan Jiongbe7a0102014-05-15 15:56:14 +08002632#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY)
2633#define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE)
2634
2635/* Remove routers and update dst entries when gateway turn into host. */
2636static int fib6_clean_tohost(struct rt6_info *rt, void *arg)
2637{
2638 struct in6_addr *gateway = (struct in6_addr *)arg;
2639
2640 if ((((rt->rt6i_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) ||
2641 ((rt->rt6i_flags & RTF_CACHE_GATEWAY) == RTF_CACHE_GATEWAY)) &&
2642 ipv6_addr_equal(gateway, &rt->rt6i_gateway)) {
2643 return -1;
2644 }
2645 return 0;
2646}
2647
2648void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
2649{
2650 fib6_clean_all(net, fib6_clean_tohost, gateway);
2651}
2652
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002653struct arg_dev_net {
2654 struct net_device *dev;
2655 struct net *net;
2656};
2657
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658static int fib6_ifdown(struct rt6_info *rt, void *arg)
2659{
stephen hemmingerbc3ef662010-12-16 17:42:40 +00002660 const struct arg_dev_net *adn = arg;
2661 const struct net_device *dev = adn->dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002662
David S. Millerd1918542011-12-28 20:19:20 -05002663 if ((rt->dst.dev == dev || !dev) &&
David S. Millerc159d302011-12-26 15:24:36 -05002664 rt != adn->net->ipv6.ip6_null_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 return -1;
David S. Millerc159d302011-12-26 15:24:36 -05002666
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 return 0;
2668}
2669
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002670void rt6_ifdown(struct net *net, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002672 struct arg_dev_net adn = {
2673 .dev = dev,
2674 .net = net,
2675 };
2676
Li RongQing0c3584d2013-12-27 16:32:38 +08002677 fib6_clean_all(net, fib6_ifdown, &adn);
David S. Miller1e493d12008-09-10 17:27:15 -07002678 icmp6_clean_all(fib6_ifdown, &adn);
Eric W. Biedermane332bc62015-10-12 11:02:08 -05002679 if (dev)
2680 rt6_uncached_list_flush_dev(net, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681}
2682
Eric Dumazet95c96172012-04-15 05:58:06 +00002683struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00002685 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686};
2687
2688static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
2689{
2690 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
2691 struct inet6_dev *idev;
2692
2693 /* In IPv6 pmtu discovery is not optional,
2694 so that RTAX_MTU lock cannot disable it.
2695 We still use this lock to block changes
2696 caused by addrconf/ndisc.
2697 */
2698
2699 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05002700 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 return 0;
2702
2703 /* For administrative MTU increase, there is no way to discover
2704 IPv6 PMTU increase, so PMTU increase should be updated here.
2705 Since RFC 1981 doesn't include administrative MTU increase
2706 update PMTU increase is a MUST. (i.e. jumbo frame)
2707 */
2708 /*
2709 If new MTU is less than route PMTU, this new MTU will be the
2710 lowest MTU in the path, update the route PMTU to reflect PMTU
2711 decreases; if new MTU is greater than route PMTU, and the
2712 old MTU is the lowest MTU in the path, update the route PMTU
2713 to reflect the increase. In this case if the other nodes' MTU
2714 also have the lowest MTU, TOO BIG MESSAGE will be lead to
2715 PMTU discouvery.
2716 */
David S. Millerd1918542011-12-28 20:19:20 -05002717 if (rt->dst.dev == arg->dev &&
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002718 !dst_metric_locked(&rt->dst, RTAX_MTU)) {
2719 if (rt->rt6i_flags & RTF_CACHE) {
2720 /* For RTF_CACHE with rt6i_pmtu == 0
2721 * (i.e. a redirected route),
2722 * the metrics of its rt->dst.from has already
2723 * been updated.
2724 */
2725 if (rt->rt6i_pmtu && rt->rt6i_pmtu > arg->mtu)
2726 rt->rt6i_pmtu = arg->mtu;
2727 } else if (dst_mtu(&rt->dst) >= arg->mtu ||
2728 (dst_mtu(&rt->dst) < arg->mtu &&
2729 dst_mtu(&rt->dst) == idev->cnf.mtu6)) {
2730 dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu);
2731 }
Simon Arlott566cfd82007-07-26 00:09:55 -07002732 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 return 0;
2734}
2735
Eric Dumazet95c96172012-04-15 05:58:06 +00002736void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737{
Thomas Grafc71099a2006-08-04 23:20:06 -07002738 struct rt6_mtu_change_arg arg = {
2739 .dev = dev,
2740 .mtu = mtu,
2741 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742
Li RongQing0c3584d2013-12-27 16:32:38 +08002743 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744}
2745
Patrick McHardyef7c79e2007-06-05 12:38:30 -07002746static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07002747 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07002748 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07002749 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002750 [RTA_PRIORITY] = { .type = NLA_U32 },
2751 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002752 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002753 [RTA_PREF] = { .type = NLA_U8 },
Roopa Prabhu19e42e42015-07-21 10:43:48 +02002754 [RTA_ENCAP_TYPE] = { .type = NLA_U16 },
2755 [RTA_ENCAP] = { .type = NLA_NESTED },
Xin Long32bc2012015-12-16 17:50:11 +08002756 [RTA_EXPIRES] = { .type = NLA_U32 },
Lorenzo Colitti3b824972014-03-31 16:23:51 +09002757 [RTA_UID] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002758};
2759
2760static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
2761 struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762{
Thomas Graf86872cb2006-08-22 00:01:08 -07002763 struct rtmsg *rtm;
2764 struct nlattr *tb[RTA_MAX+1];
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002765 unsigned int pref;
Thomas Graf86872cb2006-08-22 00:01:08 -07002766 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767
Thomas Graf86872cb2006-08-22 00:01:08 -07002768 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2769 if (err < 0)
2770 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771
Thomas Graf86872cb2006-08-22 00:01:08 -07002772 err = -EINVAL;
2773 rtm = nlmsg_data(nlh);
2774 memset(cfg, 0, sizeof(*cfg));
2775
2776 cfg->fc_table = rtm->rtm_table;
2777 cfg->fc_dst_len = rtm->rtm_dst_len;
2778 cfg->fc_src_len = rtm->rtm_src_len;
2779 cfg->fc_flags = RTF_UP;
2780 cfg->fc_protocol = rtm->rtm_protocol;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002781 cfg->fc_type = rtm->rtm_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07002782
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002783 if (rtm->rtm_type == RTN_UNREACHABLE ||
2784 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002785 rtm->rtm_type == RTN_PROHIBIT ||
2786 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07002787 cfg->fc_flags |= RTF_REJECT;
2788
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002789 if (rtm->rtm_type == RTN_LOCAL)
2790 cfg->fc_flags |= RTF_LOCAL;
2791
Martin KaFai Lau1f56a012015-04-28 13:03:03 -07002792 if (rtm->rtm_flags & RTM_F_CLONED)
2793 cfg->fc_flags |= RTF_CACHE;
2794
Eric W. Biederman15e47302012-09-07 20:12:54 +00002795 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
Thomas Graf86872cb2006-08-22 00:01:08 -07002796 cfg->fc_nlinfo.nlh = nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002797 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
Thomas Graf86872cb2006-08-22 00:01:08 -07002798
2799 if (tb[RTA_GATEWAY]) {
Jiri Benc67b61f62015-03-29 16:59:26 +02002800 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
Thomas Graf86872cb2006-08-22 00:01:08 -07002801 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002803
2804 if (tb[RTA_DST]) {
2805 int plen = (rtm->rtm_dst_len + 7) >> 3;
2806
2807 if (nla_len(tb[RTA_DST]) < plen)
2808 goto errout;
2809
2810 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002812
2813 if (tb[RTA_SRC]) {
2814 int plen = (rtm->rtm_src_len + 7) >> 3;
2815
2816 if (nla_len(tb[RTA_SRC]) < plen)
2817 goto errout;
2818
2819 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002821
Daniel Walterc3968a82011-04-13 21:10:57 +00002822 if (tb[RTA_PREFSRC])
Jiri Benc67b61f62015-03-29 16:59:26 +02002823 cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]);
Daniel Walterc3968a82011-04-13 21:10:57 +00002824
Thomas Graf86872cb2006-08-22 00:01:08 -07002825 if (tb[RTA_OIF])
2826 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
2827
2828 if (tb[RTA_PRIORITY])
2829 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
2830
2831 if (tb[RTA_METRICS]) {
2832 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
2833 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002835
2836 if (tb[RTA_TABLE])
2837 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
2838
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002839 if (tb[RTA_MULTIPATH]) {
2840 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
2841 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
2842 }
2843
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002844 if (tb[RTA_PREF]) {
2845 pref = nla_get_u8(tb[RTA_PREF]);
2846 if (pref != ICMPV6_ROUTER_PREF_LOW &&
2847 pref != ICMPV6_ROUTER_PREF_HIGH)
2848 pref = ICMPV6_ROUTER_PREF_MEDIUM;
2849 cfg->fc_flags |= RTF_PREF(pref);
2850 }
2851
Roopa Prabhu19e42e42015-07-21 10:43:48 +02002852 if (tb[RTA_ENCAP])
2853 cfg->fc_encap = tb[RTA_ENCAP];
2854
2855 if (tb[RTA_ENCAP_TYPE])
2856 cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]);
2857
Xin Long32bc2012015-12-16 17:50:11 +08002858 if (tb[RTA_EXPIRES]) {
2859 unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ);
2860
2861 if (addrconf_finite_timeout(timeout)) {
2862 cfg->fc_expires = jiffies_to_clock_t(timeout * HZ);
2863 cfg->fc_flags |= RTF_EXPIRES;
2864 }
2865 }
2866
Thomas Graf86872cb2006-08-22 00:01:08 -07002867 err = 0;
2868errout:
2869 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870}
2871
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002872struct rt6_nh {
2873 struct rt6_info *rt6_info;
2874 struct fib6_config r_cfg;
2875 struct mx6_config mxc;
2876 struct list_head next;
2877};
2878
2879static void ip6_print_replace_route_err(struct list_head *rt6_nh_list)
2880{
2881 struct rt6_nh *nh;
2882
2883 list_for_each_entry(nh, rt6_nh_list, next) {
2884 pr_warn("IPV6: multipath route replace failed (check consistency of installed routes): %pI6 nexthop %pI6 ifi %d\n",
2885 &nh->r_cfg.fc_dst, &nh->r_cfg.fc_gateway,
2886 nh->r_cfg.fc_ifindex);
2887 }
2888}
2889
2890static int ip6_route_info_append(struct list_head *rt6_nh_list,
2891 struct rt6_info *rt, struct fib6_config *r_cfg)
2892{
2893 struct rt6_nh *nh;
2894 struct rt6_info *rtnh;
2895 int err = -EEXIST;
2896
2897 list_for_each_entry(nh, rt6_nh_list, next) {
2898 /* check if rt6_info already exists */
2899 rtnh = nh->rt6_info;
2900
2901 if (rtnh->dst.dev == rt->dst.dev &&
2902 rtnh->rt6i_idev == rt->rt6i_idev &&
2903 ipv6_addr_equal(&rtnh->rt6i_gateway,
2904 &rt->rt6i_gateway))
2905 return err;
2906 }
2907
2908 nh = kzalloc(sizeof(*nh), GFP_KERNEL);
2909 if (!nh)
2910 return -ENOMEM;
2911 nh->rt6_info = rt;
2912 err = ip6_convert_metrics(&nh->mxc, r_cfg);
2913 if (err) {
2914 kfree(nh);
2915 return err;
2916 }
2917 memcpy(&nh->r_cfg, r_cfg, sizeof(*r_cfg));
2918 list_add_tail(&nh->next, rt6_nh_list);
2919
2920 return 0;
2921}
2922
2923static int ip6_route_multipath_add(struct fib6_config *cfg)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002924{
2925 struct fib6_config r_cfg;
2926 struct rtnexthop *rtnh;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002927 struct rt6_info *rt;
2928 struct rt6_nh *err_nh;
2929 struct rt6_nh *nh, *nh_safe;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002930 int remaining;
2931 int attrlen;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002932 int err = 1;
2933 int nhn = 0;
2934 int replace = (cfg->fc_nlinfo.nlh &&
2935 (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE));
2936 LIST_HEAD(rt6_nh_list);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002937
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02002938 remaining = cfg->fc_mp_len;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002939 rtnh = (struct rtnexthop *)cfg->fc_mp;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002940
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002941 /* Parse a Multipath Entry and build a list (rt6_nh_list) of
2942 * rt6_info structs per nexthop
2943 */
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002944 while (rtnh_ok(rtnh, remaining)) {
2945 memcpy(&r_cfg, cfg, sizeof(*cfg));
2946 if (rtnh->rtnh_ifindex)
2947 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
2948
2949 attrlen = rtnh_attrlen(rtnh);
2950 if (attrlen > 0) {
2951 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
2952
2953 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
2954 if (nla) {
Jiri Benc67b61f62015-03-29 16:59:26 +02002955 r_cfg.fc_gateway = nla_get_in6_addr(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002956 r_cfg.fc_flags |= RTF_GATEWAY;
2957 }
Roopa Prabhu19e42e42015-07-21 10:43:48 +02002958 r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
2959 nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
2960 if (nla)
2961 r_cfg.fc_encap_type = nla_get_u16(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002962 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002963
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002964 rt = ip6_route_info_create(&r_cfg);
2965 if (IS_ERR(rt)) {
2966 err = PTR_ERR(rt);
2967 rt = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002968 goto cleanup;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002969 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002970
2971 err = ip6_route_info_append(&rt6_nh_list, rt, &r_cfg);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002972 if (err) {
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002973 dst_free(&rt->dst);
2974 goto cleanup;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002975 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002976
2977 rtnh = rtnh_next(rtnh, &remaining);
2978 }
2979
2980 err_nh = NULL;
2981 list_for_each_entry(nh, &rt6_nh_list, next) {
2982 err = __ip6_ins_rt(nh->rt6_info, &cfg->fc_nlinfo, &nh->mxc);
2983 /* nh->rt6_info is used or freed at this point, reset to NULL*/
2984 nh->rt6_info = NULL;
2985 if (err) {
2986 if (replace && nhn)
2987 ip6_print_replace_route_err(&rt6_nh_list);
2988 err_nh = nh;
2989 goto add_errout;
2990 }
2991
Nicolas Dichtel1a724182012-11-01 22:58:22 +00002992 /* Because each route is added like a single route we remove
Michal Kubeček27596472015-05-18 20:54:00 +02002993 * these flags after the first nexthop: if there is a collision,
2994 * we have already failed to add the first nexthop:
2995 * fib6_add_rt2node() has rejected it; when replacing, old
2996 * nexthops have been replaced by first new, the rest should
2997 * be added to it.
Nicolas Dichtel1a724182012-11-01 22:58:22 +00002998 */
Michal Kubeček27596472015-05-18 20:54:00 +02002999 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
3000 NLM_F_REPLACE);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003001 nhn++;
3002 }
3003
3004 goto cleanup;
3005
3006add_errout:
3007 /* Delete routes that were already added */
3008 list_for_each_entry(nh, &rt6_nh_list, next) {
3009 if (err_nh == nh)
3010 break;
3011 ip6_route_del(&nh->r_cfg);
3012 }
3013
3014cleanup:
3015 list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) {
3016 if (nh->rt6_info)
3017 dst_free(&nh->rt6_info->dst);
Wu Fengguang52fe51f2015-09-10 06:57:12 +08003018 kfree(nh->mxc.mx);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003019 list_del(&nh->next);
3020 kfree(nh);
3021 }
3022
3023 return err;
3024}
3025
3026static int ip6_route_multipath_del(struct fib6_config *cfg)
3027{
3028 struct fib6_config r_cfg;
3029 struct rtnexthop *rtnh;
3030 int remaining;
3031 int attrlen;
3032 int err = 1, last_err = 0;
3033
3034 remaining = cfg->fc_mp_len;
3035 rtnh = (struct rtnexthop *)cfg->fc_mp;
3036
3037 /* Parse a Multipath Entry */
3038 while (rtnh_ok(rtnh, remaining)) {
3039 memcpy(&r_cfg, cfg, sizeof(*cfg));
3040 if (rtnh->rtnh_ifindex)
3041 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
3042
3043 attrlen = rtnh_attrlen(rtnh);
3044 if (attrlen > 0) {
3045 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
3046
3047 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
3048 if (nla) {
3049 nla_memcpy(&r_cfg.fc_gateway, nla, 16);
3050 r_cfg.fc_flags |= RTF_GATEWAY;
3051 }
3052 }
3053 err = ip6_route_del(&r_cfg);
3054 if (err)
3055 last_err = err;
3056
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003057 rtnh = rtnh_next(rtnh, &remaining);
3058 }
3059
3060 return last_err;
3061}
3062
Ian Morris67ba4152014-08-24 21:53:10 +01003063static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064{
Thomas Graf86872cb2006-08-22 00:01:08 -07003065 struct fib6_config cfg;
3066 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067
Thomas Graf86872cb2006-08-22 00:01:08 -07003068 err = rtm_to_fib6_config(skb, nlh, &cfg);
3069 if (err < 0)
3070 return err;
3071
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003072 if (cfg.fc_mp)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003073 return ip6_route_multipath_del(&cfg);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003074 else
3075 return ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076}
3077
Ian Morris67ba4152014-08-24 21:53:10 +01003078static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079{
Thomas Graf86872cb2006-08-22 00:01:08 -07003080 struct fib6_config cfg;
3081 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082
Thomas Graf86872cb2006-08-22 00:01:08 -07003083 err = rtm_to_fib6_config(skb, nlh, &cfg);
3084 if (err < 0)
3085 return err;
3086
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003087 if (cfg.fc_mp)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003088 return ip6_route_multipath_add(&cfg);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003089 else
3090 return ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091}
3092
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003093static inline size_t rt6_nlmsg_size(struct rt6_info *rt)
Thomas Graf339bf982006-11-10 14:10:15 -08003094{
3095 return NLMSG_ALIGN(sizeof(struct rtmsg))
3096 + nla_total_size(16) /* RTA_SRC */
3097 + nla_total_size(16) /* RTA_DST */
3098 + nla_total_size(16) /* RTA_GATEWAY */
3099 + nla_total_size(16) /* RTA_PREFSRC */
3100 + nla_total_size(4) /* RTA_TABLE */
3101 + nla_total_size(4) /* RTA_IIF */
3102 + nla_total_size(4) /* RTA_OIF */
3103 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08003104 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Daniel Borkmannea697632015-01-05 23:57:47 +01003105 + nla_total_size(sizeof(struct rta_cacheinfo))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01003106 + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003107 + nla_total_size(1) /* RTA_PREF */
Jiri Benc61adedf2015-08-20 13:56:25 +02003108 + lwtunnel_get_encap_size(rt->dst.lwtstate);
Thomas Graf339bf982006-11-10 14:10:15 -08003109}
3110
Brian Haley191cd582008-08-14 15:33:21 -07003111static int rt6_fill_node(struct net *net,
3112 struct sk_buff *skb, struct rt6_info *rt,
Jamal Hadi Salim0d51aa82005-06-21 13:51:04 -07003113 struct in6_addr *dst, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003114 int iif, int type, u32 portid, u32 seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003115 int prefix, int nowait, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07003117 u32 metrics[RTAX_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 struct rtmsg *rtm;
Thomas Graf2d7202b2006-08-22 00:01:27 -07003119 struct nlmsghdr *nlh;
Thomas Grafe3703b32006-11-27 09:27:07 -08003120 long expires;
Patrick McHardy9e762a42006-08-10 23:09:48 -07003121 u32 table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122
3123 if (prefix) { /* user wants prefix routes only */
3124 if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
3125 /* success since this is not a prefix route */
3126 return 1;
3127 }
3128 }
3129
Eric W. Biederman15e47302012-09-07 20:12:54 +00003130 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05003131 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08003132 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07003133
3134 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 rtm->rtm_family = AF_INET6;
3136 rtm->rtm_dst_len = rt->rt6i_dst.plen;
3137 rtm->rtm_src_len = rt->rt6i_src.plen;
3138 rtm->rtm_tos = 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07003139 if (rt->rt6i_table)
Patrick McHardy9e762a42006-08-10 23:09:48 -07003140 table = rt->rt6i_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07003141 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07003142 table = RT6_TABLE_UNSPEC;
3143 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04003144 if (nla_put_u32(skb, RTA_TABLE, table))
3145 goto nla_put_failure;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00003146 if (rt->rt6i_flags & RTF_REJECT) {
3147 switch (rt->dst.error) {
3148 case -EINVAL:
3149 rtm->rtm_type = RTN_BLACKHOLE;
3150 break;
3151 case -EACCES:
3152 rtm->rtm_type = RTN_PROHIBIT;
3153 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00003154 case -EAGAIN:
3155 rtm->rtm_type = RTN_THROW;
3156 break;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00003157 default:
3158 rtm->rtm_type = RTN_UNREACHABLE;
3159 break;
3160 }
3161 }
David S. Miller38308472011-12-03 18:02:47 -05003162 else if (rt->rt6i_flags & RTF_LOCAL)
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00003163 rtm->rtm_type = RTN_LOCAL;
David S. Millerd1918542011-12-28 20:19:20 -05003164 else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 rtm->rtm_type = RTN_LOCAL;
3166 else
3167 rtm->rtm_type = RTN_UNICAST;
3168 rtm->rtm_flags = 0;
Andy Gospodarek35103d12015-08-13 10:39:01 -04003169 if (!netif_carrier_ok(rt->dst.dev)) {
Andy Gospodarekcea45e22015-08-13 10:39:00 -04003170 rtm->rtm_flags |= RTNH_F_LINKDOWN;
Andy Gospodarek35103d12015-08-13 10:39:01 -04003171 if (rt->rt6i_idev->cnf.ignore_routes_with_linkdown)
3172 rtm->rtm_flags |= RTNH_F_DEAD;
3173 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
3175 rtm->rtm_protocol = rt->rt6i_protocol;
David S. Miller38308472011-12-03 18:02:47 -05003176 if (rt->rt6i_flags & RTF_DYNAMIC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 rtm->rtm_protocol = RTPROT_REDIRECT;
Denis Ovsienkof0396f602012-07-10 04:45:50 +00003178 else if (rt->rt6i_flags & RTF_ADDRCONF) {
3179 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ROUTEINFO))
3180 rtm->rtm_protocol = RTPROT_RA;
3181 else
3182 rtm->rtm_protocol = RTPROT_KERNEL;
3183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184
David S. Miller38308472011-12-03 18:02:47 -05003185 if (rt->rt6i_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186 rtm->rtm_flags |= RTM_F_CLONED;
3187
3188 if (dst) {
Jiri Benc930345e2015-03-29 16:59:25 +02003189 if (nla_put_in6_addr(skb, RTA_DST, dst))
David S. Millerc78679e2012-04-01 20:27:33 -04003190 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003191 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 } else if (rtm->rtm_dst_len)
Jiri Benc930345e2015-03-29 16:59:25 +02003193 if (nla_put_in6_addr(skb, RTA_DST, &rt->rt6i_dst.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04003194 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195#ifdef CONFIG_IPV6_SUBTREES
3196 if (src) {
Jiri Benc930345e2015-03-29 16:59:25 +02003197 if (nla_put_in6_addr(skb, RTA_SRC, src))
David S. Millerc78679e2012-04-01 20:27:33 -04003198 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003199 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04003200 } else if (rtm->rtm_src_len &&
Jiri Benc930345e2015-03-29 16:59:25 +02003201 nla_put_in6_addr(skb, RTA_SRC, &rt->rt6i_src.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04003202 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003204 if (iif) {
3205#ifdef CONFIG_IPV6_MROUTE
3206 if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02003207 int err = ip6mr_get_route(net, skb, rtm, nowait,
3208 portid);
3209
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003210 if (err <= 0) {
3211 if (!nowait) {
3212 if (err == 0)
3213 return 0;
3214 goto nla_put_failure;
3215 } else {
3216 if (err == -EMSGSIZE)
3217 goto nla_put_failure;
3218 }
3219 }
3220 } else
3221#endif
David S. Millerc78679e2012-04-01 20:27:33 -04003222 if (nla_put_u32(skb, RTA_IIF, iif))
3223 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003224 } else if (dst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 struct in6_addr saddr_buf;
David S. Millerc78679e2012-04-01 20:27:33 -04003226 if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0 &&
Jiri Benc930345e2015-03-29 16:59:25 +02003227 nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04003228 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07003230
Daniel Walterc3968a82011-04-13 21:10:57 +00003231 if (rt->rt6i_prefsrc.plen) {
3232 struct in6_addr saddr_buf;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003233 saddr_buf = rt->rt6i_prefsrc.addr;
Jiri Benc930345e2015-03-29 16:59:25 +02003234 if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04003235 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00003236 }
3237
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07003238 memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics));
3239 if (rt->rt6i_pmtu)
3240 metrics[RTAX_MTU - 1] = rt->rt6i_pmtu;
3241 if (rtnetlink_put_metrics(skb, metrics) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07003242 goto nla_put_failure;
3243
YOSHIFUJI Hideaki / 吉藤英明dd0cbf22013-01-17 12:53:15 +00003244 if (rt->rt6i_flags & RTF_GATEWAY) {
Jiri Benc930345e2015-03-29 16:59:25 +02003245 if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->rt6i_gateway) < 0)
Eric Dumazet94f826b2012-03-27 09:53:52 +00003246 goto nla_put_failure;
Eric Dumazet94f826b2012-03-27 09:53:52 +00003247 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07003248
David S. Millerc78679e2012-04-01 20:27:33 -04003249 if (rt->dst.dev &&
3250 nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex))
3251 goto nla_put_failure;
3252 if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric))
3253 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00003254
3255 expires = (rt->rt6i_flags & RTF_EXPIRES) ? rt->dst.expires - jiffies : 0;
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07003256
David S. Miller87a50692012-07-10 05:06:14 -07003257 if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, rt->dst.error) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08003258 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01003260 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags)))
3261 goto nla_put_failure;
3262
Jiri Benc61adedf2015-08-20 13:56:25 +02003263 lwtunnel_fill_encap(skb, rt->dst.lwtstate);
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003264
Johannes Berg053c0952015-01-16 22:09:00 +01003265 nlmsg_end(skb, nlh);
3266 return 0;
Thomas Graf2d7202b2006-08-22 00:01:27 -07003267
3268nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08003269 nlmsg_cancel(skb, nlh);
3270 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271}
3272
Patrick McHardy1b43af52006-08-10 23:11:17 -07003273int rt6_dump_route(struct rt6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274{
3275 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
3276 int prefix;
3277
Thomas Graf2d7202b2006-08-22 00:01:27 -07003278 if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
3279 struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0;
3281 } else
3282 prefix = 0;
3283
Brian Haley191cd582008-08-14 15:33:21 -07003284 return rt6_fill_node(arg->net,
3285 arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003286 NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003287 prefix, 0, NLM_F_MULTI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288}
3289
Ian Morris67ba4152014-08-24 21:53:10 +01003290static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09003292 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07003293 struct nlattr *tb[RTA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07003295 struct sk_buff *skb;
3296 struct rtmsg *rtm;
David S. Miller4c9483b2011-03-12 16:22:43 -05003297 struct flowi6 fl6;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003298 int err, iif = 0, oif = 0;
Thomas Grafab364a62006-08-22 00:01:47 -07003299
3300 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
3301 if (err < 0)
3302 goto errout;
3303
3304 err = -EINVAL;
David S. Miller4c9483b2011-03-12 16:22:43 -05003305 memset(&fl6, 0, sizeof(fl6));
Hannes Frederic Sowa38b70972016-06-11 20:08:19 +02003306 rtm = nlmsg_data(nlh);
3307 fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0);
Thomas Grafab364a62006-08-22 00:01:47 -07003308
3309 if (tb[RTA_SRC]) {
3310 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
3311 goto errout;
3312
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003313 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07003314 }
3315
3316 if (tb[RTA_DST]) {
3317 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
3318 goto errout;
3319
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003320 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07003321 }
3322
3323 if (tb[RTA_IIF])
3324 iif = nla_get_u32(tb[RTA_IIF]);
3325
3326 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003327 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07003328
Lorenzo Colitti2e47b292014-05-15 16:38:41 -07003329 if (tb[RTA_MARK])
3330 fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
3331
Lorenzo Colitti3b824972014-03-31 16:23:51 +09003332 if (tb[RTA_UID])
3333 fl6.flowi6_uid = make_kuid(current_user_ns(),
3334 nla_get_u32(tb[RTA_UID]));
3335 else
3336 fl6.flowi6_uid = iif ? INVALID_UID : current_uid();
Thomas Grafab364a62006-08-22 00:01:47 -07003337 if (iif) {
3338 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003339 int flags = 0;
3340
Daniel Lezcano55786892008-03-04 13:47:47 -08003341 dev = __dev_get_by_index(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07003342 if (!dev) {
3343 err = -ENODEV;
3344 goto errout;
3345 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003346
3347 fl6.flowi6_iif = iif;
3348
3349 if (!ipv6_addr_any(&fl6.saddr))
3350 flags |= RT6_LOOKUP_F_HAS_SADDR;
3351
3352 rt = (struct rt6_info *)ip6_route_input_lookup(net, dev, &fl6,
3353 flags);
3354 } else {
3355 fl6.flowi6_oif = oif;
3356
3357 rt = (struct rt6_info *)ip6_route_output(net, NULL, &fl6);
Thomas Grafab364a62006-08-22 00:01:47 -07003358 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359
3360 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05003361 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00003362 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07003363 err = -ENOBUFS;
3364 goto errout;
3365 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366
3367 /* Reserve room for dummy headers, this skb can pass
3368 through good chunk of routing engine.
3369 */
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07003370 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
3372
Changli Gaod8d1f302010-06-10 23:31:35 -07003373 skb_dst_set(skb, &rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374
David S. Miller4c9483b2011-03-12 16:22:43 -05003375 err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003376 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003377 nlh->nlmsg_seq, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07003379 kfree_skb(skb);
3380 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 }
3382
Eric W. Biederman15e47302012-09-07 20:12:54 +00003383 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07003384errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386}
3387
Roopa Prabhu37a1d362015-09-13 10:18:33 -07003388void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info,
3389 unsigned int nlm_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390{
3391 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08003392 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003393 u32 seq;
3394 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003396 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05003397 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07003398
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003399 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05003400 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07003401 goto errout;
3402
Brian Haley191cd582008-08-14 15:33:21 -07003403 err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
Roopa Prabhu37a1d362015-09-13 10:18:33 -07003404 event, info->portid, seq, 0, 0, nlm_flags);
Patrick McHardy26932562007-01-31 23:16:40 -08003405 if (err < 0) {
3406 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
3407 WARN_ON(err == -EMSGSIZE);
3408 kfree_skb(skb);
3409 goto errout;
3410 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00003411 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08003412 info->nlh, gfp_any());
3413 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07003414errout:
3415 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08003416 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417}
3418
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003419static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00003420 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003421{
Jiri Pirko351638e2013-05-28 01:30:21 +00003422 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09003423 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003424
3425 if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07003426 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003427 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
3428#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07003429 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003430 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07003431 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003432 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
3433#endif
3434 }
3435
3436 return NOTIFY_OK;
3437}
3438
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439/*
3440 * /proc
3441 */
3442
3443#ifdef CONFIG_PROC_FS
3444
Alexey Dobriyan33120b32007-11-06 05:27:11 -08003445static const struct file_operations ipv6_route_proc_fops = {
3446 .owner = THIS_MODULE,
3447 .open = ipv6_route_open,
3448 .read = seq_read,
3449 .llseek = seq_lseek,
Hannes Frederic Sowa8d2ca1d2013-09-21 16:55:59 +02003450 .release = seq_release_net,
Alexey Dobriyan33120b32007-11-06 05:27:11 -08003451};
3452
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453static int rt6_stats_seq_show(struct seq_file *seq, void *v)
3454{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003455 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003457 net->ipv6.rt6_stats->fib_nodes,
3458 net->ipv6.rt6_stats->fib_route_nodes,
3459 net->ipv6.rt6_stats->fib_rt_alloc,
3460 net->ipv6.rt6_stats->fib_rt_entries,
3461 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00003462 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003463 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464
3465 return 0;
3466}
3467
3468static int rt6_stats_seq_open(struct inode *inode, struct file *file)
3469{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07003470 return single_open_net(inode, file, rt6_stats_seq_show);
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003471}
3472
Arjan van de Ven9a321442007-02-12 00:55:35 -08003473static const struct file_operations rt6_stats_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 .owner = THIS_MODULE,
3475 .open = rt6_stats_seq_open,
3476 .read = seq_read,
3477 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07003478 .release = single_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479};
3480#endif /* CONFIG_PROC_FS */
3481
3482#ifdef CONFIG_SYSCTL
3483
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484static
Joe Perchesfe2c6332013-06-11 23:04:25 -07003485int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 void __user *buffer, size_t *lenp, loff_t *ppos)
3487{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003488 struct net *net;
3489 int delay;
3490 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003492
3493 net = (struct net *)ctl->extra1;
3494 delay = net->ipv6.sysctl.flush_delay;
3495 proc_dointvec(ctl, write, buffer, lenp, ppos);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02003496 fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003497 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498}
3499
Joe Perchesfe2c6332013-06-11 23:04:25 -07003500struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003501 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08003503 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07003505 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003506 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507 },
3508 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003510 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 .maxlen = sizeof(int),
3512 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003513 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 },
3515 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08003517 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 .maxlen = sizeof(int),
3519 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003520 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 },
3522 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08003524 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 .maxlen = sizeof(int),
3526 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003527 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 },
3529 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08003531 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 .maxlen = sizeof(int),
3533 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003534 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 },
3536 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08003538 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539 .maxlen = sizeof(int),
3540 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003541 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 },
3543 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08003545 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546 .maxlen = sizeof(int),
3547 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003548 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549 },
3550 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08003552 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 .maxlen = sizeof(int),
3554 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003555 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556 },
3557 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08003559 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 .maxlen = sizeof(int),
3561 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003562 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563 },
3564 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08003566 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567 .maxlen = sizeof(int),
3568 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003569 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08003571 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572};
3573
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003574struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003575{
3576 struct ctl_table *table;
3577
3578 table = kmemdup(ipv6_route_table_template,
3579 sizeof(ipv6_route_table_template),
3580 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003581
3582 if (table) {
3583 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003584 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003585 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003586 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
3587 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
3588 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
3589 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
3590 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
3591 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
3592 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08003593 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
Eric W. Biederman464dc802012-11-16 03:02:59 +00003594
3595 /* Don't export sysctls to unprivileged users */
3596 if (net->user_ns != &init_user_ns)
3597 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003598 }
3599
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003600 return table;
3601}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602#endif
3603
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003604static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003605{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07003606 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003607
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003608 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
3609 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003610
Eric Dumazetfc66f952010-10-08 06:37:34 +00003611 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
3612 goto out_ip6_dst_ops;
3613
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003614 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
3615 sizeof(*net->ipv6.ip6_null_entry),
3616 GFP_KERNEL);
3617 if (!net->ipv6.ip6_null_entry)
Eric Dumazetfc66f952010-10-08 06:37:34 +00003618 goto out_ip6_dst_entries;
Changli Gaod8d1f302010-06-10 23:31:35 -07003619 net->ipv6.ip6_null_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003620 (struct dst_entry *)net->ipv6.ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003621 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003622 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
3623 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003624
3625#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3626 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
3627 sizeof(*net->ipv6.ip6_prohibit_entry),
3628 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003629 if (!net->ipv6.ip6_prohibit_entry)
3630 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003631 net->ipv6.ip6_prohibit_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003632 (struct dst_entry *)net->ipv6.ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003633 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003634 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
3635 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003636
3637 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
3638 sizeof(*net->ipv6.ip6_blk_hole_entry),
3639 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003640 if (!net->ipv6.ip6_blk_hole_entry)
3641 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003642 net->ipv6.ip6_blk_hole_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003643 (struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003644 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003645 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
3646 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003647#endif
3648
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07003649 net->ipv6.sysctl.flush_delay = 0;
3650 net->ipv6.sysctl.ip6_rt_max_size = 4096;
3651 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
3652 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
3653 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
3654 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
3655 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
3656 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
3657
Benjamin Thery6891a342008-03-04 13:49:47 -08003658 net->ipv6.ip6_rt_gc_expire = 30*HZ;
3659
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003660 ret = 0;
3661out:
3662 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003663
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003664#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3665out_ip6_prohibit_entry:
3666 kfree(net->ipv6.ip6_prohibit_entry);
3667out_ip6_null_entry:
3668 kfree(net->ipv6.ip6_null_entry);
3669#endif
Eric Dumazetfc66f952010-10-08 06:37:34 +00003670out_ip6_dst_entries:
3671 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003672out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003673 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003674}
3675
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003676static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003677{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003678 kfree(net->ipv6.ip6_null_entry);
3679#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3680 kfree(net->ipv6.ip6_prohibit_entry);
3681 kfree(net->ipv6.ip6_blk_hole_entry);
3682#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003683 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003684}
3685
Thomas Grafd1896342012-06-18 12:08:33 +00003686static int __net_init ip6_route_net_init_late(struct net *net)
3687{
3688#ifdef CONFIG_PROC_FS
Gao fengd4beaa62013-02-18 01:34:54 +00003689 proc_create("ipv6_route", 0, net->proc_net, &ipv6_route_proc_fops);
3690 proc_create("rt6_stats", S_IRUGO, net->proc_net, &rt6_stats_seq_fops);
Thomas Grafd1896342012-06-18 12:08:33 +00003691#endif
3692 return 0;
3693}
3694
3695static void __net_exit ip6_route_net_exit_late(struct net *net)
3696{
3697#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00003698 remove_proc_entry("ipv6_route", net->proc_net);
3699 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00003700#endif
3701}
3702
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003703static struct pernet_operations ip6_route_net_ops = {
3704 .init = ip6_route_net_init,
3705 .exit = ip6_route_net_exit,
3706};
3707
David S. Millerc3426b42012-06-09 16:27:05 -07003708static int __net_init ipv6_inetpeer_init(struct net *net)
3709{
3710 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
3711
3712 if (!bp)
3713 return -ENOMEM;
3714 inet_peer_base_init(bp);
3715 net->ipv6.peers = bp;
3716 return 0;
3717}
3718
3719static void __net_exit ipv6_inetpeer_exit(struct net *net)
3720{
3721 struct inet_peer_base *bp = net->ipv6.peers;
3722
3723 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07003724 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07003725 kfree(bp);
3726}
3727
David S. Miller2b823f72012-06-09 19:00:16 -07003728static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07003729 .init = ipv6_inetpeer_init,
3730 .exit = ipv6_inetpeer_exit,
3731};
3732
Thomas Grafd1896342012-06-18 12:08:33 +00003733static struct pernet_operations ip6_route_net_late_ops = {
3734 .init = ip6_route_net_init_late,
3735 .exit = ip6_route_net_exit_late,
3736};
3737
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003738static struct notifier_block ip6_route_dev_notifier = {
3739 .notifier_call = ip6_route_dev_notify,
3740 .priority = 0,
3741};
3742
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003743int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003745 int ret;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07003746 int cpu;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003747
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003748 ret = -ENOMEM;
3749 ip6_dst_ops_template.kmem_cachep =
3750 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
3751 SLAB_HWCACHE_ALIGN, NULL);
3752 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08003753 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07003754
Eric Dumazetfc66f952010-10-08 06:37:34 +00003755 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003756 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003757 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003758
David S. Millerc3426b42012-06-09 16:27:05 -07003759 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
3760 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003761 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00003762
David S. Miller7e52b332012-06-15 15:51:55 -07003763 ret = register_pernet_subsys(&ip6_route_net_ops);
3764 if (ret)
3765 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07003766
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07003767 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
3768
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003769 /* Registering of the loopback is done before this portion of code,
3770 * the loopback reference in rt6_info will not be taken, do it
3771 * manually for init_net */
Changli Gaod8d1f302010-06-10 23:31:35 -07003772 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003773 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3774 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07003775 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003776 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07003777 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003778 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3779 #endif
David S. Millere8803b62012-06-16 01:12:19 -07003780 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003781 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003782 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003783
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003784 ret = xfrm6_init();
3785 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003786 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08003787
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003788 ret = fib6_rules_init();
3789 if (ret)
3790 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08003791
Thomas Grafd1896342012-06-18 12:08:33 +00003792 ret = register_pernet_subsys(&ip6_route_net_late_ops);
3793 if (ret)
3794 goto fib6_rules_init;
3795
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003796 ret = -ENOBUFS;
Greg Rosec7ac8672011-06-10 01:27:09 +00003797 if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) ||
3798 __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) ||
3799 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL))
Thomas Grafd1896342012-06-18 12:08:33 +00003800 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003801
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003802 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003803 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00003804 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003805
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07003806 for_each_possible_cpu(cpu) {
3807 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
3808
3809 INIT_LIST_HEAD(&ul->head);
3810 spin_lock_init(&ul->lock);
3811 }
3812
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003813out:
3814 return ret;
3815
Thomas Grafd1896342012-06-18 12:08:33 +00003816out_register_late_subsys:
3817 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003818fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003819 fib6_rules_cleanup();
3820xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003821 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00003822out_fib6_init:
3823 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003824out_register_subsys:
3825 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07003826out_register_inetpeer:
3827 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00003828out_dst_entries:
3829 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003830out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003831 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003832 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833}
3834
3835void ip6_route_cleanup(void)
3836{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003837 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00003838 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07003839 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07003842 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003843 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003844 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003845 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846}