blob: e7ae2430dfed805985e9390069b64c093a486cbb [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
Changli Gaod8d1f302010-06-10 23:31:35 -0700904 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -0700905 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -0800906
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700907 rt6_dst_from_metrics_check(rt);
Changli Gaod8d1f302010-06-10 23:31:35 -0700908 rt->dst.lastuse = jiffies;
909 rt->dst.__use++;
Thomas Grafc71099a2006-08-04 23:20:06 -0700910
911 return rt;
912}
913
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800914static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500915 struct flowi6 *fl6, int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -0700916{
David S. Miller4c9483b2011-03-12 16:22:43 -0500917 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -0700918}
919
Shmulik Ladkani72331bc2012-04-01 04:03:45 +0000920static struct dst_entry *ip6_route_input_lookup(struct net *net,
921 struct net_device *dev,
922 struct flowi6 *fl6, int flags)
923{
924 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
925 flags |= RT6_LOOKUP_F_IFACE;
926
927 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_input);
928}
929
Thomas Grafc71099a2006-08-04 23:20:06 -0700930void ip6_route_input(struct sk_buff *skb)
931{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000932 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900933 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -0700934 int flags = RT6_LOOKUP_F_HAS_SADDR;
David S. Miller4c9483b2011-03-12 16:22:43 -0500935 struct flowi6 fl6 = {
936 .flowi6_iif = skb->dev->ifindex,
937 .daddr = iph->daddr,
938 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +0000939 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -0500940 .flowi6_mark = skb->mark,
941 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700942 };
Thomas Grafadaa70b2006-10-13 15:01:03 -0700943
Shmulik Ladkani72331bc2012-04-01 04:03:45 +0000944 skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -0700945}
946
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800947static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500948 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -0700949{
David S. Miller4c9483b2011-03-12 16:22:43 -0500950 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -0700951}
952
Ian Morris67ba4152014-08-24 21:53:10 +0100953struct dst_entry *ip6_route_output(struct net *net, const struct sock *sk,
David S. Miller4c9483b2011-03-12 16:22:43 -0500954 struct flowi6 *fl6)
Thomas Grafc71099a2006-08-04 23:20:06 -0700955{
956 int flags = 0;
957
Pavel Emelyanov1fb94892012-08-08 21:53:36 +0000958 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +0000959
David S. Miller4c9483b2011-03-12 16:22:43 -0500960 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700961 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -0700962
David S. Miller4c9483b2011-03-12 16:22:43 -0500963 if (!ipv6_addr_any(&fl6->saddr))
Thomas Grafadaa70b2006-10-13 15:01:03 -0700964 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +0000965 else if (sk)
966 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -0700967
David S. Miller4c9483b2011-03-12 16:22:43 -0500968 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900970EXPORT_SYMBOL(ip6_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
David S. Miller2774c132011-03-01 14:59:04 -0800972struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -0700973{
David S. Miller5c1e6aa2011-04-28 14:13:38 -0700974 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
David S. Miller14e50e52007-05-24 18:17:54 -0700975 struct dst_entry *new = NULL;
976
David S. Millerf5b0a872012-07-19 12:31:33 -0700977 rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, DST_OBSOLETE_NONE, 0);
David S. Miller14e50e52007-05-24 18:17:54 -0700978 if (rt) {
Changli Gaod8d1f302010-06-10 23:31:35 -0700979 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -0700980
Steffen Klassert81048912012-07-05 23:37:09 +0000981 memset(new + 1, 0, sizeof(*rt) - sizeof(*new));
Steffen Klassert81048912012-07-05 23:37:09 +0000982
David S. Miller14e50e52007-05-24 18:17:54 -0700983 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -0800984 new->input = dst_discard;
Eric Dumazetaad88722014-04-15 13:47:15 -0400985 new->output = dst_discard_sk;
David S. Miller14e50e52007-05-24 18:17:54 -0700986
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000987 if (dst_metrics_read_only(&ort->dst))
988 new->_metrics = ort->dst._metrics;
989 else
990 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -0700991 rt->rt6i_idev = ort->rt6i_idev;
992 if (rt->rt6i_idev)
993 in6_dev_hold(rt->rt6i_idev);
David S. Miller14e50e52007-05-24 18:17:54 -0700994
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000995 rt->rt6i_gateway = ort->rt6i_gateway;
Gao feng1716a962012-04-06 00:13:10 +0000996 rt->rt6i_flags = ort->rt6i_flags;
David S. Miller14e50e52007-05-24 18:17:54 -0700997 rt->rt6i_metric = 0;
998
999 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
1000#ifdef CONFIG_IPV6_SUBTREES
1001 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1002#endif
1003
1004 dst_free(new);
1005 }
1006
David S. Miller69ead7a2011-03-01 14:45:33 -08001007 dst_release(dst_orig);
1008 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07001009}
David S. Miller14e50e52007-05-24 18:17:54 -07001010
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011/*
1012 * Destination cache support functions
1013 */
1014
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001015static void rt6_dst_from_metrics_check(struct rt6_info *rt)
1016{
1017 if (rt->dst.from &&
1018 dst_metrics_ptr(&rt->dst) != dst_metrics_ptr(rt->dst.from))
1019 dst_init_metrics(&rt->dst, dst_metrics_ptr(rt->dst.from), true);
1020}
1021
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
1023{
1024 struct rt6_info *rt;
1025
1026 rt = (struct rt6_info *) dst;
1027
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00001028 /* All IPV6 dsts are created with ->obsolete set to the value
1029 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
1030 * into this function always.
1031 */
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02001032 if (!rt->rt6i_node || (rt->rt6i_node->fn_sernum != cookie))
1033 return NULL;
Li RongQinga4477c42012-11-07 21:56:33 +00001034
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02001035 if (rt6_check_expired(rt))
1036 return NULL;
1037
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001038 rt6_dst_from_metrics_check(rt);
1039
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02001040 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041}
1042
1043static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
1044{
1045 struct rt6_info *rt = (struct rt6_info *) dst;
1046
1047 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001048 if (rt->rt6i_flags & RTF_CACHE) {
1049 if (rt6_check_expired(rt)) {
1050 ip6_del_rt(rt);
1051 dst = NULL;
1052 }
1053 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001055 dst = NULL;
1056 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001058 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059}
1060
1061static void ip6_link_failure(struct sk_buff *skb)
1062{
1063 struct rt6_info *rt;
1064
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00001065 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
Eric Dumazetadf30902009-06-02 05:19:30 +00001067 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 if (rt) {
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001069 if (rt->rt6i_flags & RTF_CACHE) {
1070 dst_hold(&rt->dst);
1071 if (ip6_del_rt(rt))
1072 dst_free(&rt->dst);
1073 } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 rt->rt6i_node->fn_sernum = -1;
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001075 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 }
1077}
1078
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001079static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
1080{
1081 struct net *net = dev_net(rt->dst.dev);
1082
1083 rt->rt6i_flags |= RTF_MODIFIED;
1084 rt->rt6i_pmtu = mtu;
1085 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
1086}
1087
1088static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
1089 const struct ipv6hdr *iph, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090{
Ian Morris67ba4152014-08-24 21:53:10 +01001091 struct rt6_info *rt6 = (struct rt6_info *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001093 if (rt6->rt6i_flags & RTF_LOCAL)
1094 return;
1095
David S. Miller81aded22012-06-15 14:54:11 -07001096 dst_confirm(dst);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001097 mtu = max_t(u32, mtu, IPV6_MIN_MTU);
1098 if (mtu >= dst_mtu(dst))
1099 return;
David S. Miller81aded22012-06-15 14:54:11 -07001100
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001101 if (rt6->rt6i_flags & RTF_CACHE) {
1102 rt6_do_update_pmtu(rt6, mtu);
1103 } else {
1104 const struct in6_addr *daddr, *saddr;
1105 struct rt6_info *nrt6;
Hagen Paul Pfeifer9d289712015-01-15 22:34:25 +01001106
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001107 if (iph) {
1108 daddr = &iph->daddr;
1109 saddr = &iph->saddr;
1110 } else if (sk) {
1111 daddr = &sk->sk_v6_daddr;
1112 saddr = &inet6_sk(sk)->saddr;
1113 } else {
1114 return;
1115 }
1116 nrt6 = ip6_rt_cache_alloc(rt6, daddr, saddr);
1117 if (nrt6) {
1118 rt6_do_update_pmtu(nrt6, mtu);
1119
1120 /* ip6_ins_rt(nrt6) will bump the
1121 * rt6->rt6i_node->fn_sernum
1122 * which will fail the next rt6_check() and
1123 * invalidate the sk->sk_dst_cache.
1124 */
1125 ip6_ins_rt(nrt6);
1126 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 }
1128}
1129
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001130static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
1131 struct sk_buff *skb, u32 mtu)
1132{
1133 __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu);
1134}
1135
David S. Miller42ae66c2012-06-15 20:01:57 -07001136void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
1137 int oif, u32 mark)
David S. Miller81aded22012-06-15 14:54:11 -07001138{
1139 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1140 struct dst_entry *dst;
1141 struct flowi6 fl6;
1142
1143 memset(&fl6, 0, sizeof(fl6));
1144 fl6.flowi6_oif = oif;
Lorenzo Colitti1b3c61d2014-05-13 10:17:34 -07001145 fl6.flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark);
David S. Miller81aded22012-06-15 14:54:11 -07001146 fl6.daddr = iph->daddr;
1147 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001148 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller81aded22012-06-15 14:54:11 -07001149
1150 dst = ip6_route_output(net, NULL, &fl6);
1151 if (!dst->error)
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001152 __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07001153 dst_release(dst);
1154}
1155EXPORT_SYMBOL_GPL(ip6_update_pmtu);
1156
1157void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
1158{
1159 ip6_update_pmtu(skb, sock_net(sk), mtu,
1160 sk->sk_bound_dev_if, sk->sk_mark);
1161}
1162EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
1163
Duan Jiongb55b76b2013-09-04 19:44:21 +08001164/* Handle redirects */
1165struct ip6rd_flowi {
1166 struct flowi6 fl6;
1167 struct in6_addr gateway;
1168};
1169
1170static struct rt6_info *__ip6_route_redirect(struct net *net,
1171 struct fib6_table *table,
1172 struct flowi6 *fl6,
1173 int flags)
1174{
1175 struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
1176 struct rt6_info *rt;
1177 struct fib6_node *fn;
1178
1179 /* Get the "current" route for this destination and
1180 * check if the redirect has come from approriate router.
1181 *
1182 * RFC 4861 specifies that redirects should only be
1183 * accepted if they come from the nexthop to the target.
1184 * Due to the way the routes are chosen, this notion
1185 * is a bit fuzzy and one might need to check all possible
1186 * routes.
1187 */
1188
1189 read_lock_bh(&table->tb6_lock);
1190 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
1191restart:
1192 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
1193 if (rt6_check_expired(rt))
1194 continue;
1195 if (rt->dst.error)
1196 break;
1197 if (!(rt->rt6i_flags & RTF_GATEWAY))
1198 continue;
1199 if (fl6->flowi6_oif != rt->dst.dev->ifindex)
1200 continue;
1201 if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway))
1202 continue;
1203 break;
1204 }
1205
1206 if (!rt)
1207 rt = net->ipv6.ip6_null_entry;
1208 else if (rt->dst.error) {
1209 rt = net->ipv6.ip6_null_entry;
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001210 goto out;
1211 }
1212
1213 if (rt == net->ipv6.ip6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001214 fn = fib6_backtrack(fn, &fl6->saddr);
1215 if (fn)
1216 goto restart;
Duan Jiongb55b76b2013-09-04 19:44:21 +08001217 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001218
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001219out:
Duan Jiongb55b76b2013-09-04 19:44:21 +08001220 dst_hold(&rt->dst);
1221
1222 read_unlock_bh(&table->tb6_lock);
1223
1224 return rt;
1225};
1226
1227static struct dst_entry *ip6_route_redirect(struct net *net,
1228 const struct flowi6 *fl6,
1229 const struct in6_addr *gateway)
1230{
1231 int flags = RT6_LOOKUP_F_HAS_SADDR;
1232 struct ip6rd_flowi rdfl;
1233
1234 rdfl.fl6 = *fl6;
1235 rdfl.gateway = *gateway;
1236
1237 return fib6_rule_lookup(net, &rdfl.fl6,
1238 flags, __ip6_route_redirect);
1239}
1240
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001241void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark)
1242{
1243 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1244 struct dst_entry *dst;
1245 struct flowi6 fl6;
1246
1247 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001248 fl6.flowi6_iif = LOOPBACK_IFINDEX;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001249 fl6.flowi6_oif = oif;
1250 fl6.flowi6_mark = mark;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001251 fl6.daddr = iph->daddr;
1252 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001253 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001254
Duan Jiongb55b76b2013-09-04 19:44:21 +08001255 dst = ip6_route_redirect(net, &fl6, &ipv6_hdr(skb)->saddr);
1256 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001257 dst_release(dst);
1258}
1259EXPORT_SYMBOL_GPL(ip6_redirect);
1260
Duan Jiongc92a59e2013-08-22 12:07:35 +08001261void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
1262 u32 mark)
1263{
1264 const struct ipv6hdr *iph = ipv6_hdr(skb);
1265 const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
1266 struct dst_entry *dst;
1267 struct flowi6 fl6;
1268
1269 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001270 fl6.flowi6_iif = LOOPBACK_IFINDEX;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001271 fl6.flowi6_oif = oif;
1272 fl6.flowi6_mark = mark;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001273 fl6.daddr = msg->dest;
1274 fl6.saddr = iph->daddr;
1275
Duan Jiongb55b76b2013-09-04 19:44:21 +08001276 dst = ip6_route_redirect(net, &fl6, &iph->saddr);
1277 rt6_do_redirect(dst, NULL, skb);
Duan Jiongc92a59e2013-08-22 12:07:35 +08001278 dst_release(dst);
1279}
1280
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001281void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
1282{
1283 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark);
1284}
1285EXPORT_SYMBOL_GPL(ip6_sk_redirect);
1286
David S. Miller0dbaee32010-12-13 12:52:14 -08001287static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288{
David S. Miller0dbaee32010-12-13 12:52:14 -08001289 struct net_device *dev = dst->dev;
1290 unsigned int mtu = dst_mtu(dst);
1291 struct net *net = dev_net(dev);
1292
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
1294
Daniel Lezcano55786892008-03-04 13:47:47 -08001295 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
1296 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297
1298 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001299 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
1300 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
1301 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 * rely only on pmtu discovery"
1303 */
1304 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
1305 mtu = IPV6_MAXPLEN;
1306 return mtu;
1307}
1308
Steffen Klassertebb762f2011-11-23 02:12:51 +00001309static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08001310{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001311 const struct rt6_info *rt = (const struct rt6_info *)dst;
1312 unsigned int mtu = rt->rt6i_pmtu;
David S. Millerd33e4552010-12-14 13:01:14 -08001313 struct inet6_dev *idev;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001314
1315 if (mtu)
Eric Dumazet30f78d82014-04-10 21:23:36 -07001316 goto out;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001317
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001318 mtu = dst_metric_raw(dst, RTAX_MTU);
1319 if (mtu)
1320 goto out;
1321
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001322 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08001323
1324 rcu_read_lock();
1325 idev = __in6_dev_get(dst->dev);
1326 if (idev)
1327 mtu = idev->cnf.mtu6;
1328 rcu_read_unlock();
1329
Eric Dumazet30f78d82014-04-10 21:23:36 -07001330out:
1331 return min_t(unsigned int, mtu, IP6_MAX_MTU);
David S. Millerd33e4552010-12-14 13:01:14 -08001332}
1333
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001334static struct dst_entry *icmp6_dst_gc_list;
1335static DEFINE_SPINLOCK(icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001336
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001337struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05001338 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339{
David S. Miller87a11572011-12-06 17:04:13 -05001340 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 struct rt6_info *rt;
1342 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001343 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344
David S. Miller38308472011-12-03 18:02:47 -05001345 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00001346 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347
David S. Miller8b96d222012-06-11 02:01:56 -07001348 rt = ip6_dst_alloc(net, dev, 0, NULL);
David S. Miller38308472011-12-03 18:02:47 -05001349 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05001351 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 goto out;
1353 }
1354
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001355 rt->dst.flags |= DST_HOST;
1356 rt->dst.output = ip6_output;
Changli Gaod8d1f302010-06-10 23:31:35 -07001357 atomic_set(&rt->dst.__refcnt, 1);
Julian Anastasov550bab42013-10-20 15:43:04 +03001358 rt->rt6i_gateway = fl6->daddr;
David S. Miller87a11572011-12-06 17:04:13 -05001359 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001360 rt->rt6i_dst.plen = 128;
1361 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08001362 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001364 spin_lock_bh(&icmp6_dst_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001365 rt->dst.next = icmp6_dst_gc_list;
1366 icmp6_dst_gc_list = &rt->dst;
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001367 spin_unlock_bh(&icmp6_dst_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368
Daniel Lezcano55786892008-03-04 13:47:47 -08001369 fib6_force_start_gc(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
David S. Miller87a11572011-12-06 17:04:13 -05001371 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
1372
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373out:
David S. Miller87a11572011-12-06 17:04:13 -05001374 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375}
1376
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001377int icmp6_dst_gc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378{
Hagen Paul Pfeifere9476e92011-02-25 05:45:19 +00001379 struct dst_entry *dst, **pprev;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001380 int more = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001382 spin_lock_bh(&icmp6_dst_lock);
1383 pprev = &icmp6_dst_gc_list;
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001384
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 while ((dst = *pprev) != NULL) {
1386 if (!atomic_read(&dst->__refcnt)) {
1387 *pprev = dst->next;
1388 dst_free(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 } else {
1390 pprev = &dst->next;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001391 ++more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 }
1393 }
1394
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001395 spin_unlock_bh(&icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001396
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001397 return more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398}
1399
David S. Miller1e493d12008-09-10 17:27:15 -07001400static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg),
1401 void *arg)
1402{
1403 struct dst_entry *dst, **pprev;
1404
1405 spin_lock_bh(&icmp6_dst_lock);
1406 pprev = &icmp6_dst_gc_list;
1407 while ((dst = *pprev) != NULL) {
1408 struct rt6_info *rt = (struct rt6_info *) dst;
1409 if (func(rt, arg)) {
1410 *pprev = dst->next;
1411 dst_free(dst);
1412 } else {
1413 pprev = &dst->next;
1414 }
1415 }
1416 spin_unlock_bh(&icmp6_dst_lock);
1417}
1418
Daniel Lezcano569d3642008-01-18 03:56:57 -08001419static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420{
Alexey Dobriyan86393e52009-08-29 01:34:49 +00001421 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08001422 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
1423 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
1424 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
1425 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
1426 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001427 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428
Eric Dumazetfc66f952010-10-08 06:37:34 +00001429 entries = dst_entries_get_fast(ops);
Michal Kubeček49a18d82013-08-01 10:04:24 +02001430 if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00001431 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 goto out;
1433
Benjamin Thery6891a342008-03-04 13:49:47 -08001434 net->ipv6.ip6_rt_gc_expire++;
Li RongQing14956642014-05-19 17:30:28 +08001435 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
Eric Dumazetfc66f952010-10-08 06:37:34 +00001436 entries = dst_entries_get_slow(ops);
1437 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08001438 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08001440 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001441 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442}
1443
Florian Westphale715b6d2015-01-05 23:57:44 +01001444static int ip6_convert_metrics(struct mx6_config *mxc,
1445 const struct fib6_config *cfg)
1446{
1447 struct nlattr *nla;
1448 int remaining;
1449 u32 *mp;
1450
Ian Morris63159f22015-03-29 14:00:04 +01001451 if (!cfg->fc_mx)
Florian Westphale715b6d2015-01-05 23:57:44 +01001452 return 0;
1453
1454 mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
1455 if (unlikely(!mp))
1456 return -ENOMEM;
1457
1458 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
1459 int type = nla_type(nla);
1460
1461 if (type) {
Daniel Borkmannea697632015-01-05 23:57:47 +01001462 u32 val;
1463
Florian Westphale715b6d2015-01-05 23:57:44 +01001464 if (unlikely(type > RTAX_MAX))
1465 goto err;
Daniel Borkmannea697632015-01-05 23:57:47 +01001466 if (type == RTAX_CC_ALGO) {
1467 char tmp[TCP_CA_NAME_MAX];
Florian Westphale715b6d2015-01-05 23:57:44 +01001468
Daniel Borkmannea697632015-01-05 23:57:47 +01001469 nla_strlcpy(tmp, nla, sizeof(tmp));
1470 val = tcp_ca_get_key_by_name(tmp);
1471 if (val == TCP_CA_UNSPEC)
1472 goto err;
1473 } else {
1474 val = nla_get_u32(nla);
1475 }
1476
1477 mp[type - 1] = val;
Florian Westphale715b6d2015-01-05 23:57:44 +01001478 __set_bit(type - 1, mxc->mx_valid);
1479 }
1480 }
1481
1482 mxc->mx = mp;
1483
1484 return 0;
1485 err:
1486 kfree(mp);
1487 return -EINVAL;
1488}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489
Thomas Graf86872cb2006-08-22 00:01:08 -07001490int ip6_route_add(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491{
1492 int err;
Daniel Lezcano55786892008-03-04 13:47:47 -08001493 struct net *net = cfg->fc_nlinfo.nl_net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 struct rt6_info *rt = NULL;
1495 struct net_device *dev = NULL;
1496 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001497 struct fib6_table *table;
Florian Westphale715b6d2015-01-05 23:57:44 +01001498 struct mx6_config mxc = { .mx = NULL, };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 int addr_type;
1500
Thomas Graf86872cb2006-08-22 00:01:08 -07001501 if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 return -EINVAL;
1503#ifndef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001504 if (cfg->fc_src_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 return -EINVAL;
1506#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07001507 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08001509 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 if (!dev)
1511 goto out;
1512 idev = in6_dev_get(dev);
1513 if (!idev)
1514 goto out;
1515 }
1516
Thomas Graf86872cb2006-08-22 00:01:08 -07001517 if (cfg->fc_metric == 0)
1518 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519
Matti Vaittinend71314b2011-11-14 00:14:49 +00001520 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05001521 if (cfg->fc_nlinfo.nlh &&
1522 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00001523 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001524 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00001525 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00001526 table = fib6_new_table(net, cfg->fc_table);
1527 }
1528 } else {
1529 table = fib6_new_table(net, cfg->fc_table);
1530 }
David S. Miller38308472011-12-03 18:02:47 -05001531
1532 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001533 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07001534
Sabrina Dubrocac88507f2014-03-06 17:51:57 +01001535 rt = ip6_dst_alloc(net, NULL, (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT, table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536
David S. Miller38308472011-12-03 18:02:47 -05001537 if (!rt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 err = -ENOMEM;
1539 goto out;
1540 }
1541
Gao feng1716a962012-04-06 00:13:10 +00001542 if (cfg->fc_flags & RTF_EXPIRES)
1543 rt6_set_expires(rt, jiffies +
1544 clock_t_to_jiffies(cfg->fc_expires));
1545 else
1546 rt6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547
Thomas Graf86872cb2006-08-22 00:01:08 -07001548 if (cfg->fc_protocol == RTPROT_UNSPEC)
1549 cfg->fc_protocol = RTPROT_BOOT;
1550 rt->rt6i_protocol = cfg->fc_protocol;
1551
1552 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553
1554 if (addr_type & IPV6_ADDR_MULTICAST)
Changli Gaod8d1f302010-06-10 23:31:35 -07001555 rt->dst.input = ip6_mc_input;
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00001556 else if (cfg->fc_flags & RTF_LOCAL)
1557 rt->dst.input = ip6_input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 else
Changli Gaod8d1f302010-06-10 23:31:35 -07001559 rt->dst.input = ip6_forward;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560
Changli Gaod8d1f302010-06-10 23:31:35 -07001561 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562
Thomas Graf86872cb2006-08-22 00:01:08 -07001563 ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
1564 rt->rt6i_dst.plen = cfg->fc_dst_len;
Martin KaFai Lauafc4eef2015-04-28 13:03:07 -07001565 if (rt->rt6i_dst.plen == 128)
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001566 rt->dst.flags |= DST_HOST;
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001567
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568#ifdef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001569 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
1570 rt->rt6i_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571#endif
1572
Thomas Graf86872cb2006-08-22 00:01:08 -07001573 rt->rt6i_metric = cfg->fc_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
1575 /* We cannot add true routes via loopback here,
1576 they would result in kernel looping; promote them to reject routes
1577 */
Thomas Graf86872cb2006-08-22 00:01:08 -07001578 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05001579 (dev && (dev->flags & IFF_LOOPBACK) &&
1580 !(addr_type & IPV6_ADDR_LOOPBACK) &&
1581 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08001583 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 if (dev) {
1585 dev_put(dev);
1586 in6_dev_put(idev);
1587 }
Daniel Lezcano55786892008-03-04 13:47:47 -08001588 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 dev_hold(dev);
1590 idev = in6_dev_get(dev);
1591 if (!idev) {
1592 err = -ENODEV;
1593 goto out;
1594 }
1595 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001597 switch (cfg->fc_type) {
1598 case RTN_BLACKHOLE:
1599 rt->dst.error = -EINVAL;
Eric Dumazetaad88722014-04-15 13:47:15 -04001600 rt->dst.output = dst_discard_sk;
Kamala R7150aed2013-12-02 19:55:21 +05301601 rt->dst.input = dst_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001602 break;
1603 case RTN_PROHIBIT:
1604 rt->dst.error = -EACCES;
Kamala R7150aed2013-12-02 19:55:21 +05301605 rt->dst.output = ip6_pkt_prohibit_out;
1606 rt->dst.input = ip6_pkt_prohibit;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001607 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00001608 case RTN_THROW:
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001609 default:
Kamala R7150aed2013-12-02 19:55:21 +05301610 rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN
1611 : -ENETUNREACH;
1612 rt->dst.output = ip6_pkt_discard_out;
1613 rt->dst.input = ip6_pkt_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001614 break;
1615 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 goto install_route;
1617 }
1618
Thomas Graf86872cb2006-08-22 00:01:08 -07001619 if (cfg->fc_flags & RTF_GATEWAY) {
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001620 const struct in6_addr *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 int gwa_type;
1622
Thomas Graf86872cb2006-08-22 00:01:08 -07001623 gw_addr = &cfg->fc_gateway;
Florian Westphal48ed7b22015-05-21 00:25:41 +02001624
1625 /* if gw_addr is local we will fail to detect this in case
1626 * address is still TENTATIVE (DAD in progress). rt6_lookup()
1627 * will return already-added prefix route via interface that
1628 * prefix route was assigned to, which might be non-loopback.
1629 */
1630 err = -EINVAL;
1631 if (ipv6_chk_addr_and_flags(net, gw_addr, NULL, 0, 0))
1632 goto out;
1633
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001634 rt->rt6i_gateway = *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 gwa_type = ipv6_addr_type(gw_addr);
1636
1637 if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
1638 struct rt6_info *grt;
1639
1640 /* IPv6 strictly inhibits using not link-local
1641 addresses as nexthop address.
1642 Otherwise, router will not able to send redirects.
1643 It is very good, but in some (rare!) circumstances
1644 (SIT, PtP, NBMA NOARP links) it is handy to allow
1645 some exceptions. --ANK
1646 */
David S. Miller38308472011-12-03 18:02:47 -05001647 if (!(gwa_type & IPV6_ADDR_UNICAST))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 goto out;
1649
Daniel Lezcano55786892008-03-04 13:47:47 -08001650 grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651
1652 err = -EHOSTUNREACH;
David S. Miller38308472011-12-03 18:02:47 -05001653 if (!grt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 goto out;
1655 if (dev) {
David S. Millerd1918542011-12-28 20:19:20 -05001656 if (dev != grt->dst.dev) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00001657 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 goto out;
1659 }
1660 } else {
David S. Millerd1918542011-12-28 20:19:20 -05001661 dev = grt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 idev = grt->rt6i_idev;
1663 dev_hold(dev);
1664 in6_dev_hold(grt->rt6i_idev);
1665 }
David S. Miller38308472011-12-03 18:02:47 -05001666 if (!(grt->rt6i_flags & RTF_GATEWAY))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 err = 0;
Amerigo Wang94e187c2012-10-29 00:13:19 +00001668 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669
1670 if (err)
1671 goto out;
1672 }
1673 err = -EINVAL;
David S. Miller38308472011-12-03 18:02:47 -05001674 if (!dev || (dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 goto out;
1676 }
1677
1678 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05001679 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 goto out;
1681
Daniel Walterc3968a82011-04-13 21:10:57 +00001682 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
1683 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
1684 err = -EINVAL;
1685 goto out;
1686 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001687 rt->rt6i_prefsrc.addr = cfg->fc_prefsrc;
Daniel Walterc3968a82011-04-13 21:10:57 +00001688 rt->rt6i_prefsrc.plen = 128;
1689 } else
1690 rt->rt6i_prefsrc.plen = 0;
1691
Thomas Graf86872cb2006-08-22 00:01:08 -07001692 rt->rt6i_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
1694install_route:
Changli Gaod8d1f302010-06-10 23:31:35 -07001695 rt->dst.dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 rt->rt6i_idev = idev;
Thomas Grafc71099a2006-08-04 23:20:06 -07001697 rt->rt6i_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001698
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001699 cfg->fc_nlinfo.nl_net = dev_net(dev);
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001700
Florian Westphale715b6d2015-01-05 23:57:44 +01001701 err = ip6_convert_metrics(&mxc, cfg);
1702 if (err)
1703 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704
Florian Westphale715b6d2015-01-05 23:57:44 +01001705 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, &mxc);
1706
1707 kfree(mxc.mx);
1708 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709out:
1710 if (dev)
1711 dev_put(dev);
1712 if (idev)
1713 in6_dev_put(idev);
1714 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07001715 dst_free(&rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 return err;
1717}
1718
Thomas Graf86872cb2006-08-22 00:01:08 -07001719static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720{
1721 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07001722 struct fib6_table *table;
David S. Millerd1918542011-12-28 20:19:20 -05001723 struct net *net = dev_net(rt->dst.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724
Gao feng6825a262012-09-19 19:25:34 +00001725 if (rt == net->ipv6.ip6_null_entry) {
1726 err = -ENOENT;
1727 goto out;
1728 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07001729
Thomas Grafc71099a2006-08-04 23:20:06 -07001730 table = rt->rt6i_table;
1731 write_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07001732 err = fib6_del(rt, info);
Thomas Grafc71099a2006-08-04 23:20:06 -07001733 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734
Gao feng6825a262012-09-19 19:25:34 +00001735out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00001736 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 return err;
1738}
1739
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001740int ip6_del_rt(struct rt6_info *rt)
1741{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08001742 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -05001743 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08001744 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08001745 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001746}
1747
Thomas Graf86872cb2006-08-22 00:01:08 -07001748static int ip6_route_del(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749{
Thomas Grafc71099a2006-08-04 23:20:06 -07001750 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 struct fib6_node *fn;
1752 struct rt6_info *rt;
1753 int err = -ESRCH;
1754
Daniel Lezcano55786892008-03-04 13:47:47 -08001755 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001756 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001757 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758
Thomas Grafc71099a2006-08-04 23:20:06 -07001759 read_lock_bh(&table->tb6_lock);
1760
1761 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07001762 &cfg->fc_dst, cfg->fc_dst_len,
1763 &cfg->fc_src, cfg->fc_src_len);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001764
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 if (fn) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001766 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
Martin KaFai Lau1f56a012015-04-28 13:03:03 -07001767 if ((rt->rt6i_flags & RTF_CACHE) &&
1768 !(cfg->fc_flags & RTF_CACHE))
1769 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001770 if (cfg->fc_ifindex &&
David S. Millerd1918542011-12-28 20:19:20 -05001771 (!rt->dst.dev ||
1772 rt->dst.dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001774 if (cfg->fc_flags & RTF_GATEWAY &&
1775 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001777 if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07001779 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07001780 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781
Thomas Graf86872cb2006-08-22 00:01:08 -07001782 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 }
1784 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001785 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786
1787 return err;
1788}
1789
David S. Miller6700c272012-07-17 03:29:28 -07001790static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001791{
David S. Millere8599ff2012-07-11 23:43:53 -07001792 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001793 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07001794 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07001795 struct ndisc_options ndopts;
1796 struct inet6_dev *in6_dev;
1797 struct neighbour *neigh;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001798 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07001799 int optlen, on_link;
1800 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07001801
Simon Horman29a3cad2013-05-28 20:34:26 +00001802 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001803 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07001804
1805 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07001806 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001807 return;
1808 }
1809
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001810 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07001811
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001812 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07001813 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001814 return;
1815 }
1816
David S. Miller6e157b62012-07-12 00:05:02 -07001817 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001818 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07001819 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001820 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07001821 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07001822 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001823 return;
1824 }
1825
1826 in6_dev = __in6_dev_get(skb->dev);
1827 if (!in6_dev)
1828 return;
1829 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
1830 return;
1831
1832 /* RFC2461 8.1:
1833 * The IP source address of the Redirect MUST be the same as the current
1834 * first-hop router for the specified ICMP Destination Address.
1835 */
1836
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001837 if (!ndisc_parse_options(msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07001838 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
1839 return;
1840 }
David S. Miller6e157b62012-07-12 00:05:02 -07001841
1842 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07001843 if (ndopts.nd_opts_tgt_lladdr) {
1844 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
1845 skb->dev);
1846 if (!lladdr) {
1847 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
1848 return;
1849 }
1850 }
1851
David S. Miller6e157b62012-07-12 00:05:02 -07001852 rt = (struct rt6_info *) dst;
1853 if (rt == net->ipv6.ip6_null_entry) {
1854 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
1855 return;
1856 }
1857
1858 /* Redirect received -> path was valid.
1859 * Look, redirects are sent only in response to data packets,
1860 * so that this nexthop apparently is reachable. --ANK
1861 */
1862 dst_confirm(&rt->dst);
1863
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001864 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07001865 if (!neigh)
1866 return;
1867
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 /*
1869 * We have finally decided to accept it.
1870 */
1871
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001872 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1874 NEIGH_UPDATE_F_OVERRIDE|
1875 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1876 NEIGH_UPDATE_F_ISROUTER))
1877 );
1878
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001879 nrt = ip6_rt_copy(rt, &msg->dest);
David S. Miller38308472011-12-03 18:02:47 -05001880 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 goto out;
1882
1883 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
1884 if (on_link)
1885 nrt->rt6i_flags &= ~RTF_GATEWAY;
1886
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001887 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888
Thomas Graf40e22e82006-08-22 00:00:45 -07001889 if (ip6_ins_rt(nrt))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 goto out;
1891
Changli Gaod8d1f302010-06-10 23:31:35 -07001892 netevent.old = &rt->dst;
1893 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001894 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00001895 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07001896 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
1897
David S. Miller38308472011-12-03 18:02:47 -05001898 if (rt->rt6i_flags & RTF_CACHE) {
David S. Miller6e157b62012-07-12 00:05:02 -07001899 rt = (struct rt6_info *) dst_clone(&rt->dst);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001900 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 }
1902
1903out:
David S. Millere8599ff2012-07-11 23:43:53 -07001904 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07001905}
1906
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 * Misc support functions
1909 */
1910
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001911static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from)
1912{
1913 BUG_ON(from->dst.from);
1914
1915 rt->rt6i_flags &= ~RTF_EXPIRES;
1916 dst_hold(&from->dst);
1917 rt->dst.from = &from->dst;
1918 dst_init_metrics(&rt->dst, dst_metrics_ptr(&from->dst), true);
1919}
1920
Gao feng1716a962012-04-06 00:13:10 +00001921static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
Eric Dumazet21efcfa2011-07-19 20:18:36 +00001922 const struct in6_addr *dest)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923{
David S. Millerd1918542011-12-28 20:19:20 -05001924 struct net *net = dev_net(ort->dst.dev);
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001925 struct rt6_info *rt;
1926
1927 if (ort->rt6i_flags & RTF_CACHE)
1928 ort = (struct rt6_info *)ort->dst.from;
1929
1930 rt = ip6_dst_alloc(net, ort->dst.dev, 0,
1931 ort->rt6i_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932
1933 if (rt) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001934 rt->dst.input = ort->dst.input;
1935 rt->dst.output = ort->dst.output;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001936 rt->dst.flags |= DST_HOST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001938 rt->rt6i_dst.addr = *dest;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001939 rt->rt6i_dst.plen = 128;
Changli Gaod8d1f302010-06-10 23:31:35 -07001940 rt->dst.error = ort->dst.error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 rt->rt6i_idev = ort->rt6i_idev;
1942 if (rt->rt6i_idev)
1943 in6_dev_hold(rt->rt6i_idev);
Changli Gaod8d1f302010-06-10 23:31:35 -07001944 rt->dst.lastuse = jiffies;
Martin KaFai Lau2647a9b2015-05-22 20:55:58 -07001945 rt->rt6i_gateway = ort->rt6i_gateway;
Gao feng1716a962012-04-06 00:13:10 +00001946 rt->rt6i_flags = ort->rt6i_flags;
Li RongQing24f5b852013-12-19 12:40:26 +08001947 rt6_set_from(rt, ort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 rt->rt6i_metric = 0;
1949
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950#ifdef CONFIG_IPV6_SUBTREES
1951 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1952#endif
Florian Westphal0f6c6392011-05-20 11:27:24 +00001953 memcpy(&rt->rt6i_prefsrc, &ort->rt6i_prefsrc, sizeof(struct rt6key));
Thomas Grafc71099a2006-08-04 23:20:06 -07001954 rt->rt6i_table = ort->rt6i_table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 }
1956 return rt;
1957}
1958
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001959#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001960static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001961 const struct in6_addr *prefix, int prefixlen,
1962 const struct in6_addr *gwaddr, int ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001963{
1964 struct fib6_node *fn;
1965 struct rt6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001966 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001967
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001968 table = fib6_get_table(net, RT6_TABLE_INFO);
David S. Miller38308472011-12-03 18:02:47 -05001969 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001970 return NULL;
1971
Li RongQing5744dd92012-09-11 21:59:01 +00001972 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01001973 fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001974 if (!fn)
1975 goto out;
1976
Changli Gaod8d1f302010-06-10 23:31:35 -07001977 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05001978 if (rt->dst.dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001979 continue;
1980 if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
1981 continue;
1982 if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
1983 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07001984 dst_hold(&rt->dst);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001985 break;
1986 }
1987out:
Li RongQing5744dd92012-09-11 21:59:01 +00001988 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001989 return rt;
1990}
1991
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001992static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001993 const struct in6_addr *prefix, int prefixlen,
1994 const struct in6_addr *gwaddr, int ifindex,
Eric Dumazet95c96172012-04-15 05:58:06 +00001995 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001996{
Thomas Graf86872cb2006-08-22 00:01:08 -07001997 struct fib6_config cfg = {
1998 .fc_table = RT6_TABLE_INFO,
Rami Rosen238fc7e2008-02-09 23:43:11 -08001999 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07002000 .fc_ifindex = ifindex,
2001 .fc_dst_len = prefixlen,
2002 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
2003 RTF_UP | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00002004 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002005 .fc_nlinfo.nlh = NULL,
2006 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07002007 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002008
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002009 cfg.fc_dst = *prefix;
2010 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07002011
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08002012 /* We should treat it as a default route if prefix length is 0. */
2013 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07002014 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002015
Thomas Graf86872cb2006-08-22 00:01:08 -07002016 ip6_route_add(&cfg);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002017
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002018 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002019}
2020#endif
2021
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002022struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002023{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07002025 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002027 table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05002028 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002029 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030
Li RongQing5744dd92012-09-11 21:59:01 +00002031 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01002032 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05002033 if (dev == rt->dst.dev &&
YOSHIFUJI Hideaki045927f2006-03-20 17:00:48 -08002034 ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 ipv6_addr_equal(&rt->rt6i_gateway, addr))
2036 break;
2037 }
2038 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07002039 dst_hold(&rt->dst);
Li RongQing5744dd92012-09-11 21:59:01 +00002040 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 return rt;
2042}
2043
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002044struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08002045 struct net_device *dev,
2046 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047{
Thomas Graf86872cb2006-08-22 00:01:08 -07002048 struct fib6_config cfg = {
2049 .fc_table = RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08002050 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07002051 .fc_ifindex = dev->ifindex,
2052 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
2053 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00002054 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08002055 .fc_nlinfo.nlh = NULL,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002056 .fc_nlinfo.nl_net = dev_net(dev),
Thomas Graf86872cb2006-08-22 00:01:08 -07002057 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002059 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060
Thomas Graf86872cb2006-08-22 00:01:08 -07002061 ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 return rt6_get_dflt_router(gwaddr, dev);
2064}
2065
Daniel Lezcano7b4da532008-03-04 13:47:14 -08002066void rt6_purge_dflt_routers(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067{
2068 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07002069 struct fib6_table *table;
2070
2071 /* NOTE: Keep consistent with rt6_get_dflt_router */
Daniel Lezcano7b4da532008-03-04 13:47:14 -08002072 table = fib6_get_table(net, RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05002073 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002074 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075
2076restart:
Thomas Grafc71099a2006-08-04 23:20:06 -07002077 read_lock_bh(&table->tb6_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07002078 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
Lorenzo Colitti3e8b0ac2013-03-03 20:46:46 +00002079 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
2080 (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002081 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07002082 read_unlock_bh(&table->tb6_lock);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002083 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 goto restart;
2085 }
2086 }
Thomas Grafc71099a2006-08-04 23:20:06 -07002087 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088}
2089
Daniel Lezcano55786892008-03-04 13:47:47 -08002090static void rtmsg_to_fib6_config(struct net *net,
2091 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07002092 struct fib6_config *cfg)
2093{
2094 memset(cfg, 0, sizeof(*cfg));
2095
2096 cfg->fc_table = RT6_TABLE_MAIN;
2097 cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
2098 cfg->fc_metric = rtmsg->rtmsg_metric;
2099 cfg->fc_expires = rtmsg->rtmsg_info;
2100 cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
2101 cfg->fc_src_len = rtmsg->rtmsg_src_len;
2102 cfg->fc_flags = rtmsg->rtmsg_flags;
2103
Daniel Lezcano55786892008-03-04 13:47:47 -08002104 cfg->fc_nlinfo.nl_net = net;
Benjamin Theryf1243c22008-02-26 18:10:03 -08002105
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002106 cfg->fc_dst = rtmsg->rtmsg_dst;
2107 cfg->fc_src = rtmsg->rtmsg_src;
2108 cfg->fc_gateway = rtmsg->rtmsg_gateway;
Thomas Graf86872cb2006-08-22 00:01:08 -07002109}
2110
Daniel Lezcano55786892008-03-04 13:47:47 -08002111int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112{
Thomas Graf86872cb2006-08-22 00:01:08 -07002113 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 struct in6_rtmsg rtmsg;
2115 int err;
2116
Ian Morris67ba4152014-08-24 21:53:10 +01002117 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 case SIOCADDRT: /* Add a route */
2119 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00002120 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 return -EPERM;
2122 err = copy_from_user(&rtmsg, arg,
2123 sizeof(struct in6_rtmsg));
2124 if (err)
2125 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07002126
Daniel Lezcano55786892008-03-04 13:47:47 -08002127 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07002128
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 rtnl_lock();
2130 switch (cmd) {
2131 case SIOCADDRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07002132 err = ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 break;
2134 case SIOCDELRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07002135 err = ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136 break;
2137 default:
2138 err = -EINVAL;
2139 }
2140 rtnl_unlock();
2141
2142 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07002143 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144
2145 return -EINVAL;
2146}
2147
2148/*
2149 * Drop the packet on the floor
2150 */
2151
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07002152static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002154 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00002155 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002156 switch (ipstats_mib_noroutes) {
2157 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07002158 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00002159 if (type == IPV6_ADDR_ANY) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002160 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2161 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002162 break;
2163 }
2164 /* FALLTHROUGH */
2165 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002166 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2167 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002168 break;
2169 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002170 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 kfree_skb(skb);
2172 return 0;
2173}
2174
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002175static int ip6_pkt_discard(struct sk_buff *skb)
2176{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002177 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002178}
2179
Eric Dumazetaad88722014-04-15 13:47:15 -04002180static int ip6_pkt_discard_out(struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181{
Eric Dumazetadf30902009-06-02 05:19:30 +00002182 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002183 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184}
2185
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002186static int ip6_pkt_prohibit(struct sk_buff *skb)
2187{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002188 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002189}
2190
Eric Dumazetaad88722014-04-15 13:47:15 -04002191static int ip6_pkt_prohibit_out(struct sock *sk, struct sk_buff *skb)
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002192{
Eric Dumazetadf30902009-06-02 05:19:30 +00002193 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002194 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002195}
2196
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197/*
2198 * Allocate a dst for local (unicast / anycast) address.
2199 */
2200
2201struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
2202 const struct in6_addr *addr,
David S. Miller8f031512011-12-06 16:48:14 -05002203 bool anycast)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002205 struct net *net = dev_net(idev->dev);
Hannes Frederic Sowaa3300ef2013-12-07 03:33:45 +01002206 struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev,
2207 DST_NOCOUNT, NULL);
2208 if (!rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 return ERR_PTR(-ENOMEM);
2210
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 in6_dev_hold(idev);
2212
David S. Miller11d53b42011-06-24 15:23:34 -07002213 rt->dst.flags |= DST_HOST;
Changli Gaod8d1f302010-06-10 23:31:35 -07002214 rt->dst.input = ip6_input;
2215 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 rt->rt6i_idev = idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217
2218 rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +09002219 if (anycast)
2220 rt->rt6i_flags |= RTF_ANYCAST;
2221 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 rt->rt6i_flags |= RTF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223
Julian Anastasov550bab42013-10-20 15:43:04 +03002224 rt->rt6i_gateway = *addr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002225 rt->rt6i_dst.addr = *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 rt->rt6i_dst.plen = 128;
Daniel Lezcano55786892008-03-04 13:47:47 -08002227 rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228
Changli Gaod8d1f302010-06-10 23:31:35 -07002229 atomic_set(&rt->dst.__refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230
2231 return rt;
2232}
2233
Daniel Walterc3968a82011-04-13 21:10:57 +00002234int ip6_route_get_saddr(struct net *net,
2235 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002236 const struct in6_addr *daddr,
Daniel Walterc3968a82011-04-13 21:10:57 +00002237 unsigned int prefs,
2238 struct in6_addr *saddr)
2239{
Markus Stenberge16e8882015-05-05 13:36:59 +03002240 struct inet6_dev *idev =
2241 rt ? ip6_dst_idev((struct dst_entry *)rt) : NULL;
Daniel Walterc3968a82011-04-13 21:10:57 +00002242 int err = 0;
Markus Stenberge16e8882015-05-05 13:36:59 +03002243 if (rt && rt->rt6i_prefsrc.plen)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002244 *saddr = rt->rt6i_prefsrc.addr;
Daniel Walterc3968a82011-04-13 21:10:57 +00002245 else
2246 err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
2247 daddr, prefs, saddr);
2248 return err;
2249}
2250
2251/* remove deleted ip from prefsrc entries */
2252struct arg_dev_net_ip {
2253 struct net_device *dev;
2254 struct net *net;
2255 struct in6_addr *addr;
2256};
2257
2258static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
2259{
2260 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
2261 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
2262 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
2263
David S. Millerd1918542011-12-28 20:19:20 -05002264 if (((void *)rt->dst.dev == dev || !dev) &&
Daniel Walterc3968a82011-04-13 21:10:57 +00002265 rt != net->ipv6.ip6_null_entry &&
2266 ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
2267 /* remove prefsrc entry */
2268 rt->rt6i_prefsrc.plen = 0;
2269 }
2270 return 0;
2271}
2272
2273void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
2274{
2275 struct net *net = dev_net(ifp->idev->dev);
2276 struct arg_dev_net_ip adni = {
2277 .dev = ifp->idev->dev,
2278 .net = net,
2279 .addr = &ifp->addr,
2280 };
Li RongQing0c3584d2013-12-27 16:32:38 +08002281 fib6_clean_all(net, fib6_remove_prefsrc, &adni);
Daniel Walterc3968a82011-04-13 21:10:57 +00002282}
2283
Duan Jiongbe7a0102014-05-15 15:56:14 +08002284#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY)
2285#define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE)
2286
2287/* Remove routers and update dst entries when gateway turn into host. */
2288static int fib6_clean_tohost(struct rt6_info *rt, void *arg)
2289{
2290 struct in6_addr *gateway = (struct in6_addr *)arg;
2291
2292 if ((((rt->rt6i_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) ||
2293 ((rt->rt6i_flags & RTF_CACHE_GATEWAY) == RTF_CACHE_GATEWAY)) &&
2294 ipv6_addr_equal(gateway, &rt->rt6i_gateway)) {
2295 return -1;
2296 }
2297 return 0;
2298}
2299
2300void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
2301{
2302 fib6_clean_all(net, fib6_clean_tohost, gateway);
2303}
2304
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002305struct arg_dev_net {
2306 struct net_device *dev;
2307 struct net *net;
2308};
2309
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310static int fib6_ifdown(struct rt6_info *rt, void *arg)
2311{
stephen hemmingerbc3ef662010-12-16 17:42:40 +00002312 const struct arg_dev_net *adn = arg;
2313 const struct net_device *dev = adn->dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002314
David S. Millerd1918542011-12-28 20:19:20 -05002315 if ((rt->dst.dev == dev || !dev) &&
David S. Millerc159d302011-12-26 15:24:36 -05002316 rt != adn->net->ipv6.ip6_null_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 return -1;
David S. Millerc159d302011-12-26 15:24:36 -05002318
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 return 0;
2320}
2321
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002322void rt6_ifdown(struct net *net, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002324 struct arg_dev_net adn = {
2325 .dev = dev,
2326 .net = net,
2327 };
2328
Li RongQing0c3584d2013-12-27 16:32:38 +08002329 fib6_clean_all(net, fib6_ifdown, &adn);
David S. Miller1e493d12008-09-10 17:27:15 -07002330 icmp6_clean_all(fib6_ifdown, &adn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331}
2332
Eric Dumazet95c96172012-04-15 05:58:06 +00002333struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00002335 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336};
2337
2338static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
2339{
2340 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
2341 struct inet6_dev *idev;
2342
2343 /* In IPv6 pmtu discovery is not optional,
2344 so that RTAX_MTU lock cannot disable it.
2345 We still use this lock to block changes
2346 caused by addrconf/ndisc.
2347 */
2348
2349 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05002350 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 return 0;
2352
2353 /* For administrative MTU increase, there is no way to discover
2354 IPv6 PMTU increase, so PMTU increase should be updated here.
2355 Since RFC 1981 doesn't include administrative MTU increase
2356 update PMTU increase is a MUST. (i.e. jumbo frame)
2357 */
2358 /*
2359 If new MTU is less than route PMTU, this new MTU will be the
2360 lowest MTU in the path, update the route PMTU to reflect PMTU
2361 decreases; if new MTU is greater than route PMTU, and the
2362 old MTU is the lowest MTU in the path, update the route PMTU
2363 to reflect the increase. In this case if the other nodes' MTU
2364 also have the lowest MTU, TOO BIG MESSAGE will be lead to
2365 PMTU discouvery.
2366 */
David S. Millerd1918542011-12-28 20:19:20 -05002367 if (rt->dst.dev == arg->dev &&
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002368 !dst_metric_locked(&rt->dst, RTAX_MTU)) {
2369 if (rt->rt6i_flags & RTF_CACHE) {
2370 /* For RTF_CACHE with rt6i_pmtu == 0
2371 * (i.e. a redirected route),
2372 * the metrics of its rt->dst.from has already
2373 * been updated.
2374 */
2375 if (rt->rt6i_pmtu && rt->rt6i_pmtu > arg->mtu)
2376 rt->rt6i_pmtu = arg->mtu;
2377 } else if (dst_mtu(&rt->dst) >= arg->mtu ||
2378 (dst_mtu(&rt->dst) < arg->mtu &&
2379 dst_mtu(&rt->dst) == idev->cnf.mtu6)) {
2380 dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu);
2381 }
Simon Arlott566cfd82007-07-26 00:09:55 -07002382 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 return 0;
2384}
2385
Eric Dumazet95c96172012-04-15 05:58:06 +00002386void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387{
Thomas Grafc71099a2006-08-04 23:20:06 -07002388 struct rt6_mtu_change_arg arg = {
2389 .dev = dev,
2390 .mtu = mtu,
2391 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392
Li RongQing0c3584d2013-12-27 16:32:38 +08002393 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394}
2395
Patrick McHardyef7c79e2007-06-05 12:38:30 -07002396static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07002397 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07002398 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07002399 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002400 [RTA_PRIORITY] = { .type = NLA_U32 },
2401 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002402 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002403 [RTA_PREF] = { .type = NLA_U8 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002404};
2405
2406static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
2407 struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408{
Thomas Graf86872cb2006-08-22 00:01:08 -07002409 struct rtmsg *rtm;
2410 struct nlattr *tb[RTA_MAX+1];
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002411 unsigned int pref;
Thomas Graf86872cb2006-08-22 00:01:08 -07002412 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413
Thomas Graf86872cb2006-08-22 00:01:08 -07002414 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2415 if (err < 0)
2416 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417
Thomas Graf86872cb2006-08-22 00:01:08 -07002418 err = -EINVAL;
2419 rtm = nlmsg_data(nlh);
2420 memset(cfg, 0, sizeof(*cfg));
2421
2422 cfg->fc_table = rtm->rtm_table;
2423 cfg->fc_dst_len = rtm->rtm_dst_len;
2424 cfg->fc_src_len = rtm->rtm_src_len;
2425 cfg->fc_flags = RTF_UP;
2426 cfg->fc_protocol = rtm->rtm_protocol;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002427 cfg->fc_type = rtm->rtm_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07002428
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002429 if (rtm->rtm_type == RTN_UNREACHABLE ||
2430 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002431 rtm->rtm_type == RTN_PROHIBIT ||
2432 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07002433 cfg->fc_flags |= RTF_REJECT;
2434
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002435 if (rtm->rtm_type == RTN_LOCAL)
2436 cfg->fc_flags |= RTF_LOCAL;
2437
Martin KaFai Lau1f56a012015-04-28 13:03:03 -07002438 if (rtm->rtm_flags & RTM_F_CLONED)
2439 cfg->fc_flags |= RTF_CACHE;
2440
Eric W. Biederman15e47302012-09-07 20:12:54 +00002441 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
Thomas Graf86872cb2006-08-22 00:01:08 -07002442 cfg->fc_nlinfo.nlh = nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002443 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
Thomas Graf86872cb2006-08-22 00:01:08 -07002444
2445 if (tb[RTA_GATEWAY]) {
Jiri Benc67b61f62015-03-29 16:59:26 +02002446 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
Thomas Graf86872cb2006-08-22 00:01:08 -07002447 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002449
2450 if (tb[RTA_DST]) {
2451 int plen = (rtm->rtm_dst_len + 7) >> 3;
2452
2453 if (nla_len(tb[RTA_DST]) < plen)
2454 goto errout;
2455
2456 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002458
2459 if (tb[RTA_SRC]) {
2460 int plen = (rtm->rtm_src_len + 7) >> 3;
2461
2462 if (nla_len(tb[RTA_SRC]) < plen)
2463 goto errout;
2464
2465 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002467
Daniel Walterc3968a82011-04-13 21:10:57 +00002468 if (tb[RTA_PREFSRC])
Jiri Benc67b61f62015-03-29 16:59:26 +02002469 cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]);
Daniel Walterc3968a82011-04-13 21:10:57 +00002470
Thomas Graf86872cb2006-08-22 00:01:08 -07002471 if (tb[RTA_OIF])
2472 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
2473
2474 if (tb[RTA_PRIORITY])
2475 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
2476
2477 if (tb[RTA_METRICS]) {
2478 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
2479 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002481
2482 if (tb[RTA_TABLE])
2483 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
2484
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002485 if (tb[RTA_MULTIPATH]) {
2486 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
2487 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
2488 }
2489
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002490 if (tb[RTA_PREF]) {
2491 pref = nla_get_u8(tb[RTA_PREF]);
2492 if (pref != ICMPV6_ROUTER_PREF_LOW &&
2493 pref != ICMPV6_ROUTER_PREF_HIGH)
2494 pref = ICMPV6_ROUTER_PREF_MEDIUM;
2495 cfg->fc_flags |= RTF_PREF(pref);
2496 }
2497
Thomas Graf86872cb2006-08-22 00:01:08 -07002498 err = 0;
2499errout:
2500 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501}
2502
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002503static int ip6_route_multipath(struct fib6_config *cfg, int add)
2504{
2505 struct fib6_config r_cfg;
2506 struct rtnexthop *rtnh;
2507 int remaining;
2508 int attrlen;
2509 int err = 0, last_err = 0;
2510
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02002511 remaining = cfg->fc_mp_len;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002512beginning:
2513 rtnh = (struct rtnexthop *)cfg->fc_mp;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002514
2515 /* Parse a Multipath Entry */
2516 while (rtnh_ok(rtnh, remaining)) {
2517 memcpy(&r_cfg, cfg, sizeof(*cfg));
2518 if (rtnh->rtnh_ifindex)
2519 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
2520
2521 attrlen = rtnh_attrlen(rtnh);
2522 if (attrlen > 0) {
2523 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
2524
2525 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
2526 if (nla) {
Jiri Benc67b61f62015-03-29 16:59:26 +02002527 r_cfg.fc_gateway = nla_get_in6_addr(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002528 r_cfg.fc_flags |= RTF_GATEWAY;
2529 }
2530 }
2531 err = add ? ip6_route_add(&r_cfg) : ip6_route_del(&r_cfg);
2532 if (err) {
2533 last_err = err;
2534 /* If we are trying to remove a route, do not stop the
2535 * loop when ip6_route_del() fails (because next hop is
2536 * already gone), we should try to remove all next hops.
2537 */
2538 if (add) {
2539 /* If add fails, we should try to delete all
2540 * next hops that have been already added.
2541 */
2542 add = 0;
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02002543 remaining = cfg->fc_mp_len - remaining;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002544 goto beginning;
2545 }
2546 }
Nicolas Dichtel1a724182012-11-01 22:58:22 +00002547 /* Because each route is added like a single route we remove
Michal Kubeček27596472015-05-18 20:54:00 +02002548 * these flags after the first nexthop: if there is a collision,
2549 * we have already failed to add the first nexthop:
2550 * fib6_add_rt2node() has rejected it; when replacing, old
2551 * nexthops have been replaced by first new, the rest should
2552 * be added to it.
Nicolas Dichtel1a724182012-11-01 22:58:22 +00002553 */
Michal Kubeček27596472015-05-18 20:54:00 +02002554 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
2555 NLM_F_REPLACE);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002556 rtnh = rtnh_next(rtnh, &remaining);
2557 }
2558
2559 return last_err;
2560}
2561
Ian Morris67ba4152014-08-24 21:53:10 +01002562static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563{
Thomas Graf86872cb2006-08-22 00:01:08 -07002564 struct fib6_config cfg;
2565 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566
Thomas Graf86872cb2006-08-22 00:01:08 -07002567 err = rtm_to_fib6_config(skb, nlh, &cfg);
2568 if (err < 0)
2569 return err;
2570
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002571 if (cfg.fc_mp)
2572 return ip6_route_multipath(&cfg, 0);
2573 else
2574 return ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575}
2576
Ian Morris67ba4152014-08-24 21:53:10 +01002577static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578{
Thomas Graf86872cb2006-08-22 00:01:08 -07002579 struct fib6_config cfg;
2580 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581
Thomas Graf86872cb2006-08-22 00:01:08 -07002582 err = rtm_to_fib6_config(skb, nlh, &cfg);
2583 if (err < 0)
2584 return err;
2585
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002586 if (cfg.fc_mp)
2587 return ip6_route_multipath(&cfg, 1);
2588 else
2589 return ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590}
2591
Thomas Graf339bf982006-11-10 14:10:15 -08002592static inline size_t rt6_nlmsg_size(void)
2593{
2594 return NLMSG_ALIGN(sizeof(struct rtmsg))
2595 + nla_total_size(16) /* RTA_SRC */
2596 + nla_total_size(16) /* RTA_DST */
2597 + nla_total_size(16) /* RTA_GATEWAY */
2598 + nla_total_size(16) /* RTA_PREFSRC */
2599 + nla_total_size(4) /* RTA_TABLE */
2600 + nla_total_size(4) /* RTA_IIF */
2601 + nla_total_size(4) /* RTA_OIF */
2602 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08002603 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Daniel Borkmannea697632015-01-05 23:57:47 +01002604 + nla_total_size(sizeof(struct rta_cacheinfo))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002605 + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
2606 + nla_total_size(1); /* RTA_PREF */
Thomas Graf339bf982006-11-10 14:10:15 -08002607}
2608
Brian Haley191cd582008-08-14 15:33:21 -07002609static int rt6_fill_node(struct net *net,
2610 struct sk_buff *skb, struct rt6_info *rt,
Jamal Hadi Salim0d51aa82005-06-21 13:51:04 -07002611 struct in6_addr *dst, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002612 int iif, int type, u32 portid, u32 seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002613 int prefix, int nowait, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002615 u32 metrics[RTAX_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 struct rtmsg *rtm;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002617 struct nlmsghdr *nlh;
Thomas Grafe3703b32006-11-27 09:27:07 -08002618 long expires;
Patrick McHardy9e762a42006-08-10 23:09:48 -07002619 u32 table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620
2621 if (prefix) { /* user wants prefix routes only */
2622 if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
2623 /* success since this is not a prefix route */
2624 return 1;
2625 }
2626 }
2627
Eric W. Biederman15e47302012-09-07 20:12:54 +00002628 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05002629 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08002630 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002631
2632 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 rtm->rtm_family = AF_INET6;
2634 rtm->rtm_dst_len = rt->rt6i_dst.plen;
2635 rtm->rtm_src_len = rt->rt6i_src.plen;
2636 rtm->rtm_tos = 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07002637 if (rt->rt6i_table)
Patrick McHardy9e762a42006-08-10 23:09:48 -07002638 table = rt->rt6i_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07002639 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07002640 table = RT6_TABLE_UNSPEC;
2641 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04002642 if (nla_put_u32(skb, RTA_TABLE, table))
2643 goto nla_put_failure;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002644 if (rt->rt6i_flags & RTF_REJECT) {
2645 switch (rt->dst.error) {
2646 case -EINVAL:
2647 rtm->rtm_type = RTN_BLACKHOLE;
2648 break;
2649 case -EACCES:
2650 rtm->rtm_type = RTN_PROHIBIT;
2651 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002652 case -EAGAIN:
2653 rtm->rtm_type = RTN_THROW;
2654 break;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002655 default:
2656 rtm->rtm_type = RTN_UNREACHABLE;
2657 break;
2658 }
2659 }
David S. Miller38308472011-12-03 18:02:47 -05002660 else if (rt->rt6i_flags & RTF_LOCAL)
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002661 rtm->rtm_type = RTN_LOCAL;
David S. Millerd1918542011-12-28 20:19:20 -05002662 else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 rtm->rtm_type = RTN_LOCAL;
2664 else
2665 rtm->rtm_type = RTN_UNICAST;
2666 rtm->rtm_flags = 0;
2667 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
2668 rtm->rtm_protocol = rt->rt6i_protocol;
David S. Miller38308472011-12-03 18:02:47 -05002669 if (rt->rt6i_flags & RTF_DYNAMIC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 rtm->rtm_protocol = RTPROT_REDIRECT;
Denis Ovsienkof0396f602012-07-10 04:45:50 +00002671 else if (rt->rt6i_flags & RTF_ADDRCONF) {
2672 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ROUTEINFO))
2673 rtm->rtm_protocol = RTPROT_RA;
2674 else
2675 rtm->rtm_protocol = RTPROT_KERNEL;
2676 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677
David S. Miller38308472011-12-03 18:02:47 -05002678 if (rt->rt6i_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 rtm->rtm_flags |= RTM_F_CLONED;
2680
2681 if (dst) {
Jiri Benc930345e2015-03-29 16:59:25 +02002682 if (nla_put_in6_addr(skb, RTA_DST, dst))
David S. Millerc78679e2012-04-01 20:27:33 -04002683 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002684 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 } else if (rtm->rtm_dst_len)
Jiri Benc930345e2015-03-29 16:59:25 +02002686 if (nla_put_in6_addr(skb, RTA_DST, &rt->rt6i_dst.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04002687 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688#ifdef CONFIG_IPV6_SUBTREES
2689 if (src) {
Jiri Benc930345e2015-03-29 16:59:25 +02002690 if (nla_put_in6_addr(skb, RTA_SRC, src))
David S. Millerc78679e2012-04-01 20:27:33 -04002691 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002692 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04002693 } else if (rtm->rtm_src_len &&
Jiri Benc930345e2015-03-29 16:59:25 +02002694 nla_put_in6_addr(skb, RTA_SRC, &rt->rt6i_src.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04002695 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002697 if (iif) {
2698#ifdef CONFIG_IPV6_MROUTE
2699 if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
Benjamin Thery8229efd2008-12-10 16:30:15 -08002700 int err = ip6mr_get_route(net, skb, rtm, nowait);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002701 if (err <= 0) {
2702 if (!nowait) {
2703 if (err == 0)
2704 return 0;
2705 goto nla_put_failure;
2706 } else {
2707 if (err == -EMSGSIZE)
2708 goto nla_put_failure;
2709 }
2710 }
2711 } else
2712#endif
David S. Millerc78679e2012-04-01 20:27:33 -04002713 if (nla_put_u32(skb, RTA_IIF, iif))
2714 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002715 } else if (dst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 struct in6_addr saddr_buf;
David S. Millerc78679e2012-04-01 20:27:33 -04002717 if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0 &&
Jiri Benc930345e2015-03-29 16:59:25 +02002718 nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04002719 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07002721
Daniel Walterc3968a82011-04-13 21:10:57 +00002722 if (rt->rt6i_prefsrc.plen) {
2723 struct in6_addr saddr_buf;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002724 saddr_buf = rt->rt6i_prefsrc.addr;
Jiri Benc930345e2015-03-29 16:59:25 +02002725 if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04002726 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00002727 }
2728
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002729 memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics));
2730 if (rt->rt6i_pmtu)
2731 metrics[RTAX_MTU - 1] = rt->rt6i_pmtu;
2732 if (rtnetlink_put_metrics(skb, metrics) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07002733 goto nla_put_failure;
2734
YOSHIFUJI Hideaki / 吉藤英明dd0cbf22013-01-17 12:53:15 +00002735 if (rt->rt6i_flags & RTF_GATEWAY) {
Jiri Benc930345e2015-03-29 16:59:25 +02002736 if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->rt6i_gateway) < 0)
Eric Dumazet94f826b2012-03-27 09:53:52 +00002737 goto nla_put_failure;
Eric Dumazet94f826b2012-03-27 09:53:52 +00002738 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07002739
David S. Millerc78679e2012-04-01 20:27:33 -04002740 if (rt->dst.dev &&
2741 nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex))
2742 goto nla_put_failure;
2743 if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric))
2744 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00002745
2746 expires = (rt->rt6i_flags & RTF_EXPIRES) ? rt->dst.expires - jiffies : 0;
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07002747
David S. Miller87a50692012-07-10 05:06:14 -07002748 if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, rt->dst.error) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08002749 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002751 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags)))
2752 goto nla_put_failure;
2753
Johannes Berg053c0952015-01-16 22:09:00 +01002754 nlmsg_end(skb, nlh);
2755 return 0;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002756
2757nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002758 nlmsg_cancel(skb, nlh);
2759 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760}
2761
Patrick McHardy1b43af52006-08-10 23:11:17 -07002762int rt6_dump_route(struct rt6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763{
2764 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
2765 int prefix;
2766
Thomas Graf2d7202b2006-08-22 00:01:27 -07002767 if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
2768 struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0;
2770 } else
2771 prefix = 0;
2772
Brian Haley191cd582008-08-14 15:33:21 -07002773 return rt6_fill_node(arg->net,
2774 arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002775 NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002776 prefix, 0, NLM_F_MULTI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777}
2778
Ian Morris67ba4152014-08-24 21:53:10 +01002779static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002781 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07002782 struct nlattr *tb[RTA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07002784 struct sk_buff *skb;
2785 struct rtmsg *rtm;
David S. Miller4c9483b2011-03-12 16:22:43 -05002786 struct flowi6 fl6;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002787 int err, iif = 0, oif = 0;
Thomas Grafab364a62006-08-22 00:01:47 -07002788
2789 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2790 if (err < 0)
2791 goto errout;
2792
2793 err = -EINVAL;
David S. Miller4c9483b2011-03-12 16:22:43 -05002794 memset(&fl6, 0, sizeof(fl6));
Thomas Grafab364a62006-08-22 00:01:47 -07002795
2796 if (tb[RTA_SRC]) {
2797 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
2798 goto errout;
2799
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002800 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07002801 }
2802
2803 if (tb[RTA_DST]) {
2804 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
2805 goto errout;
2806
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002807 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07002808 }
2809
2810 if (tb[RTA_IIF])
2811 iif = nla_get_u32(tb[RTA_IIF]);
2812
2813 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002814 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07002815
Lorenzo Colitti2e47b292014-05-15 16:38:41 -07002816 if (tb[RTA_MARK])
2817 fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
2818
Thomas Grafab364a62006-08-22 00:01:47 -07002819 if (iif) {
2820 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002821 int flags = 0;
2822
Daniel Lezcano55786892008-03-04 13:47:47 -08002823 dev = __dev_get_by_index(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07002824 if (!dev) {
2825 err = -ENODEV;
2826 goto errout;
2827 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002828
2829 fl6.flowi6_iif = iif;
2830
2831 if (!ipv6_addr_any(&fl6.saddr))
2832 flags |= RT6_LOOKUP_F_HAS_SADDR;
2833
2834 rt = (struct rt6_info *)ip6_route_input_lookup(net, dev, &fl6,
2835 flags);
2836 } else {
2837 fl6.flowi6_oif = oif;
2838
2839 rt = (struct rt6_info *)ip6_route_output(net, NULL, &fl6);
Thomas Grafab364a62006-08-22 00:01:47 -07002840 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841
2842 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05002843 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00002844 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07002845 err = -ENOBUFS;
2846 goto errout;
2847 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848
2849 /* Reserve room for dummy headers, this skb can pass
2850 through good chunk of routing engine.
2851 */
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07002852 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
2854
Changli Gaod8d1f302010-06-10 23:31:35 -07002855 skb_dst_set(skb, &rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856
David S. Miller4c9483b2011-03-12 16:22:43 -05002857 err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002858 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002859 nlh->nlmsg_seq, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07002861 kfree_skb(skb);
2862 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 }
2864
Eric W. Biederman15e47302012-09-07 20:12:54 +00002865 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07002866errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868}
2869
Thomas Graf86872cb2006-08-22 00:01:08 -07002870void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871{
2872 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08002873 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002874 u32 seq;
2875 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002877 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05002878 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07002879
Thomas Graf339bf982006-11-10 14:10:15 -08002880 skb = nlmsg_new(rt6_nlmsg_size(), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05002881 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07002882 goto errout;
2883
Brian Haley191cd582008-08-14 15:33:21 -07002884 err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002885 event, info->portid, seq, 0, 0, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08002886 if (err < 0) {
2887 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
2888 WARN_ON(err == -EMSGSIZE);
2889 kfree_skb(skb);
2890 goto errout;
2891 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00002892 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08002893 info->nlh, gfp_any());
2894 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07002895errout:
2896 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08002897 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898}
2899
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002900static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00002901 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002902{
Jiri Pirko351638e2013-05-28 01:30:21 +00002903 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002904 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002905
2906 if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002907 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002908 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
2909#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07002910 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002911 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07002912 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002913 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
2914#endif
2915 }
2916
2917 return NOTIFY_OK;
2918}
2919
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920/*
2921 * /proc
2922 */
2923
2924#ifdef CONFIG_PROC_FS
2925
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002926static const struct file_operations ipv6_route_proc_fops = {
2927 .owner = THIS_MODULE,
2928 .open = ipv6_route_open,
2929 .read = seq_read,
2930 .llseek = seq_lseek,
Hannes Frederic Sowa8d2ca1d2013-09-21 16:55:59 +02002931 .release = seq_release_net,
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002932};
2933
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934static int rt6_stats_seq_show(struct seq_file *seq, void *v)
2935{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002936 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002938 net->ipv6.rt6_stats->fib_nodes,
2939 net->ipv6.rt6_stats->fib_route_nodes,
2940 net->ipv6.rt6_stats->fib_rt_alloc,
2941 net->ipv6.rt6_stats->fib_rt_entries,
2942 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00002943 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002944 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945
2946 return 0;
2947}
2948
2949static int rt6_stats_seq_open(struct inode *inode, struct file *file)
2950{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07002951 return single_open_net(inode, file, rt6_stats_seq_show);
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002952}
2953
Arjan van de Ven9a321442007-02-12 00:55:35 -08002954static const struct file_operations rt6_stats_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 .owner = THIS_MODULE,
2956 .open = rt6_stats_seq_open,
2957 .read = seq_read,
2958 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07002959 .release = single_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960};
2961#endif /* CONFIG_PROC_FS */
2962
2963#ifdef CONFIG_SYSCTL
2964
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965static
Joe Perchesfe2c6332013-06-11 23:04:25 -07002966int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 void __user *buffer, size_t *lenp, loff_t *ppos)
2968{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00002969 struct net *net;
2970 int delay;
2971 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00002973
2974 net = (struct net *)ctl->extra1;
2975 delay = net->ipv6.sysctl.flush_delay;
2976 proc_dointvec(ctl, write, buffer, lenp, ppos);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02002977 fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00002978 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979}
2980
Joe Perchesfe2c6332013-06-11 23:04:25 -07002981struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002982 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08002984 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07002986 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002987 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 },
2989 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08002991 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 .maxlen = sizeof(int),
2993 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002994 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 },
2996 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08002998 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 .maxlen = sizeof(int),
3000 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003001 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 },
3003 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08003005 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 .maxlen = sizeof(int),
3007 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003008 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 },
3010 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08003012 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 .maxlen = sizeof(int),
3014 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003015 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 },
3017 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08003019 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 .maxlen = sizeof(int),
3021 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003022 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 },
3024 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08003026 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 .maxlen = sizeof(int),
3028 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003029 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030 },
3031 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08003033 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 .maxlen = sizeof(int),
3035 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003036 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 },
3038 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08003040 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 .maxlen = sizeof(int),
3042 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003043 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 },
3045 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08003047 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 .maxlen = sizeof(int),
3049 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003050 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08003052 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053};
3054
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003055struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003056{
3057 struct ctl_table *table;
3058
3059 table = kmemdup(ipv6_route_table_template,
3060 sizeof(ipv6_route_table_template),
3061 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003062
3063 if (table) {
3064 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003065 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003066 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003067 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
3068 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
3069 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
3070 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
3071 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
3072 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
3073 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08003074 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
Eric W. Biederman464dc802012-11-16 03:02:59 +00003075
3076 /* Don't export sysctls to unprivileged users */
3077 if (net->user_ns != &init_user_ns)
3078 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003079 }
3080
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003081 return table;
3082}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083#endif
3084
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003085static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003086{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07003087 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003088
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003089 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
3090 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003091
Eric Dumazetfc66f952010-10-08 06:37:34 +00003092 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
3093 goto out_ip6_dst_ops;
3094
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003095 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
3096 sizeof(*net->ipv6.ip6_null_entry),
3097 GFP_KERNEL);
3098 if (!net->ipv6.ip6_null_entry)
Eric Dumazetfc66f952010-10-08 06:37:34 +00003099 goto out_ip6_dst_entries;
Changli Gaod8d1f302010-06-10 23:31:35 -07003100 net->ipv6.ip6_null_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003101 (struct dst_entry *)net->ipv6.ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003102 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003103 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
3104 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003105
3106#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3107 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
3108 sizeof(*net->ipv6.ip6_prohibit_entry),
3109 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003110 if (!net->ipv6.ip6_prohibit_entry)
3111 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003112 net->ipv6.ip6_prohibit_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003113 (struct dst_entry *)net->ipv6.ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003114 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003115 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
3116 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003117
3118 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
3119 sizeof(*net->ipv6.ip6_blk_hole_entry),
3120 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003121 if (!net->ipv6.ip6_blk_hole_entry)
3122 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003123 net->ipv6.ip6_blk_hole_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003124 (struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003125 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003126 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
3127 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003128#endif
3129
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07003130 net->ipv6.sysctl.flush_delay = 0;
3131 net->ipv6.sysctl.ip6_rt_max_size = 4096;
3132 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
3133 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
3134 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
3135 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
3136 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
3137 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
3138
Benjamin Thery6891a342008-03-04 13:49:47 -08003139 net->ipv6.ip6_rt_gc_expire = 30*HZ;
3140
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003141 ret = 0;
3142out:
3143 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003144
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003145#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3146out_ip6_prohibit_entry:
3147 kfree(net->ipv6.ip6_prohibit_entry);
3148out_ip6_null_entry:
3149 kfree(net->ipv6.ip6_null_entry);
3150#endif
Eric Dumazetfc66f952010-10-08 06:37:34 +00003151out_ip6_dst_entries:
3152 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003153out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003154 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003155}
3156
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003157static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003158{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003159 kfree(net->ipv6.ip6_null_entry);
3160#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3161 kfree(net->ipv6.ip6_prohibit_entry);
3162 kfree(net->ipv6.ip6_blk_hole_entry);
3163#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003164 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003165}
3166
Thomas Grafd1896342012-06-18 12:08:33 +00003167static int __net_init ip6_route_net_init_late(struct net *net)
3168{
3169#ifdef CONFIG_PROC_FS
Gao fengd4beaa62013-02-18 01:34:54 +00003170 proc_create("ipv6_route", 0, net->proc_net, &ipv6_route_proc_fops);
3171 proc_create("rt6_stats", S_IRUGO, net->proc_net, &rt6_stats_seq_fops);
Thomas Grafd1896342012-06-18 12:08:33 +00003172#endif
3173 return 0;
3174}
3175
3176static void __net_exit ip6_route_net_exit_late(struct net *net)
3177{
3178#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00003179 remove_proc_entry("ipv6_route", net->proc_net);
3180 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00003181#endif
3182}
3183
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003184static struct pernet_operations ip6_route_net_ops = {
3185 .init = ip6_route_net_init,
3186 .exit = ip6_route_net_exit,
3187};
3188
David S. Millerc3426b42012-06-09 16:27:05 -07003189static int __net_init ipv6_inetpeer_init(struct net *net)
3190{
3191 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
3192
3193 if (!bp)
3194 return -ENOMEM;
3195 inet_peer_base_init(bp);
3196 net->ipv6.peers = bp;
3197 return 0;
3198}
3199
3200static void __net_exit ipv6_inetpeer_exit(struct net *net)
3201{
3202 struct inet_peer_base *bp = net->ipv6.peers;
3203
3204 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07003205 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07003206 kfree(bp);
3207}
3208
David S. Miller2b823f72012-06-09 19:00:16 -07003209static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07003210 .init = ipv6_inetpeer_init,
3211 .exit = ipv6_inetpeer_exit,
3212};
3213
Thomas Grafd1896342012-06-18 12:08:33 +00003214static struct pernet_operations ip6_route_net_late_ops = {
3215 .init = ip6_route_net_init_late,
3216 .exit = ip6_route_net_exit_late,
3217};
3218
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003219static struct notifier_block ip6_route_dev_notifier = {
3220 .notifier_call = ip6_route_dev_notify,
3221 .priority = 0,
3222};
3223
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003224int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003226 int ret;
3227
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003228 ret = -ENOMEM;
3229 ip6_dst_ops_template.kmem_cachep =
3230 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
3231 SLAB_HWCACHE_ALIGN, NULL);
3232 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08003233 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07003234
Eric Dumazetfc66f952010-10-08 06:37:34 +00003235 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003236 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003237 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003238
David S. Millerc3426b42012-06-09 16:27:05 -07003239 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
3240 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003241 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00003242
David S. Miller7e52b332012-06-15 15:51:55 -07003243 ret = register_pernet_subsys(&ip6_route_net_ops);
3244 if (ret)
3245 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07003246
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07003247 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
3248
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003249 /* Registering of the loopback is done before this portion of code,
3250 * the loopback reference in rt6_info will not be taken, do it
3251 * manually for init_net */
Changli Gaod8d1f302010-06-10 23:31:35 -07003252 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003253 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3254 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07003255 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003256 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07003257 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003258 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3259 #endif
David S. Millere8803b62012-06-16 01:12:19 -07003260 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003261 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003262 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003263
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003264 ret = xfrm6_init();
3265 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003266 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08003267
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003268 ret = fib6_rules_init();
3269 if (ret)
3270 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08003271
Thomas Grafd1896342012-06-18 12:08:33 +00003272 ret = register_pernet_subsys(&ip6_route_net_late_ops);
3273 if (ret)
3274 goto fib6_rules_init;
3275
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003276 ret = -ENOBUFS;
Greg Rosec7ac8672011-06-10 01:27:09 +00003277 if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) ||
3278 __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) ||
3279 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL))
Thomas Grafd1896342012-06-18 12:08:33 +00003280 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003281
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003282 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003283 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00003284 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003285
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003286out:
3287 return ret;
3288
Thomas Grafd1896342012-06-18 12:08:33 +00003289out_register_late_subsys:
3290 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003291fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003292 fib6_rules_cleanup();
3293xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003294 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00003295out_fib6_init:
3296 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003297out_register_subsys:
3298 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07003299out_register_inetpeer:
3300 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00003301out_dst_entries:
3302 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003303out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003304 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003305 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306}
3307
3308void ip6_route_cleanup(void)
3309{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003310 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00003311 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07003312 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07003315 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003316 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003317 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003318 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319}