blob: 94ce1e0b5a33ce151f18e847dbec025a31886de1 [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
Gao feng1716a962012-04-06 00:13:10 +000075static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
Eric Dumazet21efcfa2011-07-19 20:18:36 +000076 const struct in6_addr *dest);
Linus Torvalds1da177e2005-04-16 15:20:36 -070077static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
David S. Miller0dbaee32010-12-13 12:52:14 -080078static unsigned int ip6_default_advmss(const struct dst_entry *dst);
Steffen Klassertebb762f2011-11-23 02:12:51 +000079static unsigned int ip6_mtu(const struct dst_entry *dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080static struct dst_entry *ip6_negative_advice(struct dst_entry *);
81static void ip6_dst_destroy(struct dst_entry *);
82static void ip6_dst_ifdown(struct dst_entry *,
83 struct net_device *dev, int how);
Daniel Lezcano569d3642008-01-18 03:56:57 -080084static int ip6_dst_gc(struct dst_ops *ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
86static int ip6_pkt_discard(struct sk_buff *skb);
Eric Dumazetaad88722014-04-15 13:47:15 -040087static int ip6_pkt_discard_out(struct sock *sk, struct sk_buff *skb);
Kamala R7150aed2013-12-02 19:55:21 +053088static int ip6_pkt_prohibit(struct sk_buff *skb);
Eric Dumazetaad88722014-04-15 13:47:15 -040089static int ip6_pkt_prohibit_out(struct sock *sk, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070090static void ip6_link_failure(struct sk_buff *skb);
David S. Miller6700c272012-07-17 03:29:28 -070091static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
92 struct sk_buff *skb, u32 mtu);
93static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
94 struct sk_buff *skb);
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -070095static void rt6_dst_from_metrics_check(struct rt6_info *rt);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +020096static int rt6_score_route(struct rt6_info *rt, int oif, int strict);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -080098#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -080099static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000100 const struct in6_addr *prefix, int prefixlen,
101 const struct in6_addr *gwaddr, int ifindex,
Eric Dumazet95c96172012-04-15 05:58:06 +0000102 unsigned int pref);
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800103static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000104 const struct in6_addr *prefix, int prefixlen,
105 const struct in6_addr *gwaddr, int ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800106#endif
107
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700108struct uncached_list {
109 spinlock_t lock;
110 struct list_head head;
111};
112
113static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list);
114
115static void rt6_uncached_list_add(struct rt6_info *rt)
116{
117 struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);
118
119 rt->dst.flags |= DST_NOCACHE;
120 rt->rt6i_uncached_list = ul;
121
122 spin_lock_bh(&ul->lock);
123 list_add_tail(&rt->rt6i_uncached, &ul->head);
124 spin_unlock_bh(&ul->lock);
125}
126
127static void rt6_uncached_list_del(struct rt6_info *rt)
128{
129 if (!list_empty(&rt->rt6i_uncached)) {
130 struct uncached_list *ul = rt->rt6i_uncached_list;
131
132 spin_lock_bh(&ul->lock);
133 list_del(&rt->rt6i_uncached);
134 spin_unlock_bh(&ul->lock);
135 }
136}
137
138static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev)
139{
140 struct net_device *loopback_dev = net->loopback_dev;
141 int cpu;
142
143 for_each_possible_cpu(cpu) {
144 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
145 struct rt6_info *rt;
146
147 spin_lock_bh(&ul->lock);
148 list_for_each_entry(rt, &ul->head, rt6i_uncached) {
149 struct inet6_dev *rt_idev = rt->rt6i_idev;
150 struct net_device *rt_dev = rt->dst.dev;
151
152 if (rt_idev && (rt_idev->dev == dev || !dev) &&
153 rt_idev->dev != loopback_dev) {
154 rt->rt6i_idev = in6_dev_get(loopback_dev);
155 in6_dev_put(rt_idev);
156 }
157
158 if (rt_dev && (rt_dev == dev || !dev) &&
159 rt_dev != loopback_dev) {
160 rt->dst.dev = loopback_dev;
161 dev_hold(rt->dst.dev);
162 dev_put(rt_dev);
163 }
164 }
165 spin_unlock_bh(&ul->lock);
166 }
167}
168
David S. Miller06582542011-01-27 14:58:42 -0800169static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
170{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700171 struct rt6_info *rt = (struct rt6_info *)dst;
David S. Miller06582542011-01-27 14:58:42 -0800172
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700173 if (rt->rt6i_flags & RTF_CACHE)
174 return NULL;
175 else
Martin KaFai Lau3b471172015-02-12 16:14:08 -0800176 return dst_cow_metrics_generic(dst, old);
David S. Miller06582542011-01-27 14:58:42 -0800177}
178
David S. Millerf894cbf2012-07-02 21:52:24 -0700179static inline const void *choose_neigh_daddr(struct rt6_info *rt,
180 struct sk_buff *skb,
181 const void *daddr)
David S. Miller39232972012-01-26 15:22:32 -0500182{
183 struct in6_addr *p = &rt->rt6i_gateway;
184
David S. Millera7563f32012-01-26 16:29:16 -0500185 if (!ipv6_addr_any(p))
David S. Miller39232972012-01-26 15:22:32 -0500186 return (const void *) p;
David S. Millerf894cbf2012-07-02 21:52:24 -0700187 else if (skb)
188 return &ipv6_hdr(skb)->daddr;
David S. Miller39232972012-01-26 15:22:32 -0500189 return daddr;
190}
191
David S. Millerf894cbf2012-07-02 21:52:24 -0700192static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst,
193 struct sk_buff *skb,
194 const void *daddr)
David S. Millerd3aaeb32011-07-18 00:40:17 -0700195{
David S. Miller39232972012-01-26 15:22:32 -0500196 struct rt6_info *rt = (struct rt6_info *) dst;
197 struct neighbour *n;
198
David S. Millerf894cbf2012-07-02 21:52:24 -0700199 daddr = choose_neigh_daddr(rt, skb, daddr);
YOSHIFUJI Hideaki / 吉藤英明8e022ee2013-01-17 12:53:09 +0000200 n = __ipv6_neigh_lookup(dst->dev, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500201 if (n)
202 return n;
203 return neigh_create(&nd_tbl, daddr, dst->dev);
204}
205
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -0800206static struct dst_ops ip6_dst_ops_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 .family = AF_INET6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 .gc = ip6_dst_gc,
209 .gc_thresh = 1024,
210 .check = ip6_dst_check,
David S. Miller0dbaee32010-12-13 12:52:14 -0800211 .default_advmss = ip6_default_advmss,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000212 .mtu = ip6_mtu,
David S. Miller06582542011-01-27 14:58:42 -0800213 .cow_metrics = ipv6_cow_metrics,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 .destroy = ip6_dst_destroy,
215 .ifdown = ip6_dst_ifdown,
216 .negative_advice = ip6_negative_advice,
217 .link_failure = ip6_link_failure,
218 .update_pmtu = ip6_rt_update_pmtu,
David S. Miller6e157b62012-07-12 00:05:02 -0700219 .redirect = rt6_do_redirect,
Herbert Xu1ac06e02008-05-20 14:32:14 -0700220 .local_out = __ip6_local_out,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700221 .neigh_lookup = ip6_neigh_lookup,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222};
223
Steffen Klassertebb762f2011-11-23 02:12:51 +0000224static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
Roland Dreierec831ea2011-01-31 13:16:00 -0800225{
Steffen Klassert618f9bc2011-11-23 02:13:31 +0000226 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
227
228 return mtu ? : dst->dev->mtu;
Roland Dreierec831ea2011-01-31 13:16:00 -0800229}
230
David S. Miller6700c272012-07-17 03:29:28 -0700231static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
232 struct sk_buff *skb, u32 mtu)
David S. Miller14e50e52007-05-24 18:17:54 -0700233{
234}
235
David S. Miller6700c272012-07-17 03:29:28 -0700236static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
237 struct sk_buff *skb)
David S. Millerb587ee32012-07-12 00:39:24 -0700238{
239}
240
Held Bernhard0972ddb2011-04-24 22:07:32 +0000241static u32 *ip6_rt_blackhole_cow_metrics(struct dst_entry *dst,
242 unsigned long old)
243{
244 return NULL;
245}
246
David S. Miller14e50e52007-05-24 18:17:54 -0700247static struct dst_ops ip6_dst_blackhole_ops = {
248 .family = AF_INET6,
David S. Miller14e50e52007-05-24 18:17:54 -0700249 .destroy = ip6_dst_destroy,
250 .check = ip6_dst_check,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000251 .mtu = ip6_blackhole_mtu,
Eric Dumazet214f45c2011-02-18 11:39:01 -0800252 .default_advmss = ip6_default_advmss,
David S. Miller14e50e52007-05-24 18:17:54 -0700253 .update_pmtu = ip6_rt_blackhole_update_pmtu,
David S. Millerb587ee32012-07-12 00:39:24 -0700254 .redirect = ip6_rt_blackhole_redirect,
Held Bernhard0972ddb2011-04-24 22:07:32 +0000255 .cow_metrics = ip6_rt_blackhole_cow_metrics,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700256 .neigh_lookup = ip6_neigh_lookup,
David S. Miller14e50e52007-05-24 18:17:54 -0700257};
258
David S. Miller62fa8a82011-01-26 20:51:05 -0800259static const u32 ip6_template_metrics[RTAX_MAX] = {
Li RongQing14edd872012-10-24 14:01:18 +0800260 [RTAX_HOPLIMIT - 1] = 0,
David S. Miller62fa8a82011-01-26 20:51:05 -0800261};
262
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000263static const struct rt6_info ip6_null_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700264 .dst = {
265 .__refcnt = ATOMIC_INIT(1),
266 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000267 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700268 .error = -ENETUNREACH,
Changli Gaod8d1f302010-06-10 23:31:35 -0700269 .input = ip6_pkt_discard,
270 .output = ip6_pkt_discard_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 },
272 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700273 .rt6i_protocol = RTPROT_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 .rt6i_metric = ~(u32) 0,
275 .rt6i_ref = ATOMIC_INIT(1),
276};
277
Thomas Graf101367c2006-08-04 03:39:02 -0700278#ifdef CONFIG_IPV6_MULTIPLE_TABLES
279
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000280static const struct rt6_info ip6_prohibit_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700281 .dst = {
282 .__refcnt = ATOMIC_INIT(1),
283 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000284 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700285 .error = -EACCES,
Changli Gaod8d1f302010-06-10 23:31:35 -0700286 .input = ip6_pkt_prohibit,
287 .output = ip6_pkt_prohibit_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700288 },
289 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700290 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700291 .rt6i_metric = ~(u32) 0,
292 .rt6i_ref = ATOMIC_INIT(1),
293};
294
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000295static const struct rt6_info ip6_blk_hole_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700296 .dst = {
297 .__refcnt = ATOMIC_INIT(1),
298 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000299 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700300 .error = -EINVAL,
Changli Gaod8d1f302010-06-10 23:31:35 -0700301 .input = dst_discard,
Eric Dumazetaad88722014-04-15 13:47:15 -0400302 .output = dst_discard_sk,
Thomas Graf101367c2006-08-04 03:39:02 -0700303 },
304 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700305 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700306 .rt6i_metric = ~(u32) 0,
307 .rt6i_ref = ATOMIC_INIT(1),
308};
309
310#endif
311
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312/* allocate dst with ip6_dst_ops */
David S. Miller97bab732012-06-09 22:36:36 -0700313static inline struct rt6_info *ip6_dst_alloc(struct net *net,
David S. Miller957c6652011-06-24 15:25:00 -0700314 struct net_device *dev,
David S. Miller8b96d222012-06-11 02:01:56 -0700315 int flags,
316 struct fib6_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317{
David S. Miller97bab732012-06-09 22:36:36 -0700318 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +0000319 0, DST_OBSOLETE_FORCE_CHK, flags);
David S. Millercf911662011-04-28 14:31:47 -0700320
David S. Miller97bab732012-06-09 22:36:36 -0700321 if (rt) {
Steffen Klassert81048912012-07-05 23:37:09 +0000322 struct dst_entry *dst = &rt->dst;
323
324 memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000325 INIT_LIST_HEAD(&rt->rt6i_siblings);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700326 INIT_LIST_HEAD(&rt->rt6i_uncached);
David S. Miller97bab732012-06-09 22:36:36 -0700327 }
David S. Millercf911662011-04-28 14:31:47 -0700328 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329}
330
331static void ip6_dst_destroy(struct dst_entry *dst)
332{
333 struct rt6_info *rt = (struct rt6_info *)dst;
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000334 struct dst_entry *from = dst->from;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700335 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700337 dst_destroy_metrics_generic(dst);
Yan, Zheng8e2ec632011-09-05 21:34:30 +0000338
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700339 rt6_uncached_list_del(rt);
340
341 idev = rt->rt6i_idev;
David S. Miller38308472011-12-03 18:02:47 -0500342 if (idev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 rt->rt6i_idev = NULL;
344 in6_dev_put(idev);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900345 }
Gao feng1716a962012-04-06 00:13:10 +0000346
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000347 dst->from = NULL;
348 dst_release(from);
David S. Millerb3419362010-11-30 12:27:11 -0800349}
350
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
352 int how)
353{
354 struct rt6_info *rt = (struct rt6_info *)dst;
355 struct inet6_dev *idev = rt->rt6i_idev;
Denis V. Lunev5a3e55d2007-12-07 00:38:10 -0800356 struct net_device *loopback_dev =
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900357 dev_net(dev)->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
David S. Miller97cac082012-07-02 22:43:47 -0700359 if (dev != loopback_dev) {
360 if (idev && idev->dev == dev) {
361 struct inet6_dev *loopback_idev =
362 in6_dev_get(loopback_dev);
363 if (loopback_idev) {
364 rt->rt6i_idev = loopback_idev;
365 in6_dev_put(idev);
366 }
367 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 }
369}
370
Eric Dumazeta50feda2012-05-18 18:57:34 +0000371static bool rt6_check_expired(const struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372{
Gao feng1716a962012-04-06 00:13:10 +0000373 if (rt->rt6i_flags & RTF_EXPIRES) {
374 if (time_after(jiffies, rt->dst.expires))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000375 return true;
Gao feng1716a962012-04-06 00:13:10 +0000376 } else if (rt->dst.from) {
Li RongQing3fd91fb2012-09-13 19:54:57 +0000377 return rt6_check_expired((struct rt6_info *) rt->dst.from);
Gao feng1716a962012-04-06 00:13:10 +0000378 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000379 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380}
381
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000382/* Multipath route selection:
383 * Hash based function using packet header and flowlabel.
384 * Adapted from fib_info_hashfn()
385 */
386static int rt6_info_hash_nhsfn(unsigned int candidate_count,
387 const struct flowi6 *fl6)
388{
389 unsigned int val = fl6->flowi6_proto;
390
YOSHIFUJI Hideaki / 吉藤英明c08977b2013-01-13 05:02:29 +0000391 val ^= ipv6_addr_hash(&fl6->daddr);
392 val ^= ipv6_addr_hash(&fl6->saddr);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000393
394 /* Work only if this not encapsulated */
395 switch (fl6->flowi6_proto) {
396 case IPPROTO_UDP:
397 case IPPROTO_TCP:
398 case IPPROTO_SCTP:
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000399 val ^= (__force u16)fl6->fl6_sport;
400 val ^= (__force u16)fl6->fl6_dport;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000401 break;
402
403 case IPPROTO_ICMPV6:
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000404 val ^= (__force u16)fl6->fl6_icmp_type;
405 val ^= (__force u16)fl6->fl6_icmp_code;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000406 break;
407 }
408 /* RFC6438 recommands to use flowlabel */
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000409 val ^= (__force u32)fl6->flowlabel;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000410
411 /* Perhaps, we need to tune, this function? */
412 val = val ^ (val >> 7) ^ (val >> 12);
413 return val % candidate_count;
414}
415
416static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200417 struct flowi6 *fl6, int oif,
418 int strict)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000419{
420 struct rt6_info *sibling, *next_sibling;
421 int route_choosen;
422
423 route_choosen = rt6_info_hash_nhsfn(match->rt6i_nsiblings + 1, fl6);
424 /* Don't change the route, if route_choosen == 0
425 * (siblings does not include ourself)
426 */
427 if (route_choosen)
428 list_for_each_entry_safe(sibling, next_sibling,
429 &match->rt6i_siblings, rt6i_siblings) {
430 route_choosen--;
431 if (route_choosen == 0) {
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200432 if (rt6_score_route(sibling, oif, strict) < 0)
433 break;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000434 match = sibling;
435 break;
436 }
437 }
438 return match;
439}
440
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441/*
Thomas Grafc71099a2006-08-04 23:20:06 -0700442 * Route lookup. Any table->tb6_lock is implied.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 */
444
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800445static inline struct rt6_info *rt6_device_match(struct net *net,
446 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000447 const struct in6_addr *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 int oif,
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700449 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450{
451 struct rt6_info *local = NULL;
452 struct rt6_info *sprt;
453
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900454 if (!oif && ipv6_addr_any(saddr))
455 goto out;
456
Changli Gaod8d1f302010-06-10 23:31:35 -0700457 for (sprt = rt; sprt; sprt = sprt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -0500458 struct net_device *dev = sprt->dst.dev;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900459
460 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 if (dev->ifindex == oif)
462 return sprt;
463 if (dev->flags & IFF_LOOPBACK) {
David S. Miller38308472011-12-03 18:02:47 -0500464 if (!sprt->rt6i_idev ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 sprt->rt6i_idev->dev->ifindex != oif) {
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700466 if (flags & RT6_LOOKUP_F_IFACE && oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 continue;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900468 if (local && (!oif ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 local->rt6i_idev->dev->ifindex == oif))
470 continue;
471 }
472 local = sprt;
473 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900474 } else {
475 if (ipv6_chk_addr(net, saddr, dev,
476 flags & RT6_LOOKUP_F_IFACE))
477 return sprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900479 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900481 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 if (local)
483 return local;
484
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700485 if (flags & RT6_LOOKUP_F_IFACE)
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800486 return net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900488out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 return rt;
490}
491
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800492#ifdef CONFIG_IPV6_ROUTER_PREF
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200493struct __rt6_probe_work {
494 struct work_struct work;
495 struct in6_addr target;
496 struct net_device *dev;
497};
498
499static void rt6_probe_deferred(struct work_struct *w)
500{
501 struct in6_addr mcaddr;
502 struct __rt6_probe_work *work =
503 container_of(w, struct __rt6_probe_work, work);
504
505 addrconf_addr_solict_mult(&work->target, &mcaddr);
506 ndisc_send_ns(work->dev, NULL, &work->target, &mcaddr, NULL);
507 dev_put(work->dev);
Michael Büsch662f5532015-02-08 10:14:07 +0100508 kfree(work);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200509}
510
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800511static void rt6_probe(struct rt6_info *rt)
512{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000513 struct neighbour *neigh;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800514 /*
515 * Okay, this does not seem to be appropriate
516 * for now, however, we need to check if it
517 * is really so; aka Router Reachability Probing.
518 *
519 * Router Reachability Probe MUST be rate-limited
520 * to no more than one per minute.
521 */
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000522 if (!rt || !(rt->rt6i_flags & RTF_GATEWAY))
Amerigo Wangfdd66812012-09-10 02:48:44 +0000523 return;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000524 rcu_read_lock_bh();
525 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
526 if (neigh) {
527 write_lock(&neigh->lock);
528 if (neigh->nud_state & NUD_VALID)
529 goto out;
YOSHIFUJI Hideaki / 吉藤英明7ff74a52013-01-17 12:53:02 +0000530 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000531
532 if (!neigh ||
YOSHIFUJI Hideaki52e16352006-03-20 17:05:47 -0800533 time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) {
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200534 struct __rt6_probe_work *work;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800535
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200536 work = kmalloc(sizeof(*work), GFP_ATOMIC);
537
538 if (neigh && work)
Jiri Benc7e980562013-12-11 13:48:20 +0100539 __neigh_set_probe_once(neigh);
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000540
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200541 if (neigh)
542 write_unlock(&neigh->lock);
543
544 if (work) {
545 INIT_WORK(&work->work, rt6_probe_deferred);
546 work->target = rt->rt6i_gateway;
547 dev_hold(rt->dst.dev);
548 work->dev = rt->dst.dev;
549 schedule_work(&work->work);
550 }
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000551 } else {
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000552out:
553 write_unlock(&neigh->lock);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000554 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000555 rcu_read_unlock_bh();
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800556}
557#else
558static inline void rt6_probe(struct rt6_info *rt)
559{
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800560}
561#endif
562
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563/*
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800564 * Default Router Selection (RFC 2461 6.3.6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 */
Dave Jonesb6f99a22007-03-22 12:27:49 -0700566static inline int rt6_check_dev(struct rt6_info *rt, int oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567{
David S. Millerd1918542011-12-28 20:19:20 -0500568 struct net_device *dev = rt->dst.dev;
David S. Miller161980f2007-04-06 11:42:27 -0700569 if (!oif || dev->ifindex == oif)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800570 return 2;
David S. Miller161980f2007-04-06 11:42:27 -0700571 if ((dev->flags & IFF_LOOPBACK) &&
572 rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
573 return 1;
574 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575}
576
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200577static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000579 struct neighbour *neigh;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200580 enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000581
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700582 if (rt->rt6i_flags & RTF_NONEXTHOP ||
583 !(rt->rt6i_flags & RTF_GATEWAY))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200584 return RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000585
586 rcu_read_lock_bh();
587 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
588 if (neigh) {
589 read_lock(&neigh->lock);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800590 if (neigh->nud_state & NUD_VALID)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200591 ret = RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800592#ifdef CONFIG_IPV6_ROUTER_PREF
Paul Marksa5a81f02012-12-03 10:26:54 +0000593 else if (!(neigh->nud_state & NUD_FAILED))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200594 ret = RT6_NUD_SUCCEED;
Jiri Benc7e980562013-12-11 13:48:20 +0100595 else
596 ret = RT6_NUD_FAIL_PROBE;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800597#endif
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000598 read_unlock(&neigh->lock);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200599 } else {
600 ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
Jiri Benc7e980562013-12-11 13:48:20 +0100601 RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR;
Paul Marksa5a81f02012-12-03 10:26:54 +0000602 }
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000603 rcu_read_unlock_bh();
604
Paul Marksa5a81f02012-12-03 10:26:54 +0000605 return ret;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800606}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800608static int rt6_score_route(struct rt6_info *rt, int oif,
609 int strict)
610{
Paul Marksa5a81f02012-12-03 10:26:54 +0000611 int m;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900612
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700613 m = rt6_check_dev(rt, oif);
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700614 if (!m && (strict & RT6_LOOKUP_F_IFACE))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200615 return RT6_NUD_FAIL_HARD;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800616#ifdef CONFIG_IPV6_ROUTER_PREF
617 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
618#endif
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200619 if (strict & RT6_LOOKUP_F_REACHABLE) {
620 int n = rt6_check_neigh(rt);
621 if (n < 0)
622 return n;
623 }
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800624 return m;
625}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626
David S. Millerf11e6652007-03-24 20:36:25 -0700627static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200628 int *mpri, struct rt6_info *match,
629 bool *do_rr)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800630{
David S. Millerf11e6652007-03-24 20:36:25 -0700631 int m;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200632 bool match_do_rr = false;
David S. Millerf11e6652007-03-24 20:36:25 -0700633
634 if (rt6_check_expired(rt))
635 goto out;
636
637 m = rt6_score_route(rt, oif, strict);
Jiri Benc7e980562013-12-11 13:48:20 +0100638 if (m == RT6_NUD_FAIL_DO_RR) {
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200639 match_do_rr = true;
640 m = 0; /* lowest valid score */
Jiri Benc7e980562013-12-11 13:48:20 +0100641 } else if (m == RT6_NUD_FAIL_HARD) {
David S. Millerf11e6652007-03-24 20:36:25 -0700642 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700643 }
644
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200645 if (strict & RT6_LOOKUP_F_REACHABLE)
646 rt6_probe(rt);
647
Jiri Benc7e980562013-12-11 13:48:20 +0100648 /* note that m can be RT6_NUD_FAIL_PROBE at this point */
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200649 if (m > *mpri) {
650 *do_rr = match_do_rr;
651 *mpri = m;
652 match = rt;
653 }
David S. Millerf11e6652007-03-24 20:36:25 -0700654out:
655 return match;
656}
657
658static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
659 struct rt6_info *rr_head,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200660 u32 metric, int oif, int strict,
661 bool *do_rr)
David S. Millerf11e6652007-03-24 20:36:25 -0700662{
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700663 struct rt6_info *rt, *match, *cont;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800664 int mpri = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
David S. Millerf11e6652007-03-24 20:36:25 -0700666 match = NULL;
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700667 cont = NULL;
668 for (rt = rr_head; rt; rt = rt->dst.rt6_next) {
669 if (rt->rt6i_metric != metric) {
670 cont = rt;
671 break;
672 }
673
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200674 match = find_match(rt, oif, strict, &mpri, match, do_rr);
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700675 }
676
677 for (rt = fn->leaf; rt && rt != rr_head; rt = rt->dst.rt6_next) {
678 if (rt->rt6i_metric != metric) {
679 cont = rt;
680 break;
681 }
682
683 match = find_match(rt, oif, strict, &mpri, match, do_rr);
684 }
685
686 if (match || !cont)
687 return match;
688
689 for (rt = cont; rt; rt = rt->dst.rt6_next)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200690 match = find_match(rt, oif, strict, &mpri, match, do_rr);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800691
David S. Millerf11e6652007-03-24 20:36:25 -0700692 return match;
693}
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800694
David S. Millerf11e6652007-03-24 20:36:25 -0700695static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
696{
697 struct rt6_info *match, *rt0;
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800698 struct net *net;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200699 bool do_rr = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
David S. Millerf11e6652007-03-24 20:36:25 -0700701 rt0 = fn->rr_ptr;
702 if (!rt0)
703 fn->rr_ptr = rt0 = fn->leaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200705 match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict,
706 &do_rr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200708 if (do_rr) {
Changli Gaod8d1f302010-06-10 23:31:35 -0700709 struct rt6_info *next = rt0->dst.rt6_next;
David S. Millerf11e6652007-03-24 20:36:25 -0700710
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800711 /* no entries matched; do round-robin */
David S. Millerf11e6652007-03-24 20:36:25 -0700712 if (!next || next->rt6i_metric != rt0->rt6i_metric)
713 next = fn->leaf;
714
715 if (next != rt0)
716 fn->rr_ptr = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 }
718
David S. Millerd1918542011-12-28 20:19:20 -0500719 net = dev_net(rt0->dst.dev);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000720 return match ? match : net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721}
722
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700723static bool rt6_is_gw_or_nonexthop(const struct rt6_info *rt)
724{
725 return (rt->rt6i_flags & (RTF_NONEXTHOP | RTF_GATEWAY));
726}
727
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800728#ifdef CONFIG_IPV6_ROUTE_INFO
729int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000730 const struct in6_addr *gwaddr)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800731{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900732 struct net *net = dev_net(dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800733 struct route_info *rinfo = (struct route_info *) opt;
734 struct in6_addr prefix_buf, *prefix;
735 unsigned int pref;
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900736 unsigned long lifetime;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800737 struct rt6_info *rt;
738
739 if (len < sizeof(struct route_info)) {
740 return -EINVAL;
741 }
742
743 /* Sanity check for prefix_len and length */
744 if (rinfo->length > 3) {
745 return -EINVAL;
746 } else if (rinfo->prefix_len > 128) {
747 return -EINVAL;
748 } else if (rinfo->prefix_len > 64) {
749 if (rinfo->length < 2) {
750 return -EINVAL;
751 }
752 } else if (rinfo->prefix_len > 0) {
753 if (rinfo->length < 1) {
754 return -EINVAL;
755 }
756 }
757
758 pref = rinfo->route_pref;
759 if (pref == ICMPV6_ROUTER_PREF_INVALID)
Jens Rosenboom3933fc92009-09-10 06:25:11 +0000760 return -EINVAL;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800761
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900762 lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800763
764 if (rinfo->length == 3)
765 prefix = (struct in6_addr *)rinfo->prefix;
766 else {
767 /* this function is safe */
768 ipv6_addr_prefix(&prefix_buf,
769 (struct in6_addr *)rinfo->prefix,
770 rinfo->prefix_len);
771 prefix = &prefix_buf;
772 }
773
Duan Jiongf104a562013-11-08 09:56:53 +0800774 if (rinfo->prefix_len == 0)
775 rt = rt6_get_dflt_router(gwaddr, dev);
776 else
777 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len,
778 gwaddr, dev->ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800779
780 if (rt && !lifetime) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -0700781 ip6_del_rt(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800782 rt = NULL;
783 }
784
785 if (!rt && lifetime)
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800786 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800787 pref);
788 else if (rt)
789 rt->rt6i_flags = RTF_ROUTEINFO |
790 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
791
792 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +0000793 if (!addrconf_finite_timeout(lifetime))
794 rt6_clean_expires(rt);
795 else
796 rt6_set_expires(rt, jiffies + HZ * lifetime);
797
Amerigo Wang94e187c2012-10-29 00:13:19 +0000798 ip6_rt_put(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800799 }
800 return 0;
801}
802#endif
803
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700804static struct fib6_node* fib6_backtrack(struct fib6_node *fn,
805 struct in6_addr *saddr)
806{
807 struct fib6_node *pn;
808 while (1) {
809 if (fn->fn_flags & RTN_TL_ROOT)
810 return NULL;
811 pn = fn->parent;
812 if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn)
813 fn = fib6_lookup(FIB6_SUBTREE(pn), NULL, saddr);
814 else
815 fn = pn;
816 if (fn->fn_flags & RTN_RTINFO)
817 return fn;
818 }
819}
Thomas Grafc71099a2006-08-04 23:20:06 -0700820
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800821static struct rt6_info *ip6_pol_route_lookup(struct net *net,
822 struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500823 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824{
825 struct fib6_node *fn;
826 struct rt6_info *rt;
827
Thomas Grafc71099a2006-08-04 23:20:06 -0700828 read_lock_bh(&table->tb6_lock);
David S. Miller4c9483b2011-03-12 16:22:43 -0500829 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -0700830restart:
831 rt = fn->leaf;
David S. Miller4c9483b2011-03-12 16:22:43 -0500832 rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000833 if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0)
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200834 rt = rt6_multipath_select(rt, fl6, fl6->flowi6_oif, flags);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700835 if (rt == net->ipv6.ip6_null_entry) {
836 fn = fib6_backtrack(fn, &fl6->saddr);
837 if (fn)
838 goto restart;
839 }
Changli Gaod8d1f302010-06-10 23:31:35 -0700840 dst_use(&rt->dst, jiffies);
Thomas Grafc71099a2006-08-04 23:20:06 -0700841 read_unlock_bh(&table->tb6_lock);
Thomas Grafc71099a2006-08-04 23:20:06 -0700842 return rt;
843
844}
845
Ian Morris67ba4152014-08-24 21:53:10 +0100846struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
Florian Westphalea6e5742011-09-05 16:05:44 +0200847 int flags)
848{
849 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup);
850}
851EXPORT_SYMBOL_GPL(ip6_route_lookup);
852
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900853struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
854 const struct in6_addr *saddr, int oif, int strict)
Thomas Grafc71099a2006-08-04 23:20:06 -0700855{
David S. Miller4c9483b2011-03-12 16:22:43 -0500856 struct flowi6 fl6 = {
857 .flowi6_oif = oif,
858 .daddr = *daddr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700859 };
860 struct dst_entry *dst;
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700861 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
Thomas Grafc71099a2006-08-04 23:20:06 -0700862
Thomas Grafadaa70b2006-10-13 15:01:03 -0700863 if (saddr) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500864 memcpy(&fl6.saddr, saddr, sizeof(*saddr));
Thomas Grafadaa70b2006-10-13 15:01:03 -0700865 flags |= RT6_LOOKUP_F_HAS_SADDR;
866 }
867
David S. Miller4c9483b2011-03-12 16:22:43 -0500868 dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup);
Thomas Grafc71099a2006-08-04 23:20:06 -0700869 if (dst->error == 0)
870 return (struct rt6_info *) dst;
871
872 dst_release(dst);
873
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 return NULL;
875}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900876EXPORT_SYMBOL(rt6_lookup);
877
Thomas Grafc71099a2006-08-04 23:20:06 -0700878/* ip6_ins_rt is called with FREE table->tb6_lock.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 It takes new route entry, the addition fails by any reason the
880 route is freed. In any case, if caller does not hold it, it may
881 be destroyed.
882 */
883
Michal Kubečeke5fd3872014-03-27 13:04:08 +0100884static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info,
Florian Westphale715b6d2015-01-05 23:57:44 +0100885 struct mx6_config *mxc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886{
887 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -0700888 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889
Thomas Grafc71099a2006-08-04 23:20:06 -0700890 table = rt->rt6i_table;
891 write_lock_bh(&table->tb6_lock);
Florian Westphale715b6d2015-01-05 23:57:44 +0100892 err = fib6_add(&table->tb6_root, rt, info, mxc);
Thomas Grafc71099a2006-08-04 23:20:06 -0700893 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894
895 return err;
896}
897
Thomas Graf40e22e82006-08-22 00:00:45 -0700898int ip6_ins_rt(struct rt6_info *rt)
899{
Florian Westphale715b6d2015-01-05 23:57:44 +0100900 struct nl_info info = { .nl_net = dev_net(rt->dst.dev), };
901 struct mx6_config mxc = { .mx = NULL, };
902
903 return __ip6_ins_rt(rt, &info, &mxc);
Thomas Graf40e22e82006-08-22 00:00:45 -0700904}
905
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700906static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort,
907 const struct in6_addr *daddr,
908 const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 struct rt6_info *rt;
911
912 /*
913 * Clone the route.
914 */
915
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000916 rt = ip6_rt_copy(ort, daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
918 if (rt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 rt->rt6i_flags |= RTF_CACHE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700921 if (!rt6_is_gw_or_nonexthop(ort)) {
922 if (ort->rt6i_dst.plen != 128 &&
923 ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
924 rt->rt6i_flags |= RTF_ANYCAST;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700926 if (rt->rt6i_src.plen && saddr) {
927 rt->rt6i_src.addr = *saddr;
928 rt->rt6i_src.plen = 128;
929 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930#endif
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700931 }
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800932 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800934 return rt;
935}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800937static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif,
David S. Miller4c9483b2011-03-12 16:22:43 -0500938 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939{
Martin KaFai Lau367efcb2014-10-20 13:42:45 -0700940 struct fib6_node *fn, *saved_fn;
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -0700941 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -0700942 int strict = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700944 strict |= flags & RT6_LOOKUP_F_IFACE;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -0700945 if (net->ipv6.devconf_all->forwarding == 0)
946 strict |= RT6_LOOKUP_F_REACHABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
Thomas Grafc71099a2006-08-04 23:20:06 -0700948 read_lock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
David S. Miller4c9483b2011-03-12 16:22:43 -0500950 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Martin KaFai Lau367efcb2014-10-20 13:42:45 -0700951 saved_fn = fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700953redo_rt6_select:
Martin KaFai Lau367efcb2014-10-20 13:42:45 -0700954 rt = rt6_select(fn, oif, strict);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200955 if (rt->rt6i_nsiblings)
Martin KaFai Lau367efcb2014-10-20 13:42:45 -0700956 rt = rt6_multipath_select(rt, fl6, oif, strict);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700957 if (rt == net->ipv6.ip6_null_entry) {
958 fn = fib6_backtrack(fn, &fl6->saddr);
959 if (fn)
960 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -0700961 else if (strict & RT6_LOOKUP_F_REACHABLE) {
962 /* also consider unreachable route */
963 strict &= ~RT6_LOOKUP_F_REACHABLE;
964 fn = saved_fn;
965 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -0700966 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700967 }
968
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -0700969 dst_use(&rt->dst, jiffies);
Thomas Grafc71099a2006-08-04 23:20:06 -0700970 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -0800971
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -0700972 if (rt == net->ipv6.ip6_null_entry || (rt->rt6i_flags & RTF_CACHE)) {
973 goto done;
974 } else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) &&
975 !(rt->rt6i_flags & RTF_GATEWAY))) {
976 /* Create a RTF_CACHE clone which will not be
977 * owned by the fib6 tree. It is for the special case where
978 * the daddr in the skb during the neighbor look-up is different
979 * from the fl6->daddr used to look-up route here.
980 */
Thomas Grafc71099a2006-08-04 23:20:06 -0700981
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -0700982 struct rt6_info *uncached_rt;
983
984 uncached_rt = ip6_rt_cache_alloc(rt, &fl6->daddr, NULL);
985 dst_release(&rt->dst);
986
987 if (uncached_rt)
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700988 rt6_uncached_list_add(uncached_rt);
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -0700989 else
990 uncached_rt = net->ipv6.ip6_null_entry;
991 dst_hold(&uncached_rt->dst);
992 return uncached_rt;
993 }
994
995done:
996 rt6_dst_from_metrics_check(rt);
Thomas Grafc71099a2006-08-04 23:20:06 -0700997 return rt;
998}
999
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001000static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -05001001 struct flowi6 *fl6, int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001002{
David S. Miller4c9483b2011-03-12 16:22:43 -05001003 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001004}
1005
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001006static struct dst_entry *ip6_route_input_lookup(struct net *net,
1007 struct net_device *dev,
1008 struct flowi6 *fl6, int flags)
1009{
1010 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
1011 flags |= RT6_LOOKUP_F_IFACE;
1012
1013 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_input);
1014}
1015
Thomas Grafc71099a2006-08-04 23:20:06 -07001016void ip6_route_input(struct sk_buff *skb)
1017{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001018 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001019 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001020 int flags = RT6_LOOKUP_F_HAS_SADDR;
David S. Miller4c9483b2011-03-12 16:22:43 -05001021 struct flowi6 fl6 = {
1022 .flowi6_iif = skb->dev->ifindex,
1023 .daddr = iph->daddr,
1024 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001025 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -05001026 .flowi6_mark = skb->mark,
1027 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -07001028 };
Thomas Grafadaa70b2006-10-13 15:01:03 -07001029
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001030 skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -07001031}
1032
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001033static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -05001034 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07001035{
David S. Miller4c9483b2011-03-12 16:22:43 -05001036 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -07001037}
1038
Ian Morris67ba4152014-08-24 21:53:10 +01001039struct dst_entry *ip6_route_output(struct net *net, const struct sock *sk,
David S. Miller4c9483b2011-03-12 16:22:43 -05001040 struct flowi6 *fl6)
Thomas Grafc71099a2006-08-04 23:20:06 -07001041{
1042 int flags = 0;
1043
Pavel Emelyanov1fb94892012-08-08 21:53:36 +00001044 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +00001045
David S. Miller4c9483b2011-03-12 16:22:43 -05001046 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001047 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -07001048
David S. Miller4c9483b2011-03-12 16:22:43 -05001049 if (!ipv6_addr_any(&fl6->saddr))
Thomas Grafadaa70b2006-10-13 15:01:03 -07001050 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +00001051 else if (sk)
1052 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001053
David S. Miller4c9483b2011-03-12 16:22:43 -05001054 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +09001056EXPORT_SYMBOL(ip6_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
David S. Miller2774c132011-03-01 14:59:04 -08001058struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -07001059{
David S. Miller5c1e6aa2011-04-28 14:13:38 -07001060 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
David S. Miller14e50e52007-05-24 18:17:54 -07001061 struct dst_entry *new = NULL;
1062
David S. Millerf5b0a872012-07-19 12:31:33 -07001063 rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, DST_OBSOLETE_NONE, 0);
David S. Miller14e50e52007-05-24 18:17:54 -07001064 if (rt) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001065 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -07001066
Steffen Klassert81048912012-07-05 23:37:09 +00001067 memset(new + 1, 0, sizeof(*rt) - sizeof(*new));
Steffen Klassert81048912012-07-05 23:37:09 +00001068
David S. Miller14e50e52007-05-24 18:17:54 -07001069 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08001070 new->input = dst_discard;
Eric Dumazetaad88722014-04-15 13:47:15 -04001071 new->output = dst_discard_sk;
David S. Miller14e50e52007-05-24 18:17:54 -07001072
Eric Dumazet21efcfa2011-07-19 20:18:36 +00001073 if (dst_metrics_read_only(&ort->dst))
1074 new->_metrics = ort->dst._metrics;
1075 else
1076 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07001077 rt->rt6i_idev = ort->rt6i_idev;
1078 if (rt->rt6i_idev)
1079 in6_dev_hold(rt->rt6i_idev);
David S. Miller14e50e52007-05-24 18:17:54 -07001080
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001081 rt->rt6i_gateway = ort->rt6i_gateway;
Gao feng1716a962012-04-06 00:13:10 +00001082 rt->rt6i_flags = ort->rt6i_flags;
David S. Miller14e50e52007-05-24 18:17:54 -07001083 rt->rt6i_metric = 0;
1084
1085 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
1086#ifdef CONFIG_IPV6_SUBTREES
1087 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1088#endif
1089
1090 dst_free(new);
1091 }
1092
David S. Miller69ead7a2011-03-01 14:45:33 -08001093 dst_release(dst_orig);
1094 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07001095}
David S. Miller14e50e52007-05-24 18:17:54 -07001096
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097/*
1098 * Destination cache support functions
1099 */
1100
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001101static void rt6_dst_from_metrics_check(struct rt6_info *rt)
1102{
1103 if (rt->dst.from &&
1104 dst_metrics_ptr(&rt->dst) != dst_metrics_ptr(rt->dst.from))
1105 dst_init_metrics(&rt->dst, dst_metrics_ptr(rt->dst.from), true);
1106}
1107
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001108static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie)
1109{
1110 if (!rt->rt6i_node || (rt->rt6i_node->fn_sernum != cookie))
1111 return NULL;
1112
1113 if (rt6_check_expired(rt))
1114 return NULL;
1115
1116 return &rt->dst;
1117}
1118
1119static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, u32 cookie)
1120{
1121 if (rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
1122 rt6_check((struct rt6_info *)(rt->dst.from), cookie))
1123 return &rt->dst;
1124 else
1125 return NULL;
1126}
1127
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
1129{
1130 struct rt6_info *rt;
1131
1132 rt = (struct rt6_info *) dst;
1133
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00001134 /* All IPV6 dsts are created with ->obsolete set to the value
1135 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
1136 * into this function always.
1137 */
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02001138
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001139 rt6_dst_from_metrics_check(rt);
1140
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001141 if (unlikely(dst->flags & DST_NOCACHE))
1142 return rt6_dst_from_check(rt, cookie);
1143 else
1144 return rt6_check(rt, cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145}
1146
1147static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
1148{
1149 struct rt6_info *rt = (struct rt6_info *) dst;
1150
1151 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001152 if (rt->rt6i_flags & RTF_CACHE) {
1153 if (rt6_check_expired(rt)) {
1154 ip6_del_rt(rt);
1155 dst = NULL;
1156 }
1157 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001159 dst = NULL;
1160 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001162 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163}
1164
1165static void ip6_link_failure(struct sk_buff *skb)
1166{
1167 struct rt6_info *rt;
1168
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00001169 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170
Eric Dumazetadf30902009-06-02 05:19:30 +00001171 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 if (rt) {
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001173 if (rt->rt6i_flags & RTF_CACHE) {
1174 dst_hold(&rt->dst);
1175 if (ip6_del_rt(rt))
1176 dst_free(&rt->dst);
1177 } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 rt->rt6i_node->fn_sernum = -1;
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001179 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 }
1181}
1182
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001183static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
1184{
1185 struct net *net = dev_net(rt->dst.dev);
1186
1187 rt->rt6i_flags |= RTF_MODIFIED;
1188 rt->rt6i_pmtu = mtu;
1189 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
1190}
1191
1192static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
1193 const struct ipv6hdr *iph, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194{
Ian Morris67ba4152014-08-24 21:53:10 +01001195 struct rt6_info *rt6 = (struct rt6_info *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001197 if (rt6->rt6i_flags & RTF_LOCAL)
1198 return;
1199
David S. Miller81aded22012-06-15 14:54:11 -07001200 dst_confirm(dst);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001201 mtu = max_t(u32, mtu, IPV6_MIN_MTU);
1202 if (mtu >= dst_mtu(dst))
1203 return;
David S. Miller81aded22012-06-15 14:54:11 -07001204
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001205 if (rt6->rt6i_flags & RTF_CACHE) {
1206 rt6_do_update_pmtu(rt6, mtu);
1207 } else {
1208 const struct in6_addr *daddr, *saddr;
1209 struct rt6_info *nrt6;
Hagen Paul Pfeifer9d289712015-01-15 22:34:25 +01001210
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001211 if (iph) {
1212 daddr = &iph->daddr;
1213 saddr = &iph->saddr;
1214 } else if (sk) {
1215 daddr = &sk->sk_v6_daddr;
1216 saddr = &inet6_sk(sk)->saddr;
1217 } else {
1218 return;
1219 }
1220 nrt6 = ip6_rt_cache_alloc(rt6, daddr, saddr);
1221 if (nrt6) {
1222 rt6_do_update_pmtu(nrt6, mtu);
1223
1224 /* ip6_ins_rt(nrt6) will bump the
1225 * rt6->rt6i_node->fn_sernum
1226 * which will fail the next rt6_check() and
1227 * invalidate the sk->sk_dst_cache.
1228 */
1229 ip6_ins_rt(nrt6);
1230 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 }
1232}
1233
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001234static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
1235 struct sk_buff *skb, u32 mtu)
1236{
1237 __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu);
1238}
1239
David S. Miller42ae66c2012-06-15 20:01:57 -07001240void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
1241 int oif, u32 mark)
David S. Miller81aded22012-06-15 14:54:11 -07001242{
1243 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1244 struct dst_entry *dst;
1245 struct flowi6 fl6;
1246
1247 memset(&fl6, 0, sizeof(fl6));
1248 fl6.flowi6_oif = oif;
Lorenzo Colitti1b3c61d2014-05-13 10:17:34 -07001249 fl6.flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark);
David S. Miller81aded22012-06-15 14:54:11 -07001250 fl6.daddr = iph->daddr;
1251 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001252 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller81aded22012-06-15 14:54:11 -07001253
1254 dst = ip6_route_output(net, NULL, &fl6);
1255 if (!dst->error)
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001256 __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07001257 dst_release(dst);
1258}
1259EXPORT_SYMBOL_GPL(ip6_update_pmtu);
1260
1261void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
1262{
1263 ip6_update_pmtu(skb, sock_net(sk), mtu,
1264 sk->sk_bound_dev_if, sk->sk_mark);
1265}
1266EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
1267
Duan Jiongb55b76b2013-09-04 19:44:21 +08001268/* Handle redirects */
1269struct ip6rd_flowi {
1270 struct flowi6 fl6;
1271 struct in6_addr gateway;
1272};
1273
1274static struct rt6_info *__ip6_route_redirect(struct net *net,
1275 struct fib6_table *table,
1276 struct flowi6 *fl6,
1277 int flags)
1278{
1279 struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
1280 struct rt6_info *rt;
1281 struct fib6_node *fn;
1282
1283 /* Get the "current" route for this destination and
1284 * check if the redirect has come from approriate router.
1285 *
1286 * RFC 4861 specifies that redirects should only be
1287 * accepted if they come from the nexthop to the target.
1288 * Due to the way the routes are chosen, this notion
1289 * is a bit fuzzy and one might need to check all possible
1290 * routes.
1291 */
1292
1293 read_lock_bh(&table->tb6_lock);
1294 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
1295restart:
1296 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
1297 if (rt6_check_expired(rt))
1298 continue;
1299 if (rt->dst.error)
1300 break;
1301 if (!(rt->rt6i_flags & RTF_GATEWAY))
1302 continue;
1303 if (fl6->flowi6_oif != rt->dst.dev->ifindex)
1304 continue;
1305 if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway))
1306 continue;
1307 break;
1308 }
1309
1310 if (!rt)
1311 rt = net->ipv6.ip6_null_entry;
1312 else if (rt->dst.error) {
1313 rt = net->ipv6.ip6_null_entry;
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001314 goto out;
1315 }
1316
1317 if (rt == net->ipv6.ip6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001318 fn = fib6_backtrack(fn, &fl6->saddr);
1319 if (fn)
1320 goto restart;
Duan Jiongb55b76b2013-09-04 19:44:21 +08001321 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001322
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001323out:
Duan Jiongb55b76b2013-09-04 19:44:21 +08001324 dst_hold(&rt->dst);
1325
1326 read_unlock_bh(&table->tb6_lock);
1327
1328 return rt;
1329};
1330
1331static struct dst_entry *ip6_route_redirect(struct net *net,
1332 const struct flowi6 *fl6,
1333 const struct in6_addr *gateway)
1334{
1335 int flags = RT6_LOOKUP_F_HAS_SADDR;
1336 struct ip6rd_flowi rdfl;
1337
1338 rdfl.fl6 = *fl6;
1339 rdfl.gateway = *gateway;
1340
1341 return fib6_rule_lookup(net, &rdfl.fl6,
1342 flags, __ip6_route_redirect);
1343}
1344
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001345void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark)
1346{
1347 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1348 struct dst_entry *dst;
1349 struct flowi6 fl6;
1350
1351 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001352 fl6.flowi6_iif = LOOPBACK_IFINDEX;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001353 fl6.flowi6_oif = oif;
1354 fl6.flowi6_mark = mark;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001355 fl6.daddr = iph->daddr;
1356 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001357 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001358
Duan Jiongb55b76b2013-09-04 19:44:21 +08001359 dst = ip6_route_redirect(net, &fl6, &ipv6_hdr(skb)->saddr);
1360 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001361 dst_release(dst);
1362}
1363EXPORT_SYMBOL_GPL(ip6_redirect);
1364
Duan Jiongc92a59e2013-08-22 12:07:35 +08001365void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
1366 u32 mark)
1367{
1368 const struct ipv6hdr *iph = ipv6_hdr(skb);
1369 const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
1370 struct dst_entry *dst;
1371 struct flowi6 fl6;
1372
1373 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001374 fl6.flowi6_iif = LOOPBACK_IFINDEX;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001375 fl6.flowi6_oif = oif;
1376 fl6.flowi6_mark = mark;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001377 fl6.daddr = msg->dest;
1378 fl6.saddr = iph->daddr;
1379
Duan Jiongb55b76b2013-09-04 19:44:21 +08001380 dst = ip6_route_redirect(net, &fl6, &iph->saddr);
1381 rt6_do_redirect(dst, NULL, skb);
Duan Jiongc92a59e2013-08-22 12:07:35 +08001382 dst_release(dst);
1383}
1384
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001385void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
1386{
1387 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark);
1388}
1389EXPORT_SYMBOL_GPL(ip6_sk_redirect);
1390
David S. Miller0dbaee32010-12-13 12:52:14 -08001391static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392{
David S. Miller0dbaee32010-12-13 12:52:14 -08001393 struct net_device *dev = dst->dev;
1394 unsigned int mtu = dst_mtu(dst);
1395 struct net *net = dev_net(dev);
1396
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
1398
Daniel Lezcano55786892008-03-04 13:47:47 -08001399 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
1400 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401
1402 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001403 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
1404 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
1405 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 * rely only on pmtu discovery"
1407 */
1408 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
1409 mtu = IPV6_MAXPLEN;
1410 return mtu;
1411}
1412
Steffen Klassertebb762f2011-11-23 02:12:51 +00001413static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08001414{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001415 const struct rt6_info *rt = (const struct rt6_info *)dst;
1416 unsigned int mtu = rt->rt6i_pmtu;
David S. Millerd33e4552010-12-14 13:01:14 -08001417 struct inet6_dev *idev;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001418
1419 if (mtu)
Eric Dumazet30f78d82014-04-10 21:23:36 -07001420 goto out;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001421
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001422 mtu = dst_metric_raw(dst, RTAX_MTU);
1423 if (mtu)
1424 goto out;
1425
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001426 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08001427
1428 rcu_read_lock();
1429 idev = __in6_dev_get(dst->dev);
1430 if (idev)
1431 mtu = idev->cnf.mtu6;
1432 rcu_read_unlock();
1433
Eric Dumazet30f78d82014-04-10 21:23:36 -07001434out:
1435 return min_t(unsigned int, mtu, IP6_MAX_MTU);
David S. Millerd33e4552010-12-14 13:01:14 -08001436}
1437
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001438static struct dst_entry *icmp6_dst_gc_list;
1439static DEFINE_SPINLOCK(icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001440
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001441struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05001442 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443{
David S. Miller87a11572011-12-06 17:04:13 -05001444 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 struct rt6_info *rt;
1446 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001447 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448
David S. Miller38308472011-12-03 18:02:47 -05001449 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00001450 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451
David S. Miller8b96d222012-06-11 02:01:56 -07001452 rt = ip6_dst_alloc(net, dev, 0, NULL);
David S. Miller38308472011-12-03 18:02:47 -05001453 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05001455 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 goto out;
1457 }
1458
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001459 rt->dst.flags |= DST_HOST;
1460 rt->dst.output = ip6_output;
Changli Gaod8d1f302010-06-10 23:31:35 -07001461 atomic_set(&rt->dst.__refcnt, 1);
Julian Anastasov550bab42013-10-20 15:43:04 +03001462 rt->rt6i_gateway = fl6->daddr;
David S. Miller87a11572011-12-06 17:04:13 -05001463 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001464 rt->rt6i_dst.plen = 128;
1465 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08001466 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001468 spin_lock_bh(&icmp6_dst_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001469 rt->dst.next = icmp6_dst_gc_list;
1470 icmp6_dst_gc_list = &rt->dst;
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001471 spin_unlock_bh(&icmp6_dst_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472
Daniel Lezcano55786892008-03-04 13:47:47 -08001473 fib6_force_start_gc(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474
David S. Miller87a11572011-12-06 17:04:13 -05001475 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
1476
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477out:
David S. Miller87a11572011-12-06 17:04:13 -05001478 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479}
1480
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001481int icmp6_dst_gc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482{
Hagen Paul Pfeifere9476e92011-02-25 05:45:19 +00001483 struct dst_entry *dst, **pprev;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001484 int more = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001486 spin_lock_bh(&icmp6_dst_lock);
1487 pprev = &icmp6_dst_gc_list;
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001488
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 while ((dst = *pprev) != NULL) {
1490 if (!atomic_read(&dst->__refcnt)) {
1491 *pprev = dst->next;
1492 dst_free(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 } else {
1494 pprev = &dst->next;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001495 ++more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 }
1497 }
1498
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001499 spin_unlock_bh(&icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001500
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001501 return more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502}
1503
David S. Miller1e493d12008-09-10 17:27:15 -07001504static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg),
1505 void *arg)
1506{
1507 struct dst_entry *dst, **pprev;
1508
1509 spin_lock_bh(&icmp6_dst_lock);
1510 pprev = &icmp6_dst_gc_list;
1511 while ((dst = *pprev) != NULL) {
1512 struct rt6_info *rt = (struct rt6_info *) dst;
1513 if (func(rt, arg)) {
1514 *pprev = dst->next;
1515 dst_free(dst);
1516 } else {
1517 pprev = &dst->next;
1518 }
1519 }
1520 spin_unlock_bh(&icmp6_dst_lock);
1521}
1522
Daniel Lezcano569d3642008-01-18 03:56:57 -08001523static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524{
Alexey Dobriyan86393e52009-08-29 01:34:49 +00001525 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08001526 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
1527 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
1528 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
1529 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
1530 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001531 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532
Eric Dumazetfc66f952010-10-08 06:37:34 +00001533 entries = dst_entries_get_fast(ops);
Michal Kubeček49a18d82013-08-01 10:04:24 +02001534 if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00001535 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 goto out;
1537
Benjamin Thery6891a342008-03-04 13:49:47 -08001538 net->ipv6.ip6_rt_gc_expire++;
Li RongQing14956642014-05-19 17:30:28 +08001539 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
Eric Dumazetfc66f952010-10-08 06:37:34 +00001540 entries = dst_entries_get_slow(ops);
1541 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08001542 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08001544 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001545 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546}
1547
Florian Westphale715b6d2015-01-05 23:57:44 +01001548static int ip6_convert_metrics(struct mx6_config *mxc,
1549 const struct fib6_config *cfg)
1550{
1551 struct nlattr *nla;
1552 int remaining;
1553 u32 *mp;
1554
Ian Morris63159f22015-03-29 14:00:04 +01001555 if (!cfg->fc_mx)
Florian Westphale715b6d2015-01-05 23:57:44 +01001556 return 0;
1557
1558 mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
1559 if (unlikely(!mp))
1560 return -ENOMEM;
1561
1562 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
1563 int type = nla_type(nla);
1564
1565 if (type) {
Daniel Borkmannea697632015-01-05 23:57:47 +01001566 u32 val;
1567
Florian Westphale715b6d2015-01-05 23:57:44 +01001568 if (unlikely(type > RTAX_MAX))
1569 goto err;
Daniel Borkmannea697632015-01-05 23:57:47 +01001570 if (type == RTAX_CC_ALGO) {
1571 char tmp[TCP_CA_NAME_MAX];
Florian Westphale715b6d2015-01-05 23:57:44 +01001572
Daniel Borkmannea697632015-01-05 23:57:47 +01001573 nla_strlcpy(tmp, nla, sizeof(tmp));
1574 val = tcp_ca_get_key_by_name(tmp);
1575 if (val == TCP_CA_UNSPEC)
1576 goto err;
1577 } else {
1578 val = nla_get_u32(nla);
1579 }
1580
1581 mp[type - 1] = val;
Florian Westphale715b6d2015-01-05 23:57:44 +01001582 __set_bit(type - 1, mxc->mx_valid);
1583 }
1584 }
1585
1586 mxc->mx = mp;
1587
1588 return 0;
1589 err:
1590 kfree(mp);
1591 return -EINVAL;
1592}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593
Thomas Graf86872cb2006-08-22 00:01:08 -07001594int ip6_route_add(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595{
1596 int err;
Daniel Lezcano55786892008-03-04 13:47:47 -08001597 struct net *net = cfg->fc_nlinfo.nl_net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 struct rt6_info *rt = NULL;
1599 struct net_device *dev = NULL;
1600 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001601 struct fib6_table *table;
Florian Westphale715b6d2015-01-05 23:57:44 +01001602 struct mx6_config mxc = { .mx = NULL, };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 int addr_type;
1604
Thomas Graf86872cb2006-08-22 00:01:08 -07001605 if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 return -EINVAL;
1607#ifndef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001608 if (cfg->fc_src_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 return -EINVAL;
1610#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07001611 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08001613 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 if (!dev)
1615 goto out;
1616 idev = in6_dev_get(dev);
1617 if (!idev)
1618 goto out;
1619 }
1620
Thomas Graf86872cb2006-08-22 00:01:08 -07001621 if (cfg->fc_metric == 0)
1622 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623
Matti Vaittinend71314b2011-11-14 00:14:49 +00001624 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05001625 if (cfg->fc_nlinfo.nlh &&
1626 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00001627 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001628 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00001629 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00001630 table = fib6_new_table(net, cfg->fc_table);
1631 }
1632 } else {
1633 table = fib6_new_table(net, cfg->fc_table);
1634 }
David S. Miller38308472011-12-03 18:02:47 -05001635
1636 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001637 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07001638
Sabrina Dubrocac88507f2014-03-06 17:51:57 +01001639 rt = ip6_dst_alloc(net, NULL, (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT, table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640
David S. Miller38308472011-12-03 18:02:47 -05001641 if (!rt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 err = -ENOMEM;
1643 goto out;
1644 }
1645
Gao feng1716a962012-04-06 00:13:10 +00001646 if (cfg->fc_flags & RTF_EXPIRES)
1647 rt6_set_expires(rt, jiffies +
1648 clock_t_to_jiffies(cfg->fc_expires));
1649 else
1650 rt6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651
Thomas Graf86872cb2006-08-22 00:01:08 -07001652 if (cfg->fc_protocol == RTPROT_UNSPEC)
1653 cfg->fc_protocol = RTPROT_BOOT;
1654 rt->rt6i_protocol = cfg->fc_protocol;
1655
1656 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657
1658 if (addr_type & IPV6_ADDR_MULTICAST)
Changli Gaod8d1f302010-06-10 23:31:35 -07001659 rt->dst.input = ip6_mc_input;
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00001660 else if (cfg->fc_flags & RTF_LOCAL)
1661 rt->dst.input = ip6_input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 else
Changli Gaod8d1f302010-06-10 23:31:35 -07001663 rt->dst.input = ip6_forward;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664
Changli Gaod8d1f302010-06-10 23:31:35 -07001665 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666
Thomas Graf86872cb2006-08-22 00:01:08 -07001667 ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
1668 rt->rt6i_dst.plen = cfg->fc_dst_len;
Martin KaFai Lauafc4eef2015-04-28 13:03:07 -07001669 if (rt->rt6i_dst.plen == 128)
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001670 rt->dst.flags |= DST_HOST;
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001671
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672#ifdef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001673 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
1674 rt->rt6i_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675#endif
1676
Thomas Graf86872cb2006-08-22 00:01:08 -07001677 rt->rt6i_metric = cfg->fc_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678
1679 /* We cannot add true routes via loopback here,
1680 they would result in kernel looping; promote them to reject routes
1681 */
Thomas Graf86872cb2006-08-22 00:01:08 -07001682 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05001683 (dev && (dev->flags & IFF_LOOPBACK) &&
1684 !(addr_type & IPV6_ADDR_LOOPBACK) &&
1685 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08001687 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 if (dev) {
1689 dev_put(dev);
1690 in6_dev_put(idev);
1691 }
Daniel Lezcano55786892008-03-04 13:47:47 -08001692 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 dev_hold(dev);
1694 idev = in6_dev_get(dev);
1695 if (!idev) {
1696 err = -ENODEV;
1697 goto out;
1698 }
1699 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001701 switch (cfg->fc_type) {
1702 case RTN_BLACKHOLE:
1703 rt->dst.error = -EINVAL;
Eric Dumazetaad88722014-04-15 13:47:15 -04001704 rt->dst.output = dst_discard_sk;
Kamala R7150aed2013-12-02 19:55:21 +05301705 rt->dst.input = dst_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001706 break;
1707 case RTN_PROHIBIT:
1708 rt->dst.error = -EACCES;
Kamala R7150aed2013-12-02 19:55:21 +05301709 rt->dst.output = ip6_pkt_prohibit_out;
1710 rt->dst.input = ip6_pkt_prohibit;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001711 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00001712 case RTN_THROW:
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001713 default:
Kamala R7150aed2013-12-02 19:55:21 +05301714 rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN
1715 : -ENETUNREACH;
1716 rt->dst.output = ip6_pkt_discard_out;
1717 rt->dst.input = ip6_pkt_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001718 break;
1719 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 goto install_route;
1721 }
1722
Thomas Graf86872cb2006-08-22 00:01:08 -07001723 if (cfg->fc_flags & RTF_GATEWAY) {
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001724 const struct in6_addr *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 int gwa_type;
1726
Thomas Graf86872cb2006-08-22 00:01:08 -07001727 gw_addr = &cfg->fc_gateway;
Florian Westphal48ed7b22015-05-21 00:25:41 +02001728
1729 /* if gw_addr is local we will fail to detect this in case
1730 * address is still TENTATIVE (DAD in progress). rt6_lookup()
1731 * will return already-added prefix route via interface that
1732 * prefix route was assigned to, which might be non-loopback.
1733 */
1734 err = -EINVAL;
1735 if (ipv6_chk_addr_and_flags(net, gw_addr, NULL, 0, 0))
1736 goto out;
1737
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001738 rt->rt6i_gateway = *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 gwa_type = ipv6_addr_type(gw_addr);
1740
1741 if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
1742 struct rt6_info *grt;
1743
1744 /* IPv6 strictly inhibits using not link-local
1745 addresses as nexthop address.
1746 Otherwise, router will not able to send redirects.
1747 It is very good, but in some (rare!) circumstances
1748 (SIT, PtP, NBMA NOARP links) it is handy to allow
1749 some exceptions. --ANK
1750 */
David S. Miller38308472011-12-03 18:02:47 -05001751 if (!(gwa_type & IPV6_ADDR_UNICAST))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 goto out;
1753
Daniel Lezcano55786892008-03-04 13:47:47 -08001754 grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755
1756 err = -EHOSTUNREACH;
David S. Miller38308472011-12-03 18:02:47 -05001757 if (!grt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 goto out;
1759 if (dev) {
David S. Millerd1918542011-12-28 20:19:20 -05001760 if (dev != grt->dst.dev) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00001761 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 goto out;
1763 }
1764 } else {
David S. Millerd1918542011-12-28 20:19:20 -05001765 dev = grt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 idev = grt->rt6i_idev;
1767 dev_hold(dev);
1768 in6_dev_hold(grt->rt6i_idev);
1769 }
David S. Miller38308472011-12-03 18:02:47 -05001770 if (!(grt->rt6i_flags & RTF_GATEWAY))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 err = 0;
Amerigo Wang94e187c2012-10-29 00:13:19 +00001772 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773
1774 if (err)
1775 goto out;
1776 }
1777 err = -EINVAL;
David S. Miller38308472011-12-03 18:02:47 -05001778 if (!dev || (dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 goto out;
1780 }
1781
1782 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05001783 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 goto out;
1785
Daniel Walterc3968a82011-04-13 21:10:57 +00001786 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
1787 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
1788 err = -EINVAL;
1789 goto out;
1790 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001791 rt->rt6i_prefsrc.addr = cfg->fc_prefsrc;
Daniel Walterc3968a82011-04-13 21:10:57 +00001792 rt->rt6i_prefsrc.plen = 128;
1793 } else
1794 rt->rt6i_prefsrc.plen = 0;
1795
Thomas Graf86872cb2006-08-22 00:01:08 -07001796 rt->rt6i_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797
1798install_route:
Changli Gaod8d1f302010-06-10 23:31:35 -07001799 rt->dst.dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 rt->rt6i_idev = idev;
Thomas Grafc71099a2006-08-04 23:20:06 -07001801 rt->rt6i_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001802
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001803 cfg->fc_nlinfo.nl_net = dev_net(dev);
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001804
Florian Westphale715b6d2015-01-05 23:57:44 +01001805 err = ip6_convert_metrics(&mxc, cfg);
1806 if (err)
1807 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808
Florian Westphale715b6d2015-01-05 23:57:44 +01001809 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, &mxc);
1810
1811 kfree(mxc.mx);
1812 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813out:
1814 if (dev)
1815 dev_put(dev);
1816 if (idev)
1817 in6_dev_put(idev);
1818 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07001819 dst_free(&rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 return err;
1821}
1822
Thomas Graf86872cb2006-08-22 00:01:08 -07001823static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824{
1825 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07001826 struct fib6_table *table;
David S. Millerd1918542011-12-28 20:19:20 -05001827 struct net *net = dev_net(rt->dst.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828
Gao feng6825a262012-09-19 19:25:34 +00001829 if (rt == net->ipv6.ip6_null_entry) {
1830 err = -ENOENT;
1831 goto out;
1832 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07001833
Thomas Grafc71099a2006-08-04 23:20:06 -07001834 table = rt->rt6i_table;
1835 write_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07001836 err = fib6_del(rt, info);
Thomas Grafc71099a2006-08-04 23:20:06 -07001837 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838
Gao feng6825a262012-09-19 19:25:34 +00001839out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00001840 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 return err;
1842}
1843
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001844int ip6_del_rt(struct rt6_info *rt)
1845{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08001846 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -05001847 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08001848 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08001849 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001850}
1851
Thomas Graf86872cb2006-08-22 00:01:08 -07001852static int ip6_route_del(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853{
Thomas Grafc71099a2006-08-04 23:20:06 -07001854 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 struct fib6_node *fn;
1856 struct rt6_info *rt;
1857 int err = -ESRCH;
1858
Daniel Lezcano55786892008-03-04 13:47:47 -08001859 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001860 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001861 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862
Thomas Grafc71099a2006-08-04 23:20:06 -07001863 read_lock_bh(&table->tb6_lock);
1864
1865 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07001866 &cfg->fc_dst, cfg->fc_dst_len,
1867 &cfg->fc_src, cfg->fc_src_len);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001868
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 if (fn) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001870 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
Martin KaFai Lau1f56a012015-04-28 13:03:03 -07001871 if ((rt->rt6i_flags & RTF_CACHE) &&
1872 !(cfg->fc_flags & RTF_CACHE))
1873 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001874 if (cfg->fc_ifindex &&
David S. Millerd1918542011-12-28 20:19:20 -05001875 (!rt->dst.dev ||
1876 rt->dst.dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001878 if (cfg->fc_flags & RTF_GATEWAY &&
1879 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001881 if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07001883 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07001884 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885
Thomas Graf86872cb2006-08-22 00:01:08 -07001886 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 }
1888 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001889 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890
1891 return err;
1892}
1893
David S. Miller6700c272012-07-17 03:29:28 -07001894static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001895{
David S. Millere8599ff2012-07-11 23:43:53 -07001896 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001897 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07001898 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07001899 struct ndisc_options ndopts;
1900 struct inet6_dev *in6_dev;
1901 struct neighbour *neigh;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001902 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07001903 int optlen, on_link;
1904 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07001905
Simon Horman29a3cad2013-05-28 20:34:26 +00001906 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001907 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07001908
1909 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07001910 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001911 return;
1912 }
1913
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001914 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07001915
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001916 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07001917 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001918 return;
1919 }
1920
David S. Miller6e157b62012-07-12 00:05:02 -07001921 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001922 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07001923 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001924 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07001925 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07001926 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001927 return;
1928 }
1929
1930 in6_dev = __in6_dev_get(skb->dev);
1931 if (!in6_dev)
1932 return;
1933 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
1934 return;
1935
1936 /* RFC2461 8.1:
1937 * The IP source address of the Redirect MUST be the same as the current
1938 * first-hop router for the specified ICMP Destination Address.
1939 */
1940
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001941 if (!ndisc_parse_options(msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07001942 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
1943 return;
1944 }
David S. Miller6e157b62012-07-12 00:05:02 -07001945
1946 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07001947 if (ndopts.nd_opts_tgt_lladdr) {
1948 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
1949 skb->dev);
1950 if (!lladdr) {
1951 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
1952 return;
1953 }
1954 }
1955
David S. Miller6e157b62012-07-12 00:05:02 -07001956 rt = (struct rt6_info *) dst;
1957 if (rt == net->ipv6.ip6_null_entry) {
1958 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
1959 return;
1960 }
1961
1962 /* Redirect received -> path was valid.
1963 * Look, redirects are sent only in response to data packets,
1964 * so that this nexthop apparently is reachable. --ANK
1965 */
1966 dst_confirm(&rt->dst);
1967
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001968 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07001969 if (!neigh)
1970 return;
1971
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 /*
1973 * We have finally decided to accept it.
1974 */
1975
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001976 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1978 NEIGH_UPDATE_F_OVERRIDE|
1979 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1980 NEIGH_UPDATE_F_ISROUTER))
1981 );
1982
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001983 nrt = ip6_rt_copy(rt, &msg->dest);
David S. Miller38308472011-12-03 18:02:47 -05001984 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 goto out;
1986
1987 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
1988 if (on_link)
1989 nrt->rt6i_flags &= ~RTF_GATEWAY;
1990
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001991 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992
Thomas Graf40e22e82006-08-22 00:00:45 -07001993 if (ip6_ins_rt(nrt))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 goto out;
1995
Changli Gaod8d1f302010-06-10 23:31:35 -07001996 netevent.old = &rt->dst;
1997 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001998 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00001999 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07002000 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
2001
David S. Miller38308472011-12-03 18:02:47 -05002002 if (rt->rt6i_flags & RTF_CACHE) {
David S. Miller6e157b62012-07-12 00:05:02 -07002003 rt = (struct rt6_info *) dst_clone(&rt->dst);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002004 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 }
2006
2007out:
David S. Millere8599ff2012-07-11 23:43:53 -07002008 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07002009}
2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 * Misc support functions
2013 */
2014
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002015static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from)
2016{
2017 BUG_ON(from->dst.from);
2018
2019 rt->rt6i_flags &= ~RTF_EXPIRES;
2020 dst_hold(&from->dst);
2021 rt->dst.from = &from->dst;
2022 dst_init_metrics(&rt->dst, dst_metrics_ptr(&from->dst), true);
2023}
2024
Gao feng1716a962012-04-06 00:13:10 +00002025static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
Eric Dumazet21efcfa2011-07-19 20:18:36 +00002026 const struct in6_addr *dest)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027{
David S. Millerd1918542011-12-28 20:19:20 -05002028 struct net *net = dev_net(ort->dst.dev);
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002029 struct rt6_info *rt;
2030
2031 if (ort->rt6i_flags & RTF_CACHE)
2032 ort = (struct rt6_info *)ort->dst.from;
2033
2034 rt = ip6_dst_alloc(net, ort->dst.dev, 0,
2035 ort->rt6i_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036
2037 if (rt) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002038 rt->dst.input = ort->dst.input;
2039 rt->dst.output = ort->dst.output;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002040 rt->dst.flags |= DST_HOST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002042 rt->rt6i_dst.addr = *dest;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002043 rt->rt6i_dst.plen = 128;
Changli Gaod8d1f302010-06-10 23:31:35 -07002044 rt->dst.error = ort->dst.error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 rt->rt6i_idev = ort->rt6i_idev;
2046 if (rt->rt6i_idev)
2047 in6_dev_hold(rt->rt6i_idev);
Changli Gaod8d1f302010-06-10 23:31:35 -07002048 rt->dst.lastuse = jiffies;
Martin KaFai Lau2647a9b2015-05-22 20:55:58 -07002049 rt->rt6i_gateway = ort->rt6i_gateway;
Gao feng1716a962012-04-06 00:13:10 +00002050 rt->rt6i_flags = ort->rt6i_flags;
Li RongQing24f5b852013-12-19 12:40:26 +08002051 rt6_set_from(rt, ort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 rt->rt6i_metric = 0;
2053
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054#ifdef CONFIG_IPV6_SUBTREES
2055 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
2056#endif
Florian Westphal0f6c6392011-05-20 11:27:24 +00002057 memcpy(&rt->rt6i_prefsrc, &ort->rt6i_prefsrc, sizeof(struct rt6key));
Thomas Grafc71099a2006-08-04 23:20:06 -07002058 rt->rt6i_table = ort->rt6i_table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 }
2060 return rt;
2061}
2062
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002063#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002064static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002065 const struct in6_addr *prefix, int prefixlen,
2066 const struct in6_addr *gwaddr, int ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002067{
2068 struct fib6_node *fn;
2069 struct rt6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07002070 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002071
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002072 table = fib6_get_table(net, RT6_TABLE_INFO);
David S. Miller38308472011-12-03 18:02:47 -05002073 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002074 return NULL;
2075
Li RongQing5744dd92012-09-11 21:59:01 +00002076 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01002077 fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002078 if (!fn)
2079 goto out;
2080
Changli Gaod8d1f302010-06-10 23:31:35 -07002081 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05002082 if (rt->dst.dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002083 continue;
2084 if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
2085 continue;
2086 if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
2087 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07002088 dst_hold(&rt->dst);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002089 break;
2090 }
2091out:
Li RongQing5744dd92012-09-11 21:59:01 +00002092 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002093 return rt;
2094}
2095
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002096static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002097 const struct in6_addr *prefix, int prefixlen,
2098 const struct in6_addr *gwaddr, int ifindex,
Eric Dumazet95c96172012-04-15 05:58:06 +00002099 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002100{
Thomas Graf86872cb2006-08-22 00:01:08 -07002101 struct fib6_config cfg = {
2102 .fc_table = RT6_TABLE_INFO,
Rami Rosen238fc7e2008-02-09 23:43:11 -08002103 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07002104 .fc_ifindex = ifindex,
2105 .fc_dst_len = prefixlen,
2106 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
2107 RTF_UP | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00002108 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002109 .fc_nlinfo.nlh = NULL,
2110 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07002111 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002112
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002113 cfg.fc_dst = *prefix;
2114 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07002115
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08002116 /* We should treat it as a default route if prefix length is 0. */
2117 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07002118 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002119
Thomas Graf86872cb2006-08-22 00:01:08 -07002120 ip6_route_add(&cfg);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002121
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002122 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002123}
2124#endif
2125
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002126struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002127{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07002129 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002131 table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05002132 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002133 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134
Li RongQing5744dd92012-09-11 21:59:01 +00002135 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01002136 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05002137 if (dev == rt->dst.dev &&
YOSHIFUJI Hideaki045927f2006-03-20 17:00:48 -08002138 ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 ipv6_addr_equal(&rt->rt6i_gateway, addr))
2140 break;
2141 }
2142 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07002143 dst_hold(&rt->dst);
Li RongQing5744dd92012-09-11 21:59:01 +00002144 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 return rt;
2146}
2147
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002148struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08002149 struct net_device *dev,
2150 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151{
Thomas Graf86872cb2006-08-22 00:01:08 -07002152 struct fib6_config cfg = {
2153 .fc_table = RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08002154 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07002155 .fc_ifindex = dev->ifindex,
2156 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
2157 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00002158 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08002159 .fc_nlinfo.nlh = NULL,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002160 .fc_nlinfo.nl_net = dev_net(dev),
Thomas Graf86872cb2006-08-22 00:01:08 -07002161 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002163 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164
Thomas Graf86872cb2006-08-22 00:01:08 -07002165 ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 return rt6_get_dflt_router(gwaddr, dev);
2168}
2169
Daniel Lezcano7b4da532008-03-04 13:47:14 -08002170void rt6_purge_dflt_routers(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171{
2172 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07002173 struct fib6_table *table;
2174
2175 /* NOTE: Keep consistent with rt6_get_dflt_router */
Daniel Lezcano7b4da532008-03-04 13:47:14 -08002176 table = fib6_get_table(net, RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05002177 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002178 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179
2180restart:
Thomas Grafc71099a2006-08-04 23:20:06 -07002181 read_lock_bh(&table->tb6_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07002182 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
Lorenzo Colitti3e8b0ac2013-03-03 20:46:46 +00002183 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
2184 (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002185 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07002186 read_unlock_bh(&table->tb6_lock);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002187 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 goto restart;
2189 }
2190 }
Thomas Grafc71099a2006-08-04 23:20:06 -07002191 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192}
2193
Daniel Lezcano55786892008-03-04 13:47:47 -08002194static void rtmsg_to_fib6_config(struct net *net,
2195 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07002196 struct fib6_config *cfg)
2197{
2198 memset(cfg, 0, sizeof(*cfg));
2199
2200 cfg->fc_table = RT6_TABLE_MAIN;
2201 cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
2202 cfg->fc_metric = rtmsg->rtmsg_metric;
2203 cfg->fc_expires = rtmsg->rtmsg_info;
2204 cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
2205 cfg->fc_src_len = rtmsg->rtmsg_src_len;
2206 cfg->fc_flags = rtmsg->rtmsg_flags;
2207
Daniel Lezcano55786892008-03-04 13:47:47 -08002208 cfg->fc_nlinfo.nl_net = net;
Benjamin Theryf1243c22008-02-26 18:10:03 -08002209
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002210 cfg->fc_dst = rtmsg->rtmsg_dst;
2211 cfg->fc_src = rtmsg->rtmsg_src;
2212 cfg->fc_gateway = rtmsg->rtmsg_gateway;
Thomas Graf86872cb2006-08-22 00:01:08 -07002213}
2214
Daniel Lezcano55786892008-03-04 13:47:47 -08002215int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216{
Thomas Graf86872cb2006-08-22 00:01:08 -07002217 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 struct in6_rtmsg rtmsg;
2219 int err;
2220
Ian Morris67ba4152014-08-24 21:53:10 +01002221 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 case SIOCADDRT: /* Add a route */
2223 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00002224 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 return -EPERM;
2226 err = copy_from_user(&rtmsg, arg,
2227 sizeof(struct in6_rtmsg));
2228 if (err)
2229 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07002230
Daniel Lezcano55786892008-03-04 13:47:47 -08002231 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07002232
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 rtnl_lock();
2234 switch (cmd) {
2235 case SIOCADDRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07002236 err = ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 break;
2238 case SIOCDELRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07002239 err = ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 break;
2241 default:
2242 err = -EINVAL;
2243 }
2244 rtnl_unlock();
2245
2246 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07002247 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248
2249 return -EINVAL;
2250}
2251
2252/*
2253 * Drop the packet on the floor
2254 */
2255
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07002256static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002258 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00002259 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002260 switch (ipstats_mib_noroutes) {
2261 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07002262 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00002263 if (type == IPV6_ADDR_ANY) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002264 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2265 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002266 break;
2267 }
2268 /* FALLTHROUGH */
2269 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002270 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2271 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002272 break;
2273 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002274 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 kfree_skb(skb);
2276 return 0;
2277}
2278
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002279static int ip6_pkt_discard(struct sk_buff *skb)
2280{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002281 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002282}
2283
Eric Dumazetaad88722014-04-15 13:47:15 -04002284static int ip6_pkt_discard_out(struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285{
Eric Dumazetadf30902009-06-02 05:19:30 +00002286 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002287 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288}
2289
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002290static int ip6_pkt_prohibit(struct sk_buff *skb)
2291{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002292 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002293}
2294
Eric Dumazetaad88722014-04-15 13:47:15 -04002295static int ip6_pkt_prohibit_out(struct sock *sk, struct sk_buff *skb)
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002296{
Eric Dumazetadf30902009-06-02 05:19:30 +00002297 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002298 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002299}
2300
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301/*
2302 * Allocate a dst for local (unicast / anycast) address.
2303 */
2304
2305struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
2306 const struct in6_addr *addr,
David S. Miller8f031512011-12-06 16:48:14 -05002307 bool anycast)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002309 struct net *net = dev_net(idev->dev);
Hannes Frederic Sowaa3300ef2013-12-07 03:33:45 +01002310 struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev,
2311 DST_NOCOUNT, NULL);
2312 if (!rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 return ERR_PTR(-ENOMEM);
2314
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 in6_dev_hold(idev);
2316
David S. Miller11d53b42011-06-24 15:23:34 -07002317 rt->dst.flags |= DST_HOST;
Changli Gaod8d1f302010-06-10 23:31:35 -07002318 rt->dst.input = ip6_input;
2319 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 rt->rt6i_idev = idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321
2322 rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +09002323 if (anycast)
2324 rt->rt6i_flags |= RTF_ANYCAST;
2325 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 rt->rt6i_flags |= RTF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327
Julian Anastasov550bab42013-10-20 15:43:04 +03002328 rt->rt6i_gateway = *addr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002329 rt->rt6i_dst.addr = *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 rt->rt6i_dst.plen = 128;
Daniel Lezcano55786892008-03-04 13:47:47 -08002331 rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332
Changli Gaod8d1f302010-06-10 23:31:35 -07002333 atomic_set(&rt->dst.__refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334
2335 return rt;
2336}
2337
Daniel Walterc3968a82011-04-13 21:10:57 +00002338int ip6_route_get_saddr(struct net *net,
2339 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002340 const struct in6_addr *daddr,
Daniel Walterc3968a82011-04-13 21:10:57 +00002341 unsigned int prefs,
2342 struct in6_addr *saddr)
2343{
Markus Stenberge16e8882015-05-05 13:36:59 +03002344 struct inet6_dev *idev =
2345 rt ? ip6_dst_idev((struct dst_entry *)rt) : NULL;
Daniel Walterc3968a82011-04-13 21:10:57 +00002346 int err = 0;
Markus Stenberge16e8882015-05-05 13:36:59 +03002347 if (rt && rt->rt6i_prefsrc.plen)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002348 *saddr = rt->rt6i_prefsrc.addr;
Daniel Walterc3968a82011-04-13 21:10:57 +00002349 else
2350 err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
2351 daddr, prefs, saddr);
2352 return err;
2353}
2354
2355/* remove deleted ip from prefsrc entries */
2356struct arg_dev_net_ip {
2357 struct net_device *dev;
2358 struct net *net;
2359 struct in6_addr *addr;
2360};
2361
2362static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
2363{
2364 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
2365 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
2366 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
2367
David S. Millerd1918542011-12-28 20:19:20 -05002368 if (((void *)rt->dst.dev == dev || !dev) &&
Daniel Walterc3968a82011-04-13 21:10:57 +00002369 rt != net->ipv6.ip6_null_entry &&
2370 ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
2371 /* remove prefsrc entry */
2372 rt->rt6i_prefsrc.plen = 0;
2373 }
2374 return 0;
2375}
2376
2377void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
2378{
2379 struct net *net = dev_net(ifp->idev->dev);
2380 struct arg_dev_net_ip adni = {
2381 .dev = ifp->idev->dev,
2382 .net = net,
2383 .addr = &ifp->addr,
2384 };
Li RongQing0c3584d2013-12-27 16:32:38 +08002385 fib6_clean_all(net, fib6_remove_prefsrc, &adni);
Daniel Walterc3968a82011-04-13 21:10:57 +00002386}
2387
Duan Jiongbe7a0102014-05-15 15:56:14 +08002388#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY)
2389#define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE)
2390
2391/* Remove routers and update dst entries when gateway turn into host. */
2392static int fib6_clean_tohost(struct rt6_info *rt, void *arg)
2393{
2394 struct in6_addr *gateway = (struct in6_addr *)arg;
2395
2396 if ((((rt->rt6i_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) ||
2397 ((rt->rt6i_flags & RTF_CACHE_GATEWAY) == RTF_CACHE_GATEWAY)) &&
2398 ipv6_addr_equal(gateway, &rt->rt6i_gateway)) {
2399 return -1;
2400 }
2401 return 0;
2402}
2403
2404void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
2405{
2406 fib6_clean_all(net, fib6_clean_tohost, gateway);
2407}
2408
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002409struct arg_dev_net {
2410 struct net_device *dev;
2411 struct net *net;
2412};
2413
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414static int fib6_ifdown(struct rt6_info *rt, void *arg)
2415{
stephen hemmingerbc3ef662010-12-16 17:42:40 +00002416 const struct arg_dev_net *adn = arg;
2417 const struct net_device *dev = adn->dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002418
David S. Millerd1918542011-12-28 20:19:20 -05002419 if ((rt->dst.dev == dev || !dev) &&
David S. Millerc159d302011-12-26 15:24:36 -05002420 rt != adn->net->ipv6.ip6_null_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 return -1;
David S. Millerc159d302011-12-26 15:24:36 -05002422
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 return 0;
2424}
2425
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002426void rt6_ifdown(struct net *net, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002428 struct arg_dev_net adn = {
2429 .dev = dev,
2430 .net = net,
2431 };
2432
Li RongQing0c3584d2013-12-27 16:32:38 +08002433 fib6_clean_all(net, fib6_ifdown, &adn);
David S. Miller1e493d12008-09-10 17:27:15 -07002434 icmp6_clean_all(fib6_ifdown, &adn);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07002435 rt6_uncached_list_flush_dev(net, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436}
2437
Eric Dumazet95c96172012-04-15 05:58:06 +00002438struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00002440 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441};
2442
2443static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
2444{
2445 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
2446 struct inet6_dev *idev;
2447
2448 /* In IPv6 pmtu discovery is not optional,
2449 so that RTAX_MTU lock cannot disable it.
2450 We still use this lock to block changes
2451 caused by addrconf/ndisc.
2452 */
2453
2454 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05002455 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 return 0;
2457
2458 /* For administrative MTU increase, there is no way to discover
2459 IPv6 PMTU increase, so PMTU increase should be updated here.
2460 Since RFC 1981 doesn't include administrative MTU increase
2461 update PMTU increase is a MUST. (i.e. jumbo frame)
2462 */
2463 /*
2464 If new MTU is less than route PMTU, this new MTU will be the
2465 lowest MTU in the path, update the route PMTU to reflect PMTU
2466 decreases; if new MTU is greater than route PMTU, and the
2467 old MTU is the lowest MTU in the path, update the route PMTU
2468 to reflect the increase. In this case if the other nodes' MTU
2469 also have the lowest MTU, TOO BIG MESSAGE will be lead to
2470 PMTU discouvery.
2471 */
David S. Millerd1918542011-12-28 20:19:20 -05002472 if (rt->dst.dev == arg->dev &&
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002473 !dst_metric_locked(&rt->dst, RTAX_MTU)) {
2474 if (rt->rt6i_flags & RTF_CACHE) {
2475 /* For RTF_CACHE with rt6i_pmtu == 0
2476 * (i.e. a redirected route),
2477 * the metrics of its rt->dst.from has already
2478 * been updated.
2479 */
2480 if (rt->rt6i_pmtu && rt->rt6i_pmtu > arg->mtu)
2481 rt->rt6i_pmtu = arg->mtu;
2482 } else if (dst_mtu(&rt->dst) >= arg->mtu ||
2483 (dst_mtu(&rt->dst) < arg->mtu &&
2484 dst_mtu(&rt->dst) == idev->cnf.mtu6)) {
2485 dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu);
2486 }
Simon Arlott566cfd82007-07-26 00:09:55 -07002487 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 return 0;
2489}
2490
Eric Dumazet95c96172012-04-15 05:58:06 +00002491void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492{
Thomas Grafc71099a2006-08-04 23:20:06 -07002493 struct rt6_mtu_change_arg arg = {
2494 .dev = dev,
2495 .mtu = mtu,
2496 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497
Li RongQing0c3584d2013-12-27 16:32:38 +08002498 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499}
2500
Patrick McHardyef7c79e2007-06-05 12:38:30 -07002501static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07002502 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07002503 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07002504 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002505 [RTA_PRIORITY] = { .type = NLA_U32 },
2506 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002507 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002508 [RTA_PREF] = { .type = NLA_U8 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002509};
2510
2511static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
2512 struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513{
Thomas Graf86872cb2006-08-22 00:01:08 -07002514 struct rtmsg *rtm;
2515 struct nlattr *tb[RTA_MAX+1];
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002516 unsigned int pref;
Thomas Graf86872cb2006-08-22 00:01:08 -07002517 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518
Thomas Graf86872cb2006-08-22 00:01:08 -07002519 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2520 if (err < 0)
2521 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522
Thomas Graf86872cb2006-08-22 00:01:08 -07002523 err = -EINVAL;
2524 rtm = nlmsg_data(nlh);
2525 memset(cfg, 0, sizeof(*cfg));
2526
2527 cfg->fc_table = rtm->rtm_table;
2528 cfg->fc_dst_len = rtm->rtm_dst_len;
2529 cfg->fc_src_len = rtm->rtm_src_len;
2530 cfg->fc_flags = RTF_UP;
2531 cfg->fc_protocol = rtm->rtm_protocol;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002532 cfg->fc_type = rtm->rtm_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07002533
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002534 if (rtm->rtm_type == RTN_UNREACHABLE ||
2535 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002536 rtm->rtm_type == RTN_PROHIBIT ||
2537 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07002538 cfg->fc_flags |= RTF_REJECT;
2539
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002540 if (rtm->rtm_type == RTN_LOCAL)
2541 cfg->fc_flags |= RTF_LOCAL;
2542
Martin KaFai Lau1f56a012015-04-28 13:03:03 -07002543 if (rtm->rtm_flags & RTM_F_CLONED)
2544 cfg->fc_flags |= RTF_CACHE;
2545
Eric W. Biederman15e47302012-09-07 20:12:54 +00002546 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
Thomas Graf86872cb2006-08-22 00:01:08 -07002547 cfg->fc_nlinfo.nlh = nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002548 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
Thomas Graf86872cb2006-08-22 00:01:08 -07002549
2550 if (tb[RTA_GATEWAY]) {
Jiri Benc67b61f62015-03-29 16:59:26 +02002551 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
Thomas Graf86872cb2006-08-22 00:01:08 -07002552 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002554
2555 if (tb[RTA_DST]) {
2556 int plen = (rtm->rtm_dst_len + 7) >> 3;
2557
2558 if (nla_len(tb[RTA_DST]) < plen)
2559 goto errout;
2560
2561 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002563
2564 if (tb[RTA_SRC]) {
2565 int plen = (rtm->rtm_src_len + 7) >> 3;
2566
2567 if (nla_len(tb[RTA_SRC]) < plen)
2568 goto errout;
2569
2570 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002572
Daniel Walterc3968a82011-04-13 21:10:57 +00002573 if (tb[RTA_PREFSRC])
Jiri Benc67b61f62015-03-29 16:59:26 +02002574 cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]);
Daniel Walterc3968a82011-04-13 21:10:57 +00002575
Thomas Graf86872cb2006-08-22 00:01:08 -07002576 if (tb[RTA_OIF])
2577 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
2578
2579 if (tb[RTA_PRIORITY])
2580 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
2581
2582 if (tb[RTA_METRICS]) {
2583 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
2584 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002586
2587 if (tb[RTA_TABLE])
2588 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
2589
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002590 if (tb[RTA_MULTIPATH]) {
2591 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
2592 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
2593 }
2594
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002595 if (tb[RTA_PREF]) {
2596 pref = nla_get_u8(tb[RTA_PREF]);
2597 if (pref != ICMPV6_ROUTER_PREF_LOW &&
2598 pref != ICMPV6_ROUTER_PREF_HIGH)
2599 pref = ICMPV6_ROUTER_PREF_MEDIUM;
2600 cfg->fc_flags |= RTF_PREF(pref);
2601 }
2602
Thomas Graf86872cb2006-08-22 00:01:08 -07002603 err = 0;
2604errout:
2605 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606}
2607
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002608static int ip6_route_multipath(struct fib6_config *cfg, int add)
2609{
2610 struct fib6_config r_cfg;
2611 struct rtnexthop *rtnh;
2612 int remaining;
2613 int attrlen;
2614 int err = 0, last_err = 0;
2615
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02002616 remaining = cfg->fc_mp_len;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002617beginning:
2618 rtnh = (struct rtnexthop *)cfg->fc_mp;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002619
2620 /* Parse a Multipath Entry */
2621 while (rtnh_ok(rtnh, remaining)) {
2622 memcpy(&r_cfg, cfg, sizeof(*cfg));
2623 if (rtnh->rtnh_ifindex)
2624 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
2625
2626 attrlen = rtnh_attrlen(rtnh);
2627 if (attrlen > 0) {
2628 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
2629
2630 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
2631 if (nla) {
Jiri Benc67b61f62015-03-29 16:59:26 +02002632 r_cfg.fc_gateway = nla_get_in6_addr(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002633 r_cfg.fc_flags |= RTF_GATEWAY;
2634 }
2635 }
2636 err = add ? ip6_route_add(&r_cfg) : ip6_route_del(&r_cfg);
2637 if (err) {
2638 last_err = err;
2639 /* If we are trying to remove a route, do not stop the
2640 * loop when ip6_route_del() fails (because next hop is
2641 * already gone), we should try to remove all next hops.
2642 */
2643 if (add) {
2644 /* If add fails, we should try to delete all
2645 * next hops that have been already added.
2646 */
2647 add = 0;
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02002648 remaining = cfg->fc_mp_len - remaining;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002649 goto beginning;
2650 }
2651 }
Nicolas Dichtel1a724182012-11-01 22:58:22 +00002652 /* Because each route is added like a single route we remove
Michal Kubeček27596472015-05-18 20:54:00 +02002653 * these flags after the first nexthop: if there is a collision,
2654 * we have already failed to add the first nexthop:
2655 * fib6_add_rt2node() has rejected it; when replacing, old
2656 * nexthops have been replaced by first new, the rest should
2657 * be added to it.
Nicolas Dichtel1a724182012-11-01 22:58:22 +00002658 */
Michal Kubeček27596472015-05-18 20:54:00 +02002659 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
2660 NLM_F_REPLACE);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002661 rtnh = rtnh_next(rtnh, &remaining);
2662 }
2663
2664 return last_err;
2665}
2666
Ian Morris67ba4152014-08-24 21:53:10 +01002667static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668{
Thomas Graf86872cb2006-08-22 00:01:08 -07002669 struct fib6_config cfg;
2670 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671
Thomas Graf86872cb2006-08-22 00:01:08 -07002672 err = rtm_to_fib6_config(skb, nlh, &cfg);
2673 if (err < 0)
2674 return err;
2675
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002676 if (cfg.fc_mp)
2677 return ip6_route_multipath(&cfg, 0);
2678 else
2679 return ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680}
2681
Ian Morris67ba4152014-08-24 21:53:10 +01002682static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683{
Thomas Graf86872cb2006-08-22 00:01:08 -07002684 struct fib6_config cfg;
2685 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686
Thomas Graf86872cb2006-08-22 00:01:08 -07002687 err = rtm_to_fib6_config(skb, nlh, &cfg);
2688 if (err < 0)
2689 return err;
2690
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002691 if (cfg.fc_mp)
2692 return ip6_route_multipath(&cfg, 1);
2693 else
2694 return ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695}
2696
Thomas Graf339bf982006-11-10 14:10:15 -08002697static inline size_t rt6_nlmsg_size(void)
2698{
2699 return NLMSG_ALIGN(sizeof(struct rtmsg))
2700 + nla_total_size(16) /* RTA_SRC */
2701 + nla_total_size(16) /* RTA_DST */
2702 + nla_total_size(16) /* RTA_GATEWAY */
2703 + nla_total_size(16) /* RTA_PREFSRC */
2704 + nla_total_size(4) /* RTA_TABLE */
2705 + nla_total_size(4) /* RTA_IIF */
2706 + nla_total_size(4) /* RTA_OIF */
2707 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08002708 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Daniel Borkmannea697632015-01-05 23:57:47 +01002709 + nla_total_size(sizeof(struct rta_cacheinfo))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002710 + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
2711 + nla_total_size(1); /* RTA_PREF */
Thomas Graf339bf982006-11-10 14:10:15 -08002712}
2713
Brian Haley191cd582008-08-14 15:33:21 -07002714static int rt6_fill_node(struct net *net,
2715 struct sk_buff *skb, struct rt6_info *rt,
Jamal Hadi Salim0d51aa82005-06-21 13:51:04 -07002716 struct in6_addr *dst, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002717 int iif, int type, u32 portid, u32 seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002718 int prefix, int nowait, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002720 u32 metrics[RTAX_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 struct rtmsg *rtm;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002722 struct nlmsghdr *nlh;
Thomas Grafe3703b32006-11-27 09:27:07 -08002723 long expires;
Patrick McHardy9e762a42006-08-10 23:09:48 -07002724 u32 table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725
2726 if (prefix) { /* user wants prefix routes only */
2727 if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
2728 /* success since this is not a prefix route */
2729 return 1;
2730 }
2731 }
2732
Eric W. Biederman15e47302012-09-07 20:12:54 +00002733 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05002734 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08002735 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002736
2737 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 rtm->rtm_family = AF_INET6;
2739 rtm->rtm_dst_len = rt->rt6i_dst.plen;
2740 rtm->rtm_src_len = rt->rt6i_src.plen;
2741 rtm->rtm_tos = 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07002742 if (rt->rt6i_table)
Patrick McHardy9e762a42006-08-10 23:09:48 -07002743 table = rt->rt6i_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07002744 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07002745 table = RT6_TABLE_UNSPEC;
2746 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04002747 if (nla_put_u32(skb, RTA_TABLE, table))
2748 goto nla_put_failure;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002749 if (rt->rt6i_flags & RTF_REJECT) {
2750 switch (rt->dst.error) {
2751 case -EINVAL:
2752 rtm->rtm_type = RTN_BLACKHOLE;
2753 break;
2754 case -EACCES:
2755 rtm->rtm_type = RTN_PROHIBIT;
2756 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002757 case -EAGAIN:
2758 rtm->rtm_type = RTN_THROW;
2759 break;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002760 default:
2761 rtm->rtm_type = RTN_UNREACHABLE;
2762 break;
2763 }
2764 }
David S. Miller38308472011-12-03 18:02:47 -05002765 else if (rt->rt6i_flags & RTF_LOCAL)
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002766 rtm->rtm_type = RTN_LOCAL;
David S. Millerd1918542011-12-28 20:19:20 -05002767 else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 rtm->rtm_type = RTN_LOCAL;
2769 else
2770 rtm->rtm_type = RTN_UNICAST;
2771 rtm->rtm_flags = 0;
2772 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
2773 rtm->rtm_protocol = rt->rt6i_protocol;
David S. Miller38308472011-12-03 18:02:47 -05002774 if (rt->rt6i_flags & RTF_DYNAMIC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 rtm->rtm_protocol = RTPROT_REDIRECT;
Denis Ovsienkof0396f602012-07-10 04:45:50 +00002776 else if (rt->rt6i_flags & RTF_ADDRCONF) {
2777 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ROUTEINFO))
2778 rtm->rtm_protocol = RTPROT_RA;
2779 else
2780 rtm->rtm_protocol = RTPROT_KERNEL;
2781 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782
David S. Miller38308472011-12-03 18:02:47 -05002783 if (rt->rt6i_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 rtm->rtm_flags |= RTM_F_CLONED;
2785
2786 if (dst) {
Jiri Benc930345e2015-03-29 16:59:25 +02002787 if (nla_put_in6_addr(skb, RTA_DST, dst))
David S. Millerc78679e2012-04-01 20:27:33 -04002788 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002789 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 } else if (rtm->rtm_dst_len)
Jiri Benc930345e2015-03-29 16:59:25 +02002791 if (nla_put_in6_addr(skb, RTA_DST, &rt->rt6i_dst.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04002792 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793#ifdef CONFIG_IPV6_SUBTREES
2794 if (src) {
Jiri Benc930345e2015-03-29 16:59:25 +02002795 if (nla_put_in6_addr(skb, RTA_SRC, src))
David S. Millerc78679e2012-04-01 20:27:33 -04002796 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002797 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04002798 } else if (rtm->rtm_src_len &&
Jiri Benc930345e2015-03-29 16:59:25 +02002799 nla_put_in6_addr(skb, RTA_SRC, &rt->rt6i_src.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04002800 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002802 if (iif) {
2803#ifdef CONFIG_IPV6_MROUTE
2804 if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
Benjamin Thery8229efd2008-12-10 16:30:15 -08002805 int err = ip6mr_get_route(net, skb, rtm, nowait);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002806 if (err <= 0) {
2807 if (!nowait) {
2808 if (err == 0)
2809 return 0;
2810 goto nla_put_failure;
2811 } else {
2812 if (err == -EMSGSIZE)
2813 goto nla_put_failure;
2814 }
2815 }
2816 } else
2817#endif
David S. Millerc78679e2012-04-01 20:27:33 -04002818 if (nla_put_u32(skb, RTA_IIF, iif))
2819 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002820 } else if (dst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 struct in6_addr saddr_buf;
David S. Millerc78679e2012-04-01 20:27:33 -04002822 if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0 &&
Jiri Benc930345e2015-03-29 16:59:25 +02002823 nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04002824 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07002826
Daniel Walterc3968a82011-04-13 21:10:57 +00002827 if (rt->rt6i_prefsrc.plen) {
2828 struct in6_addr saddr_buf;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002829 saddr_buf = rt->rt6i_prefsrc.addr;
Jiri Benc930345e2015-03-29 16:59:25 +02002830 if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04002831 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00002832 }
2833
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002834 memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics));
2835 if (rt->rt6i_pmtu)
2836 metrics[RTAX_MTU - 1] = rt->rt6i_pmtu;
2837 if (rtnetlink_put_metrics(skb, metrics) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07002838 goto nla_put_failure;
2839
YOSHIFUJI Hideaki / 吉藤英明dd0cbf22013-01-17 12:53:15 +00002840 if (rt->rt6i_flags & RTF_GATEWAY) {
Jiri Benc930345e2015-03-29 16:59:25 +02002841 if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->rt6i_gateway) < 0)
Eric Dumazet94f826b2012-03-27 09:53:52 +00002842 goto nla_put_failure;
Eric Dumazet94f826b2012-03-27 09:53:52 +00002843 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07002844
David S. Millerc78679e2012-04-01 20:27:33 -04002845 if (rt->dst.dev &&
2846 nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex))
2847 goto nla_put_failure;
2848 if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric))
2849 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00002850
2851 expires = (rt->rt6i_flags & RTF_EXPIRES) ? rt->dst.expires - jiffies : 0;
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07002852
David S. Miller87a50692012-07-10 05:06:14 -07002853 if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, rt->dst.error) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08002854 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002856 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags)))
2857 goto nla_put_failure;
2858
Johannes Berg053c0952015-01-16 22:09:00 +01002859 nlmsg_end(skb, nlh);
2860 return 0;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002861
2862nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002863 nlmsg_cancel(skb, nlh);
2864 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865}
2866
Patrick McHardy1b43af52006-08-10 23:11:17 -07002867int rt6_dump_route(struct rt6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868{
2869 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
2870 int prefix;
2871
Thomas Graf2d7202b2006-08-22 00:01:27 -07002872 if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
2873 struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0;
2875 } else
2876 prefix = 0;
2877
Brian Haley191cd582008-08-14 15:33:21 -07002878 return rt6_fill_node(arg->net,
2879 arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002880 NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002881 prefix, 0, NLM_F_MULTI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882}
2883
Ian Morris67ba4152014-08-24 21:53:10 +01002884static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002886 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07002887 struct nlattr *tb[RTA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07002889 struct sk_buff *skb;
2890 struct rtmsg *rtm;
David S. Miller4c9483b2011-03-12 16:22:43 -05002891 struct flowi6 fl6;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002892 int err, iif = 0, oif = 0;
Thomas Grafab364a62006-08-22 00:01:47 -07002893
2894 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2895 if (err < 0)
2896 goto errout;
2897
2898 err = -EINVAL;
David S. Miller4c9483b2011-03-12 16:22:43 -05002899 memset(&fl6, 0, sizeof(fl6));
Thomas Grafab364a62006-08-22 00:01:47 -07002900
2901 if (tb[RTA_SRC]) {
2902 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
2903 goto errout;
2904
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002905 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07002906 }
2907
2908 if (tb[RTA_DST]) {
2909 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
2910 goto errout;
2911
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002912 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07002913 }
2914
2915 if (tb[RTA_IIF])
2916 iif = nla_get_u32(tb[RTA_IIF]);
2917
2918 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002919 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07002920
Lorenzo Colitti2e47b292014-05-15 16:38:41 -07002921 if (tb[RTA_MARK])
2922 fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
2923
Thomas Grafab364a62006-08-22 00:01:47 -07002924 if (iif) {
2925 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002926 int flags = 0;
2927
Daniel Lezcano55786892008-03-04 13:47:47 -08002928 dev = __dev_get_by_index(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07002929 if (!dev) {
2930 err = -ENODEV;
2931 goto errout;
2932 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002933
2934 fl6.flowi6_iif = iif;
2935
2936 if (!ipv6_addr_any(&fl6.saddr))
2937 flags |= RT6_LOOKUP_F_HAS_SADDR;
2938
2939 rt = (struct rt6_info *)ip6_route_input_lookup(net, dev, &fl6,
2940 flags);
2941 } else {
2942 fl6.flowi6_oif = oif;
2943
2944 rt = (struct rt6_info *)ip6_route_output(net, NULL, &fl6);
Thomas Grafab364a62006-08-22 00:01:47 -07002945 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946
2947 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05002948 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00002949 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07002950 err = -ENOBUFS;
2951 goto errout;
2952 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953
2954 /* Reserve room for dummy headers, this skb can pass
2955 through good chunk of routing engine.
2956 */
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07002957 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
2959
Changli Gaod8d1f302010-06-10 23:31:35 -07002960 skb_dst_set(skb, &rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961
David S. Miller4c9483b2011-03-12 16:22:43 -05002962 err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002963 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002964 nlh->nlmsg_seq, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07002966 kfree_skb(skb);
2967 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 }
2969
Eric W. Biederman15e47302012-09-07 20:12:54 +00002970 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07002971errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973}
2974
Thomas Graf86872cb2006-08-22 00:01:08 -07002975void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976{
2977 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08002978 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002979 u32 seq;
2980 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002982 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05002983 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07002984
Thomas Graf339bf982006-11-10 14:10:15 -08002985 skb = nlmsg_new(rt6_nlmsg_size(), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05002986 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07002987 goto errout;
2988
Brian Haley191cd582008-08-14 15:33:21 -07002989 err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002990 event, info->portid, seq, 0, 0, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08002991 if (err < 0) {
2992 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
2993 WARN_ON(err == -EMSGSIZE);
2994 kfree_skb(skb);
2995 goto errout;
2996 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00002997 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08002998 info->nlh, gfp_any());
2999 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07003000errout:
3001 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08003002 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003}
3004
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003005static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00003006 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003007{
Jiri Pirko351638e2013-05-28 01:30:21 +00003008 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09003009 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003010
3011 if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07003012 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003013 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
3014#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07003015 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003016 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07003017 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003018 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
3019#endif
3020 }
3021
3022 return NOTIFY_OK;
3023}
3024
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025/*
3026 * /proc
3027 */
3028
3029#ifdef CONFIG_PROC_FS
3030
Alexey Dobriyan33120b32007-11-06 05:27:11 -08003031static const struct file_operations ipv6_route_proc_fops = {
3032 .owner = THIS_MODULE,
3033 .open = ipv6_route_open,
3034 .read = seq_read,
3035 .llseek = seq_lseek,
Hannes Frederic Sowa8d2ca1d2013-09-21 16:55:59 +02003036 .release = seq_release_net,
Alexey Dobriyan33120b32007-11-06 05:27:11 -08003037};
3038
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039static int rt6_stats_seq_show(struct seq_file *seq, void *v)
3040{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003041 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003043 net->ipv6.rt6_stats->fib_nodes,
3044 net->ipv6.rt6_stats->fib_route_nodes,
3045 net->ipv6.rt6_stats->fib_rt_alloc,
3046 net->ipv6.rt6_stats->fib_rt_entries,
3047 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00003048 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003049 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050
3051 return 0;
3052}
3053
3054static int rt6_stats_seq_open(struct inode *inode, struct file *file)
3055{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07003056 return single_open_net(inode, file, rt6_stats_seq_show);
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003057}
3058
Arjan van de Ven9a321442007-02-12 00:55:35 -08003059static const struct file_operations rt6_stats_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 .owner = THIS_MODULE,
3061 .open = rt6_stats_seq_open,
3062 .read = seq_read,
3063 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07003064 .release = single_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065};
3066#endif /* CONFIG_PROC_FS */
3067
3068#ifdef CONFIG_SYSCTL
3069
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070static
Joe Perchesfe2c6332013-06-11 23:04:25 -07003071int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 void __user *buffer, size_t *lenp, loff_t *ppos)
3073{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003074 struct net *net;
3075 int delay;
3076 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003078
3079 net = (struct net *)ctl->extra1;
3080 delay = net->ipv6.sysctl.flush_delay;
3081 proc_dointvec(ctl, write, buffer, lenp, ppos);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02003082 fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003083 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084}
3085
Joe Perchesfe2c6332013-06-11 23:04:25 -07003086struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003087 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08003089 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07003091 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003092 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 },
3094 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003096 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 .maxlen = sizeof(int),
3098 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003099 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 },
3101 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08003103 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 .maxlen = sizeof(int),
3105 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003106 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107 },
3108 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08003110 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 .maxlen = sizeof(int),
3112 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003113 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 },
3115 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08003117 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 .maxlen = sizeof(int),
3119 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003120 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 },
3122 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08003124 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 .maxlen = sizeof(int),
3126 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003127 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 },
3129 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08003131 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 .maxlen = sizeof(int),
3133 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003134 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 },
3136 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08003138 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 .maxlen = sizeof(int),
3140 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003141 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 },
3143 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08003145 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 .maxlen = sizeof(int),
3147 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003148 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 },
3150 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08003152 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 .maxlen = sizeof(int),
3154 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003155 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08003157 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158};
3159
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003160struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003161{
3162 struct ctl_table *table;
3163
3164 table = kmemdup(ipv6_route_table_template,
3165 sizeof(ipv6_route_table_template),
3166 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003167
3168 if (table) {
3169 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003170 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003171 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003172 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
3173 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
3174 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
3175 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
3176 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
3177 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
3178 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08003179 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
Eric W. Biederman464dc802012-11-16 03:02:59 +00003180
3181 /* Don't export sysctls to unprivileged users */
3182 if (net->user_ns != &init_user_ns)
3183 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003184 }
3185
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003186 return table;
3187}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188#endif
3189
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003190static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003191{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07003192 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003193
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003194 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
3195 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003196
Eric Dumazetfc66f952010-10-08 06:37:34 +00003197 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
3198 goto out_ip6_dst_ops;
3199
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003200 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
3201 sizeof(*net->ipv6.ip6_null_entry),
3202 GFP_KERNEL);
3203 if (!net->ipv6.ip6_null_entry)
Eric Dumazetfc66f952010-10-08 06:37:34 +00003204 goto out_ip6_dst_entries;
Changli Gaod8d1f302010-06-10 23:31:35 -07003205 net->ipv6.ip6_null_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003206 (struct dst_entry *)net->ipv6.ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003207 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003208 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
3209 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003210
3211#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3212 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
3213 sizeof(*net->ipv6.ip6_prohibit_entry),
3214 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003215 if (!net->ipv6.ip6_prohibit_entry)
3216 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003217 net->ipv6.ip6_prohibit_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003218 (struct dst_entry *)net->ipv6.ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003219 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003220 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
3221 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003222
3223 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
3224 sizeof(*net->ipv6.ip6_blk_hole_entry),
3225 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003226 if (!net->ipv6.ip6_blk_hole_entry)
3227 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003228 net->ipv6.ip6_blk_hole_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003229 (struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003230 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003231 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
3232 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003233#endif
3234
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07003235 net->ipv6.sysctl.flush_delay = 0;
3236 net->ipv6.sysctl.ip6_rt_max_size = 4096;
3237 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
3238 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
3239 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
3240 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
3241 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
3242 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
3243
Benjamin Thery6891a342008-03-04 13:49:47 -08003244 net->ipv6.ip6_rt_gc_expire = 30*HZ;
3245
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003246 ret = 0;
3247out:
3248 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003249
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003250#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3251out_ip6_prohibit_entry:
3252 kfree(net->ipv6.ip6_prohibit_entry);
3253out_ip6_null_entry:
3254 kfree(net->ipv6.ip6_null_entry);
3255#endif
Eric Dumazetfc66f952010-10-08 06:37:34 +00003256out_ip6_dst_entries:
3257 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003258out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003259 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003260}
3261
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003262static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003263{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003264 kfree(net->ipv6.ip6_null_entry);
3265#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3266 kfree(net->ipv6.ip6_prohibit_entry);
3267 kfree(net->ipv6.ip6_blk_hole_entry);
3268#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003269 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003270}
3271
Thomas Grafd1896342012-06-18 12:08:33 +00003272static int __net_init ip6_route_net_init_late(struct net *net)
3273{
3274#ifdef CONFIG_PROC_FS
Gao fengd4beaa62013-02-18 01:34:54 +00003275 proc_create("ipv6_route", 0, net->proc_net, &ipv6_route_proc_fops);
3276 proc_create("rt6_stats", S_IRUGO, net->proc_net, &rt6_stats_seq_fops);
Thomas Grafd1896342012-06-18 12:08:33 +00003277#endif
3278 return 0;
3279}
3280
3281static void __net_exit ip6_route_net_exit_late(struct net *net)
3282{
3283#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00003284 remove_proc_entry("ipv6_route", net->proc_net);
3285 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00003286#endif
3287}
3288
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003289static struct pernet_operations ip6_route_net_ops = {
3290 .init = ip6_route_net_init,
3291 .exit = ip6_route_net_exit,
3292};
3293
David S. Millerc3426b42012-06-09 16:27:05 -07003294static int __net_init ipv6_inetpeer_init(struct net *net)
3295{
3296 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
3297
3298 if (!bp)
3299 return -ENOMEM;
3300 inet_peer_base_init(bp);
3301 net->ipv6.peers = bp;
3302 return 0;
3303}
3304
3305static void __net_exit ipv6_inetpeer_exit(struct net *net)
3306{
3307 struct inet_peer_base *bp = net->ipv6.peers;
3308
3309 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07003310 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07003311 kfree(bp);
3312}
3313
David S. Miller2b823f72012-06-09 19:00:16 -07003314static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07003315 .init = ipv6_inetpeer_init,
3316 .exit = ipv6_inetpeer_exit,
3317};
3318
Thomas Grafd1896342012-06-18 12:08:33 +00003319static struct pernet_operations ip6_route_net_late_ops = {
3320 .init = ip6_route_net_init_late,
3321 .exit = ip6_route_net_exit_late,
3322};
3323
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003324static struct notifier_block ip6_route_dev_notifier = {
3325 .notifier_call = ip6_route_dev_notify,
3326 .priority = 0,
3327};
3328
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003329int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003331 int ret;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07003332 int cpu;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003333
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003334 ret = -ENOMEM;
3335 ip6_dst_ops_template.kmem_cachep =
3336 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
3337 SLAB_HWCACHE_ALIGN, NULL);
3338 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08003339 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07003340
Eric Dumazetfc66f952010-10-08 06:37:34 +00003341 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003342 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003343 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003344
David S. Millerc3426b42012-06-09 16:27:05 -07003345 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
3346 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003347 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00003348
David S. Miller7e52b332012-06-15 15:51:55 -07003349 ret = register_pernet_subsys(&ip6_route_net_ops);
3350 if (ret)
3351 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07003352
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07003353 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
3354
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003355 /* Registering of the loopback is done before this portion of code,
3356 * the loopback reference in rt6_info will not be taken, do it
3357 * manually for init_net */
Changli Gaod8d1f302010-06-10 23:31:35 -07003358 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003359 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3360 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07003361 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003362 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07003363 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003364 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3365 #endif
David S. Millere8803b62012-06-16 01:12:19 -07003366 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003367 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003368 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003369
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003370 ret = xfrm6_init();
3371 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003372 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08003373
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003374 ret = fib6_rules_init();
3375 if (ret)
3376 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08003377
Thomas Grafd1896342012-06-18 12:08:33 +00003378 ret = register_pernet_subsys(&ip6_route_net_late_ops);
3379 if (ret)
3380 goto fib6_rules_init;
3381
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003382 ret = -ENOBUFS;
Greg Rosec7ac8672011-06-10 01:27:09 +00003383 if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) ||
3384 __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) ||
3385 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL))
Thomas Grafd1896342012-06-18 12:08:33 +00003386 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003387
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003388 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003389 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00003390 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003391
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07003392 for_each_possible_cpu(cpu) {
3393 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
3394
3395 INIT_LIST_HEAD(&ul->head);
3396 spin_lock_init(&ul->lock);
3397 }
3398
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003399out:
3400 return ret;
3401
Thomas Grafd1896342012-06-18 12:08:33 +00003402out_register_late_subsys:
3403 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003404fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003405 fib6_rules_cleanup();
3406xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003407 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00003408out_fib6_init:
3409 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003410out_register_subsys:
3411 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07003412out_register_inetpeer:
3413 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00003414out_dst_entries:
3415 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003416out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003417 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003418 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419}
3420
3421void ip6_route_cleanup(void)
3422{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003423 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00003424 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07003425 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07003428 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003429 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003430 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003431 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432}