blob: c95c3197c186cefc082c895be9c9183a2c6e847b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Linux INET6 implementation
3 * FIB front-end.
4 *
5 * Authors:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09006 * Pedro Roque <roque@di.fc.ul.pt>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
13
14/* Changes:
15 *
16 * YOSHIFUJI Hideaki @USAGI
17 * reworked default router selection.
18 * - respect outgoing interface
19 * - select from (probably) reachable routers (i.e.
20 * routers in REACHABLE, STALE, DELAY or PROBE states).
21 * - always select the same router if it is (probably)
22 * reachable. otherwise, round-robin the list.
YOSHIFUJI Hideakic0bece92006-08-23 17:23:25 -070023 * Ville Nuorvala
24 * Fixed routing subtrees.
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 */
26
Joe Perchesf3213832012-05-15 14:11:53 +000027#define pr_fmt(fmt) "IPv6: " fmt
28
Randy Dunlap4fc268d2006-01-11 12:17:47 -080029#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/errno.h>
Paul Gortmakerbc3b2d72011-07-15 11:47:34 -040031#include <linux/export.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/types.h>
33#include <linux/times.h>
34#include <linux/socket.h>
35#include <linux/sockios.h>
36#include <linux/net.h>
37#include <linux/route.h>
38#include <linux/netdevice.h>
39#include <linux/in6.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090040#include <linux/mroute6.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <linux/if_arp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/proc_fs.h>
44#include <linux/seq_file.h>
Daniel Lezcano5b7c9312008-03-03 23:28:58 -080045#include <linux/nsproxy.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090046#include <linux/slab.h>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020047#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <net/snmp.h>
49#include <net/ipv6.h>
50#include <net/ip6_fib.h>
51#include <net/ip6_route.h>
52#include <net/ndisc.h>
53#include <net/addrconf.h>
54#include <net/tcp.h>
55#include <linux/rtnetlink.h>
56#include <net/dst.h>
57#include <net/xfrm.h>
Tom Tucker8d717402006-07-30 20:43:36 -070058#include <net/netevent.h>
Thomas Graf21713eb2006-08-15 00:35:24 -070059#include <net/netlink.h>
Nicolas Dichtel51ebd312012-10-22 03:42:09 +000060#include <net/nexthop.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
62#include <asm/uaccess.h>
63
64#ifdef CONFIG_SYSCTL
65#include <linux/sysctl.h>
66#endif
67
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +020068enum rt6_nud_state {
Jiri Benc7e980562013-12-11 13:48:20 +010069 RT6_NUD_FAIL_HARD = -3,
70 RT6_NUD_FAIL_PROBE = -2,
71 RT6_NUD_FAIL_DO_RR = -1,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +020072 RT6_NUD_SUCCEED = 1
73};
74
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -070075static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort);
Linus Torvalds1da177e2005-04-16 15:20:36 -070076static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
David S. Miller0dbaee32010-12-13 12:52:14 -080077static unsigned int ip6_default_advmss(const struct dst_entry *dst);
Steffen Klassertebb762f2011-11-23 02:12:51 +000078static unsigned int ip6_mtu(const struct dst_entry *dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079static struct dst_entry *ip6_negative_advice(struct dst_entry *);
80static void ip6_dst_destroy(struct dst_entry *);
81static void ip6_dst_ifdown(struct dst_entry *,
82 struct net_device *dev, int how);
Daniel Lezcano569d3642008-01-18 03:56:57 -080083static int ip6_dst_gc(struct dst_ops *ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
85static int ip6_pkt_discard(struct sk_buff *skb);
Eric Dumazetaad88722014-04-15 13:47:15 -040086static int ip6_pkt_discard_out(struct sock *sk, struct sk_buff *skb);
Kamala R7150aed2013-12-02 19:55:21 +053087static int ip6_pkt_prohibit(struct sk_buff *skb);
Eric Dumazetaad88722014-04-15 13:47:15 -040088static int ip6_pkt_prohibit_out(struct sock *sk, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089static void ip6_link_failure(struct sk_buff *skb);
David S. Miller6700c272012-07-17 03:29:28 -070090static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
91 struct sk_buff *skb, u32 mtu);
92static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
93 struct sk_buff *skb);
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -070094static void rt6_dst_from_metrics_check(struct rt6_info *rt);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +020095static int rt6_score_route(struct rt6_info *rt, int oif, int strict);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -080097#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -080098static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +000099 const struct in6_addr *prefix, int prefixlen,
100 const struct in6_addr *gwaddr, int ifindex,
Eric Dumazet95c96172012-04-15 05:58:06 +0000101 unsigned int pref);
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800102static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000103 const struct in6_addr *prefix, int prefixlen,
104 const struct in6_addr *gwaddr, int ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800105#endif
106
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700107struct uncached_list {
108 spinlock_t lock;
109 struct list_head head;
110};
111
112static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list);
113
114static void rt6_uncached_list_add(struct rt6_info *rt)
115{
116 struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);
117
118 rt->dst.flags |= DST_NOCACHE;
119 rt->rt6i_uncached_list = ul;
120
121 spin_lock_bh(&ul->lock);
122 list_add_tail(&rt->rt6i_uncached, &ul->head);
123 spin_unlock_bh(&ul->lock);
124}
125
126static void rt6_uncached_list_del(struct rt6_info *rt)
127{
128 if (!list_empty(&rt->rt6i_uncached)) {
129 struct uncached_list *ul = rt->rt6i_uncached_list;
130
131 spin_lock_bh(&ul->lock);
132 list_del(&rt->rt6i_uncached);
133 spin_unlock_bh(&ul->lock);
134 }
135}
136
137static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev)
138{
139 struct net_device *loopback_dev = net->loopback_dev;
140 int cpu;
141
142 for_each_possible_cpu(cpu) {
143 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
144 struct rt6_info *rt;
145
146 spin_lock_bh(&ul->lock);
147 list_for_each_entry(rt, &ul->head, rt6i_uncached) {
148 struct inet6_dev *rt_idev = rt->rt6i_idev;
149 struct net_device *rt_dev = rt->dst.dev;
150
151 if (rt_idev && (rt_idev->dev == dev || !dev) &&
152 rt_idev->dev != loopback_dev) {
153 rt->rt6i_idev = in6_dev_get(loopback_dev);
154 in6_dev_put(rt_idev);
155 }
156
157 if (rt_dev && (rt_dev == dev || !dev) &&
158 rt_dev != loopback_dev) {
159 rt->dst.dev = loopback_dev;
160 dev_hold(rt->dst.dev);
161 dev_put(rt_dev);
162 }
163 }
164 spin_unlock_bh(&ul->lock);
165 }
166}
167
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700168static u32 *rt6_pcpu_cow_metrics(struct rt6_info *rt)
169{
170 return dst_metrics_write_ptr(rt->dst.from);
171}
172
David S. Miller06582542011-01-27 14:58:42 -0800173static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
174{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700175 struct rt6_info *rt = (struct rt6_info *)dst;
David S. Miller06582542011-01-27 14:58:42 -0800176
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700177 if (rt->rt6i_flags & RTF_PCPU)
178 return rt6_pcpu_cow_metrics(rt);
179 else if (rt->rt6i_flags & RTF_CACHE)
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700180 return NULL;
181 else
Martin KaFai Lau3b471172015-02-12 16:14:08 -0800182 return dst_cow_metrics_generic(dst, old);
David S. Miller06582542011-01-27 14:58:42 -0800183}
184
David S. Millerf894cbf2012-07-02 21:52:24 -0700185static inline const void *choose_neigh_daddr(struct rt6_info *rt,
186 struct sk_buff *skb,
187 const void *daddr)
David S. Miller39232972012-01-26 15:22:32 -0500188{
189 struct in6_addr *p = &rt->rt6i_gateway;
190
David S. Millera7563f32012-01-26 16:29:16 -0500191 if (!ipv6_addr_any(p))
David S. Miller39232972012-01-26 15:22:32 -0500192 return (const void *) p;
David S. Millerf894cbf2012-07-02 21:52:24 -0700193 else if (skb)
194 return &ipv6_hdr(skb)->daddr;
David S. Miller39232972012-01-26 15:22:32 -0500195 return daddr;
196}
197
David S. Millerf894cbf2012-07-02 21:52:24 -0700198static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst,
199 struct sk_buff *skb,
200 const void *daddr)
David S. Millerd3aaeb32011-07-18 00:40:17 -0700201{
David S. Miller39232972012-01-26 15:22:32 -0500202 struct rt6_info *rt = (struct rt6_info *) dst;
203 struct neighbour *n;
204
David S. Millerf894cbf2012-07-02 21:52:24 -0700205 daddr = choose_neigh_daddr(rt, skb, daddr);
YOSHIFUJI Hideaki / 吉藤英明8e022ee2013-01-17 12:53:09 +0000206 n = __ipv6_neigh_lookup(dst->dev, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500207 if (n)
208 return n;
209 return neigh_create(&nd_tbl, daddr, dst->dev);
210}
211
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -0800212static struct dst_ops ip6_dst_ops_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 .family = AF_INET6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 .gc = ip6_dst_gc,
215 .gc_thresh = 1024,
216 .check = ip6_dst_check,
David S. Miller0dbaee32010-12-13 12:52:14 -0800217 .default_advmss = ip6_default_advmss,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000218 .mtu = ip6_mtu,
David S. Miller06582542011-01-27 14:58:42 -0800219 .cow_metrics = ipv6_cow_metrics,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 .destroy = ip6_dst_destroy,
221 .ifdown = ip6_dst_ifdown,
222 .negative_advice = ip6_negative_advice,
223 .link_failure = ip6_link_failure,
224 .update_pmtu = ip6_rt_update_pmtu,
David S. Miller6e157b62012-07-12 00:05:02 -0700225 .redirect = rt6_do_redirect,
Herbert Xu1ac06e02008-05-20 14:32:14 -0700226 .local_out = __ip6_local_out,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700227 .neigh_lookup = ip6_neigh_lookup,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228};
229
Steffen Klassertebb762f2011-11-23 02:12:51 +0000230static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
Roland Dreierec831ea2011-01-31 13:16:00 -0800231{
Steffen Klassert618f9bc2011-11-23 02:13:31 +0000232 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
233
234 return mtu ? : dst->dev->mtu;
Roland Dreierec831ea2011-01-31 13:16:00 -0800235}
236
David S. Miller6700c272012-07-17 03:29:28 -0700237static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
238 struct sk_buff *skb, u32 mtu)
David S. Miller14e50e52007-05-24 18:17:54 -0700239{
240}
241
David S. Miller6700c272012-07-17 03:29:28 -0700242static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
243 struct sk_buff *skb)
David S. Millerb587ee32012-07-12 00:39:24 -0700244{
245}
246
Held Bernhard0972ddb2011-04-24 22:07:32 +0000247static u32 *ip6_rt_blackhole_cow_metrics(struct dst_entry *dst,
248 unsigned long old)
249{
250 return NULL;
251}
252
David S. Miller14e50e52007-05-24 18:17:54 -0700253static struct dst_ops ip6_dst_blackhole_ops = {
254 .family = AF_INET6,
David S. Miller14e50e52007-05-24 18:17:54 -0700255 .destroy = ip6_dst_destroy,
256 .check = ip6_dst_check,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000257 .mtu = ip6_blackhole_mtu,
Eric Dumazet214f45c2011-02-18 11:39:01 -0800258 .default_advmss = ip6_default_advmss,
David S. Miller14e50e52007-05-24 18:17:54 -0700259 .update_pmtu = ip6_rt_blackhole_update_pmtu,
David S. Millerb587ee32012-07-12 00:39:24 -0700260 .redirect = ip6_rt_blackhole_redirect,
Held Bernhard0972ddb2011-04-24 22:07:32 +0000261 .cow_metrics = ip6_rt_blackhole_cow_metrics,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700262 .neigh_lookup = ip6_neigh_lookup,
David S. Miller14e50e52007-05-24 18:17:54 -0700263};
264
David S. Miller62fa8a82011-01-26 20:51:05 -0800265static const u32 ip6_template_metrics[RTAX_MAX] = {
Li RongQing14edd872012-10-24 14:01:18 +0800266 [RTAX_HOPLIMIT - 1] = 0,
David S. Miller62fa8a82011-01-26 20:51:05 -0800267};
268
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000269static const struct rt6_info ip6_null_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700270 .dst = {
271 .__refcnt = ATOMIC_INIT(1),
272 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000273 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700274 .error = -ENETUNREACH,
Changli Gaod8d1f302010-06-10 23:31:35 -0700275 .input = ip6_pkt_discard,
276 .output = ip6_pkt_discard_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 },
278 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700279 .rt6i_protocol = RTPROT_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 .rt6i_metric = ~(u32) 0,
281 .rt6i_ref = ATOMIC_INIT(1),
282};
283
Thomas Graf101367c2006-08-04 03:39:02 -0700284#ifdef CONFIG_IPV6_MULTIPLE_TABLES
285
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000286static const struct rt6_info ip6_prohibit_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700287 .dst = {
288 .__refcnt = ATOMIC_INIT(1),
289 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000290 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700291 .error = -EACCES,
Changli Gaod8d1f302010-06-10 23:31:35 -0700292 .input = ip6_pkt_prohibit,
293 .output = ip6_pkt_prohibit_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700294 },
295 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700296 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700297 .rt6i_metric = ~(u32) 0,
298 .rt6i_ref = ATOMIC_INIT(1),
299};
300
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000301static const struct rt6_info ip6_blk_hole_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700302 .dst = {
303 .__refcnt = ATOMIC_INIT(1),
304 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000305 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700306 .error = -EINVAL,
Changli Gaod8d1f302010-06-10 23:31:35 -0700307 .input = dst_discard,
Eric Dumazetaad88722014-04-15 13:47:15 -0400308 .output = dst_discard_sk,
Thomas Graf101367c2006-08-04 03:39:02 -0700309 },
310 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700311 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700312 .rt6i_metric = ~(u32) 0,
313 .rt6i_ref = ATOMIC_INIT(1),
314};
315
316#endif
317
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318/* allocate dst with ip6_dst_ops */
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700319static struct rt6_info *__ip6_dst_alloc(struct net *net,
320 struct net_device *dev,
Martin KaFai Lauad706862015-08-14 11:05:52 -0700321 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322{
David S. Miller97bab732012-06-09 22:36:36 -0700323 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +0000324 0, DST_OBSOLETE_FORCE_CHK, flags);
David S. Millercf911662011-04-28 14:31:47 -0700325
David S. Miller97bab732012-06-09 22:36:36 -0700326 if (rt) {
Steffen Klassert81048912012-07-05 23:37:09 +0000327 struct dst_entry *dst = &rt->dst;
328
329 memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000330 INIT_LIST_HEAD(&rt->rt6i_siblings);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700331 INIT_LIST_HEAD(&rt->rt6i_uncached);
David S. Miller97bab732012-06-09 22:36:36 -0700332 }
David S. Millercf911662011-04-28 14:31:47 -0700333 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334}
335
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700336static struct rt6_info *ip6_dst_alloc(struct net *net,
337 struct net_device *dev,
Martin KaFai Lauad706862015-08-14 11:05:52 -0700338 int flags)
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700339{
Martin KaFai Lauad706862015-08-14 11:05:52 -0700340 struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700341
342 if (rt) {
343 rt->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, GFP_ATOMIC);
344 if (rt->rt6i_pcpu) {
345 int cpu;
346
347 for_each_possible_cpu(cpu) {
348 struct rt6_info **p;
349
350 p = per_cpu_ptr(rt->rt6i_pcpu, cpu);
351 /* no one shares rt */
352 *p = NULL;
353 }
354 } else {
355 dst_destroy((struct dst_entry *)rt);
356 return NULL;
357 }
358 }
359
360 return rt;
361}
362
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363static void ip6_dst_destroy(struct dst_entry *dst)
364{
365 struct rt6_info *rt = (struct rt6_info *)dst;
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000366 struct dst_entry *from = dst->from;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700367 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700369 dst_destroy_metrics_generic(dst);
Markus Elfring87775312015-07-02 16:30:24 +0200370 free_percpu(rt->rt6i_pcpu);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700371 rt6_uncached_list_del(rt);
372
373 idev = rt->rt6i_idev;
David S. Miller38308472011-12-03 18:02:47 -0500374 if (idev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 rt->rt6i_idev = NULL;
376 in6_dev_put(idev);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900377 }
Gao feng1716a962012-04-06 00:13:10 +0000378
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000379 dst->from = NULL;
380 dst_release(from);
David S. Millerb3419362010-11-30 12:27:11 -0800381}
382
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
384 int how)
385{
386 struct rt6_info *rt = (struct rt6_info *)dst;
387 struct inet6_dev *idev = rt->rt6i_idev;
Denis V. Lunev5a3e55d2007-12-07 00:38:10 -0800388 struct net_device *loopback_dev =
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900389 dev_net(dev)->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
David S. Miller97cac082012-07-02 22:43:47 -0700391 if (dev != loopback_dev) {
392 if (idev && idev->dev == dev) {
393 struct inet6_dev *loopback_idev =
394 in6_dev_get(loopback_dev);
395 if (loopback_idev) {
396 rt->rt6i_idev = loopback_idev;
397 in6_dev_put(idev);
398 }
399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 }
401}
402
Eric Dumazeta50feda2012-05-18 18:57:34 +0000403static bool rt6_check_expired(const struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404{
Gao feng1716a962012-04-06 00:13:10 +0000405 if (rt->rt6i_flags & RTF_EXPIRES) {
406 if (time_after(jiffies, rt->dst.expires))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000407 return true;
Gao feng1716a962012-04-06 00:13:10 +0000408 } else if (rt->dst.from) {
Li RongQing3fd91fb2012-09-13 19:54:57 +0000409 return rt6_check_expired((struct rt6_info *) rt->dst.from);
Gao feng1716a962012-04-06 00:13:10 +0000410 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000411 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412}
413
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000414/* Multipath route selection:
415 * Hash based function using packet header and flowlabel.
416 * Adapted from fib_info_hashfn()
417 */
418static int rt6_info_hash_nhsfn(unsigned int candidate_count,
419 const struct flowi6 *fl6)
420{
421 unsigned int val = fl6->flowi6_proto;
422
YOSHIFUJI Hideaki / 吉藤英明c08977b2013-01-13 05:02:29 +0000423 val ^= ipv6_addr_hash(&fl6->daddr);
424 val ^= ipv6_addr_hash(&fl6->saddr);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000425
426 /* Work only if this not encapsulated */
427 switch (fl6->flowi6_proto) {
428 case IPPROTO_UDP:
429 case IPPROTO_TCP:
430 case IPPROTO_SCTP:
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000431 val ^= (__force u16)fl6->fl6_sport;
432 val ^= (__force u16)fl6->fl6_dport;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000433 break;
434
435 case IPPROTO_ICMPV6:
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000436 val ^= (__force u16)fl6->fl6_icmp_type;
437 val ^= (__force u16)fl6->fl6_icmp_code;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000438 break;
439 }
440 /* RFC6438 recommands to use flowlabel */
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000441 val ^= (__force u32)fl6->flowlabel;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000442
443 /* Perhaps, we need to tune, this function? */
444 val = val ^ (val >> 7) ^ (val >> 12);
445 return val % candidate_count;
446}
447
448static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200449 struct flowi6 *fl6, int oif,
450 int strict)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000451{
452 struct rt6_info *sibling, *next_sibling;
453 int route_choosen;
454
455 route_choosen = rt6_info_hash_nhsfn(match->rt6i_nsiblings + 1, fl6);
456 /* Don't change the route, if route_choosen == 0
457 * (siblings does not include ourself)
458 */
459 if (route_choosen)
460 list_for_each_entry_safe(sibling, next_sibling,
461 &match->rt6i_siblings, rt6i_siblings) {
462 route_choosen--;
463 if (route_choosen == 0) {
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200464 if (rt6_score_route(sibling, oif, strict) < 0)
465 break;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000466 match = sibling;
467 break;
468 }
469 }
470 return match;
471}
472
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473/*
Thomas Grafc71099a2006-08-04 23:20:06 -0700474 * Route lookup. Any table->tb6_lock is implied.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 */
476
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800477static inline struct rt6_info *rt6_device_match(struct net *net,
478 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000479 const struct in6_addr *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 int oif,
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700481 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
483 struct rt6_info *local = NULL;
484 struct rt6_info *sprt;
485
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900486 if (!oif && ipv6_addr_any(saddr))
487 goto out;
488
Changli Gaod8d1f302010-06-10 23:31:35 -0700489 for (sprt = rt; sprt; sprt = sprt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -0500490 struct net_device *dev = sprt->dst.dev;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900491
492 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 if (dev->ifindex == oif)
494 return sprt;
495 if (dev->flags & IFF_LOOPBACK) {
David S. Miller38308472011-12-03 18:02:47 -0500496 if (!sprt->rt6i_idev ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 sprt->rt6i_idev->dev->ifindex != oif) {
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700498 if (flags & RT6_LOOKUP_F_IFACE && oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 continue;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900500 if (local && (!oif ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 local->rt6i_idev->dev->ifindex == oif))
502 continue;
503 }
504 local = sprt;
505 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900506 } else {
507 if (ipv6_chk_addr(net, saddr, dev,
508 flags & RT6_LOOKUP_F_IFACE))
509 return sprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900511 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900513 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 if (local)
515 return local;
516
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700517 if (flags & RT6_LOOKUP_F_IFACE)
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800518 return net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900520out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 return rt;
522}
523
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800524#ifdef CONFIG_IPV6_ROUTER_PREF
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200525struct __rt6_probe_work {
526 struct work_struct work;
527 struct in6_addr target;
528 struct net_device *dev;
529};
530
531static void rt6_probe_deferred(struct work_struct *w)
532{
533 struct in6_addr mcaddr;
534 struct __rt6_probe_work *work =
535 container_of(w, struct __rt6_probe_work, work);
536
537 addrconf_addr_solict_mult(&work->target, &mcaddr);
538 ndisc_send_ns(work->dev, NULL, &work->target, &mcaddr, NULL);
539 dev_put(work->dev);
Michael Büsch662f5532015-02-08 10:14:07 +0100540 kfree(work);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200541}
542
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800543static void rt6_probe(struct rt6_info *rt)
544{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000545 struct neighbour *neigh;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800546 /*
547 * Okay, this does not seem to be appropriate
548 * for now, however, we need to check if it
549 * is really so; aka Router Reachability Probing.
550 *
551 * Router Reachability Probe MUST be rate-limited
552 * to no more than one per minute.
553 */
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000554 if (!rt || !(rt->rt6i_flags & RTF_GATEWAY))
Amerigo Wangfdd66812012-09-10 02:48:44 +0000555 return;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000556 rcu_read_lock_bh();
557 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
558 if (neigh) {
559 write_lock(&neigh->lock);
560 if (neigh->nud_state & NUD_VALID)
561 goto out;
YOSHIFUJI Hideaki / 吉藤英明7ff74a52013-01-17 12:53:02 +0000562 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000563
564 if (!neigh ||
YOSHIFUJI Hideaki52e16352006-03-20 17:05:47 -0800565 time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) {
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200566 struct __rt6_probe_work *work;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800567
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200568 work = kmalloc(sizeof(*work), GFP_ATOMIC);
569
570 if (neigh && work)
Jiri Benc7e980562013-12-11 13:48:20 +0100571 __neigh_set_probe_once(neigh);
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000572
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200573 if (neigh)
574 write_unlock(&neigh->lock);
575
576 if (work) {
577 INIT_WORK(&work->work, rt6_probe_deferred);
578 work->target = rt->rt6i_gateway;
579 dev_hold(rt->dst.dev);
580 work->dev = rt->dst.dev;
581 schedule_work(&work->work);
582 }
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000583 } else {
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000584out:
585 write_unlock(&neigh->lock);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000586 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000587 rcu_read_unlock_bh();
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800588}
589#else
590static inline void rt6_probe(struct rt6_info *rt)
591{
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800592}
593#endif
594
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595/*
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800596 * Default Router Selection (RFC 2461 6.3.6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 */
Dave Jonesb6f99a22007-03-22 12:27:49 -0700598static inline int rt6_check_dev(struct rt6_info *rt, int oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599{
David S. Millerd1918542011-12-28 20:19:20 -0500600 struct net_device *dev = rt->dst.dev;
David S. Miller161980f2007-04-06 11:42:27 -0700601 if (!oif || dev->ifindex == oif)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800602 return 2;
David S. Miller161980f2007-04-06 11:42:27 -0700603 if ((dev->flags & IFF_LOOPBACK) &&
604 rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
605 return 1;
606 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607}
608
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200609static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000611 struct neighbour *neigh;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200612 enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000613
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700614 if (rt->rt6i_flags & RTF_NONEXTHOP ||
615 !(rt->rt6i_flags & RTF_GATEWAY))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200616 return RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000617
618 rcu_read_lock_bh();
619 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
620 if (neigh) {
621 read_lock(&neigh->lock);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800622 if (neigh->nud_state & NUD_VALID)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200623 ret = RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800624#ifdef CONFIG_IPV6_ROUTER_PREF
Paul Marksa5a81f02012-12-03 10:26:54 +0000625 else if (!(neigh->nud_state & NUD_FAILED))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200626 ret = RT6_NUD_SUCCEED;
Jiri Benc7e980562013-12-11 13:48:20 +0100627 else
628 ret = RT6_NUD_FAIL_PROBE;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800629#endif
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000630 read_unlock(&neigh->lock);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200631 } else {
632 ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
Jiri Benc7e980562013-12-11 13:48:20 +0100633 RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR;
Paul Marksa5a81f02012-12-03 10:26:54 +0000634 }
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000635 rcu_read_unlock_bh();
636
Paul Marksa5a81f02012-12-03 10:26:54 +0000637 return ret;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800638}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800640static int rt6_score_route(struct rt6_info *rt, int oif,
641 int strict)
642{
Paul Marksa5a81f02012-12-03 10:26:54 +0000643 int m;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900644
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700645 m = rt6_check_dev(rt, oif);
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700646 if (!m && (strict & RT6_LOOKUP_F_IFACE))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200647 return RT6_NUD_FAIL_HARD;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800648#ifdef CONFIG_IPV6_ROUTER_PREF
649 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
650#endif
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200651 if (strict & RT6_LOOKUP_F_REACHABLE) {
652 int n = rt6_check_neigh(rt);
653 if (n < 0)
654 return n;
655 }
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800656 return m;
657}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
David S. Millerf11e6652007-03-24 20:36:25 -0700659static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200660 int *mpri, struct rt6_info *match,
661 bool *do_rr)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800662{
David S. Millerf11e6652007-03-24 20:36:25 -0700663 int m;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200664 bool match_do_rr = false;
David S. Millerf11e6652007-03-24 20:36:25 -0700665
666 if (rt6_check_expired(rt))
667 goto out;
668
669 m = rt6_score_route(rt, oif, strict);
Jiri Benc7e980562013-12-11 13:48:20 +0100670 if (m == RT6_NUD_FAIL_DO_RR) {
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200671 match_do_rr = true;
672 m = 0; /* lowest valid score */
Jiri Benc7e980562013-12-11 13:48:20 +0100673 } else if (m == RT6_NUD_FAIL_HARD) {
David S. Millerf11e6652007-03-24 20:36:25 -0700674 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700675 }
676
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200677 if (strict & RT6_LOOKUP_F_REACHABLE)
678 rt6_probe(rt);
679
Jiri Benc7e980562013-12-11 13:48:20 +0100680 /* note that m can be RT6_NUD_FAIL_PROBE at this point */
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200681 if (m > *mpri) {
682 *do_rr = match_do_rr;
683 *mpri = m;
684 match = rt;
685 }
David S. Millerf11e6652007-03-24 20:36:25 -0700686out:
687 return match;
688}
689
690static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
691 struct rt6_info *rr_head,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200692 u32 metric, int oif, int strict,
693 bool *do_rr)
David S. Millerf11e6652007-03-24 20:36:25 -0700694{
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700695 struct rt6_info *rt, *match, *cont;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800696 int mpri = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
David S. Millerf11e6652007-03-24 20:36:25 -0700698 match = NULL;
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700699 cont = NULL;
700 for (rt = rr_head; rt; rt = rt->dst.rt6_next) {
701 if (rt->rt6i_metric != metric) {
702 cont = rt;
703 break;
704 }
705
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200706 match = find_match(rt, oif, strict, &mpri, match, do_rr);
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700707 }
708
709 for (rt = fn->leaf; rt && rt != rr_head; rt = rt->dst.rt6_next) {
710 if (rt->rt6i_metric != metric) {
711 cont = rt;
712 break;
713 }
714
715 match = find_match(rt, oif, strict, &mpri, match, do_rr);
716 }
717
718 if (match || !cont)
719 return match;
720
721 for (rt = cont; rt; rt = rt->dst.rt6_next)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200722 match = find_match(rt, oif, strict, &mpri, match, do_rr);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800723
David S. Millerf11e6652007-03-24 20:36:25 -0700724 return match;
725}
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800726
David S. Millerf11e6652007-03-24 20:36:25 -0700727static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
728{
729 struct rt6_info *match, *rt0;
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800730 struct net *net;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200731 bool do_rr = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
David S. Millerf11e6652007-03-24 20:36:25 -0700733 rt0 = fn->rr_ptr;
734 if (!rt0)
735 fn->rr_ptr = rt0 = fn->leaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200737 match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict,
738 &do_rr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200740 if (do_rr) {
Changli Gaod8d1f302010-06-10 23:31:35 -0700741 struct rt6_info *next = rt0->dst.rt6_next;
David S. Millerf11e6652007-03-24 20:36:25 -0700742
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800743 /* no entries matched; do round-robin */
David S. Millerf11e6652007-03-24 20:36:25 -0700744 if (!next || next->rt6i_metric != rt0->rt6i_metric)
745 next = fn->leaf;
746
747 if (next != rt0)
748 fn->rr_ptr = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 }
750
David S. Millerd1918542011-12-28 20:19:20 -0500751 net = dev_net(rt0->dst.dev);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000752 return match ? match : net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753}
754
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700755static bool rt6_is_gw_or_nonexthop(const struct rt6_info *rt)
756{
757 return (rt->rt6i_flags & (RTF_NONEXTHOP | RTF_GATEWAY));
758}
759
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800760#ifdef CONFIG_IPV6_ROUTE_INFO
761int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000762 const struct in6_addr *gwaddr)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800763{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900764 struct net *net = dev_net(dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800765 struct route_info *rinfo = (struct route_info *) opt;
766 struct in6_addr prefix_buf, *prefix;
767 unsigned int pref;
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900768 unsigned long lifetime;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800769 struct rt6_info *rt;
770
771 if (len < sizeof(struct route_info)) {
772 return -EINVAL;
773 }
774
775 /* Sanity check for prefix_len and length */
776 if (rinfo->length > 3) {
777 return -EINVAL;
778 } else if (rinfo->prefix_len > 128) {
779 return -EINVAL;
780 } else if (rinfo->prefix_len > 64) {
781 if (rinfo->length < 2) {
782 return -EINVAL;
783 }
784 } else if (rinfo->prefix_len > 0) {
785 if (rinfo->length < 1) {
786 return -EINVAL;
787 }
788 }
789
790 pref = rinfo->route_pref;
791 if (pref == ICMPV6_ROUTER_PREF_INVALID)
Jens Rosenboom3933fc92009-09-10 06:25:11 +0000792 return -EINVAL;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800793
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900794 lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800795
796 if (rinfo->length == 3)
797 prefix = (struct in6_addr *)rinfo->prefix;
798 else {
799 /* this function is safe */
800 ipv6_addr_prefix(&prefix_buf,
801 (struct in6_addr *)rinfo->prefix,
802 rinfo->prefix_len);
803 prefix = &prefix_buf;
804 }
805
Duan Jiongf104a562013-11-08 09:56:53 +0800806 if (rinfo->prefix_len == 0)
807 rt = rt6_get_dflt_router(gwaddr, dev);
808 else
809 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len,
810 gwaddr, dev->ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800811
812 if (rt && !lifetime) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -0700813 ip6_del_rt(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800814 rt = NULL;
815 }
816
817 if (!rt && lifetime)
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800818 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800819 pref);
820 else if (rt)
821 rt->rt6i_flags = RTF_ROUTEINFO |
822 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
823
824 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +0000825 if (!addrconf_finite_timeout(lifetime))
826 rt6_clean_expires(rt);
827 else
828 rt6_set_expires(rt, jiffies + HZ * lifetime);
829
Amerigo Wang94e187c2012-10-29 00:13:19 +0000830 ip6_rt_put(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800831 }
832 return 0;
833}
834#endif
835
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700836static struct fib6_node* fib6_backtrack(struct fib6_node *fn,
837 struct in6_addr *saddr)
838{
839 struct fib6_node *pn;
840 while (1) {
841 if (fn->fn_flags & RTN_TL_ROOT)
842 return NULL;
843 pn = fn->parent;
844 if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn)
845 fn = fib6_lookup(FIB6_SUBTREE(pn), NULL, saddr);
846 else
847 fn = pn;
848 if (fn->fn_flags & RTN_RTINFO)
849 return fn;
850 }
851}
Thomas Grafc71099a2006-08-04 23:20:06 -0700852
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800853static struct rt6_info *ip6_pol_route_lookup(struct net *net,
854 struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500855 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856{
857 struct fib6_node *fn;
858 struct rt6_info *rt;
859
Thomas Grafc71099a2006-08-04 23:20:06 -0700860 read_lock_bh(&table->tb6_lock);
David S. Miller4c9483b2011-03-12 16:22:43 -0500861 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -0700862restart:
863 rt = fn->leaf;
David S. Miller4c9483b2011-03-12 16:22:43 -0500864 rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000865 if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0)
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200866 rt = rt6_multipath_select(rt, fl6, fl6->flowi6_oif, flags);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700867 if (rt == net->ipv6.ip6_null_entry) {
868 fn = fib6_backtrack(fn, &fl6->saddr);
869 if (fn)
870 goto restart;
871 }
Changli Gaod8d1f302010-06-10 23:31:35 -0700872 dst_use(&rt->dst, jiffies);
Thomas Grafc71099a2006-08-04 23:20:06 -0700873 read_unlock_bh(&table->tb6_lock);
Thomas Grafc71099a2006-08-04 23:20:06 -0700874 return rt;
875
876}
877
Ian Morris67ba4152014-08-24 21:53:10 +0100878struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
Florian Westphalea6e5742011-09-05 16:05:44 +0200879 int flags)
880{
881 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup);
882}
883EXPORT_SYMBOL_GPL(ip6_route_lookup);
884
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900885struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
886 const struct in6_addr *saddr, int oif, int strict)
Thomas Grafc71099a2006-08-04 23:20:06 -0700887{
David S. Miller4c9483b2011-03-12 16:22:43 -0500888 struct flowi6 fl6 = {
889 .flowi6_oif = oif,
890 .daddr = *daddr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700891 };
892 struct dst_entry *dst;
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700893 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
Thomas Grafc71099a2006-08-04 23:20:06 -0700894
Thomas Grafadaa70b2006-10-13 15:01:03 -0700895 if (saddr) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500896 memcpy(&fl6.saddr, saddr, sizeof(*saddr));
Thomas Grafadaa70b2006-10-13 15:01:03 -0700897 flags |= RT6_LOOKUP_F_HAS_SADDR;
898 }
899
David S. Miller4c9483b2011-03-12 16:22:43 -0500900 dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup);
Thomas Grafc71099a2006-08-04 23:20:06 -0700901 if (dst->error == 0)
902 return (struct rt6_info *) dst;
903
904 dst_release(dst);
905
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 return NULL;
907}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900908EXPORT_SYMBOL(rt6_lookup);
909
Thomas Grafc71099a2006-08-04 23:20:06 -0700910/* ip6_ins_rt is called with FREE table->tb6_lock.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 It takes new route entry, the addition fails by any reason the
912 route is freed. In any case, if caller does not hold it, it may
913 be destroyed.
914 */
915
Michal Kubečeke5fd3872014-03-27 13:04:08 +0100916static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info,
Florian Westphale715b6d2015-01-05 23:57:44 +0100917 struct mx6_config *mxc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918{
919 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -0700920 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921
Thomas Grafc71099a2006-08-04 23:20:06 -0700922 table = rt->rt6i_table;
923 write_lock_bh(&table->tb6_lock);
Florian Westphale715b6d2015-01-05 23:57:44 +0100924 err = fib6_add(&table->tb6_root, rt, info, mxc);
Thomas Grafc71099a2006-08-04 23:20:06 -0700925 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
927 return err;
928}
929
Thomas Graf40e22e82006-08-22 00:00:45 -0700930int ip6_ins_rt(struct rt6_info *rt)
931{
Florian Westphale715b6d2015-01-05 23:57:44 +0100932 struct nl_info info = { .nl_net = dev_net(rt->dst.dev), };
933 struct mx6_config mxc = { .mx = NULL, };
934
935 return __ip6_ins_rt(rt, &info, &mxc);
Thomas Graf40e22e82006-08-22 00:00:45 -0700936}
937
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700938static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort,
939 const struct in6_addr *daddr,
940 const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 struct rt6_info *rt;
943
944 /*
945 * Clone the route.
946 */
947
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700948 if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU))
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700949 ort = (struct rt6_info *)ort->dst.from;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
Martin KaFai Lauad706862015-08-14 11:05:52 -0700951 rt = __ip6_dst_alloc(dev_net(ort->dst.dev), ort->dst.dev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700953 if (!rt)
954 return NULL;
955
956 ip6_rt_copy_init(rt, ort);
957 rt->rt6i_flags |= RTF_CACHE;
958 rt->rt6i_metric = 0;
959 rt->dst.flags |= DST_HOST;
960 rt->rt6i_dst.addr = *daddr;
961 rt->rt6i_dst.plen = 128;
962
963 if (!rt6_is_gw_or_nonexthop(ort)) {
964 if (ort->rt6i_dst.plen != 128 &&
965 ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
966 rt->rt6i_flags |= RTF_ANYCAST;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700968 if (rt->rt6i_src.plen && saddr) {
969 rt->rt6i_src.addr = *saddr;
970 rt->rt6i_src.plen = 128;
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700971 }
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700972#endif
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800973 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800975 return rt;
976}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700978static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt)
979{
980 struct rt6_info *pcpu_rt;
981
982 pcpu_rt = __ip6_dst_alloc(dev_net(rt->dst.dev),
Martin KaFai Lauad706862015-08-14 11:05:52 -0700983 rt->dst.dev, rt->dst.flags);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700984
985 if (!pcpu_rt)
986 return NULL;
987 ip6_rt_copy_init(pcpu_rt, rt);
988 pcpu_rt->rt6i_protocol = rt->rt6i_protocol;
989 pcpu_rt->rt6i_flags |= RTF_PCPU;
990 return pcpu_rt;
991}
992
993/* It should be called with read_lock_bh(&tb6_lock) acquired */
994static struct rt6_info *rt6_get_pcpu_route(struct rt6_info *rt)
995{
996 struct rt6_info *pcpu_rt, *prev, **p;
997
998 p = this_cpu_ptr(rt->rt6i_pcpu);
999 pcpu_rt = *p;
1000
1001 if (pcpu_rt)
1002 goto done;
1003
1004 pcpu_rt = ip6_rt_pcpu_alloc(rt);
1005 if (!pcpu_rt) {
1006 struct net *net = dev_net(rt->dst.dev);
1007
1008 pcpu_rt = net->ipv6.ip6_null_entry;
1009 goto done;
1010 }
1011
1012 prev = cmpxchg(p, NULL, pcpu_rt);
1013 if (prev) {
1014 /* If someone did it before us, return prev instead */
1015 dst_destroy(&pcpu_rt->dst);
1016 pcpu_rt = prev;
1017 }
1018
1019done:
1020 dst_hold(&pcpu_rt->dst);
1021 rt6_dst_from_metrics_check(pcpu_rt);
1022 return pcpu_rt;
1023}
1024
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001025static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif,
David S. Miller4c9483b2011-03-12 16:22:43 -05001026 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027{
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001028 struct fib6_node *fn, *saved_fn;
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001029 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001030 int strict = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001032 strict |= flags & RT6_LOOKUP_F_IFACE;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001033 if (net->ipv6.devconf_all->forwarding == 0)
1034 strict |= RT6_LOOKUP_F_REACHABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035
Thomas Grafc71099a2006-08-04 23:20:06 -07001036 read_lock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037
David S. Miller4c9483b2011-03-12 16:22:43 -05001038 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001039 saved_fn = fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001041redo_rt6_select:
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001042 rt = rt6_select(fn, oif, strict);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +02001043 if (rt->rt6i_nsiblings)
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001044 rt = rt6_multipath_select(rt, fl6, oif, strict);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001045 if (rt == net->ipv6.ip6_null_entry) {
1046 fn = fib6_backtrack(fn, &fl6->saddr);
1047 if (fn)
1048 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001049 else if (strict & RT6_LOOKUP_F_REACHABLE) {
1050 /* also consider unreachable route */
1051 strict &= ~RT6_LOOKUP_F_REACHABLE;
1052 fn = saved_fn;
1053 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001054 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001055 }
1056
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -08001057
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001058 if (rt == net->ipv6.ip6_null_entry || (rt->rt6i_flags & RTF_CACHE)) {
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001059 dst_use(&rt->dst, jiffies);
1060 read_unlock_bh(&table->tb6_lock);
1061
1062 rt6_dst_from_metrics_check(rt);
1063 return rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001064 } else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) &&
1065 !(rt->rt6i_flags & RTF_GATEWAY))) {
1066 /* Create a RTF_CACHE clone which will not be
1067 * owned by the fib6 tree. It is for the special case where
1068 * the daddr in the skb during the neighbor look-up is different
1069 * from the fl6->daddr used to look-up route here.
1070 */
Thomas Grafc71099a2006-08-04 23:20:06 -07001071
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001072 struct rt6_info *uncached_rt;
1073
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001074 dst_use(&rt->dst, jiffies);
1075 read_unlock_bh(&table->tb6_lock);
1076
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001077 uncached_rt = ip6_rt_cache_alloc(rt, &fl6->daddr, NULL);
1078 dst_release(&rt->dst);
1079
1080 if (uncached_rt)
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07001081 rt6_uncached_list_add(uncached_rt);
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001082 else
1083 uncached_rt = net->ipv6.ip6_null_entry;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001084
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001085 dst_hold(&uncached_rt->dst);
1086 return uncached_rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001087
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001088 } else {
1089 /* Get a percpu copy */
1090
1091 struct rt6_info *pcpu_rt;
1092
1093 rt->dst.lastuse = jiffies;
1094 rt->dst.__use++;
1095 pcpu_rt = rt6_get_pcpu_route(rt);
1096 read_unlock_bh(&table->tb6_lock);
1097
1098 return pcpu_rt;
1099 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001100}
1101
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001102static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -05001103 struct flowi6 *fl6, int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001104{
David S. Miller4c9483b2011-03-12 16:22:43 -05001105 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001106}
1107
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001108static struct dst_entry *ip6_route_input_lookup(struct net *net,
1109 struct net_device *dev,
1110 struct flowi6 *fl6, int flags)
1111{
1112 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
1113 flags |= RT6_LOOKUP_F_IFACE;
1114
1115 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_input);
1116}
1117
Thomas Grafc71099a2006-08-04 23:20:06 -07001118void ip6_route_input(struct sk_buff *skb)
1119{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001120 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001121 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001122 int flags = RT6_LOOKUP_F_HAS_SADDR;
David S. Miller4c9483b2011-03-12 16:22:43 -05001123 struct flowi6 fl6 = {
1124 .flowi6_iif = skb->dev->ifindex,
1125 .daddr = iph->daddr,
1126 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001127 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -05001128 .flowi6_mark = skb->mark,
1129 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -07001130 };
Thomas Grafadaa70b2006-10-13 15:01:03 -07001131
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001132 skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -07001133}
1134
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001135static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -05001136 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07001137{
David S. Miller4c9483b2011-03-12 16:22:43 -05001138 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -07001139}
1140
Ian Morris67ba4152014-08-24 21:53:10 +01001141struct dst_entry *ip6_route_output(struct net *net, const struct sock *sk,
David S. Miller4c9483b2011-03-12 16:22:43 -05001142 struct flowi6 *fl6)
Thomas Grafc71099a2006-08-04 23:20:06 -07001143{
1144 int flags = 0;
1145
Pavel Emelyanov1fb94892012-08-08 21:53:36 +00001146 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +00001147
David S. Miller4c9483b2011-03-12 16:22:43 -05001148 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001149 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -07001150
David S. Miller4c9483b2011-03-12 16:22:43 -05001151 if (!ipv6_addr_any(&fl6->saddr))
Thomas Grafadaa70b2006-10-13 15:01:03 -07001152 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +00001153 else if (sk)
1154 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001155
David S. Miller4c9483b2011-03-12 16:22:43 -05001156 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +09001158EXPORT_SYMBOL(ip6_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159
David S. Miller2774c132011-03-01 14:59:04 -08001160struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -07001161{
David S. Miller5c1e6aa2011-04-28 14:13:38 -07001162 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
David S. Miller14e50e52007-05-24 18:17:54 -07001163 struct dst_entry *new = NULL;
1164
David S. Millerf5b0a872012-07-19 12:31:33 -07001165 rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, DST_OBSOLETE_NONE, 0);
David S. Miller14e50e52007-05-24 18:17:54 -07001166 if (rt) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001167 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -07001168
Steffen Klassert81048912012-07-05 23:37:09 +00001169 memset(new + 1, 0, sizeof(*rt) - sizeof(*new));
Steffen Klassert81048912012-07-05 23:37:09 +00001170
David S. Miller14e50e52007-05-24 18:17:54 -07001171 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08001172 new->input = dst_discard;
Eric Dumazetaad88722014-04-15 13:47:15 -04001173 new->output = dst_discard_sk;
David S. Miller14e50e52007-05-24 18:17:54 -07001174
Eric Dumazet21efcfa2011-07-19 20:18:36 +00001175 if (dst_metrics_read_only(&ort->dst))
1176 new->_metrics = ort->dst._metrics;
1177 else
1178 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07001179 rt->rt6i_idev = ort->rt6i_idev;
1180 if (rt->rt6i_idev)
1181 in6_dev_hold(rt->rt6i_idev);
David S. Miller14e50e52007-05-24 18:17:54 -07001182
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001183 rt->rt6i_gateway = ort->rt6i_gateway;
Gao feng1716a962012-04-06 00:13:10 +00001184 rt->rt6i_flags = ort->rt6i_flags;
David S. Miller14e50e52007-05-24 18:17:54 -07001185 rt->rt6i_metric = 0;
1186
1187 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
1188#ifdef CONFIG_IPV6_SUBTREES
1189 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1190#endif
1191
1192 dst_free(new);
1193 }
1194
David S. Miller69ead7a2011-03-01 14:45:33 -08001195 dst_release(dst_orig);
1196 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07001197}
David S. Miller14e50e52007-05-24 18:17:54 -07001198
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199/*
1200 * Destination cache support functions
1201 */
1202
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001203static void rt6_dst_from_metrics_check(struct rt6_info *rt)
1204{
1205 if (rt->dst.from &&
1206 dst_metrics_ptr(&rt->dst) != dst_metrics_ptr(rt->dst.from))
1207 dst_init_metrics(&rt->dst, dst_metrics_ptr(rt->dst.from), true);
1208}
1209
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001210static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie)
1211{
1212 if (!rt->rt6i_node || (rt->rt6i_node->fn_sernum != cookie))
1213 return NULL;
1214
1215 if (rt6_check_expired(rt))
1216 return NULL;
1217
1218 return &rt->dst;
1219}
1220
1221static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, u32 cookie)
1222{
1223 if (rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
1224 rt6_check((struct rt6_info *)(rt->dst.from), cookie))
1225 return &rt->dst;
1226 else
1227 return NULL;
1228}
1229
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
1231{
1232 struct rt6_info *rt;
1233
1234 rt = (struct rt6_info *) dst;
1235
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00001236 /* All IPV6 dsts are created with ->obsolete set to the value
1237 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
1238 * into this function always.
1239 */
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02001240
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001241 rt6_dst_from_metrics_check(rt);
1242
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001243 if ((rt->rt6i_flags & RTF_PCPU) || unlikely(dst->flags & DST_NOCACHE))
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001244 return rt6_dst_from_check(rt, cookie);
1245 else
1246 return rt6_check(rt, cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247}
1248
1249static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
1250{
1251 struct rt6_info *rt = (struct rt6_info *) dst;
1252
1253 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001254 if (rt->rt6i_flags & RTF_CACHE) {
1255 if (rt6_check_expired(rt)) {
1256 ip6_del_rt(rt);
1257 dst = NULL;
1258 }
1259 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001261 dst = NULL;
1262 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001264 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265}
1266
1267static void ip6_link_failure(struct sk_buff *skb)
1268{
1269 struct rt6_info *rt;
1270
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00001271 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272
Eric Dumazetadf30902009-06-02 05:19:30 +00001273 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 if (rt) {
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001275 if (rt->rt6i_flags & RTF_CACHE) {
1276 dst_hold(&rt->dst);
1277 if (ip6_del_rt(rt))
1278 dst_free(&rt->dst);
1279 } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 rt->rt6i_node->fn_sernum = -1;
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001281 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 }
1283}
1284
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001285static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
1286{
1287 struct net *net = dev_net(rt->dst.dev);
1288
1289 rt->rt6i_flags |= RTF_MODIFIED;
1290 rt->rt6i_pmtu = mtu;
1291 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
1292}
1293
1294static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
1295 const struct ipv6hdr *iph, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296{
Ian Morris67ba4152014-08-24 21:53:10 +01001297 struct rt6_info *rt6 = (struct rt6_info *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001299 if (rt6->rt6i_flags & RTF_LOCAL)
1300 return;
1301
David S. Miller81aded22012-06-15 14:54:11 -07001302 dst_confirm(dst);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001303 mtu = max_t(u32, mtu, IPV6_MIN_MTU);
1304 if (mtu >= dst_mtu(dst))
1305 return;
David S. Miller81aded22012-06-15 14:54:11 -07001306
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001307 if (rt6->rt6i_flags & RTF_CACHE) {
1308 rt6_do_update_pmtu(rt6, mtu);
1309 } else {
1310 const struct in6_addr *daddr, *saddr;
1311 struct rt6_info *nrt6;
Hagen Paul Pfeifer9d289712015-01-15 22:34:25 +01001312
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001313 if (iph) {
1314 daddr = &iph->daddr;
1315 saddr = &iph->saddr;
1316 } else if (sk) {
1317 daddr = &sk->sk_v6_daddr;
1318 saddr = &inet6_sk(sk)->saddr;
1319 } else {
1320 return;
1321 }
1322 nrt6 = ip6_rt_cache_alloc(rt6, daddr, saddr);
1323 if (nrt6) {
1324 rt6_do_update_pmtu(nrt6, mtu);
1325
1326 /* ip6_ins_rt(nrt6) will bump the
1327 * rt6->rt6i_node->fn_sernum
1328 * which will fail the next rt6_check() and
1329 * invalidate the sk->sk_dst_cache.
1330 */
1331 ip6_ins_rt(nrt6);
1332 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 }
1334}
1335
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001336static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
1337 struct sk_buff *skb, u32 mtu)
1338{
1339 __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu);
1340}
1341
David S. Miller42ae66c2012-06-15 20:01:57 -07001342void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
1343 int oif, u32 mark)
David S. Miller81aded22012-06-15 14:54:11 -07001344{
1345 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1346 struct dst_entry *dst;
1347 struct flowi6 fl6;
1348
1349 memset(&fl6, 0, sizeof(fl6));
1350 fl6.flowi6_oif = oif;
Lorenzo Colitti1b3c61d2014-05-13 10:17:34 -07001351 fl6.flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark);
David S. Miller81aded22012-06-15 14:54:11 -07001352 fl6.daddr = iph->daddr;
1353 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001354 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller81aded22012-06-15 14:54:11 -07001355
1356 dst = ip6_route_output(net, NULL, &fl6);
1357 if (!dst->error)
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001358 __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07001359 dst_release(dst);
1360}
1361EXPORT_SYMBOL_GPL(ip6_update_pmtu);
1362
1363void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
1364{
1365 ip6_update_pmtu(skb, sock_net(sk), mtu,
1366 sk->sk_bound_dev_if, sk->sk_mark);
1367}
1368EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
1369
Duan Jiongb55b76b2013-09-04 19:44:21 +08001370/* Handle redirects */
1371struct ip6rd_flowi {
1372 struct flowi6 fl6;
1373 struct in6_addr gateway;
1374};
1375
1376static struct rt6_info *__ip6_route_redirect(struct net *net,
1377 struct fib6_table *table,
1378 struct flowi6 *fl6,
1379 int flags)
1380{
1381 struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
1382 struct rt6_info *rt;
1383 struct fib6_node *fn;
1384
1385 /* Get the "current" route for this destination and
1386 * check if the redirect has come from approriate router.
1387 *
1388 * RFC 4861 specifies that redirects should only be
1389 * accepted if they come from the nexthop to the target.
1390 * Due to the way the routes are chosen, this notion
1391 * is a bit fuzzy and one might need to check all possible
1392 * routes.
1393 */
1394
1395 read_lock_bh(&table->tb6_lock);
1396 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
1397restart:
1398 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
1399 if (rt6_check_expired(rt))
1400 continue;
1401 if (rt->dst.error)
1402 break;
1403 if (!(rt->rt6i_flags & RTF_GATEWAY))
1404 continue;
1405 if (fl6->flowi6_oif != rt->dst.dev->ifindex)
1406 continue;
1407 if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway))
1408 continue;
1409 break;
1410 }
1411
1412 if (!rt)
1413 rt = net->ipv6.ip6_null_entry;
1414 else if (rt->dst.error) {
1415 rt = net->ipv6.ip6_null_entry;
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001416 goto out;
1417 }
1418
1419 if (rt == net->ipv6.ip6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001420 fn = fib6_backtrack(fn, &fl6->saddr);
1421 if (fn)
1422 goto restart;
Duan Jiongb55b76b2013-09-04 19:44:21 +08001423 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001424
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001425out:
Duan Jiongb55b76b2013-09-04 19:44:21 +08001426 dst_hold(&rt->dst);
1427
1428 read_unlock_bh(&table->tb6_lock);
1429
1430 return rt;
1431};
1432
1433static struct dst_entry *ip6_route_redirect(struct net *net,
1434 const struct flowi6 *fl6,
1435 const struct in6_addr *gateway)
1436{
1437 int flags = RT6_LOOKUP_F_HAS_SADDR;
1438 struct ip6rd_flowi rdfl;
1439
1440 rdfl.fl6 = *fl6;
1441 rdfl.gateway = *gateway;
1442
1443 return fib6_rule_lookup(net, &rdfl.fl6,
1444 flags, __ip6_route_redirect);
1445}
1446
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001447void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark)
1448{
1449 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1450 struct dst_entry *dst;
1451 struct flowi6 fl6;
1452
1453 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001454 fl6.flowi6_iif = LOOPBACK_IFINDEX;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001455 fl6.flowi6_oif = oif;
1456 fl6.flowi6_mark = mark;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001457 fl6.daddr = iph->daddr;
1458 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001459 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001460
Duan Jiongb55b76b2013-09-04 19:44:21 +08001461 dst = ip6_route_redirect(net, &fl6, &ipv6_hdr(skb)->saddr);
1462 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001463 dst_release(dst);
1464}
1465EXPORT_SYMBOL_GPL(ip6_redirect);
1466
Duan Jiongc92a59e2013-08-22 12:07:35 +08001467void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
1468 u32 mark)
1469{
1470 const struct ipv6hdr *iph = ipv6_hdr(skb);
1471 const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
1472 struct dst_entry *dst;
1473 struct flowi6 fl6;
1474
1475 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001476 fl6.flowi6_iif = LOOPBACK_IFINDEX;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001477 fl6.flowi6_oif = oif;
1478 fl6.flowi6_mark = mark;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001479 fl6.daddr = msg->dest;
1480 fl6.saddr = iph->daddr;
1481
Duan Jiongb55b76b2013-09-04 19:44:21 +08001482 dst = ip6_route_redirect(net, &fl6, &iph->saddr);
1483 rt6_do_redirect(dst, NULL, skb);
Duan Jiongc92a59e2013-08-22 12:07:35 +08001484 dst_release(dst);
1485}
1486
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001487void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
1488{
1489 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark);
1490}
1491EXPORT_SYMBOL_GPL(ip6_sk_redirect);
1492
David S. Miller0dbaee32010-12-13 12:52:14 -08001493static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494{
David S. Miller0dbaee32010-12-13 12:52:14 -08001495 struct net_device *dev = dst->dev;
1496 unsigned int mtu = dst_mtu(dst);
1497 struct net *net = dev_net(dev);
1498
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
1500
Daniel Lezcano55786892008-03-04 13:47:47 -08001501 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
1502 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503
1504 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001505 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
1506 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
1507 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 * rely only on pmtu discovery"
1509 */
1510 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
1511 mtu = IPV6_MAXPLEN;
1512 return mtu;
1513}
1514
Steffen Klassertebb762f2011-11-23 02:12:51 +00001515static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08001516{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001517 const struct rt6_info *rt = (const struct rt6_info *)dst;
1518 unsigned int mtu = rt->rt6i_pmtu;
David S. Millerd33e4552010-12-14 13:01:14 -08001519 struct inet6_dev *idev;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001520
1521 if (mtu)
Eric Dumazet30f78d82014-04-10 21:23:36 -07001522 goto out;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001523
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001524 mtu = dst_metric_raw(dst, RTAX_MTU);
1525 if (mtu)
1526 goto out;
1527
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001528 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08001529
1530 rcu_read_lock();
1531 idev = __in6_dev_get(dst->dev);
1532 if (idev)
1533 mtu = idev->cnf.mtu6;
1534 rcu_read_unlock();
1535
Eric Dumazet30f78d82014-04-10 21:23:36 -07001536out:
1537 return min_t(unsigned int, mtu, IP6_MAX_MTU);
David S. Millerd33e4552010-12-14 13:01:14 -08001538}
1539
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001540static struct dst_entry *icmp6_dst_gc_list;
1541static DEFINE_SPINLOCK(icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001542
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001543struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05001544 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545{
David S. Miller87a11572011-12-06 17:04:13 -05001546 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 struct rt6_info *rt;
1548 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001549 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550
David S. Miller38308472011-12-03 18:02:47 -05001551 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00001552 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553
Martin KaFai Lauad706862015-08-14 11:05:52 -07001554 rt = ip6_dst_alloc(net, dev, 0);
David S. Miller38308472011-12-03 18:02:47 -05001555 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05001557 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 goto out;
1559 }
1560
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001561 rt->dst.flags |= DST_HOST;
1562 rt->dst.output = ip6_output;
Changli Gaod8d1f302010-06-10 23:31:35 -07001563 atomic_set(&rt->dst.__refcnt, 1);
Julian Anastasov550bab42013-10-20 15:43:04 +03001564 rt->rt6i_gateway = fl6->daddr;
David S. Miller87a11572011-12-06 17:04:13 -05001565 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001566 rt->rt6i_dst.plen = 128;
1567 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08001568 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001570 spin_lock_bh(&icmp6_dst_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001571 rt->dst.next = icmp6_dst_gc_list;
1572 icmp6_dst_gc_list = &rt->dst;
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001573 spin_unlock_bh(&icmp6_dst_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
Daniel Lezcano55786892008-03-04 13:47:47 -08001575 fib6_force_start_gc(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576
David S. Miller87a11572011-12-06 17:04:13 -05001577 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
1578
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579out:
David S. Miller87a11572011-12-06 17:04:13 -05001580 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581}
1582
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001583int icmp6_dst_gc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584{
Hagen Paul Pfeifere9476e92011-02-25 05:45:19 +00001585 struct dst_entry *dst, **pprev;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001586 int more = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001588 spin_lock_bh(&icmp6_dst_lock);
1589 pprev = &icmp6_dst_gc_list;
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001590
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 while ((dst = *pprev) != NULL) {
1592 if (!atomic_read(&dst->__refcnt)) {
1593 *pprev = dst->next;
1594 dst_free(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 } else {
1596 pprev = &dst->next;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001597 ++more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 }
1599 }
1600
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001601 spin_unlock_bh(&icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001602
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001603 return more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604}
1605
David S. Miller1e493d12008-09-10 17:27:15 -07001606static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg),
1607 void *arg)
1608{
1609 struct dst_entry *dst, **pprev;
1610
1611 spin_lock_bh(&icmp6_dst_lock);
1612 pprev = &icmp6_dst_gc_list;
1613 while ((dst = *pprev) != NULL) {
1614 struct rt6_info *rt = (struct rt6_info *) dst;
1615 if (func(rt, arg)) {
1616 *pprev = dst->next;
1617 dst_free(dst);
1618 } else {
1619 pprev = &dst->next;
1620 }
1621 }
1622 spin_unlock_bh(&icmp6_dst_lock);
1623}
1624
Daniel Lezcano569d3642008-01-18 03:56:57 -08001625static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626{
Alexey Dobriyan86393e52009-08-29 01:34:49 +00001627 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08001628 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
1629 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
1630 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
1631 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
1632 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001633 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634
Eric Dumazetfc66f952010-10-08 06:37:34 +00001635 entries = dst_entries_get_fast(ops);
Michal Kubeček49a18d82013-08-01 10:04:24 +02001636 if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00001637 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 goto out;
1639
Benjamin Thery6891a342008-03-04 13:49:47 -08001640 net->ipv6.ip6_rt_gc_expire++;
Li RongQing14956642014-05-19 17:30:28 +08001641 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
Eric Dumazetfc66f952010-10-08 06:37:34 +00001642 entries = dst_entries_get_slow(ops);
1643 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08001644 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08001646 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001647 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648}
1649
Florian Westphale715b6d2015-01-05 23:57:44 +01001650static int ip6_convert_metrics(struct mx6_config *mxc,
1651 const struct fib6_config *cfg)
1652{
1653 struct nlattr *nla;
1654 int remaining;
1655 u32 *mp;
1656
Ian Morris63159f22015-03-29 14:00:04 +01001657 if (!cfg->fc_mx)
Florian Westphale715b6d2015-01-05 23:57:44 +01001658 return 0;
1659
1660 mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
1661 if (unlikely(!mp))
1662 return -ENOMEM;
1663
1664 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
1665 int type = nla_type(nla);
1666
1667 if (type) {
Daniel Borkmannea697632015-01-05 23:57:47 +01001668 u32 val;
1669
Florian Westphale715b6d2015-01-05 23:57:44 +01001670 if (unlikely(type > RTAX_MAX))
1671 goto err;
Daniel Borkmannea697632015-01-05 23:57:47 +01001672 if (type == RTAX_CC_ALGO) {
1673 char tmp[TCP_CA_NAME_MAX];
Florian Westphale715b6d2015-01-05 23:57:44 +01001674
Daniel Borkmannea697632015-01-05 23:57:47 +01001675 nla_strlcpy(tmp, nla, sizeof(tmp));
1676 val = tcp_ca_get_key_by_name(tmp);
1677 if (val == TCP_CA_UNSPEC)
1678 goto err;
1679 } else {
1680 val = nla_get_u32(nla);
1681 }
1682
1683 mp[type - 1] = val;
Florian Westphale715b6d2015-01-05 23:57:44 +01001684 __set_bit(type - 1, mxc->mx_valid);
1685 }
1686 }
1687
1688 mxc->mx = mp;
1689
1690 return 0;
1691 err:
1692 kfree(mp);
1693 return -EINVAL;
1694}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695
Thomas Graf86872cb2006-08-22 00:01:08 -07001696int ip6_route_add(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697{
1698 int err;
Daniel Lezcano55786892008-03-04 13:47:47 -08001699 struct net *net = cfg->fc_nlinfo.nl_net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 struct rt6_info *rt = NULL;
1701 struct net_device *dev = NULL;
1702 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001703 struct fib6_table *table;
Florian Westphale715b6d2015-01-05 23:57:44 +01001704 struct mx6_config mxc = { .mx = NULL, };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 int addr_type;
1706
Thomas Graf86872cb2006-08-22 00:01:08 -07001707 if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 return -EINVAL;
1709#ifndef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001710 if (cfg->fc_src_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 return -EINVAL;
1712#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07001713 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08001715 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 if (!dev)
1717 goto out;
1718 idev = in6_dev_get(dev);
1719 if (!idev)
1720 goto out;
1721 }
1722
Thomas Graf86872cb2006-08-22 00:01:08 -07001723 if (cfg->fc_metric == 0)
1724 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725
Matti Vaittinend71314b2011-11-14 00:14:49 +00001726 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05001727 if (cfg->fc_nlinfo.nlh &&
1728 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00001729 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001730 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00001731 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00001732 table = fib6_new_table(net, cfg->fc_table);
1733 }
1734 } else {
1735 table = fib6_new_table(net, cfg->fc_table);
1736 }
David S. Miller38308472011-12-03 18:02:47 -05001737
1738 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001739 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07001740
Martin KaFai Lauad706862015-08-14 11:05:52 -07001741 rt = ip6_dst_alloc(net, NULL,
1742 (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743
David S. Miller38308472011-12-03 18:02:47 -05001744 if (!rt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 err = -ENOMEM;
1746 goto out;
1747 }
1748
Gao feng1716a962012-04-06 00:13:10 +00001749 if (cfg->fc_flags & RTF_EXPIRES)
1750 rt6_set_expires(rt, jiffies +
1751 clock_t_to_jiffies(cfg->fc_expires));
1752 else
1753 rt6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754
Thomas Graf86872cb2006-08-22 00:01:08 -07001755 if (cfg->fc_protocol == RTPROT_UNSPEC)
1756 cfg->fc_protocol = RTPROT_BOOT;
1757 rt->rt6i_protocol = cfg->fc_protocol;
1758
1759 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760
1761 if (addr_type & IPV6_ADDR_MULTICAST)
Changli Gaod8d1f302010-06-10 23:31:35 -07001762 rt->dst.input = ip6_mc_input;
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00001763 else if (cfg->fc_flags & RTF_LOCAL)
1764 rt->dst.input = ip6_input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 else
Changli Gaod8d1f302010-06-10 23:31:35 -07001766 rt->dst.input = ip6_forward;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767
Changli Gaod8d1f302010-06-10 23:31:35 -07001768 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769
Thomas Graf86872cb2006-08-22 00:01:08 -07001770 ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
1771 rt->rt6i_dst.plen = cfg->fc_dst_len;
Martin KaFai Lauafc4eef2015-04-28 13:03:07 -07001772 if (rt->rt6i_dst.plen == 128)
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001773 rt->dst.flags |= DST_HOST;
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001774
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775#ifdef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001776 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
1777 rt->rt6i_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778#endif
1779
Thomas Graf86872cb2006-08-22 00:01:08 -07001780 rt->rt6i_metric = cfg->fc_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781
1782 /* We cannot add true routes via loopback here,
1783 they would result in kernel looping; promote them to reject routes
1784 */
Thomas Graf86872cb2006-08-22 00:01:08 -07001785 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05001786 (dev && (dev->flags & IFF_LOOPBACK) &&
1787 !(addr_type & IPV6_ADDR_LOOPBACK) &&
1788 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08001790 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 if (dev) {
1792 dev_put(dev);
1793 in6_dev_put(idev);
1794 }
Daniel Lezcano55786892008-03-04 13:47:47 -08001795 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 dev_hold(dev);
1797 idev = in6_dev_get(dev);
1798 if (!idev) {
1799 err = -ENODEV;
1800 goto out;
1801 }
1802 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001804 switch (cfg->fc_type) {
1805 case RTN_BLACKHOLE:
1806 rt->dst.error = -EINVAL;
Eric Dumazetaad88722014-04-15 13:47:15 -04001807 rt->dst.output = dst_discard_sk;
Kamala R7150aed2013-12-02 19:55:21 +05301808 rt->dst.input = dst_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001809 break;
1810 case RTN_PROHIBIT:
1811 rt->dst.error = -EACCES;
Kamala R7150aed2013-12-02 19:55:21 +05301812 rt->dst.output = ip6_pkt_prohibit_out;
1813 rt->dst.input = ip6_pkt_prohibit;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001814 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00001815 case RTN_THROW:
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001816 default:
Kamala R7150aed2013-12-02 19:55:21 +05301817 rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN
1818 : -ENETUNREACH;
1819 rt->dst.output = ip6_pkt_discard_out;
1820 rt->dst.input = ip6_pkt_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001821 break;
1822 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 goto install_route;
1824 }
1825
Thomas Graf86872cb2006-08-22 00:01:08 -07001826 if (cfg->fc_flags & RTF_GATEWAY) {
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001827 const struct in6_addr *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 int gwa_type;
1829
Thomas Graf86872cb2006-08-22 00:01:08 -07001830 gw_addr = &cfg->fc_gateway;
Florian Westphal330567b2015-08-07 10:54:28 +02001831 gwa_type = ipv6_addr_type(gw_addr);
Florian Westphal48ed7b22015-05-21 00:25:41 +02001832
1833 /* if gw_addr is local we will fail to detect this in case
1834 * address is still TENTATIVE (DAD in progress). rt6_lookup()
1835 * will return already-added prefix route via interface that
1836 * prefix route was assigned to, which might be non-loopback.
1837 */
1838 err = -EINVAL;
Florian Westphal330567b2015-08-07 10:54:28 +02001839 if (ipv6_chk_addr_and_flags(net, gw_addr,
1840 gwa_type & IPV6_ADDR_LINKLOCAL ?
1841 dev : NULL, 0, 0))
Florian Westphal48ed7b22015-05-21 00:25:41 +02001842 goto out;
1843
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001844 rt->rt6i_gateway = *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845
1846 if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
1847 struct rt6_info *grt;
1848
1849 /* IPv6 strictly inhibits using not link-local
1850 addresses as nexthop address.
1851 Otherwise, router will not able to send redirects.
1852 It is very good, but in some (rare!) circumstances
1853 (SIT, PtP, NBMA NOARP links) it is handy to allow
1854 some exceptions. --ANK
1855 */
David S. Miller38308472011-12-03 18:02:47 -05001856 if (!(gwa_type & IPV6_ADDR_UNICAST))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 goto out;
1858
Daniel Lezcano55786892008-03-04 13:47:47 -08001859 grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860
1861 err = -EHOSTUNREACH;
David S. Miller38308472011-12-03 18:02:47 -05001862 if (!grt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 goto out;
1864 if (dev) {
David S. Millerd1918542011-12-28 20:19:20 -05001865 if (dev != grt->dst.dev) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00001866 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 goto out;
1868 }
1869 } else {
David S. Millerd1918542011-12-28 20:19:20 -05001870 dev = grt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 idev = grt->rt6i_idev;
1872 dev_hold(dev);
1873 in6_dev_hold(grt->rt6i_idev);
1874 }
David S. Miller38308472011-12-03 18:02:47 -05001875 if (!(grt->rt6i_flags & RTF_GATEWAY))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 err = 0;
Amerigo Wang94e187c2012-10-29 00:13:19 +00001877 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878
1879 if (err)
1880 goto out;
1881 }
1882 err = -EINVAL;
David S. Miller38308472011-12-03 18:02:47 -05001883 if (!dev || (dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 goto out;
1885 }
1886
1887 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05001888 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 goto out;
1890
Daniel Walterc3968a82011-04-13 21:10:57 +00001891 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
1892 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
1893 err = -EINVAL;
1894 goto out;
1895 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001896 rt->rt6i_prefsrc.addr = cfg->fc_prefsrc;
Daniel Walterc3968a82011-04-13 21:10:57 +00001897 rt->rt6i_prefsrc.plen = 128;
1898 } else
1899 rt->rt6i_prefsrc.plen = 0;
1900
Thomas Graf86872cb2006-08-22 00:01:08 -07001901 rt->rt6i_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902
1903install_route:
Changli Gaod8d1f302010-06-10 23:31:35 -07001904 rt->dst.dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 rt->rt6i_idev = idev;
Thomas Grafc71099a2006-08-04 23:20:06 -07001906 rt->rt6i_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001907
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001908 cfg->fc_nlinfo.nl_net = dev_net(dev);
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001909
Florian Westphale715b6d2015-01-05 23:57:44 +01001910 err = ip6_convert_metrics(&mxc, cfg);
1911 if (err)
1912 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913
Florian Westphale715b6d2015-01-05 23:57:44 +01001914 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, &mxc);
1915
1916 kfree(mxc.mx);
1917 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918out:
1919 if (dev)
1920 dev_put(dev);
1921 if (idev)
1922 in6_dev_put(idev);
1923 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07001924 dst_free(&rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 return err;
1926}
1927
Thomas Graf86872cb2006-08-22 00:01:08 -07001928static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929{
1930 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07001931 struct fib6_table *table;
David S. Millerd1918542011-12-28 20:19:20 -05001932 struct net *net = dev_net(rt->dst.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933
Gao feng6825a262012-09-19 19:25:34 +00001934 if (rt == net->ipv6.ip6_null_entry) {
1935 err = -ENOENT;
1936 goto out;
1937 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07001938
Thomas Grafc71099a2006-08-04 23:20:06 -07001939 table = rt->rt6i_table;
1940 write_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07001941 err = fib6_del(rt, info);
Thomas Grafc71099a2006-08-04 23:20:06 -07001942 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943
Gao feng6825a262012-09-19 19:25:34 +00001944out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00001945 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 return err;
1947}
1948
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001949int ip6_del_rt(struct rt6_info *rt)
1950{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08001951 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -05001952 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08001953 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08001954 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001955}
1956
Thomas Graf86872cb2006-08-22 00:01:08 -07001957static int ip6_route_del(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958{
Thomas Grafc71099a2006-08-04 23:20:06 -07001959 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 struct fib6_node *fn;
1961 struct rt6_info *rt;
1962 int err = -ESRCH;
1963
Daniel Lezcano55786892008-03-04 13:47:47 -08001964 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001965 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001966 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967
Thomas Grafc71099a2006-08-04 23:20:06 -07001968 read_lock_bh(&table->tb6_lock);
1969
1970 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07001971 &cfg->fc_dst, cfg->fc_dst_len,
1972 &cfg->fc_src, cfg->fc_src_len);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001973
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 if (fn) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001975 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
Martin KaFai Lau1f56a012015-04-28 13:03:03 -07001976 if ((rt->rt6i_flags & RTF_CACHE) &&
1977 !(cfg->fc_flags & RTF_CACHE))
1978 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001979 if (cfg->fc_ifindex &&
David S. Millerd1918542011-12-28 20:19:20 -05001980 (!rt->dst.dev ||
1981 rt->dst.dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001983 if (cfg->fc_flags & RTF_GATEWAY &&
1984 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001986 if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07001988 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07001989 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990
Thomas Graf86872cb2006-08-22 00:01:08 -07001991 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 }
1993 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001994 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995
1996 return err;
1997}
1998
David S. Miller6700c272012-07-17 03:29:28 -07001999static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07002000{
David S. Millere8599ff2012-07-11 23:43:53 -07002001 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07002002 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07002003 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07002004 struct ndisc_options ndopts;
2005 struct inet6_dev *in6_dev;
2006 struct neighbour *neigh;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002007 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07002008 int optlen, on_link;
2009 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07002010
Simon Horman29a3cad2013-05-28 20:34:26 +00002011 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002012 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07002013
2014 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07002015 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002016 return;
2017 }
2018
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002019 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07002020
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002021 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07002022 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002023 return;
2024 }
2025
David S. Miller6e157b62012-07-12 00:05:02 -07002026 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002027 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07002028 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002029 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07002030 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07002031 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002032 return;
2033 }
2034
2035 in6_dev = __in6_dev_get(skb->dev);
2036 if (!in6_dev)
2037 return;
2038 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
2039 return;
2040
2041 /* RFC2461 8.1:
2042 * The IP source address of the Redirect MUST be the same as the current
2043 * first-hop router for the specified ICMP Destination Address.
2044 */
2045
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002046 if (!ndisc_parse_options(msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07002047 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
2048 return;
2049 }
David S. Miller6e157b62012-07-12 00:05:02 -07002050
2051 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07002052 if (ndopts.nd_opts_tgt_lladdr) {
2053 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
2054 skb->dev);
2055 if (!lladdr) {
2056 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
2057 return;
2058 }
2059 }
2060
David S. Miller6e157b62012-07-12 00:05:02 -07002061 rt = (struct rt6_info *) dst;
2062 if (rt == net->ipv6.ip6_null_entry) {
2063 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
2064 return;
2065 }
2066
2067 /* Redirect received -> path was valid.
2068 * Look, redirects are sent only in response to data packets,
2069 * so that this nexthop apparently is reachable. --ANK
2070 */
2071 dst_confirm(&rt->dst);
2072
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002073 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07002074 if (!neigh)
2075 return;
2076
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 /*
2078 * We have finally decided to accept it.
2079 */
2080
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002081 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 NEIGH_UPDATE_F_WEAK_OVERRIDE|
2083 NEIGH_UPDATE_F_OVERRIDE|
2084 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
2085 NEIGH_UPDATE_F_ISROUTER))
2086 );
2087
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002088 nrt = ip6_rt_cache_alloc(rt, &msg->dest, NULL);
David S. Miller38308472011-12-03 18:02:47 -05002089 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 goto out;
2091
2092 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
2093 if (on_link)
2094 nrt->rt6i_flags &= ~RTF_GATEWAY;
2095
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002096 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097
Thomas Graf40e22e82006-08-22 00:00:45 -07002098 if (ip6_ins_rt(nrt))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 goto out;
2100
Changli Gaod8d1f302010-06-10 23:31:35 -07002101 netevent.old = &rt->dst;
2102 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002103 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00002104 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07002105 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
2106
David S. Miller38308472011-12-03 18:02:47 -05002107 if (rt->rt6i_flags & RTF_CACHE) {
David S. Miller6e157b62012-07-12 00:05:02 -07002108 rt = (struct rt6_info *) dst_clone(&rt->dst);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002109 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 }
2111
2112out:
David S. Millere8599ff2012-07-11 23:43:53 -07002113 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07002114}
2115
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 * Misc support functions
2118 */
2119
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002120static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from)
2121{
2122 BUG_ON(from->dst.from);
2123
2124 rt->rt6i_flags &= ~RTF_EXPIRES;
2125 dst_hold(&from->dst);
2126 rt->dst.from = &from->dst;
2127 dst_init_metrics(&rt->dst, dst_metrics_ptr(&from->dst), true);
2128}
2129
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002130static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131{
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002132 rt->dst.input = ort->dst.input;
2133 rt->dst.output = ort->dst.output;
2134 rt->rt6i_dst = ort->rt6i_dst;
2135 rt->dst.error = ort->dst.error;
2136 rt->rt6i_idev = ort->rt6i_idev;
2137 if (rt->rt6i_idev)
2138 in6_dev_hold(rt->rt6i_idev);
2139 rt->dst.lastuse = jiffies;
2140 rt->rt6i_gateway = ort->rt6i_gateway;
2141 rt->rt6i_flags = ort->rt6i_flags;
2142 rt6_set_from(rt, ort);
2143 rt->rt6i_metric = ort->rt6i_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002145 rt->rt6i_src = ort->rt6i_src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146#endif
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002147 rt->rt6i_prefsrc = ort->rt6i_prefsrc;
2148 rt->rt6i_table = ort->rt6i_table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149}
2150
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002151#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002152static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002153 const struct in6_addr *prefix, int prefixlen,
2154 const struct in6_addr *gwaddr, int ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002155{
2156 struct fib6_node *fn;
2157 struct rt6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07002158 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002159
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002160 table = fib6_get_table(net, RT6_TABLE_INFO);
David S. Miller38308472011-12-03 18:02:47 -05002161 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002162 return NULL;
2163
Li RongQing5744dd92012-09-11 21:59:01 +00002164 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01002165 fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002166 if (!fn)
2167 goto out;
2168
Changli Gaod8d1f302010-06-10 23:31:35 -07002169 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05002170 if (rt->dst.dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002171 continue;
2172 if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
2173 continue;
2174 if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
2175 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07002176 dst_hold(&rt->dst);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002177 break;
2178 }
2179out:
Li RongQing5744dd92012-09-11 21:59:01 +00002180 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002181 return rt;
2182}
2183
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002184static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002185 const struct in6_addr *prefix, int prefixlen,
2186 const struct in6_addr *gwaddr, int ifindex,
Eric Dumazet95c96172012-04-15 05:58:06 +00002187 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002188{
Thomas Graf86872cb2006-08-22 00:01:08 -07002189 struct fib6_config cfg = {
2190 .fc_table = RT6_TABLE_INFO,
Rami Rosen238fc7e2008-02-09 23:43:11 -08002191 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07002192 .fc_ifindex = ifindex,
2193 .fc_dst_len = prefixlen,
2194 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
2195 RTF_UP | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00002196 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002197 .fc_nlinfo.nlh = NULL,
2198 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07002199 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002200
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002201 cfg.fc_dst = *prefix;
2202 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07002203
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08002204 /* We should treat it as a default route if prefix length is 0. */
2205 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07002206 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002207
Thomas Graf86872cb2006-08-22 00:01:08 -07002208 ip6_route_add(&cfg);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002209
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002210 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002211}
2212#endif
2213
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002214struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002215{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07002217 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002219 table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05002220 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002221 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222
Li RongQing5744dd92012-09-11 21:59:01 +00002223 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01002224 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05002225 if (dev == rt->dst.dev &&
YOSHIFUJI Hideaki045927f2006-03-20 17:00:48 -08002226 ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 ipv6_addr_equal(&rt->rt6i_gateway, addr))
2228 break;
2229 }
2230 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07002231 dst_hold(&rt->dst);
Li RongQing5744dd92012-09-11 21:59:01 +00002232 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 return rt;
2234}
2235
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002236struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08002237 struct net_device *dev,
2238 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239{
Thomas Graf86872cb2006-08-22 00:01:08 -07002240 struct fib6_config cfg = {
2241 .fc_table = RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08002242 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07002243 .fc_ifindex = dev->ifindex,
2244 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
2245 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00002246 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08002247 .fc_nlinfo.nlh = NULL,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002248 .fc_nlinfo.nl_net = dev_net(dev),
Thomas Graf86872cb2006-08-22 00:01:08 -07002249 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002251 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252
Thomas Graf86872cb2006-08-22 00:01:08 -07002253 ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 return rt6_get_dflt_router(gwaddr, dev);
2256}
2257
Daniel Lezcano7b4da532008-03-04 13:47:14 -08002258void rt6_purge_dflt_routers(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259{
2260 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07002261 struct fib6_table *table;
2262
2263 /* NOTE: Keep consistent with rt6_get_dflt_router */
Daniel Lezcano7b4da532008-03-04 13:47:14 -08002264 table = fib6_get_table(net, RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05002265 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002266 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267
2268restart:
Thomas Grafc71099a2006-08-04 23:20:06 -07002269 read_lock_bh(&table->tb6_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07002270 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
Lorenzo Colitti3e8b0ac2013-03-03 20:46:46 +00002271 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
2272 (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002273 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07002274 read_unlock_bh(&table->tb6_lock);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002275 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 goto restart;
2277 }
2278 }
Thomas Grafc71099a2006-08-04 23:20:06 -07002279 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280}
2281
Daniel Lezcano55786892008-03-04 13:47:47 -08002282static void rtmsg_to_fib6_config(struct net *net,
2283 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07002284 struct fib6_config *cfg)
2285{
2286 memset(cfg, 0, sizeof(*cfg));
2287
2288 cfg->fc_table = RT6_TABLE_MAIN;
2289 cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
2290 cfg->fc_metric = rtmsg->rtmsg_metric;
2291 cfg->fc_expires = rtmsg->rtmsg_info;
2292 cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
2293 cfg->fc_src_len = rtmsg->rtmsg_src_len;
2294 cfg->fc_flags = rtmsg->rtmsg_flags;
2295
Daniel Lezcano55786892008-03-04 13:47:47 -08002296 cfg->fc_nlinfo.nl_net = net;
Benjamin Theryf1243c22008-02-26 18:10:03 -08002297
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002298 cfg->fc_dst = rtmsg->rtmsg_dst;
2299 cfg->fc_src = rtmsg->rtmsg_src;
2300 cfg->fc_gateway = rtmsg->rtmsg_gateway;
Thomas Graf86872cb2006-08-22 00:01:08 -07002301}
2302
Daniel Lezcano55786892008-03-04 13:47:47 -08002303int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304{
Thomas Graf86872cb2006-08-22 00:01:08 -07002305 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 struct in6_rtmsg rtmsg;
2307 int err;
2308
Ian Morris67ba4152014-08-24 21:53:10 +01002309 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 case SIOCADDRT: /* Add a route */
2311 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00002312 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 return -EPERM;
2314 err = copy_from_user(&rtmsg, arg,
2315 sizeof(struct in6_rtmsg));
2316 if (err)
2317 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07002318
Daniel Lezcano55786892008-03-04 13:47:47 -08002319 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07002320
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 rtnl_lock();
2322 switch (cmd) {
2323 case SIOCADDRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07002324 err = ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 break;
2326 case SIOCDELRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07002327 err = ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 break;
2329 default:
2330 err = -EINVAL;
2331 }
2332 rtnl_unlock();
2333
2334 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07002335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336
2337 return -EINVAL;
2338}
2339
2340/*
2341 * Drop the packet on the floor
2342 */
2343
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07002344static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002346 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00002347 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002348 switch (ipstats_mib_noroutes) {
2349 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07002350 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00002351 if (type == IPV6_ADDR_ANY) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002352 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2353 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002354 break;
2355 }
2356 /* FALLTHROUGH */
2357 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002358 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2359 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002360 break;
2361 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002362 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 kfree_skb(skb);
2364 return 0;
2365}
2366
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002367static int ip6_pkt_discard(struct sk_buff *skb)
2368{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002369 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002370}
2371
Eric Dumazetaad88722014-04-15 13:47:15 -04002372static int ip6_pkt_discard_out(struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373{
Eric Dumazetadf30902009-06-02 05:19:30 +00002374 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002375 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376}
2377
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002378static int ip6_pkt_prohibit(struct sk_buff *skb)
2379{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002380 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002381}
2382
Eric Dumazetaad88722014-04-15 13:47:15 -04002383static int ip6_pkt_prohibit_out(struct sock *sk, struct sk_buff *skb)
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002384{
Eric Dumazetadf30902009-06-02 05:19:30 +00002385 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002386 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002387}
2388
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389/*
2390 * Allocate a dst for local (unicast / anycast) address.
2391 */
2392
2393struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
2394 const struct in6_addr *addr,
David S. Miller8f031512011-12-06 16:48:14 -05002395 bool anycast)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002397 struct net *net = dev_net(idev->dev);
Hannes Frederic Sowaa3300ef2013-12-07 03:33:45 +01002398 struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev,
Martin KaFai Lauad706862015-08-14 11:05:52 -07002399 DST_NOCOUNT);
Hannes Frederic Sowaa3300ef2013-12-07 03:33:45 +01002400 if (!rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 return ERR_PTR(-ENOMEM);
2402
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 in6_dev_hold(idev);
2404
David S. Miller11d53b42011-06-24 15:23:34 -07002405 rt->dst.flags |= DST_HOST;
Changli Gaod8d1f302010-06-10 23:31:35 -07002406 rt->dst.input = ip6_input;
2407 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 rt->rt6i_idev = idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409
2410 rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +09002411 if (anycast)
2412 rt->rt6i_flags |= RTF_ANYCAST;
2413 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 rt->rt6i_flags |= RTF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415
Julian Anastasov550bab42013-10-20 15:43:04 +03002416 rt->rt6i_gateway = *addr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002417 rt->rt6i_dst.addr = *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 rt->rt6i_dst.plen = 128;
Daniel Lezcano55786892008-03-04 13:47:47 -08002419 rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420
Changli Gaod8d1f302010-06-10 23:31:35 -07002421 atomic_set(&rt->dst.__refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422
2423 return rt;
2424}
2425
Daniel Walterc3968a82011-04-13 21:10:57 +00002426int ip6_route_get_saddr(struct net *net,
2427 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002428 const struct in6_addr *daddr,
Daniel Walterc3968a82011-04-13 21:10:57 +00002429 unsigned int prefs,
2430 struct in6_addr *saddr)
2431{
Markus Stenberge16e8882015-05-05 13:36:59 +03002432 struct inet6_dev *idev =
2433 rt ? ip6_dst_idev((struct dst_entry *)rt) : NULL;
Daniel Walterc3968a82011-04-13 21:10:57 +00002434 int err = 0;
Markus Stenberge16e8882015-05-05 13:36:59 +03002435 if (rt && rt->rt6i_prefsrc.plen)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002436 *saddr = rt->rt6i_prefsrc.addr;
Daniel Walterc3968a82011-04-13 21:10:57 +00002437 else
2438 err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
2439 daddr, prefs, saddr);
2440 return err;
2441}
2442
2443/* remove deleted ip from prefsrc entries */
2444struct arg_dev_net_ip {
2445 struct net_device *dev;
2446 struct net *net;
2447 struct in6_addr *addr;
2448};
2449
2450static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
2451{
2452 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
2453 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
2454 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
2455
David S. Millerd1918542011-12-28 20:19:20 -05002456 if (((void *)rt->dst.dev == dev || !dev) &&
Daniel Walterc3968a82011-04-13 21:10:57 +00002457 rt != net->ipv6.ip6_null_entry &&
2458 ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
2459 /* remove prefsrc entry */
2460 rt->rt6i_prefsrc.plen = 0;
2461 }
2462 return 0;
2463}
2464
2465void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
2466{
2467 struct net *net = dev_net(ifp->idev->dev);
2468 struct arg_dev_net_ip adni = {
2469 .dev = ifp->idev->dev,
2470 .net = net,
2471 .addr = &ifp->addr,
2472 };
Li RongQing0c3584d2013-12-27 16:32:38 +08002473 fib6_clean_all(net, fib6_remove_prefsrc, &adni);
Daniel Walterc3968a82011-04-13 21:10:57 +00002474}
2475
Duan Jiongbe7a0102014-05-15 15:56:14 +08002476#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY)
2477#define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE)
2478
2479/* Remove routers and update dst entries when gateway turn into host. */
2480static int fib6_clean_tohost(struct rt6_info *rt, void *arg)
2481{
2482 struct in6_addr *gateway = (struct in6_addr *)arg;
2483
2484 if ((((rt->rt6i_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) ||
2485 ((rt->rt6i_flags & RTF_CACHE_GATEWAY) == RTF_CACHE_GATEWAY)) &&
2486 ipv6_addr_equal(gateway, &rt->rt6i_gateway)) {
2487 return -1;
2488 }
2489 return 0;
2490}
2491
2492void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
2493{
2494 fib6_clean_all(net, fib6_clean_tohost, gateway);
2495}
2496
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002497struct arg_dev_net {
2498 struct net_device *dev;
2499 struct net *net;
2500};
2501
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502static int fib6_ifdown(struct rt6_info *rt, void *arg)
2503{
stephen hemmingerbc3ef662010-12-16 17:42:40 +00002504 const struct arg_dev_net *adn = arg;
2505 const struct net_device *dev = adn->dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002506
David S. Millerd1918542011-12-28 20:19:20 -05002507 if ((rt->dst.dev == dev || !dev) &&
David S. Millerc159d302011-12-26 15:24:36 -05002508 rt != adn->net->ipv6.ip6_null_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 return -1;
David S. Millerc159d302011-12-26 15:24:36 -05002510
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 return 0;
2512}
2513
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002514void rt6_ifdown(struct net *net, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002516 struct arg_dev_net adn = {
2517 .dev = dev,
2518 .net = net,
2519 };
2520
Li RongQing0c3584d2013-12-27 16:32:38 +08002521 fib6_clean_all(net, fib6_ifdown, &adn);
David S. Miller1e493d12008-09-10 17:27:15 -07002522 icmp6_clean_all(fib6_ifdown, &adn);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07002523 rt6_uncached_list_flush_dev(net, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524}
2525
Eric Dumazet95c96172012-04-15 05:58:06 +00002526struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00002528 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529};
2530
2531static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
2532{
2533 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
2534 struct inet6_dev *idev;
2535
2536 /* In IPv6 pmtu discovery is not optional,
2537 so that RTAX_MTU lock cannot disable it.
2538 We still use this lock to block changes
2539 caused by addrconf/ndisc.
2540 */
2541
2542 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05002543 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 return 0;
2545
2546 /* For administrative MTU increase, there is no way to discover
2547 IPv6 PMTU increase, so PMTU increase should be updated here.
2548 Since RFC 1981 doesn't include administrative MTU increase
2549 update PMTU increase is a MUST. (i.e. jumbo frame)
2550 */
2551 /*
2552 If new MTU is less than route PMTU, this new MTU will be the
2553 lowest MTU in the path, update the route PMTU to reflect PMTU
2554 decreases; if new MTU is greater than route PMTU, and the
2555 old MTU is the lowest MTU in the path, update the route PMTU
2556 to reflect the increase. In this case if the other nodes' MTU
2557 also have the lowest MTU, TOO BIG MESSAGE will be lead to
2558 PMTU discouvery.
2559 */
David S. Millerd1918542011-12-28 20:19:20 -05002560 if (rt->dst.dev == arg->dev &&
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002561 !dst_metric_locked(&rt->dst, RTAX_MTU)) {
2562 if (rt->rt6i_flags & RTF_CACHE) {
2563 /* For RTF_CACHE with rt6i_pmtu == 0
2564 * (i.e. a redirected route),
2565 * the metrics of its rt->dst.from has already
2566 * been updated.
2567 */
2568 if (rt->rt6i_pmtu && rt->rt6i_pmtu > arg->mtu)
2569 rt->rt6i_pmtu = arg->mtu;
2570 } else if (dst_mtu(&rt->dst) >= arg->mtu ||
2571 (dst_mtu(&rt->dst) < arg->mtu &&
2572 dst_mtu(&rt->dst) == idev->cnf.mtu6)) {
2573 dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu);
2574 }
Simon Arlott566cfd82007-07-26 00:09:55 -07002575 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 return 0;
2577}
2578
Eric Dumazet95c96172012-04-15 05:58:06 +00002579void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580{
Thomas Grafc71099a2006-08-04 23:20:06 -07002581 struct rt6_mtu_change_arg arg = {
2582 .dev = dev,
2583 .mtu = mtu,
2584 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585
Li RongQing0c3584d2013-12-27 16:32:38 +08002586 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587}
2588
Patrick McHardyef7c79e2007-06-05 12:38:30 -07002589static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07002590 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07002591 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07002592 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002593 [RTA_PRIORITY] = { .type = NLA_U32 },
2594 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002595 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002596 [RTA_PREF] = { .type = NLA_U8 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002597};
2598
2599static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
2600 struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601{
Thomas Graf86872cb2006-08-22 00:01:08 -07002602 struct rtmsg *rtm;
2603 struct nlattr *tb[RTA_MAX+1];
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002604 unsigned int pref;
Thomas Graf86872cb2006-08-22 00:01:08 -07002605 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606
Thomas Graf86872cb2006-08-22 00:01:08 -07002607 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2608 if (err < 0)
2609 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610
Thomas Graf86872cb2006-08-22 00:01:08 -07002611 err = -EINVAL;
2612 rtm = nlmsg_data(nlh);
2613 memset(cfg, 0, sizeof(*cfg));
2614
2615 cfg->fc_table = rtm->rtm_table;
2616 cfg->fc_dst_len = rtm->rtm_dst_len;
2617 cfg->fc_src_len = rtm->rtm_src_len;
2618 cfg->fc_flags = RTF_UP;
2619 cfg->fc_protocol = rtm->rtm_protocol;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002620 cfg->fc_type = rtm->rtm_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07002621
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002622 if (rtm->rtm_type == RTN_UNREACHABLE ||
2623 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002624 rtm->rtm_type == RTN_PROHIBIT ||
2625 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07002626 cfg->fc_flags |= RTF_REJECT;
2627
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002628 if (rtm->rtm_type == RTN_LOCAL)
2629 cfg->fc_flags |= RTF_LOCAL;
2630
Martin KaFai Lau1f56a012015-04-28 13:03:03 -07002631 if (rtm->rtm_flags & RTM_F_CLONED)
2632 cfg->fc_flags |= RTF_CACHE;
2633
Eric W. Biederman15e47302012-09-07 20:12:54 +00002634 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
Thomas Graf86872cb2006-08-22 00:01:08 -07002635 cfg->fc_nlinfo.nlh = nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002636 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
Thomas Graf86872cb2006-08-22 00:01:08 -07002637
2638 if (tb[RTA_GATEWAY]) {
Jiri Benc67b61f62015-03-29 16:59:26 +02002639 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
Thomas Graf86872cb2006-08-22 00:01:08 -07002640 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002642
2643 if (tb[RTA_DST]) {
2644 int plen = (rtm->rtm_dst_len + 7) >> 3;
2645
2646 if (nla_len(tb[RTA_DST]) < plen)
2647 goto errout;
2648
2649 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002651
2652 if (tb[RTA_SRC]) {
2653 int plen = (rtm->rtm_src_len + 7) >> 3;
2654
2655 if (nla_len(tb[RTA_SRC]) < plen)
2656 goto errout;
2657
2658 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002660
Daniel Walterc3968a82011-04-13 21:10:57 +00002661 if (tb[RTA_PREFSRC])
Jiri Benc67b61f62015-03-29 16:59:26 +02002662 cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]);
Daniel Walterc3968a82011-04-13 21:10:57 +00002663
Thomas Graf86872cb2006-08-22 00:01:08 -07002664 if (tb[RTA_OIF])
2665 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
2666
2667 if (tb[RTA_PRIORITY])
2668 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
2669
2670 if (tb[RTA_METRICS]) {
2671 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
2672 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002674
2675 if (tb[RTA_TABLE])
2676 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
2677
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002678 if (tb[RTA_MULTIPATH]) {
2679 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
2680 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
2681 }
2682
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002683 if (tb[RTA_PREF]) {
2684 pref = nla_get_u8(tb[RTA_PREF]);
2685 if (pref != ICMPV6_ROUTER_PREF_LOW &&
2686 pref != ICMPV6_ROUTER_PREF_HIGH)
2687 pref = ICMPV6_ROUTER_PREF_MEDIUM;
2688 cfg->fc_flags |= RTF_PREF(pref);
2689 }
2690
Thomas Graf86872cb2006-08-22 00:01:08 -07002691 err = 0;
2692errout:
2693 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694}
2695
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002696static int ip6_route_multipath(struct fib6_config *cfg, int add)
2697{
2698 struct fib6_config r_cfg;
2699 struct rtnexthop *rtnh;
2700 int remaining;
2701 int attrlen;
2702 int err = 0, last_err = 0;
2703
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02002704 remaining = cfg->fc_mp_len;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002705beginning:
2706 rtnh = (struct rtnexthop *)cfg->fc_mp;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002707
2708 /* Parse a Multipath Entry */
2709 while (rtnh_ok(rtnh, remaining)) {
2710 memcpy(&r_cfg, cfg, sizeof(*cfg));
2711 if (rtnh->rtnh_ifindex)
2712 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
2713
2714 attrlen = rtnh_attrlen(rtnh);
2715 if (attrlen > 0) {
2716 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
2717
2718 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
2719 if (nla) {
Jiri Benc67b61f62015-03-29 16:59:26 +02002720 r_cfg.fc_gateway = nla_get_in6_addr(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002721 r_cfg.fc_flags |= RTF_GATEWAY;
2722 }
2723 }
2724 err = add ? ip6_route_add(&r_cfg) : ip6_route_del(&r_cfg);
2725 if (err) {
2726 last_err = err;
2727 /* If we are trying to remove a route, do not stop the
2728 * loop when ip6_route_del() fails (because next hop is
2729 * already gone), we should try to remove all next hops.
2730 */
2731 if (add) {
2732 /* If add fails, we should try to delete all
2733 * next hops that have been already added.
2734 */
2735 add = 0;
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02002736 remaining = cfg->fc_mp_len - remaining;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002737 goto beginning;
2738 }
2739 }
Nicolas Dichtel1a724182012-11-01 22:58:22 +00002740 /* Because each route is added like a single route we remove
Michal Kubeček27596472015-05-18 20:54:00 +02002741 * these flags after the first nexthop: if there is a collision,
2742 * we have already failed to add the first nexthop:
2743 * fib6_add_rt2node() has rejected it; when replacing, old
2744 * nexthops have been replaced by first new, the rest should
2745 * be added to it.
Nicolas Dichtel1a724182012-11-01 22:58:22 +00002746 */
Michal Kubeček27596472015-05-18 20:54:00 +02002747 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
2748 NLM_F_REPLACE);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002749 rtnh = rtnh_next(rtnh, &remaining);
2750 }
2751
2752 return last_err;
2753}
2754
Ian Morris67ba4152014-08-24 21:53:10 +01002755static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756{
Thomas Graf86872cb2006-08-22 00:01:08 -07002757 struct fib6_config cfg;
2758 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759
Thomas Graf86872cb2006-08-22 00:01:08 -07002760 err = rtm_to_fib6_config(skb, nlh, &cfg);
2761 if (err < 0)
2762 return err;
2763
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002764 if (cfg.fc_mp)
2765 return ip6_route_multipath(&cfg, 0);
2766 else
2767 return ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768}
2769
Ian Morris67ba4152014-08-24 21:53:10 +01002770static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771{
Thomas Graf86872cb2006-08-22 00:01:08 -07002772 struct fib6_config cfg;
2773 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774
Thomas Graf86872cb2006-08-22 00:01:08 -07002775 err = rtm_to_fib6_config(skb, nlh, &cfg);
2776 if (err < 0)
2777 return err;
2778
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002779 if (cfg.fc_mp)
2780 return ip6_route_multipath(&cfg, 1);
2781 else
2782 return ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783}
2784
Thomas Graf339bf982006-11-10 14:10:15 -08002785static inline size_t rt6_nlmsg_size(void)
2786{
2787 return NLMSG_ALIGN(sizeof(struct rtmsg))
2788 + nla_total_size(16) /* RTA_SRC */
2789 + nla_total_size(16) /* RTA_DST */
2790 + nla_total_size(16) /* RTA_GATEWAY */
2791 + nla_total_size(16) /* RTA_PREFSRC */
2792 + nla_total_size(4) /* RTA_TABLE */
2793 + nla_total_size(4) /* RTA_IIF */
2794 + nla_total_size(4) /* RTA_OIF */
2795 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08002796 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Daniel Borkmannea697632015-01-05 23:57:47 +01002797 + nla_total_size(sizeof(struct rta_cacheinfo))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002798 + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
2799 + nla_total_size(1); /* RTA_PREF */
Thomas Graf339bf982006-11-10 14:10:15 -08002800}
2801
Brian Haley191cd582008-08-14 15:33:21 -07002802static int rt6_fill_node(struct net *net,
2803 struct sk_buff *skb, struct rt6_info *rt,
Jamal Hadi Salim0d51aa82005-06-21 13:51:04 -07002804 struct in6_addr *dst, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002805 int iif, int type, u32 portid, u32 seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002806 int prefix, int nowait, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002808 u32 metrics[RTAX_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 struct rtmsg *rtm;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002810 struct nlmsghdr *nlh;
Thomas Grafe3703b32006-11-27 09:27:07 -08002811 long expires;
Patrick McHardy9e762a42006-08-10 23:09:48 -07002812 u32 table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813
2814 if (prefix) { /* user wants prefix routes only */
2815 if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
2816 /* success since this is not a prefix route */
2817 return 1;
2818 }
2819 }
2820
Eric W. Biederman15e47302012-09-07 20:12:54 +00002821 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05002822 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08002823 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002824
2825 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 rtm->rtm_family = AF_INET6;
2827 rtm->rtm_dst_len = rt->rt6i_dst.plen;
2828 rtm->rtm_src_len = rt->rt6i_src.plen;
2829 rtm->rtm_tos = 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07002830 if (rt->rt6i_table)
Patrick McHardy9e762a42006-08-10 23:09:48 -07002831 table = rt->rt6i_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07002832 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07002833 table = RT6_TABLE_UNSPEC;
2834 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04002835 if (nla_put_u32(skb, RTA_TABLE, table))
2836 goto nla_put_failure;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002837 if (rt->rt6i_flags & RTF_REJECT) {
2838 switch (rt->dst.error) {
2839 case -EINVAL:
2840 rtm->rtm_type = RTN_BLACKHOLE;
2841 break;
2842 case -EACCES:
2843 rtm->rtm_type = RTN_PROHIBIT;
2844 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002845 case -EAGAIN:
2846 rtm->rtm_type = RTN_THROW;
2847 break;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002848 default:
2849 rtm->rtm_type = RTN_UNREACHABLE;
2850 break;
2851 }
2852 }
David S. Miller38308472011-12-03 18:02:47 -05002853 else if (rt->rt6i_flags & RTF_LOCAL)
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002854 rtm->rtm_type = RTN_LOCAL;
David S. Millerd1918542011-12-28 20:19:20 -05002855 else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 rtm->rtm_type = RTN_LOCAL;
2857 else
2858 rtm->rtm_type = RTN_UNICAST;
2859 rtm->rtm_flags = 0;
2860 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
2861 rtm->rtm_protocol = rt->rt6i_protocol;
David S. Miller38308472011-12-03 18:02:47 -05002862 if (rt->rt6i_flags & RTF_DYNAMIC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 rtm->rtm_protocol = RTPROT_REDIRECT;
Denis Ovsienkof0396f602012-07-10 04:45:50 +00002864 else if (rt->rt6i_flags & RTF_ADDRCONF) {
2865 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ROUTEINFO))
2866 rtm->rtm_protocol = RTPROT_RA;
2867 else
2868 rtm->rtm_protocol = RTPROT_KERNEL;
2869 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870
David S. Miller38308472011-12-03 18:02:47 -05002871 if (rt->rt6i_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 rtm->rtm_flags |= RTM_F_CLONED;
2873
2874 if (dst) {
Jiri Benc930345e2015-03-29 16:59:25 +02002875 if (nla_put_in6_addr(skb, RTA_DST, dst))
David S. Millerc78679e2012-04-01 20:27:33 -04002876 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002877 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 } else if (rtm->rtm_dst_len)
Jiri Benc930345e2015-03-29 16:59:25 +02002879 if (nla_put_in6_addr(skb, RTA_DST, &rt->rt6i_dst.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04002880 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881#ifdef CONFIG_IPV6_SUBTREES
2882 if (src) {
Jiri Benc930345e2015-03-29 16:59:25 +02002883 if (nla_put_in6_addr(skb, RTA_SRC, src))
David S. Millerc78679e2012-04-01 20:27:33 -04002884 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002885 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04002886 } else if (rtm->rtm_src_len &&
Jiri Benc930345e2015-03-29 16:59:25 +02002887 nla_put_in6_addr(skb, RTA_SRC, &rt->rt6i_src.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04002888 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002890 if (iif) {
2891#ifdef CONFIG_IPV6_MROUTE
2892 if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
Benjamin Thery8229efd2008-12-10 16:30:15 -08002893 int err = ip6mr_get_route(net, skb, rtm, nowait);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002894 if (err <= 0) {
2895 if (!nowait) {
2896 if (err == 0)
2897 return 0;
2898 goto nla_put_failure;
2899 } else {
2900 if (err == -EMSGSIZE)
2901 goto nla_put_failure;
2902 }
2903 }
2904 } else
2905#endif
David S. Millerc78679e2012-04-01 20:27:33 -04002906 if (nla_put_u32(skb, RTA_IIF, iif))
2907 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002908 } else if (dst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 struct in6_addr saddr_buf;
David S. Millerc78679e2012-04-01 20:27:33 -04002910 if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0 &&
Jiri Benc930345e2015-03-29 16:59:25 +02002911 nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04002912 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07002914
Daniel Walterc3968a82011-04-13 21:10:57 +00002915 if (rt->rt6i_prefsrc.plen) {
2916 struct in6_addr saddr_buf;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002917 saddr_buf = rt->rt6i_prefsrc.addr;
Jiri Benc930345e2015-03-29 16:59:25 +02002918 if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04002919 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00002920 }
2921
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002922 memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics));
2923 if (rt->rt6i_pmtu)
2924 metrics[RTAX_MTU - 1] = rt->rt6i_pmtu;
2925 if (rtnetlink_put_metrics(skb, metrics) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07002926 goto nla_put_failure;
2927
YOSHIFUJI Hideaki / 吉藤英明dd0cbf22013-01-17 12:53:15 +00002928 if (rt->rt6i_flags & RTF_GATEWAY) {
Jiri Benc930345e2015-03-29 16:59:25 +02002929 if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->rt6i_gateway) < 0)
Eric Dumazet94f826b2012-03-27 09:53:52 +00002930 goto nla_put_failure;
Eric Dumazet94f826b2012-03-27 09:53:52 +00002931 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07002932
David S. Millerc78679e2012-04-01 20:27:33 -04002933 if (rt->dst.dev &&
2934 nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex))
2935 goto nla_put_failure;
2936 if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric))
2937 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00002938
2939 expires = (rt->rt6i_flags & RTF_EXPIRES) ? rt->dst.expires - jiffies : 0;
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07002940
David S. Miller87a50692012-07-10 05:06:14 -07002941 if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, rt->dst.error) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08002942 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002944 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags)))
2945 goto nla_put_failure;
2946
Johannes Berg053c0952015-01-16 22:09:00 +01002947 nlmsg_end(skb, nlh);
2948 return 0;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002949
2950nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002951 nlmsg_cancel(skb, nlh);
2952 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953}
2954
Patrick McHardy1b43af52006-08-10 23:11:17 -07002955int rt6_dump_route(struct rt6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956{
2957 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
2958 int prefix;
2959
Thomas Graf2d7202b2006-08-22 00:01:27 -07002960 if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
2961 struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0;
2963 } else
2964 prefix = 0;
2965
Brian Haley191cd582008-08-14 15:33:21 -07002966 return rt6_fill_node(arg->net,
2967 arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002968 NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002969 prefix, 0, NLM_F_MULTI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970}
2971
Ian Morris67ba4152014-08-24 21:53:10 +01002972static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002974 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07002975 struct nlattr *tb[RTA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07002977 struct sk_buff *skb;
2978 struct rtmsg *rtm;
David S. Miller4c9483b2011-03-12 16:22:43 -05002979 struct flowi6 fl6;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002980 int err, iif = 0, oif = 0;
Thomas Grafab364a62006-08-22 00:01:47 -07002981
2982 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2983 if (err < 0)
2984 goto errout;
2985
2986 err = -EINVAL;
David S. Miller4c9483b2011-03-12 16:22:43 -05002987 memset(&fl6, 0, sizeof(fl6));
Thomas Grafab364a62006-08-22 00:01:47 -07002988
2989 if (tb[RTA_SRC]) {
2990 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
2991 goto errout;
2992
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002993 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07002994 }
2995
2996 if (tb[RTA_DST]) {
2997 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
2998 goto errout;
2999
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003000 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07003001 }
3002
3003 if (tb[RTA_IIF])
3004 iif = nla_get_u32(tb[RTA_IIF]);
3005
3006 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003007 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07003008
Lorenzo Colitti2e47b292014-05-15 16:38:41 -07003009 if (tb[RTA_MARK])
3010 fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
3011
Thomas Grafab364a62006-08-22 00:01:47 -07003012 if (iif) {
3013 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003014 int flags = 0;
3015
Daniel Lezcano55786892008-03-04 13:47:47 -08003016 dev = __dev_get_by_index(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07003017 if (!dev) {
3018 err = -ENODEV;
3019 goto errout;
3020 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003021
3022 fl6.flowi6_iif = iif;
3023
3024 if (!ipv6_addr_any(&fl6.saddr))
3025 flags |= RT6_LOOKUP_F_HAS_SADDR;
3026
3027 rt = (struct rt6_info *)ip6_route_input_lookup(net, dev, &fl6,
3028 flags);
3029 } else {
3030 fl6.flowi6_oif = oif;
3031
3032 rt = (struct rt6_info *)ip6_route_output(net, NULL, &fl6);
Thomas Grafab364a62006-08-22 00:01:47 -07003033 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034
3035 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05003036 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00003037 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07003038 err = -ENOBUFS;
3039 goto errout;
3040 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041
3042 /* Reserve room for dummy headers, this skb can pass
3043 through good chunk of routing engine.
3044 */
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07003045 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
3047
Changli Gaod8d1f302010-06-10 23:31:35 -07003048 skb_dst_set(skb, &rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049
David S. Miller4c9483b2011-03-12 16:22:43 -05003050 err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003051 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003052 nlh->nlmsg_seq, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07003054 kfree_skb(skb);
3055 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 }
3057
Eric W. Biederman15e47302012-09-07 20:12:54 +00003058 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07003059errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061}
3062
Thomas Graf86872cb2006-08-22 00:01:08 -07003063void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064{
3065 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08003066 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003067 u32 seq;
3068 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003070 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05003071 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07003072
Thomas Graf339bf982006-11-10 14:10:15 -08003073 skb = nlmsg_new(rt6_nlmsg_size(), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05003074 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07003075 goto errout;
3076
Brian Haley191cd582008-08-14 15:33:21 -07003077 err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003078 event, info->portid, seq, 0, 0, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08003079 if (err < 0) {
3080 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
3081 WARN_ON(err == -EMSGSIZE);
3082 kfree_skb(skb);
3083 goto errout;
3084 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00003085 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08003086 info->nlh, gfp_any());
3087 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07003088errout:
3089 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08003090 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091}
3092
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003093static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00003094 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003095{
Jiri Pirko351638e2013-05-28 01:30:21 +00003096 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09003097 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003098
3099 if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07003100 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003101 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
3102#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07003103 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003104 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07003105 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003106 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
3107#endif
3108 }
3109
3110 return NOTIFY_OK;
3111}
3112
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113/*
3114 * /proc
3115 */
3116
3117#ifdef CONFIG_PROC_FS
3118
Alexey Dobriyan33120b32007-11-06 05:27:11 -08003119static const struct file_operations ipv6_route_proc_fops = {
3120 .owner = THIS_MODULE,
3121 .open = ipv6_route_open,
3122 .read = seq_read,
3123 .llseek = seq_lseek,
Hannes Frederic Sowa8d2ca1d2013-09-21 16:55:59 +02003124 .release = seq_release_net,
Alexey Dobriyan33120b32007-11-06 05:27:11 -08003125};
3126
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127static int rt6_stats_seq_show(struct seq_file *seq, void *v)
3128{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003129 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003131 net->ipv6.rt6_stats->fib_nodes,
3132 net->ipv6.rt6_stats->fib_route_nodes,
3133 net->ipv6.rt6_stats->fib_rt_alloc,
3134 net->ipv6.rt6_stats->fib_rt_entries,
3135 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00003136 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003137 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138
3139 return 0;
3140}
3141
3142static int rt6_stats_seq_open(struct inode *inode, struct file *file)
3143{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07003144 return single_open_net(inode, file, rt6_stats_seq_show);
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003145}
3146
Arjan van de Ven9a321442007-02-12 00:55:35 -08003147static const struct file_operations rt6_stats_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148 .owner = THIS_MODULE,
3149 .open = rt6_stats_seq_open,
3150 .read = seq_read,
3151 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07003152 .release = single_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153};
3154#endif /* CONFIG_PROC_FS */
3155
3156#ifdef CONFIG_SYSCTL
3157
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158static
Joe Perchesfe2c6332013-06-11 23:04:25 -07003159int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 void __user *buffer, size_t *lenp, loff_t *ppos)
3161{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003162 struct net *net;
3163 int delay;
3164 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003166
3167 net = (struct net *)ctl->extra1;
3168 delay = net->ipv6.sysctl.flush_delay;
3169 proc_dointvec(ctl, write, buffer, lenp, ppos);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02003170 fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003171 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172}
3173
Joe Perchesfe2c6332013-06-11 23:04:25 -07003174struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003175 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08003177 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07003179 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003180 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 },
3182 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003184 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 .maxlen = sizeof(int),
3186 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003187 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 },
3189 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08003191 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 .maxlen = sizeof(int),
3193 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003194 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 },
3196 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08003198 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 .maxlen = sizeof(int),
3200 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003201 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202 },
3203 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08003205 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206 .maxlen = sizeof(int),
3207 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003208 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209 },
3210 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08003212 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 .maxlen = sizeof(int),
3214 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003215 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216 },
3217 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08003219 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220 .maxlen = sizeof(int),
3221 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003222 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223 },
3224 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08003226 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227 .maxlen = sizeof(int),
3228 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003229 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 },
3231 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08003233 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 .maxlen = sizeof(int),
3235 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003236 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 },
3238 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08003240 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 .maxlen = sizeof(int),
3242 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003243 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08003245 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246};
3247
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003248struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003249{
3250 struct ctl_table *table;
3251
3252 table = kmemdup(ipv6_route_table_template,
3253 sizeof(ipv6_route_table_template),
3254 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003255
3256 if (table) {
3257 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003258 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003259 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003260 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
3261 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
3262 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
3263 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
3264 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
3265 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
3266 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08003267 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
Eric W. Biederman464dc802012-11-16 03:02:59 +00003268
3269 /* Don't export sysctls to unprivileged users */
3270 if (net->user_ns != &init_user_ns)
3271 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003272 }
3273
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003274 return table;
3275}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276#endif
3277
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003278static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003279{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07003280 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003281
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003282 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
3283 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003284
Eric Dumazetfc66f952010-10-08 06:37:34 +00003285 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
3286 goto out_ip6_dst_ops;
3287
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003288 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
3289 sizeof(*net->ipv6.ip6_null_entry),
3290 GFP_KERNEL);
3291 if (!net->ipv6.ip6_null_entry)
Eric Dumazetfc66f952010-10-08 06:37:34 +00003292 goto out_ip6_dst_entries;
Changli Gaod8d1f302010-06-10 23:31:35 -07003293 net->ipv6.ip6_null_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003294 (struct dst_entry *)net->ipv6.ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003295 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003296 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
3297 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003298
3299#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3300 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
3301 sizeof(*net->ipv6.ip6_prohibit_entry),
3302 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003303 if (!net->ipv6.ip6_prohibit_entry)
3304 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003305 net->ipv6.ip6_prohibit_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003306 (struct dst_entry *)net->ipv6.ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003307 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003308 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
3309 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003310
3311 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
3312 sizeof(*net->ipv6.ip6_blk_hole_entry),
3313 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003314 if (!net->ipv6.ip6_blk_hole_entry)
3315 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003316 net->ipv6.ip6_blk_hole_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003317 (struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003318 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003319 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
3320 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003321#endif
3322
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07003323 net->ipv6.sysctl.flush_delay = 0;
3324 net->ipv6.sysctl.ip6_rt_max_size = 4096;
3325 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
3326 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
3327 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
3328 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
3329 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
3330 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
3331
Benjamin Thery6891a342008-03-04 13:49:47 -08003332 net->ipv6.ip6_rt_gc_expire = 30*HZ;
3333
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003334 ret = 0;
3335out:
3336 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003337
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003338#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3339out_ip6_prohibit_entry:
3340 kfree(net->ipv6.ip6_prohibit_entry);
3341out_ip6_null_entry:
3342 kfree(net->ipv6.ip6_null_entry);
3343#endif
Eric Dumazetfc66f952010-10-08 06:37:34 +00003344out_ip6_dst_entries:
3345 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003346out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003347 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003348}
3349
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003350static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003351{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003352 kfree(net->ipv6.ip6_null_entry);
3353#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3354 kfree(net->ipv6.ip6_prohibit_entry);
3355 kfree(net->ipv6.ip6_blk_hole_entry);
3356#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003357 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003358}
3359
Thomas Grafd1896342012-06-18 12:08:33 +00003360static int __net_init ip6_route_net_init_late(struct net *net)
3361{
3362#ifdef CONFIG_PROC_FS
Gao fengd4beaa62013-02-18 01:34:54 +00003363 proc_create("ipv6_route", 0, net->proc_net, &ipv6_route_proc_fops);
3364 proc_create("rt6_stats", S_IRUGO, net->proc_net, &rt6_stats_seq_fops);
Thomas Grafd1896342012-06-18 12:08:33 +00003365#endif
3366 return 0;
3367}
3368
3369static void __net_exit ip6_route_net_exit_late(struct net *net)
3370{
3371#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00003372 remove_proc_entry("ipv6_route", net->proc_net);
3373 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00003374#endif
3375}
3376
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003377static struct pernet_operations ip6_route_net_ops = {
3378 .init = ip6_route_net_init,
3379 .exit = ip6_route_net_exit,
3380};
3381
David S. Millerc3426b42012-06-09 16:27:05 -07003382static int __net_init ipv6_inetpeer_init(struct net *net)
3383{
3384 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
3385
3386 if (!bp)
3387 return -ENOMEM;
3388 inet_peer_base_init(bp);
3389 net->ipv6.peers = bp;
3390 return 0;
3391}
3392
3393static void __net_exit ipv6_inetpeer_exit(struct net *net)
3394{
3395 struct inet_peer_base *bp = net->ipv6.peers;
3396
3397 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07003398 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07003399 kfree(bp);
3400}
3401
David S. Miller2b823f72012-06-09 19:00:16 -07003402static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07003403 .init = ipv6_inetpeer_init,
3404 .exit = ipv6_inetpeer_exit,
3405};
3406
Thomas Grafd1896342012-06-18 12:08:33 +00003407static struct pernet_operations ip6_route_net_late_ops = {
3408 .init = ip6_route_net_init_late,
3409 .exit = ip6_route_net_exit_late,
3410};
3411
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003412static struct notifier_block ip6_route_dev_notifier = {
3413 .notifier_call = ip6_route_dev_notify,
3414 .priority = 0,
3415};
3416
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003417int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003419 int ret;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07003420 int cpu;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003421
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003422 ret = -ENOMEM;
3423 ip6_dst_ops_template.kmem_cachep =
3424 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
3425 SLAB_HWCACHE_ALIGN, NULL);
3426 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08003427 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07003428
Eric Dumazetfc66f952010-10-08 06:37:34 +00003429 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003430 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003431 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003432
David S. Millerc3426b42012-06-09 16:27:05 -07003433 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
3434 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003435 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00003436
David S. Miller7e52b332012-06-15 15:51:55 -07003437 ret = register_pernet_subsys(&ip6_route_net_ops);
3438 if (ret)
3439 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07003440
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07003441 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
3442
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003443 /* Registering of the loopback is done before this portion of code,
3444 * the loopback reference in rt6_info will not be taken, do it
3445 * manually for init_net */
Changli Gaod8d1f302010-06-10 23:31:35 -07003446 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003447 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3448 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07003449 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003450 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07003451 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003452 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3453 #endif
David S. Millere8803b62012-06-16 01:12:19 -07003454 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003455 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003456 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003457
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003458 ret = xfrm6_init();
3459 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003460 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08003461
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003462 ret = fib6_rules_init();
3463 if (ret)
3464 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08003465
Thomas Grafd1896342012-06-18 12:08:33 +00003466 ret = register_pernet_subsys(&ip6_route_net_late_ops);
3467 if (ret)
3468 goto fib6_rules_init;
3469
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003470 ret = -ENOBUFS;
Greg Rosec7ac8672011-06-10 01:27:09 +00003471 if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) ||
3472 __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) ||
3473 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL))
Thomas Grafd1896342012-06-18 12:08:33 +00003474 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003475
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003476 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003477 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00003478 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003479
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07003480 for_each_possible_cpu(cpu) {
3481 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
3482
3483 INIT_LIST_HEAD(&ul->head);
3484 spin_lock_init(&ul->lock);
3485 }
3486
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003487out:
3488 return ret;
3489
Thomas Grafd1896342012-06-18 12:08:33 +00003490out_register_late_subsys:
3491 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003492fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003493 fib6_rules_cleanup();
3494xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003495 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00003496out_fib6_init:
3497 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003498out_register_subsys:
3499 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07003500out_register_inetpeer:
3501 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00003502out_dst_entries:
3503 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003504out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003505 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003506 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507}
3508
3509void ip6_route_cleanup(void)
3510{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003511 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00003512 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07003513 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07003516 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003517 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003518 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003519 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520}