blob: d3d946773a3e8caa3dddbcdaef222b3bb9efa59e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Linux INET6 implementation
3 * FIB front-end.
4 *
5 * Authors:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09006 * Pedro Roque <roque@di.fc.ul.pt>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
13
14/* Changes:
15 *
16 * YOSHIFUJI Hideaki @USAGI
17 * reworked default router selection.
18 * - respect outgoing interface
19 * - select from (probably) reachable routers (i.e.
20 * routers in REACHABLE, STALE, DELAY or PROBE states).
21 * - always select the same router if it is (probably)
22 * reachable. otherwise, round-robin the list.
YOSHIFUJI Hideakic0bece92006-08-23 17:23:25 -070023 * Ville Nuorvala
24 * Fixed routing subtrees.
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 */
26
Joe Perchesf3213832012-05-15 14:11:53 +000027#define pr_fmt(fmt) "IPv6: " fmt
28
Randy Dunlap4fc268d2006-01-11 12:17:47 -080029#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/errno.h>
Paul Gortmakerbc3b2d72011-07-15 11:47:34 -040031#include <linux/export.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/types.h>
33#include <linux/times.h>
34#include <linux/socket.h>
35#include <linux/sockios.h>
36#include <linux/net.h>
37#include <linux/route.h>
38#include <linux/netdevice.h>
39#include <linux/in6.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090040#include <linux/mroute6.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <linux/if_arp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/proc_fs.h>
44#include <linux/seq_file.h>
Daniel Lezcano5b7c9312008-03-03 23:28:58 -080045#include <linux/nsproxy.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090046#include <linux/slab.h>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020047#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <net/snmp.h>
49#include <net/ipv6.h>
50#include <net/ip6_fib.h>
51#include <net/ip6_route.h>
52#include <net/ndisc.h>
53#include <net/addrconf.h>
54#include <net/tcp.h>
55#include <linux/rtnetlink.h>
56#include <net/dst.h>
Jiri Benc904af042015-08-20 13:56:31 +020057#include <net/dst_metadata.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#include <net/xfrm.h>
Tom Tucker8d717402006-07-30 20:43:36 -070059#include <net/netevent.h>
Thomas Graf21713eb2006-08-15 00:35:24 -070060#include <net/netlink.h>
Nicolas Dichtel51ebd312012-10-22 03:42:09 +000061#include <net/nexthop.h>
Roopa Prabhu19e42e42015-07-21 10:43:48 +020062#include <net/lwtunnel.h>
Jiri Benc904af042015-08-20 13:56:31 +020063#include <net/ip_tunnels.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65#include <asm/uaccess.h>
66
67#ifdef CONFIG_SYSCTL
68#include <linux/sysctl.h>
69#endif
70
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +020071enum rt6_nud_state {
Jiri Benc7e980562013-12-11 13:48:20 +010072 RT6_NUD_FAIL_HARD = -3,
73 RT6_NUD_FAIL_PROBE = -2,
74 RT6_NUD_FAIL_DO_RR = -1,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +020075 RT6_NUD_SUCCEED = 1
76};
77
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -070078static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
David S. Miller0dbaee32010-12-13 12:52:14 -080080static unsigned int ip6_default_advmss(const struct dst_entry *dst);
Steffen Klassertebb762f2011-11-23 02:12:51 +000081static unsigned int ip6_mtu(const struct dst_entry *dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -070082static struct dst_entry *ip6_negative_advice(struct dst_entry *);
83static void ip6_dst_destroy(struct dst_entry *);
84static void ip6_dst_ifdown(struct dst_entry *,
85 struct net_device *dev, int how);
Daniel Lezcano569d3642008-01-18 03:56:57 -080086static int ip6_dst_gc(struct dst_ops *ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087
88static int ip6_pkt_discard(struct sk_buff *skb);
Eric Dumazetaad88722014-04-15 13:47:15 -040089static int ip6_pkt_discard_out(struct sock *sk, struct sk_buff *skb);
Kamala R7150aed2013-12-02 19:55:21 +053090static int ip6_pkt_prohibit(struct sk_buff *skb);
Eric Dumazetaad88722014-04-15 13:47:15 -040091static int ip6_pkt_prohibit_out(struct sock *sk, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070092static void ip6_link_failure(struct sk_buff *skb);
David S. Miller6700c272012-07-17 03:29:28 -070093static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
94 struct sk_buff *skb, u32 mtu);
95static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
96 struct sk_buff *skb);
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -070097static void rt6_dst_from_metrics_check(struct rt6_info *rt);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +020098static int rt6_score_route(struct rt6_info *rt, int oif, int strict);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800100#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800101static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000102 const struct in6_addr *prefix, int prefixlen,
103 const struct in6_addr *gwaddr, int ifindex,
Eric Dumazet95c96172012-04-15 05:58:06 +0000104 unsigned int pref);
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800105static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000106 const struct in6_addr *prefix, int prefixlen,
107 const struct in6_addr *gwaddr, int ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800108#endif
109
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700110struct uncached_list {
111 spinlock_t lock;
112 struct list_head head;
113};
114
115static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list);
116
117static void rt6_uncached_list_add(struct rt6_info *rt)
118{
119 struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);
120
121 rt->dst.flags |= DST_NOCACHE;
122 rt->rt6i_uncached_list = ul;
123
124 spin_lock_bh(&ul->lock);
125 list_add_tail(&rt->rt6i_uncached, &ul->head);
126 spin_unlock_bh(&ul->lock);
127}
128
129static void rt6_uncached_list_del(struct rt6_info *rt)
130{
131 if (!list_empty(&rt->rt6i_uncached)) {
132 struct uncached_list *ul = rt->rt6i_uncached_list;
133
134 spin_lock_bh(&ul->lock);
135 list_del(&rt->rt6i_uncached);
136 spin_unlock_bh(&ul->lock);
137 }
138}
139
140static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev)
141{
142 struct net_device *loopback_dev = net->loopback_dev;
143 int cpu;
144
145 for_each_possible_cpu(cpu) {
146 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
147 struct rt6_info *rt;
148
149 spin_lock_bh(&ul->lock);
150 list_for_each_entry(rt, &ul->head, rt6i_uncached) {
151 struct inet6_dev *rt_idev = rt->rt6i_idev;
152 struct net_device *rt_dev = rt->dst.dev;
153
154 if (rt_idev && (rt_idev->dev == dev || !dev) &&
155 rt_idev->dev != loopback_dev) {
156 rt->rt6i_idev = in6_dev_get(loopback_dev);
157 in6_dev_put(rt_idev);
158 }
159
160 if (rt_dev && (rt_dev == dev || !dev) &&
161 rt_dev != loopback_dev) {
162 rt->dst.dev = loopback_dev;
163 dev_hold(rt->dst.dev);
164 dev_put(rt_dev);
165 }
166 }
167 spin_unlock_bh(&ul->lock);
168 }
169}
170
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700171static u32 *rt6_pcpu_cow_metrics(struct rt6_info *rt)
172{
173 return dst_metrics_write_ptr(rt->dst.from);
174}
175
David S. Miller06582542011-01-27 14:58:42 -0800176static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
177{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700178 struct rt6_info *rt = (struct rt6_info *)dst;
David S. Miller06582542011-01-27 14:58:42 -0800179
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700180 if (rt->rt6i_flags & RTF_PCPU)
181 return rt6_pcpu_cow_metrics(rt);
182 else if (rt->rt6i_flags & RTF_CACHE)
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700183 return NULL;
184 else
Martin KaFai Lau3b471172015-02-12 16:14:08 -0800185 return dst_cow_metrics_generic(dst, old);
David S. Miller06582542011-01-27 14:58:42 -0800186}
187
David S. Millerf894cbf2012-07-02 21:52:24 -0700188static inline const void *choose_neigh_daddr(struct rt6_info *rt,
189 struct sk_buff *skb,
190 const void *daddr)
David S. Miller39232972012-01-26 15:22:32 -0500191{
192 struct in6_addr *p = &rt->rt6i_gateway;
193
David S. Millera7563f32012-01-26 16:29:16 -0500194 if (!ipv6_addr_any(p))
David S. Miller39232972012-01-26 15:22:32 -0500195 return (const void *) p;
David S. Millerf894cbf2012-07-02 21:52:24 -0700196 else if (skb)
197 return &ipv6_hdr(skb)->daddr;
David S. Miller39232972012-01-26 15:22:32 -0500198 return daddr;
199}
200
David S. Millerf894cbf2012-07-02 21:52:24 -0700201static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst,
202 struct sk_buff *skb,
203 const void *daddr)
David S. Millerd3aaeb32011-07-18 00:40:17 -0700204{
David S. Miller39232972012-01-26 15:22:32 -0500205 struct rt6_info *rt = (struct rt6_info *) dst;
206 struct neighbour *n;
207
David S. Millerf894cbf2012-07-02 21:52:24 -0700208 daddr = choose_neigh_daddr(rt, skb, daddr);
YOSHIFUJI Hideaki / 吉藤英明8e022ee2013-01-17 12:53:09 +0000209 n = __ipv6_neigh_lookup(dst->dev, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500210 if (n)
211 return n;
212 return neigh_create(&nd_tbl, daddr, dst->dev);
213}
214
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -0800215static struct dst_ops ip6_dst_ops_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 .family = AF_INET6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 .gc = ip6_dst_gc,
218 .gc_thresh = 1024,
219 .check = ip6_dst_check,
David S. Miller0dbaee32010-12-13 12:52:14 -0800220 .default_advmss = ip6_default_advmss,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000221 .mtu = ip6_mtu,
David S. Miller06582542011-01-27 14:58:42 -0800222 .cow_metrics = ipv6_cow_metrics,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 .destroy = ip6_dst_destroy,
224 .ifdown = ip6_dst_ifdown,
225 .negative_advice = ip6_negative_advice,
226 .link_failure = ip6_link_failure,
227 .update_pmtu = ip6_rt_update_pmtu,
David S. Miller6e157b62012-07-12 00:05:02 -0700228 .redirect = rt6_do_redirect,
Eric W. Biederman9f8955c2015-10-07 16:48:39 -0500229 .local_out = __ip6_local_out,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700230 .neigh_lookup = ip6_neigh_lookup,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231};
232
Steffen Klassertebb762f2011-11-23 02:12:51 +0000233static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
Roland Dreierec831ea2011-01-31 13:16:00 -0800234{
Steffen Klassert618f9bc2011-11-23 02:13:31 +0000235 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
236
237 return mtu ? : dst->dev->mtu;
Roland Dreierec831ea2011-01-31 13:16:00 -0800238}
239
David S. Miller6700c272012-07-17 03:29:28 -0700240static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
241 struct sk_buff *skb, u32 mtu)
David S. Miller14e50e52007-05-24 18:17:54 -0700242{
243}
244
David S. Miller6700c272012-07-17 03:29:28 -0700245static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
246 struct sk_buff *skb)
David S. Millerb587ee32012-07-12 00:39:24 -0700247{
248}
249
Held Bernhard0972ddb2011-04-24 22:07:32 +0000250static u32 *ip6_rt_blackhole_cow_metrics(struct dst_entry *dst,
251 unsigned long old)
252{
253 return NULL;
254}
255
David S. Miller14e50e52007-05-24 18:17:54 -0700256static struct dst_ops ip6_dst_blackhole_ops = {
257 .family = AF_INET6,
David S. Miller14e50e52007-05-24 18:17:54 -0700258 .destroy = ip6_dst_destroy,
259 .check = ip6_dst_check,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000260 .mtu = ip6_blackhole_mtu,
Eric Dumazet214f45c2011-02-18 11:39:01 -0800261 .default_advmss = ip6_default_advmss,
David S. Miller14e50e52007-05-24 18:17:54 -0700262 .update_pmtu = ip6_rt_blackhole_update_pmtu,
David S. Millerb587ee32012-07-12 00:39:24 -0700263 .redirect = ip6_rt_blackhole_redirect,
Held Bernhard0972ddb2011-04-24 22:07:32 +0000264 .cow_metrics = ip6_rt_blackhole_cow_metrics,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700265 .neigh_lookup = ip6_neigh_lookup,
David S. Miller14e50e52007-05-24 18:17:54 -0700266};
267
David S. Miller62fa8a82011-01-26 20:51:05 -0800268static const u32 ip6_template_metrics[RTAX_MAX] = {
Li RongQing14edd872012-10-24 14:01:18 +0800269 [RTAX_HOPLIMIT - 1] = 0,
David S. Miller62fa8a82011-01-26 20:51:05 -0800270};
271
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000272static const struct rt6_info ip6_null_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700273 .dst = {
274 .__refcnt = ATOMIC_INIT(1),
275 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000276 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700277 .error = -ENETUNREACH,
Changli Gaod8d1f302010-06-10 23:31:35 -0700278 .input = ip6_pkt_discard,
279 .output = ip6_pkt_discard_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 },
281 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700282 .rt6i_protocol = RTPROT_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 .rt6i_metric = ~(u32) 0,
284 .rt6i_ref = ATOMIC_INIT(1),
285};
286
Thomas Graf101367c2006-08-04 03:39:02 -0700287#ifdef CONFIG_IPV6_MULTIPLE_TABLES
288
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000289static const struct rt6_info ip6_prohibit_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700290 .dst = {
291 .__refcnt = ATOMIC_INIT(1),
292 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000293 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700294 .error = -EACCES,
Changli Gaod8d1f302010-06-10 23:31:35 -0700295 .input = ip6_pkt_prohibit,
296 .output = ip6_pkt_prohibit_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700297 },
298 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700299 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700300 .rt6i_metric = ~(u32) 0,
301 .rt6i_ref = ATOMIC_INIT(1),
302};
303
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000304static const struct rt6_info ip6_blk_hole_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700305 .dst = {
306 .__refcnt = ATOMIC_INIT(1),
307 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000308 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700309 .error = -EINVAL,
Changli Gaod8d1f302010-06-10 23:31:35 -0700310 .input = dst_discard,
Eric Dumazetaad88722014-04-15 13:47:15 -0400311 .output = dst_discard_sk,
Thomas Graf101367c2006-08-04 03:39:02 -0700312 },
313 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700314 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700315 .rt6i_metric = ~(u32) 0,
316 .rt6i_ref = ATOMIC_INIT(1),
317};
318
319#endif
320
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321/* allocate dst with ip6_dst_ops */
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700322static struct rt6_info *__ip6_dst_alloc(struct net *net,
323 struct net_device *dev,
Martin KaFai Lauad706862015-08-14 11:05:52 -0700324 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325{
David S. Miller97bab732012-06-09 22:36:36 -0700326 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +0000327 0, DST_OBSOLETE_FORCE_CHK, flags);
David S. Millercf911662011-04-28 14:31:47 -0700328
David S. Miller97bab732012-06-09 22:36:36 -0700329 if (rt) {
Steffen Klassert81048912012-07-05 23:37:09 +0000330 struct dst_entry *dst = &rt->dst;
331
332 memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000333 INIT_LIST_HEAD(&rt->rt6i_siblings);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700334 INIT_LIST_HEAD(&rt->rt6i_uncached);
David S. Miller97bab732012-06-09 22:36:36 -0700335 }
David S. Millercf911662011-04-28 14:31:47 -0700336 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337}
338
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700339static struct rt6_info *ip6_dst_alloc(struct net *net,
340 struct net_device *dev,
Martin KaFai Lauad706862015-08-14 11:05:52 -0700341 int flags)
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700342{
Martin KaFai Lauad706862015-08-14 11:05:52 -0700343 struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700344
345 if (rt) {
346 rt->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, GFP_ATOMIC);
347 if (rt->rt6i_pcpu) {
348 int cpu;
349
350 for_each_possible_cpu(cpu) {
351 struct rt6_info **p;
352
353 p = per_cpu_ptr(rt->rt6i_pcpu, cpu);
354 /* no one shares rt */
355 *p = NULL;
356 }
357 } else {
358 dst_destroy((struct dst_entry *)rt);
359 return NULL;
360 }
361 }
362
363 return rt;
364}
365
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366static void ip6_dst_destroy(struct dst_entry *dst)
367{
368 struct rt6_info *rt = (struct rt6_info *)dst;
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000369 struct dst_entry *from = dst->from;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700370 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700372 dst_destroy_metrics_generic(dst);
Markus Elfring87775312015-07-02 16:30:24 +0200373 free_percpu(rt->rt6i_pcpu);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700374 rt6_uncached_list_del(rt);
375
376 idev = rt->rt6i_idev;
David S. Miller38308472011-12-03 18:02:47 -0500377 if (idev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 rt->rt6i_idev = NULL;
379 in6_dev_put(idev);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900380 }
Gao feng1716a962012-04-06 00:13:10 +0000381
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000382 dst->from = NULL;
383 dst_release(from);
David S. Millerb3419362010-11-30 12:27:11 -0800384}
385
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
387 int how)
388{
389 struct rt6_info *rt = (struct rt6_info *)dst;
390 struct inet6_dev *idev = rt->rt6i_idev;
Denis V. Lunev5a3e55d2007-12-07 00:38:10 -0800391 struct net_device *loopback_dev =
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900392 dev_net(dev)->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
David S. Miller97cac082012-07-02 22:43:47 -0700394 if (dev != loopback_dev) {
395 if (idev && idev->dev == dev) {
396 struct inet6_dev *loopback_idev =
397 in6_dev_get(loopback_dev);
398 if (loopback_idev) {
399 rt->rt6i_idev = loopback_idev;
400 in6_dev_put(idev);
401 }
402 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 }
404}
405
Eric Dumazeta50feda2012-05-18 18:57:34 +0000406static bool rt6_check_expired(const struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407{
Gao feng1716a962012-04-06 00:13:10 +0000408 if (rt->rt6i_flags & RTF_EXPIRES) {
409 if (time_after(jiffies, rt->dst.expires))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000410 return true;
Gao feng1716a962012-04-06 00:13:10 +0000411 } else if (rt->dst.from) {
Li RongQing3fd91fb2012-09-13 19:54:57 +0000412 return rt6_check_expired((struct rt6_info *) rt->dst.from);
Gao feng1716a962012-04-06 00:13:10 +0000413 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000414 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415}
416
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000417/* Multipath route selection:
418 * Hash based function using packet header and flowlabel.
419 * Adapted from fib_info_hashfn()
420 */
421static int rt6_info_hash_nhsfn(unsigned int candidate_count,
422 const struct flowi6 *fl6)
423{
Tom Herbert644d0e62015-09-23 14:13:35 -0700424 return get_hash_from_flowi6(fl6) % candidate_count;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000425}
426
427static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200428 struct flowi6 *fl6, int oif,
429 int strict)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000430{
431 struct rt6_info *sibling, *next_sibling;
432 int route_choosen;
433
434 route_choosen = rt6_info_hash_nhsfn(match->rt6i_nsiblings + 1, fl6);
435 /* Don't change the route, if route_choosen == 0
436 * (siblings does not include ourself)
437 */
438 if (route_choosen)
439 list_for_each_entry_safe(sibling, next_sibling,
440 &match->rt6i_siblings, rt6i_siblings) {
441 route_choosen--;
442 if (route_choosen == 0) {
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200443 if (rt6_score_route(sibling, oif, strict) < 0)
444 break;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000445 match = sibling;
446 break;
447 }
448 }
449 return match;
450}
451
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452/*
Thomas Grafc71099a2006-08-04 23:20:06 -0700453 * Route lookup. Any table->tb6_lock is implied.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 */
455
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800456static inline struct rt6_info *rt6_device_match(struct net *net,
457 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000458 const struct in6_addr *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 int oif,
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700460 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461{
462 struct rt6_info *local = NULL;
463 struct rt6_info *sprt;
464
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900465 if (!oif && ipv6_addr_any(saddr))
466 goto out;
467
Changli Gaod8d1f302010-06-10 23:31:35 -0700468 for (sprt = rt; sprt; sprt = sprt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -0500469 struct net_device *dev = sprt->dst.dev;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900470
471 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 if (dev->ifindex == oif)
473 return sprt;
474 if (dev->flags & IFF_LOOPBACK) {
David S. Miller38308472011-12-03 18:02:47 -0500475 if (!sprt->rt6i_idev ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 sprt->rt6i_idev->dev->ifindex != oif) {
David Ahern17fb0b22015-09-25 15:22:54 -0600477 if (flags & RT6_LOOKUP_F_IFACE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 continue;
David Ahern17fb0b22015-09-25 15:22:54 -0600479 if (local &&
480 local->rt6i_idev->dev->ifindex == oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 continue;
482 }
483 local = sprt;
484 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900485 } else {
486 if (ipv6_chk_addr(net, saddr, dev,
487 flags & RT6_LOOKUP_F_IFACE))
488 return sprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900490 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900492 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 if (local)
494 return local;
495
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700496 if (flags & RT6_LOOKUP_F_IFACE)
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800497 return net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900499out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 return rt;
501}
502
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800503#ifdef CONFIG_IPV6_ROUTER_PREF
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200504struct __rt6_probe_work {
505 struct work_struct work;
506 struct in6_addr target;
507 struct net_device *dev;
508};
509
510static void rt6_probe_deferred(struct work_struct *w)
511{
512 struct in6_addr mcaddr;
513 struct __rt6_probe_work *work =
514 container_of(w, struct __rt6_probe_work, work);
515
516 addrconf_addr_solict_mult(&work->target, &mcaddr);
Jiri Benc38cf5952015-09-22 18:57:13 +0200517 ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL, NULL);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200518 dev_put(work->dev);
Michael Büsch662f5532015-02-08 10:14:07 +0100519 kfree(work);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200520}
521
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800522static void rt6_probe(struct rt6_info *rt)
523{
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700524 struct __rt6_probe_work *work;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000525 struct neighbour *neigh;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800526 /*
527 * Okay, this does not seem to be appropriate
528 * for now, however, we need to check if it
529 * is really so; aka Router Reachability Probing.
530 *
531 * Router Reachability Probe MUST be rate-limited
532 * to no more than one per minute.
533 */
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000534 if (!rt || !(rt->rt6i_flags & RTF_GATEWAY))
Amerigo Wangfdd66812012-09-10 02:48:44 +0000535 return;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000536 rcu_read_lock_bh();
537 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
538 if (neigh) {
Martin KaFai Lau8d6c31b2015-07-24 09:57:43 -0700539 if (neigh->nud_state & NUD_VALID)
540 goto out;
541
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700542 work = NULL;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000543 write_lock(&neigh->lock);
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700544 if (!(neigh->nud_state & NUD_VALID) &&
545 time_after(jiffies,
546 neigh->updated +
547 rt->rt6i_idev->cnf.rtr_probe_interval)) {
548 work = kmalloc(sizeof(*work), GFP_ATOMIC);
549 if (work)
550 __neigh_set_probe_once(neigh);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200551 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000552 write_unlock(&neigh->lock);
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700553 } else {
554 work = kmalloc(sizeof(*work), GFP_ATOMIC);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000555 }
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700556
557 if (work) {
558 INIT_WORK(&work->work, rt6_probe_deferred);
559 work->target = rt->rt6i_gateway;
560 dev_hold(rt->dst.dev);
561 work->dev = rt->dst.dev;
562 schedule_work(&work->work);
563 }
564
Martin KaFai Lau8d6c31b2015-07-24 09:57:43 -0700565out:
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000566 rcu_read_unlock_bh();
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800567}
568#else
569static inline void rt6_probe(struct rt6_info *rt)
570{
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800571}
572#endif
573
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574/*
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800575 * Default Router Selection (RFC 2461 6.3.6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 */
Dave Jonesb6f99a22007-03-22 12:27:49 -0700577static inline int rt6_check_dev(struct rt6_info *rt, int oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578{
David S. Millerd1918542011-12-28 20:19:20 -0500579 struct net_device *dev = rt->dst.dev;
David S. Miller161980f2007-04-06 11:42:27 -0700580 if (!oif || dev->ifindex == oif)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800581 return 2;
David S. Miller161980f2007-04-06 11:42:27 -0700582 if ((dev->flags & IFF_LOOPBACK) &&
583 rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
584 return 1;
585 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586}
587
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200588static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000590 struct neighbour *neigh;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200591 enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000592
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700593 if (rt->rt6i_flags & RTF_NONEXTHOP ||
594 !(rt->rt6i_flags & RTF_GATEWAY))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200595 return RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000596
597 rcu_read_lock_bh();
598 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
599 if (neigh) {
600 read_lock(&neigh->lock);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800601 if (neigh->nud_state & NUD_VALID)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200602 ret = RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800603#ifdef CONFIG_IPV6_ROUTER_PREF
Paul Marksa5a81f02012-12-03 10:26:54 +0000604 else if (!(neigh->nud_state & NUD_FAILED))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200605 ret = RT6_NUD_SUCCEED;
Jiri Benc7e980562013-12-11 13:48:20 +0100606 else
607 ret = RT6_NUD_FAIL_PROBE;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800608#endif
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000609 read_unlock(&neigh->lock);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200610 } else {
611 ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
Jiri Benc7e980562013-12-11 13:48:20 +0100612 RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR;
Paul Marksa5a81f02012-12-03 10:26:54 +0000613 }
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000614 rcu_read_unlock_bh();
615
Paul Marksa5a81f02012-12-03 10:26:54 +0000616 return ret;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800617}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800619static int rt6_score_route(struct rt6_info *rt, int oif,
620 int strict)
621{
Paul Marksa5a81f02012-12-03 10:26:54 +0000622 int m;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900623
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700624 m = rt6_check_dev(rt, oif);
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700625 if (!m && (strict & RT6_LOOKUP_F_IFACE))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200626 return RT6_NUD_FAIL_HARD;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800627#ifdef CONFIG_IPV6_ROUTER_PREF
628 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
629#endif
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200630 if (strict & RT6_LOOKUP_F_REACHABLE) {
631 int n = rt6_check_neigh(rt);
632 if (n < 0)
633 return n;
634 }
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800635 return m;
636}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
David S. Millerf11e6652007-03-24 20:36:25 -0700638static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200639 int *mpri, struct rt6_info *match,
640 bool *do_rr)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800641{
David S. Millerf11e6652007-03-24 20:36:25 -0700642 int m;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200643 bool match_do_rr = false;
Andy Gospodarek35103d12015-08-13 10:39:01 -0400644 struct inet6_dev *idev = rt->rt6i_idev;
645 struct net_device *dev = rt->dst.dev;
646
647 if (dev && !netif_carrier_ok(dev) &&
648 idev->cnf.ignore_routes_with_linkdown)
649 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700650
651 if (rt6_check_expired(rt))
652 goto out;
653
654 m = rt6_score_route(rt, oif, strict);
Jiri Benc7e980562013-12-11 13:48:20 +0100655 if (m == RT6_NUD_FAIL_DO_RR) {
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200656 match_do_rr = true;
657 m = 0; /* lowest valid score */
Jiri Benc7e980562013-12-11 13:48:20 +0100658 } else if (m == RT6_NUD_FAIL_HARD) {
David S. Millerf11e6652007-03-24 20:36:25 -0700659 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700660 }
661
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200662 if (strict & RT6_LOOKUP_F_REACHABLE)
663 rt6_probe(rt);
664
Jiri Benc7e980562013-12-11 13:48:20 +0100665 /* note that m can be RT6_NUD_FAIL_PROBE at this point */
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200666 if (m > *mpri) {
667 *do_rr = match_do_rr;
668 *mpri = m;
669 match = rt;
670 }
David S. Millerf11e6652007-03-24 20:36:25 -0700671out:
672 return match;
673}
674
675static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
676 struct rt6_info *rr_head,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200677 u32 metric, int oif, int strict,
678 bool *do_rr)
David S. Millerf11e6652007-03-24 20:36:25 -0700679{
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700680 struct rt6_info *rt, *match, *cont;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800681 int mpri = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
David S. Millerf11e6652007-03-24 20:36:25 -0700683 match = NULL;
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700684 cont = NULL;
685 for (rt = rr_head; rt; rt = rt->dst.rt6_next) {
686 if (rt->rt6i_metric != metric) {
687 cont = rt;
688 break;
689 }
690
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200691 match = find_match(rt, oif, strict, &mpri, match, do_rr);
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700692 }
693
694 for (rt = fn->leaf; rt && rt != rr_head; rt = rt->dst.rt6_next) {
695 if (rt->rt6i_metric != metric) {
696 cont = rt;
697 break;
698 }
699
700 match = find_match(rt, oif, strict, &mpri, match, do_rr);
701 }
702
703 if (match || !cont)
704 return match;
705
706 for (rt = cont; rt; rt = rt->dst.rt6_next)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200707 match = find_match(rt, oif, strict, &mpri, match, do_rr);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800708
David S. Millerf11e6652007-03-24 20:36:25 -0700709 return match;
710}
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800711
David S. Millerf11e6652007-03-24 20:36:25 -0700712static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
713{
714 struct rt6_info *match, *rt0;
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800715 struct net *net;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200716 bool do_rr = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717
David S. Millerf11e6652007-03-24 20:36:25 -0700718 rt0 = fn->rr_ptr;
719 if (!rt0)
720 fn->rr_ptr = rt0 = fn->leaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200722 match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict,
723 &do_rr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200725 if (do_rr) {
Changli Gaod8d1f302010-06-10 23:31:35 -0700726 struct rt6_info *next = rt0->dst.rt6_next;
David S. Millerf11e6652007-03-24 20:36:25 -0700727
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800728 /* no entries matched; do round-robin */
David S. Millerf11e6652007-03-24 20:36:25 -0700729 if (!next || next->rt6i_metric != rt0->rt6i_metric)
730 next = fn->leaf;
731
732 if (next != rt0)
733 fn->rr_ptr = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 }
735
David S. Millerd1918542011-12-28 20:19:20 -0500736 net = dev_net(rt0->dst.dev);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000737 return match ? match : net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738}
739
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700740static bool rt6_is_gw_or_nonexthop(const struct rt6_info *rt)
741{
742 return (rt->rt6i_flags & (RTF_NONEXTHOP | RTF_GATEWAY));
743}
744
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800745#ifdef CONFIG_IPV6_ROUTE_INFO
746int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000747 const struct in6_addr *gwaddr)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800748{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900749 struct net *net = dev_net(dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800750 struct route_info *rinfo = (struct route_info *) opt;
751 struct in6_addr prefix_buf, *prefix;
752 unsigned int pref;
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900753 unsigned long lifetime;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800754 struct rt6_info *rt;
755
756 if (len < sizeof(struct route_info)) {
757 return -EINVAL;
758 }
759
760 /* Sanity check for prefix_len and length */
761 if (rinfo->length > 3) {
762 return -EINVAL;
763 } else if (rinfo->prefix_len > 128) {
764 return -EINVAL;
765 } else if (rinfo->prefix_len > 64) {
766 if (rinfo->length < 2) {
767 return -EINVAL;
768 }
769 } else if (rinfo->prefix_len > 0) {
770 if (rinfo->length < 1) {
771 return -EINVAL;
772 }
773 }
774
775 pref = rinfo->route_pref;
776 if (pref == ICMPV6_ROUTER_PREF_INVALID)
Jens Rosenboom3933fc92009-09-10 06:25:11 +0000777 return -EINVAL;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800778
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900779 lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800780
781 if (rinfo->length == 3)
782 prefix = (struct in6_addr *)rinfo->prefix;
783 else {
784 /* this function is safe */
785 ipv6_addr_prefix(&prefix_buf,
786 (struct in6_addr *)rinfo->prefix,
787 rinfo->prefix_len);
788 prefix = &prefix_buf;
789 }
790
Duan Jiongf104a562013-11-08 09:56:53 +0800791 if (rinfo->prefix_len == 0)
792 rt = rt6_get_dflt_router(gwaddr, dev);
793 else
794 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len,
795 gwaddr, dev->ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800796
797 if (rt && !lifetime) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -0700798 ip6_del_rt(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800799 rt = NULL;
800 }
801
802 if (!rt && lifetime)
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800803 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800804 pref);
805 else if (rt)
806 rt->rt6i_flags = RTF_ROUTEINFO |
807 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
808
809 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +0000810 if (!addrconf_finite_timeout(lifetime))
811 rt6_clean_expires(rt);
812 else
813 rt6_set_expires(rt, jiffies + HZ * lifetime);
814
Amerigo Wang94e187c2012-10-29 00:13:19 +0000815 ip6_rt_put(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800816 }
817 return 0;
818}
819#endif
820
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700821static struct fib6_node* fib6_backtrack(struct fib6_node *fn,
822 struct in6_addr *saddr)
823{
824 struct fib6_node *pn;
825 while (1) {
826 if (fn->fn_flags & RTN_TL_ROOT)
827 return NULL;
828 pn = fn->parent;
829 if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn)
830 fn = fib6_lookup(FIB6_SUBTREE(pn), NULL, saddr);
831 else
832 fn = pn;
833 if (fn->fn_flags & RTN_RTINFO)
834 return fn;
835 }
836}
Thomas Grafc71099a2006-08-04 23:20:06 -0700837
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800838static struct rt6_info *ip6_pol_route_lookup(struct net *net,
839 struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500840 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841{
842 struct fib6_node *fn;
843 struct rt6_info *rt;
844
Thomas Grafc71099a2006-08-04 23:20:06 -0700845 read_lock_bh(&table->tb6_lock);
David S. Miller4c9483b2011-03-12 16:22:43 -0500846 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -0700847restart:
848 rt = fn->leaf;
David S. Miller4c9483b2011-03-12 16:22:43 -0500849 rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000850 if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0)
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200851 rt = rt6_multipath_select(rt, fl6, fl6->flowi6_oif, flags);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700852 if (rt == net->ipv6.ip6_null_entry) {
853 fn = fib6_backtrack(fn, &fl6->saddr);
854 if (fn)
855 goto restart;
856 }
Changli Gaod8d1f302010-06-10 23:31:35 -0700857 dst_use(&rt->dst, jiffies);
Thomas Grafc71099a2006-08-04 23:20:06 -0700858 read_unlock_bh(&table->tb6_lock);
Thomas Grafc71099a2006-08-04 23:20:06 -0700859 return rt;
860
861}
862
Ian Morris67ba4152014-08-24 21:53:10 +0100863struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
Florian Westphalea6e5742011-09-05 16:05:44 +0200864 int flags)
865{
866 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup);
867}
868EXPORT_SYMBOL_GPL(ip6_route_lookup);
869
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900870struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
871 const struct in6_addr *saddr, int oif, int strict)
Thomas Grafc71099a2006-08-04 23:20:06 -0700872{
David S. Miller4c9483b2011-03-12 16:22:43 -0500873 struct flowi6 fl6 = {
874 .flowi6_oif = oif,
875 .daddr = *daddr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700876 };
877 struct dst_entry *dst;
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700878 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
Thomas Grafc71099a2006-08-04 23:20:06 -0700879
Thomas Grafadaa70b2006-10-13 15:01:03 -0700880 if (saddr) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500881 memcpy(&fl6.saddr, saddr, sizeof(*saddr));
Thomas Grafadaa70b2006-10-13 15:01:03 -0700882 flags |= RT6_LOOKUP_F_HAS_SADDR;
883 }
884
David S. Miller4c9483b2011-03-12 16:22:43 -0500885 dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup);
Thomas Grafc71099a2006-08-04 23:20:06 -0700886 if (dst->error == 0)
887 return (struct rt6_info *) dst;
888
889 dst_release(dst);
890
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 return NULL;
892}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900893EXPORT_SYMBOL(rt6_lookup);
894
Thomas Grafc71099a2006-08-04 23:20:06 -0700895/* ip6_ins_rt is called with FREE table->tb6_lock.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 It takes new route entry, the addition fails by any reason the
897 route is freed. In any case, if caller does not hold it, it may
898 be destroyed.
899 */
900
Michal Kubečeke5fd3872014-03-27 13:04:08 +0100901static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info,
Florian Westphale715b6d2015-01-05 23:57:44 +0100902 struct mx6_config *mxc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903{
904 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -0700905 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906
Thomas Grafc71099a2006-08-04 23:20:06 -0700907 table = rt->rt6i_table;
908 write_lock_bh(&table->tb6_lock);
Florian Westphale715b6d2015-01-05 23:57:44 +0100909 err = fib6_add(&table->tb6_root, rt, info, mxc);
Thomas Grafc71099a2006-08-04 23:20:06 -0700910 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911
912 return err;
913}
914
Thomas Graf40e22e82006-08-22 00:00:45 -0700915int ip6_ins_rt(struct rt6_info *rt)
916{
Florian Westphale715b6d2015-01-05 23:57:44 +0100917 struct nl_info info = { .nl_net = dev_net(rt->dst.dev), };
918 struct mx6_config mxc = { .mx = NULL, };
919
920 return __ip6_ins_rt(rt, &info, &mxc);
Thomas Graf40e22e82006-08-22 00:00:45 -0700921}
922
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700923static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort,
924 const struct in6_addr *daddr,
925 const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 struct rt6_info *rt;
928
929 /*
930 * Clone the route.
931 */
932
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700933 if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU))
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700934 ort = (struct rt6_info *)ort->dst.from;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
Martin KaFai Lauad706862015-08-14 11:05:52 -0700936 rt = __ip6_dst_alloc(dev_net(ort->dst.dev), ort->dst.dev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700938 if (!rt)
939 return NULL;
940
941 ip6_rt_copy_init(rt, ort);
942 rt->rt6i_flags |= RTF_CACHE;
943 rt->rt6i_metric = 0;
944 rt->dst.flags |= DST_HOST;
945 rt->rt6i_dst.addr = *daddr;
946 rt->rt6i_dst.plen = 128;
947
948 if (!rt6_is_gw_or_nonexthop(ort)) {
949 if (ort->rt6i_dst.plen != 128 &&
950 ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
951 rt->rt6i_flags |= RTF_ANYCAST;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700953 if (rt->rt6i_src.plen && saddr) {
954 rt->rt6i_src.addr = *saddr;
955 rt->rt6i_src.plen = 128;
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700956 }
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700957#endif
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800958 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800960 return rt;
961}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700963static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt)
964{
965 struct rt6_info *pcpu_rt;
966
967 pcpu_rt = __ip6_dst_alloc(dev_net(rt->dst.dev),
Martin KaFai Lauad706862015-08-14 11:05:52 -0700968 rt->dst.dev, rt->dst.flags);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700969
970 if (!pcpu_rt)
971 return NULL;
972 ip6_rt_copy_init(pcpu_rt, rt);
973 pcpu_rt->rt6i_protocol = rt->rt6i_protocol;
974 pcpu_rt->rt6i_flags |= RTF_PCPU;
975 return pcpu_rt;
976}
977
978/* It should be called with read_lock_bh(&tb6_lock) acquired */
979static struct rt6_info *rt6_get_pcpu_route(struct rt6_info *rt)
980{
Martin KaFai Laua73e4192015-08-14 11:05:53 -0700981 struct rt6_info *pcpu_rt, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700982
983 p = this_cpu_ptr(rt->rt6i_pcpu);
984 pcpu_rt = *p;
985
Martin KaFai Laua73e4192015-08-14 11:05:53 -0700986 if (pcpu_rt) {
987 dst_hold(&pcpu_rt->dst);
988 rt6_dst_from_metrics_check(pcpu_rt);
989 }
990 return pcpu_rt;
991}
992
993static struct rt6_info *rt6_make_pcpu_route(struct rt6_info *rt)
994{
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -0700995 struct fib6_table *table = rt->rt6i_table;
Martin KaFai Laua73e4192015-08-14 11:05:53 -0700996 struct rt6_info *pcpu_rt, *prev, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700997
998 pcpu_rt = ip6_rt_pcpu_alloc(rt);
999 if (!pcpu_rt) {
1000 struct net *net = dev_net(rt->dst.dev);
1001
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001002 dst_hold(&net->ipv6.ip6_null_entry->dst);
1003 return net->ipv6.ip6_null_entry;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001004 }
1005
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001006 read_lock_bh(&table->tb6_lock);
1007 if (rt->rt6i_pcpu) {
1008 p = this_cpu_ptr(rt->rt6i_pcpu);
1009 prev = cmpxchg(p, NULL, pcpu_rt);
1010 if (prev) {
1011 /* If someone did it before us, return prev instead */
1012 dst_destroy(&pcpu_rt->dst);
1013 pcpu_rt = prev;
1014 }
1015 } else {
1016 /* rt has been removed from the fib6 tree
1017 * before we have a chance to acquire the read_lock.
1018 * In this case, don't brother to create a pcpu rt
1019 * since rt is going away anyway. The next
1020 * dst_check() will trigger a re-lookup.
1021 */
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001022 dst_destroy(&pcpu_rt->dst);
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001023 pcpu_rt = rt;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001024 }
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001025 dst_hold(&pcpu_rt->dst);
1026 rt6_dst_from_metrics_check(pcpu_rt);
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001027 read_unlock_bh(&table->tb6_lock);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001028 return pcpu_rt;
1029}
1030
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001031static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif,
David S. Miller4c9483b2011-03-12 16:22:43 -05001032 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033{
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001034 struct fib6_node *fn, *saved_fn;
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001035 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001036 int strict = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001038 strict |= flags & RT6_LOOKUP_F_IFACE;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001039 if (net->ipv6.devconf_all->forwarding == 0)
1040 strict |= RT6_LOOKUP_F_REACHABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041
Thomas Grafc71099a2006-08-04 23:20:06 -07001042 read_lock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
David S. Miller4c9483b2011-03-12 16:22:43 -05001044 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001045 saved_fn = fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001047redo_rt6_select:
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001048 rt = rt6_select(fn, oif, strict);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +02001049 if (rt->rt6i_nsiblings)
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001050 rt = rt6_multipath_select(rt, fl6, oif, strict);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001051 if (rt == net->ipv6.ip6_null_entry) {
1052 fn = fib6_backtrack(fn, &fl6->saddr);
1053 if (fn)
1054 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001055 else if (strict & RT6_LOOKUP_F_REACHABLE) {
1056 /* also consider unreachable route */
1057 strict &= ~RT6_LOOKUP_F_REACHABLE;
1058 fn = saved_fn;
1059 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001060 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001061 }
1062
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -08001063
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001064 if (rt == net->ipv6.ip6_null_entry || (rt->rt6i_flags & RTF_CACHE)) {
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001065 dst_use(&rt->dst, jiffies);
1066 read_unlock_bh(&table->tb6_lock);
1067
1068 rt6_dst_from_metrics_check(rt);
1069 return rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001070 } else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) &&
1071 !(rt->rt6i_flags & RTF_GATEWAY))) {
1072 /* Create a RTF_CACHE clone which will not be
1073 * owned by the fib6 tree. It is for the special case where
1074 * the daddr in the skb during the neighbor look-up is different
1075 * from the fl6->daddr used to look-up route here.
1076 */
Thomas Grafc71099a2006-08-04 23:20:06 -07001077
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001078 struct rt6_info *uncached_rt;
1079
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001080 dst_use(&rt->dst, jiffies);
1081 read_unlock_bh(&table->tb6_lock);
1082
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001083 uncached_rt = ip6_rt_cache_alloc(rt, &fl6->daddr, NULL);
1084 dst_release(&rt->dst);
1085
1086 if (uncached_rt)
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07001087 rt6_uncached_list_add(uncached_rt);
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001088 else
1089 uncached_rt = net->ipv6.ip6_null_entry;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001090
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001091 dst_hold(&uncached_rt->dst);
1092 return uncached_rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001093
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001094 } else {
1095 /* Get a percpu copy */
1096
1097 struct rt6_info *pcpu_rt;
1098
1099 rt->dst.lastuse = jiffies;
1100 rt->dst.__use++;
1101 pcpu_rt = rt6_get_pcpu_route(rt);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001102
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001103 if (pcpu_rt) {
1104 read_unlock_bh(&table->tb6_lock);
1105 } else {
1106 /* We have to do the read_unlock first
1107 * because rt6_make_pcpu_route() may trigger
1108 * ip6_dst_gc() which will take the write_lock.
1109 */
1110 dst_hold(&rt->dst);
1111 read_unlock_bh(&table->tb6_lock);
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001112 pcpu_rt = rt6_make_pcpu_route(rt);
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001113 dst_release(&rt->dst);
1114 }
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001115
1116 return pcpu_rt;
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001117
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001118 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001119}
1120
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001121static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -05001122 struct flowi6 *fl6, int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001123{
David S. Miller4c9483b2011-03-12 16:22:43 -05001124 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001125}
1126
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001127static struct dst_entry *ip6_route_input_lookup(struct net *net,
1128 struct net_device *dev,
1129 struct flowi6 *fl6, int flags)
1130{
1131 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
1132 flags |= RT6_LOOKUP_F_IFACE;
1133
1134 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_input);
1135}
1136
Thomas Grafc71099a2006-08-04 23:20:06 -07001137void ip6_route_input(struct sk_buff *skb)
1138{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001139 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001140 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001141 int flags = RT6_LOOKUP_F_HAS_SADDR;
Jiri Benc904af042015-08-20 13:56:31 +02001142 struct ip_tunnel_info *tun_info;
David S. Miller4c9483b2011-03-12 16:22:43 -05001143 struct flowi6 fl6 = {
1144 .flowi6_iif = skb->dev->ifindex,
1145 .daddr = iph->daddr,
1146 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001147 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -05001148 .flowi6_mark = skb->mark,
1149 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -07001150 };
Thomas Grafadaa70b2006-10-13 15:01:03 -07001151
Jiri Benc904af042015-08-20 13:56:31 +02001152 tun_info = skb_tunnel_info(skb);
Jiri Benc46fa0622015-08-28 20:48:19 +02001153 if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX))
Jiri Benc904af042015-08-20 13:56:31 +02001154 fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id;
Jiri Benc06e9d042015-08-20 13:56:26 +02001155 skb_dst_drop(skb);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001156 skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -07001157}
1158
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001159static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -05001160 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07001161{
David S. Miller4c9483b2011-03-12 16:22:43 -05001162 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -07001163}
1164
Ian Morris67ba4152014-08-24 21:53:10 +01001165struct dst_entry *ip6_route_output(struct net *net, const struct sock *sk,
David S. Miller4c9483b2011-03-12 16:22:43 -05001166 struct flowi6 *fl6)
Thomas Grafc71099a2006-08-04 23:20:06 -07001167{
1168 int flags = 0;
1169
Pavel Emelyanov1fb94892012-08-08 21:53:36 +00001170 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +00001171
David Ahern741a11d2015-09-28 10:12:13 -07001172 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) ||
1173 fl6->flowi6_oif)
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001174 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -07001175
David S. Miller4c9483b2011-03-12 16:22:43 -05001176 if (!ipv6_addr_any(&fl6->saddr))
Thomas Grafadaa70b2006-10-13 15:01:03 -07001177 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +00001178 else if (sk)
1179 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001180
David S. Miller4c9483b2011-03-12 16:22:43 -05001181 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +09001183EXPORT_SYMBOL(ip6_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184
David S. Miller2774c132011-03-01 14:59:04 -08001185struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -07001186{
David S. Miller5c1e6aa2011-04-28 14:13:38 -07001187 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
David S. Miller14e50e52007-05-24 18:17:54 -07001188 struct dst_entry *new = NULL;
1189
David S. Millerf5b0a872012-07-19 12:31:33 -07001190 rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, DST_OBSOLETE_NONE, 0);
David S. Miller14e50e52007-05-24 18:17:54 -07001191 if (rt) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001192 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -07001193
Steffen Klassert81048912012-07-05 23:37:09 +00001194 memset(new + 1, 0, sizeof(*rt) - sizeof(*new));
Steffen Klassert81048912012-07-05 23:37:09 +00001195
David S. Miller14e50e52007-05-24 18:17:54 -07001196 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08001197 new->input = dst_discard;
Eric Dumazetaad88722014-04-15 13:47:15 -04001198 new->output = dst_discard_sk;
David S. Miller14e50e52007-05-24 18:17:54 -07001199
Eric Dumazet21efcfa2011-07-19 20:18:36 +00001200 if (dst_metrics_read_only(&ort->dst))
1201 new->_metrics = ort->dst._metrics;
1202 else
1203 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07001204 rt->rt6i_idev = ort->rt6i_idev;
1205 if (rt->rt6i_idev)
1206 in6_dev_hold(rt->rt6i_idev);
David S. Miller14e50e52007-05-24 18:17:54 -07001207
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001208 rt->rt6i_gateway = ort->rt6i_gateway;
Gao feng1716a962012-04-06 00:13:10 +00001209 rt->rt6i_flags = ort->rt6i_flags;
David S. Miller14e50e52007-05-24 18:17:54 -07001210 rt->rt6i_metric = 0;
1211
1212 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
1213#ifdef CONFIG_IPV6_SUBTREES
1214 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1215#endif
1216
1217 dst_free(new);
1218 }
1219
David S. Miller69ead7a2011-03-01 14:45:33 -08001220 dst_release(dst_orig);
1221 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07001222}
David S. Miller14e50e52007-05-24 18:17:54 -07001223
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224/*
1225 * Destination cache support functions
1226 */
1227
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001228static void rt6_dst_from_metrics_check(struct rt6_info *rt)
1229{
1230 if (rt->dst.from &&
1231 dst_metrics_ptr(&rt->dst) != dst_metrics_ptr(rt->dst.from))
1232 dst_init_metrics(&rt->dst, dst_metrics_ptr(rt->dst.from), true);
1233}
1234
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001235static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie)
1236{
1237 if (!rt->rt6i_node || (rt->rt6i_node->fn_sernum != cookie))
1238 return NULL;
1239
1240 if (rt6_check_expired(rt))
1241 return NULL;
1242
1243 return &rt->dst;
1244}
1245
1246static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, u32 cookie)
1247{
1248 if (rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
1249 rt6_check((struct rt6_info *)(rt->dst.from), cookie))
1250 return &rt->dst;
1251 else
1252 return NULL;
1253}
1254
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
1256{
1257 struct rt6_info *rt;
1258
1259 rt = (struct rt6_info *) dst;
1260
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00001261 /* All IPV6 dsts are created with ->obsolete set to the value
1262 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
1263 * into this function always.
1264 */
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02001265
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001266 rt6_dst_from_metrics_check(rt);
1267
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001268 if ((rt->rt6i_flags & RTF_PCPU) || unlikely(dst->flags & DST_NOCACHE))
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001269 return rt6_dst_from_check(rt, cookie);
1270 else
1271 return rt6_check(rt, cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272}
1273
1274static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
1275{
1276 struct rt6_info *rt = (struct rt6_info *) dst;
1277
1278 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001279 if (rt->rt6i_flags & RTF_CACHE) {
1280 if (rt6_check_expired(rt)) {
1281 ip6_del_rt(rt);
1282 dst = NULL;
1283 }
1284 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001286 dst = NULL;
1287 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001289 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290}
1291
1292static void ip6_link_failure(struct sk_buff *skb)
1293{
1294 struct rt6_info *rt;
1295
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00001296 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297
Eric Dumazetadf30902009-06-02 05:19:30 +00001298 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 if (rt) {
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001300 if (rt->rt6i_flags & RTF_CACHE) {
1301 dst_hold(&rt->dst);
Martin KaFai Lau8e3d5be2015-09-15 14:30:08 -07001302 ip6_del_rt(rt);
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001303 } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 rt->rt6i_node->fn_sernum = -1;
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001305 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 }
1307}
1308
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001309static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
1310{
1311 struct net *net = dev_net(rt->dst.dev);
1312
1313 rt->rt6i_flags |= RTF_MODIFIED;
1314 rt->rt6i_pmtu = mtu;
1315 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
1316}
1317
1318static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
1319 const struct ipv6hdr *iph, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320{
Ian Morris67ba4152014-08-24 21:53:10 +01001321 struct rt6_info *rt6 = (struct rt6_info *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001323 if (rt6->rt6i_flags & RTF_LOCAL)
1324 return;
1325
David S. Miller81aded22012-06-15 14:54:11 -07001326 dst_confirm(dst);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001327 mtu = max_t(u32, mtu, IPV6_MIN_MTU);
1328 if (mtu >= dst_mtu(dst))
1329 return;
David S. Miller81aded22012-06-15 14:54:11 -07001330
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001331 if (rt6->rt6i_flags & RTF_CACHE) {
1332 rt6_do_update_pmtu(rt6, mtu);
1333 } else {
1334 const struct in6_addr *daddr, *saddr;
1335 struct rt6_info *nrt6;
Hagen Paul Pfeifer9d289712015-01-15 22:34:25 +01001336
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001337 if (iph) {
1338 daddr = &iph->daddr;
1339 saddr = &iph->saddr;
1340 } else if (sk) {
1341 daddr = &sk->sk_v6_daddr;
1342 saddr = &inet6_sk(sk)->saddr;
1343 } else {
1344 return;
1345 }
1346 nrt6 = ip6_rt_cache_alloc(rt6, daddr, saddr);
1347 if (nrt6) {
1348 rt6_do_update_pmtu(nrt6, mtu);
1349
1350 /* ip6_ins_rt(nrt6) will bump the
1351 * rt6->rt6i_node->fn_sernum
1352 * which will fail the next rt6_check() and
1353 * invalidate the sk->sk_dst_cache.
1354 */
1355 ip6_ins_rt(nrt6);
1356 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 }
1358}
1359
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001360static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
1361 struct sk_buff *skb, u32 mtu)
1362{
1363 __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu);
1364}
1365
David S. Miller42ae66c2012-06-15 20:01:57 -07001366void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
1367 int oif, u32 mark)
David S. Miller81aded22012-06-15 14:54:11 -07001368{
1369 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1370 struct dst_entry *dst;
1371 struct flowi6 fl6;
1372
1373 memset(&fl6, 0, sizeof(fl6));
1374 fl6.flowi6_oif = oif;
Lorenzo Colitti1b3c61d2014-05-13 10:17:34 -07001375 fl6.flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark);
David S. Miller81aded22012-06-15 14:54:11 -07001376 fl6.daddr = iph->daddr;
1377 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001378 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller81aded22012-06-15 14:54:11 -07001379
1380 dst = ip6_route_output(net, NULL, &fl6);
1381 if (!dst->error)
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001382 __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07001383 dst_release(dst);
1384}
1385EXPORT_SYMBOL_GPL(ip6_update_pmtu);
1386
1387void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
1388{
1389 ip6_update_pmtu(skb, sock_net(sk), mtu,
1390 sk->sk_bound_dev_if, sk->sk_mark);
1391}
1392EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
1393
Duan Jiongb55b76b2013-09-04 19:44:21 +08001394/* Handle redirects */
1395struct ip6rd_flowi {
1396 struct flowi6 fl6;
1397 struct in6_addr gateway;
1398};
1399
1400static struct rt6_info *__ip6_route_redirect(struct net *net,
1401 struct fib6_table *table,
1402 struct flowi6 *fl6,
1403 int flags)
1404{
1405 struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
1406 struct rt6_info *rt;
1407 struct fib6_node *fn;
1408
1409 /* Get the "current" route for this destination and
1410 * check if the redirect has come from approriate router.
1411 *
1412 * RFC 4861 specifies that redirects should only be
1413 * accepted if they come from the nexthop to the target.
1414 * Due to the way the routes are chosen, this notion
1415 * is a bit fuzzy and one might need to check all possible
1416 * routes.
1417 */
1418
1419 read_lock_bh(&table->tb6_lock);
1420 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
1421restart:
1422 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
1423 if (rt6_check_expired(rt))
1424 continue;
1425 if (rt->dst.error)
1426 break;
1427 if (!(rt->rt6i_flags & RTF_GATEWAY))
1428 continue;
1429 if (fl6->flowi6_oif != rt->dst.dev->ifindex)
1430 continue;
1431 if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway))
1432 continue;
1433 break;
1434 }
1435
1436 if (!rt)
1437 rt = net->ipv6.ip6_null_entry;
1438 else if (rt->dst.error) {
1439 rt = net->ipv6.ip6_null_entry;
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001440 goto out;
1441 }
1442
1443 if (rt == net->ipv6.ip6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001444 fn = fib6_backtrack(fn, &fl6->saddr);
1445 if (fn)
1446 goto restart;
Duan Jiongb55b76b2013-09-04 19:44:21 +08001447 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001448
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001449out:
Duan Jiongb55b76b2013-09-04 19:44:21 +08001450 dst_hold(&rt->dst);
1451
1452 read_unlock_bh(&table->tb6_lock);
1453
1454 return rt;
1455};
1456
1457static struct dst_entry *ip6_route_redirect(struct net *net,
1458 const struct flowi6 *fl6,
1459 const struct in6_addr *gateway)
1460{
1461 int flags = RT6_LOOKUP_F_HAS_SADDR;
1462 struct ip6rd_flowi rdfl;
1463
1464 rdfl.fl6 = *fl6;
1465 rdfl.gateway = *gateway;
1466
1467 return fib6_rule_lookup(net, &rdfl.fl6,
1468 flags, __ip6_route_redirect);
1469}
1470
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001471void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark)
1472{
1473 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1474 struct dst_entry *dst;
1475 struct flowi6 fl6;
1476
1477 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001478 fl6.flowi6_iif = LOOPBACK_IFINDEX;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001479 fl6.flowi6_oif = oif;
1480 fl6.flowi6_mark = mark;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001481 fl6.daddr = iph->daddr;
1482 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001483 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001484
Duan Jiongb55b76b2013-09-04 19:44:21 +08001485 dst = ip6_route_redirect(net, &fl6, &ipv6_hdr(skb)->saddr);
1486 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001487 dst_release(dst);
1488}
1489EXPORT_SYMBOL_GPL(ip6_redirect);
1490
Duan Jiongc92a59e2013-08-22 12:07:35 +08001491void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
1492 u32 mark)
1493{
1494 const struct ipv6hdr *iph = ipv6_hdr(skb);
1495 const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
1496 struct dst_entry *dst;
1497 struct flowi6 fl6;
1498
1499 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001500 fl6.flowi6_iif = LOOPBACK_IFINDEX;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001501 fl6.flowi6_oif = oif;
1502 fl6.flowi6_mark = mark;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001503 fl6.daddr = msg->dest;
1504 fl6.saddr = iph->daddr;
1505
Duan Jiongb55b76b2013-09-04 19:44:21 +08001506 dst = ip6_route_redirect(net, &fl6, &iph->saddr);
1507 rt6_do_redirect(dst, NULL, skb);
Duan Jiongc92a59e2013-08-22 12:07:35 +08001508 dst_release(dst);
1509}
1510
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001511void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
1512{
1513 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark);
1514}
1515EXPORT_SYMBOL_GPL(ip6_sk_redirect);
1516
David S. Miller0dbaee32010-12-13 12:52:14 -08001517static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518{
David S. Miller0dbaee32010-12-13 12:52:14 -08001519 struct net_device *dev = dst->dev;
1520 unsigned int mtu = dst_mtu(dst);
1521 struct net *net = dev_net(dev);
1522
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
1524
Daniel Lezcano55786892008-03-04 13:47:47 -08001525 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
1526 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527
1528 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001529 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
1530 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
1531 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 * rely only on pmtu discovery"
1533 */
1534 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
1535 mtu = IPV6_MAXPLEN;
1536 return mtu;
1537}
1538
Steffen Klassertebb762f2011-11-23 02:12:51 +00001539static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08001540{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001541 const struct rt6_info *rt = (const struct rt6_info *)dst;
1542 unsigned int mtu = rt->rt6i_pmtu;
David S. Millerd33e4552010-12-14 13:01:14 -08001543 struct inet6_dev *idev;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001544
1545 if (mtu)
Eric Dumazet30f78d82014-04-10 21:23:36 -07001546 goto out;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001547
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001548 mtu = dst_metric_raw(dst, RTAX_MTU);
1549 if (mtu)
1550 goto out;
1551
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001552 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08001553
1554 rcu_read_lock();
1555 idev = __in6_dev_get(dst->dev);
1556 if (idev)
1557 mtu = idev->cnf.mtu6;
1558 rcu_read_unlock();
1559
Eric Dumazet30f78d82014-04-10 21:23:36 -07001560out:
1561 return min_t(unsigned int, mtu, IP6_MAX_MTU);
David S. Millerd33e4552010-12-14 13:01:14 -08001562}
1563
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001564static struct dst_entry *icmp6_dst_gc_list;
1565static DEFINE_SPINLOCK(icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001566
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001567struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05001568 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569{
David S. Miller87a11572011-12-06 17:04:13 -05001570 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 struct rt6_info *rt;
1572 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001573 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
David S. Miller38308472011-12-03 18:02:47 -05001575 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00001576 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577
Martin KaFai Lauad706862015-08-14 11:05:52 -07001578 rt = ip6_dst_alloc(net, dev, 0);
David S. Miller38308472011-12-03 18:02:47 -05001579 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05001581 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 goto out;
1583 }
1584
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001585 rt->dst.flags |= DST_HOST;
1586 rt->dst.output = ip6_output;
Changli Gaod8d1f302010-06-10 23:31:35 -07001587 atomic_set(&rt->dst.__refcnt, 1);
Julian Anastasov550bab42013-10-20 15:43:04 +03001588 rt->rt6i_gateway = fl6->daddr;
David S. Miller87a11572011-12-06 17:04:13 -05001589 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001590 rt->rt6i_dst.plen = 128;
1591 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08001592 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001594 spin_lock_bh(&icmp6_dst_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001595 rt->dst.next = icmp6_dst_gc_list;
1596 icmp6_dst_gc_list = &rt->dst;
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001597 spin_unlock_bh(&icmp6_dst_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598
Daniel Lezcano55786892008-03-04 13:47:47 -08001599 fib6_force_start_gc(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600
David S. Miller87a11572011-12-06 17:04:13 -05001601 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
1602
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603out:
David S. Miller87a11572011-12-06 17:04:13 -05001604 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605}
1606
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001607int icmp6_dst_gc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608{
Hagen Paul Pfeifere9476e92011-02-25 05:45:19 +00001609 struct dst_entry *dst, **pprev;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001610 int more = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001612 spin_lock_bh(&icmp6_dst_lock);
1613 pprev = &icmp6_dst_gc_list;
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001614
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 while ((dst = *pprev) != NULL) {
1616 if (!atomic_read(&dst->__refcnt)) {
1617 *pprev = dst->next;
1618 dst_free(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 } else {
1620 pprev = &dst->next;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001621 ++more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 }
1623 }
1624
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001625 spin_unlock_bh(&icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001626
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001627 return more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628}
1629
David S. Miller1e493d12008-09-10 17:27:15 -07001630static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg),
1631 void *arg)
1632{
1633 struct dst_entry *dst, **pprev;
1634
1635 spin_lock_bh(&icmp6_dst_lock);
1636 pprev = &icmp6_dst_gc_list;
1637 while ((dst = *pprev) != NULL) {
1638 struct rt6_info *rt = (struct rt6_info *) dst;
1639 if (func(rt, arg)) {
1640 *pprev = dst->next;
1641 dst_free(dst);
1642 } else {
1643 pprev = &dst->next;
1644 }
1645 }
1646 spin_unlock_bh(&icmp6_dst_lock);
1647}
1648
Daniel Lezcano569d3642008-01-18 03:56:57 -08001649static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650{
Alexey Dobriyan86393e52009-08-29 01:34:49 +00001651 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08001652 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
1653 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
1654 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
1655 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
1656 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001657 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658
Eric Dumazetfc66f952010-10-08 06:37:34 +00001659 entries = dst_entries_get_fast(ops);
Michal Kubeček49a18d82013-08-01 10:04:24 +02001660 if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00001661 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 goto out;
1663
Benjamin Thery6891a342008-03-04 13:49:47 -08001664 net->ipv6.ip6_rt_gc_expire++;
Li RongQing14956642014-05-19 17:30:28 +08001665 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
Eric Dumazetfc66f952010-10-08 06:37:34 +00001666 entries = dst_entries_get_slow(ops);
1667 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08001668 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08001670 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001671 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672}
1673
Florian Westphale715b6d2015-01-05 23:57:44 +01001674static int ip6_convert_metrics(struct mx6_config *mxc,
1675 const struct fib6_config *cfg)
1676{
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001677 bool ecn_ca = false;
Florian Westphale715b6d2015-01-05 23:57:44 +01001678 struct nlattr *nla;
1679 int remaining;
1680 u32 *mp;
1681
Ian Morris63159f22015-03-29 14:00:04 +01001682 if (!cfg->fc_mx)
Florian Westphale715b6d2015-01-05 23:57:44 +01001683 return 0;
1684
1685 mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
1686 if (unlikely(!mp))
1687 return -ENOMEM;
1688
1689 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
1690 int type = nla_type(nla);
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001691 u32 val;
Florian Westphale715b6d2015-01-05 23:57:44 +01001692
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001693 if (!type)
1694 continue;
1695 if (unlikely(type > RTAX_MAX))
1696 goto err;
Daniel Borkmannea697632015-01-05 23:57:47 +01001697
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001698 if (type == RTAX_CC_ALGO) {
1699 char tmp[TCP_CA_NAME_MAX];
1700
1701 nla_strlcpy(tmp, nla, sizeof(tmp));
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001702 val = tcp_ca_get_key_by_name(tmp, &ecn_ca);
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001703 if (val == TCP_CA_UNSPEC)
Florian Westphale715b6d2015-01-05 23:57:44 +01001704 goto err;
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001705 } else {
1706 val = nla_get_u32(nla);
Florian Westphale715b6d2015-01-05 23:57:44 +01001707 }
Daniel Borkmannb8d3e412015-08-31 15:58:46 +02001708 if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK))
1709 goto err;
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001710
1711 mp[type - 1] = val;
1712 __set_bit(type - 1, mxc->mx_valid);
Florian Westphale715b6d2015-01-05 23:57:44 +01001713 }
1714
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001715 if (ecn_ca) {
1716 __set_bit(RTAX_FEATURES - 1, mxc->mx_valid);
1717 mp[RTAX_FEATURES - 1] |= DST_FEATURE_ECN_CA;
1718 }
Florian Westphale715b6d2015-01-05 23:57:44 +01001719
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001720 mxc->mx = mp;
Florian Westphale715b6d2015-01-05 23:57:44 +01001721 return 0;
1722 err:
1723 kfree(mp);
1724 return -EINVAL;
1725}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07001727int ip6_route_info_create(struct fib6_config *cfg, struct rt6_info **rt_ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728{
1729 int err;
Daniel Lezcano55786892008-03-04 13:47:47 -08001730 struct net *net = cfg->fc_nlinfo.nl_net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 struct rt6_info *rt = NULL;
1732 struct net_device *dev = NULL;
1733 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001734 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 int addr_type;
1736
Thomas Graf86872cb2006-08-22 00:01:08 -07001737 if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 return -EINVAL;
1739#ifndef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001740 if (cfg->fc_src_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 return -EINVAL;
1742#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07001743 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08001745 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 if (!dev)
1747 goto out;
1748 idev = in6_dev_get(dev);
1749 if (!idev)
1750 goto out;
1751 }
1752
Thomas Graf86872cb2006-08-22 00:01:08 -07001753 if (cfg->fc_metric == 0)
1754 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755
Matti Vaittinend71314b2011-11-14 00:14:49 +00001756 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05001757 if (cfg->fc_nlinfo.nlh &&
1758 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00001759 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001760 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00001761 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00001762 table = fib6_new_table(net, cfg->fc_table);
1763 }
1764 } else {
1765 table = fib6_new_table(net, cfg->fc_table);
1766 }
David S. Miller38308472011-12-03 18:02:47 -05001767
1768 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001769 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07001770
Martin KaFai Lauad706862015-08-14 11:05:52 -07001771 rt = ip6_dst_alloc(net, NULL,
1772 (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773
David S. Miller38308472011-12-03 18:02:47 -05001774 if (!rt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 err = -ENOMEM;
1776 goto out;
1777 }
1778
Gao feng1716a962012-04-06 00:13:10 +00001779 if (cfg->fc_flags & RTF_EXPIRES)
1780 rt6_set_expires(rt, jiffies +
1781 clock_t_to_jiffies(cfg->fc_expires));
1782 else
1783 rt6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784
Thomas Graf86872cb2006-08-22 00:01:08 -07001785 if (cfg->fc_protocol == RTPROT_UNSPEC)
1786 cfg->fc_protocol = RTPROT_BOOT;
1787 rt->rt6i_protocol = cfg->fc_protocol;
1788
1789 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790
1791 if (addr_type & IPV6_ADDR_MULTICAST)
Changli Gaod8d1f302010-06-10 23:31:35 -07001792 rt->dst.input = ip6_mc_input;
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00001793 else if (cfg->fc_flags & RTF_LOCAL)
1794 rt->dst.input = ip6_input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 else
Changli Gaod8d1f302010-06-10 23:31:35 -07001796 rt->dst.input = ip6_forward;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797
Changli Gaod8d1f302010-06-10 23:31:35 -07001798 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799
Roopa Prabhu19e42e42015-07-21 10:43:48 +02001800 if (cfg->fc_encap) {
1801 struct lwtunnel_state *lwtstate;
1802
1803 err = lwtunnel_build_state(dev, cfg->fc_encap_type,
Tom Herbert127eb7c2015-08-24 09:45:41 -07001804 cfg->fc_encap, AF_INET6, cfg,
1805 &lwtstate);
Roopa Prabhu19e42e42015-07-21 10:43:48 +02001806 if (err)
1807 goto out;
Jiri Benc61adedf2015-08-20 13:56:25 +02001808 rt->dst.lwtstate = lwtstate_get(lwtstate);
1809 if (lwtunnel_output_redirect(rt->dst.lwtstate)) {
1810 rt->dst.lwtstate->orig_output = rt->dst.output;
1811 rt->dst.output = lwtunnel_output;
Tom Herbert25368622015-08-17 13:42:24 -07001812 }
Jiri Benc61adedf2015-08-20 13:56:25 +02001813 if (lwtunnel_input_redirect(rt->dst.lwtstate)) {
1814 rt->dst.lwtstate->orig_input = rt->dst.input;
1815 rt->dst.input = lwtunnel_input;
Tom Herbert25368622015-08-17 13:42:24 -07001816 }
Roopa Prabhu19e42e42015-07-21 10:43:48 +02001817 }
1818
Thomas Graf86872cb2006-08-22 00:01:08 -07001819 ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
1820 rt->rt6i_dst.plen = cfg->fc_dst_len;
Martin KaFai Lauafc4eef2015-04-28 13:03:07 -07001821 if (rt->rt6i_dst.plen == 128)
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001822 rt->dst.flags |= DST_HOST;
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001823
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824#ifdef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001825 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
1826 rt->rt6i_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827#endif
1828
Thomas Graf86872cb2006-08-22 00:01:08 -07001829 rt->rt6i_metric = cfg->fc_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830
1831 /* We cannot add true routes via loopback here,
1832 they would result in kernel looping; promote them to reject routes
1833 */
Thomas Graf86872cb2006-08-22 00:01:08 -07001834 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05001835 (dev && (dev->flags & IFF_LOOPBACK) &&
1836 !(addr_type & IPV6_ADDR_LOOPBACK) &&
1837 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08001839 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 if (dev) {
1841 dev_put(dev);
1842 in6_dev_put(idev);
1843 }
Daniel Lezcano55786892008-03-04 13:47:47 -08001844 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 dev_hold(dev);
1846 idev = in6_dev_get(dev);
1847 if (!idev) {
1848 err = -ENODEV;
1849 goto out;
1850 }
1851 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001853 switch (cfg->fc_type) {
1854 case RTN_BLACKHOLE:
1855 rt->dst.error = -EINVAL;
Eric Dumazetaad88722014-04-15 13:47:15 -04001856 rt->dst.output = dst_discard_sk;
Kamala R7150aed2013-12-02 19:55:21 +05301857 rt->dst.input = dst_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001858 break;
1859 case RTN_PROHIBIT:
1860 rt->dst.error = -EACCES;
Kamala R7150aed2013-12-02 19:55:21 +05301861 rt->dst.output = ip6_pkt_prohibit_out;
1862 rt->dst.input = ip6_pkt_prohibit;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001863 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00001864 case RTN_THROW:
Nikola Forró0315e382015-09-17 16:01:32 +02001865 case RTN_UNREACHABLE:
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001866 default:
Kamala R7150aed2013-12-02 19:55:21 +05301867 rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN
Nikola Forró0315e382015-09-17 16:01:32 +02001868 : (cfg->fc_type == RTN_UNREACHABLE)
1869 ? -EHOSTUNREACH : -ENETUNREACH;
Kamala R7150aed2013-12-02 19:55:21 +05301870 rt->dst.output = ip6_pkt_discard_out;
1871 rt->dst.input = ip6_pkt_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001872 break;
1873 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 goto install_route;
1875 }
1876
Thomas Graf86872cb2006-08-22 00:01:08 -07001877 if (cfg->fc_flags & RTF_GATEWAY) {
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001878 const struct in6_addr *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 int gwa_type;
1880
Thomas Graf86872cb2006-08-22 00:01:08 -07001881 gw_addr = &cfg->fc_gateway;
Florian Westphal330567b2015-08-07 10:54:28 +02001882 gwa_type = ipv6_addr_type(gw_addr);
Florian Westphal48ed7b22015-05-21 00:25:41 +02001883
1884 /* if gw_addr is local we will fail to detect this in case
1885 * address is still TENTATIVE (DAD in progress). rt6_lookup()
1886 * will return already-added prefix route via interface that
1887 * prefix route was assigned to, which might be non-loopback.
1888 */
1889 err = -EINVAL;
Florian Westphal330567b2015-08-07 10:54:28 +02001890 if (ipv6_chk_addr_and_flags(net, gw_addr,
1891 gwa_type & IPV6_ADDR_LINKLOCAL ?
1892 dev : NULL, 0, 0))
Florian Westphal48ed7b22015-05-21 00:25:41 +02001893 goto out;
1894
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001895 rt->rt6i_gateway = *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896
1897 if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
1898 struct rt6_info *grt;
1899
1900 /* IPv6 strictly inhibits using not link-local
1901 addresses as nexthop address.
1902 Otherwise, router will not able to send redirects.
1903 It is very good, but in some (rare!) circumstances
1904 (SIT, PtP, NBMA NOARP links) it is handy to allow
1905 some exceptions. --ANK
1906 */
David S. Miller38308472011-12-03 18:02:47 -05001907 if (!(gwa_type & IPV6_ADDR_UNICAST))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 goto out;
1909
Daniel Lezcano55786892008-03-04 13:47:47 -08001910 grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911
1912 err = -EHOSTUNREACH;
David S. Miller38308472011-12-03 18:02:47 -05001913 if (!grt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 goto out;
1915 if (dev) {
David S. Millerd1918542011-12-28 20:19:20 -05001916 if (dev != grt->dst.dev) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00001917 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 goto out;
1919 }
1920 } else {
David S. Millerd1918542011-12-28 20:19:20 -05001921 dev = grt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 idev = grt->rt6i_idev;
1923 dev_hold(dev);
1924 in6_dev_hold(grt->rt6i_idev);
1925 }
David S. Miller38308472011-12-03 18:02:47 -05001926 if (!(grt->rt6i_flags & RTF_GATEWAY))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 err = 0;
Amerigo Wang94e187c2012-10-29 00:13:19 +00001928 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929
1930 if (err)
1931 goto out;
1932 }
1933 err = -EINVAL;
David S. Miller38308472011-12-03 18:02:47 -05001934 if (!dev || (dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 goto out;
1936 }
1937
1938 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05001939 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 goto out;
1941
Daniel Walterc3968a82011-04-13 21:10:57 +00001942 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
1943 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
1944 err = -EINVAL;
1945 goto out;
1946 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001947 rt->rt6i_prefsrc.addr = cfg->fc_prefsrc;
Daniel Walterc3968a82011-04-13 21:10:57 +00001948 rt->rt6i_prefsrc.plen = 128;
1949 } else
1950 rt->rt6i_prefsrc.plen = 0;
1951
Thomas Graf86872cb2006-08-22 00:01:08 -07001952 rt->rt6i_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953
1954install_route:
Changli Gaod8d1f302010-06-10 23:31:35 -07001955 rt->dst.dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 rt->rt6i_idev = idev;
Thomas Grafc71099a2006-08-04 23:20:06 -07001957 rt->rt6i_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001958
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001959 cfg->fc_nlinfo.nl_net = dev_net(dev);
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001960
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07001961 *rt_ret = rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07001963 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964out:
1965 if (dev)
1966 dev_put(dev);
1967 if (idev)
1968 in6_dev_put(idev);
1969 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07001970 dst_free(&rt->dst);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07001971
1972 *rt_ret = NULL;
1973
1974 return err;
1975}
1976
1977int ip6_route_add(struct fib6_config *cfg)
1978{
1979 struct mx6_config mxc = { .mx = NULL, };
1980 struct rt6_info *rt = NULL;
1981 int err;
1982
1983 err = ip6_route_info_create(cfg, &rt);
1984 if (err)
1985 goto out;
1986
1987 err = ip6_convert_metrics(&mxc, cfg);
1988 if (err)
1989 goto out;
1990
1991 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, &mxc);
1992
1993 kfree(mxc.mx);
1994
1995 return err;
1996out:
1997 if (rt)
1998 dst_free(&rt->dst);
1999
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 return err;
2001}
2002
Thomas Graf86872cb2006-08-22 00:01:08 -07002003static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004{
2005 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07002006 struct fib6_table *table;
David S. Millerd1918542011-12-28 20:19:20 -05002007 struct net *net = dev_net(rt->dst.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008
Martin KaFai Lau8e3d5be2015-09-15 14:30:08 -07002009 if (rt == net->ipv6.ip6_null_entry ||
2010 rt->dst.flags & DST_NOCACHE) {
Gao feng6825a262012-09-19 19:25:34 +00002011 err = -ENOENT;
2012 goto out;
2013 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07002014
Thomas Grafc71099a2006-08-04 23:20:06 -07002015 table = rt->rt6i_table;
2016 write_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07002017 err = fib6_del(rt, info);
Thomas Grafc71099a2006-08-04 23:20:06 -07002018 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019
Gao feng6825a262012-09-19 19:25:34 +00002020out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00002021 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 return err;
2023}
2024
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002025int ip6_del_rt(struct rt6_info *rt)
2026{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08002027 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -05002028 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08002029 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002030 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002031}
2032
Thomas Graf86872cb2006-08-22 00:01:08 -07002033static int ip6_route_del(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034{
Thomas Grafc71099a2006-08-04 23:20:06 -07002035 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 struct fib6_node *fn;
2037 struct rt6_info *rt;
2038 int err = -ESRCH;
2039
Daniel Lezcano55786892008-03-04 13:47:47 -08002040 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05002041 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002042 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043
Thomas Grafc71099a2006-08-04 23:20:06 -07002044 read_lock_bh(&table->tb6_lock);
2045
2046 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07002047 &cfg->fc_dst, cfg->fc_dst_len,
2048 &cfg->fc_src, cfg->fc_src_len);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002049
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050 if (fn) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002051 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
Martin KaFai Lau1f56a012015-04-28 13:03:03 -07002052 if ((rt->rt6i_flags & RTF_CACHE) &&
2053 !(cfg->fc_flags & RTF_CACHE))
2054 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002055 if (cfg->fc_ifindex &&
David S. Millerd1918542011-12-28 20:19:20 -05002056 (!rt->dst.dev ||
2057 rt->dst.dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002059 if (cfg->fc_flags & RTF_GATEWAY &&
2060 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002062 if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07002064 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07002065 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066
Thomas Graf86872cb2006-08-22 00:01:08 -07002067 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 }
2069 }
Thomas Grafc71099a2006-08-04 23:20:06 -07002070 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071
2072 return err;
2073}
2074
David S. Miller6700c272012-07-17 03:29:28 -07002075static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07002076{
David S. Millere8599ff2012-07-11 23:43:53 -07002077 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07002078 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07002079 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07002080 struct ndisc_options ndopts;
2081 struct inet6_dev *in6_dev;
2082 struct neighbour *neigh;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002083 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07002084 int optlen, on_link;
2085 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07002086
Simon Horman29a3cad2013-05-28 20:34:26 +00002087 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002088 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07002089
2090 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07002091 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002092 return;
2093 }
2094
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002095 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07002096
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002097 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07002098 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002099 return;
2100 }
2101
David S. Miller6e157b62012-07-12 00:05:02 -07002102 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002103 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07002104 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002105 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07002106 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07002107 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002108 return;
2109 }
2110
2111 in6_dev = __in6_dev_get(skb->dev);
2112 if (!in6_dev)
2113 return;
2114 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
2115 return;
2116
2117 /* RFC2461 8.1:
2118 * The IP source address of the Redirect MUST be the same as the current
2119 * first-hop router for the specified ICMP Destination Address.
2120 */
2121
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002122 if (!ndisc_parse_options(msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07002123 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
2124 return;
2125 }
David S. Miller6e157b62012-07-12 00:05:02 -07002126
2127 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07002128 if (ndopts.nd_opts_tgt_lladdr) {
2129 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
2130 skb->dev);
2131 if (!lladdr) {
2132 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
2133 return;
2134 }
2135 }
2136
David S. Miller6e157b62012-07-12 00:05:02 -07002137 rt = (struct rt6_info *) dst;
2138 if (rt == net->ipv6.ip6_null_entry) {
2139 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
2140 return;
2141 }
2142
2143 /* Redirect received -> path was valid.
2144 * Look, redirects are sent only in response to data packets,
2145 * so that this nexthop apparently is reachable. --ANK
2146 */
2147 dst_confirm(&rt->dst);
2148
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002149 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07002150 if (!neigh)
2151 return;
2152
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 /*
2154 * We have finally decided to accept it.
2155 */
2156
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002157 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 NEIGH_UPDATE_F_WEAK_OVERRIDE|
2159 NEIGH_UPDATE_F_OVERRIDE|
2160 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
2161 NEIGH_UPDATE_F_ISROUTER))
2162 );
2163
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002164 nrt = ip6_rt_cache_alloc(rt, &msg->dest, NULL);
David S. Miller38308472011-12-03 18:02:47 -05002165 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 goto out;
2167
2168 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
2169 if (on_link)
2170 nrt->rt6i_flags &= ~RTF_GATEWAY;
2171
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002172 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173
Thomas Graf40e22e82006-08-22 00:00:45 -07002174 if (ip6_ins_rt(nrt))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 goto out;
2176
Changli Gaod8d1f302010-06-10 23:31:35 -07002177 netevent.old = &rt->dst;
2178 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002179 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00002180 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07002181 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
2182
David S. Miller38308472011-12-03 18:02:47 -05002183 if (rt->rt6i_flags & RTF_CACHE) {
David S. Miller6e157b62012-07-12 00:05:02 -07002184 rt = (struct rt6_info *) dst_clone(&rt->dst);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002185 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 }
2187
2188out:
David S. Millere8599ff2012-07-11 23:43:53 -07002189 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07002190}
2191
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 * Misc support functions
2194 */
2195
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002196static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from)
2197{
2198 BUG_ON(from->dst.from);
2199
2200 rt->rt6i_flags &= ~RTF_EXPIRES;
2201 dst_hold(&from->dst);
2202 rt->dst.from = &from->dst;
2203 dst_init_metrics(&rt->dst, dst_metrics_ptr(&from->dst), true);
2204}
2205
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002206static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207{
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002208 rt->dst.input = ort->dst.input;
2209 rt->dst.output = ort->dst.output;
2210 rt->rt6i_dst = ort->rt6i_dst;
2211 rt->dst.error = ort->dst.error;
2212 rt->rt6i_idev = ort->rt6i_idev;
2213 if (rt->rt6i_idev)
2214 in6_dev_hold(rt->rt6i_idev);
2215 rt->dst.lastuse = jiffies;
2216 rt->rt6i_gateway = ort->rt6i_gateway;
2217 rt->rt6i_flags = ort->rt6i_flags;
2218 rt6_set_from(rt, ort);
2219 rt->rt6i_metric = ort->rt6i_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002221 rt->rt6i_src = ort->rt6i_src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222#endif
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002223 rt->rt6i_prefsrc = ort->rt6i_prefsrc;
2224 rt->rt6i_table = ort->rt6i_table;
Jiri Benc61adedf2015-08-20 13:56:25 +02002225 rt->dst.lwtstate = lwtstate_get(ort->dst.lwtstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226}
2227
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002228#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002229static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002230 const struct in6_addr *prefix, int prefixlen,
2231 const struct in6_addr *gwaddr, int ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002232{
2233 struct fib6_node *fn;
2234 struct rt6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07002235 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002236
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002237 table = fib6_get_table(net, RT6_TABLE_INFO);
David S. Miller38308472011-12-03 18:02:47 -05002238 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002239 return NULL;
2240
Li RongQing5744dd92012-09-11 21:59:01 +00002241 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01002242 fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002243 if (!fn)
2244 goto out;
2245
Changli Gaod8d1f302010-06-10 23:31:35 -07002246 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05002247 if (rt->dst.dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002248 continue;
2249 if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
2250 continue;
2251 if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
2252 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07002253 dst_hold(&rt->dst);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002254 break;
2255 }
2256out:
Li RongQing5744dd92012-09-11 21:59:01 +00002257 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002258 return rt;
2259}
2260
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002261static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002262 const struct in6_addr *prefix, int prefixlen,
2263 const struct in6_addr *gwaddr, int ifindex,
Eric Dumazet95c96172012-04-15 05:58:06 +00002264 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002265{
Thomas Graf86872cb2006-08-22 00:01:08 -07002266 struct fib6_config cfg = {
2267 .fc_table = RT6_TABLE_INFO,
Rami Rosen238fc7e2008-02-09 23:43:11 -08002268 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07002269 .fc_ifindex = ifindex,
2270 .fc_dst_len = prefixlen,
2271 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
2272 RTF_UP | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00002273 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002274 .fc_nlinfo.nlh = NULL,
2275 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07002276 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002277
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002278 cfg.fc_dst = *prefix;
2279 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07002280
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08002281 /* We should treat it as a default route if prefix length is 0. */
2282 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07002283 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002284
Thomas Graf86872cb2006-08-22 00:01:08 -07002285 ip6_route_add(&cfg);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002286
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002287 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002288}
2289#endif
2290
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002291struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002292{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07002294 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002296 table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05002297 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002298 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299
Li RongQing5744dd92012-09-11 21:59:01 +00002300 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01002301 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05002302 if (dev == rt->dst.dev &&
YOSHIFUJI Hideaki045927f2006-03-20 17:00:48 -08002303 ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 ipv6_addr_equal(&rt->rt6i_gateway, addr))
2305 break;
2306 }
2307 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07002308 dst_hold(&rt->dst);
Li RongQing5744dd92012-09-11 21:59:01 +00002309 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 return rt;
2311}
2312
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002313struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08002314 struct net_device *dev,
2315 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316{
Thomas Graf86872cb2006-08-22 00:01:08 -07002317 struct fib6_config cfg = {
2318 .fc_table = RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08002319 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07002320 .fc_ifindex = dev->ifindex,
2321 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
2322 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00002323 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08002324 .fc_nlinfo.nlh = NULL,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002325 .fc_nlinfo.nl_net = dev_net(dev),
Thomas Graf86872cb2006-08-22 00:01:08 -07002326 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002328 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329
Thomas Graf86872cb2006-08-22 00:01:08 -07002330 ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 return rt6_get_dflt_router(gwaddr, dev);
2333}
2334
Daniel Lezcano7b4da532008-03-04 13:47:14 -08002335void rt6_purge_dflt_routers(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336{
2337 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07002338 struct fib6_table *table;
2339
2340 /* NOTE: Keep consistent with rt6_get_dflt_router */
Daniel Lezcano7b4da532008-03-04 13:47:14 -08002341 table = fib6_get_table(net, RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05002342 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002343 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344
2345restart:
Thomas Grafc71099a2006-08-04 23:20:06 -07002346 read_lock_bh(&table->tb6_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07002347 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
Lorenzo Colitti3e8b0ac2013-03-03 20:46:46 +00002348 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
2349 (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002350 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07002351 read_unlock_bh(&table->tb6_lock);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002352 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 goto restart;
2354 }
2355 }
Thomas Grafc71099a2006-08-04 23:20:06 -07002356 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357}
2358
Daniel Lezcano55786892008-03-04 13:47:47 -08002359static void rtmsg_to_fib6_config(struct net *net,
2360 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07002361 struct fib6_config *cfg)
2362{
2363 memset(cfg, 0, sizeof(*cfg));
2364
2365 cfg->fc_table = RT6_TABLE_MAIN;
2366 cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
2367 cfg->fc_metric = rtmsg->rtmsg_metric;
2368 cfg->fc_expires = rtmsg->rtmsg_info;
2369 cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
2370 cfg->fc_src_len = rtmsg->rtmsg_src_len;
2371 cfg->fc_flags = rtmsg->rtmsg_flags;
2372
Daniel Lezcano55786892008-03-04 13:47:47 -08002373 cfg->fc_nlinfo.nl_net = net;
Benjamin Theryf1243c22008-02-26 18:10:03 -08002374
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002375 cfg->fc_dst = rtmsg->rtmsg_dst;
2376 cfg->fc_src = rtmsg->rtmsg_src;
2377 cfg->fc_gateway = rtmsg->rtmsg_gateway;
Thomas Graf86872cb2006-08-22 00:01:08 -07002378}
2379
Daniel Lezcano55786892008-03-04 13:47:47 -08002380int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381{
Thomas Graf86872cb2006-08-22 00:01:08 -07002382 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 struct in6_rtmsg rtmsg;
2384 int err;
2385
Ian Morris67ba4152014-08-24 21:53:10 +01002386 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 case SIOCADDRT: /* Add a route */
2388 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00002389 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 return -EPERM;
2391 err = copy_from_user(&rtmsg, arg,
2392 sizeof(struct in6_rtmsg));
2393 if (err)
2394 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07002395
Daniel Lezcano55786892008-03-04 13:47:47 -08002396 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07002397
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 rtnl_lock();
2399 switch (cmd) {
2400 case SIOCADDRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07002401 err = ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 break;
2403 case SIOCDELRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07002404 err = ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 break;
2406 default:
2407 err = -EINVAL;
2408 }
2409 rtnl_unlock();
2410
2411 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07002412 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413
2414 return -EINVAL;
2415}
2416
2417/*
2418 * Drop the packet on the floor
2419 */
2420
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07002421static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002423 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00002424 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002425 switch (ipstats_mib_noroutes) {
2426 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07002427 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00002428 if (type == IPV6_ADDR_ANY) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002429 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2430 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002431 break;
2432 }
2433 /* FALLTHROUGH */
2434 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002435 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2436 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002437 break;
2438 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002439 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 kfree_skb(skb);
2441 return 0;
2442}
2443
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002444static int ip6_pkt_discard(struct sk_buff *skb)
2445{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002446 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002447}
2448
Eric Dumazetaad88722014-04-15 13:47:15 -04002449static int ip6_pkt_discard_out(struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450{
Eric Dumazetadf30902009-06-02 05:19:30 +00002451 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002452 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453}
2454
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002455static int ip6_pkt_prohibit(struct sk_buff *skb)
2456{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002457 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002458}
2459
Eric Dumazetaad88722014-04-15 13:47:15 -04002460static int ip6_pkt_prohibit_out(struct sock *sk, struct sk_buff *skb)
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002461{
Eric Dumazetadf30902009-06-02 05:19:30 +00002462 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002463 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002464}
2465
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466/*
2467 * Allocate a dst for local (unicast / anycast) address.
2468 */
2469
2470struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
2471 const struct in6_addr *addr,
David S. Miller8f031512011-12-06 16:48:14 -05002472 bool anycast)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002474 struct net *net = dev_net(idev->dev);
Hannes Frederic Sowaa3300ef2013-12-07 03:33:45 +01002475 struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev,
Martin KaFai Lauad706862015-08-14 11:05:52 -07002476 DST_NOCOUNT);
Hannes Frederic Sowaa3300ef2013-12-07 03:33:45 +01002477 if (!rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 return ERR_PTR(-ENOMEM);
2479
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 in6_dev_hold(idev);
2481
David S. Miller11d53b42011-06-24 15:23:34 -07002482 rt->dst.flags |= DST_HOST;
Changli Gaod8d1f302010-06-10 23:31:35 -07002483 rt->dst.input = ip6_input;
2484 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 rt->rt6i_idev = idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486
2487 rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +09002488 if (anycast)
2489 rt->rt6i_flags |= RTF_ANYCAST;
2490 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 rt->rt6i_flags |= RTF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492
Julian Anastasov550bab42013-10-20 15:43:04 +03002493 rt->rt6i_gateway = *addr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002494 rt->rt6i_dst.addr = *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 rt->rt6i_dst.plen = 128;
Daniel Lezcano55786892008-03-04 13:47:47 -08002496 rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL);
Martin KaFai Lau8e3d5be2015-09-15 14:30:08 -07002497 rt->dst.flags |= DST_NOCACHE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498
Changli Gaod8d1f302010-06-10 23:31:35 -07002499 atomic_set(&rt->dst.__refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500
2501 return rt;
2502}
2503
Daniel Walterc3968a82011-04-13 21:10:57 +00002504int ip6_route_get_saddr(struct net *net,
2505 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002506 const struct in6_addr *daddr,
Daniel Walterc3968a82011-04-13 21:10:57 +00002507 unsigned int prefs,
2508 struct in6_addr *saddr)
2509{
Markus Stenberge16e8882015-05-05 13:36:59 +03002510 struct inet6_dev *idev =
2511 rt ? ip6_dst_idev((struct dst_entry *)rt) : NULL;
Daniel Walterc3968a82011-04-13 21:10:57 +00002512 int err = 0;
Markus Stenberge16e8882015-05-05 13:36:59 +03002513 if (rt && rt->rt6i_prefsrc.plen)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002514 *saddr = rt->rt6i_prefsrc.addr;
Daniel Walterc3968a82011-04-13 21:10:57 +00002515 else
2516 err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
2517 daddr, prefs, saddr);
2518 return err;
2519}
2520
2521/* remove deleted ip from prefsrc entries */
2522struct arg_dev_net_ip {
2523 struct net_device *dev;
2524 struct net *net;
2525 struct in6_addr *addr;
2526};
2527
2528static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
2529{
2530 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
2531 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
2532 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
2533
David S. Millerd1918542011-12-28 20:19:20 -05002534 if (((void *)rt->dst.dev == dev || !dev) &&
Daniel Walterc3968a82011-04-13 21:10:57 +00002535 rt != net->ipv6.ip6_null_entry &&
2536 ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
2537 /* remove prefsrc entry */
2538 rt->rt6i_prefsrc.plen = 0;
2539 }
2540 return 0;
2541}
2542
2543void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
2544{
2545 struct net *net = dev_net(ifp->idev->dev);
2546 struct arg_dev_net_ip adni = {
2547 .dev = ifp->idev->dev,
2548 .net = net,
2549 .addr = &ifp->addr,
2550 };
Li RongQing0c3584d2013-12-27 16:32:38 +08002551 fib6_clean_all(net, fib6_remove_prefsrc, &adni);
Daniel Walterc3968a82011-04-13 21:10:57 +00002552}
2553
Duan Jiongbe7a0102014-05-15 15:56:14 +08002554#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY)
2555#define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE)
2556
2557/* Remove routers and update dst entries when gateway turn into host. */
2558static int fib6_clean_tohost(struct rt6_info *rt, void *arg)
2559{
2560 struct in6_addr *gateway = (struct in6_addr *)arg;
2561
2562 if ((((rt->rt6i_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) ||
2563 ((rt->rt6i_flags & RTF_CACHE_GATEWAY) == RTF_CACHE_GATEWAY)) &&
2564 ipv6_addr_equal(gateway, &rt->rt6i_gateway)) {
2565 return -1;
2566 }
2567 return 0;
2568}
2569
2570void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
2571{
2572 fib6_clean_all(net, fib6_clean_tohost, gateway);
2573}
2574
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002575struct arg_dev_net {
2576 struct net_device *dev;
2577 struct net *net;
2578};
2579
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580static int fib6_ifdown(struct rt6_info *rt, void *arg)
2581{
stephen hemmingerbc3ef662010-12-16 17:42:40 +00002582 const struct arg_dev_net *adn = arg;
2583 const struct net_device *dev = adn->dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002584
David S. Millerd1918542011-12-28 20:19:20 -05002585 if ((rt->dst.dev == dev || !dev) &&
David S. Millerc159d302011-12-26 15:24:36 -05002586 rt != adn->net->ipv6.ip6_null_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 return -1;
David S. Millerc159d302011-12-26 15:24:36 -05002588
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 return 0;
2590}
2591
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002592void rt6_ifdown(struct net *net, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002594 struct arg_dev_net adn = {
2595 .dev = dev,
2596 .net = net,
2597 };
2598
Li RongQing0c3584d2013-12-27 16:32:38 +08002599 fib6_clean_all(net, fib6_ifdown, &adn);
David S. Miller1e493d12008-09-10 17:27:15 -07002600 icmp6_clean_all(fib6_ifdown, &adn);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07002601 rt6_uncached_list_flush_dev(net, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602}
2603
Eric Dumazet95c96172012-04-15 05:58:06 +00002604struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00002606 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607};
2608
2609static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
2610{
2611 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
2612 struct inet6_dev *idev;
2613
2614 /* In IPv6 pmtu discovery is not optional,
2615 so that RTAX_MTU lock cannot disable it.
2616 We still use this lock to block changes
2617 caused by addrconf/ndisc.
2618 */
2619
2620 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05002621 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 return 0;
2623
2624 /* For administrative MTU increase, there is no way to discover
2625 IPv6 PMTU increase, so PMTU increase should be updated here.
2626 Since RFC 1981 doesn't include administrative MTU increase
2627 update PMTU increase is a MUST. (i.e. jumbo frame)
2628 */
2629 /*
2630 If new MTU is less than route PMTU, this new MTU will be the
2631 lowest MTU in the path, update the route PMTU to reflect PMTU
2632 decreases; if new MTU is greater than route PMTU, and the
2633 old MTU is the lowest MTU in the path, update the route PMTU
2634 to reflect the increase. In this case if the other nodes' MTU
2635 also have the lowest MTU, TOO BIG MESSAGE will be lead to
2636 PMTU discouvery.
2637 */
David S. Millerd1918542011-12-28 20:19:20 -05002638 if (rt->dst.dev == arg->dev &&
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002639 !dst_metric_locked(&rt->dst, RTAX_MTU)) {
2640 if (rt->rt6i_flags & RTF_CACHE) {
2641 /* For RTF_CACHE with rt6i_pmtu == 0
2642 * (i.e. a redirected route),
2643 * the metrics of its rt->dst.from has already
2644 * been updated.
2645 */
2646 if (rt->rt6i_pmtu && rt->rt6i_pmtu > arg->mtu)
2647 rt->rt6i_pmtu = arg->mtu;
2648 } else if (dst_mtu(&rt->dst) >= arg->mtu ||
2649 (dst_mtu(&rt->dst) < arg->mtu &&
2650 dst_mtu(&rt->dst) == idev->cnf.mtu6)) {
2651 dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu);
2652 }
Simon Arlott566cfd82007-07-26 00:09:55 -07002653 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 return 0;
2655}
2656
Eric Dumazet95c96172012-04-15 05:58:06 +00002657void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658{
Thomas Grafc71099a2006-08-04 23:20:06 -07002659 struct rt6_mtu_change_arg arg = {
2660 .dev = dev,
2661 .mtu = mtu,
2662 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663
Li RongQing0c3584d2013-12-27 16:32:38 +08002664 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665}
2666
Patrick McHardyef7c79e2007-06-05 12:38:30 -07002667static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07002668 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07002669 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07002670 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002671 [RTA_PRIORITY] = { .type = NLA_U32 },
2672 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002673 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002674 [RTA_PREF] = { .type = NLA_U8 },
Roopa Prabhu19e42e42015-07-21 10:43:48 +02002675 [RTA_ENCAP_TYPE] = { .type = NLA_U16 },
2676 [RTA_ENCAP] = { .type = NLA_NESTED },
Thomas Graf86872cb2006-08-22 00:01:08 -07002677};
2678
2679static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
2680 struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681{
Thomas Graf86872cb2006-08-22 00:01:08 -07002682 struct rtmsg *rtm;
2683 struct nlattr *tb[RTA_MAX+1];
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002684 unsigned int pref;
Thomas Graf86872cb2006-08-22 00:01:08 -07002685 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686
Thomas Graf86872cb2006-08-22 00:01:08 -07002687 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2688 if (err < 0)
2689 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690
Thomas Graf86872cb2006-08-22 00:01:08 -07002691 err = -EINVAL;
2692 rtm = nlmsg_data(nlh);
2693 memset(cfg, 0, sizeof(*cfg));
2694
2695 cfg->fc_table = rtm->rtm_table;
2696 cfg->fc_dst_len = rtm->rtm_dst_len;
2697 cfg->fc_src_len = rtm->rtm_src_len;
2698 cfg->fc_flags = RTF_UP;
2699 cfg->fc_protocol = rtm->rtm_protocol;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002700 cfg->fc_type = rtm->rtm_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07002701
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002702 if (rtm->rtm_type == RTN_UNREACHABLE ||
2703 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002704 rtm->rtm_type == RTN_PROHIBIT ||
2705 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07002706 cfg->fc_flags |= RTF_REJECT;
2707
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002708 if (rtm->rtm_type == RTN_LOCAL)
2709 cfg->fc_flags |= RTF_LOCAL;
2710
Martin KaFai Lau1f56a012015-04-28 13:03:03 -07002711 if (rtm->rtm_flags & RTM_F_CLONED)
2712 cfg->fc_flags |= RTF_CACHE;
2713
Eric W. Biederman15e47302012-09-07 20:12:54 +00002714 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
Thomas Graf86872cb2006-08-22 00:01:08 -07002715 cfg->fc_nlinfo.nlh = nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002716 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
Thomas Graf86872cb2006-08-22 00:01:08 -07002717
2718 if (tb[RTA_GATEWAY]) {
Jiri Benc67b61f62015-03-29 16:59:26 +02002719 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
Thomas Graf86872cb2006-08-22 00:01:08 -07002720 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002722
2723 if (tb[RTA_DST]) {
2724 int plen = (rtm->rtm_dst_len + 7) >> 3;
2725
2726 if (nla_len(tb[RTA_DST]) < plen)
2727 goto errout;
2728
2729 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002731
2732 if (tb[RTA_SRC]) {
2733 int plen = (rtm->rtm_src_len + 7) >> 3;
2734
2735 if (nla_len(tb[RTA_SRC]) < plen)
2736 goto errout;
2737
2738 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002740
Daniel Walterc3968a82011-04-13 21:10:57 +00002741 if (tb[RTA_PREFSRC])
Jiri Benc67b61f62015-03-29 16:59:26 +02002742 cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]);
Daniel Walterc3968a82011-04-13 21:10:57 +00002743
Thomas Graf86872cb2006-08-22 00:01:08 -07002744 if (tb[RTA_OIF])
2745 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
2746
2747 if (tb[RTA_PRIORITY])
2748 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
2749
2750 if (tb[RTA_METRICS]) {
2751 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
2752 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002754
2755 if (tb[RTA_TABLE])
2756 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
2757
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002758 if (tb[RTA_MULTIPATH]) {
2759 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
2760 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
2761 }
2762
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002763 if (tb[RTA_PREF]) {
2764 pref = nla_get_u8(tb[RTA_PREF]);
2765 if (pref != ICMPV6_ROUTER_PREF_LOW &&
2766 pref != ICMPV6_ROUTER_PREF_HIGH)
2767 pref = ICMPV6_ROUTER_PREF_MEDIUM;
2768 cfg->fc_flags |= RTF_PREF(pref);
2769 }
2770
Roopa Prabhu19e42e42015-07-21 10:43:48 +02002771 if (tb[RTA_ENCAP])
2772 cfg->fc_encap = tb[RTA_ENCAP];
2773
2774 if (tb[RTA_ENCAP_TYPE])
2775 cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]);
2776
Thomas Graf86872cb2006-08-22 00:01:08 -07002777 err = 0;
2778errout:
2779 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780}
2781
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002782struct rt6_nh {
2783 struct rt6_info *rt6_info;
2784 struct fib6_config r_cfg;
2785 struct mx6_config mxc;
2786 struct list_head next;
2787};
2788
2789static void ip6_print_replace_route_err(struct list_head *rt6_nh_list)
2790{
2791 struct rt6_nh *nh;
2792
2793 list_for_each_entry(nh, rt6_nh_list, next) {
2794 pr_warn("IPV6: multipath route replace failed (check consistency of installed routes): %pI6 nexthop %pI6 ifi %d\n",
2795 &nh->r_cfg.fc_dst, &nh->r_cfg.fc_gateway,
2796 nh->r_cfg.fc_ifindex);
2797 }
2798}
2799
2800static int ip6_route_info_append(struct list_head *rt6_nh_list,
2801 struct rt6_info *rt, struct fib6_config *r_cfg)
2802{
2803 struct rt6_nh *nh;
2804 struct rt6_info *rtnh;
2805 int err = -EEXIST;
2806
2807 list_for_each_entry(nh, rt6_nh_list, next) {
2808 /* check if rt6_info already exists */
2809 rtnh = nh->rt6_info;
2810
2811 if (rtnh->dst.dev == rt->dst.dev &&
2812 rtnh->rt6i_idev == rt->rt6i_idev &&
2813 ipv6_addr_equal(&rtnh->rt6i_gateway,
2814 &rt->rt6i_gateway))
2815 return err;
2816 }
2817
2818 nh = kzalloc(sizeof(*nh), GFP_KERNEL);
2819 if (!nh)
2820 return -ENOMEM;
2821 nh->rt6_info = rt;
2822 err = ip6_convert_metrics(&nh->mxc, r_cfg);
2823 if (err) {
2824 kfree(nh);
2825 return err;
2826 }
2827 memcpy(&nh->r_cfg, r_cfg, sizeof(*r_cfg));
2828 list_add_tail(&nh->next, rt6_nh_list);
2829
2830 return 0;
2831}
2832
2833static int ip6_route_multipath_add(struct fib6_config *cfg)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002834{
2835 struct fib6_config r_cfg;
2836 struct rtnexthop *rtnh;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002837 struct rt6_info *rt;
2838 struct rt6_nh *err_nh;
2839 struct rt6_nh *nh, *nh_safe;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002840 int remaining;
2841 int attrlen;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002842 int err = 1;
2843 int nhn = 0;
2844 int replace = (cfg->fc_nlinfo.nlh &&
2845 (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE));
2846 LIST_HEAD(rt6_nh_list);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002847
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02002848 remaining = cfg->fc_mp_len;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002849 rtnh = (struct rtnexthop *)cfg->fc_mp;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002850
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002851 /* Parse a Multipath Entry and build a list (rt6_nh_list) of
2852 * rt6_info structs per nexthop
2853 */
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002854 while (rtnh_ok(rtnh, remaining)) {
2855 memcpy(&r_cfg, cfg, sizeof(*cfg));
2856 if (rtnh->rtnh_ifindex)
2857 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
2858
2859 attrlen = rtnh_attrlen(rtnh);
2860 if (attrlen > 0) {
2861 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
2862
2863 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
2864 if (nla) {
Jiri Benc67b61f62015-03-29 16:59:26 +02002865 r_cfg.fc_gateway = nla_get_in6_addr(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002866 r_cfg.fc_flags |= RTF_GATEWAY;
2867 }
Roopa Prabhu19e42e42015-07-21 10:43:48 +02002868 r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
2869 nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
2870 if (nla)
2871 r_cfg.fc_encap_type = nla_get_u16(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002872 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002873
2874 err = ip6_route_info_create(&r_cfg, &rt);
2875 if (err)
2876 goto cleanup;
2877
2878 err = ip6_route_info_append(&rt6_nh_list, rt, &r_cfg);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002879 if (err) {
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002880 dst_free(&rt->dst);
2881 goto cleanup;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002882 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002883
2884 rtnh = rtnh_next(rtnh, &remaining);
2885 }
2886
2887 err_nh = NULL;
2888 list_for_each_entry(nh, &rt6_nh_list, next) {
2889 err = __ip6_ins_rt(nh->rt6_info, &cfg->fc_nlinfo, &nh->mxc);
2890 /* nh->rt6_info is used or freed at this point, reset to NULL*/
2891 nh->rt6_info = NULL;
2892 if (err) {
2893 if (replace && nhn)
2894 ip6_print_replace_route_err(&rt6_nh_list);
2895 err_nh = nh;
2896 goto add_errout;
2897 }
2898
Nicolas Dichtel1a724182012-11-01 22:58:22 +00002899 /* Because each route is added like a single route we remove
Michal Kubeček27596472015-05-18 20:54:00 +02002900 * these flags after the first nexthop: if there is a collision,
2901 * we have already failed to add the first nexthop:
2902 * fib6_add_rt2node() has rejected it; when replacing, old
2903 * nexthops have been replaced by first new, the rest should
2904 * be added to it.
Nicolas Dichtel1a724182012-11-01 22:58:22 +00002905 */
Michal Kubeček27596472015-05-18 20:54:00 +02002906 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
2907 NLM_F_REPLACE);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002908 nhn++;
2909 }
2910
2911 goto cleanup;
2912
2913add_errout:
2914 /* Delete routes that were already added */
2915 list_for_each_entry(nh, &rt6_nh_list, next) {
2916 if (err_nh == nh)
2917 break;
2918 ip6_route_del(&nh->r_cfg);
2919 }
2920
2921cleanup:
2922 list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) {
2923 if (nh->rt6_info)
2924 dst_free(&nh->rt6_info->dst);
Wu Fengguang52fe51f2015-09-10 06:57:12 +08002925 kfree(nh->mxc.mx);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002926 list_del(&nh->next);
2927 kfree(nh);
2928 }
2929
2930 return err;
2931}
2932
2933static int ip6_route_multipath_del(struct fib6_config *cfg)
2934{
2935 struct fib6_config r_cfg;
2936 struct rtnexthop *rtnh;
2937 int remaining;
2938 int attrlen;
2939 int err = 1, last_err = 0;
2940
2941 remaining = cfg->fc_mp_len;
2942 rtnh = (struct rtnexthop *)cfg->fc_mp;
2943
2944 /* Parse a Multipath Entry */
2945 while (rtnh_ok(rtnh, remaining)) {
2946 memcpy(&r_cfg, cfg, sizeof(*cfg));
2947 if (rtnh->rtnh_ifindex)
2948 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
2949
2950 attrlen = rtnh_attrlen(rtnh);
2951 if (attrlen > 0) {
2952 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
2953
2954 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
2955 if (nla) {
2956 nla_memcpy(&r_cfg.fc_gateway, nla, 16);
2957 r_cfg.fc_flags |= RTF_GATEWAY;
2958 }
2959 }
2960 err = ip6_route_del(&r_cfg);
2961 if (err)
2962 last_err = err;
2963
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002964 rtnh = rtnh_next(rtnh, &remaining);
2965 }
2966
2967 return last_err;
2968}
2969
Ian Morris67ba4152014-08-24 21:53:10 +01002970static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971{
Thomas Graf86872cb2006-08-22 00:01:08 -07002972 struct fib6_config cfg;
2973 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974
Thomas Graf86872cb2006-08-22 00:01:08 -07002975 err = rtm_to_fib6_config(skb, nlh, &cfg);
2976 if (err < 0)
2977 return err;
2978
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002979 if (cfg.fc_mp)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002980 return ip6_route_multipath_del(&cfg);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002981 else
2982 return ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983}
2984
Ian Morris67ba4152014-08-24 21:53:10 +01002985static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986{
Thomas Graf86872cb2006-08-22 00:01:08 -07002987 struct fib6_config cfg;
2988 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989
Thomas Graf86872cb2006-08-22 00:01:08 -07002990 err = rtm_to_fib6_config(skb, nlh, &cfg);
2991 if (err < 0)
2992 return err;
2993
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002994 if (cfg.fc_mp)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002995 return ip6_route_multipath_add(&cfg);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002996 else
2997 return ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998}
2999
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003000static inline size_t rt6_nlmsg_size(struct rt6_info *rt)
Thomas Graf339bf982006-11-10 14:10:15 -08003001{
3002 return NLMSG_ALIGN(sizeof(struct rtmsg))
3003 + nla_total_size(16) /* RTA_SRC */
3004 + nla_total_size(16) /* RTA_DST */
3005 + nla_total_size(16) /* RTA_GATEWAY */
3006 + nla_total_size(16) /* RTA_PREFSRC */
3007 + nla_total_size(4) /* RTA_TABLE */
3008 + nla_total_size(4) /* RTA_IIF */
3009 + nla_total_size(4) /* RTA_OIF */
3010 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08003011 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Daniel Borkmannea697632015-01-05 23:57:47 +01003012 + nla_total_size(sizeof(struct rta_cacheinfo))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01003013 + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003014 + nla_total_size(1) /* RTA_PREF */
Jiri Benc61adedf2015-08-20 13:56:25 +02003015 + lwtunnel_get_encap_size(rt->dst.lwtstate);
Thomas Graf339bf982006-11-10 14:10:15 -08003016}
3017
Brian Haley191cd582008-08-14 15:33:21 -07003018static int rt6_fill_node(struct net *net,
3019 struct sk_buff *skb, struct rt6_info *rt,
Jamal Hadi Salim0d51aa82005-06-21 13:51:04 -07003020 struct in6_addr *dst, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003021 int iif, int type, u32 portid, u32 seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003022 int prefix, int nowait, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07003024 u32 metrics[RTAX_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 struct rtmsg *rtm;
Thomas Graf2d7202b2006-08-22 00:01:27 -07003026 struct nlmsghdr *nlh;
Thomas Grafe3703b32006-11-27 09:27:07 -08003027 long expires;
Patrick McHardy9e762a42006-08-10 23:09:48 -07003028 u32 table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029
3030 if (prefix) { /* user wants prefix routes only */
3031 if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
3032 /* success since this is not a prefix route */
3033 return 1;
3034 }
3035 }
3036
Eric W. Biederman15e47302012-09-07 20:12:54 +00003037 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05003038 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08003039 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07003040
3041 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 rtm->rtm_family = AF_INET6;
3043 rtm->rtm_dst_len = rt->rt6i_dst.plen;
3044 rtm->rtm_src_len = rt->rt6i_src.plen;
3045 rtm->rtm_tos = 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07003046 if (rt->rt6i_table)
Patrick McHardy9e762a42006-08-10 23:09:48 -07003047 table = rt->rt6i_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07003048 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07003049 table = RT6_TABLE_UNSPEC;
3050 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04003051 if (nla_put_u32(skb, RTA_TABLE, table))
3052 goto nla_put_failure;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00003053 if (rt->rt6i_flags & RTF_REJECT) {
3054 switch (rt->dst.error) {
3055 case -EINVAL:
3056 rtm->rtm_type = RTN_BLACKHOLE;
3057 break;
3058 case -EACCES:
3059 rtm->rtm_type = RTN_PROHIBIT;
3060 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00003061 case -EAGAIN:
3062 rtm->rtm_type = RTN_THROW;
3063 break;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00003064 default:
3065 rtm->rtm_type = RTN_UNREACHABLE;
3066 break;
3067 }
3068 }
David S. Miller38308472011-12-03 18:02:47 -05003069 else if (rt->rt6i_flags & RTF_LOCAL)
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00003070 rtm->rtm_type = RTN_LOCAL;
David S. Millerd1918542011-12-28 20:19:20 -05003071 else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 rtm->rtm_type = RTN_LOCAL;
3073 else
3074 rtm->rtm_type = RTN_UNICAST;
3075 rtm->rtm_flags = 0;
Andy Gospodarek35103d12015-08-13 10:39:01 -04003076 if (!netif_carrier_ok(rt->dst.dev)) {
Andy Gospodarekcea45e22015-08-13 10:39:00 -04003077 rtm->rtm_flags |= RTNH_F_LINKDOWN;
Andy Gospodarek35103d12015-08-13 10:39:01 -04003078 if (rt->rt6i_idev->cnf.ignore_routes_with_linkdown)
3079 rtm->rtm_flags |= RTNH_F_DEAD;
3080 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
3082 rtm->rtm_protocol = rt->rt6i_protocol;
David S. Miller38308472011-12-03 18:02:47 -05003083 if (rt->rt6i_flags & RTF_DYNAMIC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 rtm->rtm_protocol = RTPROT_REDIRECT;
Denis Ovsienkof0396f602012-07-10 04:45:50 +00003085 else if (rt->rt6i_flags & RTF_ADDRCONF) {
3086 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ROUTEINFO))
3087 rtm->rtm_protocol = RTPROT_RA;
3088 else
3089 rtm->rtm_protocol = RTPROT_KERNEL;
3090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091
David S. Miller38308472011-12-03 18:02:47 -05003092 if (rt->rt6i_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 rtm->rtm_flags |= RTM_F_CLONED;
3094
3095 if (dst) {
Jiri Benc930345e2015-03-29 16:59:25 +02003096 if (nla_put_in6_addr(skb, RTA_DST, dst))
David S. Millerc78679e2012-04-01 20:27:33 -04003097 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003098 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 } else if (rtm->rtm_dst_len)
Jiri Benc930345e2015-03-29 16:59:25 +02003100 if (nla_put_in6_addr(skb, RTA_DST, &rt->rt6i_dst.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04003101 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102#ifdef CONFIG_IPV6_SUBTREES
3103 if (src) {
Jiri Benc930345e2015-03-29 16:59:25 +02003104 if (nla_put_in6_addr(skb, RTA_SRC, src))
David S. Millerc78679e2012-04-01 20:27:33 -04003105 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003106 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04003107 } else if (rtm->rtm_src_len &&
Jiri Benc930345e2015-03-29 16:59:25 +02003108 nla_put_in6_addr(skb, RTA_SRC, &rt->rt6i_src.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04003109 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003111 if (iif) {
3112#ifdef CONFIG_IPV6_MROUTE
3113 if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
Benjamin Thery8229efd2008-12-10 16:30:15 -08003114 int err = ip6mr_get_route(net, skb, rtm, nowait);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003115 if (err <= 0) {
3116 if (!nowait) {
3117 if (err == 0)
3118 return 0;
3119 goto nla_put_failure;
3120 } else {
3121 if (err == -EMSGSIZE)
3122 goto nla_put_failure;
3123 }
3124 }
3125 } else
3126#endif
David S. Millerc78679e2012-04-01 20:27:33 -04003127 if (nla_put_u32(skb, RTA_IIF, iif))
3128 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003129 } else if (dst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 struct in6_addr saddr_buf;
David S. Millerc78679e2012-04-01 20:27:33 -04003131 if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0 &&
Jiri Benc930345e2015-03-29 16:59:25 +02003132 nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04003133 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07003135
Daniel Walterc3968a82011-04-13 21:10:57 +00003136 if (rt->rt6i_prefsrc.plen) {
3137 struct in6_addr saddr_buf;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003138 saddr_buf = rt->rt6i_prefsrc.addr;
Jiri Benc930345e2015-03-29 16:59:25 +02003139 if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04003140 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00003141 }
3142
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07003143 memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics));
3144 if (rt->rt6i_pmtu)
3145 metrics[RTAX_MTU - 1] = rt->rt6i_pmtu;
3146 if (rtnetlink_put_metrics(skb, metrics) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07003147 goto nla_put_failure;
3148
YOSHIFUJI Hideaki / 吉藤英明dd0cbf22013-01-17 12:53:15 +00003149 if (rt->rt6i_flags & RTF_GATEWAY) {
Jiri Benc930345e2015-03-29 16:59:25 +02003150 if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->rt6i_gateway) < 0)
Eric Dumazet94f826b2012-03-27 09:53:52 +00003151 goto nla_put_failure;
Eric Dumazet94f826b2012-03-27 09:53:52 +00003152 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07003153
David S. Millerc78679e2012-04-01 20:27:33 -04003154 if (rt->dst.dev &&
3155 nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex))
3156 goto nla_put_failure;
3157 if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric))
3158 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00003159
3160 expires = (rt->rt6i_flags & RTF_EXPIRES) ? rt->dst.expires - jiffies : 0;
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07003161
David S. Miller87a50692012-07-10 05:06:14 -07003162 if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, rt->dst.error) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08003163 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01003165 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags)))
3166 goto nla_put_failure;
3167
Jiri Benc61adedf2015-08-20 13:56:25 +02003168 lwtunnel_fill_encap(skb, rt->dst.lwtstate);
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003169
Johannes Berg053c0952015-01-16 22:09:00 +01003170 nlmsg_end(skb, nlh);
3171 return 0;
Thomas Graf2d7202b2006-08-22 00:01:27 -07003172
3173nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08003174 nlmsg_cancel(skb, nlh);
3175 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176}
3177
Patrick McHardy1b43af52006-08-10 23:11:17 -07003178int rt6_dump_route(struct rt6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179{
3180 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
3181 int prefix;
3182
Thomas Graf2d7202b2006-08-22 00:01:27 -07003183 if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
3184 struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0;
3186 } else
3187 prefix = 0;
3188
Brian Haley191cd582008-08-14 15:33:21 -07003189 return rt6_fill_node(arg->net,
3190 arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003191 NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003192 prefix, 0, NLM_F_MULTI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193}
3194
Ian Morris67ba4152014-08-24 21:53:10 +01003195static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09003197 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07003198 struct nlattr *tb[RTA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07003200 struct sk_buff *skb;
3201 struct rtmsg *rtm;
David S. Miller4c9483b2011-03-12 16:22:43 -05003202 struct flowi6 fl6;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003203 int err, iif = 0, oif = 0;
Thomas Grafab364a62006-08-22 00:01:47 -07003204
3205 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
3206 if (err < 0)
3207 goto errout;
3208
3209 err = -EINVAL;
David S. Miller4c9483b2011-03-12 16:22:43 -05003210 memset(&fl6, 0, sizeof(fl6));
Thomas Grafab364a62006-08-22 00:01:47 -07003211
3212 if (tb[RTA_SRC]) {
3213 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
3214 goto errout;
3215
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003216 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07003217 }
3218
3219 if (tb[RTA_DST]) {
3220 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
3221 goto errout;
3222
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003223 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07003224 }
3225
3226 if (tb[RTA_IIF])
3227 iif = nla_get_u32(tb[RTA_IIF]);
3228
3229 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003230 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07003231
Lorenzo Colitti2e47b292014-05-15 16:38:41 -07003232 if (tb[RTA_MARK])
3233 fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
3234
Thomas Grafab364a62006-08-22 00:01:47 -07003235 if (iif) {
3236 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003237 int flags = 0;
3238
Daniel Lezcano55786892008-03-04 13:47:47 -08003239 dev = __dev_get_by_index(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07003240 if (!dev) {
3241 err = -ENODEV;
3242 goto errout;
3243 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003244
3245 fl6.flowi6_iif = iif;
3246
3247 if (!ipv6_addr_any(&fl6.saddr))
3248 flags |= RT6_LOOKUP_F_HAS_SADDR;
3249
3250 rt = (struct rt6_info *)ip6_route_input_lookup(net, dev, &fl6,
3251 flags);
3252 } else {
3253 fl6.flowi6_oif = oif;
3254
3255 rt = (struct rt6_info *)ip6_route_output(net, NULL, &fl6);
Thomas Grafab364a62006-08-22 00:01:47 -07003256 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257
3258 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05003259 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00003260 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07003261 err = -ENOBUFS;
3262 goto errout;
3263 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264
3265 /* Reserve room for dummy headers, this skb can pass
3266 through good chunk of routing engine.
3267 */
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07003268 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
3270
Changli Gaod8d1f302010-06-10 23:31:35 -07003271 skb_dst_set(skb, &rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272
David S. Miller4c9483b2011-03-12 16:22:43 -05003273 err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003274 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003275 nlh->nlmsg_seq, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07003277 kfree_skb(skb);
3278 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 }
3280
Eric W. Biederman15e47302012-09-07 20:12:54 +00003281 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07003282errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284}
3285
Roopa Prabhu37a1d362015-09-13 10:18:33 -07003286void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info,
3287 unsigned int nlm_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288{
3289 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08003290 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003291 u32 seq;
3292 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003294 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05003295 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07003296
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003297 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05003298 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07003299 goto errout;
3300
Brian Haley191cd582008-08-14 15:33:21 -07003301 err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
Roopa Prabhu37a1d362015-09-13 10:18:33 -07003302 event, info->portid, seq, 0, 0, nlm_flags);
Patrick McHardy26932562007-01-31 23:16:40 -08003303 if (err < 0) {
3304 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
3305 WARN_ON(err == -EMSGSIZE);
3306 kfree_skb(skb);
3307 goto errout;
3308 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00003309 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08003310 info->nlh, gfp_any());
3311 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07003312errout:
3313 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08003314 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315}
3316
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003317static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00003318 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003319{
Jiri Pirko351638e2013-05-28 01:30:21 +00003320 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09003321 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003322
3323 if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07003324 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003325 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
3326#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07003327 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003328 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07003329 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003330 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
3331#endif
3332 }
3333
3334 return NOTIFY_OK;
3335}
3336
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337/*
3338 * /proc
3339 */
3340
3341#ifdef CONFIG_PROC_FS
3342
Alexey Dobriyan33120b32007-11-06 05:27:11 -08003343static const struct file_operations ipv6_route_proc_fops = {
3344 .owner = THIS_MODULE,
3345 .open = ipv6_route_open,
3346 .read = seq_read,
3347 .llseek = seq_lseek,
Hannes Frederic Sowa8d2ca1d2013-09-21 16:55:59 +02003348 .release = seq_release_net,
Alexey Dobriyan33120b32007-11-06 05:27:11 -08003349};
3350
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351static int rt6_stats_seq_show(struct seq_file *seq, void *v)
3352{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003353 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003355 net->ipv6.rt6_stats->fib_nodes,
3356 net->ipv6.rt6_stats->fib_route_nodes,
3357 net->ipv6.rt6_stats->fib_rt_alloc,
3358 net->ipv6.rt6_stats->fib_rt_entries,
3359 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00003360 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003361 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362
3363 return 0;
3364}
3365
3366static int rt6_stats_seq_open(struct inode *inode, struct file *file)
3367{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07003368 return single_open_net(inode, file, rt6_stats_seq_show);
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003369}
3370
Arjan van de Ven9a321442007-02-12 00:55:35 -08003371static const struct file_operations rt6_stats_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 .owner = THIS_MODULE,
3373 .open = rt6_stats_seq_open,
3374 .read = seq_read,
3375 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07003376 .release = single_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377};
3378#endif /* CONFIG_PROC_FS */
3379
3380#ifdef CONFIG_SYSCTL
3381
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382static
Joe Perchesfe2c6332013-06-11 23:04:25 -07003383int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 void __user *buffer, size_t *lenp, loff_t *ppos)
3385{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003386 struct net *net;
3387 int delay;
3388 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003390
3391 net = (struct net *)ctl->extra1;
3392 delay = net->ipv6.sysctl.flush_delay;
3393 proc_dointvec(ctl, write, buffer, lenp, ppos);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02003394 fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003395 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396}
3397
Joe Perchesfe2c6332013-06-11 23:04:25 -07003398struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003399 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08003401 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07003403 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003404 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 },
3406 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003408 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409 .maxlen = sizeof(int),
3410 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003411 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 },
3413 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08003415 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 .maxlen = sizeof(int),
3417 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003418 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419 },
3420 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08003422 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 .maxlen = sizeof(int),
3424 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003425 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 },
3427 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08003429 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 .maxlen = sizeof(int),
3431 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003432 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 },
3434 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08003436 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 .maxlen = sizeof(int),
3438 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003439 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 },
3441 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08003443 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 .maxlen = sizeof(int),
3445 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003446 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447 },
3448 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08003450 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451 .maxlen = sizeof(int),
3452 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003453 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 },
3455 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08003457 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 .maxlen = sizeof(int),
3459 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003460 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461 },
3462 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08003464 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465 .maxlen = sizeof(int),
3466 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003467 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08003469 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470};
3471
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003472struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003473{
3474 struct ctl_table *table;
3475
3476 table = kmemdup(ipv6_route_table_template,
3477 sizeof(ipv6_route_table_template),
3478 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003479
3480 if (table) {
3481 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003482 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003483 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003484 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
3485 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
3486 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
3487 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
3488 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
3489 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
3490 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08003491 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
Eric W. Biederman464dc802012-11-16 03:02:59 +00003492
3493 /* Don't export sysctls to unprivileged users */
3494 if (net->user_ns != &init_user_ns)
3495 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003496 }
3497
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003498 return table;
3499}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500#endif
3501
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003502static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003503{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07003504 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003505
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003506 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
3507 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003508
Eric Dumazetfc66f952010-10-08 06:37:34 +00003509 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
3510 goto out_ip6_dst_ops;
3511
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003512 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
3513 sizeof(*net->ipv6.ip6_null_entry),
3514 GFP_KERNEL);
3515 if (!net->ipv6.ip6_null_entry)
Eric Dumazetfc66f952010-10-08 06:37:34 +00003516 goto out_ip6_dst_entries;
Changli Gaod8d1f302010-06-10 23:31:35 -07003517 net->ipv6.ip6_null_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003518 (struct dst_entry *)net->ipv6.ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003519 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003520 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
3521 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003522
3523#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3524 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
3525 sizeof(*net->ipv6.ip6_prohibit_entry),
3526 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003527 if (!net->ipv6.ip6_prohibit_entry)
3528 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003529 net->ipv6.ip6_prohibit_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003530 (struct dst_entry *)net->ipv6.ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003531 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003532 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
3533 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003534
3535 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
3536 sizeof(*net->ipv6.ip6_blk_hole_entry),
3537 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003538 if (!net->ipv6.ip6_blk_hole_entry)
3539 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003540 net->ipv6.ip6_blk_hole_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003541 (struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003542 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003543 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
3544 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003545#endif
3546
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07003547 net->ipv6.sysctl.flush_delay = 0;
3548 net->ipv6.sysctl.ip6_rt_max_size = 4096;
3549 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
3550 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
3551 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
3552 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
3553 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
3554 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
3555
Benjamin Thery6891a342008-03-04 13:49:47 -08003556 net->ipv6.ip6_rt_gc_expire = 30*HZ;
3557
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003558 ret = 0;
3559out:
3560 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003561
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003562#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3563out_ip6_prohibit_entry:
3564 kfree(net->ipv6.ip6_prohibit_entry);
3565out_ip6_null_entry:
3566 kfree(net->ipv6.ip6_null_entry);
3567#endif
Eric Dumazetfc66f952010-10-08 06:37:34 +00003568out_ip6_dst_entries:
3569 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003570out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003571 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003572}
3573
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003574static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003575{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003576 kfree(net->ipv6.ip6_null_entry);
3577#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3578 kfree(net->ipv6.ip6_prohibit_entry);
3579 kfree(net->ipv6.ip6_blk_hole_entry);
3580#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003581 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003582}
3583
Thomas Grafd1896342012-06-18 12:08:33 +00003584static int __net_init ip6_route_net_init_late(struct net *net)
3585{
3586#ifdef CONFIG_PROC_FS
Gao fengd4beaa62013-02-18 01:34:54 +00003587 proc_create("ipv6_route", 0, net->proc_net, &ipv6_route_proc_fops);
3588 proc_create("rt6_stats", S_IRUGO, net->proc_net, &rt6_stats_seq_fops);
Thomas Grafd1896342012-06-18 12:08:33 +00003589#endif
3590 return 0;
3591}
3592
3593static void __net_exit ip6_route_net_exit_late(struct net *net)
3594{
3595#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00003596 remove_proc_entry("ipv6_route", net->proc_net);
3597 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00003598#endif
3599}
3600
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003601static struct pernet_operations ip6_route_net_ops = {
3602 .init = ip6_route_net_init,
3603 .exit = ip6_route_net_exit,
3604};
3605
David S. Millerc3426b42012-06-09 16:27:05 -07003606static int __net_init ipv6_inetpeer_init(struct net *net)
3607{
3608 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
3609
3610 if (!bp)
3611 return -ENOMEM;
3612 inet_peer_base_init(bp);
3613 net->ipv6.peers = bp;
3614 return 0;
3615}
3616
3617static void __net_exit ipv6_inetpeer_exit(struct net *net)
3618{
3619 struct inet_peer_base *bp = net->ipv6.peers;
3620
3621 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07003622 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07003623 kfree(bp);
3624}
3625
David S. Miller2b823f72012-06-09 19:00:16 -07003626static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07003627 .init = ipv6_inetpeer_init,
3628 .exit = ipv6_inetpeer_exit,
3629};
3630
Thomas Grafd1896342012-06-18 12:08:33 +00003631static struct pernet_operations ip6_route_net_late_ops = {
3632 .init = ip6_route_net_init_late,
3633 .exit = ip6_route_net_exit_late,
3634};
3635
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003636static struct notifier_block ip6_route_dev_notifier = {
3637 .notifier_call = ip6_route_dev_notify,
3638 .priority = 0,
3639};
3640
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003641int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003643 int ret;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07003644 int cpu;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003645
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003646 ret = -ENOMEM;
3647 ip6_dst_ops_template.kmem_cachep =
3648 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
3649 SLAB_HWCACHE_ALIGN, NULL);
3650 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08003651 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07003652
Eric Dumazetfc66f952010-10-08 06:37:34 +00003653 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003654 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003655 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003656
David S. Millerc3426b42012-06-09 16:27:05 -07003657 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
3658 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003659 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00003660
David S. Miller7e52b332012-06-15 15:51:55 -07003661 ret = register_pernet_subsys(&ip6_route_net_ops);
3662 if (ret)
3663 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07003664
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07003665 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
3666
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003667 /* Registering of the loopback is done before this portion of code,
3668 * the loopback reference in rt6_info will not be taken, do it
3669 * manually for init_net */
Changli Gaod8d1f302010-06-10 23:31:35 -07003670 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003671 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3672 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07003673 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003674 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07003675 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003676 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3677 #endif
David S. Millere8803b62012-06-16 01:12:19 -07003678 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003679 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003680 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003681
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003682 ret = xfrm6_init();
3683 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003684 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08003685
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003686 ret = fib6_rules_init();
3687 if (ret)
3688 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08003689
Thomas Grafd1896342012-06-18 12:08:33 +00003690 ret = register_pernet_subsys(&ip6_route_net_late_ops);
3691 if (ret)
3692 goto fib6_rules_init;
3693
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003694 ret = -ENOBUFS;
Greg Rosec7ac8672011-06-10 01:27:09 +00003695 if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) ||
3696 __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) ||
3697 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL))
Thomas Grafd1896342012-06-18 12:08:33 +00003698 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003699
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003700 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003701 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00003702 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003703
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07003704 for_each_possible_cpu(cpu) {
3705 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
3706
3707 INIT_LIST_HEAD(&ul->head);
3708 spin_lock_init(&ul->lock);
3709 }
3710
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003711out:
3712 return ret;
3713
Thomas Grafd1896342012-06-18 12:08:33 +00003714out_register_late_subsys:
3715 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003716fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003717 fib6_rules_cleanup();
3718xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003719 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00003720out_fib6_init:
3721 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003722out_register_subsys:
3723 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07003724out_register_inetpeer:
3725 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00003726out_dst_entries:
3727 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003728out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003729 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003730 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731}
3732
3733void ip6_route_cleanup(void)
3734{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003735 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00003736 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07003737 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07003740 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003741 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003742 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003743 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744}