blob: 98565ce0ebcdff78da7c0f0c11737bbb8c2dee59 [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);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +020095static int rt6_score_route(struct rt6_info *rt, int oif, int strict);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -080097#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -080098static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +000099 const struct in6_addr *prefix, int prefixlen,
100 const struct in6_addr *gwaddr, int ifindex,
Eric Dumazet95c96172012-04-15 05:58:06 +0000101 unsigned int pref);
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800102static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000103 const struct in6_addr *prefix, int prefixlen,
104 const struct in6_addr *gwaddr, int ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800105#endif
106
stephen hemmingere8243532013-12-29 14:03:31 -0800107static void rt6_bind_peer(struct rt6_info *rt, int create)
108{
109 struct inet_peer_base *base;
110 struct inet_peer *peer;
111
112 base = inetpeer_base_ptr(rt->_rt6i_peer);
113 if (!base)
114 return;
115
116 peer = inet_getpeer_v6(base, &rt->rt6i_dst.addr, create);
117 if (peer) {
118 if (!rt6_set_peer(rt, peer))
119 inet_putpeer(peer);
120 }
121}
122
123static struct inet_peer *__rt6_get_peer(struct rt6_info *rt, int create)
124{
125 if (rt6_has_peer(rt))
126 return rt6_peer_ptr(rt);
127
128 rt6_bind_peer(rt, create);
129 return (rt6_has_peer(rt) ? rt6_peer_ptr(rt) : NULL);
130}
131
132static struct inet_peer *rt6_get_peer_create(struct rt6_info *rt)
133{
134 return __rt6_get_peer(rt, 1);
135}
136
David S. Miller06582542011-01-27 14:58:42 -0800137static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
138{
139 struct rt6_info *rt = (struct rt6_info *) dst;
140 struct inet_peer *peer;
141 u32 *p = NULL;
142
Yan, Zheng8e2ec632011-09-05 21:34:30 +0000143 if (!(rt->dst.flags & DST_HOST))
144 return NULL;
145
David S. Millerfbfe95a2012-06-08 23:24:18 -0700146 peer = rt6_get_peer_create(rt);
David S. Miller06582542011-01-27 14:58:42 -0800147 if (peer) {
148 u32 *old_p = __DST_METRICS_PTR(old);
149 unsigned long prev, new;
150
151 p = peer->metrics;
Michal Kubečeke5fd3872014-03-27 13:04:08 +0100152 if (inet_metrics_new(peer) ||
153 (old & DST_METRICS_FORCE_OVERWRITE))
David S. Miller06582542011-01-27 14:58:42 -0800154 memcpy(p, old_p, sizeof(u32) * RTAX_MAX);
155
156 new = (unsigned long) p;
157 prev = cmpxchg(&dst->_metrics, old, new);
158
159 if (prev != old) {
160 p = __DST_METRICS_PTR(prev);
161 if (prev & DST_METRICS_READ_ONLY)
162 p = NULL;
163 }
164 }
165 return p;
166}
167
David S. Millerf894cbf2012-07-02 21:52:24 -0700168static inline const void *choose_neigh_daddr(struct rt6_info *rt,
169 struct sk_buff *skb,
170 const void *daddr)
David S. Miller39232972012-01-26 15:22:32 -0500171{
172 struct in6_addr *p = &rt->rt6i_gateway;
173
David S. Millera7563f32012-01-26 16:29:16 -0500174 if (!ipv6_addr_any(p))
David S. Miller39232972012-01-26 15:22:32 -0500175 return (const void *) p;
David S. Millerf894cbf2012-07-02 21:52:24 -0700176 else if (skb)
177 return &ipv6_hdr(skb)->daddr;
David S. Miller39232972012-01-26 15:22:32 -0500178 return daddr;
179}
180
David S. Millerf894cbf2012-07-02 21:52:24 -0700181static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst,
182 struct sk_buff *skb,
183 const void *daddr)
David S. Millerd3aaeb32011-07-18 00:40:17 -0700184{
David S. Miller39232972012-01-26 15:22:32 -0500185 struct rt6_info *rt = (struct rt6_info *) dst;
186 struct neighbour *n;
187
David S. Millerf894cbf2012-07-02 21:52:24 -0700188 daddr = choose_neigh_daddr(rt, skb, daddr);
YOSHIFUJI Hideaki / 吉藤英明8e022ee2013-01-17 12:53:09 +0000189 n = __ipv6_neigh_lookup(dst->dev, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500190 if (n)
191 return n;
192 return neigh_create(&nd_tbl, daddr, dst->dev);
193}
194
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -0800195static struct dst_ops ip6_dst_ops_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 .family = AF_INET6,
Harvey Harrison09640e62009-02-01 00:45:17 -0800197 .protocol = cpu_to_be16(ETH_P_IPV6),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 .gc = ip6_dst_gc,
199 .gc_thresh = 1024,
200 .check = ip6_dst_check,
David S. Miller0dbaee32010-12-13 12:52:14 -0800201 .default_advmss = ip6_default_advmss,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000202 .mtu = ip6_mtu,
David S. Miller06582542011-01-27 14:58:42 -0800203 .cow_metrics = ipv6_cow_metrics,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 .destroy = ip6_dst_destroy,
205 .ifdown = ip6_dst_ifdown,
206 .negative_advice = ip6_negative_advice,
207 .link_failure = ip6_link_failure,
208 .update_pmtu = ip6_rt_update_pmtu,
David S. Miller6e157b62012-07-12 00:05:02 -0700209 .redirect = rt6_do_redirect,
Herbert Xu1ac06e02008-05-20 14:32:14 -0700210 .local_out = __ip6_local_out,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700211 .neigh_lookup = ip6_neigh_lookup,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212};
213
Steffen Klassertebb762f2011-11-23 02:12:51 +0000214static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
Roland Dreierec831ea2011-01-31 13:16:00 -0800215{
Steffen Klassert618f9bc2011-11-23 02:13:31 +0000216 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
217
218 return mtu ? : dst->dev->mtu;
Roland Dreierec831ea2011-01-31 13:16:00 -0800219}
220
David S. Miller6700c272012-07-17 03:29:28 -0700221static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
222 struct sk_buff *skb, u32 mtu)
David S. Miller14e50e52007-05-24 18:17:54 -0700223{
224}
225
David S. Miller6700c272012-07-17 03:29:28 -0700226static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
227 struct sk_buff *skb)
David S. Millerb587ee32012-07-12 00:39:24 -0700228{
229}
230
Held Bernhard0972ddb2011-04-24 22:07:32 +0000231static u32 *ip6_rt_blackhole_cow_metrics(struct dst_entry *dst,
232 unsigned long old)
233{
234 return NULL;
235}
236
David S. Miller14e50e52007-05-24 18:17:54 -0700237static struct dst_ops ip6_dst_blackhole_ops = {
238 .family = AF_INET6,
Harvey Harrison09640e62009-02-01 00:45:17 -0800239 .protocol = cpu_to_be16(ETH_P_IPV6),
David S. Miller14e50e52007-05-24 18:17:54 -0700240 .destroy = ip6_dst_destroy,
241 .check = ip6_dst_check,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000242 .mtu = ip6_blackhole_mtu,
Eric Dumazet214f45c2011-02-18 11:39:01 -0800243 .default_advmss = ip6_default_advmss,
David S. Miller14e50e52007-05-24 18:17:54 -0700244 .update_pmtu = ip6_rt_blackhole_update_pmtu,
David S. Millerb587ee32012-07-12 00:39:24 -0700245 .redirect = ip6_rt_blackhole_redirect,
Held Bernhard0972ddb2011-04-24 22:07:32 +0000246 .cow_metrics = ip6_rt_blackhole_cow_metrics,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700247 .neigh_lookup = ip6_neigh_lookup,
David S. Miller14e50e52007-05-24 18:17:54 -0700248};
249
David S. Miller62fa8a82011-01-26 20:51:05 -0800250static const u32 ip6_template_metrics[RTAX_MAX] = {
Li RongQing14edd872012-10-24 14:01:18 +0800251 [RTAX_HOPLIMIT - 1] = 0,
David S. Miller62fa8a82011-01-26 20:51:05 -0800252};
253
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000254static const struct rt6_info ip6_null_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700255 .dst = {
256 .__refcnt = ATOMIC_INIT(1),
257 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000258 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700259 .error = -ENETUNREACH,
Changli Gaod8d1f302010-06-10 23:31:35 -0700260 .input = ip6_pkt_discard,
261 .output = ip6_pkt_discard_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 },
263 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700264 .rt6i_protocol = RTPROT_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 .rt6i_metric = ~(u32) 0,
266 .rt6i_ref = ATOMIC_INIT(1),
267};
268
Thomas Graf101367c2006-08-04 03:39:02 -0700269#ifdef CONFIG_IPV6_MULTIPLE_TABLES
270
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000271static const struct rt6_info ip6_prohibit_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700272 .dst = {
273 .__refcnt = ATOMIC_INIT(1),
274 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000275 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700276 .error = -EACCES,
Changli Gaod8d1f302010-06-10 23:31:35 -0700277 .input = ip6_pkt_prohibit,
278 .output = ip6_pkt_prohibit_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700279 },
280 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700281 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700282 .rt6i_metric = ~(u32) 0,
283 .rt6i_ref = ATOMIC_INIT(1),
284};
285
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000286static const struct rt6_info ip6_blk_hole_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700287 .dst = {
288 .__refcnt = ATOMIC_INIT(1),
289 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000290 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700291 .error = -EINVAL,
Changli Gaod8d1f302010-06-10 23:31:35 -0700292 .input = dst_discard,
Eric Dumazetaad88722014-04-15 13:47:15 -0400293 .output = dst_discard_sk,
Thomas Graf101367c2006-08-04 03:39:02 -0700294 },
295 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700296 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700297 .rt6i_metric = ~(u32) 0,
298 .rt6i_ref = ATOMIC_INIT(1),
299};
300
301#endif
302
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303/* allocate dst with ip6_dst_ops */
David S. Miller97bab732012-06-09 22:36:36 -0700304static inline struct rt6_info *ip6_dst_alloc(struct net *net,
David S. Miller957c6652011-06-24 15:25:00 -0700305 struct net_device *dev,
David S. Miller8b96d222012-06-11 02:01:56 -0700306 int flags,
307 struct fib6_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308{
David S. Miller97bab732012-06-09 22:36:36 -0700309 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +0000310 0, DST_OBSOLETE_FORCE_CHK, flags);
David S. Millercf911662011-04-28 14:31:47 -0700311
David S. Miller97bab732012-06-09 22:36:36 -0700312 if (rt) {
Steffen Klassert81048912012-07-05 23:37:09 +0000313 struct dst_entry *dst = &rt->dst;
314
315 memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
David S. Miller8b96d222012-06-11 02:01:56 -0700316 rt6_init_peer(rt, table ? &table->tb6_peers : net->ipv6.peers);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000317 INIT_LIST_HEAD(&rt->rt6i_siblings);
David S. Miller97bab732012-06-09 22:36:36 -0700318 }
David S. Millercf911662011-04-28 14:31:47 -0700319 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320}
321
322static void ip6_dst_destroy(struct dst_entry *dst)
323{
324 struct rt6_info *rt = (struct rt6_info *)dst;
325 struct inet6_dev *idev = rt->rt6i_idev;
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000326 struct dst_entry *from = dst->from;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
Yan, Zheng8e2ec632011-09-05 21:34:30 +0000328 if (!(rt->dst.flags & DST_HOST))
329 dst_destroy_metrics_generic(dst);
330
David S. Miller38308472011-12-03 18:02:47 -0500331 if (idev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 rt->rt6i_idev = NULL;
333 in6_dev_put(idev);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900334 }
Gao feng1716a962012-04-06 00:13:10 +0000335
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000336 dst->from = NULL;
337 dst_release(from);
Gao feng1716a962012-04-06 00:13:10 +0000338
David S. Miller97bab732012-06-09 22:36:36 -0700339 if (rt6_has_peer(rt)) {
340 struct inet_peer *peer = rt6_peer_ptr(rt);
David S. Millerb3419362010-11-30 12:27:11 -0800341 inet_putpeer(peer);
342 }
343}
344
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
346 int how)
347{
348 struct rt6_info *rt = (struct rt6_info *)dst;
349 struct inet6_dev *idev = rt->rt6i_idev;
Denis V. Lunev5a3e55d2007-12-07 00:38:10 -0800350 struct net_device *loopback_dev =
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900351 dev_net(dev)->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
David S. Miller97cac082012-07-02 22:43:47 -0700353 if (dev != loopback_dev) {
354 if (idev && idev->dev == dev) {
355 struct inet6_dev *loopback_idev =
356 in6_dev_get(loopback_dev);
357 if (loopback_idev) {
358 rt->rt6i_idev = loopback_idev;
359 in6_dev_put(idev);
360 }
361 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 }
363}
364
Eric Dumazeta50feda2012-05-18 18:57:34 +0000365static bool rt6_check_expired(const struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366{
Gao feng1716a962012-04-06 00:13:10 +0000367 if (rt->rt6i_flags & RTF_EXPIRES) {
368 if (time_after(jiffies, rt->dst.expires))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000369 return true;
Gao feng1716a962012-04-06 00:13:10 +0000370 } else if (rt->dst.from) {
Li RongQing3fd91fb2012-09-13 19:54:57 +0000371 return rt6_check_expired((struct rt6_info *) rt->dst.from);
Gao feng1716a962012-04-06 00:13:10 +0000372 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000373 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374}
375
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000376/* Multipath route selection:
377 * Hash based function using packet header and flowlabel.
378 * Adapted from fib_info_hashfn()
379 */
380static int rt6_info_hash_nhsfn(unsigned int candidate_count,
381 const struct flowi6 *fl6)
382{
383 unsigned int val = fl6->flowi6_proto;
384
YOSHIFUJI Hideaki / 吉藤英明c08977b2013-01-13 05:02:29 +0000385 val ^= ipv6_addr_hash(&fl6->daddr);
386 val ^= ipv6_addr_hash(&fl6->saddr);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000387
388 /* Work only if this not encapsulated */
389 switch (fl6->flowi6_proto) {
390 case IPPROTO_UDP:
391 case IPPROTO_TCP:
392 case IPPROTO_SCTP:
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000393 val ^= (__force u16)fl6->fl6_sport;
394 val ^= (__force u16)fl6->fl6_dport;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000395 break;
396
397 case IPPROTO_ICMPV6:
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000398 val ^= (__force u16)fl6->fl6_icmp_type;
399 val ^= (__force u16)fl6->fl6_icmp_code;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000400 break;
401 }
402 /* RFC6438 recommands to use flowlabel */
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000403 val ^= (__force u32)fl6->flowlabel;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000404
405 /* Perhaps, we need to tune, this function? */
406 val = val ^ (val >> 7) ^ (val >> 12);
407 return val % candidate_count;
408}
409
410static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200411 struct flowi6 *fl6, int oif,
412 int strict)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000413{
414 struct rt6_info *sibling, *next_sibling;
415 int route_choosen;
416
417 route_choosen = rt6_info_hash_nhsfn(match->rt6i_nsiblings + 1, fl6);
418 /* Don't change the route, if route_choosen == 0
419 * (siblings does not include ourself)
420 */
421 if (route_choosen)
422 list_for_each_entry_safe(sibling, next_sibling,
423 &match->rt6i_siblings, rt6i_siblings) {
424 route_choosen--;
425 if (route_choosen == 0) {
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200426 if (rt6_score_route(sibling, oif, strict) < 0)
427 break;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000428 match = sibling;
429 break;
430 }
431 }
432 return match;
433}
434
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435/*
Thomas Grafc71099a2006-08-04 23:20:06 -0700436 * Route lookup. Any table->tb6_lock is implied.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 */
438
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800439static inline struct rt6_info *rt6_device_match(struct net *net,
440 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000441 const struct in6_addr *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 int oif,
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700443 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444{
445 struct rt6_info *local = NULL;
446 struct rt6_info *sprt;
447
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900448 if (!oif && ipv6_addr_any(saddr))
449 goto out;
450
Changli Gaod8d1f302010-06-10 23:31:35 -0700451 for (sprt = rt; sprt; sprt = sprt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -0500452 struct net_device *dev = sprt->dst.dev;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900453
454 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 if (dev->ifindex == oif)
456 return sprt;
457 if (dev->flags & IFF_LOOPBACK) {
David S. Miller38308472011-12-03 18:02:47 -0500458 if (!sprt->rt6i_idev ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 sprt->rt6i_idev->dev->ifindex != oif) {
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700460 if (flags & RT6_LOOKUP_F_IFACE && oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 continue;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900462 if (local && (!oif ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 local->rt6i_idev->dev->ifindex == oif))
464 continue;
465 }
466 local = sprt;
467 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900468 } else {
469 if (ipv6_chk_addr(net, saddr, dev,
470 flags & RT6_LOOKUP_F_IFACE))
471 return sprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900475 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 if (local)
477 return local;
478
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700479 if (flags & RT6_LOOKUP_F_IFACE)
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800480 return net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900482out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 return rt;
484}
485
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800486#ifdef CONFIG_IPV6_ROUTER_PREF
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200487struct __rt6_probe_work {
488 struct work_struct work;
489 struct in6_addr target;
490 struct net_device *dev;
491};
492
493static void rt6_probe_deferred(struct work_struct *w)
494{
495 struct in6_addr mcaddr;
496 struct __rt6_probe_work *work =
497 container_of(w, struct __rt6_probe_work, work);
498
499 addrconf_addr_solict_mult(&work->target, &mcaddr);
500 ndisc_send_ns(work->dev, NULL, &work->target, &mcaddr, NULL);
501 dev_put(work->dev);
Michael Büsch662f5532015-02-08 10:14:07 +0100502 kfree(work);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200503}
504
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800505static void rt6_probe(struct rt6_info *rt)
506{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000507 struct neighbour *neigh;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800508 /*
509 * Okay, this does not seem to be appropriate
510 * for now, however, we need to check if it
511 * is really so; aka Router Reachability Probing.
512 *
513 * Router Reachability Probe MUST be rate-limited
514 * to no more than one per minute.
515 */
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000516 if (!rt || !(rt->rt6i_flags & RTF_GATEWAY))
Amerigo Wangfdd66812012-09-10 02:48:44 +0000517 return;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000518 rcu_read_lock_bh();
519 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
520 if (neigh) {
521 write_lock(&neigh->lock);
522 if (neigh->nud_state & NUD_VALID)
523 goto out;
YOSHIFUJI Hideaki / 吉藤英明7ff74a52013-01-17 12:53:02 +0000524 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000525
526 if (!neigh ||
YOSHIFUJI Hideaki52e16352006-03-20 17:05:47 -0800527 time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) {
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200528 struct __rt6_probe_work *work;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800529
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200530 work = kmalloc(sizeof(*work), GFP_ATOMIC);
531
532 if (neigh && work)
Jiri Benc7e980562013-12-11 13:48:20 +0100533 __neigh_set_probe_once(neigh);
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000534
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200535 if (neigh)
536 write_unlock(&neigh->lock);
537
538 if (work) {
539 INIT_WORK(&work->work, rt6_probe_deferred);
540 work->target = rt->rt6i_gateway;
541 dev_hold(rt->dst.dev);
542 work->dev = rt->dst.dev;
543 schedule_work(&work->work);
544 }
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000545 } else {
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000546out:
547 write_unlock(&neigh->lock);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000548 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000549 rcu_read_unlock_bh();
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800550}
551#else
552static inline void rt6_probe(struct rt6_info *rt)
553{
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800554}
555#endif
556
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557/*
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800558 * Default Router Selection (RFC 2461 6.3.6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 */
Dave Jonesb6f99a22007-03-22 12:27:49 -0700560static inline int rt6_check_dev(struct rt6_info *rt, int oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561{
David S. Millerd1918542011-12-28 20:19:20 -0500562 struct net_device *dev = rt->dst.dev;
David S. Miller161980f2007-04-06 11:42:27 -0700563 if (!oif || dev->ifindex == oif)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800564 return 2;
David S. Miller161980f2007-04-06 11:42:27 -0700565 if ((dev->flags & IFF_LOOPBACK) &&
566 rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
567 return 1;
568 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569}
570
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200571static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000573 struct neighbour *neigh;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200574 enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000575
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700576 if (rt->rt6i_flags & RTF_NONEXTHOP ||
577 !(rt->rt6i_flags & RTF_GATEWAY))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200578 return RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000579
580 rcu_read_lock_bh();
581 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
582 if (neigh) {
583 read_lock(&neigh->lock);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800584 if (neigh->nud_state & NUD_VALID)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200585 ret = RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800586#ifdef CONFIG_IPV6_ROUTER_PREF
Paul Marksa5a81f02012-12-03 10:26:54 +0000587 else if (!(neigh->nud_state & NUD_FAILED))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200588 ret = RT6_NUD_SUCCEED;
Jiri Benc7e980562013-12-11 13:48:20 +0100589 else
590 ret = RT6_NUD_FAIL_PROBE;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800591#endif
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000592 read_unlock(&neigh->lock);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200593 } else {
594 ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
Jiri Benc7e980562013-12-11 13:48:20 +0100595 RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR;
Paul Marksa5a81f02012-12-03 10:26:54 +0000596 }
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000597 rcu_read_unlock_bh();
598
Paul Marksa5a81f02012-12-03 10:26:54 +0000599 return ret;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800600}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800602static int rt6_score_route(struct rt6_info *rt, int oif,
603 int strict)
604{
Paul Marksa5a81f02012-12-03 10:26:54 +0000605 int m;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900606
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700607 m = rt6_check_dev(rt, oif);
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700608 if (!m && (strict & RT6_LOOKUP_F_IFACE))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200609 return RT6_NUD_FAIL_HARD;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800610#ifdef CONFIG_IPV6_ROUTER_PREF
611 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
612#endif
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200613 if (strict & RT6_LOOKUP_F_REACHABLE) {
614 int n = rt6_check_neigh(rt);
615 if (n < 0)
616 return n;
617 }
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800618 return m;
619}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
David S. Millerf11e6652007-03-24 20:36:25 -0700621static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200622 int *mpri, struct rt6_info *match,
623 bool *do_rr)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800624{
David S. Millerf11e6652007-03-24 20:36:25 -0700625 int m;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200626 bool match_do_rr = false;
David S. Millerf11e6652007-03-24 20:36:25 -0700627
628 if (rt6_check_expired(rt))
629 goto out;
630
631 m = rt6_score_route(rt, oif, strict);
Jiri Benc7e980562013-12-11 13:48:20 +0100632 if (m == RT6_NUD_FAIL_DO_RR) {
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200633 match_do_rr = true;
634 m = 0; /* lowest valid score */
Jiri Benc7e980562013-12-11 13:48:20 +0100635 } else if (m == RT6_NUD_FAIL_HARD) {
David S. Millerf11e6652007-03-24 20:36:25 -0700636 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700637 }
638
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200639 if (strict & RT6_LOOKUP_F_REACHABLE)
640 rt6_probe(rt);
641
Jiri Benc7e980562013-12-11 13:48:20 +0100642 /* note that m can be RT6_NUD_FAIL_PROBE at this point */
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200643 if (m > *mpri) {
644 *do_rr = match_do_rr;
645 *mpri = m;
646 match = rt;
647 }
David S. Millerf11e6652007-03-24 20:36:25 -0700648out:
649 return match;
650}
651
652static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
653 struct rt6_info *rr_head,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200654 u32 metric, int oif, int strict,
655 bool *do_rr)
David S. Millerf11e6652007-03-24 20:36:25 -0700656{
657 struct rt6_info *rt, *match;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800658 int mpri = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
David S. Millerf11e6652007-03-24 20:36:25 -0700660 match = NULL;
661 for (rt = rr_head; rt && rt->rt6i_metric == metric;
Changli Gaod8d1f302010-06-10 23:31:35 -0700662 rt = rt->dst.rt6_next)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200663 match = find_match(rt, oif, strict, &mpri, match, do_rr);
David S. Millerf11e6652007-03-24 20:36:25 -0700664 for (rt = fn->leaf; rt && rt != rr_head && rt->rt6i_metric == metric;
Changli Gaod8d1f302010-06-10 23:31:35 -0700665 rt = rt->dst.rt6_next)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200666 match = find_match(rt, oif, strict, &mpri, match, do_rr);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800667
David S. Millerf11e6652007-03-24 20:36:25 -0700668 return match;
669}
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800670
David S. Millerf11e6652007-03-24 20:36:25 -0700671static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
672{
673 struct rt6_info *match, *rt0;
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800674 struct net *net;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200675 bool do_rr = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676
David S. Millerf11e6652007-03-24 20:36:25 -0700677 rt0 = fn->rr_ptr;
678 if (!rt0)
679 fn->rr_ptr = rt0 = fn->leaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200681 match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict,
682 &do_rr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200684 if (do_rr) {
Changli Gaod8d1f302010-06-10 23:31:35 -0700685 struct rt6_info *next = rt0->dst.rt6_next;
David S. Millerf11e6652007-03-24 20:36:25 -0700686
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800687 /* no entries matched; do round-robin */
David S. Millerf11e6652007-03-24 20:36:25 -0700688 if (!next || next->rt6i_metric != rt0->rt6i_metric)
689 next = fn->leaf;
690
691 if (next != rt0)
692 fn->rr_ptr = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 }
694
David S. Millerd1918542011-12-28 20:19:20 -0500695 net = dev_net(rt0->dst.dev);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000696 return match ? match : net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697}
698
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800699#ifdef CONFIG_IPV6_ROUTE_INFO
700int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000701 const struct in6_addr *gwaddr)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800702{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900703 struct net *net = dev_net(dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800704 struct route_info *rinfo = (struct route_info *) opt;
705 struct in6_addr prefix_buf, *prefix;
706 unsigned int pref;
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900707 unsigned long lifetime;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800708 struct rt6_info *rt;
709
710 if (len < sizeof(struct route_info)) {
711 return -EINVAL;
712 }
713
714 /* Sanity check for prefix_len and length */
715 if (rinfo->length > 3) {
716 return -EINVAL;
717 } else if (rinfo->prefix_len > 128) {
718 return -EINVAL;
719 } else if (rinfo->prefix_len > 64) {
720 if (rinfo->length < 2) {
721 return -EINVAL;
722 }
723 } else if (rinfo->prefix_len > 0) {
724 if (rinfo->length < 1) {
725 return -EINVAL;
726 }
727 }
728
729 pref = rinfo->route_pref;
730 if (pref == ICMPV6_ROUTER_PREF_INVALID)
Jens Rosenboom3933fc92009-09-10 06:25:11 +0000731 return -EINVAL;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800732
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900733 lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800734
735 if (rinfo->length == 3)
736 prefix = (struct in6_addr *)rinfo->prefix;
737 else {
738 /* this function is safe */
739 ipv6_addr_prefix(&prefix_buf,
740 (struct in6_addr *)rinfo->prefix,
741 rinfo->prefix_len);
742 prefix = &prefix_buf;
743 }
744
Duan Jiongf104a562013-11-08 09:56:53 +0800745 if (rinfo->prefix_len == 0)
746 rt = rt6_get_dflt_router(gwaddr, dev);
747 else
748 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len,
749 gwaddr, dev->ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800750
751 if (rt && !lifetime) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -0700752 ip6_del_rt(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800753 rt = NULL;
754 }
755
756 if (!rt && lifetime)
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800757 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800758 pref);
759 else if (rt)
760 rt->rt6i_flags = RTF_ROUTEINFO |
761 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
762
763 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +0000764 if (!addrconf_finite_timeout(lifetime))
765 rt6_clean_expires(rt);
766 else
767 rt6_set_expires(rt, jiffies + HZ * lifetime);
768
Amerigo Wang94e187c2012-10-29 00:13:19 +0000769 ip6_rt_put(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800770 }
771 return 0;
772}
773#endif
774
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700775static struct fib6_node* fib6_backtrack(struct fib6_node *fn,
776 struct in6_addr *saddr)
777{
778 struct fib6_node *pn;
779 while (1) {
780 if (fn->fn_flags & RTN_TL_ROOT)
781 return NULL;
782 pn = fn->parent;
783 if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn)
784 fn = fib6_lookup(FIB6_SUBTREE(pn), NULL, saddr);
785 else
786 fn = pn;
787 if (fn->fn_flags & RTN_RTINFO)
788 return fn;
789 }
790}
Thomas Grafc71099a2006-08-04 23:20:06 -0700791
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800792static struct rt6_info *ip6_pol_route_lookup(struct net *net,
793 struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500794 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795{
796 struct fib6_node *fn;
797 struct rt6_info *rt;
798
Thomas Grafc71099a2006-08-04 23:20:06 -0700799 read_lock_bh(&table->tb6_lock);
David S. Miller4c9483b2011-03-12 16:22:43 -0500800 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -0700801restart:
802 rt = fn->leaf;
David S. Miller4c9483b2011-03-12 16:22:43 -0500803 rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000804 if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0)
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200805 rt = rt6_multipath_select(rt, fl6, fl6->flowi6_oif, flags);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700806 if (rt == net->ipv6.ip6_null_entry) {
807 fn = fib6_backtrack(fn, &fl6->saddr);
808 if (fn)
809 goto restart;
810 }
Changli Gaod8d1f302010-06-10 23:31:35 -0700811 dst_use(&rt->dst, jiffies);
Thomas Grafc71099a2006-08-04 23:20:06 -0700812 read_unlock_bh(&table->tb6_lock);
Thomas Grafc71099a2006-08-04 23:20:06 -0700813 return rt;
814
815}
816
Ian Morris67ba4152014-08-24 21:53:10 +0100817struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
Florian Westphalea6e5742011-09-05 16:05:44 +0200818 int flags)
819{
820 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup);
821}
822EXPORT_SYMBOL_GPL(ip6_route_lookup);
823
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900824struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
825 const struct in6_addr *saddr, int oif, int strict)
Thomas Grafc71099a2006-08-04 23:20:06 -0700826{
David S. Miller4c9483b2011-03-12 16:22:43 -0500827 struct flowi6 fl6 = {
828 .flowi6_oif = oif,
829 .daddr = *daddr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700830 };
831 struct dst_entry *dst;
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700832 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
Thomas Grafc71099a2006-08-04 23:20:06 -0700833
Thomas Grafadaa70b2006-10-13 15:01:03 -0700834 if (saddr) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500835 memcpy(&fl6.saddr, saddr, sizeof(*saddr));
Thomas Grafadaa70b2006-10-13 15:01:03 -0700836 flags |= RT6_LOOKUP_F_HAS_SADDR;
837 }
838
David S. Miller4c9483b2011-03-12 16:22:43 -0500839 dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup);
Thomas Grafc71099a2006-08-04 23:20:06 -0700840 if (dst->error == 0)
841 return (struct rt6_info *) dst;
842
843 dst_release(dst);
844
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 return NULL;
846}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900847EXPORT_SYMBOL(rt6_lookup);
848
Thomas Grafc71099a2006-08-04 23:20:06 -0700849/* ip6_ins_rt is called with FREE table->tb6_lock.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 It takes new route entry, the addition fails by any reason the
851 route is freed. In any case, if caller does not hold it, it may
852 be destroyed.
853 */
854
Michal Kubečeke5fd3872014-03-27 13:04:08 +0100855static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info,
Florian Westphale715b6d2015-01-05 23:57:44 +0100856 struct mx6_config *mxc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857{
858 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -0700859 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860
Thomas Grafc71099a2006-08-04 23:20:06 -0700861 table = rt->rt6i_table;
862 write_lock_bh(&table->tb6_lock);
Florian Westphale715b6d2015-01-05 23:57:44 +0100863 err = fib6_add(&table->tb6_root, rt, info, mxc);
Thomas Grafc71099a2006-08-04 23:20:06 -0700864 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865
866 return err;
867}
868
Thomas Graf40e22e82006-08-22 00:00:45 -0700869int ip6_ins_rt(struct rt6_info *rt)
870{
Florian Westphale715b6d2015-01-05 23:57:44 +0100871 struct nl_info info = { .nl_net = dev_net(rt->dst.dev), };
872 struct mx6_config mxc = { .mx = NULL, };
873
874 return __ip6_ins_rt(rt, &info, &mxc);
Thomas Graf40e22e82006-08-22 00:00:45 -0700875}
876
Gao feng1716a962012-04-06 00:13:10 +0000877static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort,
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000878 const struct in6_addr *daddr,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000879 const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 struct rt6_info *rt;
882
883 /*
884 * Clone the route.
885 */
886
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000887 rt = ip6_rt_copy(ort, daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888
889 if (rt) {
Duan Jiong249a3632013-11-05 13:34:53 +0800890 if (ort->rt6i_dst.plen != 128 &&
891 ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
892 rt->rt6i_flags |= RTF_ANYCAST;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 rt->rt6i_flags |= RTF_CACHE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895
896#ifdef CONFIG_IPV6_SUBTREES
897 if (rt->rt6i_src.plen && saddr) {
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000898 rt->rt6i_src.addr = *saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 rt->rt6i_src.plen = 128;
900 }
901#endif
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800902 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800904 return rt;
905}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000907static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort,
908 const struct in6_addr *daddr)
YOSHIFUJI Hideaki299d9932006-03-20 16:58:32 -0800909{
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000910 struct rt6_info *rt = ip6_rt_copy(ort, daddr);
911
YOSHIFUJI Hideaki / 吉藤英明887c95c2013-01-17 12:54:05 +0000912 if (rt)
YOSHIFUJI Hideaki299d9932006-03-20 16:58:32 -0800913 rt->rt6i_flags |= RTF_CACHE;
YOSHIFUJI Hideaki299d9932006-03-20 16:58:32 -0800914 return rt;
915}
916
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800917static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif,
David S. Miller4c9483b2011-03-12 16:22:43 -0500918 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919{
Martin KaFai Lau367efcb2014-10-20 13:42:45 -0700920 struct fib6_node *fn, *saved_fn;
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800921 struct rt6_info *rt, *nrt;
Thomas Grafc71099a2006-08-04 23:20:06 -0700922 int strict = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 int attempts = 3;
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800924 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700926 strict |= flags & RT6_LOOKUP_F_IFACE;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -0700927 if (net->ipv6.devconf_all->forwarding == 0)
928 strict |= RT6_LOOKUP_F_REACHABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700930redo_fib6_lookup_lock:
Thomas Grafc71099a2006-08-04 23:20:06 -0700931 read_lock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
David S. Miller4c9483b2011-03-12 16:22:43 -0500933 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Martin KaFai Lau367efcb2014-10-20 13:42:45 -0700934 saved_fn = fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700936redo_rt6_select:
Martin KaFai Lau367efcb2014-10-20 13:42:45 -0700937 rt = rt6_select(fn, oif, strict);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200938 if (rt->rt6i_nsiblings)
Martin KaFai Lau367efcb2014-10-20 13:42:45 -0700939 rt = rt6_multipath_select(rt, fl6, oif, strict);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700940 if (rt == net->ipv6.ip6_null_entry) {
941 fn = fib6_backtrack(fn, &fl6->saddr);
942 if (fn)
943 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -0700944 else if (strict & RT6_LOOKUP_F_REACHABLE) {
945 /* also consider unreachable route */
946 strict &= ~RT6_LOOKUP_F_REACHABLE;
947 fn = saved_fn;
948 goto redo_rt6_select;
949 } else {
950 dst_hold(&rt->dst);
951 read_unlock_bh(&table->tb6_lock);
952 goto out2;
953 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700954 }
955
Changli Gaod8d1f302010-06-10 23:31:35 -0700956 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -0700957 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -0800958
Martin KaFai Lau94c77bb2014-10-20 13:42:44 -0700959 if (rt->rt6i_flags & RTF_CACHE)
960 goto out2;
961
YOSHIFUJI Hideaki / 吉藤英明c440f162013-01-17 12:53:32 +0000962 if (!(rt->rt6i_flags & (RTF_NONEXTHOP | RTF_GATEWAY)))
David S. Miller4c9483b2011-03-12 16:22:43 -0500963 nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr);
David S. Miller7343ff32011-03-09 19:55:25 -0800964 else if (!(rt->dst.flags & DST_HOST))
David S. Miller4c9483b2011-03-12 16:22:43 -0500965 nrt = rt6_alloc_clone(rt, &fl6->daddr);
David S. Miller7343ff32011-03-09 19:55:25 -0800966 else
967 goto out2;
YOSHIFUJI Hideakie40cf352006-03-20 16:59:27 -0800968
Amerigo Wang94e187c2012-10-29 00:13:19 +0000969 ip6_rt_put(rt);
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800970 rt = nrt ? : net->ipv6.ip6_null_entry;
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800971
Changli Gaod8d1f302010-06-10 23:31:35 -0700972 dst_hold(&rt->dst);
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800973 if (nrt) {
Thomas Graf40e22e82006-08-22 00:00:45 -0700974 err = ip6_ins_rt(nrt);
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800975 if (!err)
976 goto out2;
977 }
978
979 if (--attempts <= 0)
980 goto out2;
981
982 /*
Thomas Grafc71099a2006-08-04 23:20:06 -0700983 * Race condition! In the gap, when table->tb6_lock was
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800984 * released someone could insert this route. Relookup.
985 */
Amerigo Wang94e187c2012-10-29 00:13:19 +0000986 ip6_rt_put(rt);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700987 goto redo_fib6_lookup_lock;
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800988
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989out2:
Changli Gaod8d1f302010-06-10 23:31:35 -0700990 rt->dst.lastuse = jiffies;
991 rt->dst.__use++;
Thomas Grafc71099a2006-08-04 23:20:06 -0700992
993 return rt;
994}
995
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800996static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500997 struct flowi6 *fl6, int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -0700998{
David S. Miller4c9483b2011-03-12 16:22:43 -0500999 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001000}
1001
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001002static struct dst_entry *ip6_route_input_lookup(struct net *net,
1003 struct net_device *dev,
1004 struct flowi6 *fl6, int flags)
1005{
1006 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
1007 flags |= RT6_LOOKUP_F_IFACE;
1008
1009 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_input);
1010}
1011
Thomas Grafc71099a2006-08-04 23:20:06 -07001012void ip6_route_input(struct sk_buff *skb)
1013{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001014 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001015 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001016 int flags = RT6_LOOKUP_F_HAS_SADDR;
David S. Miller4c9483b2011-03-12 16:22:43 -05001017 struct flowi6 fl6 = {
1018 .flowi6_iif = skb->dev->ifindex,
1019 .daddr = iph->daddr,
1020 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001021 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -05001022 .flowi6_mark = skb->mark,
1023 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -07001024 };
Thomas Grafadaa70b2006-10-13 15:01:03 -07001025
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001026 skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -07001027}
1028
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001029static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -05001030 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07001031{
David S. Miller4c9483b2011-03-12 16:22:43 -05001032 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -07001033}
1034
Ian Morris67ba4152014-08-24 21:53:10 +01001035struct dst_entry *ip6_route_output(struct net *net, const struct sock *sk,
David S. Miller4c9483b2011-03-12 16:22:43 -05001036 struct flowi6 *fl6)
Thomas Grafc71099a2006-08-04 23:20:06 -07001037{
1038 int flags = 0;
1039
Pavel Emelyanov1fb94892012-08-08 21:53:36 +00001040 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +00001041
David S. Miller4c9483b2011-03-12 16:22:43 -05001042 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001043 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -07001044
David S. Miller4c9483b2011-03-12 16:22:43 -05001045 if (!ipv6_addr_any(&fl6->saddr))
Thomas Grafadaa70b2006-10-13 15:01:03 -07001046 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +00001047 else if (sk)
1048 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001049
David S. Miller4c9483b2011-03-12 16:22:43 -05001050 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +09001052EXPORT_SYMBOL(ip6_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053
David S. Miller2774c132011-03-01 14:59:04 -08001054struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -07001055{
David S. Miller5c1e6aa2011-04-28 14:13:38 -07001056 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
David S. Miller14e50e52007-05-24 18:17:54 -07001057 struct dst_entry *new = NULL;
1058
David S. Millerf5b0a872012-07-19 12:31:33 -07001059 rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, DST_OBSOLETE_NONE, 0);
David S. Miller14e50e52007-05-24 18:17:54 -07001060 if (rt) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001061 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -07001062
Steffen Klassert81048912012-07-05 23:37:09 +00001063 memset(new + 1, 0, sizeof(*rt) - sizeof(*new));
1064 rt6_init_peer(rt, net->ipv6.peers);
1065
David S. Miller14e50e52007-05-24 18:17:54 -07001066 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08001067 new->input = dst_discard;
Eric Dumazetaad88722014-04-15 13:47:15 -04001068 new->output = dst_discard_sk;
David S. Miller14e50e52007-05-24 18:17:54 -07001069
Eric Dumazet21efcfa2011-07-19 20:18:36 +00001070 if (dst_metrics_read_only(&ort->dst))
1071 new->_metrics = ort->dst._metrics;
1072 else
1073 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07001074 rt->rt6i_idev = ort->rt6i_idev;
1075 if (rt->rt6i_idev)
1076 in6_dev_hold(rt->rt6i_idev);
David S. Miller14e50e52007-05-24 18:17:54 -07001077
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001078 rt->rt6i_gateway = ort->rt6i_gateway;
Gao feng1716a962012-04-06 00:13:10 +00001079 rt->rt6i_flags = ort->rt6i_flags;
David S. Miller14e50e52007-05-24 18:17:54 -07001080 rt->rt6i_metric = 0;
1081
1082 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
1083#ifdef CONFIG_IPV6_SUBTREES
1084 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1085#endif
1086
1087 dst_free(new);
1088 }
1089
David S. Miller69ead7a2011-03-01 14:45:33 -08001090 dst_release(dst_orig);
1091 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07001092}
David S. Miller14e50e52007-05-24 18:17:54 -07001093
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094/*
1095 * Destination cache support functions
1096 */
1097
1098static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
1099{
1100 struct rt6_info *rt;
1101
1102 rt = (struct rt6_info *) dst;
1103
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00001104 /* All IPV6 dsts are created with ->obsolete set to the value
1105 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
1106 * into this function always.
1107 */
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02001108 if (!rt->rt6i_node || (rt->rt6i_node->fn_sernum != cookie))
1109 return NULL;
Li RongQinga4477c42012-11-07 21:56:33 +00001110
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02001111 if (rt6_check_expired(rt))
1112 return NULL;
1113
1114 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115}
1116
1117static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
1118{
1119 struct rt6_info *rt = (struct rt6_info *) dst;
1120
1121 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001122 if (rt->rt6i_flags & RTF_CACHE) {
1123 if (rt6_check_expired(rt)) {
1124 ip6_del_rt(rt);
1125 dst = NULL;
1126 }
1127 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001129 dst = NULL;
1130 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001132 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133}
1134
1135static void ip6_link_failure(struct sk_buff *skb)
1136{
1137 struct rt6_info *rt;
1138
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00001139 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140
Eric Dumazetadf30902009-06-02 05:19:30 +00001141 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 if (rt) {
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001143 if (rt->rt6i_flags & RTF_CACHE) {
1144 dst_hold(&rt->dst);
1145 if (ip6_del_rt(rt))
1146 dst_free(&rt->dst);
1147 } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 rt->rt6i_node->fn_sernum = -1;
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001149 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 }
1151}
1152
David S. Miller6700c272012-07-17 03:29:28 -07001153static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
1154 struct sk_buff *skb, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155{
Ian Morris67ba4152014-08-24 21:53:10 +01001156 struct rt6_info *rt6 = (struct rt6_info *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157
David S. Miller81aded22012-06-15 14:54:11 -07001158 dst_confirm(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 if (mtu < dst_mtu(dst) && rt6->rt6i_dst.plen == 128) {
David S. Miller81aded22012-06-15 14:54:11 -07001160 struct net *net = dev_net(dst->dev);
1161
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 rt6->rt6i_flags |= RTF_MODIFIED;
Hagen Paul Pfeifer9d289712015-01-15 22:34:25 +01001163 if (mtu < IPV6_MIN_MTU)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 mtu = IPV6_MIN_MTU;
Hagen Paul Pfeifer9d289712015-01-15 22:34:25 +01001165
David S. Millerdefb3512010-12-08 21:16:57 -08001166 dst_metric_set(dst, RTAX_MTU, mtu);
David S. Miller81aded22012-06-15 14:54:11 -07001167 rt6_update_expires(rt6, net->ipv6.sysctl.ip6_rt_mtu_expires);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 }
1169}
1170
David S. Miller42ae66c2012-06-15 20:01:57 -07001171void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
1172 int oif, u32 mark)
David S. Miller81aded22012-06-15 14:54:11 -07001173{
1174 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1175 struct dst_entry *dst;
1176 struct flowi6 fl6;
1177
1178 memset(&fl6, 0, sizeof(fl6));
1179 fl6.flowi6_oif = oif;
Lorenzo Colitti1b3c61d2014-05-13 10:17:34 -07001180 fl6.flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark);
David S. Miller81aded22012-06-15 14:54:11 -07001181 fl6.daddr = iph->daddr;
1182 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001183 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller81aded22012-06-15 14:54:11 -07001184
1185 dst = ip6_route_output(net, NULL, &fl6);
1186 if (!dst->error)
David S. Miller6700c272012-07-17 03:29:28 -07001187 ip6_rt_update_pmtu(dst, NULL, skb, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07001188 dst_release(dst);
1189}
1190EXPORT_SYMBOL_GPL(ip6_update_pmtu);
1191
1192void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
1193{
1194 ip6_update_pmtu(skb, sock_net(sk), mtu,
1195 sk->sk_bound_dev_if, sk->sk_mark);
1196}
1197EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
1198
Duan Jiongb55b76b2013-09-04 19:44:21 +08001199/* Handle redirects */
1200struct ip6rd_flowi {
1201 struct flowi6 fl6;
1202 struct in6_addr gateway;
1203};
1204
1205static struct rt6_info *__ip6_route_redirect(struct net *net,
1206 struct fib6_table *table,
1207 struct flowi6 *fl6,
1208 int flags)
1209{
1210 struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
1211 struct rt6_info *rt;
1212 struct fib6_node *fn;
1213
1214 /* Get the "current" route for this destination and
1215 * check if the redirect has come from approriate router.
1216 *
1217 * RFC 4861 specifies that redirects should only be
1218 * accepted if they come from the nexthop to the target.
1219 * Due to the way the routes are chosen, this notion
1220 * is a bit fuzzy and one might need to check all possible
1221 * routes.
1222 */
1223
1224 read_lock_bh(&table->tb6_lock);
1225 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
1226restart:
1227 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
1228 if (rt6_check_expired(rt))
1229 continue;
1230 if (rt->dst.error)
1231 break;
1232 if (!(rt->rt6i_flags & RTF_GATEWAY))
1233 continue;
1234 if (fl6->flowi6_oif != rt->dst.dev->ifindex)
1235 continue;
1236 if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway))
1237 continue;
1238 break;
1239 }
1240
1241 if (!rt)
1242 rt = net->ipv6.ip6_null_entry;
1243 else if (rt->dst.error) {
1244 rt = net->ipv6.ip6_null_entry;
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001245 goto out;
1246 }
1247
1248 if (rt == net->ipv6.ip6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001249 fn = fib6_backtrack(fn, &fl6->saddr);
1250 if (fn)
1251 goto restart;
Duan Jiongb55b76b2013-09-04 19:44:21 +08001252 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001253
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001254out:
Duan Jiongb55b76b2013-09-04 19:44:21 +08001255 dst_hold(&rt->dst);
1256
1257 read_unlock_bh(&table->tb6_lock);
1258
1259 return rt;
1260};
1261
1262static struct dst_entry *ip6_route_redirect(struct net *net,
1263 const struct flowi6 *fl6,
1264 const struct in6_addr *gateway)
1265{
1266 int flags = RT6_LOOKUP_F_HAS_SADDR;
1267 struct ip6rd_flowi rdfl;
1268
1269 rdfl.fl6 = *fl6;
1270 rdfl.gateway = *gateway;
1271
1272 return fib6_rule_lookup(net, &rdfl.fl6,
1273 flags, __ip6_route_redirect);
1274}
1275
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001276void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark)
1277{
1278 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1279 struct dst_entry *dst;
1280 struct flowi6 fl6;
1281
1282 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001283 fl6.flowi6_iif = LOOPBACK_IFINDEX;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001284 fl6.flowi6_oif = oif;
1285 fl6.flowi6_mark = mark;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001286 fl6.daddr = iph->daddr;
1287 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001288 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001289
Duan Jiongb55b76b2013-09-04 19:44:21 +08001290 dst = ip6_route_redirect(net, &fl6, &ipv6_hdr(skb)->saddr);
1291 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001292 dst_release(dst);
1293}
1294EXPORT_SYMBOL_GPL(ip6_redirect);
1295
Duan Jiongc92a59e2013-08-22 12:07:35 +08001296void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
1297 u32 mark)
1298{
1299 const struct ipv6hdr *iph = ipv6_hdr(skb);
1300 const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
1301 struct dst_entry *dst;
1302 struct flowi6 fl6;
1303
1304 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001305 fl6.flowi6_iif = LOOPBACK_IFINDEX;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001306 fl6.flowi6_oif = oif;
1307 fl6.flowi6_mark = mark;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001308 fl6.daddr = msg->dest;
1309 fl6.saddr = iph->daddr;
1310
Duan Jiongb55b76b2013-09-04 19:44:21 +08001311 dst = ip6_route_redirect(net, &fl6, &iph->saddr);
1312 rt6_do_redirect(dst, NULL, skb);
Duan Jiongc92a59e2013-08-22 12:07:35 +08001313 dst_release(dst);
1314}
1315
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001316void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
1317{
1318 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark);
1319}
1320EXPORT_SYMBOL_GPL(ip6_sk_redirect);
1321
David S. Miller0dbaee32010-12-13 12:52:14 -08001322static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323{
David S. Miller0dbaee32010-12-13 12:52:14 -08001324 struct net_device *dev = dst->dev;
1325 unsigned int mtu = dst_mtu(dst);
1326 struct net *net = dev_net(dev);
1327
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
1329
Daniel Lezcano55786892008-03-04 13:47:47 -08001330 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
1331 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332
1333 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001334 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
1335 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
1336 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 * rely only on pmtu discovery"
1338 */
1339 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
1340 mtu = IPV6_MAXPLEN;
1341 return mtu;
1342}
1343
Steffen Klassertebb762f2011-11-23 02:12:51 +00001344static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08001345{
David S. Millerd33e4552010-12-14 13:01:14 -08001346 struct inet6_dev *idev;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001347 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
1348
1349 if (mtu)
Eric Dumazet30f78d82014-04-10 21:23:36 -07001350 goto out;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001351
1352 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08001353
1354 rcu_read_lock();
1355 idev = __in6_dev_get(dst->dev);
1356 if (idev)
1357 mtu = idev->cnf.mtu6;
1358 rcu_read_unlock();
1359
Eric Dumazet30f78d82014-04-10 21:23:36 -07001360out:
1361 return min_t(unsigned int, mtu, IP6_MAX_MTU);
David S. Millerd33e4552010-12-14 13:01:14 -08001362}
1363
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001364static struct dst_entry *icmp6_dst_gc_list;
1365static DEFINE_SPINLOCK(icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001366
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001367struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05001368 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369{
David S. Miller87a11572011-12-06 17:04:13 -05001370 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 struct rt6_info *rt;
1372 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001373 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374
David S. Miller38308472011-12-03 18:02:47 -05001375 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00001376 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377
David S. Miller8b96d222012-06-11 02:01:56 -07001378 rt = ip6_dst_alloc(net, dev, 0, NULL);
David S. Miller38308472011-12-03 18:02:47 -05001379 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05001381 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 goto out;
1383 }
1384
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001385 rt->dst.flags |= DST_HOST;
1386 rt->dst.output = ip6_output;
Changli Gaod8d1f302010-06-10 23:31:35 -07001387 atomic_set(&rt->dst.__refcnt, 1);
Julian Anastasov550bab42013-10-20 15:43:04 +03001388 rt->rt6i_gateway = fl6->daddr;
David S. Miller87a11572011-12-06 17:04:13 -05001389 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001390 rt->rt6i_dst.plen = 128;
1391 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08001392 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001394 spin_lock_bh(&icmp6_dst_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001395 rt->dst.next = icmp6_dst_gc_list;
1396 icmp6_dst_gc_list = &rt->dst;
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001397 spin_unlock_bh(&icmp6_dst_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
Daniel Lezcano55786892008-03-04 13:47:47 -08001399 fib6_force_start_gc(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400
David S. Miller87a11572011-12-06 17:04:13 -05001401 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
1402
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403out:
David S. Miller87a11572011-12-06 17:04:13 -05001404 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405}
1406
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001407int icmp6_dst_gc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408{
Hagen Paul Pfeifere9476e92011-02-25 05:45:19 +00001409 struct dst_entry *dst, **pprev;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001410 int more = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001412 spin_lock_bh(&icmp6_dst_lock);
1413 pprev = &icmp6_dst_gc_list;
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001414
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 while ((dst = *pprev) != NULL) {
1416 if (!atomic_read(&dst->__refcnt)) {
1417 *pprev = dst->next;
1418 dst_free(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 } else {
1420 pprev = &dst->next;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001421 ++more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 }
1423 }
1424
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001425 spin_unlock_bh(&icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001426
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001427 return more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428}
1429
David S. Miller1e493d12008-09-10 17:27:15 -07001430static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg),
1431 void *arg)
1432{
1433 struct dst_entry *dst, **pprev;
1434
1435 spin_lock_bh(&icmp6_dst_lock);
1436 pprev = &icmp6_dst_gc_list;
1437 while ((dst = *pprev) != NULL) {
1438 struct rt6_info *rt = (struct rt6_info *) dst;
1439 if (func(rt, arg)) {
1440 *pprev = dst->next;
1441 dst_free(dst);
1442 } else {
1443 pprev = &dst->next;
1444 }
1445 }
1446 spin_unlock_bh(&icmp6_dst_lock);
1447}
1448
Daniel Lezcano569d3642008-01-18 03:56:57 -08001449static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450{
Alexey Dobriyan86393e52009-08-29 01:34:49 +00001451 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08001452 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
1453 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
1454 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
1455 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
1456 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001457 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458
Eric Dumazetfc66f952010-10-08 06:37:34 +00001459 entries = dst_entries_get_fast(ops);
Michal Kubeček49a18d82013-08-01 10:04:24 +02001460 if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00001461 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 goto out;
1463
Benjamin Thery6891a342008-03-04 13:49:47 -08001464 net->ipv6.ip6_rt_gc_expire++;
Li RongQing14956642014-05-19 17:30:28 +08001465 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
Eric Dumazetfc66f952010-10-08 06:37:34 +00001466 entries = dst_entries_get_slow(ops);
1467 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08001468 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08001470 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001471 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472}
1473
Florian Westphale715b6d2015-01-05 23:57:44 +01001474static int ip6_convert_metrics(struct mx6_config *mxc,
1475 const struct fib6_config *cfg)
1476{
1477 struct nlattr *nla;
1478 int remaining;
1479 u32 *mp;
1480
1481 if (cfg->fc_mx == NULL)
1482 return 0;
1483
1484 mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
1485 if (unlikely(!mp))
1486 return -ENOMEM;
1487
1488 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
1489 int type = nla_type(nla);
1490
1491 if (type) {
Daniel Borkmannea697632015-01-05 23:57:47 +01001492 u32 val;
1493
Florian Westphale715b6d2015-01-05 23:57:44 +01001494 if (unlikely(type > RTAX_MAX))
1495 goto err;
Daniel Borkmannea697632015-01-05 23:57:47 +01001496 if (type == RTAX_CC_ALGO) {
1497 char tmp[TCP_CA_NAME_MAX];
Florian Westphale715b6d2015-01-05 23:57:44 +01001498
Daniel Borkmannea697632015-01-05 23:57:47 +01001499 nla_strlcpy(tmp, nla, sizeof(tmp));
1500 val = tcp_ca_get_key_by_name(tmp);
1501 if (val == TCP_CA_UNSPEC)
1502 goto err;
1503 } else {
1504 val = nla_get_u32(nla);
1505 }
1506
1507 mp[type - 1] = val;
Florian Westphale715b6d2015-01-05 23:57:44 +01001508 __set_bit(type - 1, mxc->mx_valid);
1509 }
1510 }
1511
1512 mxc->mx = mp;
1513
1514 return 0;
1515 err:
1516 kfree(mp);
1517 return -EINVAL;
1518}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519
Thomas Graf86872cb2006-08-22 00:01:08 -07001520int ip6_route_add(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521{
1522 int err;
Daniel Lezcano55786892008-03-04 13:47:47 -08001523 struct net *net = cfg->fc_nlinfo.nl_net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 struct rt6_info *rt = NULL;
1525 struct net_device *dev = NULL;
1526 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001527 struct fib6_table *table;
Florian Westphale715b6d2015-01-05 23:57:44 +01001528 struct mx6_config mxc = { .mx = NULL, };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 int addr_type;
1530
Thomas Graf86872cb2006-08-22 00:01:08 -07001531 if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 return -EINVAL;
1533#ifndef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001534 if (cfg->fc_src_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 return -EINVAL;
1536#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07001537 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08001539 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 if (!dev)
1541 goto out;
1542 idev = in6_dev_get(dev);
1543 if (!idev)
1544 goto out;
1545 }
1546
Thomas Graf86872cb2006-08-22 00:01:08 -07001547 if (cfg->fc_metric == 0)
1548 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549
Matti Vaittinend71314b2011-11-14 00:14:49 +00001550 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05001551 if (cfg->fc_nlinfo.nlh &&
1552 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00001553 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001554 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00001555 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00001556 table = fib6_new_table(net, cfg->fc_table);
1557 }
1558 } else {
1559 table = fib6_new_table(net, cfg->fc_table);
1560 }
David S. Miller38308472011-12-03 18:02:47 -05001561
1562 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001563 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07001564
Sabrina Dubrocac88507f2014-03-06 17:51:57 +01001565 rt = ip6_dst_alloc(net, NULL, (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT, table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566
David S. Miller38308472011-12-03 18:02:47 -05001567 if (!rt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 err = -ENOMEM;
1569 goto out;
1570 }
1571
Gao feng1716a962012-04-06 00:13:10 +00001572 if (cfg->fc_flags & RTF_EXPIRES)
1573 rt6_set_expires(rt, jiffies +
1574 clock_t_to_jiffies(cfg->fc_expires));
1575 else
1576 rt6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577
Thomas Graf86872cb2006-08-22 00:01:08 -07001578 if (cfg->fc_protocol == RTPROT_UNSPEC)
1579 cfg->fc_protocol = RTPROT_BOOT;
1580 rt->rt6i_protocol = cfg->fc_protocol;
1581
1582 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583
1584 if (addr_type & IPV6_ADDR_MULTICAST)
Changli Gaod8d1f302010-06-10 23:31:35 -07001585 rt->dst.input = ip6_mc_input;
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00001586 else if (cfg->fc_flags & RTF_LOCAL)
1587 rt->dst.input = ip6_input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 else
Changli Gaod8d1f302010-06-10 23:31:35 -07001589 rt->dst.input = ip6_forward;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590
Changli Gaod8d1f302010-06-10 23:31:35 -07001591 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592
Thomas Graf86872cb2006-08-22 00:01:08 -07001593 ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
1594 rt->rt6i_dst.plen = cfg->fc_dst_len;
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001595 if (rt->rt6i_dst.plen == 128) {
1596 rt->dst.flags |= DST_HOST;
1597 dst_metrics_set_force_overwrite(&rt->dst);
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001598 }
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001599
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600#ifdef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001601 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
1602 rt->rt6i_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603#endif
1604
Thomas Graf86872cb2006-08-22 00:01:08 -07001605 rt->rt6i_metric = cfg->fc_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606
1607 /* We cannot add true routes via loopback here,
1608 they would result in kernel looping; promote them to reject routes
1609 */
Thomas Graf86872cb2006-08-22 00:01:08 -07001610 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05001611 (dev && (dev->flags & IFF_LOOPBACK) &&
1612 !(addr_type & IPV6_ADDR_LOOPBACK) &&
1613 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08001615 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 if (dev) {
1617 dev_put(dev);
1618 in6_dev_put(idev);
1619 }
Daniel Lezcano55786892008-03-04 13:47:47 -08001620 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 dev_hold(dev);
1622 idev = in6_dev_get(dev);
1623 if (!idev) {
1624 err = -ENODEV;
1625 goto out;
1626 }
1627 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001629 switch (cfg->fc_type) {
1630 case RTN_BLACKHOLE:
1631 rt->dst.error = -EINVAL;
Eric Dumazetaad88722014-04-15 13:47:15 -04001632 rt->dst.output = dst_discard_sk;
Kamala R7150aed2013-12-02 19:55:21 +05301633 rt->dst.input = dst_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001634 break;
1635 case RTN_PROHIBIT:
1636 rt->dst.error = -EACCES;
Kamala R7150aed2013-12-02 19:55:21 +05301637 rt->dst.output = ip6_pkt_prohibit_out;
1638 rt->dst.input = ip6_pkt_prohibit;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001639 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00001640 case RTN_THROW:
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001641 default:
Kamala R7150aed2013-12-02 19:55:21 +05301642 rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN
1643 : -ENETUNREACH;
1644 rt->dst.output = ip6_pkt_discard_out;
1645 rt->dst.input = ip6_pkt_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001646 break;
1647 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 goto install_route;
1649 }
1650
Thomas Graf86872cb2006-08-22 00:01:08 -07001651 if (cfg->fc_flags & RTF_GATEWAY) {
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001652 const struct in6_addr *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 int gwa_type;
1654
Thomas Graf86872cb2006-08-22 00:01:08 -07001655 gw_addr = &cfg->fc_gateway;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001656 rt->rt6i_gateway = *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 gwa_type = ipv6_addr_type(gw_addr);
1658
1659 if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
1660 struct rt6_info *grt;
1661
1662 /* IPv6 strictly inhibits using not link-local
1663 addresses as nexthop address.
1664 Otherwise, router will not able to send redirects.
1665 It is very good, but in some (rare!) circumstances
1666 (SIT, PtP, NBMA NOARP links) it is handy to allow
1667 some exceptions. --ANK
1668 */
1669 err = -EINVAL;
David S. Miller38308472011-12-03 18:02:47 -05001670 if (!(gwa_type & IPV6_ADDR_UNICAST))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 goto out;
1672
Daniel Lezcano55786892008-03-04 13:47:47 -08001673 grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674
1675 err = -EHOSTUNREACH;
David S. Miller38308472011-12-03 18:02:47 -05001676 if (!grt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 goto out;
1678 if (dev) {
David S. Millerd1918542011-12-28 20:19:20 -05001679 if (dev != grt->dst.dev) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00001680 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 goto out;
1682 }
1683 } else {
David S. Millerd1918542011-12-28 20:19:20 -05001684 dev = grt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 idev = grt->rt6i_idev;
1686 dev_hold(dev);
1687 in6_dev_hold(grt->rt6i_idev);
1688 }
David S. Miller38308472011-12-03 18:02:47 -05001689 if (!(grt->rt6i_flags & RTF_GATEWAY))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 err = 0;
Amerigo Wang94e187c2012-10-29 00:13:19 +00001691 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
1693 if (err)
1694 goto out;
1695 }
1696 err = -EINVAL;
David S. Miller38308472011-12-03 18:02:47 -05001697 if (!dev || (dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 goto out;
1699 }
1700
1701 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05001702 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 goto out;
1704
Daniel Walterc3968a82011-04-13 21:10:57 +00001705 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
1706 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
1707 err = -EINVAL;
1708 goto out;
1709 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001710 rt->rt6i_prefsrc.addr = cfg->fc_prefsrc;
Daniel Walterc3968a82011-04-13 21:10:57 +00001711 rt->rt6i_prefsrc.plen = 128;
1712 } else
1713 rt->rt6i_prefsrc.plen = 0;
1714
Thomas Graf86872cb2006-08-22 00:01:08 -07001715 rt->rt6i_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716
1717install_route:
Changli Gaod8d1f302010-06-10 23:31:35 -07001718 rt->dst.dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 rt->rt6i_idev = idev;
Thomas Grafc71099a2006-08-04 23:20:06 -07001720 rt->rt6i_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001721
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001722 cfg->fc_nlinfo.nl_net = dev_net(dev);
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001723
Florian Westphale715b6d2015-01-05 23:57:44 +01001724 err = ip6_convert_metrics(&mxc, cfg);
1725 if (err)
1726 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727
Florian Westphale715b6d2015-01-05 23:57:44 +01001728 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, &mxc);
1729
1730 kfree(mxc.mx);
1731 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732out:
1733 if (dev)
1734 dev_put(dev);
1735 if (idev)
1736 in6_dev_put(idev);
1737 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07001738 dst_free(&rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 return err;
1740}
1741
Thomas Graf86872cb2006-08-22 00:01:08 -07001742static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743{
1744 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07001745 struct fib6_table *table;
David S. Millerd1918542011-12-28 20:19:20 -05001746 struct net *net = dev_net(rt->dst.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747
Gao feng6825a262012-09-19 19:25:34 +00001748 if (rt == net->ipv6.ip6_null_entry) {
1749 err = -ENOENT;
1750 goto out;
1751 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07001752
Thomas Grafc71099a2006-08-04 23:20:06 -07001753 table = rt->rt6i_table;
1754 write_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07001755 err = fib6_del(rt, info);
Thomas Grafc71099a2006-08-04 23:20:06 -07001756 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757
Gao feng6825a262012-09-19 19:25:34 +00001758out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00001759 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 return err;
1761}
1762
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001763int ip6_del_rt(struct rt6_info *rt)
1764{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08001765 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -05001766 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08001767 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08001768 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001769}
1770
Thomas Graf86872cb2006-08-22 00:01:08 -07001771static int ip6_route_del(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772{
Thomas Grafc71099a2006-08-04 23:20:06 -07001773 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 struct fib6_node *fn;
1775 struct rt6_info *rt;
1776 int err = -ESRCH;
1777
Daniel Lezcano55786892008-03-04 13:47:47 -08001778 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001779 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001780 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781
Thomas Grafc71099a2006-08-04 23:20:06 -07001782 read_lock_bh(&table->tb6_lock);
1783
1784 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07001785 &cfg->fc_dst, cfg->fc_dst_len,
1786 &cfg->fc_src, cfg->fc_src_len);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001787
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 if (fn) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001789 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
Thomas Graf86872cb2006-08-22 00:01:08 -07001790 if (cfg->fc_ifindex &&
David S. Millerd1918542011-12-28 20:19:20 -05001791 (!rt->dst.dev ||
1792 rt->dst.dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001794 if (cfg->fc_flags & RTF_GATEWAY &&
1795 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001797 if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07001799 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07001800 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801
Thomas Graf86872cb2006-08-22 00:01:08 -07001802 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 }
1804 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001805 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806
1807 return err;
1808}
1809
David S. Miller6700c272012-07-17 03:29:28 -07001810static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001811{
David S. Millere8599ff2012-07-11 23:43:53 -07001812 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001813 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07001814 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07001815 struct ndisc_options ndopts;
1816 struct inet6_dev *in6_dev;
1817 struct neighbour *neigh;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001818 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07001819 int optlen, on_link;
1820 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07001821
Simon Horman29a3cad2013-05-28 20:34:26 +00001822 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001823 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07001824
1825 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07001826 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001827 return;
1828 }
1829
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001830 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07001831
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001832 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07001833 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001834 return;
1835 }
1836
David S. Miller6e157b62012-07-12 00:05:02 -07001837 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001838 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07001839 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001840 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07001841 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07001842 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001843 return;
1844 }
1845
1846 in6_dev = __in6_dev_get(skb->dev);
1847 if (!in6_dev)
1848 return;
1849 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
1850 return;
1851
1852 /* RFC2461 8.1:
1853 * The IP source address of the Redirect MUST be the same as the current
1854 * first-hop router for the specified ICMP Destination Address.
1855 */
1856
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001857 if (!ndisc_parse_options(msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07001858 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
1859 return;
1860 }
David S. Miller6e157b62012-07-12 00:05:02 -07001861
1862 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07001863 if (ndopts.nd_opts_tgt_lladdr) {
1864 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
1865 skb->dev);
1866 if (!lladdr) {
1867 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
1868 return;
1869 }
1870 }
1871
David S. Miller6e157b62012-07-12 00:05:02 -07001872 rt = (struct rt6_info *) dst;
1873 if (rt == net->ipv6.ip6_null_entry) {
1874 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
1875 return;
1876 }
1877
1878 /* Redirect received -> path was valid.
1879 * Look, redirects are sent only in response to data packets,
1880 * so that this nexthop apparently is reachable. --ANK
1881 */
1882 dst_confirm(&rt->dst);
1883
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001884 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07001885 if (!neigh)
1886 return;
1887
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 /*
1889 * We have finally decided to accept it.
1890 */
1891
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001892 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1894 NEIGH_UPDATE_F_OVERRIDE|
1895 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1896 NEIGH_UPDATE_F_ISROUTER))
1897 );
1898
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001899 nrt = ip6_rt_copy(rt, &msg->dest);
David S. Miller38308472011-12-03 18:02:47 -05001900 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 goto out;
1902
1903 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
1904 if (on_link)
1905 nrt->rt6i_flags &= ~RTF_GATEWAY;
1906
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001907 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908
Thomas Graf40e22e82006-08-22 00:00:45 -07001909 if (ip6_ins_rt(nrt))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 goto out;
1911
Changli Gaod8d1f302010-06-10 23:31:35 -07001912 netevent.old = &rt->dst;
1913 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001914 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00001915 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07001916 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
1917
David S. Miller38308472011-12-03 18:02:47 -05001918 if (rt->rt6i_flags & RTF_CACHE) {
David S. Miller6e157b62012-07-12 00:05:02 -07001919 rt = (struct rt6_info *) dst_clone(&rt->dst);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001920 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 }
1922
1923out:
David S. Millere8599ff2012-07-11 23:43:53 -07001924 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07001925}
1926
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 * Misc support functions
1929 */
1930
Gao feng1716a962012-04-06 00:13:10 +00001931static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
Eric Dumazet21efcfa2011-07-19 20:18:36 +00001932 const struct in6_addr *dest)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933{
David S. Millerd1918542011-12-28 20:19:20 -05001934 struct net *net = dev_net(ort->dst.dev);
David S. Miller8b96d222012-06-11 02:01:56 -07001935 struct rt6_info *rt = ip6_dst_alloc(net, ort->dst.dev, 0,
1936 ort->rt6i_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937
1938 if (rt) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001939 rt->dst.input = ort->dst.input;
1940 rt->dst.output = ort->dst.output;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001941 rt->dst.flags |= DST_HOST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001943 rt->rt6i_dst.addr = *dest;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001944 rt->rt6i_dst.plen = 128;
David S. Millerdefb3512010-12-08 21:16:57 -08001945 dst_copy_metrics(&rt->dst, &ort->dst);
Changli Gaod8d1f302010-06-10 23:31:35 -07001946 rt->dst.error = ort->dst.error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 rt->rt6i_idev = ort->rt6i_idev;
1948 if (rt->rt6i_idev)
1949 in6_dev_hold(rt->rt6i_idev);
Changli Gaod8d1f302010-06-10 23:31:35 -07001950 rt->dst.lastuse = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951
Julian Anastasov550bab42013-10-20 15:43:04 +03001952 if (ort->rt6i_flags & RTF_GATEWAY)
1953 rt->rt6i_gateway = ort->rt6i_gateway;
1954 else
1955 rt->rt6i_gateway = *dest;
Gao feng1716a962012-04-06 00:13:10 +00001956 rt->rt6i_flags = ort->rt6i_flags;
Li RongQing24f5b852013-12-19 12:40:26 +08001957 rt6_set_from(rt, ort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 rt->rt6i_metric = 0;
1959
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960#ifdef CONFIG_IPV6_SUBTREES
1961 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1962#endif
Florian Westphal0f6c6392011-05-20 11:27:24 +00001963 memcpy(&rt->rt6i_prefsrc, &ort->rt6i_prefsrc, sizeof(struct rt6key));
Thomas Grafc71099a2006-08-04 23:20:06 -07001964 rt->rt6i_table = ort->rt6i_table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 }
1966 return rt;
1967}
1968
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001969#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001970static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001971 const struct in6_addr *prefix, int prefixlen,
1972 const struct in6_addr *gwaddr, int ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001973{
1974 struct fib6_node *fn;
1975 struct rt6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001976 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001977
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001978 table = fib6_get_table(net, RT6_TABLE_INFO);
David S. Miller38308472011-12-03 18:02:47 -05001979 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001980 return NULL;
1981
Li RongQing5744dd92012-09-11 21:59:01 +00001982 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01001983 fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001984 if (!fn)
1985 goto out;
1986
Changli Gaod8d1f302010-06-10 23:31:35 -07001987 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05001988 if (rt->dst.dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001989 continue;
1990 if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
1991 continue;
1992 if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
1993 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07001994 dst_hold(&rt->dst);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001995 break;
1996 }
1997out:
Li RongQing5744dd92012-09-11 21:59:01 +00001998 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001999 return rt;
2000}
2001
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002002static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002003 const struct in6_addr *prefix, int prefixlen,
2004 const struct in6_addr *gwaddr, int ifindex,
Eric Dumazet95c96172012-04-15 05:58:06 +00002005 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002006{
Thomas Graf86872cb2006-08-22 00:01:08 -07002007 struct fib6_config cfg = {
2008 .fc_table = RT6_TABLE_INFO,
Rami Rosen238fc7e2008-02-09 23:43:11 -08002009 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07002010 .fc_ifindex = ifindex,
2011 .fc_dst_len = prefixlen,
2012 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
2013 RTF_UP | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00002014 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002015 .fc_nlinfo.nlh = NULL,
2016 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07002017 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002018
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002019 cfg.fc_dst = *prefix;
2020 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07002021
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08002022 /* We should treat it as a default route if prefix length is 0. */
2023 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07002024 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002025
Thomas Graf86872cb2006-08-22 00:01:08 -07002026 ip6_route_add(&cfg);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002027
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002028 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002029}
2030#endif
2031
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002032struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002033{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07002035 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002037 table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05002038 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002039 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040
Li RongQing5744dd92012-09-11 21:59:01 +00002041 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01002042 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05002043 if (dev == rt->dst.dev &&
YOSHIFUJI Hideaki045927f2006-03-20 17:00:48 -08002044 ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 ipv6_addr_equal(&rt->rt6i_gateway, addr))
2046 break;
2047 }
2048 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07002049 dst_hold(&rt->dst);
Li RongQing5744dd92012-09-11 21:59:01 +00002050 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 return rt;
2052}
2053
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002054struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08002055 struct net_device *dev,
2056 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057{
Thomas Graf86872cb2006-08-22 00:01:08 -07002058 struct fib6_config cfg = {
2059 .fc_table = RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08002060 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07002061 .fc_ifindex = dev->ifindex,
2062 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
2063 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00002064 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08002065 .fc_nlinfo.nlh = NULL,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002066 .fc_nlinfo.nl_net = dev_net(dev),
Thomas Graf86872cb2006-08-22 00:01:08 -07002067 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002069 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070
Thomas Graf86872cb2006-08-22 00:01:08 -07002071 ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 return rt6_get_dflt_router(gwaddr, dev);
2074}
2075
Daniel Lezcano7b4da532008-03-04 13:47:14 -08002076void rt6_purge_dflt_routers(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077{
2078 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07002079 struct fib6_table *table;
2080
2081 /* NOTE: Keep consistent with rt6_get_dflt_router */
Daniel Lezcano7b4da532008-03-04 13:47:14 -08002082 table = fib6_get_table(net, RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05002083 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002084 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085
2086restart:
Thomas Grafc71099a2006-08-04 23:20:06 -07002087 read_lock_bh(&table->tb6_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07002088 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
Lorenzo Colitti3e8b0ac2013-03-03 20:46:46 +00002089 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
2090 (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002091 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07002092 read_unlock_bh(&table->tb6_lock);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002093 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 goto restart;
2095 }
2096 }
Thomas Grafc71099a2006-08-04 23:20:06 -07002097 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098}
2099
Daniel Lezcano55786892008-03-04 13:47:47 -08002100static void rtmsg_to_fib6_config(struct net *net,
2101 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07002102 struct fib6_config *cfg)
2103{
2104 memset(cfg, 0, sizeof(*cfg));
2105
2106 cfg->fc_table = RT6_TABLE_MAIN;
2107 cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
2108 cfg->fc_metric = rtmsg->rtmsg_metric;
2109 cfg->fc_expires = rtmsg->rtmsg_info;
2110 cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
2111 cfg->fc_src_len = rtmsg->rtmsg_src_len;
2112 cfg->fc_flags = rtmsg->rtmsg_flags;
2113
Daniel Lezcano55786892008-03-04 13:47:47 -08002114 cfg->fc_nlinfo.nl_net = net;
Benjamin Theryf1243c22008-02-26 18:10:03 -08002115
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002116 cfg->fc_dst = rtmsg->rtmsg_dst;
2117 cfg->fc_src = rtmsg->rtmsg_src;
2118 cfg->fc_gateway = rtmsg->rtmsg_gateway;
Thomas Graf86872cb2006-08-22 00:01:08 -07002119}
2120
Daniel Lezcano55786892008-03-04 13:47:47 -08002121int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122{
Thomas Graf86872cb2006-08-22 00:01:08 -07002123 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 struct in6_rtmsg rtmsg;
2125 int err;
2126
Ian Morris67ba4152014-08-24 21:53:10 +01002127 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 case SIOCADDRT: /* Add a route */
2129 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00002130 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 return -EPERM;
2132 err = copy_from_user(&rtmsg, arg,
2133 sizeof(struct in6_rtmsg));
2134 if (err)
2135 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07002136
Daniel Lezcano55786892008-03-04 13:47:47 -08002137 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07002138
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 rtnl_lock();
2140 switch (cmd) {
2141 case SIOCADDRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07002142 err = ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 break;
2144 case SIOCDELRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07002145 err = ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 break;
2147 default:
2148 err = -EINVAL;
2149 }
2150 rtnl_unlock();
2151
2152 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07002153 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154
2155 return -EINVAL;
2156}
2157
2158/*
2159 * Drop the packet on the floor
2160 */
2161
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07002162static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002164 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00002165 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002166 switch (ipstats_mib_noroutes) {
2167 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07002168 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00002169 if (type == IPV6_ADDR_ANY) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002170 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2171 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002172 break;
2173 }
2174 /* FALLTHROUGH */
2175 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002176 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2177 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002178 break;
2179 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002180 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 kfree_skb(skb);
2182 return 0;
2183}
2184
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002185static int ip6_pkt_discard(struct sk_buff *skb)
2186{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002187 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002188}
2189
Eric Dumazetaad88722014-04-15 13:47:15 -04002190static int ip6_pkt_discard_out(struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191{
Eric Dumazetadf30902009-06-02 05:19:30 +00002192 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002193 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194}
2195
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002196static int ip6_pkt_prohibit(struct sk_buff *skb)
2197{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002198 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002199}
2200
Eric Dumazetaad88722014-04-15 13:47:15 -04002201static int ip6_pkt_prohibit_out(struct sock *sk, struct sk_buff *skb)
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002202{
Eric Dumazetadf30902009-06-02 05:19:30 +00002203 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002204 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002205}
2206
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207/*
2208 * Allocate a dst for local (unicast / anycast) address.
2209 */
2210
2211struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
2212 const struct in6_addr *addr,
David S. Miller8f031512011-12-06 16:48:14 -05002213 bool anycast)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002215 struct net *net = dev_net(idev->dev);
Hannes Frederic Sowaa3300ef2013-12-07 03:33:45 +01002216 struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev,
2217 DST_NOCOUNT, NULL);
2218 if (!rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 return ERR_PTR(-ENOMEM);
2220
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 in6_dev_hold(idev);
2222
David S. Miller11d53b42011-06-24 15:23:34 -07002223 rt->dst.flags |= DST_HOST;
Changli Gaod8d1f302010-06-10 23:31:35 -07002224 rt->dst.input = ip6_input;
2225 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 rt->rt6i_idev = idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227
2228 rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +09002229 if (anycast)
2230 rt->rt6i_flags |= RTF_ANYCAST;
2231 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 rt->rt6i_flags |= RTF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233
Julian Anastasov550bab42013-10-20 15:43:04 +03002234 rt->rt6i_gateway = *addr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002235 rt->rt6i_dst.addr = *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 rt->rt6i_dst.plen = 128;
Daniel Lezcano55786892008-03-04 13:47:47 -08002237 rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238
Changli Gaod8d1f302010-06-10 23:31:35 -07002239 atomic_set(&rt->dst.__refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240
2241 return rt;
2242}
2243
Daniel Walterc3968a82011-04-13 21:10:57 +00002244int ip6_route_get_saddr(struct net *net,
2245 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002246 const struct in6_addr *daddr,
Daniel Walterc3968a82011-04-13 21:10:57 +00002247 unsigned int prefs,
2248 struct in6_addr *saddr)
2249{
Ian Morris67ba4152014-08-24 21:53:10 +01002250 struct inet6_dev *idev = ip6_dst_idev((struct dst_entry *)rt);
Daniel Walterc3968a82011-04-13 21:10:57 +00002251 int err = 0;
2252 if (rt->rt6i_prefsrc.plen)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002253 *saddr = rt->rt6i_prefsrc.addr;
Daniel Walterc3968a82011-04-13 21:10:57 +00002254 else
2255 err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
2256 daddr, prefs, saddr);
2257 return err;
2258}
2259
2260/* remove deleted ip from prefsrc entries */
2261struct arg_dev_net_ip {
2262 struct net_device *dev;
2263 struct net *net;
2264 struct in6_addr *addr;
2265};
2266
2267static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
2268{
2269 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
2270 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
2271 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
2272
David S. Millerd1918542011-12-28 20:19:20 -05002273 if (((void *)rt->dst.dev == dev || !dev) &&
Daniel Walterc3968a82011-04-13 21:10:57 +00002274 rt != net->ipv6.ip6_null_entry &&
2275 ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
2276 /* remove prefsrc entry */
2277 rt->rt6i_prefsrc.plen = 0;
2278 }
2279 return 0;
2280}
2281
2282void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
2283{
2284 struct net *net = dev_net(ifp->idev->dev);
2285 struct arg_dev_net_ip adni = {
2286 .dev = ifp->idev->dev,
2287 .net = net,
2288 .addr = &ifp->addr,
2289 };
Li RongQing0c3584d2013-12-27 16:32:38 +08002290 fib6_clean_all(net, fib6_remove_prefsrc, &adni);
Daniel Walterc3968a82011-04-13 21:10:57 +00002291}
2292
Duan Jiongbe7a0102014-05-15 15:56:14 +08002293#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY)
2294#define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE)
2295
2296/* Remove routers and update dst entries when gateway turn into host. */
2297static int fib6_clean_tohost(struct rt6_info *rt, void *arg)
2298{
2299 struct in6_addr *gateway = (struct in6_addr *)arg;
2300
2301 if ((((rt->rt6i_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) ||
2302 ((rt->rt6i_flags & RTF_CACHE_GATEWAY) == RTF_CACHE_GATEWAY)) &&
2303 ipv6_addr_equal(gateway, &rt->rt6i_gateway)) {
2304 return -1;
2305 }
2306 return 0;
2307}
2308
2309void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
2310{
2311 fib6_clean_all(net, fib6_clean_tohost, gateway);
2312}
2313
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002314struct arg_dev_net {
2315 struct net_device *dev;
2316 struct net *net;
2317};
2318
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319static int fib6_ifdown(struct rt6_info *rt, void *arg)
2320{
stephen hemmingerbc3ef662010-12-16 17:42:40 +00002321 const struct arg_dev_net *adn = arg;
2322 const struct net_device *dev = adn->dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002323
David S. Millerd1918542011-12-28 20:19:20 -05002324 if ((rt->dst.dev == dev || !dev) &&
David S. Millerc159d302011-12-26 15:24:36 -05002325 rt != adn->net->ipv6.ip6_null_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 return -1;
David S. Millerc159d302011-12-26 15:24:36 -05002327
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 return 0;
2329}
2330
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002331void rt6_ifdown(struct net *net, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002333 struct arg_dev_net adn = {
2334 .dev = dev,
2335 .net = net,
2336 };
2337
Li RongQing0c3584d2013-12-27 16:32:38 +08002338 fib6_clean_all(net, fib6_ifdown, &adn);
David S. Miller1e493d12008-09-10 17:27:15 -07002339 icmp6_clean_all(fib6_ifdown, &adn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340}
2341
Eric Dumazet95c96172012-04-15 05:58:06 +00002342struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00002344 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345};
2346
2347static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
2348{
2349 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
2350 struct inet6_dev *idev;
2351
2352 /* In IPv6 pmtu discovery is not optional,
2353 so that RTAX_MTU lock cannot disable it.
2354 We still use this lock to block changes
2355 caused by addrconf/ndisc.
2356 */
2357
2358 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05002359 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 return 0;
2361
2362 /* For administrative MTU increase, there is no way to discover
2363 IPv6 PMTU increase, so PMTU increase should be updated here.
2364 Since RFC 1981 doesn't include administrative MTU increase
2365 update PMTU increase is a MUST. (i.e. jumbo frame)
2366 */
2367 /*
2368 If new MTU is less than route PMTU, this new MTU will be the
2369 lowest MTU in the path, update the route PMTU to reflect PMTU
2370 decreases; if new MTU is greater than route PMTU, and the
2371 old MTU is the lowest MTU in the path, update the route PMTU
2372 to reflect the increase. In this case if the other nodes' MTU
2373 also have the lowest MTU, TOO BIG MESSAGE will be lead to
2374 PMTU discouvery.
2375 */
David S. Millerd1918542011-12-28 20:19:20 -05002376 if (rt->dst.dev == arg->dev &&
Changli Gaod8d1f302010-06-10 23:31:35 -07002377 !dst_metric_locked(&rt->dst, RTAX_MTU) &&
2378 (dst_mtu(&rt->dst) >= arg->mtu ||
2379 (dst_mtu(&rt->dst) < arg->mtu &&
2380 dst_mtu(&rt->dst) == idev->cnf.mtu6))) {
David S. Millerdefb3512010-12-08 21:16:57 -08002381 dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu);
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) },
Thomas Graf86872cb2006-08-22 00:01:08 -07002403};
2404
2405static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
2406 struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407{
Thomas Graf86872cb2006-08-22 00:01:08 -07002408 struct rtmsg *rtm;
2409 struct nlattr *tb[RTA_MAX+1];
2410 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411
Thomas Graf86872cb2006-08-22 00:01:08 -07002412 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2413 if (err < 0)
2414 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415
Thomas Graf86872cb2006-08-22 00:01:08 -07002416 err = -EINVAL;
2417 rtm = nlmsg_data(nlh);
2418 memset(cfg, 0, sizeof(*cfg));
2419
2420 cfg->fc_table = rtm->rtm_table;
2421 cfg->fc_dst_len = rtm->rtm_dst_len;
2422 cfg->fc_src_len = rtm->rtm_src_len;
2423 cfg->fc_flags = RTF_UP;
2424 cfg->fc_protocol = rtm->rtm_protocol;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002425 cfg->fc_type = rtm->rtm_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07002426
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002427 if (rtm->rtm_type == RTN_UNREACHABLE ||
2428 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002429 rtm->rtm_type == RTN_PROHIBIT ||
2430 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07002431 cfg->fc_flags |= RTF_REJECT;
2432
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002433 if (rtm->rtm_type == RTN_LOCAL)
2434 cfg->fc_flags |= RTF_LOCAL;
2435
Eric W. Biederman15e47302012-09-07 20:12:54 +00002436 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
Thomas Graf86872cb2006-08-22 00:01:08 -07002437 cfg->fc_nlinfo.nlh = nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002438 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
Thomas Graf86872cb2006-08-22 00:01:08 -07002439
2440 if (tb[RTA_GATEWAY]) {
2441 nla_memcpy(&cfg->fc_gateway, tb[RTA_GATEWAY], 16);
2442 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002444
2445 if (tb[RTA_DST]) {
2446 int plen = (rtm->rtm_dst_len + 7) >> 3;
2447
2448 if (nla_len(tb[RTA_DST]) < plen)
2449 goto errout;
2450
2451 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002453
2454 if (tb[RTA_SRC]) {
2455 int plen = (rtm->rtm_src_len + 7) >> 3;
2456
2457 if (nla_len(tb[RTA_SRC]) < plen)
2458 goto errout;
2459
2460 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002462
Daniel Walterc3968a82011-04-13 21:10:57 +00002463 if (tb[RTA_PREFSRC])
2464 nla_memcpy(&cfg->fc_prefsrc, tb[RTA_PREFSRC], 16);
2465
Thomas Graf86872cb2006-08-22 00:01:08 -07002466 if (tb[RTA_OIF])
2467 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
2468
2469 if (tb[RTA_PRIORITY])
2470 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
2471
2472 if (tb[RTA_METRICS]) {
2473 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
2474 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002476
2477 if (tb[RTA_TABLE])
2478 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
2479
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002480 if (tb[RTA_MULTIPATH]) {
2481 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
2482 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
2483 }
2484
Thomas Graf86872cb2006-08-22 00:01:08 -07002485 err = 0;
2486errout:
2487 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488}
2489
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002490static int ip6_route_multipath(struct fib6_config *cfg, int add)
2491{
2492 struct fib6_config r_cfg;
2493 struct rtnexthop *rtnh;
2494 int remaining;
2495 int attrlen;
2496 int err = 0, last_err = 0;
2497
2498beginning:
2499 rtnh = (struct rtnexthop *)cfg->fc_mp;
2500 remaining = cfg->fc_mp_len;
2501
2502 /* Parse a Multipath Entry */
2503 while (rtnh_ok(rtnh, remaining)) {
2504 memcpy(&r_cfg, cfg, sizeof(*cfg));
2505 if (rtnh->rtnh_ifindex)
2506 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
2507
2508 attrlen = rtnh_attrlen(rtnh);
2509 if (attrlen > 0) {
2510 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
2511
2512 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
2513 if (nla) {
2514 nla_memcpy(&r_cfg.fc_gateway, nla, 16);
2515 r_cfg.fc_flags |= RTF_GATEWAY;
2516 }
2517 }
2518 err = add ? ip6_route_add(&r_cfg) : ip6_route_del(&r_cfg);
2519 if (err) {
2520 last_err = err;
2521 /* If we are trying to remove a route, do not stop the
2522 * loop when ip6_route_del() fails (because next hop is
2523 * already gone), we should try to remove all next hops.
2524 */
2525 if (add) {
2526 /* If add fails, we should try to delete all
2527 * next hops that have been already added.
2528 */
2529 add = 0;
2530 goto beginning;
2531 }
2532 }
Nicolas Dichtel1a724182012-11-01 22:58:22 +00002533 /* Because each route is added like a single route we remove
2534 * this flag after the first nexthop (if there is a collision,
2535 * we have already fail to add the first nexthop:
2536 * fib6_add_rt2node() has reject it).
2537 */
2538 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~NLM_F_EXCL;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002539 rtnh = rtnh_next(rtnh, &remaining);
2540 }
2541
2542 return last_err;
2543}
2544
Ian Morris67ba4152014-08-24 21:53:10 +01002545static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546{
Thomas Graf86872cb2006-08-22 00:01:08 -07002547 struct fib6_config cfg;
2548 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549
Thomas Graf86872cb2006-08-22 00:01:08 -07002550 err = rtm_to_fib6_config(skb, nlh, &cfg);
2551 if (err < 0)
2552 return err;
2553
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002554 if (cfg.fc_mp)
2555 return ip6_route_multipath(&cfg, 0);
2556 else
2557 return ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558}
2559
Ian Morris67ba4152014-08-24 21:53:10 +01002560static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561{
Thomas Graf86872cb2006-08-22 00:01:08 -07002562 struct fib6_config cfg;
2563 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564
Thomas Graf86872cb2006-08-22 00:01:08 -07002565 err = rtm_to_fib6_config(skb, nlh, &cfg);
2566 if (err < 0)
2567 return err;
2568
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002569 if (cfg.fc_mp)
2570 return ip6_route_multipath(&cfg, 1);
2571 else
2572 return ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573}
2574
Thomas Graf339bf982006-11-10 14:10:15 -08002575static inline size_t rt6_nlmsg_size(void)
2576{
2577 return NLMSG_ALIGN(sizeof(struct rtmsg))
2578 + nla_total_size(16) /* RTA_SRC */
2579 + nla_total_size(16) /* RTA_DST */
2580 + nla_total_size(16) /* RTA_GATEWAY */
2581 + nla_total_size(16) /* RTA_PREFSRC */
2582 + nla_total_size(4) /* RTA_TABLE */
2583 + nla_total_size(4) /* RTA_IIF */
2584 + nla_total_size(4) /* RTA_OIF */
2585 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08002586 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Daniel Borkmannea697632015-01-05 23:57:47 +01002587 + nla_total_size(sizeof(struct rta_cacheinfo))
2588 + nla_total_size(TCP_CA_NAME_MAX); /* RTAX_CC_ALGO */
Thomas Graf339bf982006-11-10 14:10:15 -08002589}
2590
Brian Haley191cd582008-08-14 15:33:21 -07002591static int rt6_fill_node(struct net *net,
2592 struct sk_buff *skb, struct rt6_info *rt,
Jamal Hadi Salim0d51aa82005-06-21 13:51:04 -07002593 struct in6_addr *dst, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002594 int iif, int type, u32 portid, u32 seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002595 int prefix, int nowait, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596{
2597 struct rtmsg *rtm;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002598 struct nlmsghdr *nlh;
Thomas Grafe3703b32006-11-27 09:27:07 -08002599 long expires;
Patrick McHardy9e762a42006-08-10 23:09:48 -07002600 u32 table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601
2602 if (prefix) { /* user wants prefix routes only */
2603 if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
2604 /* success since this is not a prefix route */
2605 return 1;
2606 }
2607 }
2608
Eric W. Biederman15e47302012-09-07 20:12:54 +00002609 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05002610 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08002611 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002612
2613 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 rtm->rtm_family = AF_INET6;
2615 rtm->rtm_dst_len = rt->rt6i_dst.plen;
2616 rtm->rtm_src_len = rt->rt6i_src.plen;
2617 rtm->rtm_tos = 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07002618 if (rt->rt6i_table)
Patrick McHardy9e762a42006-08-10 23:09:48 -07002619 table = rt->rt6i_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07002620 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07002621 table = RT6_TABLE_UNSPEC;
2622 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04002623 if (nla_put_u32(skb, RTA_TABLE, table))
2624 goto nla_put_failure;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002625 if (rt->rt6i_flags & RTF_REJECT) {
2626 switch (rt->dst.error) {
2627 case -EINVAL:
2628 rtm->rtm_type = RTN_BLACKHOLE;
2629 break;
2630 case -EACCES:
2631 rtm->rtm_type = RTN_PROHIBIT;
2632 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002633 case -EAGAIN:
2634 rtm->rtm_type = RTN_THROW;
2635 break;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002636 default:
2637 rtm->rtm_type = RTN_UNREACHABLE;
2638 break;
2639 }
2640 }
David S. Miller38308472011-12-03 18:02:47 -05002641 else if (rt->rt6i_flags & RTF_LOCAL)
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002642 rtm->rtm_type = RTN_LOCAL;
David S. Millerd1918542011-12-28 20:19:20 -05002643 else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 rtm->rtm_type = RTN_LOCAL;
2645 else
2646 rtm->rtm_type = RTN_UNICAST;
2647 rtm->rtm_flags = 0;
2648 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
2649 rtm->rtm_protocol = rt->rt6i_protocol;
David S. Miller38308472011-12-03 18:02:47 -05002650 if (rt->rt6i_flags & RTF_DYNAMIC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 rtm->rtm_protocol = RTPROT_REDIRECT;
Denis Ovsienkof0396f602012-07-10 04:45:50 +00002652 else if (rt->rt6i_flags & RTF_ADDRCONF) {
2653 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ROUTEINFO))
2654 rtm->rtm_protocol = RTPROT_RA;
2655 else
2656 rtm->rtm_protocol = RTPROT_KERNEL;
2657 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658
David S. Miller38308472011-12-03 18:02:47 -05002659 if (rt->rt6i_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 rtm->rtm_flags |= RTM_F_CLONED;
2661
2662 if (dst) {
David S. Millerc78679e2012-04-01 20:27:33 -04002663 if (nla_put(skb, RTA_DST, 16, dst))
2664 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002665 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 } else if (rtm->rtm_dst_len)
David S. Millerc78679e2012-04-01 20:27:33 -04002667 if (nla_put(skb, RTA_DST, 16, &rt->rt6i_dst.addr))
2668 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669#ifdef CONFIG_IPV6_SUBTREES
2670 if (src) {
David S. Millerc78679e2012-04-01 20:27:33 -04002671 if (nla_put(skb, RTA_SRC, 16, src))
2672 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002673 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04002674 } else if (rtm->rtm_src_len &&
2675 nla_put(skb, RTA_SRC, 16, &rt->rt6i_src.addr))
2676 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002678 if (iif) {
2679#ifdef CONFIG_IPV6_MROUTE
2680 if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
Benjamin Thery8229efd2008-12-10 16:30:15 -08002681 int err = ip6mr_get_route(net, skb, rtm, nowait);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002682 if (err <= 0) {
2683 if (!nowait) {
2684 if (err == 0)
2685 return 0;
2686 goto nla_put_failure;
2687 } else {
2688 if (err == -EMSGSIZE)
2689 goto nla_put_failure;
2690 }
2691 }
2692 } else
2693#endif
David S. Millerc78679e2012-04-01 20:27:33 -04002694 if (nla_put_u32(skb, RTA_IIF, iif))
2695 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002696 } else if (dst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 struct in6_addr saddr_buf;
David S. Millerc78679e2012-04-01 20:27:33 -04002698 if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0 &&
2699 nla_put(skb, RTA_PREFSRC, 16, &saddr_buf))
2700 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07002702
Daniel Walterc3968a82011-04-13 21:10:57 +00002703 if (rt->rt6i_prefsrc.plen) {
2704 struct in6_addr saddr_buf;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002705 saddr_buf = rt->rt6i_prefsrc.addr;
David S. Millerc78679e2012-04-01 20:27:33 -04002706 if (nla_put(skb, RTA_PREFSRC, 16, &saddr_buf))
2707 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00002708 }
2709
David S. Millerdefb3512010-12-08 21:16:57 -08002710 if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07002711 goto nla_put_failure;
2712
YOSHIFUJI Hideaki / 吉藤英明dd0cbf22013-01-17 12:53:15 +00002713 if (rt->rt6i_flags & RTF_GATEWAY) {
2714 if (nla_put(skb, RTA_GATEWAY, 16, &rt->rt6i_gateway) < 0)
Eric Dumazet94f826b2012-03-27 09:53:52 +00002715 goto nla_put_failure;
Eric Dumazet94f826b2012-03-27 09:53:52 +00002716 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07002717
David S. Millerc78679e2012-04-01 20:27:33 -04002718 if (rt->dst.dev &&
2719 nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex))
2720 goto nla_put_failure;
2721 if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric))
2722 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00002723
2724 expires = (rt->rt6i_flags & RTF_EXPIRES) ? rt->dst.expires - jiffies : 0;
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07002725
David S. Miller87a50692012-07-10 05:06:14 -07002726 if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, rt->dst.error) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08002727 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728
Johannes Berg053c0952015-01-16 22:09:00 +01002729 nlmsg_end(skb, nlh);
2730 return 0;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002731
2732nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002733 nlmsg_cancel(skb, nlh);
2734 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735}
2736
Patrick McHardy1b43af52006-08-10 23:11:17 -07002737int rt6_dump_route(struct rt6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738{
2739 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
2740 int prefix;
2741
Thomas Graf2d7202b2006-08-22 00:01:27 -07002742 if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
2743 struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0;
2745 } else
2746 prefix = 0;
2747
Brian Haley191cd582008-08-14 15:33:21 -07002748 return rt6_fill_node(arg->net,
2749 arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002750 NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002751 prefix, 0, NLM_F_MULTI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752}
2753
Ian Morris67ba4152014-08-24 21:53:10 +01002754static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002756 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07002757 struct nlattr *tb[RTA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07002759 struct sk_buff *skb;
2760 struct rtmsg *rtm;
David S. Miller4c9483b2011-03-12 16:22:43 -05002761 struct flowi6 fl6;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002762 int err, iif = 0, oif = 0;
Thomas Grafab364a62006-08-22 00:01:47 -07002763
2764 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2765 if (err < 0)
2766 goto errout;
2767
2768 err = -EINVAL;
David S. Miller4c9483b2011-03-12 16:22:43 -05002769 memset(&fl6, 0, sizeof(fl6));
Thomas Grafab364a62006-08-22 00:01:47 -07002770
2771 if (tb[RTA_SRC]) {
2772 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
2773 goto errout;
2774
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002775 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07002776 }
2777
2778 if (tb[RTA_DST]) {
2779 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
2780 goto errout;
2781
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002782 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07002783 }
2784
2785 if (tb[RTA_IIF])
2786 iif = nla_get_u32(tb[RTA_IIF]);
2787
2788 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002789 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07002790
Lorenzo Colitti2e47b292014-05-15 16:38:41 -07002791 if (tb[RTA_MARK])
2792 fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
2793
Thomas Grafab364a62006-08-22 00:01:47 -07002794 if (iif) {
2795 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002796 int flags = 0;
2797
Daniel Lezcano55786892008-03-04 13:47:47 -08002798 dev = __dev_get_by_index(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07002799 if (!dev) {
2800 err = -ENODEV;
2801 goto errout;
2802 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002803
2804 fl6.flowi6_iif = iif;
2805
2806 if (!ipv6_addr_any(&fl6.saddr))
2807 flags |= RT6_LOOKUP_F_HAS_SADDR;
2808
2809 rt = (struct rt6_info *)ip6_route_input_lookup(net, dev, &fl6,
2810 flags);
2811 } else {
2812 fl6.flowi6_oif = oif;
2813
2814 rt = (struct rt6_info *)ip6_route_output(net, NULL, &fl6);
Thomas Grafab364a62006-08-22 00:01:47 -07002815 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816
2817 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05002818 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00002819 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07002820 err = -ENOBUFS;
2821 goto errout;
2822 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823
2824 /* Reserve room for dummy headers, this skb can pass
2825 through good chunk of routing engine.
2826 */
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07002827 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
2829
Changli Gaod8d1f302010-06-10 23:31:35 -07002830 skb_dst_set(skb, &rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831
David S. Miller4c9483b2011-03-12 16:22:43 -05002832 err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002833 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002834 nlh->nlmsg_seq, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07002836 kfree_skb(skb);
2837 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 }
2839
Eric W. Biederman15e47302012-09-07 20:12:54 +00002840 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07002841errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843}
2844
Thomas Graf86872cb2006-08-22 00:01:08 -07002845void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846{
2847 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08002848 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002849 u32 seq;
2850 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002852 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05002853 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07002854
Thomas Graf339bf982006-11-10 14:10:15 -08002855 skb = nlmsg_new(rt6_nlmsg_size(), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05002856 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07002857 goto errout;
2858
Brian Haley191cd582008-08-14 15:33:21 -07002859 err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002860 event, info->portid, seq, 0, 0, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08002861 if (err < 0) {
2862 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
2863 WARN_ON(err == -EMSGSIZE);
2864 kfree_skb(skb);
2865 goto errout;
2866 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00002867 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08002868 info->nlh, gfp_any());
2869 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07002870errout:
2871 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08002872 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873}
2874
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002875static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00002876 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002877{
Jiri Pirko351638e2013-05-28 01:30:21 +00002878 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002879 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002880
2881 if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002882 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002883 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
2884#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07002885 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002886 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07002887 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002888 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
2889#endif
2890 }
2891
2892 return NOTIFY_OK;
2893}
2894
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895/*
2896 * /proc
2897 */
2898
2899#ifdef CONFIG_PROC_FS
2900
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002901static const struct file_operations ipv6_route_proc_fops = {
2902 .owner = THIS_MODULE,
2903 .open = ipv6_route_open,
2904 .read = seq_read,
2905 .llseek = seq_lseek,
Hannes Frederic Sowa8d2ca1d2013-09-21 16:55:59 +02002906 .release = seq_release_net,
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002907};
2908
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909static int rt6_stats_seq_show(struct seq_file *seq, void *v)
2910{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002911 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002913 net->ipv6.rt6_stats->fib_nodes,
2914 net->ipv6.rt6_stats->fib_route_nodes,
2915 net->ipv6.rt6_stats->fib_rt_alloc,
2916 net->ipv6.rt6_stats->fib_rt_entries,
2917 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00002918 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002919 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920
2921 return 0;
2922}
2923
2924static int rt6_stats_seq_open(struct inode *inode, struct file *file)
2925{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07002926 return single_open_net(inode, file, rt6_stats_seq_show);
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002927}
2928
Arjan van de Ven9a321442007-02-12 00:55:35 -08002929static const struct file_operations rt6_stats_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 .owner = THIS_MODULE,
2931 .open = rt6_stats_seq_open,
2932 .read = seq_read,
2933 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07002934 .release = single_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935};
2936#endif /* CONFIG_PROC_FS */
2937
2938#ifdef CONFIG_SYSCTL
2939
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940static
Joe Perchesfe2c6332013-06-11 23:04:25 -07002941int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 void __user *buffer, size_t *lenp, loff_t *ppos)
2943{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00002944 struct net *net;
2945 int delay;
2946 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00002948
2949 net = (struct net *)ctl->extra1;
2950 delay = net->ipv6.sysctl.flush_delay;
2951 proc_dointvec(ctl, write, buffer, lenp, ppos);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02002952 fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00002953 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954}
2955
Joe Perchesfe2c6332013-06-11 23:04:25 -07002956struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002957 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08002959 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07002961 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002962 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 },
2964 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08002966 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 .maxlen = sizeof(int),
2968 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002969 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 },
2971 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08002973 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 .maxlen = sizeof(int),
2975 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002976 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 },
2978 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08002980 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 .maxlen = sizeof(int),
2982 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002983 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 },
2985 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08002987 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 .maxlen = sizeof(int),
2989 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002990 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 },
2992 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08002994 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 .maxlen = sizeof(int),
2996 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002997 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 },
2999 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08003001 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 .maxlen = sizeof(int),
3003 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003004 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 },
3006 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08003008 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 .maxlen = sizeof(int),
3010 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003011 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 },
3013 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08003015 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 .maxlen = sizeof(int),
3017 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003018 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019 },
3020 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08003022 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 .maxlen = sizeof(int),
3024 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003025 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08003027 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028};
3029
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003030struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003031{
3032 struct ctl_table *table;
3033
3034 table = kmemdup(ipv6_route_table_template,
3035 sizeof(ipv6_route_table_template),
3036 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003037
3038 if (table) {
3039 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003040 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003041 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003042 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
3043 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
3044 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
3045 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
3046 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
3047 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
3048 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08003049 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
Eric W. Biederman464dc802012-11-16 03:02:59 +00003050
3051 /* Don't export sysctls to unprivileged users */
3052 if (net->user_ns != &init_user_ns)
3053 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003054 }
3055
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003056 return table;
3057}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058#endif
3059
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003060static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003061{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07003062 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003063
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003064 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
3065 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003066
Eric Dumazetfc66f952010-10-08 06:37:34 +00003067 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
3068 goto out_ip6_dst_ops;
3069
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003070 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
3071 sizeof(*net->ipv6.ip6_null_entry),
3072 GFP_KERNEL);
3073 if (!net->ipv6.ip6_null_entry)
Eric Dumazetfc66f952010-10-08 06:37:34 +00003074 goto out_ip6_dst_entries;
Changli Gaod8d1f302010-06-10 23:31:35 -07003075 net->ipv6.ip6_null_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003076 (struct dst_entry *)net->ipv6.ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003077 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003078 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
3079 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003080
3081#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3082 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
3083 sizeof(*net->ipv6.ip6_prohibit_entry),
3084 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003085 if (!net->ipv6.ip6_prohibit_entry)
3086 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003087 net->ipv6.ip6_prohibit_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003088 (struct dst_entry *)net->ipv6.ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003089 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003090 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
3091 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003092
3093 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
3094 sizeof(*net->ipv6.ip6_blk_hole_entry),
3095 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003096 if (!net->ipv6.ip6_blk_hole_entry)
3097 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003098 net->ipv6.ip6_blk_hole_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003099 (struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003100 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003101 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
3102 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003103#endif
3104
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07003105 net->ipv6.sysctl.flush_delay = 0;
3106 net->ipv6.sysctl.ip6_rt_max_size = 4096;
3107 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
3108 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
3109 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
3110 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
3111 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
3112 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
3113
Benjamin Thery6891a342008-03-04 13:49:47 -08003114 net->ipv6.ip6_rt_gc_expire = 30*HZ;
3115
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003116 ret = 0;
3117out:
3118 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003119
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003120#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3121out_ip6_prohibit_entry:
3122 kfree(net->ipv6.ip6_prohibit_entry);
3123out_ip6_null_entry:
3124 kfree(net->ipv6.ip6_null_entry);
3125#endif
Eric Dumazetfc66f952010-10-08 06:37:34 +00003126out_ip6_dst_entries:
3127 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003128out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003129 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003130}
3131
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003132static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003133{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003134 kfree(net->ipv6.ip6_null_entry);
3135#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3136 kfree(net->ipv6.ip6_prohibit_entry);
3137 kfree(net->ipv6.ip6_blk_hole_entry);
3138#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003139 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003140}
3141
Thomas Grafd1896342012-06-18 12:08:33 +00003142static int __net_init ip6_route_net_init_late(struct net *net)
3143{
3144#ifdef CONFIG_PROC_FS
Gao fengd4beaa62013-02-18 01:34:54 +00003145 proc_create("ipv6_route", 0, net->proc_net, &ipv6_route_proc_fops);
3146 proc_create("rt6_stats", S_IRUGO, net->proc_net, &rt6_stats_seq_fops);
Thomas Grafd1896342012-06-18 12:08:33 +00003147#endif
3148 return 0;
3149}
3150
3151static void __net_exit ip6_route_net_exit_late(struct net *net)
3152{
3153#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00003154 remove_proc_entry("ipv6_route", net->proc_net);
3155 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00003156#endif
3157}
3158
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003159static struct pernet_operations ip6_route_net_ops = {
3160 .init = ip6_route_net_init,
3161 .exit = ip6_route_net_exit,
3162};
3163
David S. Millerc3426b42012-06-09 16:27:05 -07003164static int __net_init ipv6_inetpeer_init(struct net *net)
3165{
3166 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
3167
3168 if (!bp)
3169 return -ENOMEM;
3170 inet_peer_base_init(bp);
3171 net->ipv6.peers = bp;
3172 return 0;
3173}
3174
3175static void __net_exit ipv6_inetpeer_exit(struct net *net)
3176{
3177 struct inet_peer_base *bp = net->ipv6.peers;
3178
3179 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07003180 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07003181 kfree(bp);
3182}
3183
David S. Miller2b823f72012-06-09 19:00:16 -07003184static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07003185 .init = ipv6_inetpeer_init,
3186 .exit = ipv6_inetpeer_exit,
3187};
3188
Thomas Grafd1896342012-06-18 12:08:33 +00003189static struct pernet_operations ip6_route_net_late_ops = {
3190 .init = ip6_route_net_init_late,
3191 .exit = ip6_route_net_exit_late,
3192};
3193
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003194static struct notifier_block ip6_route_dev_notifier = {
3195 .notifier_call = ip6_route_dev_notify,
3196 .priority = 0,
3197};
3198
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003199int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003201 int ret;
3202
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003203 ret = -ENOMEM;
3204 ip6_dst_ops_template.kmem_cachep =
3205 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
3206 SLAB_HWCACHE_ALIGN, NULL);
3207 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08003208 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07003209
Eric Dumazetfc66f952010-10-08 06:37:34 +00003210 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003211 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003212 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003213
David S. Millerc3426b42012-06-09 16:27:05 -07003214 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
3215 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003216 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00003217
David S. Miller7e52b332012-06-15 15:51:55 -07003218 ret = register_pernet_subsys(&ip6_route_net_ops);
3219 if (ret)
3220 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07003221
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07003222 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
3223
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003224 /* Registering of the loopback is done before this portion of code,
3225 * the loopback reference in rt6_info will not be taken, do it
3226 * manually for init_net */
Changli Gaod8d1f302010-06-10 23:31:35 -07003227 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003228 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3229 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07003230 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003231 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07003232 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003233 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3234 #endif
David S. Millere8803b62012-06-16 01:12:19 -07003235 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003236 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003237 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003238
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003239 ret = xfrm6_init();
3240 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003241 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08003242
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003243 ret = fib6_rules_init();
3244 if (ret)
3245 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08003246
Thomas Grafd1896342012-06-18 12:08:33 +00003247 ret = register_pernet_subsys(&ip6_route_net_late_ops);
3248 if (ret)
3249 goto fib6_rules_init;
3250
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003251 ret = -ENOBUFS;
Greg Rosec7ac8672011-06-10 01:27:09 +00003252 if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) ||
3253 __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) ||
3254 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL))
Thomas Grafd1896342012-06-18 12:08:33 +00003255 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003256
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003257 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003258 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00003259 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003260
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003261out:
3262 return ret;
3263
Thomas Grafd1896342012-06-18 12:08:33 +00003264out_register_late_subsys:
3265 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003266fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003267 fib6_rules_cleanup();
3268xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003269 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00003270out_fib6_init:
3271 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003272out_register_subsys:
3273 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07003274out_register_inetpeer:
3275 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00003276out_dst_entries:
3277 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003278out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003279 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003280 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281}
3282
3283void ip6_route_cleanup(void)
3284{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003285 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00003286 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07003287 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07003290 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003291 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003292 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003293 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294}