blob: 9e4c3c5d159163443b8b06c902dab9ac97e7a721 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Linux INET6 implementation
3 * FIB front-end.
4 *
5 * Authors:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09006 * Pedro Roque <roque@di.fc.ul.pt>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
13
14/* Changes:
15 *
16 * YOSHIFUJI Hideaki @USAGI
17 * reworked default router selection.
18 * - respect outgoing interface
19 * - select from (probably) reachable routers (i.e.
20 * routers in REACHABLE, STALE, DELAY or PROBE states).
21 * - always select the same router if it is (probably)
22 * reachable. otherwise, round-robin the list.
YOSHIFUJI Hideakic0bece92006-08-23 17:23:25 -070023 * Ville Nuorvala
24 * Fixed routing subtrees.
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 */
26
Joe Perchesf3213832012-05-15 14:11:53 +000027#define pr_fmt(fmt) "IPv6: " fmt
28
Randy Dunlap4fc268d2006-01-11 12:17:47 -080029#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/errno.h>
Paul Gortmakerbc3b2d72011-07-15 11:47:34 -040031#include <linux/export.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/types.h>
33#include <linux/times.h>
34#include <linux/socket.h>
35#include <linux/sockios.h>
36#include <linux/net.h>
37#include <linux/route.h>
38#include <linux/netdevice.h>
39#include <linux/in6.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090040#include <linux/mroute6.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <linux/if_arp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/proc_fs.h>
44#include <linux/seq_file.h>
Daniel Lezcano5b7c9312008-03-03 23:28:58 -080045#include <linux/nsproxy.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090046#include <linux/slab.h>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020047#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <net/snmp.h>
49#include <net/ipv6.h>
50#include <net/ip6_fib.h>
51#include <net/ip6_route.h>
52#include <net/ndisc.h>
53#include <net/addrconf.h>
54#include <net/tcp.h>
55#include <linux/rtnetlink.h>
56#include <net/dst.h>
57#include <net/xfrm.h>
Tom Tucker8d717402006-07-30 20:43:36 -070058#include <net/netevent.h>
Thomas Graf21713eb2006-08-15 00:35:24 -070059#include <net/netlink.h>
Nicolas Dichtel51ebd312012-10-22 03:42:09 +000060#include <net/nexthop.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
62#include <asm/uaccess.h>
63
64#ifdef CONFIG_SYSCTL
65#include <linux/sysctl.h>
66#endif
67
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +020068enum rt6_nud_state {
Jiri Benc7e980562013-12-11 13:48:20 +010069 RT6_NUD_FAIL_HARD = -3,
70 RT6_NUD_FAIL_PROBE = -2,
71 RT6_NUD_FAIL_DO_RR = -1,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +020072 RT6_NUD_SUCCEED = 1
73};
74
Gao feng1716a962012-04-06 00:13:10 +000075static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
Eric Dumazet21efcfa2011-07-19 20:18:36 +000076 const struct in6_addr *dest);
Linus Torvalds1da177e2005-04-16 15:20:36 -070077static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
David S. Miller0dbaee32010-12-13 12:52:14 -080078static unsigned int ip6_default_advmss(const struct dst_entry *dst);
Steffen Klassertebb762f2011-11-23 02:12:51 +000079static unsigned int ip6_mtu(const struct dst_entry *dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080static struct dst_entry *ip6_negative_advice(struct dst_entry *);
81static void ip6_dst_destroy(struct dst_entry *);
82static void ip6_dst_ifdown(struct dst_entry *,
83 struct net_device *dev, int how);
Daniel Lezcano569d3642008-01-18 03:56:57 -080084static int ip6_dst_gc(struct dst_ops *ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
86static int ip6_pkt_discard(struct sk_buff *skb);
Eric Dumazetaad88722014-04-15 13:47:15 -040087static int ip6_pkt_discard_out(struct sock *sk, struct sk_buff *skb);
Kamala R7150aed2013-12-02 19:55:21 +053088static int ip6_pkt_prohibit(struct sk_buff *skb);
Eric Dumazetaad88722014-04-15 13:47:15 -040089static int ip6_pkt_prohibit_out(struct sock *sk, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070090static void ip6_link_failure(struct sk_buff *skb);
David S. Miller6700c272012-07-17 03:29:28 -070091static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
92 struct sk_buff *skb, u32 mtu);
93static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
94 struct sk_buff *skb);
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -070095static void rt6_dst_from_metrics_check(struct rt6_info *rt);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +020096static int rt6_score_route(struct rt6_info *rt, int oif, int strict);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -080098#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -080099static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000100 const struct in6_addr *prefix, int prefixlen,
101 const struct in6_addr *gwaddr, int ifindex,
Eric Dumazet95c96172012-04-15 05:58:06 +0000102 unsigned int pref);
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800103static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000104 const struct in6_addr *prefix, int prefixlen,
105 const struct in6_addr *gwaddr, int ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800106#endif
107
David S. Miller06582542011-01-27 14:58:42 -0800108static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
109{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700110 struct rt6_info *rt = (struct rt6_info *)dst;
David S. Miller06582542011-01-27 14:58:42 -0800111
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700112 if (rt->rt6i_flags & RTF_CACHE)
113 return NULL;
114 else
Martin KaFai Lau3b471172015-02-12 16:14:08 -0800115 return dst_cow_metrics_generic(dst, old);
David S. Miller06582542011-01-27 14:58:42 -0800116}
117
David S. Millerf894cbf2012-07-02 21:52:24 -0700118static inline const void *choose_neigh_daddr(struct rt6_info *rt,
119 struct sk_buff *skb,
120 const void *daddr)
David S. Miller39232972012-01-26 15:22:32 -0500121{
122 struct in6_addr *p = &rt->rt6i_gateway;
123
David S. Millera7563f32012-01-26 16:29:16 -0500124 if (!ipv6_addr_any(p))
David S. Miller39232972012-01-26 15:22:32 -0500125 return (const void *) p;
David S. Millerf894cbf2012-07-02 21:52:24 -0700126 else if (skb)
127 return &ipv6_hdr(skb)->daddr;
David S. Miller39232972012-01-26 15:22:32 -0500128 return daddr;
129}
130
David S. Millerf894cbf2012-07-02 21:52:24 -0700131static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst,
132 struct sk_buff *skb,
133 const void *daddr)
David S. Millerd3aaeb32011-07-18 00:40:17 -0700134{
David S. Miller39232972012-01-26 15:22:32 -0500135 struct rt6_info *rt = (struct rt6_info *) dst;
136 struct neighbour *n;
137
David S. Millerf894cbf2012-07-02 21:52:24 -0700138 daddr = choose_neigh_daddr(rt, skb, daddr);
YOSHIFUJI Hideaki / 吉藤英明8e022ee2013-01-17 12:53:09 +0000139 n = __ipv6_neigh_lookup(dst->dev, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500140 if (n)
141 return n;
142 return neigh_create(&nd_tbl, daddr, dst->dev);
143}
144
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -0800145static struct dst_ops ip6_dst_ops_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 .family = AF_INET6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 .gc = ip6_dst_gc,
148 .gc_thresh = 1024,
149 .check = ip6_dst_check,
David S. Miller0dbaee32010-12-13 12:52:14 -0800150 .default_advmss = ip6_default_advmss,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000151 .mtu = ip6_mtu,
David S. Miller06582542011-01-27 14:58:42 -0800152 .cow_metrics = ipv6_cow_metrics,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 .destroy = ip6_dst_destroy,
154 .ifdown = ip6_dst_ifdown,
155 .negative_advice = ip6_negative_advice,
156 .link_failure = ip6_link_failure,
157 .update_pmtu = ip6_rt_update_pmtu,
David S. Miller6e157b62012-07-12 00:05:02 -0700158 .redirect = rt6_do_redirect,
Herbert Xu1ac06e02008-05-20 14:32:14 -0700159 .local_out = __ip6_local_out,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700160 .neigh_lookup = ip6_neigh_lookup,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161};
162
Steffen Klassertebb762f2011-11-23 02:12:51 +0000163static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
Roland Dreierec831ea2011-01-31 13:16:00 -0800164{
Steffen Klassert618f9bc2011-11-23 02:13:31 +0000165 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
166
167 return mtu ? : dst->dev->mtu;
Roland Dreierec831ea2011-01-31 13:16:00 -0800168}
169
David S. Miller6700c272012-07-17 03:29:28 -0700170static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
171 struct sk_buff *skb, u32 mtu)
David S. Miller14e50e52007-05-24 18:17:54 -0700172{
173}
174
David S. Miller6700c272012-07-17 03:29:28 -0700175static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
176 struct sk_buff *skb)
David S. Millerb587ee32012-07-12 00:39:24 -0700177{
178}
179
Held Bernhard0972ddb2011-04-24 22:07:32 +0000180static u32 *ip6_rt_blackhole_cow_metrics(struct dst_entry *dst,
181 unsigned long old)
182{
183 return NULL;
184}
185
David S. Miller14e50e52007-05-24 18:17:54 -0700186static struct dst_ops ip6_dst_blackhole_ops = {
187 .family = AF_INET6,
David S. Miller14e50e52007-05-24 18:17:54 -0700188 .destroy = ip6_dst_destroy,
189 .check = ip6_dst_check,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000190 .mtu = ip6_blackhole_mtu,
Eric Dumazet214f45c2011-02-18 11:39:01 -0800191 .default_advmss = ip6_default_advmss,
David S. Miller14e50e52007-05-24 18:17:54 -0700192 .update_pmtu = ip6_rt_blackhole_update_pmtu,
David S. Millerb587ee32012-07-12 00:39:24 -0700193 .redirect = ip6_rt_blackhole_redirect,
Held Bernhard0972ddb2011-04-24 22:07:32 +0000194 .cow_metrics = ip6_rt_blackhole_cow_metrics,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700195 .neigh_lookup = ip6_neigh_lookup,
David S. Miller14e50e52007-05-24 18:17:54 -0700196};
197
David S. Miller62fa8a82011-01-26 20:51:05 -0800198static const u32 ip6_template_metrics[RTAX_MAX] = {
Li RongQing14edd872012-10-24 14:01:18 +0800199 [RTAX_HOPLIMIT - 1] = 0,
David S. Miller62fa8a82011-01-26 20:51:05 -0800200};
201
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000202static const struct rt6_info ip6_null_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700203 .dst = {
204 .__refcnt = ATOMIC_INIT(1),
205 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000206 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700207 .error = -ENETUNREACH,
Changli Gaod8d1f302010-06-10 23:31:35 -0700208 .input = ip6_pkt_discard,
209 .output = ip6_pkt_discard_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 },
211 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700212 .rt6i_protocol = RTPROT_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 .rt6i_metric = ~(u32) 0,
214 .rt6i_ref = ATOMIC_INIT(1),
215};
216
Thomas Graf101367c2006-08-04 03:39:02 -0700217#ifdef CONFIG_IPV6_MULTIPLE_TABLES
218
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000219static const struct rt6_info ip6_prohibit_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700220 .dst = {
221 .__refcnt = ATOMIC_INIT(1),
222 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000223 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700224 .error = -EACCES,
Changli Gaod8d1f302010-06-10 23:31:35 -0700225 .input = ip6_pkt_prohibit,
226 .output = ip6_pkt_prohibit_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700227 },
228 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700229 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700230 .rt6i_metric = ~(u32) 0,
231 .rt6i_ref = ATOMIC_INIT(1),
232};
233
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000234static const struct rt6_info ip6_blk_hole_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700235 .dst = {
236 .__refcnt = ATOMIC_INIT(1),
237 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000238 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700239 .error = -EINVAL,
Changli Gaod8d1f302010-06-10 23:31:35 -0700240 .input = dst_discard,
Eric Dumazetaad88722014-04-15 13:47:15 -0400241 .output = dst_discard_sk,
Thomas Graf101367c2006-08-04 03:39:02 -0700242 },
243 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700244 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700245 .rt6i_metric = ~(u32) 0,
246 .rt6i_ref = ATOMIC_INIT(1),
247};
248
249#endif
250
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251/* allocate dst with ip6_dst_ops */
David S. Miller97bab732012-06-09 22:36:36 -0700252static inline struct rt6_info *ip6_dst_alloc(struct net *net,
David S. Miller957c6652011-06-24 15:25:00 -0700253 struct net_device *dev,
David S. Miller8b96d222012-06-11 02:01:56 -0700254 int flags,
255 struct fib6_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256{
David S. Miller97bab732012-06-09 22:36:36 -0700257 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +0000258 0, DST_OBSOLETE_FORCE_CHK, flags);
David S. Millercf911662011-04-28 14:31:47 -0700259
David S. Miller97bab732012-06-09 22:36:36 -0700260 if (rt) {
Steffen Klassert81048912012-07-05 23:37:09 +0000261 struct dst_entry *dst = &rt->dst;
262
263 memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000264 INIT_LIST_HEAD(&rt->rt6i_siblings);
David S. Miller97bab732012-06-09 22:36:36 -0700265 }
David S. Millercf911662011-04-28 14:31:47 -0700266 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267}
268
269static void ip6_dst_destroy(struct dst_entry *dst)
270{
271 struct rt6_info *rt = (struct rt6_info *)dst;
272 struct inet6_dev *idev = rt->rt6i_idev;
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000273 struct dst_entry *from = dst->from;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700275 dst_destroy_metrics_generic(dst);
Yan, Zheng8e2ec632011-09-05 21:34:30 +0000276
David S. Miller38308472011-12-03 18:02:47 -0500277 if (idev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 rt->rt6i_idev = NULL;
279 in6_dev_put(idev);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900280 }
Gao feng1716a962012-04-06 00:13:10 +0000281
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000282 dst->from = NULL;
283 dst_release(from);
David S. Millerb3419362010-11-30 12:27:11 -0800284}
285
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
287 int how)
288{
289 struct rt6_info *rt = (struct rt6_info *)dst;
290 struct inet6_dev *idev = rt->rt6i_idev;
Denis V. Lunev5a3e55d2007-12-07 00:38:10 -0800291 struct net_device *loopback_dev =
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900292 dev_net(dev)->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
David S. Miller97cac082012-07-02 22:43:47 -0700294 if (dev != loopback_dev) {
295 if (idev && idev->dev == dev) {
296 struct inet6_dev *loopback_idev =
297 in6_dev_get(loopback_dev);
298 if (loopback_idev) {
299 rt->rt6i_idev = loopback_idev;
300 in6_dev_put(idev);
301 }
302 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 }
304}
305
Eric Dumazeta50feda2012-05-18 18:57:34 +0000306static bool rt6_check_expired(const struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307{
Gao feng1716a962012-04-06 00:13:10 +0000308 if (rt->rt6i_flags & RTF_EXPIRES) {
309 if (time_after(jiffies, rt->dst.expires))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000310 return true;
Gao feng1716a962012-04-06 00:13:10 +0000311 } else if (rt->dst.from) {
Li RongQing3fd91fb2012-09-13 19:54:57 +0000312 return rt6_check_expired((struct rt6_info *) rt->dst.from);
Gao feng1716a962012-04-06 00:13:10 +0000313 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000314 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315}
316
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000317/* Multipath route selection:
318 * Hash based function using packet header and flowlabel.
319 * Adapted from fib_info_hashfn()
320 */
321static int rt6_info_hash_nhsfn(unsigned int candidate_count,
322 const struct flowi6 *fl6)
323{
324 unsigned int val = fl6->flowi6_proto;
325
YOSHIFUJI Hideaki / 吉藤英明c08977b2013-01-13 05:02:29 +0000326 val ^= ipv6_addr_hash(&fl6->daddr);
327 val ^= ipv6_addr_hash(&fl6->saddr);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000328
329 /* Work only if this not encapsulated */
330 switch (fl6->flowi6_proto) {
331 case IPPROTO_UDP:
332 case IPPROTO_TCP:
333 case IPPROTO_SCTP:
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000334 val ^= (__force u16)fl6->fl6_sport;
335 val ^= (__force u16)fl6->fl6_dport;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000336 break;
337
338 case IPPROTO_ICMPV6:
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000339 val ^= (__force u16)fl6->fl6_icmp_type;
340 val ^= (__force u16)fl6->fl6_icmp_code;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000341 break;
342 }
343 /* RFC6438 recommands to use flowlabel */
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000344 val ^= (__force u32)fl6->flowlabel;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000345
346 /* Perhaps, we need to tune, this function? */
347 val = val ^ (val >> 7) ^ (val >> 12);
348 return val % candidate_count;
349}
350
351static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200352 struct flowi6 *fl6, int oif,
353 int strict)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000354{
355 struct rt6_info *sibling, *next_sibling;
356 int route_choosen;
357
358 route_choosen = rt6_info_hash_nhsfn(match->rt6i_nsiblings + 1, fl6);
359 /* Don't change the route, if route_choosen == 0
360 * (siblings does not include ourself)
361 */
362 if (route_choosen)
363 list_for_each_entry_safe(sibling, next_sibling,
364 &match->rt6i_siblings, rt6i_siblings) {
365 route_choosen--;
366 if (route_choosen == 0) {
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200367 if (rt6_score_route(sibling, oif, strict) < 0)
368 break;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000369 match = sibling;
370 break;
371 }
372 }
373 return match;
374}
375
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376/*
Thomas Grafc71099a2006-08-04 23:20:06 -0700377 * Route lookup. Any table->tb6_lock is implied.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 */
379
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800380static inline struct rt6_info *rt6_device_match(struct net *net,
381 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000382 const struct in6_addr *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 int oif,
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700384 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385{
386 struct rt6_info *local = NULL;
387 struct rt6_info *sprt;
388
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900389 if (!oif && ipv6_addr_any(saddr))
390 goto out;
391
Changli Gaod8d1f302010-06-10 23:31:35 -0700392 for (sprt = rt; sprt; sprt = sprt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -0500393 struct net_device *dev = sprt->dst.dev;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900394
395 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 if (dev->ifindex == oif)
397 return sprt;
398 if (dev->flags & IFF_LOOPBACK) {
David S. Miller38308472011-12-03 18:02:47 -0500399 if (!sprt->rt6i_idev ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 sprt->rt6i_idev->dev->ifindex != oif) {
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700401 if (flags & RT6_LOOKUP_F_IFACE && oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 continue;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900403 if (local && (!oif ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 local->rt6i_idev->dev->ifindex == oif))
405 continue;
406 }
407 local = sprt;
408 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900409 } else {
410 if (ipv6_chk_addr(net, saddr, dev,
411 flags & RT6_LOOKUP_F_IFACE))
412 return sprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900414 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900416 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 if (local)
418 return local;
419
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700420 if (flags & RT6_LOOKUP_F_IFACE)
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800421 return net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900423out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 return rt;
425}
426
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800427#ifdef CONFIG_IPV6_ROUTER_PREF
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200428struct __rt6_probe_work {
429 struct work_struct work;
430 struct in6_addr target;
431 struct net_device *dev;
432};
433
434static void rt6_probe_deferred(struct work_struct *w)
435{
436 struct in6_addr mcaddr;
437 struct __rt6_probe_work *work =
438 container_of(w, struct __rt6_probe_work, work);
439
440 addrconf_addr_solict_mult(&work->target, &mcaddr);
441 ndisc_send_ns(work->dev, NULL, &work->target, &mcaddr, NULL);
442 dev_put(work->dev);
Michael Büsch662f5532015-02-08 10:14:07 +0100443 kfree(work);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200444}
445
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800446static void rt6_probe(struct rt6_info *rt)
447{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000448 struct neighbour *neigh;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800449 /*
450 * Okay, this does not seem to be appropriate
451 * for now, however, we need to check if it
452 * is really so; aka Router Reachability Probing.
453 *
454 * Router Reachability Probe MUST be rate-limited
455 * to no more than one per minute.
456 */
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000457 if (!rt || !(rt->rt6i_flags & RTF_GATEWAY))
Amerigo Wangfdd66812012-09-10 02:48:44 +0000458 return;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000459 rcu_read_lock_bh();
460 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
461 if (neigh) {
462 write_lock(&neigh->lock);
463 if (neigh->nud_state & NUD_VALID)
464 goto out;
YOSHIFUJI Hideaki / 吉藤英明7ff74a52013-01-17 12:53:02 +0000465 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000466
467 if (!neigh ||
YOSHIFUJI Hideaki52e16352006-03-20 17:05:47 -0800468 time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) {
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200469 struct __rt6_probe_work *work;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800470
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200471 work = kmalloc(sizeof(*work), GFP_ATOMIC);
472
473 if (neigh && work)
Jiri Benc7e980562013-12-11 13:48:20 +0100474 __neigh_set_probe_once(neigh);
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000475
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200476 if (neigh)
477 write_unlock(&neigh->lock);
478
479 if (work) {
480 INIT_WORK(&work->work, rt6_probe_deferred);
481 work->target = rt->rt6i_gateway;
482 dev_hold(rt->dst.dev);
483 work->dev = rt->dst.dev;
484 schedule_work(&work->work);
485 }
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000486 } else {
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000487out:
488 write_unlock(&neigh->lock);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000489 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000490 rcu_read_unlock_bh();
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800491}
492#else
493static inline void rt6_probe(struct rt6_info *rt)
494{
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800495}
496#endif
497
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498/*
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800499 * Default Router Selection (RFC 2461 6.3.6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 */
Dave Jonesb6f99a22007-03-22 12:27:49 -0700501static inline int rt6_check_dev(struct rt6_info *rt, int oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502{
David S. Millerd1918542011-12-28 20:19:20 -0500503 struct net_device *dev = rt->dst.dev;
David S. Miller161980f2007-04-06 11:42:27 -0700504 if (!oif || dev->ifindex == oif)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800505 return 2;
David S. Miller161980f2007-04-06 11:42:27 -0700506 if ((dev->flags & IFF_LOOPBACK) &&
507 rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
508 return 1;
509 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510}
511
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200512static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000514 struct neighbour *neigh;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200515 enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000516
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700517 if (rt->rt6i_flags & RTF_NONEXTHOP ||
518 !(rt->rt6i_flags & RTF_GATEWAY))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200519 return RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000520
521 rcu_read_lock_bh();
522 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
523 if (neigh) {
524 read_lock(&neigh->lock);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800525 if (neigh->nud_state & NUD_VALID)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200526 ret = RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800527#ifdef CONFIG_IPV6_ROUTER_PREF
Paul Marksa5a81f02012-12-03 10:26:54 +0000528 else if (!(neigh->nud_state & NUD_FAILED))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200529 ret = RT6_NUD_SUCCEED;
Jiri Benc7e980562013-12-11 13:48:20 +0100530 else
531 ret = RT6_NUD_FAIL_PROBE;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800532#endif
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000533 read_unlock(&neigh->lock);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200534 } else {
535 ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
Jiri Benc7e980562013-12-11 13:48:20 +0100536 RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR;
Paul Marksa5a81f02012-12-03 10:26:54 +0000537 }
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000538 rcu_read_unlock_bh();
539
Paul Marksa5a81f02012-12-03 10:26:54 +0000540 return ret;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800541}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800543static int rt6_score_route(struct rt6_info *rt, int oif,
544 int strict)
545{
Paul Marksa5a81f02012-12-03 10:26:54 +0000546 int m;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900547
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700548 m = rt6_check_dev(rt, oif);
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700549 if (!m && (strict & RT6_LOOKUP_F_IFACE))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200550 return RT6_NUD_FAIL_HARD;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800551#ifdef CONFIG_IPV6_ROUTER_PREF
552 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
553#endif
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200554 if (strict & RT6_LOOKUP_F_REACHABLE) {
555 int n = rt6_check_neigh(rt);
556 if (n < 0)
557 return n;
558 }
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800559 return m;
560}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
David S. Millerf11e6652007-03-24 20:36:25 -0700562static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200563 int *mpri, struct rt6_info *match,
564 bool *do_rr)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800565{
David S. Millerf11e6652007-03-24 20:36:25 -0700566 int m;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200567 bool match_do_rr = false;
David S. Millerf11e6652007-03-24 20:36:25 -0700568
569 if (rt6_check_expired(rt))
570 goto out;
571
572 m = rt6_score_route(rt, oif, strict);
Jiri Benc7e980562013-12-11 13:48:20 +0100573 if (m == RT6_NUD_FAIL_DO_RR) {
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200574 match_do_rr = true;
575 m = 0; /* lowest valid score */
Jiri Benc7e980562013-12-11 13:48:20 +0100576 } else if (m == RT6_NUD_FAIL_HARD) {
David S. Millerf11e6652007-03-24 20:36:25 -0700577 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700578 }
579
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200580 if (strict & RT6_LOOKUP_F_REACHABLE)
581 rt6_probe(rt);
582
Jiri Benc7e980562013-12-11 13:48:20 +0100583 /* note that m can be RT6_NUD_FAIL_PROBE at this point */
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200584 if (m > *mpri) {
585 *do_rr = match_do_rr;
586 *mpri = m;
587 match = rt;
588 }
David S. Millerf11e6652007-03-24 20:36:25 -0700589out:
590 return match;
591}
592
593static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
594 struct rt6_info *rr_head,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200595 u32 metric, int oif, int strict,
596 bool *do_rr)
David S. Millerf11e6652007-03-24 20:36:25 -0700597{
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700598 struct rt6_info *rt, *match, *cont;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800599 int mpri = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
David S. Millerf11e6652007-03-24 20:36:25 -0700601 match = NULL;
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700602 cont = NULL;
603 for (rt = rr_head; rt; rt = rt->dst.rt6_next) {
604 if (rt->rt6i_metric != metric) {
605 cont = rt;
606 break;
607 }
608
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200609 match = find_match(rt, oif, strict, &mpri, match, do_rr);
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700610 }
611
612 for (rt = fn->leaf; rt && rt != rr_head; rt = rt->dst.rt6_next) {
613 if (rt->rt6i_metric != metric) {
614 cont = rt;
615 break;
616 }
617
618 match = find_match(rt, oif, strict, &mpri, match, do_rr);
619 }
620
621 if (match || !cont)
622 return match;
623
624 for (rt = cont; rt; rt = rt->dst.rt6_next)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200625 match = find_match(rt, oif, strict, &mpri, match, do_rr);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800626
David S. Millerf11e6652007-03-24 20:36:25 -0700627 return match;
628}
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800629
David S. Millerf11e6652007-03-24 20:36:25 -0700630static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
631{
632 struct rt6_info *match, *rt0;
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800633 struct net *net;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200634 bool do_rr = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
David S. Millerf11e6652007-03-24 20:36:25 -0700636 rt0 = fn->rr_ptr;
637 if (!rt0)
638 fn->rr_ptr = rt0 = fn->leaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200640 match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict,
641 &do_rr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200643 if (do_rr) {
Changli Gaod8d1f302010-06-10 23:31:35 -0700644 struct rt6_info *next = rt0->dst.rt6_next;
David S. Millerf11e6652007-03-24 20:36:25 -0700645
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800646 /* no entries matched; do round-robin */
David S. Millerf11e6652007-03-24 20:36:25 -0700647 if (!next || next->rt6i_metric != rt0->rt6i_metric)
648 next = fn->leaf;
649
650 if (next != rt0)
651 fn->rr_ptr = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 }
653
David S. Millerd1918542011-12-28 20:19:20 -0500654 net = dev_net(rt0->dst.dev);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000655 return match ? match : net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656}
657
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700658static bool rt6_is_gw_or_nonexthop(const struct rt6_info *rt)
659{
660 return (rt->rt6i_flags & (RTF_NONEXTHOP | RTF_GATEWAY));
661}
662
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800663#ifdef CONFIG_IPV6_ROUTE_INFO
664int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000665 const struct in6_addr *gwaddr)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800666{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900667 struct net *net = dev_net(dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800668 struct route_info *rinfo = (struct route_info *) opt;
669 struct in6_addr prefix_buf, *prefix;
670 unsigned int pref;
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900671 unsigned long lifetime;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800672 struct rt6_info *rt;
673
674 if (len < sizeof(struct route_info)) {
675 return -EINVAL;
676 }
677
678 /* Sanity check for prefix_len and length */
679 if (rinfo->length > 3) {
680 return -EINVAL;
681 } else if (rinfo->prefix_len > 128) {
682 return -EINVAL;
683 } else if (rinfo->prefix_len > 64) {
684 if (rinfo->length < 2) {
685 return -EINVAL;
686 }
687 } else if (rinfo->prefix_len > 0) {
688 if (rinfo->length < 1) {
689 return -EINVAL;
690 }
691 }
692
693 pref = rinfo->route_pref;
694 if (pref == ICMPV6_ROUTER_PREF_INVALID)
Jens Rosenboom3933fc92009-09-10 06:25:11 +0000695 return -EINVAL;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800696
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900697 lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800698
699 if (rinfo->length == 3)
700 prefix = (struct in6_addr *)rinfo->prefix;
701 else {
702 /* this function is safe */
703 ipv6_addr_prefix(&prefix_buf,
704 (struct in6_addr *)rinfo->prefix,
705 rinfo->prefix_len);
706 prefix = &prefix_buf;
707 }
708
Duan Jiongf104a562013-11-08 09:56:53 +0800709 if (rinfo->prefix_len == 0)
710 rt = rt6_get_dflt_router(gwaddr, dev);
711 else
712 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len,
713 gwaddr, dev->ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800714
715 if (rt && !lifetime) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -0700716 ip6_del_rt(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800717 rt = NULL;
718 }
719
720 if (!rt && lifetime)
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800721 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800722 pref);
723 else if (rt)
724 rt->rt6i_flags = RTF_ROUTEINFO |
725 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
726
727 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +0000728 if (!addrconf_finite_timeout(lifetime))
729 rt6_clean_expires(rt);
730 else
731 rt6_set_expires(rt, jiffies + HZ * lifetime);
732
Amerigo Wang94e187c2012-10-29 00:13:19 +0000733 ip6_rt_put(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800734 }
735 return 0;
736}
737#endif
738
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700739static struct fib6_node* fib6_backtrack(struct fib6_node *fn,
740 struct in6_addr *saddr)
741{
742 struct fib6_node *pn;
743 while (1) {
744 if (fn->fn_flags & RTN_TL_ROOT)
745 return NULL;
746 pn = fn->parent;
747 if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn)
748 fn = fib6_lookup(FIB6_SUBTREE(pn), NULL, saddr);
749 else
750 fn = pn;
751 if (fn->fn_flags & RTN_RTINFO)
752 return fn;
753 }
754}
Thomas Grafc71099a2006-08-04 23:20:06 -0700755
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800756static struct rt6_info *ip6_pol_route_lookup(struct net *net,
757 struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500758 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759{
760 struct fib6_node *fn;
761 struct rt6_info *rt;
762
Thomas Grafc71099a2006-08-04 23:20:06 -0700763 read_lock_bh(&table->tb6_lock);
David S. Miller4c9483b2011-03-12 16:22:43 -0500764 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -0700765restart:
766 rt = fn->leaf;
David S. Miller4c9483b2011-03-12 16:22:43 -0500767 rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000768 if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0)
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200769 rt = rt6_multipath_select(rt, fl6, fl6->flowi6_oif, flags);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700770 if (rt == net->ipv6.ip6_null_entry) {
771 fn = fib6_backtrack(fn, &fl6->saddr);
772 if (fn)
773 goto restart;
774 }
Changli Gaod8d1f302010-06-10 23:31:35 -0700775 dst_use(&rt->dst, jiffies);
Thomas Grafc71099a2006-08-04 23:20:06 -0700776 read_unlock_bh(&table->tb6_lock);
Thomas Grafc71099a2006-08-04 23:20:06 -0700777 return rt;
778
779}
780
Ian Morris67ba4152014-08-24 21:53:10 +0100781struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
Florian Westphalea6e5742011-09-05 16:05:44 +0200782 int flags)
783{
784 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup);
785}
786EXPORT_SYMBOL_GPL(ip6_route_lookup);
787
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900788struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
789 const struct in6_addr *saddr, int oif, int strict)
Thomas Grafc71099a2006-08-04 23:20:06 -0700790{
David S. Miller4c9483b2011-03-12 16:22:43 -0500791 struct flowi6 fl6 = {
792 .flowi6_oif = oif,
793 .daddr = *daddr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700794 };
795 struct dst_entry *dst;
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700796 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
Thomas Grafc71099a2006-08-04 23:20:06 -0700797
Thomas Grafadaa70b2006-10-13 15:01:03 -0700798 if (saddr) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500799 memcpy(&fl6.saddr, saddr, sizeof(*saddr));
Thomas Grafadaa70b2006-10-13 15:01:03 -0700800 flags |= RT6_LOOKUP_F_HAS_SADDR;
801 }
802
David S. Miller4c9483b2011-03-12 16:22:43 -0500803 dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup);
Thomas Grafc71099a2006-08-04 23:20:06 -0700804 if (dst->error == 0)
805 return (struct rt6_info *) dst;
806
807 dst_release(dst);
808
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 return NULL;
810}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900811EXPORT_SYMBOL(rt6_lookup);
812
Thomas Grafc71099a2006-08-04 23:20:06 -0700813/* ip6_ins_rt is called with FREE table->tb6_lock.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 It takes new route entry, the addition fails by any reason the
815 route is freed. In any case, if caller does not hold it, it may
816 be destroyed.
817 */
818
Michal Kubečeke5fd3872014-03-27 13:04:08 +0100819static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info,
Florian Westphale715b6d2015-01-05 23:57:44 +0100820 struct mx6_config *mxc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821{
822 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -0700823 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
Thomas Grafc71099a2006-08-04 23:20:06 -0700825 table = rt->rt6i_table;
826 write_lock_bh(&table->tb6_lock);
Florian Westphale715b6d2015-01-05 23:57:44 +0100827 err = fib6_add(&table->tb6_root, rt, info, mxc);
Thomas Grafc71099a2006-08-04 23:20:06 -0700828 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
830 return err;
831}
832
Thomas Graf40e22e82006-08-22 00:00:45 -0700833int ip6_ins_rt(struct rt6_info *rt)
834{
Florian Westphale715b6d2015-01-05 23:57:44 +0100835 struct nl_info info = { .nl_net = dev_net(rt->dst.dev), };
836 struct mx6_config mxc = { .mx = NULL, };
837
838 return __ip6_ins_rt(rt, &info, &mxc);
Thomas Graf40e22e82006-08-22 00:00:45 -0700839}
840
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700841static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort,
842 const struct in6_addr *daddr,
843 const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 struct rt6_info *rt;
846
847 /*
848 * Clone the route.
849 */
850
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000851 rt = ip6_rt_copy(ort, daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852
853 if (rt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 rt->rt6i_flags |= RTF_CACHE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700856 if (!rt6_is_gw_or_nonexthop(ort)) {
857 if (ort->rt6i_dst.plen != 128 &&
858 ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
859 rt->rt6i_flags |= RTF_ANYCAST;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700861 if (rt->rt6i_src.plen && saddr) {
862 rt->rt6i_src.addr = *saddr;
863 rt->rt6i_src.plen = 128;
864 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865#endif
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700866 }
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800867 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800869 return rt;
870}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800872static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif,
David S. Miller4c9483b2011-03-12 16:22:43 -0500873 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874{
Martin KaFai Lau367efcb2014-10-20 13:42:45 -0700875 struct fib6_node *fn, *saved_fn;
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -0700876 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -0700877 int strict = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700879 strict |= flags & RT6_LOOKUP_F_IFACE;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -0700880 if (net->ipv6.devconf_all->forwarding == 0)
881 strict |= RT6_LOOKUP_F_REACHABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882
Thomas Grafc71099a2006-08-04 23:20:06 -0700883 read_lock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
David S. Miller4c9483b2011-03-12 16:22:43 -0500885 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Martin KaFai Lau367efcb2014-10-20 13:42:45 -0700886 saved_fn = fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700888redo_rt6_select:
Martin KaFai Lau367efcb2014-10-20 13:42:45 -0700889 rt = rt6_select(fn, oif, strict);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200890 if (rt->rt6i_nsiblings)
Martin KaFai Lau367efcb2014-10-20 13:42:45 -0700891 rt = rt6_multipath_select(rt, fl6, oif, strict);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700892 if (rt == net->ipv6.ip6_null_entry) {
893 fn = fib6_backtrack(fn, &fl6->saddr);
894 if (fn)
895 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -0700896 else if (strict & RT6_LOOKUP_F_REACHABLE) {
897 /* also consider unreachable route */
898 strict &= ~RT6_LOOKUP_F_REACHABLE;
899 fn = saved_fn;
900 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -0700901 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700902 }
903
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -0700904 dst_use(&rt->dst, jiffies);
Thomas Grafc71099a2006-08-04 23:20:06 -0700905 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -0800906
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -0700907 if (rt == net->ipv6.ip6_null_entry || (rt->rt6i_flags & RTF_CACHE)) {
908 goto done;
909 } else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) &&
910 !(rt->rt6i_flags & RTF_GATEWAY))) {
911 /* Create a RTF_CACHE clone which will not be
912 * owned by the fib6 tree. It is for the special case where
913 * the daddr in the skb during the neighbor look-up is different
914 * from the fl6->daddr used to look-up route here.
915 */
Thomas Grafc71099a2006-08-04 23:20:06 -0700916
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -0700917 struct rt6_info *uncached_rt;
918
919 uncached_rt = ip6_rt_cache_alloc(rt, &fl6->daddr, NULL);
920 dst_release(&rt->dst);
921
922 if (uncached_rt)
923 uncached_rt->dst.flags |= DST_NOCACHE;
924 else
925 uncached_rt = net->ipv6.ip6_null_entry;
926 dst_hold(&uncached_rt->dst);
927 return uncached_rt;
928 }
929
930done:
931 rt6_dst_from_metrics_check(rt);
Thomas Grafc71099a2006-08-04 23:20:06 -0700932 return rt;
933}
934
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800935static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500936 struct flowi6 *fl6, int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -0700937{
David S. Miller4c9483b2011-03-12 16:22:43 -0500938 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -0700939}
940
Shmulik Ladkani72331bc2012-04-01 04:03:45 +0000941static struct dst_entry *ip6_route_input_lookup(struct net *net,
942 struct net_device *dev,
943 struct flowi6 *fl6, int flags)
944{
945 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
946 flags |= RT6_LOOKUP_F_IFACE;
947
948 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_input);
949}
950
Thomas Grafc71099a2006-08-04 23:20:06 -0700951void ip6_route_input(struct sk_buff *skb)
952{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000953 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900954 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -0700955 int flags = RT6_LOOKUP_F_HAS_SADDR;
David S. Miller4c9483b2011-03-12 16:22:43 -0500956 struct flowi6 fl6 = {
957 .flowi6_iif = skb->dev->ifindex,
958 .daddr = iph->daddr,
959 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +0000960 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -0500961 .flowi6_mark = skb->mark,
962 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700963 };
Thomas Grafadaa70b2006-10-13 15:01:03 -0700964
Shmulik Ladkani72331bc2012-04-01 04:03:45 +0000965 skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -0700966}
967
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800968static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500969 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -0700970{
David S. Miller4c9483b2011-03-12 16:22:43 -0500971 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -0700972}
973
Ian Morris67ba4152014-08-24 21:53:10 +0100974struct dst_entry *ip6_route_output(struct net *net, const struct sock *sk,
David S. Miller4c9483b2011-03-12 16:22:43 -0500975 struct flowi6 *fl6)
Thomas Grafc71099a2006-08-04 23:20:06 -0700976{
977 int flags = 0;
978
Pavel Emelyanov1fb94892012-08-08 21:53:36 +0000979 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +0000980
David S. Miller4c9483b2011-03-12 16:22:43 -0500981 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700982 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -0700983
David S. Miller4c9483b2011-03-12 16:22:43 -0500984 if (!ipv6_addr_any(&fl6->saddr))
Thomas Grafadaa70b2006-10-13 15:01:03 -0700985 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +0000986 else if (sk)
987 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -0700988
David S. Miller4c9483b2011-03-12 16:22:43 -0500989 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900991EXPORT_SYMBOL(ip6_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
David S. Miller2774c132011-03-01 14:59:04 -0800993struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -0700994{
David S. Miller5c1e6aa2011-04-28 14:13:38 -0700995 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
David S. Miller14e50e52007-05-24 18:17:54 -0700996 struct dst_entry *new = NULL;
997
David S. Millerf5b0a872012-07-19 12:31:33 -0700998 rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, DST_OBSOLETE_NONE, 0);
David S. Miller14e50e52007-05-24 18:17:54 -0700999 if (rt) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001000 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -07001001
Steffen Klassert81048912012-07-05 23:37:09 +00001002 memset(new + 1, 0, sizeof(*rt) - sizeof(*new));
Steffen Klassert81048912012-07-05 23:37:09 +00001003
David S. Miller14e50e52007-05-24 18:17:54 -07001004 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08001005 new->input = dst_discard;
Eric Dumazetaad88722014-04-15 13:47:15 -04001006 new->output = dst_discard_sk;
David S. Miller14e50e52007-05-24 18:17:54 -07001007
Eric Dumazet21efcfa2011-07-19 20:18:36 +00001008 if (dst_metrics_read_only(&ort->dst))
1009 new->_metrics = ort->dst._metrics;
1010 else
1011 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07001012 rt->rt6i_idev = ort->rt6i_idev;
1013 if (rt->rt6i_idev)
1014 in6_dev_hold(rt->rt6i_idev);
David S. Miller14e50e52007-05-24 18:17:54 -07001015
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001016 rt->rt6i_gateway = ort->rt6i_gateway;
Gao feng1716a962012-04-06 00:13:10 +00001017 rt->rt6i_flags = ort->rt6i_flags;
David S. Miller14e50e52007-05-24 18:17:54 -07001018 rt->rt6i_metric = 0;
1019
1020 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
1021#ifdef CONFIG_IPV6_SUBTREES
1022 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1023#endif
1024
1025 dst_free(new);
1026 }
1027
David S. Miller69ead7a2011-03-01 14:45:33 -08001028 dst_release(dst_orig);
1029 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07001030}
David S. Miller14e50e52007-05-24 18:17:54 -07001031
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032/*
1033 * Destination cache support functions
1034 */
1035
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001036static void rt6_dst_from_metrics_check(struct rt6_info *rt)
1037{
1038 if (rt->dst.from &&
1039 dst_metrics_ptr(&rt->dst) != dst_metrics_ptr(rt->dst.from))
1040 dst_init_metrics(&rt->dst, dst_metrics_ptr(rt->dst.from), true);
1041}
1042
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001043static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie)
1044{
1045 if (!rt->rt6i_node || (rt->rt6i_node->fn_sernum != cookie))
1046 return NULL;
1047
1048 if (rt6_check_expired(rt))
1049 return NULL;
1050
1051 return &rt->dst;
1052}
1053
1054static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, u32 cookie)
1055{
1056 if (rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
1057 rt6_check((struct rt6_info *)(rt->dst.from), cookie))
1058 return &rt->dst;
1059 else
1060 return NULL;
1061}
1062
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
1064{
1065 struct rt6_info *rt;
1066
1067 rt = (struct rt6_info *) dst;
1068
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00001069 /* All IPV6 dsts are created with ->obsolete set to the value
1070 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
1071 * into this function always.
1072 */
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02001073
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001074 rt6_dst_from_metrics_check(rt);
1075
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001076 if (unlikely(dst->flags & DST_NOCACHE))
1077 return rt6_dst_from_check(rt, cookie);
1078 else
1079 return rt6_check(rt, cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080}
1081
1082static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
1083{
1084 struct rt6_info *rt = (struct rt6_info *) dst;
1085
1086 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001087 if (rt->rt6i_flags & RTF_CACHE) {
1088 if (rt6_check_expired(rt)) {
1089 ip6_del_rt(rt);
1090 dst = NULL;
1091 }
1092 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001094 dst = NULL;
1095 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001097 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098}
1099
1100static void ip6_link_failure(struct sk_buff *skb)
1101{
1102 struct rt6_info *rt;
1103
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00001104 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
Eric Dumazetadf30902009-06-02 05:19:30 +00001106 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 if (rt) {
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001108 if (rt->rt6i_flags & RTF_CACHE) {
1109 dst_hold(&rt->dst);
1110 if (ip6_del_rt(rt))
1111 dst_free(&rt->dst);
1112 } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 rt->rt6i_node->fn_sernum = -1;
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 }
1116}
1117
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001118static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
1119{
1120 struct net *net = dev_net(rt->dst.dev);
1121
1122 rt->rt6i_flags |= RTF_MODIFIED;
1123 rt->rt6i_pmtu = mtu;
1124 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
1125}
1126
1127static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
1128 const struct ipv6hdr *iph, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129{
Ian Morris67ba4152014-08-24 21:53:10 +01001130 struct rt6_info *rt6 = (struct rt6_info *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001132 if (rt6->rt6i_flags & RTF_LOCAL)
1133 return;
1134
David S. Miller81aded22012-06-15 14:54:11 -07001135 dst_confirm(dst);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001136 mtu = max_t(u32, mtu, IPV6_MIN_MTU);
1137 if (mtu >= dst_mtu(dst))
1138 return;
David S. Miller81aded22012-06-15 14:54:11 -07001139
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001140 if (rt6->rt6i_flags & RTF_CACHE) {
1141 rt6_do_update_pmtu(rt6, mtu);
1142 } else {
1143 const struct in6_addr *daddr, *saddr;
1144 struct rt6_info *nrt6;
Hagen Paul Pfeifer9d289712015-01-15 22:34:25 +01001145
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001146 if (iph) {
1147 daddr = &iph->daddr;
1148 saddr = &iph->saddr;
1149 } else if (sk) {
1150 daddr = &sk->sk_v6_daddr;
1151 saddr = &inet6_sk(sk)->saddr;
1152 } else {
1153 return;
1154 }
1155 nrt6 = ip6_rt_cache_alloc(rt6, daddr, saddr);
1156 if (nrt6) {
1157 rt6_do_update_pmtu(nrt6, mtu);
1158
1159 /* ip6_ins_rt(nrt6) will bump the
1160 * rt6->rt6i_node->fn_sernum
1161 * which will fail the next rt6_check() and
1162 * invalidate the sk->sk_dst_cache.
1163 */
1164 ip6_ins_rt(nrt6);
1165 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 }
1167}
1168
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001169static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
1170 struct sk_buff *skb, u32 mtu)
1171{
1172 __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu);
1173}
1174
David S. Miller42ae66c2012-06-15 20:01:57 -07001175void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
1176 int oif, u32 mark)
David S. Miller81aded22012-06-15 14:54:11 -07001177{
1178 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1179 struct dst_entry *dst;
1180 struct flowi6 fl6;
1181
1182 memset(&fl6, 0, sizeof(fl6));
1183 fl6.flowi6_oif = oif;
Lorenzo Colitti1b3c61d2014-05-13 10:17:34 -07001184 fl6.flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark);
David S. Miller81aded22012-06-15 14:54:11 -07001185 fl6.daddr = iph->daddr;
1186 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001187 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller81aded22012-06-15 14:54:11 -07001188
1189 dst = ip6_route_output(net, NULL, &fl6);
1190 if (!dst->error)
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001191 __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07001192 dst_release(dst);
1193}
1194EXPORT_SYMBOL_GPL(ip6_update_pmtu);
1195
1196void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
1197{
1198 ip6_update_pmtu(skb, sock_net(sk), mtu,
1199 sk->sk_bound_dev_if, sk->sk_mark);
1200}
1201EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
1202
Duan Jiongb55b76b2013-09-04 19:44:21 +08001203/* Handle redirects */
1204struct ip6rd_flowi {
1205 struct flowi6 fl6;
1206 struct in6_addr gateway;
1207};
1208
1209static struct rt6_info *__ip6_route_redirect(struct net *net,
1210 struct fib6_table *table,
1211 struct flowi6 *fl6,
1212 int flags)
1213{
1214 struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
1215 struct rt6_info *rt;
1216 struct fib6_node *fn;
1217
1218 /* Get the "current" route for this destination and
1219 * check if the redirect has come from approriate router.
1220 *
1221 * RFC 4861 specifies that redirects should only be
1222 * accepted if they come from the nexthop to the target.
1223 * Due to the way the routes are chosen, this notion
1224 * is a bit fuzzy and one might need to check all possible
1225 * routes.
1226 */
1227
1228 read_lock_bh(&table->tb6_lock);
1229 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
1230restart:
1231 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
1232 if (rt6_check_expired(rt))
1233 continue;
1234 if (rt->dst.error)
1235 break;
1236 if (!(rt->rt6i_flags & RTF_GATEWAY))
1237 continue;
1238 if (fl6->flowi6_oif != rt->dst.dev->ifindex)
1239 continue;
1240 if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway))
1241 continue;
1242 break;
1243 }
1244
1245 if (!rt)
1246 rt = net->ipv6.ip6_null_entry;
1247 else if (rt->dst.error) {
1248 rt = net->ipv6.ip6_null_entry;
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001249 goto out;
1250 }
1251
1252 if (rt == net->ipv6.ip6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001253 fn = fib6_backtrack(fn, &fl6->saddr);
1254 if (fn)
1255 goto restart;
Duan Jiongb55b76b2013-09-04 19:44:21 +08001256 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001257
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001258out:
Duan Jiongb55b76b2013-09-04 19:44:21 +08001259 dst_hold(&rt->dst);
1260
1261 read_unlock_bh(&table->tb6_lock);
1262
1263 return rt;
1264};
1265
1266static struct dst_entry *ip6_route_redirect(struct net *net,
1267 const struct flowi6 *fl6,
1268 const struct in6_addr *gateway)
1269{
1270 int flags = RT6_LOOKUP_F_HAS_SADDR;
1271 struct ip6rd_flowi rdfl;
1272
1273 rdfl.fl6 = *fl6;
1274 rdfl.gateway = *gateway;
1275
1276 return fib6_rule_lookup(net, &rdfl.fl6,
1277 flags, __ip6_route_redirect);
1278}
1279
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001280void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark)
1281{
1282 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1283 struct dst_entry *dst;
1284 struct flowi6 fl6;
1285
1286 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001287 fl6.flowi6_iif = LOOPBACK_IFINDEX;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001288 fl6.flowi6_oif = oif;
1289 fl6.flowi6_mark = mark;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001290 fl6.daddr = iph->daddr;
1291 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001292 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001293
Duan Jiongb55b76b2013-09-04 19:44:21 +08001294 dst = ip6_route_redirect(net, &fl6, &ipv6_hdr(skb)->saddr);
1295 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001296 dst_release(dst);
1297}
1298EXPORT_SYMBOL_GPL(ip6_redirect);
1299
Duan Jiongc92a59e2013-08-22 12:07:35 +08001300void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
1301 u32 mark)
1302{
1303 const struct ipv6hdr *iph = ipv6_hdr(skb);
1304 const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
1305 struct dst_entry *dst;
1306 struct flowi6 fl6;
1307
1308 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001309 fl6.flowi6_iif = LOOPBACK_IFINDEX;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001310 fl6.flowi6_oif = oif;
1311 fl6.flowi6_mark = mark;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001312 fl6.daddr = msg->dest;
1313 fl6.saddr = iph->daddr;
1314
Duan Jiongb55b76b2013-09-04 19:44:21 +08001315 dst = ip6_route_redirect(net, &fl6, &iph->saddr);
1316 rt6_do_redirect(dst, NULL, skb);
Duan Jiongc92a59e2013-08-22 12:07:35 +08001317 dst_release(dst);
1318}
1319
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001320void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
1321{
1322 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark);
1323}
1324EXPORT_SYMBOL_GPL(ip6_sk_redirect);
1325
David S. Miller0dbaee32010-12-13 12:52:14 -08001326static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327{
David S. Miller0dbaee32010-12-13 12:52:14 -08001328 struct net_device *dev = dst->dev;
1329 unsigned int mtu = dst_mtu(dst);
1330 struct net *net = dev_net(dev);
1331
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
1333
Daniel Lezcano55786892008-03-04 13:47:47 -08001334 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
1335 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336
1337 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001338 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
1339 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
1340 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 * rely only on pmtu discovery"
1342 */
1343 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
1344 mtu = IPV6_MAXPLEN;
1345 return mtu;
1346}
1347
Steffen Klassertebb762f2011-11-23 02:12:51 +00001348static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08001349{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001350 const struct rt6_info *rt = (const struct rt6_info *)dst;
1351 unsigned int mtu = rt->rt6i_pmtu;
David S. Millerd33e4552010-12-14 13:01:14 -08001352 struct inet6_dev *idev;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001353
1354 if (mtu)
Eric Dumazet30f78d82014-04-10 21:23:36 -07001355 goto out;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001356
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001357 mtu = dst_metric_raw(dst, RTAX_MTU);
1358 if (mtu)
1359 goto out;
1360
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001361 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08001362
1363 rcu_read_lock();
1364 idev = __in6_dev_get(dst->dev);
1365 if (idev)
1366 mtu = idev->cnf.mtu6;
1367 rcu_read_unlock();
1368
Eric Dumazet30f78d82014-04-10 21:23:36 -07001369out:
1370 return min_t(unsigned int, mtu, IP6_MAX_MTU);
David S. Millerd33e4552010-12-14 13:01:14 -08001371}
1372
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001373static struct dst_entry *icmp6_dst_gc_list;
1374static DEFINE_SPINLOCK(icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001375
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001376struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05001377 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378{
David S. Miller87a11572011-12-06 17:04:13 -05001379 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 struct rt6_info *rt;
1381 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001382 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383
David S. Miller38308472011-12-03 18:02:47 -05001384 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00001385 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386
David S. Miller8b96d222012-06-11 02:01:56 -07001387 rt = ip6_dst_alloc(net, dev, 0, NULL);
David S. Miller38308472011-12-03 18:02:47 -05001388 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05001390 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 goto out;
1392 }
1393
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001394 rt->dst.flags |= DST_HOST;
1395 rt->dst.output = ip6_output;
Changli Gaod8d1f302010-06-10 23:31:35 -07001396 atomic_set(&rt->dst.__refcnt, 1);
Julian Anastasov550bab42013-10-20 15:43:04 +03001397 rt->rt6i_gateway = fl6->daddr;
David S. Miller87a11572011-12-06 17:04:13 -05001398 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001399 rt->rt6i_dst.plen = 128;
1400 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08001401 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001403 spin_lock_bh(&icmp6_dst_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001404 rt->dst.next = icmp6_dst_gc_list;
1405 icmp6_dst_gc_list = &rt->dst;
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001406 spin_unlock_bh(&icmp6_dst_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407
Daniel Lezcano55786892008-03-04 13:47:47 -08001408 fib6_force_start_gc(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409
David S. Miller87a11572011-12-06 17:04:13 -05001410 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
1411
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412out:
David S. Miller87a11572011-12-06 17:04:13 -05001413 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414}
1415
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001416int icmp6_dst_gc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417{
Hagen Paul Pfeifere9476e92011-02-25 05:45:19 +00001418 struct dst_entry *dst, **pprev;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001419 int more = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001421 spin_lock_bh(&icmp6_dst_lock);
1422 pprev = &icmp6_dst_gc_list;
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001423
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 while ((dst = *pprev) != NULL) {
1425 if (!atomic_read(&dst->__refcnt)) {
1426 *pprev = dst->next;
1427 dst_free(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 } else {
1429 pprev = &dst->next;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001430 ++more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 }
1432 }
1433
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001434 spin_unlock_bh(&icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001435
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001436 return more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437}
1438
David S. Miller1e493d12008-09-10 17:27:15 -07001439static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg),
1440 void *arg)
1441{
1442 struct dst_entry *dst, **pprev;
1443
1444 spin_lock_bh(&icmp6_dst_lock);
1445 pprev = &icmp6_dst_gc_list;
1446 while ((dst = *pprev) != NULL) {
1447 struct rt6_info *rt = (struct rt6_info *) dst;
1448 if (func(rt, arg)) {
1449 *pprev = dst->next;
1450 dst_free(dst);
1451 } else {
1452 pprev = &dst->next;
1453 }
1454 }
1455 spin_unlock_bh(&icmp6_dst_lock);
1456}
1457
Daniel Lezcano569d3642008-01-18 03:56:57 -08001458static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459{
Alexey Dobriyan86393e52009-08-29 01:34:49 +00001460 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08001461 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
1462 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
1463 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
1464 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
1465 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001466 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467
Eric Dumazetfc66f952010-10-08 06:37:34 +00001468 entries = dst_entries_get_fast(ops);
Michal Kubeček49a18d82013-08-01 10:04:24 +02001469 if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00001470 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 goto out;
1472
Benjamin Thery6891a342008-03-04 13:49:47 -08001473 net->ipv6.ip6_rt_gc_expire++;
Li RongQing14956642014-05-19 17:30:28 +08001474 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
Eric Dumazetfc66f952010-10-08 06:37:34 +00001475 entries = dst_entries_get_slow(ops);
1476 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08001477 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08001479 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001480 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481}
1482
Florian Westphale715b6d2015-01-05 23:57:44 +01001483static int ip6_convert_metrics(struct mx6_config *mxc,
1484 const struct fib6_config *cfg)
1485{
1486 struct nlattr *nla;
1487 int remaining;
1488 u32 *mp;
1489
Ian Morris63159f22015-03-29 14:00:04 +01001490 if (!cfg->fc_mx)
Florian Westphale715b6d2015-01-05 23:57:44 +01001491 return 0;
1492
1493 mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
1494 if (unlikely(!mp))
1495 return -ENOMEM;
1496
1497 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
1498 int type = nla_type(nla);
1499
1500 if (type) {
Daniel Borkmannea697632015-01-05 23:57:47 +01001501 u32 val;
1502
Florian Westphale715b6d2015-01-05 23:57:44 +01001503 if (unlikely(type > RTAX_MAX))
1504 goto err;
Daniel Borkmannea697632015-01-05 23:57:47 +01001505 if (type == RTAX_CC_ALGO) {
1506 char tmp[TCP_CA_NAME_MAX];
Florian Westphale715b6d2015-01-05 23:57:44 +01001507
Daniel Borkmannea697632015-01-05 23:57:47 +01001508 nla_strlcpy(tmp, nla, sizeof(tmp));
1509 val = tcp_ca_get_key_by_name(tmp);
1510 if (val == TCP_CA_UNSPEC)
1511 goto err;
1512 } else {
1513 val = nla_get_u32(nla);
1514 }
1515
1516 mp[type - 1] = val;
Florian Westphale715b6d2015-01-05 23:57:44 +01001517 __set_bit(type - 1, mxc->mx_valid);
1518 }
1519 }
1520
1521 mxc->mx = mp;
1522
1523 return 0;
1524 err:
1525 kfree(mp);
1526 return -EINVAL;
1527}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528
Thomas Graf86872cb2006-08-22 00:01:08 -07001529int ip6_route_add(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530{
1531 int err;
Daniel Lezcano55786892008-03-04 13:47:47 -08001532 struct net *net = cfg->fc_nlinfo.nl_net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 struct rt6_info *rt = NULL;
1534 struct net_device *dev = NULL;
1535 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001536 struct fib6_table *table;
Florian Westphale715b6d2015-01-05 23:57:44 +01001537 struct mx6_config mxc = { .mx = NULL, };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 int addr_type;
1539
Thomas Graf86872cb2006-08-22 00:01:08 -07001540 if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 return -EINVAL;
1542#ifndef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001543 if (cfg->fc_src_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 return -EINVAL;
1545#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07001546 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08001548 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 if (!dev)
1550 goto out;
1551 idev = in6_dev_get(dev);
1552 if (!idev)
1553 goto out;
1554 }
1555
Thomas Graf86872cb2006-08-22 00:01:08 -07001556 if (cfg->fc_metric == 0)
1557 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558
Matti Vaittinend71314b2011-11-14 00:14:49 +00001559 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05001560 if (cfg->fc_nlinfo.nlh &&
1561 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00001562 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001563 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00001564 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00001565 table = fib6_new_table(net, cfg->fc_table);
1566 }
1567 } else {
1568 table = fib6_new_table(net, cfg->fc_table);
1569 }
David S. Miller38308472011-12-03 18:02:47 -05001570
1571 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001572 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07001573
Sabrina Dubrocac88507f2014-03-06 17:51:57 +01001574 rt = ip6_dst_alloc(net, NULL, (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT, table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575
David S. Miller38308472011-12-03 18:02:47 -05001576 if (!rt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 err = -ENOMEM;
1578 goto out;
1579 }
1580
Gao feng1716a962012-04-06 00:13:10 +00001581 if (cfg->fc_flags & RTF_EXPIRES)
1582 rt6_set_expires(rt, jiffies +
1583 clock_t_to_jiffies(cfg->fc_expires));
1584 else
1585 rt6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586
Thomas Graf86872cb2006-08-22 00:01:08 -07001587 if (cfg->fc_protocol == RTPROT_UNSPEC)
1588 cfg->fc_protocol = RTPROT_BOOT;
1589 rt->rt6i_protocol = cfg->fc_protocol;
1590
1591 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592
1593 if (addr_type & IPV6_ADDR_MULTICAST)
Changli Gaod8d1f302010-06-10 23:31:35 -07001594 rt->dst.input = ip6_mc_input;
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00001595 else if (cfg->fc_flags & RTF_LOCAL)
1596 rt->dst.input = ip6_input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 else
Changli Gaod8d1f302010-06-10 23:31:35 -07001598 rt->dst.input = ip6_forward;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599
Changli Gaod8d1f302010-06-10 23:31:35 -07001600 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601
Thomas Graf86872cb2006-08-22 00:01:08 -07001602 ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
1603 rt->rt6i_dst.plen = cfg->fc_dst_len;
Martin KaFai Lauafc4eef2015-04-28 13:03:07 -07001604 if (rt->rt6i_dst.plen == 128)
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001605 rt->dst.flags |= DST_HOST;
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001606
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607#ifdef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001608 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
1609 rt->rt6i_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610#endif
1611
Thomas Graf86872cb2006-08-22 00:01:08 -07001612 rt->rt6i_metric = cfg->fc_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613
1614 /* We cannot add true routes via loopback here,
1615 they would result in kernel looping; promote them to reject routes
1616 */
Thomas Graf86872cb2006-08-22 00:01:08 -07001617 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05001618 (dev && (dev->flags & IFF_LOOPBACK) &&
1619 !(addr_type & IPV6_ADDR_LOOPBACK) &&
1620 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08001622 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 if (dev) {
1624 dev_put(dev);
1625 in6_dev_put(idev);
1626 }
Daniel Lezcano55786892008-03-04 13:47:47 -08001627 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 dev_hold(dev);
1629 idev = in6_dev_get(dev);
1630 if (!idev) {
1631 err = -ENODEV;
1632 goto out;
1633 }
1634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001636 switch (cfg->fc_type) {
1637 case RTN_BLACKHOLE:
1638 rt->dst.error = -EINVAL;
Eric Dumazetaad88722014-04-15 13:47:15 -04001639 rt->dst.output = dst_discard_sk;
Kamala R7150aed2013-12-02 19:55:21 +05301640 rt->dst.input = dst_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001641 break;
1642 case RTN_PROHIBIT:
1643 rt->dst.error = -EACCES;
Kamala R7150aed2013-12-02 19:55:21 +05301644 rt->dst.output = ip6_pkt_prohibit_out;
1645 rt->dst.input = ip6_pkt_prohibit;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001646 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00001647 case RTN_THROW:
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001648 default:
Kamala R7150aed2013-12-02 19:55:21 +05301649 rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN
1650 : -ENETUNREACH;
1651 rt->dst.output = ip6_pkt_discard_out;
1652 rt->dst.input = ip6_pkt_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001653 break;
1654 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 goto install_route;
1656 }
1657
Thomas Graf86872cb2006-08-22 00:01:08 -07001658 if (cfg->fc_flags & RTF_GATEWAY) {
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001659 const struct in6_addr *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 int gwa_type;
1661
Thomas Graf86872cb2006-08-22 00:01:08 -07001662 gw_addr = &cfg->fc_gateway;
Florian Westphal48ed7b22015-05-21 00:25:41 +02001663
1664 /* if gw_addr is local we will fail to detect this in case
1665 * address is still TENTATIVE (DAD in progress). rt6_lookup()
1666 * will return already-added prefix route via interface that
1667 * prefix route was assigned to, which might be non-loopback.
1668 */
1669 err = -EINVAL;
1670 if (ipv6_chk_addr_and_flags(net, gw_addr, NULL, 0, 0))
1671 goto out;
1672
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001673 rt->rt6i_gateway = *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 gwa_type = ipv6_addr_type(gw_addr);
1675
1676 if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
1677 struct rt6_info *grt;
1678
1679 /* IPv6 strictly inhibits using not link-local
1680 addresses as nexthop address.
1681 Otherwise, router will not able to send redirects.
1682 It is very good, but in some (rare!) circumstances
1683 (SIT, PtP, NBMA NOARP links) it is handy to allow
1684 some exceptions. --ANK
1685 */
David S. Miller38308472011-12-03 18:02:47 -05001686 if (!(gwa_type & IPV6_ADDR_UNICAST))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 goto out;
1688
Daniel Lezcano55786892008-03-04 13:47:47 -08001689 grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
1691 err = -EHOSTUNREACH;
David S. Miller38308472011-12-03 18:02:47 -05001692 if (!grt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 goto out;
1694 if (dev) {
David S. Millerd1918542011-12-28 20:19:20 -05001695 if (dev != grt->dst.dev) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00001696 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 goto out;
1698 }
1699 } else {
David S. Millerd1918542011-12-28 20:19:20 -05001700 dev = grt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 idev = grt->rt6i_idev;
1702 dev_hold(dev);
1703 in6_dev_hold(grt->rt6i_idev);
1704 }
David S. Miller38308472011-12-03 18:02:47 -05001705 if (!(grt->rt6i_flags & RTF_GATEWAY))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 err = 0;
Amerigo Wang94e187c2012-10-29 00:13:19 +00001707 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708
1709 if (err)
1710 goto out;
1711 }
1712 err = -EINVAL;
David S. Miller38308472011-12-03 18:02:47 -05001713 if (!dev || (dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 goto out;
1715 }
1716
1717 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05001718 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 goto out;
1720
Daniel Walterc3968a82011-04-13 21:10:57 +00001721 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
1722 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
1723 err = -EINVAL;
1724 goto out;
1725 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001726 rt->rt6i_prefsrc.addr = cfg->fc_prefsrc;
Daniel Walterc3968a82011-04-13 21:10:57 +00001727 rt->rt6i_prefsrc.plen = 128;
1728 } else
1729 rt->rt6i_prefsrc.plen = 0;
1730
Thomas Graf86872cb2006-08-22 00:01:08 -07001731 rt->rt6i_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732
1733install_route:
Changli Gaod8d1f302010-06-10 23:31:35 -07001734 rt->dst.dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 rt->rt6i_idev = idev;
Thomas Grafc71099a2006-08-04 23:20:06 -07001736 rt->rt6i_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001737
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001738 cfg->fc_nlinfo.nl_net = dev_net(dev);
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001739
Florian Westphale715b6d2015-01-05 23:57:44 +01001740 err = ip6_convert_metrics(&mxc, cfg);
1741 if (err)
1742 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743
Florian Westphale715b6d2015-01-05 23:57:44 +01001744 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, &mxc);
1745
1746 kfree(mxc.mx);
1747 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748out:
1749 if (dev)
1750 dev_put(dev);
1751 if (idev)
1752 in6_dev_put(idev);
1753 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07001754 dst_free(&rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 return err;
1756}
1757
Thomas Graf86872cb2006-08-22 00:01:08 -07001758static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759{
1760 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07001761 struct fib6_table *table;
David S. Millerd1918542011-12-28 20:19:20 -05001762 struct net *net = dev_net(rt->dst.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763
Gao feng6825a262012-09-19 19:25:34 +00001764 if (rt == net->ipv6.ip6_null_entry) {
1765 err = -ENOENT;
1766 goto out;
1767 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07001768
Thomas Grafc71099a2006-08-04 23:20:06 -07001769 table = rt->rt6i_table;
1770 write_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07001771 err = fib6_del(rt, info);
Thomas Grafc71099a2006-08-04 23:20:06 -07001772 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773
Gao feng6825a262012-09-19 19:25:34 +00001774out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00001775 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 return err;
1777}
1778
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001779int ip6_del_rt(struct rt6_info *rt)
1780{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08001781 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -05001782 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08001783 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08001784 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001785}
1786
Thomas Graf86872cb2006-08-22 00:01:08 -07001787static int ip6_route_del(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788{
Thomas Grafc71099a2006-08-04 23:20:06 -07001789 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 struct fib6_node *fn;
1791 struct rt6_info *rt;
1792 int err = -ESRCH;
1793
Daniel Lezcano55786892008-03-04 13:47:47 -08001794 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001795 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001796 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797
Thomas Grafc71099a2006-08-04 23:20:06 -07001798 read_lock_bh(&table->tb6_lock);
1799
1800 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07001801 &cfg->fc_dst, cfg->fc_dst_len,
1802 &cfg->fc_src, cfg->fc_src_len);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001803
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 if (fn) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001805 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
Martin KaFai Lau1f56a012015-04-28 13:03:03 -07001806 if ((rt->rt6i_flags & RTF_CACHE) &&
1807 !(cfg->fc_flags & RTF_CACHE))
1808 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001809 if (cfg->fc_ifindex &&
David S. Millerd1918542011-12-28 20:19:20 -05001810 (!rt->dst.dev ||
1811 rt->dst.dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001813 if (cfg->fc_flags & RTF_GATEWAY &&
1814 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001816 if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07001818 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07001819 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820
Thomas Graf86872cb2006-08-22 00:01:08 -07001821 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 }
1823 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001824 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825
1826 return err;
1827}
1828
David S. Miller6700c272012-07-17 03:29:28 -07001829static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001830{
David S. Millere8599ff2012-07-11 23:43:53 -07001831 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001832 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07001833 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07001834 struct ndisc_options ndopts;
1835 struct inet6_dev *in6_dev;
1836 struct neighbour *neigh;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001837 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07001838 int optlen, on_link;
1839 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07001840
Simon Horman29a3cad2013-05-28 20:34:26 +00001841 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001842 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07001843
1844 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07001845 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001846 return;
1847 }
1848
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001849 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07001850
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001851 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07001852 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001853 return;
1854 }
1855
David S. Miller6e157b62012-07-12 00:05:02 -07001856 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001857 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07001858 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001859 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07001860 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07001861 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001862 return;
1863 }
1864
1865 in6_dev = __in6_dev_get(skb->dev);
1866 if (!in6_dev)
1867 return;
1868 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
1869 return;
1870
1871 /* RFC2461 8.1:
1872 * The IP source address of the Redirect MUST be the same as the current
1873 * first-hop router for the specified ICMP Destination Address.
1874 */
1875
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001876 if (!ndisc_parse_options(msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07001877 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
1878 return;
1879 }
David S. Miller6e157b62012-07-12 00:05:02 -07001880
1881 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07001882 if (ndopts.nd_opts_tgt_lladdr) {
1883 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
1884 skb->dev);
1885 if (!lladdr) {
1886 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
1887 return;
1888 }
1889 }
1890
David S. Miller6e157b62012-07-12 00:05:02 -07001891 rt = (struct rt6_info *) dst;
1892 if (rt == net->ipv6.ip6_null_entry) {
1893 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
1894 return;
1895 }
1896
1897 /* Redirect received -> path was valid.
1898 * Look, redirects are sent only in response to data packets,
1899 * so that this nexthop apparently is reachable. --ANK
1900 */
1901 dst_confirm(&rt->dst);
1902
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001903 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07001904 if (!neigh)
1905 return;
1906
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 /*
1908 * We have finally decided to accept it.
1909 */
1910
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001911 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1913 NEIGH_UPDATE_F_OVERRIDE|
1914 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1915 NEIGH_UPDATE_F_ISROUTER))
1916 );
1917
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001918 nrt = ip6_rt_copy(rt, &msg->dest);
David S. Miller38308472011-12-03 18:02:47 -05001919 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 goto out;
1921
1922 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
1923 if (on_link)
1924 nrt->rt6i_flags &= ~RTF_GATEWAY;
1925
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001926 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927
Thomas Graf40e22e82006-08-22 00:00:45 -07001928 if (ip6_ins_rt(nrt))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 goto out;
1930
Changli Gaod8d1f302010-06-10 23:31:35 -07001931 netevent.old = &rt->dst;
1932 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001933 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00001934 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07001935 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
1936
David S. Miller38308472011-12-03 18:02:47 -05001937 if (rt->rt6i_flags & RTF_CACHE) {
David S. Miller6e157b62012-07-12 00:05:02 -07001938 rt = (struct rt6_info *) dst_clone(&rt->dst);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001939 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 }
1941
1942out:
David S. Millere8599ff2012-07-11 23:43:53 -07001943 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07001944}
1945
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 * Misc support functions
1948 */
1949
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001950static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from)
1951{
1952 BUG_ON(from->dst.from);
1953
1954 rt->rt6i_flags &= ~RTF_EXPIRES;
1955 dst_hold(&from->dst);
1956 rt->dst.from = &from->dst;
1957 dst_init_metrics(&rt->dst, dst_metrics_ptr(&from->dst), true);
1958}
1959
Gao feng1716a962012-04-06 00:13:10 +00001960static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
Eric Dumazet21efcfa2011-07-19 20:18:36 +00001961 const struct in6_addr *dest)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962{
David S. Millerd1918542011-12-28 20:19:20 -05001963 struct net *net = dev_net(ort->dst.dev);
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001964 struct rt6_info *rt;
1965
1966 if (ort->rt6i_flags & RTF_CACHE)
1967 ort = (struct rt6_info *)ort->dst.from;
1968
1969 rt = ip6_dst_alloc(net, ort->dst.dev, 0,
1970 ort->rt6i_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971
1972 if (rt) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001973 rt->dst.input = ort->dst.input;
1974 rt->dst.output = ort->dst.output;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001975 rt->dst.flags |= DST_HOST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001977 rt->rt6i_dst.addr = *dest;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001978 rt->rt6i_dst.plen = 128;
Changli Gaod8d1f302010-06-10 23:31:35 -07001979 rt->dst.error = ort->dst.error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 rt->rt6i_idev = ort->rt6i_idev;
1981 if (rt->rt6i_idev)
1982 in6_dev_hold(rt->rt6i_idev);
Changli Gaod8d1f302010-06-10 23:31:35 -07001983 rt->dst.lastuse = jiffies;
Martin KaFai Lau2647a9b2015-05-22 20:55:58 -07001984 rt->rt6i_gateway = ort->rt6i_gateway;
Gao feng1716a962012-04-06 00:13:10 +00001985 rt->rt6i_flags = ort->rt6i_flags;
Li RongQing24f5b852013-12-19 12:40:26 +08001986 rt6_set_from(rt, ort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 rt->rt6i_metric = 0;
1988
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989#ifdef CONFIG_IPV6_SUBTREES
1990 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1991#endif
Florian Westphal0f6c6392011-05-20 11:27:24 +00001992 memcpy(&rt->rt6i_prefsrc, &ort->rt6i_prefsrc, sizeof(struct rt6key));
Thomas Grafc71099a2006-08-04 23:20:06 -07001993 rt->rt6i_table = ort->rt6i_table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 }
1995 return rt;
1996}
1997
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001998#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001999static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002000 const struct in6_addr *prefix, int prefixlen,
2001 const struct in6_addr *gwaddr, int ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002002{
2003 struct fib6_node *fn;
2004 struct rt6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07002005 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002006
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002007 table = fib6_get_table(net, RT6_TABLE_INFO);
David S. Miller38308472011-12-03 18:02:47 -05002008 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002009 return NULL;
2010
Li RongQing5744dd92012-09-11 21:59:01 +00002011 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01002012 fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002013 if (!fn)
2014 goto out;
2015
Changli Gaod8d1f302010-06-10 23:31:35 -07002016 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05002017 if (rt->dst.dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002018 continue;
2019 if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
2020 continue;
2021 if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
2022 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07002023 dst_hold(&rt->dst);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002024 break;
2025 }
2026out:
Li RongQing5744dd92012-09-11 21:59:01 +00002027 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002028 return rt;
2029}
2030
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002031static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002032 const struct in6_addr *prefix, int prefixlen,
2033 const struct in6_addr *gwaddr, int ifindex,
Eric Dumazet95c96172012-04-15 05:58:06 +00002034 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002035{
Thomas Graf86872cb2006-08-22 00:01:08 -07002036 struct fib6_config cfg = {
2037 .fc_table = RT6_TABLE_INFO,
Rami Rosen238fc7e2008-02-09 23:43:11 -08002038 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07002039 .fc_ifindex = ifindex,
2040 .fc_dst_len = prefixlen,
2041 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
2042 RTF_UP | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00002043 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002044 .fc_nlinfo.nlh = NULL,
2045 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07002046 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002047
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002048 cfg.fc_dst = *prefix;
2049 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07002050
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08002051 /* We should treat it as a default route if prefix length is 0. */
2052 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07002053 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002054
Thomas Graf86872cb2006-08-22 00:01:08 -07002055 ip6_route_add(&cfg);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002056
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002057 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002058}
2059#endif
2060
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002061struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002062{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07002064 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002066 table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05002067 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002068 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069
Li RongQing5744dd92012-09-11 21:59:01 +00002070 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01002071 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05002072 if (dev == rt->dst.dev &&
YOSHIFUJI Hideaki045927f2006-03-20 17:00:48 -08002073 ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 ipv6_addr_equal(&rt->rt6i_gateway, addr))
2075 break;
2076 }
2077 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07002078 dst_hold(&rt->dst);
Li RongQing5744dd92012-09-11 21:59:01 +00002079 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 return rt;
2081}
2082
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002083struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08002084 struct net_device *dev,
2085 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086{
Thomas Graf86872cb2006-08-22 00:01:08 -07002087 struct fib6_config cfg = {
2088 .fc_table = RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08002089 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07002090 .fc_ifindex = dev->ifindex,
2091 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
2092 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00002093 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08002094 .fc_nlinfo.nlh = NULL,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002095 .fc_nlinfo.nl_net = dev_net(dev),
Thomas Graf86872cb2006-08-22 00:01:08 -07002096 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002098 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099
Thomas Graf86872cb2006-08-22 00:01:08 -07002100 ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 return rt6_get_dflt_router(gwaddr, dev);
2103}
2104
Daniel Lezcano7b4da532008-03-04 13:47:14 -08002105void rt6_purge_dflt_routers(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106{
2107 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07002108 struct fib6_table *table;
2109
2110 /* NOTE: Keep consistent with rt6_get_dflt_router */
Daniel Lezcano7b4da532008-03-04 13:47:14 -08002111 table = fib6_get_table(net, RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05002112 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002113 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114
2115restart:
Thomas Grafc71099a2006-08-04 23:20:06 -07002116 read_lock_bh(&table->tb6_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07002117 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
Lorenzo Colitti3e8b0ac2013-03-03 20:46:46 +00002118 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
2119 (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002120 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07002121 read_unlock_bh(&table->tb6_lock);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002122 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 goto restart;
2124 }
2125 }
Thomas Grafc71099a2006-08-04 23:20:06 -07002126 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127}
2128
Daniel Lezcano55786892008-03-04 13:47:47 -08002129static void rtmsg_to_fib6_config(struct net *net,
2130 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07002131 struct fib6_config *cfg)
2132{
2133 memset(cfg, 0, sizeof(*cfg));
2134
2135 cfg->fc_table = RT6_TABLE_MAIN;
2136 cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
2137 cfg->fc_metric = rtmsg->rtmsg_metric;
2138 cfg->fc_expires = rtmsg->rtmsg_info;
2139 cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
2140 cfg->fc_src_len = rtmsg->rtmsg_src_len;
2141 cfg->fc_flags = rtmsg->rtmsg_flags;
2142
Daniel Lezcano55786892008-03-04 13:47:47 -08002143 cfg->fc_nlinfo.nl_net = net;
Benjamin Theryf1243c22008-02-26 18:10:03 -08002144
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002145 cfg->fc_dst = rtmsg->rtmsg_dst;
2146 cfg->fc_src = rtmsg->rtmsg_src;
2147 cfg->fc_gateway = rtmsg->rtmsg_gateway;
Thomas Graf86872cb2006-08-22 00:01:08 -07002148}
2149
Daniel Lezcano55786892008-03-04 13:47:47 -08002150int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151{
Thomas Graf86872cb2006-08-22 00:01:08 -07002152 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 struct in6_rtmsg rtmsg;
2154 int err;
2155
Ian Morris67ba4152014-08-24 21:53:10 +01002156 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 case SIOCADDRT: /* Add a route */
2158 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00002159 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 return -EPERM;
2161 err = copy_from_user(&rtmsg, arg,
2162 sizeof(struct in6_rtmsg));
2163 if (err)
2164 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07002165
Daniel Lezcano55786892008-03-04 13:47:47 -08002166 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07002167
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 rtnl_lock();
2169 switch (cmd) {
2170 case SIOCADDRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07002171 err = ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 break;
2173 case SIOCDELRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07002174 err = ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 break;
2176 default:
2177 err = -EINVAL;
2178 }
2179 rtnl_unlock();
2180
2181 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07002182 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183
2184 return -EINVAL;
2185}
2186
2187/*
2188 * Drop the packet on the floor
2189 */
2190
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07002191static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002193 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00002194 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002195 switch (ipstats_mib_noroutes) {
2196 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07002197 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00002198 if (type == IPV6_ADDR_ANY) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002199 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2200 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002201 break;
2202 }
2203 /* FALLTHROUGH */
2204 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002205 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2206 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002207 break;
2208 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002209 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 kfree_skb(skb);
2211 return 0;
2212}
2213
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002214static int ip6_pkt_discard(struct sk_buff *skb)
2215{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002216 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002217}
2218
Eric Dumazetaad88722014-04-15 13:47:15 -04002219static int ip6_pkt_discard_out(struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220{
Eric Dumazetadf30902009-06-02 05:19:30 +00002221 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002222 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223}
2224
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002225static int ip6_pkt_prohibit(struct sk_buff *skb)
2226{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002227 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002228}
2229
Eric Dumazetaad88722014-04-15 13:47:15 -04002230static int ip6_pkt_prohibit_out(struct sock *sk, struct sk_buff *skb)
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002231{
Eric Dumazetadf30902009-06-02 05:19:30 +00002232 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002233 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002234}
2235
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236/*
2237 * Allocate a dst for local (unicast / anycast) address.
2238 */
2239
2240struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
2241 const struct in6_addr *addr,
David S. Miller8f031512011-12-06 16:48:14 -05002242 bool anycast)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002244 struct net *net = dev_net(idev->dev);
Hannes Frederic Sowaa3300ef2013-12-07 03:33:45 +01002245 struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev,
2246 DST_NOCOUNT, NULL);
2247 if (!rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 return ERR_PTR(-ENOMEM);
2249
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 in6_dev_hold(idev);
2251
David S. Miller11d53b42011-06-24 15:23:34 -07002252 rt->dst.flags |= DST_HOST;
Changli Gaod8d1f302010-06-10 23:31:35 -07002253 rt->dst.input = ip6_input;
2254 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 rt->rt6i_idev = idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256
2257 rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +09002258 if (anycast)
2259 rt->rt6i_flags |= RTF_ANYCAST;
2260 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 rt->rt6i_flags |= RTF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262
Julian Anastasov550bab42013-10-20 15:43:04 +03002263 rt->rt6i_gateway = *addr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002264 rt->rt6i_dst.addr = *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 rt->rt6i_dst.plen = 128;
Daniel Lezcano55786892008-03-04 13:47:47 -08002266 rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267
Changli Gaod8d1f302010-06-10 23:31:35 -07002268 atomic_set(&rt->dst.__refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269
2270 return rt;
2271}
2272
Daniel Walterc3968a82011-04-13 21:10:57 +00002273int ip6_route_get_saddr(struct net *net,
2274 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002275 const struct in6_addr *daddr,
Daniel Walterc3968a82011-04-13 21:10:57 +00002276 unsigned int prefs,
2277 struct in6_addr *saddr)
2278{
Markus Stenberge16e8882015-05-05 13:36:59 +03002279 struct inet6_dev *idev =
2280 rt ? ip6_dst_idev((struct dst_entry *)rt) : NULL;
Daniel Walterc3968a82011-04-13 21:10:57 +00002281 int err = 0;
Markus Stenberge16e8882015-05-05 13:36:59 +03002282 if (rt && rt->rt6i_prefsrc.plen)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002283 *saddr = rt->rt6i_prefsrc.addr;
Daniel Walterc3968a82011-04-13 21:10:57 +00002284 else
2285 err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
2286 daddr, prefs, saddr);
2287 return err;
2288}
2289
2290/* remove deleted ip from prefsrc entries */
2291struct arg_dev_net_ip {
2292 struct net_device *dev;
2293 struct net *net;
2294 struct in6_addr *addr;
2295};
2296
2297static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
2298{
2299 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
2300 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
2301 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
2302
David S. Millerd1918542011-12-28 20:19:20 -05002303 if (((void *)rt->dst.dev == dev || !dev) &&
Daniel Walterc3968a82011-04-13 21:10:57 +00002304 rt != net->ipv6.ip6_null_entry &&
2305 ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
2306 /* remove prefsrc entry */
2307 rt->rt6i_prefsrc.plen = 0;
2308 }
2309 return 0;
2310}
2311
2312void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
2313{
2314 struct net *net = dev_net(ifp->idev->dev);
2315 struct arg_dev_net_ip adni = {
2316 .dev = ifp->idev->dev,
2317 .net = net,
2318 .addr = &ifp->addr,
2319 };
Li RongQing0c3584d2013-12-27 16:32:38 +08002320 fib6_clean_all(net, fib6_remove_prefsrc, &adni);
Daniel Walterc3968a82011-04-13 21:10:57 +00002321}
2322
Duan Jiongbe7a0102014-05-15 15:56:14 +08002323#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY)
2324#define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE)
2325
2326/* Remove routers and update dst entries when gateway turn into host. */
2327static int fib6_clean_tohost(struct rt6_info *rt, void *arg)
2328{
2329 struct in6_addr *gateway = (struct in6_addr *)arg;
2330
2331 if ((((rt->rt6i_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) ||
2332 ((rt->rt6i_flags & RTF_CACHE_GATEWAY) == RTF_CACHE_GATEWAY)) &&
2333 ipv6_addr_equal(gateway, &rt->rt6i_gateway)) {
2334 return -1;
2335 }
2336 return 0;
2337}
2338
2339void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
2340{
2341 fib6_clean_all(net, fib6_clean_tohost, gateway);
2342}
2343
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002344struct arg_dev_net {
2345 struct net_device *dev;
2346 struct net *net;
2347};
2348
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349static int fib6_ifdown(struct rt6_info *rt, void *arg)
2350{
stephen hemmingerbc3ef662010-12-16 17:42:40 +00002351 const struct arg_dev_net *adn = arg;
2352 const struct net_device *dev = adn->dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002353
David S. Millerd1918542011-12-28 20:19:20 -05002354 if ((rt->dst.dev == dev || !dev) &&
David S. Millerc159d302011-12-26 15:24:36 -05002355 rt != adn->net->ipv6.ip6_null_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 return -1;
David S. Millerc159d302011-12-26 15:24:36 -05002357
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 return 0;
2359}
2360
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002361void rt6_ifdown(struct net *net, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002363 struct arg_dev_net adn = {
2364 .dev = dev,
2365 .net = net,
2366 };
2367
Li RongQing0c3584d2013-12-27 16:32:38 +08002368 fib6_clean_all(net, fib6_ifdown, &adn);
David S. Miller1e493d12008-09-10 17:27:15 -07002369 icmp6_clean_all(fib6_ifdown, &adn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370}
2371
Eric Dumazet95c96172012-04-15 05:58:06 +00002372struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00002374 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375};
2376
2377static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
2378{
2379 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
2380 struct inet6_dev *idev;
2381
2382 /* In IPv6 pmtu discovery is not optional,
2383 so that RTAX_MTU lock cannot disable it.
2384 We still use this lock to block changes
2385 caused by addrconf/ndisc.
2386 */
2387
2388 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05002389 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 return 0;
2391
2392 /* For administrative MTU increase, there is no way to discover
2393 IPv6 PMTU increase, so PMTU increase should be updated here.
2394 Since RFC 1981 doesn't include administrative MTU increase
2395 update PMTU increase is a MUST. (i.e. jumbo frame)
2396 */
2397 /*
2398 If new MTU is less than route PMTU, this new MTU will be the
2399 lowest MTU in the path, update the route PMTU to reflect PMTU
2400 decreases; if new MTU is greater than route PMTU, and the
2401 old MTU is the lowest MTU in the path, update the route PMTU
2402 to reflect the increase. In this case if the other nodes' MTU
2403 also have the lowest MTU, TOO BIG MESSAGE will be lead to
2404 PMTU discouvery.
2405 */
David S. Millerd1918542011-12-28 20:19:20 -05002406 if (rt->dst.dev == arg->dev &&
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002407 !dst_metric_locked(&rt->dst, RTAX_MTU)) {
2408 if (rt->rt6i_flags & RTF_CACHE) {
2409 /* For RTF_CACHE with rt6i_pmtu == 0
2410 * (i.e. a redirected route),
2411 * the metrics of its rt->dst.from has already
2412 * been updated.
2413 */
2414 if (rt->rt6i_pmtu && rt->rt6i_pmtu > arg->mtu)
2415 rt->rt6i_pmtu = arg->mtu;
2416 } else if (dst_mtu(&rt->dst) >= arg->mtu ||
2417 (dst_mtu(&rt->dst) < arg->mtu &&
2418 dst_mtu(&rt->dst) == idev->cnf.mtu6)) {
2419 dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu);
2420 }
Simon Arlott566cfd82007-07-26 00:09:55 -07002421 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 return 0;
2423}
2424
Eric Dumazet95c96172012-04-15 05:58:06 +00002425void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426{
Thomas Grafc71099a2006-08-04 23:20:06 -07002427 struct rt6_mtu_change_arg arg = {
2428 .dev = dev,
2429 .mtu = mtu,
2430 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431
Li RongQing0c3584d2013-12-27 16:32:38 +08002432 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433}
2434
Patrick McHardyef7c79e2007-06-05 12:38:30 -07002435static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07002436 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07002437 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07002438 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002439 [RTA_PRIORITY] = { .type = NLA_U32 },
2440 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002441 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002442 [RTA_PREF] = { .type = NLA_U8 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002443};
2444
2445static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
2446 struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447{
Thomas Graf86872cb2006-08-22 00:01:08 -07002448 struct rtmsg *rtm;
2449 struct nlattr *tb[RTA_MAX+1];
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002450 unsigned int pref;
Thomas Graf86872cb2006-08-22 00:01:08 -07002451 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452
Thomas Graf86872cb2006-08-22 00:01:08 -07002453 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2454 if (err < 0)
2455 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456
Thomas Graf86872cb2006-08-22 00:01:08 -07002457 err = -EINVAL;
2458 rtm = nlmsg_data(nlh);
2459 memset(cfg, 0, sizeof(*cfg));
2460
2461 cfg->fc_table = rtm->rtm_table;
2462 cfg->fc_dst_len = rtm->rtm_dst_len;
2463 cfg->fc_src_len = rtm->rtm_src_len;
2464 cfg->fc_flags = RTF_UP;
2465 cfg->fc_protocol = rtm->rtm_protocol;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002466 cfg->fc_type = rtm->rtm_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07002467
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002468 if (rtm->rtm_type == RTN_UNREACHABLE ||
2469 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002470 rtm->rtm_type == RTN_PROHIBIT ||
2471 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07002472 cfg->fc_flags |= RTF_REJECT;
2473
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002474 if (rtm->rtm_type == RTN_LOCAL)
2475 cfg->fc_flags |= RTF_LOCAL;
2476
Martin KaFai Lau1f56a012015-04-28 13:03:03 -07002477 if (rtm->rtm_flags & RTM_F_CLONED)
2478 cfg->fc_flags |= RTF_CACHE;
2479
Eric W. Biederman15e47302012-09-07 20:12:54 +00002480 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
Thomas Graf86872cb2006-08-22 00:01:08 -07002481 cfg->fc_nlinfo.nlh = nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002482 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
Thomas Graf86872cb2006-08-22 00:01:08 -07002483
2484 if (tb[RTA_GATEWAY]) {
Jiri Benc67b61f62015-03-29 16:59:26 +02002485 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
Thomas Graf86872cb2006-08-22 00:01:08 -07002486 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002488
2489 if (tb[RTA_DST]) {
2490 int plen = (rtm->rtm_dst_len + 7) >> 3;
2491
2492 if (nla_len(tb[RTA_DST]) < plen)
2493 goto errout;
2494
2495 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002497
2498 if (tb[RTA_SRC]) {
2499 int plen = (rtm->rtm_src_len + 7) >> 3;
2500
2501 if (nla_len(tb[RTA_SRC]) < plen)
2502 goto errout;
2503
2504 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002506
Daniel Walterc3968a82011-04-13 21:10:57 +00002507 if (tb[RTA_PREFSRC])
Jiri Benc67b61f62015-03-29 16:59:26 +02002508 cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]);
Daniel Walterc3968a82011-04-13 21:10:57 +00002509
Thomas Graf86872cb2006-08-22 00:01:08 -07002510 if (tb[RTA_OIF])
2511 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
2512
2513 if (tb[RTA_PRIORITY])
2514 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
2515
2516 if (tb[RTA_METRICS]) {
2517 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
2518 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002520
2521 if (tb[RTA_TABLE])
2522 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
2523
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002524 if (tb[RTA_MULTIPATH]) {
2525 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
2526 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
2527 }
2528
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002529 if (tb[RTA_PREF]) {
2530 pref = nla_get_u8(tb[RTA_PREF]);
2531 if (pref != ICMPV6_ROUTER_PREF_LOW &&
2532 pref != ICMPV6_ROUTER_PREF_HIGH)
2533 pref = ICMPV6_ROUTER_PREF_MEDIUM;
2534 cfg->fc_flags |= RTF_PREF(pref);
2535 }
2536
Thomas Graf86872cb2006-08-22 00:01:08 -07002537 err = 0;
2538errout:
2539 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540}
2541
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002542static int ip6_route_multipath(struct fib6_config *cfg, int add)
2543{
2544 struct fib6_config r_cfg;
2545 struct rtnexthop *rtnh;
2546 int remaining;
2547 int attrlen;
2548 int err = 0, last_err = 0;
2549
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02002550 remaining = cfg->fc_mp_len;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002551beginning:
2552 rtnh = (struct rtnexthop *)cfg->fc_mp;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002553
2554 /* Parse a Multipath Entry */
2555 while (rtnh_ok(rtnh, remaining)) {
2556 memcpy(&r_cfg, cfg, sizeof(*cfg));
2557 if (rtnh->rtnh_ifindex)
2558 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
2559
2560 attrlen = rtnh_attrlen(rtnh);
2561 if (attrlen > 0) {
2562 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
2563
2564 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
2565 if (nla) {
Jiri Benc67b61f62015-03-29 16:59:26 +02002566 r_cfg.fc_gateway = nla_get_in6_addr(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002567 r_cfg.fc_flags |= RTF_GATEWAY;
2568 }
2569 }
2570 err = add ? ip6_route_add(&r_cfg) : ip6_route_del(&r_cfg);
2571 if (err) {
2572 last_err = err;
2573 /* If we are trying to remove a route, do not stop the
2574 * loop when ip6_route_del() fails (because next hop is
2575 * already gone), we should try to remove all next hops.
2576 */
2577 if (add) {
2578 /* If add fails, we should try to delete all
2579 * next hops that have been already added.
2580 */
2581 add = 0;
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02002582 remaining = cfg->fc_mp_len - remaining;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002583 goto beginning;
2584 }
2585 }
Nicolas Dichtel1a724182012-11-01 22:58:22 +00002586 /* Because each route is added like a single route we remove
Michal Kubeček27596472015-05-18 20:54:00 +02002587 * these flags after the first nexthop: if there is a collision,
2588 * we have already failed to add the first nexthop:
2589 * fib6_add_rt2node() has rejected it; when replacing, old
2590 * nexthops have been replaced by first new, the rest should
2591 * be added to it.
Nicolas Dichtel1a724182012-11-01 22:58:22 +00002592 */
Michal Kubeček27596472015-05-18 20:54:00 +02002593 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
2594 NLM_F_REPLACE);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002595 rtnh = rtnh_next(rtnh, &remaining);
2596 }
2597
2598 return last_err;
2599}
2600
Ian Morris67ba4152014-08-24 21:53:10 +01002601static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602{
Thomas Graf86872cb2006-08-22 00:01:08 -07002603 struct fib6_config cfg;
2604 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605
Thomas Graf86872cb2006-08-22 00:01:08 -07002606 err = rtm_to_fib6_config(skb, nlh, &cfg);
2607 if (err < 0)
2608 return err;
2609
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002610 if (cfg.fc_mp)
2611 return ip6_route_multipath(&cfg, 0);
2612 else
2613 return ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614}
2615
Ian Morris67ba4152014-08-24 21:53:10 +01002616static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617{
Thomas Graf86872cb2006-08-22 00:01:08 -07002618 struct fib6_config cfg;
2619 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620
Thomas Graf86872cb2006-08-22 00:01:08 -07002621 err = rtm_to_fib6_config(skb, nlh, &cfg);
2622 if (err < 0)
2623 return err;
2624
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002625 if (cfg.fc_mp)
2626 return ip6_route_multipath(&cfg, 1);
2627 else
2628 return ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629}
2630
Thomas Graf339bf982006-11-10 14:10:15 -08002631static inline size_t rt6_nlmsg_size(void)
2632{
2633 return NLMSG_ALIGN(sizeof(struct rtmsg))
2634 + nla_total_size(16) /* RTA_SRC */
2635 + nla_total_size(16) /* RTA_DST */
2636 + nla_total_size(16) /* RTA_GATEWAY */
2637 + nla_total_size(16) /* RTA_PREFSRC */
2638 + nla_total_size(4) /* RTA_TABLE */
2639 + nla_total_size(4) /* RTA_IIF */
2640 + nla_total_size(4) /* RTA_OIF */
2641 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08002642 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Daniel Borkmannea697632015-01-05 23:57:47 +01002643 + nla_total_size(sizeof(struct rta_cacheinfo))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002644 + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
2645 + nla_total_size(1); /* RTA_PREF */
Thomas Graf339bf982006-11-10 14:10:15 -08002646}
2647
Brian Haley191cd582008-08-14 15:33:21 -07002648static int rt6_fill_node(struct net *net,
2649 struct sk_buff *skb, struct rt6_info *rt,
Jamal Hadi Salim0d51aa82005-06-21 13:51:04 -07002650 struct in6_addr *dst, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002651 int iif, int type, u32 portid, u32 seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002652 int prefix, int nowait, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002654 u32 metrics[RTAX_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 struct rtmsg *rtm;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002656 struct nlmsghdr *nlh;
Thomas Grafe3703b32006-11-27 09:27:07 -08002657 long expires;
Patrick McHardy9e762a42006-08-10 23:09:48 -07002658 u32 table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659
2660 if (prefix) { /* user wants prefix routes only */
2661 if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
2662 /* success since this is not a prefix route */
2663 return 1;
2664 }
2665 }
2666
Eric W. Biederman15e47302012-09-07 20:12:54 +00002667 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05002668 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08002669 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002670
2671 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 rtm->rtm_family = AF_INET6;
2673 rtm->rtm_dst_len = rt->rt6i_dst.plen;
2674 rtm->rtm_src_len = rt->rt6i_src.plen;
2675 rtm->rtm_tos = 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07002676 if (rt->rt6i_table)
Patrick McHardy9e762a42006-08-10 23:09:48 -07002677 table = rt->rt6i_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07002678 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07002679 table = RT6_TABLE_UNSPEC;
2680 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04002681 if (nla_put_u32(skb, RTA_TABLE, table))
2682 goto nla_put_failure;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002683 if (rt->rt6i_flags & RTF_REJECT) {
2684 switch (rt->dst.error) {
2685 case -EINVAL:
2686 rtm->rtm_type = RTN_BLACKHOLE;
2687 break;
2688 case -EACCES:
2689 rtm->rtm_type = RTN_PROHIBIT;
2690 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002691 case -EAGAIN:
2692 rtm->rtm_type = RTN_THROW;
2693 break;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002694 default:
2695 rtm->rtm_type = RTN_UNREACHABLE;
2696 break;
2697 }
2698 }
David S. Miller38308472011-12-03 18:02:47 -05002699 else if (rt->rt6i_flags & RTF_LOCAL)
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002700 rtm->rtm_type = RTN_LOCAL;
David S. Millerd1918542011-12-28 20:19:20 -05002701 else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 rtm->rtm_type = RTN_LOCAL;
2703 else
2704 rtm->rtm_type = RTN_UNICAST;
2705 rtm->rtm_flags = 0;
2706 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
2707 rtm->rtm_protocol = rt->rt6i_protocol;
David S. Miller38308472011-12-03 18:02:47 -05002708 if (rt->rt6i_flags & RTF_DYNAMIC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 rtm->rtm_protocol = RTPROT_REDIRECT;
Denis Ovsienkof0396f602012-07-10 04:45:50 +00002710 else if (rt->rt6i_flags & RTF_ADDRCONF) {
2711 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ROUTEINFO))
2712 rtm->rtm_protocol = RTPROT_RA;
2713 else
2714 rtm->rtm_protocol = RTPROT_KERNEL;
2715 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716
David S. Miller38308472011-12-03 18:02:47 -05002717 if (rt->rt6i_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 rtm->rtm_flags |= RTM_F_CLONED;
2719
2720 if (dst) {
Jiri Benc930345e2015-03-29 16:59:25 +02002721 if (nla_put_in6_addr(skb, RTA_DST, dst))
David S. Millerc78679e2012-04-01 20:27:33 -04002722 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002723 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 } else if (rtm->rtm_dst_len)
Jiri Benc930345e2015-03-29 16:59:25 +02002725 if (nla_put_in6_addr(skb, RTA_DST, &rt->rt6i_dst.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04002726 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727#ifdef CONFIG_IPV6_SUBTREES
2728 if (src) {
Jiri Benc930345e2015-03-29 16:59:25 +02002729 if (nla_put_in6_addr(skb, RTA_SRC, src))
David S. Millerc78679e2012-04-01 20:27:33 -04002730 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002731 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04002732 } else if (rtm->rtm_src_len &&
Jiri Benc930345e2015-03-29 16:59:25 +02002733 nla_put_in6_addr(skb, RTA_SRC, &rt->rt6i_src.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04002734 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002736 if (iif) {
2737#ifdef CONFIG_IPV6_MROUTE
2738 if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
Benjamin Thery8229efd2008-12-10 16:30:15 -08002739 int err = ip6mr_get_route(net, skb, rtm, nowait);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002740 if (err <= 0) {
2741 if (!nowait) {
2742 if (err == 0)
2743 return 0;
2744 goto nla_put_failure;
2745 } else {
2746 if (err == -EMSGSIZE)
2747 goto nla_put_failure;
2748 }
2749 }
2750 } else
2751#endif
David S. Millerc78679e2012-04-01 20:27:33 -04002752 if (nla_put_u32(skb, RTA_IIF, iif))
2753 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002754 } else if (dst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 struct in6_addr saddr_buf;
David S. Millerc78679e2012-04-01 20:27:33 -04002756 if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0 &&
Jiri Benc930345e2015-03-29 16:59:25 +02002757 nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04002758 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07002760
Daniel Walterc3968a82011-04-13 21:10:57 +00002761 if (rt->rt6i_prefsrc.plen) {
2762 struct in6_addr saddr_buf;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002763 saddr_buf = rt->rt6i_prefsrc.addr;
Jiri Benc930345e2015-03-29 16:59:25 +02002764 if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04002765 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00002766 }
2767
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002768 memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics));
2769 if (rt->rt6i_pmtu)
2770 metrics[RTAX_MTU - 1] = rt->rt6i_pmtu;
2771 if (rtnetlink_put_metrics(skb, metrics) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07002772 goto nla_put_failure;
2773
YOSHIFUJI Hideaki / 吉藤英明dd0cbf22013-01-17 12:53:15 +00002774 if (rt->rt6i_flags & RTF_GATEWAY) {
Jiri Benc930345e2015-03-29 16:59:25 +02002775 if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->rt6i_gateway) < 0)
Eric Dumazet94f826b2012-03-27 09:53:52 +00002776 goto nla_put_failure;
Eric Dumazet94f826b2012-03-27 09:53:52 +00002777 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07002778
David S. Millerc78679e2012-04-01 20:27:33 -04002779 if (rt->dst.dev &&
2780 nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex))
2781 goto nla_put_failure;
2782 if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric))
2783 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00002784
2785 expires = (rt->rt6i_flags & RTF_EXPIRES) ? rt->dst.expires - jiffies : 0;
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07002786
David S. Miller87a50692012-07-10 05:06:14 -07002787 if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, rt->dst.error) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08002788 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002790 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags)))
2791 goto nla_put_failure;
2792
Johannes Berg053c0952015-01-16 22:09:00 +01002793 nlmsg_end(skb, nlh);
2794 return 0;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002795
2796nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002797 nlmsg_cancel(skb, nlh);
2798 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799}
2800
Patrick McHardy1b43af52006-08-10 23:11:17 -07002801int rt6_dump_route(struct rt6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802{
2803 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
2804 int prefix;
2805
Thomas Graf2d7202b2006-08-22 00:01:27 -07002806 if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
2807 struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0;
2809 } else
2810 prefix = 0;
2811
Brian Haley191cd582008-08-14 15:33:21 -07002812 return rt6_fill_node(arg->net,
2813 arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002814 NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002815 prefix, 0, NLM_F_MULTI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816}
2817
Ian Morris67ba4152014-08-24 21:53:10 +01002818static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002820 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07002821 struct nlattr *tb[RTA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07002823 struct sk_buff *skb;
2824 struct rtmsg *rtm;
David S. Miller4c9483b2011-03-12 16:22:43 -05002825 struct flowi6 fl6;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002826 int err, iif = 0, oif = 0;
Thomas Grafab364a62006-08-22 00:01:47 -07002827
2828 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2829 if (err < 0)
2830 goto errout;
2831
2832 err = -EINVAL;
David S. Miller4c9483b2011-03-12 16:22:43 -05002833 memset(&fl6, 0, sizeof(fl6));
Thomas Grafab364a62006-08-22 00:01:47 -07002834
2835 if (tb[RTA_SRC]) {
2836 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
2837 goto errout;
2838
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002839 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07002840 }
2841
2842 if (tb[RTA_DST]) {
2843 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
2844 goto errout;
2845
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002846 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07002847 }
2848
2849 if (tb[RTA_IIF])
2850 iif = nla_get_u32(tb[RTA_IIF]);
2851
2852 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002853 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07002854
Lorenzo Colitti2e47b292014-05-15 16:38:41 -07002855 if (tb[RTA_MARK])
2856 fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
2857
Thomas Grafab364a62006-08-22 00:01:47 -07002858 if (iif) {
2859 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002860 int flags = 0;
2861
Daniel Lezcano55786892008-03-04 13:47:47 -08002862 dev = __dev_get_by_index(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07002863 if (!dev) {
2864 err = -ENODEV;
2865 goto errout;
2866 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002867
2868 fl6.flowi6_iif = iif;
2869
2870 if (!ipv6_addr_any(&fl6.saddr))
2871 flags |= RT6_LOOKUP_F_HAS_SADDR;
2872
2873 rt = (struct rt6_info *)ip6_route_input_lookup(net, dev, &fl6,
2874 flags);
2875 } else {
2876 fl6.flowi6_oif = oif;
2877
2878 rt = (struct rt6_info *)ip6_route_output(net, NULL, &fl6);
Thomas Grafab364a62006-08-22 00:01:47 -07002879 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880
2881 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05002882 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00002883 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07002884 err = -ENOBUFS;
2885 goto errout;
2886 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887
2888 /* Reserve room for dummy headers, this skb can pass
2889 through good chunk of routing engine.
2890 */
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07002891 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
2893
Changli Gaod8d1f302010-06-10 23:31:35 -07002894 skb_dst_set(skb, &rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895
David S. Miller4c9483b2011-03-12 16:22:43 -05002896 err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002897 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002898 nlh->nlmsg_seq, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07002900 kfree_skb(skb);
2901 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 }
2903
Eric W. Biederman15e47302012-09-07 20:12:54 +00002904 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07002905errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907}
2908
Thomas Graf86872cb2006-08-22 00:01:08 -07002909void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910{
2911 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08002912 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002913 u32 seq;
2914 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002916 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05002917 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07002918
Thomas Graf339bf982006-11-10 14:10:15 -08002919 skb = nlmsg_new(rt6_nlmsg_size(), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05002920 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07002921 goto errout;
2922
Brian Haley191cd582008-08-14 15:33:21 -07002923 err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002924 event, info->portid, seq, 0, 0, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08002925 if (err < 0) {
2926 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
2927 WARN_ON(err == -EMSGSIZE);
2928 kfree_skb(skb);
2929 goto errout;
2930 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00002931 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08002932 info->nlh, gfp_any());
2933 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07002934errout:
2935 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08002936 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937}
2938
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002939static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00002940 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002941{
Jiri Pirko351638e2013-05-28 01:30:21 +00002942 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002943 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002944
2945 if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002946 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002947 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
2948#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07002949 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002950 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07002951 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002952 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
2953#endif
2954 }
2955
2956 return NOTIFY_OK;
2957}
2958
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959/*
2960 * /proc
2961 */
2962
2963#ifdef CONFIG_PROC_FS
2964
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002965static const struct file_operations ipv6_route_proc_fops = {
2966 .owner = THIS_MODULE,
2967 .open = ipv6_route_open,
2968 .read = seq_read,
2969 .llseek = seq_lseek,
Hannes Frederic Sowa8d2ca1d2013-09-21 16:55:59 +02002970 .release = seq_release_net,
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002971};
2972
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973static int rt6_stats_seq_show(struct seq_file *seq, void *v)
2974{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002975 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002977 net->ipv6.rt6_stats->fib_nodes,
2978 net->ipv6.rt6_stats->fib_route_nodes,
2979 net->ipv6.rt6_stats->fib_rt_alloc,
2980 net->ipv6.rt6_stats->fib_rt_entries,
2981 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00002982 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002983 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984
2985 return 0;
2986}
2987
2988static int rt6_stats_seq_open(struct inode *inode, struct file *file)
2989{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07002990 return single_open_net(inode, file, rt6_stats_seq_show);
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002991}
2992
Arjan van de Ven9a321442007-02-12 00:55:35 -08002993static const struct file_operations rt6_stats_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 .owner = THIS_MODULE,
2995 .open = rt6_stats_seq_open,
2996 .read = seq_read,
2997 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07002998 .release = single_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999};
3000#endif /* CONFIG_PROC_FS */
3001
3002#ifdef CONFIG_SYSCTL
3003
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004static
Joe Perchesfe2c6332013-06-11 23:04:25 -07003005int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 void __user *buffer, size_t *lenp, loff_t *ppos)
3007{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003008 struct net *net;
3009 int delay;
3010 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003012
3013 net = (struct net *)ctl->extra1;
3014 delay = net->ipv6.sysctl.flush_delay;
3015 proc_dointvec(ctl, write, buffer, lenp, ppos);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02003016 fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003017 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018}
3019
Joe Perchesfe2c6332013-06-11 23:04:25 -07003020struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003021 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08003023 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07003025 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003026 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 },
3028 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003030 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 .maxlen = sizeof(int),
3032 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003033 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 },
3035 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08003037 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 .maxlen = sizeof(int),
3039 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003040 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 },
3042 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08003044 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 .maxlen = sizeof(int),
3046 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003047 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 },
3049 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08003051 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 .maxlen = sizeof(int),
3053 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003054 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 },
3056 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08003058 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 .maxlen = sizeof(int),
3060 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003061 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 },
3063 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08003065 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 .maxlen = sizeof(int),
3067 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003068 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 },
3070 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08003072 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 .maxlen = sizeof(int),
3074 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003075 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 },
3077 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08003079 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 .maxlen = sizeof(int),
3081 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003082 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083 },
3084 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08003086 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 .maxlen = sizeof(int),
3088 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003089 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08003091 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092};
3093
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003094struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003095{
3096 struct ctl_table *table;
3097
3098 table = kmemdup(ipv6_route_table_template,
3099 sizeof(ipv6_route_table_template),
3100 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003101
3102 if (table) {
3103 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003104 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003105 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003106 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
3107 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
3108 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
3109 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
3110 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
3111 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
3112 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08003113 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
Eric W. Biederman464dc802012-11-16 03:02:59 +00003114
3115 /* Don't export sysctls to unprivileged users */
3116 if (net->user_ns != &init_user_ns)
3117 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003118 }
3119
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003120 return table;
3121}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122#endif
3123
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003124static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003125{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07003126 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003127
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003128 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
3129 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003130
Eric Dumazetfc66f952010-10-08 06:37:34 +00003131 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
3132 goto out_ip6_dst_ops;
3133
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003134 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
3135 sizeof(*net->ipv6.ip6_null_entry),
3136 GFP_KERNEL);
3137 if (!net->ipv6.ip6_null_entry)
Eric Dumazetfc66f952010-10-08 06:37:34 +00003138 goto out_ip6_dst_entries;
Changli Gaod8d1f302010-06-10 23:31:35 -07003139 net->ipv6.ip6_null_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003140 (struct dst_entry *)net->ipv6.ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003141 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003142 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
3143 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003144
3145#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3146 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
3147 sizeof(*net->ipv6.ip6_prohibit_entry),
3148 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003149 if (!net->ipv6.ip6_prohibit_entry)
3150 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003151 net->ipv6.ip6_prohibit_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003152 (struct dst_entry *)net->ipv6.ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003153 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003154 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
3155 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003156
3157 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
3158 sizeof(*net->ipv6.ip6_blk_hole_entry),
3159 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003160 if (!net->ipv6.ip6_blk_hole_entry)
3161 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003162 net->ipv6.ip6_blk_hole_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003163 (struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003164 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003165 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
3166 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003167#endif
3168
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07003169 net->ipv6.sysctl.flush_delay = 0;
3170 net->ipv6.sysctl.ip6_rt_max_size = 4096;
3171 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
3172 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
3173 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
3174 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
3175 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
3176 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
3177
Benjamin Thery6891a342008-03-04 13:49:47 -08003178 net->ipv6.ip6_rt_gc_expire = 30*HZ;
3179
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003180 ret = 0;
3181out:
3182 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003183
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003184#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3185out_ip6_prohibit_entry:
3186 kfree(net->ipv6.ip6_prohibit_entry);
3187out_ip6_null_entry:
3188 kfree(net->ipv6.ip6_null_entry);
3189#endif
Eric Dumazetfc66f952010-10-08 06:37:34 +00003190out_ip6_dst_entries:
3191 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003192out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003193 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003194}
3195
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003196static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003197{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003198 kfree(net->ipv6.ip6_null_entry);
3199#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3200 kfree(net->ipv6.ip6_prohibit_entry);
3201 kfree(net->ipv6.ip6_blk_hole_entry);
3202#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003203 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003204}
3205
Thomas Grafd1896342012-06-18 12:08:33 +00003206static int __net_init ip6_route_net_init_late(struct net *net)
3207{
3208#ifdef CONFIG_PROC_FS
Gao fengd4beaa62013-02-18 01:34:54 +00003209 proc_create("ipv6_route", 0, net->proc_net, &ipv6_route_proc_fops);
3210 proc_create("rt6_stats", S_IRUGO, net->proc_net, &rt6_stats_seq_fops);
Thomas Grafd1896342012-06-18 12:08:33 +00003211#endif
3212 return 0;
3213}
3214
3215static void __net_exit ip6_route_net_exit_late(struct net *net)
3216{
3217#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00003218 remove_proc_entry("ipv6_route", net->proc_net);
3219 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00003220#endif
3221}
3222
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003223static struct pernet_operations ip6_route_net_ops = {
3224 .init = ip6_route_net_init,
3225 .exit = ip6_route_net_exit,
3226};
3227
David S. Millerc3426b42012-06-09 16:27:05 -07003228static int __net_init ipv6_inetpeer_init(struct net *net)
3229{
3230 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
3231
3232 if (!bp)
3233 return -ENOMEM;
3234 inet_peer_base_init(bp);
3235 net->ipv6.peers = bp;
3236 return 0;
3237}
3238
3239static void __net_exit ipv6_inetpeer_exit(struct net *net)
3240{
3241 struct inet_peer_base *bp = net->ipv6.peers;
3242
3243 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07003244 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07003245 kfree(bp);
3246}
3247
David S. Miller2b823f72012-06-09 19:00:16 -07003248static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07003249 .init = ipv6_inetpeer_init,
3250 .exit = ipv6_inetpeer_exit,
3251};
3252
Thomas Grafd1896342012-06-18 12:08:33 +00003253static struct pernet_operations ip6_route_net_late_ops = {
3254 .init = ip6_route_net_init_late,
3255 .exit = ip6_route_net_exit_late,
3256};
3257
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003258static struct notifier_block ip6_route_dev_notifier = {
3259 .notifier_call = ip6_route_dev_notify,
3260 .priority = 0,
3261};
3262
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003263int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003265 int ret;
3266
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003267 ret = -ENOMEM;
3268 ip6_dst_ops_template.kmem_cachep =
3269 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
3270 SLAB_HWCACHE_ALIGN, NULL);
3271 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08003272 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07003273
Eric Dumazetfc66f952010-10-08 06:37:34 +00003274 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003275 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003276 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003277
David S. Millerc3426b42012-06-09 16:27:05 -07003278 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
3279 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003280 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00003281
David S. Miller7e52b332012-06-15 15:51:55 -07003282 ret = register_pernet_subsys(&ip6_route_net_ops);
3283 if (ret)
3284 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07003285
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07003286 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
3287
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003288 /* Registering of the loopback is done before this portion of code,
3289 * the loopback reference in rt6_info will not be taken, do it
3290 * manually for init_net */
Changli Gaod8d1f302010-06-10 23:31:35 -07003291 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003292 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3293 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07003294 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003295 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07003296 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003297 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3298 #endif
David S. Millere8803b62012-06-16 01:12:19 -07003299 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003300 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003301 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003302
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003303 ret = xfrm6_init();
3304 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003305 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08003306
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003307 ret = fib6_rules_init();
3308 if (ret)
3309 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08003310
Thomas Grafd1896342012-06-18 12:08:33 +00003311 ret = register_pernet_subsys(&ip6_route_net_late_ops);
3312 if (ret)
3313 goto fib6_rules_init;
3314
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003315 ret = -ENOBUFS;
Greg Rosec7ac8672011-06-10 01:27:09 +00003316 if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) ||
3317 __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) ||
3318 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL))
Thomas Grafd1896342012-06-18 12:08:33 +00003319 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003320
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003321 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003322 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00003323 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003324
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003325out:
3326 return ret;
3327
Thomas Grafd1896342012-06-18 12:08:33 +00003328out_register_late_subsys:
3329 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003330fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003331 fib6_rules_cleanup();
3332xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003333 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00003334out_fib6_init:
3335 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003336out_register_subsys:
3337 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07003338out_register_inetpeer:
3339 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00003340out_dst_entries:
3341 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003342out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003343 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003344 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345}
3346
3347void ip6_route_cleanup(void)
3348{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003349 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00003350 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07003351 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07003354 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003355 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003356 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003357 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358}