blob: 5b127e09c22422f83fef93bed9b1a84d33c51042 [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
Gao feng1716a962012-04-06 00:13:10 +000068static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
Eric Dumazet21efcfa2011-07-19 20:18:36 +000069 const struct in6_addr *dest);
Linus Torvalds1da177e2005-04-16 15:20:36 -070070static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
David S. Miller0dbaee32010-12-13 12:52:14 -080071static unsigned int ip6_default_advmss(const struct dst_entry *dst);
Steffen Klassertebb762f2011-11-23 02:12:51 +000072static unsigned int ip6_mtu(const struct dst_entry *dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -070073static struct dst_entry *ip6_negative_advice(struct dst_entry *);
74static void ip6_dst_destroy(struct dst_entry *);
75static void ip6_dst_ifdown(struct dst_entry *,
76 struct net_device *dev, int how);
Daniel Lezcano569d3642008-01-18 03:56:57 -080077static int ip6_dst_gc(struct dst_ops *ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79static int ip6_pkt_discard(struct sk_buff *skb);
80static int ip6_pkt_discard_out(struct sk_buff *skb);
81static void ip6_link_failure(struct sk_buff *skb);
David S. Miller6700c272012-07-17 03:29:28 -070082static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
83 struct sk_buff *skb, u32 mtu);
84static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
85 struct sk_buff *skb);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +020086static int rt6_score_route(struct rt6_info *rt, int oif, int strict);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -080088#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -080089static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +000090 const struct in6_addr *prefix, int prefixlen,
91 const struct in6_addr *gwaddr, int ifindex,
Eric Dumazet95c96172012-04-15 05:58:06 +000092 unsigned int pref);
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -080093static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +000094 const struct in6_addr *prefix, int prefixlen,
95 const struct in6_addr *gwaddr, int ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -080096#endif
97
David S. Miller06582542011-01-27 14:58:42 -080098static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
99{
100 struct rt6_info *rt = (struct rt6_info *) dst;
101 struct inet_peer *peer;
102 u32 *p = NULL;
103
Yan, Zheng8e2ec632011-09-05 21:34:30 +0000104 if (!(rt->dst.flags & DST_HOST))
105 return NULL;
106
David S. Millerfbfe95a2012-06-08 23:24:18 -0700107 peer = rt6_get_peer_create(rt);
David S. Miller06582542011-01-27 14:58:42 -0800108 if (peer) {
109 u32 *old_p = __DST_METRICS_PTR(old);
110 unsigned long prev, new;
111
112 p = peer->metrics;
113 if (inet_metrics_new(peer))
114 memcpy(p, old_p, sizeof(u32) * RTAX_MAX);
115
116 new = (unsigned long) p;
117 prev = cmpxchg(&dst->_metrics, old, new);
118
119 if (prev != old) {
120 p = __DST_METRICS_PTR(prev);
121 if (prev & DST_METRICS_READ_ONLY)
122 p = NULL;
123 }
124 }
125 return p;
126}
127
David S. Millerf894cbf2012-07-02 21:52:24 -0700128static inline const void *choose_neigh_daddr(struct rt6_info *rt,
129 struct sk_buff *skb,
130 const void *daddr)
David S. Miller39232972012-01-26 15:22:32 -0500131{
132 struct in6_addr *p = &rt->rt6i_gateway;
133
David S. Millera7563f32012-01-26 16:29:16 -0500134 if (!ipv6_addr_any(p))
David S. Miller39232972012-01-26 15:22:32 -0500135 return (const void *) p;
David S. Millerf894cbf2012-07-02 21:52:24 -0700136 else if (skb)
137 return &ipv6_hdr(skb)->daddr;
David S. Miller39232972012-01-26 15:22:32 -0500138 return daddr;
139}
140
David S. Millerf894cbf2012-07-02 21:52:24 -0700141static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst,
142 struct sk_buff *skb,
143 const void *daddr)
David S. Millerd3aaeb32011-07-18 00:40:17 -0700144{
David S. Miller39232972012-01-26 15:22:32 -0500145 struct rt6_info *rt = (struct rt6_info *) dst;
146 struct neighbour *n;
147
David S. Millerf894cbf2012-07-02 21:52:24 -0700148 daddr = choose_neigh_daddr(rt, skb, daddr);
YOSHIFUJI Hideaki / 吉藤英明8e022ee2013-01-17 12:53:09 +0000149 n = __ipv6_neigh_lookup(dst->dev, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500150 if (n)
151 return n;
152 return neigh_create(&nd_tbl, daddr, dst->dev);
153}
154
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -0800155static struct dst_ops ip6_dst_ops_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 .family = AF_INET6,
Harvey Harrison09640e62009-02-01 00:45:17 -0800157 .protocol = cpu_to_be16(ETH_P_IPV6),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 .gc = ip6_dst_gc,
159 .gc_thresh = 1024,
160 .check = ip6_dst_check,
David S. Miller0dbaee32010-12-13 12:52:14 -0800161 .default_advmss = ip6_default_advmss,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000162 .mtu = ip6_mtu,
David S. Miller06582542011-01-27 14:58:42 -0800163 .cow_metrics = ipv6_cow_metrics,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 .destroy = ip6_dst_destroy,
165 .ifdown = ip6_dst_ifdown,
166 .negative_advice = ip6_negative_advice,
167 .link_failure = ip6_link_failure,
168 .update_pmtu = ip6_rt_update_pmtu,
David S. Miller6e157b62012-07-12 00:05:02 -0700169 .redirect = rt6_do_redirect,
Herbert Xu1ac06e02008-05-20 14:32:14 -0700170 .local_out = __ip6_local_out,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700171 .neigh_lookup = ip6_neigh_lookup,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172};
173
Steffen Klassertebb762f2011-11-23 02:12:51 +0000174static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
Roland Dreierec831ea2011-01-31 13:16:00 -0800175{
Steffen Klassert618f9bc2011-11-23 02:13:31 +0000176 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
177
178 return mtu ? : dst->dev->mtu;
Roland Dreierec831ea2011-01-31 13:16:00 -0800179}
180
David S. Miller6700c272012-07-17 03:29:28 -0700181static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
182 struct sk_buff *skb, u32 mtu)
David S. Miller14e50e52007-05-24 18:17:54 -0700183{
184}
185
David S. Miller6700c272012-07-17 03:29:28 -0700186static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
187 struct sk_buff *skb)
David S. Millerb587ee32012-07-12 00:39:24 -0700188{
189}
190
Held Bernhard0972ddb2011-04-24 22:07:32 +0000191static u32 *ip6_rt_blackhole_cow_metrics(struct dst_entry *dst,
192 unsigned long old)
193{
194 return NULL;
195}
196
David S. Miller14e50e52007-05-24 18:17:54 -0700197static struct dst_ops ip6_dst_blackhole_ops = {
198 .family = AF_INET6,
Harvey Harrison09640e62009-02-01 00:45:17 -0800199 .protocol = cpu_to_be16(ETH_P_IPV6),
David S. Miller14e50e52007-05-24 18:17:54 -0700200 .destroy = ip6_dst_destroy,
201 .check = ip6_dst_check,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000202 .mtu = ip6_blackhole_mtu,
Eric Dumazet214f45c2011-02-18 11:39:01 -0800203 .default_advmss = ip6_default_advmss,
David S. Miller14e50e52007-05-24 18:17:54 -0700204 .update_pmtu = ip6_rt_blackhole_update_pmtu,
David S. Millerb587ee32012-07-12 00:39:24 -0700205 .redirect = ip6_rt_blackhole_redirect,
Held Bernhard0972ddb2011-04-24 22:07:32 +0000206 .cow_metrics = ip6_rt_blackhole_cow_metrics,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700207 .neigh_lookup = ip6_neigh_lookup,
David S. Miller14e50e52007-05-24 18:17:54 -0700208};
209
David S. Miller62fa8a82011-01-26 20:51:05 -0800210static const u32 ip6_template_metrics[RTAX_MAX] = {
Li RongQing14edd872012-10-24 14:01:18 +0800211 [RTAX_HOPLIMIT - 1] = 0,
David S. Miller62fa8a82011-01-26 20:51:05 -0800212};
213
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000214static const struct rt6_info ip6_null_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700215 .dst = {
216 .__refcnt = ATOMIC_INIT(1),
217 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000218 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700219 .error = -ENETUNREACH,
Changli Gaod8d1f302010-06-10 23:31:35 -0700220 .input = ip6_pkt_discard,
221 .output = ip6_pkt_discard_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 },
223 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700224 .rt6i_protocol = RTPROT_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 .rt6i_metric = ~(u32) 0,
226 .rt6i_ref = ATOMIC_INIT(1),
227};
228
Thomas Graf101367c2006-08-04 03:39:02 -0700229#ifdef CONFIG_IPV6_MULTIPLE_TABLES
230
David S. Miller6723ab52006-10-18 21:20:57 -0700231static int ip6_pkt_prohibit(struct sk_buff *skb);
232static int ip6_pkt_prohibit_out(struct sk_buff *skb);
David S. Miller6723ab52006-10-18 21:20:57 -0700233
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000234static const struct rt6_info ip6_prohibit_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700235 .dst = {
236 .__refcnt = ATOMIC_INIT(1),
237 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000238 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700239 .error = -EACCES,
Changli Gaod8d1f302010-06-10 23:31:35 -0700240 .input = ip6_pkt_prohibit,
241 .output = ip6_pkt_prohibit_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700242 },
243 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700244 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700245 .rt6i_metric = ~(u32) 0,
246 .rt6i_ref = ATOMIC_INIT(1),
247};
248
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000249static const struct rt6_info ip6_blk_hole_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700250 .dst = {
251 .__refcnt = ATOMIC_INIT(1),
252 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000253 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700254 .error = -EINVAL,
Changli Gaod8d1f302010-06-10 23:31:35 -0700255 .input = dst_discard,
256 .output = dst_discard,
Thomas Graf101367c2006-08-04 03:39:02 -0700257 },
258 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700259 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700260 .rt6i_metric = ~(u32) 0,
261 .rt6i_ref = ATOMIC_INIT(1),
262};
263
264#endif
265
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266/* allocate dst with ip6_dst_ops */
David S. Miller97bab732012-06-09 22:36:36 -0700267static inline struct rt6_info *ip6_dst_alloc(struct net *net,
David S. Miller957c6652011-06-24 15:25:00 -0700268 struct net_device *dev,
David S. Miller8b96d222012-06-11 02:01:56 -0700269 int flags,
270 struct fib6_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271{
David S. Miller97bab732012-06-09 22:36:36 -0700272 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +0000273 0, DST_OBSOLETE_FORCE_CHK, flags);
David S. Millercf911662011-04-28 14:31:47 -0700274
David S. Miller97bab732012-06-09 22:36:36 -0700275 if (rt) {
Steffen Klassert81048912012-07-05 23:37:09 +0000276 struct dst_entry *dst = &rt->dst;
277
278 memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
David S. Miller8b96d222012-06-11 02:01:56 -0700279 rt6_init_peer(rt, table ? &table->tb6_peers : net->ipv6.peers);
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +0000280 rt->rt6i_genid = rt_genid(net);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000281 INIT_LIST_HEAD(&rt->rt6i_siblings);
282 rt->rt6i_nsiblings = 0;
David S. Miller97bab732012-06-09 22:36:36 -0700283 }
David S. Millercf911662011-04-28 14:31:47 -0700284 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285}
286
287static void ip6_dst_destroy(struct dst_entry *dst)
288{
289 struct rt6_info *rt = (struct rt6_info *)dst;
290 struct inet6_dev *idev = rt->rt6i_idev;
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000291 struct dst_entry *from = dst->from;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
Yan, Zheng8e2ec632011-09-05 21:34:30 +0000293 if (!(rt->dst.flags & DST_HOST))
294 dst_destroy_metrics_generic(dst);
295
David S. Miller38308472011-12-03 18:02:47 -0500296 if (idev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 rt->rt6i_idev = NULL;
298 in6_dev_put(idev);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900299 }
Gao feng1716a962012-04-06 00:13:10 +0000300
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000301 dst->from = NULL;
302 dst_release(from);
Gao feng1716a962012-04-06 00:13:10 +0000303
David S. Miller97bab732012-06-09 22:36:36 -0700304 if (rt6_has_peer(rt)) {
305 struct inet_peer *peer = rt6_peer_ptr(rt);
David S. Millerb3419362010-11-30 12:27:11 -0800306 inet_putpeer(peer);
307 }
308}
309
310void rt6_bind_peer(struct rt6_info *rt, int create)
311{
David S. Miller97bab732012-06-09 22:36:36 -0700312 struct inet_peer_base *base;
David S. Millerb3419362010-11-30 12:27:11 -0800313 struct inet_peer *peer;
314
David S. Miller97bab732012-06-09 22:36:36 -0700315 base = inetpeer_base_ptr(rt->_rt6i_peer);
316 if (!base)
317 return;
318
319 peer = inet_getpeer_v6(base, &rt->rt6i_dst.addr, create);
David S. Miller7b34ca22012-06-11 04:13:57 -0700320 if (peer) {
321 if (!rt6_set_peer(rt, peer))
322 inet_putpeer(peer);
David S. Miller7b34ca22012-06-11 04:13:57 -0700323 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324}
325
326static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
327 int how)
328{
329 struct rt6_info *rt = (struct rt6_info *)dst;
330 struct inet6_dev *idev = rt->rt6i_idev;
Denis V. Lunev5a3e55d2007-12-07 00:38:10 -0800331 struct net_device *loopback_dev =
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900332 dev_net(dev)->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
David S. Miller97cac082012-07-02 22:43:47 -0700334 if (dev != loopback_dev) {
335 if (idev && idev->dev == dev) {
336 struct inet6_dev *loopback_idev =
337 in6_dev_get(loopback_dev);
338 if (loopback_idev) {
339 rt->rt6i_idev = loopback_idev;
340 in6_dev_put(idev);
341 }
342 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 }
344}
345
Eric Dumazeta50feda2012-05-18 18:57:34 +0000346static bool rt6_check_expired(const struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347{
Gao feng1716a962012-04-06 00:13:10 +0000348 if (rt->rt6i_flags & RTF_EXPIRES) {
349 if (time_after(jiffies, rt->dst.expires))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000350 return true;
Gao feng1716a962012-04-06 00:13:10 +0000351 } else if (rt->dst.from) {
Li RongQing3fd91fb2012-09-13 19:54:57 +0000352 return rt6_check_expired((struct rt6_info *) rt->dst.from);
Gao feng1716a962012-04-06 00:13:10 +0000353 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000354 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355}
356
Eric Dumazeta50feda2012-05-18 18:57:34 +0000357static bool rt6_need_strict(const struct in6_addr *daddr)
Thomas Grafc71099a2006-08-04 23:20:06 -0700358{
Eric Dumazeta02cec22010-09-22 20:43:57 +0000359 return ipv6_addr_type(daddr) &
360 (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK);
Thomas Grafc71099a2006-08-04 23:20:06 -0700361}
362
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000363/* Multipath route selection:
364 * Hash based function using packet header and flowlabel.
365 * Adapted from fib_info_hashfn()
366 */
367static int rt6_info_hash_nhsfn(unsigned int candidate_count,
368 const struct flowi6 *fl6)
369{
370 unsigned int val = fl6->flowi6_proto;
371
YOSHIFUJI Hideaki / 吉藤英明c08977b2013-01-13 05:02:29 +0000372 val ^= ipv6_addr_hash(&fl6->daddr);
373 val ^= ipv6_addr_hash(&fl6->saddr);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000374
375 /* Work only if this not encapsulated */
376 switch (fl6->flowi6_proto) {
377 case IPPROTO_UDP:
378 case IPPROTO_TCP:
379 case IPPROTO_SCTP:
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000380 val ^= (__force u16)fl6->fl6_sport;
381 val ^= (__force u16)fl6->fl6_dport;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000382 break;
383
384 case IPPROTO_ICMPV6:
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000385 val ^= (__force u16)fl6->fl6_icmp_type;
386 val ^= (__force u16)fl6->fl6_icmp_code;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000387 break;
388 }
389 /* RFC6438 recommands to use flowlabel */
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000390 val ^= (__force u32)fl6->flowlabel;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000391
392 /* Perhaps, we need to tune, this function? */
393 val = val ^ (val >> 7) ^ (val >> 12);
394 return val % candidate_count;
395}
396
397static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200398 struct flowi6 *fl6, int oif,
399 int strict)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000400{
401 struct rt6_info *sibling, *next_sibling;
402 int route_choosen;
403
404 route_choosen = rt6_info_hash_nhsfn(match->rt6i_nsiblings + 1, fl6);
405 /* Don't change the route, if route_choosen == 0
406 * (siblings does not include ourself)
407 */
408 if (route_choosen)
409 list_for_each_entry_safe(sibling, next_sibling,
410 &match->rt6i_siblings, rt6i_siblings) {
411 route_choosen--;
412 if (route_choosen == 0) {
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200413 if (rt6_score_route(sibling, oif, strict) < 0)
414 break;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000415 match = sibling;
416 break;
417 }
418 }
419 return match;
420}
421
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422/*
Thomas Grafc71099a2006-08-04 23:20:06 -0700423 * Route lookup. Any table->tb6_lock is implied.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 */
425
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800426static inline struct rt6_info *rt6_device_match(struct net *net,
427 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000428 const struct in6_addr *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 int oif,
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700430 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431{
432 struct rt6_info *local = NULL;
433 struct rt6_info *sprt;
434
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900435 if (!oif && ipv6_addr_any(saddr))
436 goto out;
437
Changli Gaod8d1f302010-06-10 23:31:35 -0700438 for (sprt = rt; sprt; sprt = sprt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -0500439 struct net_device *dev = sprt->dst.dev;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900440
441 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 if (dev->ifindex == oif)
443 return sprt;
444 if (dev->flags & IFF_LOOPBACK) {
David S. Miller38308472011-12-03 18:02:47 -0500445 if (!sprt->rt6i_idev ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 sprt->rt6i_idev->dev->ifindex != oif) {
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700447 if (flags & RT6_LOOKUP_F_IFACE && oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 continue;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900449 if (local && (!oif ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 local->rt6i_idev->dev->ifindex == oif))
451 continue;
452 }
453 local = sprt;
454 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900455 } else {
456 if (ipv6_chk_addr(net, saddr, dev,
457 flags & RT6_LOOKUP_F_IFACE))
458 return sprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900460 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900462 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 if (local)
464 return local;
465
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700466 if (flags & RT6_LOOKUP_F_IFACE)
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800467 return net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900469out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 return rt;
471}
472
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800473#ifdef CONFIG_IPV6_ROUTER_PREF
474static void rt6_probe(struct rt6_info *rt)
475{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000476 struct neighbour *neigh;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800477 /*
478 * Okay, this does not seem to be appropriate
479 * for now, however, we need to check if it
480 * is really so; aka Router Reachability Probing.
481 *
482 * Router Reachability Probe MUST be rate-limited
483 * to no more than one per minute.
484 */
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000485 if (!rt || !(rt->rt6i_flags & RTF_GATEWAY))
Amerigo Wangfdd66812012-09-10 02:48:44 +0000486 return;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000487 rcu_read_lock_bh();
488 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
489 if (neigh) {
490 write_lock(&neigh->lock);
491 if (neigh->nud_state & NUD_VALID)
492 goto out;
YOSHIFUJI Hideaki / 吉藤英明7ff74a52013-01-17 12:53:02 +0000493 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000494
495 if (!neigh ||
YOSHIFUJI Hideaki52e16352006-03-20 17:05:47 -0800496 time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) {
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800497 struct in6_addr mcaddr;
498 struct in6_addr *target;
499
YOSHIFUJI Hideaki / 吉藤英明b820bb62013-01-21 09:58:50 +0000500 if (neigh) {
501 neigh->updated = jiffies;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000502 write_unlock(&neigh->lock);
YOSHIFUJI Hideaki / 吉藤英明b820bb62013-01-21 09:58:50 +0000503 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000504
505 target = (struct in6_addr *)&rt->rt6i_gateway;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800506 addrconf_addr_solict_mult(target, &mcaddr);
David S. Millerd1918542011-12-28 20:19:20 -0500507 ndisc_send_ns(rt->dst.dev, NULL, target, &mcaddr, NULL);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000508 } else {
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000509out:
510 write_unlock(&neigh->lock);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000511 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000512 rcu_read_unlock_bh();
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800513}
514#else
515static inline void rt6_probe(struct rt6_info *rt)
516{
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800517}
518#endif
519
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520/*
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800521 * Default Router Selection (RFC 2461 6.3.6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 */
Dave Jonesb6f99a22007-03-22 12:27:49 -0700523static inline int rt6_check_dev(struct rt6_info *rt, int oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524{
David S. Millerd1918542011-12-28 20:19:20 -0500525 struct net_device *dev = rt->dst.dev;
David S. Miller161980f2007-04-06 11:42:27 -0700526 if (!oif || dev->ifindex == oif)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800527 return 2;
David S. Miller161980f2007-04-06 11:42:27 -0700528 if ((dev->flags & IFF_LOOPBACK) &&
529 rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
530 return 1;
531 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532}
533
Paul Marksa5a81f02012-12-03 10:26:54 +0000534static inline bool rt6_check_neigh(struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000536 struct neighbour *neigh;
Paul Marksa5a81f02012-12-03 10:26:54 +0000537 bool ret = false;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000538
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700539 if (rt->rt6i_flags & RTF_NONEXTHOP ||
540 !(rt->rt6i_flags & RTF_GATEWAY))
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000541 return true;
542
543 rcu_read_lock_bh();
544 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
545 if (neigh) {
546 read_lock(&neigh->lock);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800547 if (neigh->nud_state & NUD_VALID)
Paul Marksa5a81f02012-12-03 10:26:54 +0000548 ret = true;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800549#ifdef CONFIG_IPV6_ROUTER_PREF
Paul Marksa5a81f02012-12-03 10:26:54 +0000550 else if (!(neigh->nud_state & NUD_FAILED))
551 ret = true;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800552#endif
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000553 read_unlock(&neigh->lock);
Hannes Frederic Sowa3630d402013-07-03 20:45:04 +0200554 } else if (IS_ENABLED(CONFIG_IPV6_ROUTER_PREF)) {
555 ret = true;
Paul Marksa5a81f02012-12-03 10:26:54 +0000556 }
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000557 rcu_read_unlock_bh();
558
Paul Marksa5a81f02012-12-03 10:26:54 +0000559 return ret;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800560}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800562static int rt6_score_route(struct rt6_info *rt, int oif,
563 int strict)
564{
Paul Marksa5a81f02012-12-03 10:26:54 +0000565 int m;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900566
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700567 m = rt6_check_dev(rt, oif);
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700568 if (!m && (strict & RT6_LOOKUP_F_IFACE))
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800569 return -1;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800570#ifdef CONFIG_IPV6_ROUTER_PREF
571 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
572#endif
Paul Marksa5a81f02012-12-03 10:26:54 +0000573 if (!rt6_check_neigh(rt) && (strict & RT6_LOOKUP_F_REACHABLE))
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800574 return -1;
575 return m;
576}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
David S. Millerf11e6652007-03-24 20:36:25 -0700578static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
579 int *mpri, struct rt6_info *match)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800580{
David S. Millerf11e6652007-03-24 20:36:25 -0700581 int m;
582
583 if (rt6_check_expired(rt))
584 goto out;
585
586 m = rt6_score_route(rt, oif, strict);
587 if (m < 0)
588 goto out;
589
590 if (m > *mpri) {
591 if (strict & RT6_LOOKUP_F_REACHABLE)
592 rt6_probe(match);
593 *mpri = m;
594 match = rt;
595 } else if (strict & RT6_LOOKUP_F_REACHABLE) {
596 rt6_probe(rt);
597 }
598
599out:
600 return match;
601}
602
603static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
604 struct rt6_info *rr_head,
605 u32 metric, int oif, int strict)
606{
607 struct rt6_info *rt, *match;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800608 int mpri = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
David S. Millerf11e6652007-03-24 20:36:25 -0700610 match = NULL;
611 for (rt = rr_head; rt && rt->rt6i_metric == metric;
Changli Gaod8d1f302010-06-10 23:31:35 -0700612 rt = rt->dst.rt6_next)
David S. Millerf11e6652007-03-24 20:36:25 -0700613 match = find_match(rt, oif, strict, &mpri, match);
614 for (rt = fn->leaf; rt && rt != rr_head && rt->rt6i_metric == metric;
Changli Gaod8d1f302010-06-10 23:31:35 -0700615 rt = rt->dst.rt6_next)
David S. Millerf11e6652007-03-24 20:36:25 -0700616 match = find_match(rt, oif, strict, &mpri, match);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800617
David S. Millerf11e6652007-03-24 20:36:25 -0700618 return match;
619}
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800620
David S. Millerf11e6652007-03-24 20:36:25 -0700621static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
622{
623 struct rt6_info *match, *rt0;
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800624 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
David S. Millerf11e6652007-03-24 20:36:25 -0700626 rt0 = fn->rr_ptr;
627 if (!rt0)
628 fn->rr_ptr = rt0 = fn->leaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
David S. Millerf11e6652007-03-24 20:36:25 -0700630 match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800632 if (!match &&
David S. Millerf11e6652007-03-24 20:36:25 -0700633 (strict & RT6_LOOKUP_F_REACHABLE)) {
Changli Gaod8d1f302010-06-10 23:31:35 -0700634 struct rt6_info *next = rt0->dst.rt6_next;
David S. Millerf11e6652007-03-24 20:36:25 -0700635
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800636 /* no entries matched; do round-robin */
David S. Millerf11e6652007-03-24 20:36:25 -0700637 if (!next || next->rt6i_metric != rt0->rt6i_metric)
638 next = fn->leaf;
639
640 if (next != rt0)
641 fn->rr_ptr = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 }
643
David S. Millerd1918542011-12-28 20:19:20 -0500644 net = dev_net(rt0->dst.dev);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000645 return match ? match : net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646}
647
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800648#ifdef CONFIG_IPV6_ROUTE_INFO
649int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000650 const struct in6_addr *gwaddr)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800651{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900652 struct net *net = dev_net(dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800653 struct route_info *rinfo = (struct route_info *) opt;
654 struct in6_addr prefix_buf, *prefix;
655 unsigned int pref;
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900656 unsigned long lifetime;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800657 struct rt6_info *rt;
658
659 if (len < sizeof(struct route_info)) {
660 return -EINVAL;
661 }
662
663 /* Sanity check for prefix_len and length */
664 if (rinfo->length > 3) {
665 return -EINVAL;
666 } else if (rinfo->prefix_len > 128) {
667 return -EINVAL;
668 } else if (rinfo->prefix_len > 64) {
669 if (rinfo->length < 2) {
670 return -EINVAL;
671 }
672 } else if (rinfo->prefix_len > 0) {
673 if (rinfo->length < 1) {
674 return -EINVAL;
675 }
676 }
677
678 pref = rinfo->route_pref;
679 if (pref == ICMPV6_ROUTER_PREF_INVALID)
Jens Rosenboom3933fc92009-09-10 06:25:11 +0000680 return -EINVAL;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800681
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900682 lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800683
684 if (rinfo->length == 3)
685 prefix = (struct in6_addr *)rinfo->prefix;
686 else {
687 /* this function is safe */
688 ipv6_addr_prefix(&prefix_buf,
689 (struct in6_addr *)rinfo->prefix,
690 rinfo->prefix_len);
691 prefix = &prefix_buf;
692 }
693
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800694 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, gwaddr,
695 dev->ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800696
697 if (rt && !lifetime) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -0700698 ip6_del_rt(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800699 rt = NULL;
700 }
701
702 if (!rt && lifetime)
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800703 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800704 pref);
705 else if (rt)
706 rt->rt6i_flags = RTF_ROUTEINFO |
707 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
708
709 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +0000710 if (!addrconf_finite_timeout(lifetime))
711 rt6_clean_expires(rt);
712 else
713 rt6_set_expires(rt, jiffies + HZ * lifetime);
714
Amerigo Wang94e187c2012-10-29 00:13:19 +0000715 ip6_rt_put(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800716 }
717 return 0;
718}
719#endif
720
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800721#define BACKTRACK(__net, saddr) \
YOSHIFUJI Hideaki982f56f2006-08-23 17:22:39 -0700722do { \
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800723 if (rt == __net->ipv6.ip6_null_entry) { \
YOSHIFUJI Hideaki982f56f2006-08-23 17:22:39 -0700724 struct fib6_node *pn; \
Ville Nuorvalae0eda7b2006-10-16 22:11:11 -0700725 while (1) { \
YOSHIFUJI Hideaki982f56f2006-08-23 17:22:39 -0700726 if (fn->fn_flags & RTN_TL_ROOT) \
727 goto out; \
728 pn = fn->parent; \
729 if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn) \
Kim Nordlund8bce65b2006-12-13 16:38:29 -0800730 fn = fib6_lookup(FIB6_SUBTREE(pn), NULL, saddr); \
YOSHIFUJI Hideaki982f56f2006-08-23 17:22:39 -0700731 else \
732 fn = pn; \
733 if (fn->fn_flags & RTN_RTINFO) \
734 goto restart; \
Thomas Grafc71099a2006-08-04 23:20:06 -0700735 } \
Thomas Grafc71099a2006-08-04 23:20:06 -0700736 } \
David S. Miller38308472011-12-03 18:02:47 -0500737} while (0)
Thomas Grafc71099a2006-08-04 23:20:06 -0700738
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800739static struct rt6_info *ip6_pol_route_lookup(struct net *net,
740 struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500741 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742{
743 struct fib6_node *fn;
744 struct rt6_info *rt;
745
Thomas Grafc71099a2006-08-04 23:20:06 -0700746 read_lock_bh(&table->tb6_lock);
David S. Miller4c9483b2011-03-12 16:22:43 -0500747 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -0700748restart:
749 rt = fn->leaf;
David S. Miller4c9483b2011-03-12 16:22:43 -0500750 rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000751 if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0)
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200752 rt = rt6_multipath_select(rt, fl6, fl6->flowi6_oif, flags);
David S. Miller4c9483b2011-03-12 16:22:43 -0500753 BACKTRACK(net, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -0700754out:
Changli Gaod8d1f302010-06-10 23:31:35 -0700755 dst_use(&rt->dst, jiffies);
Thomas Grafc71099a2006-08-04 23:20:06 -0700756 read_unlock_bh(&table->tb6_lock);
Thomas Grafc71099a2006-08-04 23:20:06 -0700757 return rt;
758
759}
760
Florian Westphalea6e5742011-09-05 16:05:44 +0200761struct dst_entry * ip6_route_lookup(struct net *net, struct flowi6 *fl6,
762 int flags)
763{
764 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup);
765}
766EXPORT_SYMBOL_GPL(ip6_route_lookup);
767
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900768struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
769 const struct in6_addr *saddr, int oif, int strict)
Thomas Grafc71099a2006-08-04 23:20:06 -0700770{
David S. Miller4c9483b2011-03-12 16:22:43 -0500771 struct flowi6 fl6 = {
772 .flowi6_oif = oif,
773 .daddr = *daddr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700774 };
775 struct dst_entry *dst;
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700776 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
Thomas Grafc71099a2006-08-04 23:20:06 -0700777
Thomas Grafadaa70b2006-10-13 15:01:03 -0700778 if (saddr) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500779 memcpy(&fl6.saddr, saddr, sizeof(*saddr));
Thomas Grafadaa70b2006-10-13 15:01:03 -0700780 flags |= RT6_LOOKUP_F_HAS_SADDR;
781 }
782
David S. Miller4c9483b2011-03-12 16:22:43 -0500783 dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup);
Thomas Grafc71099a2006-08-04 23:20:06 -0700784 if (dst->error == 0)
785 return (struct rt6_info *) dst;
786
787 dst_release(dst);
788
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 return NULL;
790}
791
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900792EXPORT_SYMBOL(rt6_lookup);
793
Thomas Grafc71099a2006-08-04 23:20:06 -0700794/* ip6_ins_rt is called with FREE table->tb6_lock.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 It takes new route entry, the addition fails by any reason the
796 route is freed. In any case, if caller does not hold it, it may
797 be destroyed.
798 */
799
Thomas Graf86872cb2006-08-22 00:01:08 -0700800static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801{
802 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -0700803 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
Thomas Grafc71099a2006-08-04 23:20:06 -0700805 table = rt->rt6i_table;
806 write_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -0700807 err = fib6_add(&table->tb6_root, rt, info);
Thomas Grafc71099a2006-08-04 23:20:06 -0700808 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809
810 return err;
811}
812
Thomas Graf40e22e82006-08-22 00:00:45 -0700813int ip6_ins_rt(struct rt6_info *rt)
814{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -0800815 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -0500816 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -0800817 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -0800818 return __ip6_ins_rt(rt, &info);
Thomas Graf40e22e82006-08-22 00:00:45 -0700819}
820
Gao feng1716a962012-04-06 00:13:10 +0000821static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort,
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000822 const struct in6_addr *daddr,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000823 const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 struct rt6_info *rt;
826
827 /*
828 * Clone the route.
829 */
830
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000831 rt = ip6_rt_copy(ort, daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
833 if (rt) {
David S. Miller38308472011-12-03 18:02:47 -0500834 if (!(rt->rt6i_flags & RTF_GATEWAY)) {
David S. Millerbb3c3682011-12-13 17:35:06 -0500835 if (ort->rt6i_dst.plen != 128 &&
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000836 ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +0900837 rt->rt6i_flags |= RTF_ANYCAST;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000838 rt->rt6i_gateway = *daddr;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +0900839 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 rt->rt6i_flags |= RTF_CACHE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842
843#ifdef CONFIG_IPV6_SUBTREES
844 if (rt->rt6i_src.plen && saddr) {
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000845 rt->rt6i_src.addr = *saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 rt->rt6i_src.plen = 128;
847 }
848#endif
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800851 return rt;
852}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000854static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort,
855 const struct in6_addr *daddr)
YOSHIFUJI Hideaki299d9932006-03-20 16:58:32 -0800856{
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000857 struct rt6_info *rt = ip6_rt_copy(ort, daddr);
858
YOSHIFUJI Hideaki / 吉藤英明887c95c2013-01-17 12:54:05 +0000859 if (rt)
YOSHIFUJI Hideaki299d9932006-03-20 16:58:32 -0800860 rt->rt6i_flags |= RTF_CACHE;
YOSHIFUJI Hideaki299d9932006-03-20 16:58:32 -0800861 return rt;
862}
863
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800864static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif,
David S. Miller4c9483b2011-03-12 16:22:43 -0500865 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866{
867 struct fib6_node *fn;
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800868 struct rt6_info *rt, *nrt;
Thomas Grafc71099a2006-08-04 23:20:06 -0700869 int strict = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 int attempts = 3;
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800871 int err;
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700872 int reachable = net->ipv6.devconf_all->forwarding ? 0 : RT6_LOOKUP_F_REACHABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700874 strict |= flags & RT6_LOOKUP_F_IFACE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875
876relookup:
Thomas Grafc71099a2006-08-04 23:20:06 -0700877 read_lock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
YOSHIFUJI Hideaki8238dd02006-03-20 17:04:35 -0800879restart_2:
David S. Miller4c9483b2011-03-12 16:22:43 -0500880 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
882restart:
Pavel Emelyanov4acad722007-10-15 13:02:51 -0700883 rt = rt6_select(fn, oif, strict | reachable);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200884 if (rt->rt6i_nsiblings)
885 rt = rt6_multipath_select(rt, fl6, oif, strict | reachable);
David S. Miller4c9483b2011-03-12 16:22:43 -0500886 BACKTRACK(net, &fl6->saddr);
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800887 if (rt == net->ipv6.ip6_null_entry ||
YOSHIFUJI Hideaki8238dd02006-03-20 17:04:35 -0800888 rt->rt6i_flags & RTF_CACHE)
YOSHIFUJI Hideaki1ddef042006-03-20 17:01:24 -0800889 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
Changli Gaod8d1f302010-06-10 23:31:35 -0700891 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -0700892 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -0800893
YOSHIFUJI Hideaki / 吉藤英明c440f162013-01-17 12:53:32 +0000894 if (!(rt->rt6i_flags & (RTF_NONEXTHOP | RTF_GATEWAY)))
David S. Miller4c9483b2011-03-12 16:22:43 -0500895 nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr);
David S. Miller7343ff32011-03-09 19:55:25 -0800896 else if (!(rt->dst.flags & DST_HOST))
David S. Miller4c9483b2011-03-12 16:22:43 -0500897 nrt = rt6_alloc_clone(rt, &fl6->daddr);
David S. Miller7343ff32011-03-09 19:55:25 -0800898 else
899 goto out2;
YOSHIFUJI Hideakie40cf352006-03-20 16:59:27 -0800900
Amerigo Wang94e187c2012-10-29 00:13:19 +0000901 ip6_rt_put(rt);
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800902 rt = nrt ? : net->ipv6.ip6_null_entry;
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800903
Changli Gaod8d1f302010-06-10 23:31:35 -0700904 dst_hold(&rt->dst);
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800905 if (nrt) {
Thomas Graf40e22e82006-08-22 00:00:45 -0700906 err = ip6_ins_rt(nrt);
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800907 if (!err)
908 goto out2;
909 }
910
911 if (--attempts <= 0)
912 goto out2;
913
914 /*
Thomas Grafc71099a2006-08-04 23:20:06 -0700915 * Race condition! In the gap, when table->tb6_lock was
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800916 * released someone could insert this route. Relookup.
917 */
Amerigo Wang94e187c2012-10-29 00:13:19 +0000918 ip6_rt_put(rt);
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800919 goto relookup;
920
921out:
YOSHIFUJI Hideaki8238dd02006-03-20 17:04:35 -0800922 if (reachable) {
923 reachable = 0;
924 goto restart_2;
925 }
Changli Gaod8d1f302010-06-10 23:31:35 -0700926 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -0700927 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928out2:
Changli Gaod8d1f302010-06-10 23:31:35 -0700929 rt->dst.lastuse = jiffies;
930 rt->dst.__use++;
Thomas Grafc71099a2006-08-04 23:20:06 -0700931
932 return rt;
933}
934
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800935static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500936 struct flowi6 *fl6, int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -0700937{
David S. Miller4c9483b2011-03-12 16:22:43 -0500938 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -0700939}
940
Shmulik Ladkani72331bc2012-04-01 04:03:45 +0000941static struct dst_entry *ip6_route_input_lookup(struct net *net,
942 struct net_device *dev,
943 struct flowi6 *fl6, int flags)
944{
945 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
946 flags |= RT6_LOOKUP_F_IFACE;
947
948 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_input);
949}
950
Thomas Grafc71099a2006-08-04 23:20:06 -0700951void ip6_route_input(struct sk_buff *skb)
952{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000953 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900954 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -0700955 int flags = RT6_LOOKUP_F_HAS_SADDR;
David S. Miller4c9483b2011-03-12 16:22:43 -0500956 struct flowi6 fl6 = {
957 .flowi6_iif = skb->dev->ifindex,
958 .daddr = iph->daddr,
959 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +0000960 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -0500961 .flowi6_mark = skb->mark,
962 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700963 };
Thomas Grafadaa70b2006-10-13 15:01:03 -0700964
Shmulik Ladkani72331bc2012-04-01 04:03:45 +0000965 skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -0700966}
967
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800968static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500969 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -0700970{
David S. Miller4c9483b2011-03-12 16:22:43 -0500971 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -0700972}
973
Florian Westphal9c7a4f92011-03-22 19:17:36 -0700974struct dst_entry * ip6_route_output(struct net *net, const struct sock *sk,
David S. Miller4c9483b2011-03-12 16:22:43 -0500975 struct flowi6 *fl6)
Thomas Grafc71099a2006-08-04 23:20:06 -0700976{
977 int flags = 0;
978
Pavel Emelyanov1fb94892012-08-08 21:53:36 +0000979 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +0000980
David S. Miller4c9483b2011-03-12 16:22:43 -0500981 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700982 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -0700983
David S. Miller4c9483b2011-03-12 16:22:43 -0500984 if (!ipv6_addr_any(&fl6->saddr))
Thomas Grafadaa70b2006-10-13 15:01:03 -0700985 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +0000986 else if (sk)
987 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -0700988
David S. Miller4c9483b2011-03-12 16:22:43 -0500989 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990}
991
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900992EXPORT_SYMBOL(ip6_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
David S. Miller2774c132011-03-01 14:59:04 -0800994struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -0700995{
David S. Miller5c1e6aa2011-04-28 14:13:38 -0700996 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
David S. Miller14e50e52007-05-24 18:17:54 -0700997 struct dst_entry *new = NULL;
998
David S. Millerf5b0a872012-07-19 12:31:33 -0700999 rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, DST_OBSOLETE_NONE, 0);
David S. Miller14e50e52007-05-24 18:17:54 -07001000 if (rt) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001001 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -07001002
Steffen Klassert81048912012-07-05 23:37:09 +00001003 memset(new + 1, 0, sizeof(*rt) - sizeof(*new));
1004 rt6_init_peer(rt, net->ipv6.peers);
1005
David S. Miller14e50e52007-05-24 18:17:54 -07001006 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08001007 new->input = dst_discard;
1008 new->output = dst_discard;
David S. Miller14e50e52007-05-24 18:17:54 -07001009
Eric Dumazet21efcfa2011-07-19 20:18:36 +00001010 if (dst_metrics_read_only(&ort->dst))
1011 new->_metrics = ort->dst._metrics;
1012 else
1013 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07001014 rt->rt6i_idev = ort->rt6i_idev;
1015 if (rt->rt6i_idev)
1016 in6_dev_hold(rt->rt6i_idev);
David S. Miller14e50e52007-05-24 18:17:54 -07001017
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001018 rt->rt6i_gateway = ort->rt6i_gateway;
Gao feng1716a962012-04-06 00:13:10 +00001019 rt->rt6i_flags = ort->rt6i_flags;
David S. Miller14e50e52007-05-24 18:17:54 -07001020 rt->rt6i_metric = 0;
1021
1022 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
1023#ifdef CONFIG_IPV6_SUBTREES
1024 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1025#endif
1026
1027 dst_free(new);
1028 }
1029
David S. Miller69ead7a2011-03-01 14:45:33 -08001030 dst_release(dst_orig);
1031 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07001032}
David S. Miller14e50e52007-05-24 18:17:54 -07001033
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034/*
1035 * Destination cache support functions
1036 */
1037
1038static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
1039{
1040 struct rt6_info *rt;
1041
1042 rt = (struct rt6_info *) dst;
1043
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00001044 /* All IPV6 dsts are created with ->obsolete set to the value
1045 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
1046 * into this function always.
1047 */
1048 if (rt->rt6i_genid != rt_genid(dev_net(rt->dst.dev)))
1049 return NULL;
1050
Li RongQinga4477c42012-11-07 21:56:33 +00001051 if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 return dst;
Li RongQinga4477c42012-11-07 21:56:33 +00001053
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 return NULL;
1055}
1056
1057static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
1058{
1059 struct rt6_info *rt = (struct rt6_info *) dst;
1060
1061 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001062 if (rt->rt6i_flags & RTF_CACHE) {
1063 if (rt6_check_expired(rt)) {
1064 ip6_del_rt(rt);
1065 dst = NULL;
1066 }
1067 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001069 dst = NULL;
1070 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001072 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073}
1074
1075static void ip6_link_failure(struct sk_buff *skb)
1076{
1077 struct rt6_info *rt;
1078
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00001079 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080
Eric Dumazetadf30902009-06-02 05:19:30 +00001081 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 if (rt) {
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001083 if (rt->rt6i_flags & RTF_CACHE) {
1084 dst_hold(&rt->dst);
1085 if (ip6_del_rt(rt))
1086 dst_free(&rt->dst);
1087 } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 rt->rt6i_node->fn_sernum = -1;
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001089 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 }
1091}
1092
David S. Miller6700c272012-07-17 03:29:28 -07001093static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
1094 struct sk_buff *skb, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095{
1096 struct rt6_info *rt6 = (struct rt6_info*)dst;
1097
David S. Miller81aded22012-06-15 14:54:11 -07001098 dst_confirm(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 if (mtu < dst_mtu(dst) && rt6->rt6i_dst.plen == 128) {
David S. Miller81aded22012-06-15 14:54:11 -07001100 struct net *net = dev_net(dst->dev);
1101
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 rt6->rt6i_flags |= RTF_MODIFIED;
1103 if (mtu < IPV6_MIN_MTU) {
David S. Millerdefb3512010-12-08 21:16:57 -08001104 u32 features = dst_metric(dst, RTAX_FEATURES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 mtu = IPV6_MIN_MTU;
David S. Millerdefb3512010-12-08 21:16:57 -08001106 features |= RTAX_FEATURE_ALLFRAG;
1107 dst_metric_set(dst, RTAX_FEATURES, features);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 }
David S. Millerdefb3512010-12-08 21:16:57 -08001109 dst_metric_set(dst, RTAX_MTU, mtu);
David S. Miller81aded22012-06-15 14:54:11 -07001110 rt6_update_expires(rt6, net->ipv6.sysctl.ip6_rt_mtu_expires);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 }
1112}
1113
David S. Miller42ae66c2012-06-15 20:01:57 -07001114void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
1115 int oif, u32 mark)
David S. Miller81aded22012-06-15 14:54:11 -07001116{
1117 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1118 struct dst_entry *dst;
1119 struct flowi6 fl6;
1120
1121 memset(&fl6, 0, sizeof(fl6));
1122 fl6.flowi6_oif = oif;
1123 fl6.flowi6_mark = mark;
David S. Miller3e129392012-07-10 04:01:57 -07001124 fl6.flowi6_flags = 0;
David S. Miller81aded22012-06-15 14:54:11 -07001125 fl6.daddr = iph->daddr;
1126 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001127 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller81aded22012-06-15 14:54:11 -07001128
1129 dst = ip6_route_output(net, NULL, &fl6);
1130 if (!dst->error)
David S. Miller6700c272012-07-17 03:29:28 -07001131 ip6_rt_update_pmtu(dst, NULL, skb, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07001132 dst_release(dst);
1133}
1134EXPORT_SYMBOL_GPL(ip6_update_pmtu);
1135
1136void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
1137{
1138 ip6_update_pmtu(skb, sock_net(sk), mtu,
1139 sk->sk_bound_dev_if, sk->sk_mark);
1140}
1141EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
1142
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001143void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark)
1144{
1145 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1146 struct dst_entry *dst;
1147 struct flowi6 fl6;
1148
1149 memset(&fl6, 0, sizeof(fl6));
1150 fl6.flowi6_oif = oif;
1151 fl6.flowi6_mark = mark;
1152 fl6.flowi6_flags = 0;
1153 fl6.daddr = iph->daddr;
1154 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001155 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001156
1157 dst = ip6_route_output(net, NULL, &fl6);
1158 if (!dst->error)
David S. Miller6700c272012-07-17 03:29:28 -07001159 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001160 dst_release(dst);
1161}
1162EXPORT_SYMBOL_GPL(ip6_redirect);
1163
1164void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
1165{
1166 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark);
1167}
1168EXPORT_SYMBOL_GPL(ip6_sk_redirect);
1169
David S. Miller0dbaee32010-12-13 12:52:14 -08001170static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171{
David S. Miller0dbaee32010-12-13 12:52:14 -08001172 struct net_device *dev = dst->dev;
1173 unsigned int mtu = dst_mtu(dst);
1174 struct net *net = dev_net(dev);
1175
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
1177
Daniel Lezcano55786892008-03-04 13:47:47 -08001178 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
1179 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180
1181 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001182 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
1183 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
1184 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 * rely only on pmtu discovery"
1186 */
1187 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
1188 mtu = IPV6_MAXPLEN;
1189 return mtu;
1190}
1191
Steffen Klassertebb762f2011-11-23 02:12:51 +00001192static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08001193{
David S. Millerd33e4552010-12-14 13:01:14 -08001194 struct inet6_dev *idev;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001195 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
1196
1197 if (mtu)
1198 return mtu;
1199
1200 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08001201
1202 rcu_read_lock();
1203 idev = __in6_dev_get(dst->dev);
1204 if (idev)
1205 mtu = idev->cnf.mtu6;
1206 rcu_read_unlock();
1207
1208 return mtu;
1209}
1210
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001211static struct dst_entry *icmp6_dst_gc_list;
1212static DEFINE_SPINLOCK(icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001213
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001214struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05001215 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216{
David S. Miller87a11572011-12-06 17:04:13 -05001217 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 struct rt6_info *rt;
1219 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001220 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221
David S. Miller38308472011-12-03 18:02:47 -05001222 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00001223 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224
David S. Miller8b96d222012-06-11 02:01:56 -07001225 rt = ip6_dst_alloc(net, dev, 0, NULL);
David S. Miller38308472011-12-03 18:02:47 -05001226 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05001228 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 goto out;
1230 }
1231
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001232 rt->dst.flags |= DST_HOST;
1233 rt->dst.output = ip6_output;
Changli Gaod8d1f302010-06-10 23:31:35 -07001234 atomic_set(&rt->dst.__refcnt, 1);
David S. Miller87a11572011-12-06 17:04:13 -05001235 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001236 rt->rt6i_dst.plen = 128;
1237 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08001238 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001240 spin_lock_bh(&icmp6_dst_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001241 rt->dst.next = icmp6_dst_gc_list;
1242 icmp6_dst_gc_list = &rt->dst;
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001243 spin_unlock_bh(&icmp6_dst_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
Daniel Lezcano55786892008-03-04 13:47:47 -08001245 fib6_force_start_gc(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
David S. Miller87a11572011-12-06 17:04:13 -05001247 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
1248
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249out:
David S. Miller87a11572011-12-06 17:04:13 -05001250 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251}
1252
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001253int icmp6_dst_gc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254{
Hagen Paul Pfeifere9476e92011-02-25 05:45:19 +00001255 struct dst_entry *dst, **pprev;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001256 int more = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001258 spin_lock_bh(&icmp6_dst_lock);
1259 pprev = &icmp6_dst_gc_list;
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001260
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 while ((dst = *pprev) != NULL) {
1262 if (!atomic_read(&dst->__refcnt)) {
1263 *pprev = dst->next;
1264 dst_free(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 } else {
1266 pprev = &dst->next;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001267 ++more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 }
1269 }
1270
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001271 spin_unlock_bh(&icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001272
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001273 return more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274}
1275
David S. Miller1e493d12008-09-10 17:27:15 -07001276static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg),
1277 void *arg)
1278{
1279 struct dst_entry *dst, **pprev;
1280
1281 spin_lock_bh(&icmp6_dst_lock);
1282 pprev = &icmp6_dst_gc_list;
1283 while ((dst = *pprev) != NULL) {
1284 struct rt6_info *rt = (struct rt6_info *) dst;
1285 if (func(rt, arg)) {
1286 *pprev = dst->next;
1287 dst_free(dst);
1288 } else {
1289 pprev = &dst->next;
1290 }
1291 }
1292 spin_unlock_bh(&icmp6_dst_lock);
1293}
1294
Daniel Lezcano569d3642008-01-18 03:56:57 -08001295static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 unsigned long now = jiffies;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00001298 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08001299 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
1300 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
1301 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
1302 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
1303 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001304 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305
Eric Dumazetfc66f952010-10-08 06:37:34 +00001306 entries = dst_entries_get_fast(ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08001307 if (time_after(rt_last_gc + rt_min_interval, now) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00001308 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 goto out;
1310
Benjamin Thery6891a342008-03-04 13:49:47 -08001311 net->ipv6.ip6_rt_gc_expire++;
1312 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net);
1313 net->ipv6.ip6_rt_last_gc = now;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001314 entries = dst_entries_get_slow(ops);
1315 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08001316 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08001318 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001319 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320}
1321
YOSHIFUJI Hideaki6b75d092008-03-10 06:00:30 -04001322int ip6_dst_hoplimit(struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323{
David S. Miller5170ae82010-12-12 21:35:57 -08001324 int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT);
David S. Millera02e4b72010-12-12 21:39:02 -08001325 if (hoplimit == 0) {
YOSHIFUJI Hideaki6b75d092008-03-10 06:00:30 -04001326 struct net_device *dev = dst->dev;
Eric Dumazetc68f24c2010-06-14 04:46:20 +00001327 struct inet6_dev *idev;
1328
1329 rcu_read_lock();
1330 idev = __in6_dev_get(dev);
1331 if (idev)
YOSHIFUJI Hideaki6b75d092008-03-10 06:00:30 -04001332 hoplimit = idev->cnf.hop_limit;
Eric Dumazetc68f24c2010-06-14 04:46:20 +00001333 else
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -07001334 hoplimit = dev_net(dev)->ipv6.devconf_all->hop_limit;
Eric Dumazetc68f24c2010-06-14 04:46:20 +00001335 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 }
1337 return hoplimit;
1338}
David S. Millerabbf46a2010-12-12 21:14:46 -08001339EXPORT_SYMBOL(ip6_dst_hoplimit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340
1341/*
1342 *
1343 */
1344
Thomas Graf86872cb2006-08-22 00:01:08 -07001345int ip6_route_add(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346{
1347 int err;
Daniel Lezcano55786892008-03-04 13:47:47 -08001348 struct net *net = cfg->fc_nlinfo.nl_net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 struct rt6_info *rt = NULL;
1350 struct net_device *dev = NULL;
1351 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001352 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 int addr_type;
1354
Thomas Graf86872cb2006-08-22 00:01:08 -07001355 if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 return -EINVAL;
1357#ifndef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001358 if (cfg->fc_src_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 return -EINVAL;
1360#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07001361 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08001363 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 if (!dev)
1365 goto out;
1366 idev = in6_dev_get(dev);
1367 if (!idev)
1368 goto out;
1369 }
1370
Thomas Graf86872cb2006-08-22 00:01:08 -07001371 if (cfg->fc_metric == 0)
1372 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
Matti Vaittinend71314b2011-11-14 00:14:49 +00001374 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05001375 if (cfg->fc_nlinfo.nlh &&
1376 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00001377 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001378 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00001379 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00001380 table = fib6_new_table(net, cfg->fc_table);
1381 }
1382 } else {
1383 table = fib6_new_table(net, cfg->fc_table);
1384 }
David S. Miller38308472011-12-03 18:02:47 -05001385
1386 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001387 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07001388
David S. Miller8b96d222012-06-11 02:01:56 -07001389 rt = ip6_dst_alloc(net, NULL, DST_NOCOUNT, table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390
David S. Miller38308472011-12-03 18:02:47 -05001391 if (!rt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 err = -ENOMEM;
1393 goto out;
1394 }
1395
Gao feng1716a962012-04-06 00:13:10 +00001396 if (cfg->fc_flags & RTF_EXPIRES)
1397 rt6_set_expires(rt, jiffies +
1398 clock_t_to_jiffies(cfg->fc_expires));
1399 else
1400 rt6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401
Thomas Graf86872cb2006-08-22 00:01:08 -07001402 if (cfg->fc_protocol == RTPROT_UNSPEC)
1403 cfg->fc_protocol = RTPROT_BOOT;
1404 rt->rt6i_protocol = cfg->fc_protocol;
1405
1406 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407
1408 if (addr_type & IPV6_ADDR_MULTICAST)
Changli Gaod8d1f302010-06-10 23:31:35 -07001409 rt->dst.input = ip6_mc_input;
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00001410 else if (cfg->fc_flags & RTF_LOCAL)
1411 rt->dst.input = ip6_input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 else
Changli Gaod8d1f302010-06-10 23:31:35 -07001413 rt->dst.input = ip6_forward;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414
Changli Gaod8d1f302010-06-10 23:31:35 -07001415 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416
Thomas Graf86872cb2006-08-22 00:01:08 -07001417 ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
1418 rt->rt6i_dst.plen = cfg->fc_dst_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 if (rt->rt6i_dst.plen == 128)
David S. Miller11d53b42011-06-24 15:23:34 -07001420 rt->dst.flags |= DST_HOST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001422 if (!(rt->dst.flags & DST_HOST) && cfg->fc_mx) {
1423 u32 *metrics = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
1424 if (!metrics) {
1425 err = -ENOMEM;
1426 goto out;
1427 }
1428 dst_init_metrics(&rt->dst, metrics, 0);
1429 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430#ifdef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001431 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
1432 rt->rt6i_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433#endif
1434
Thomas Graf86872cb2006-08-22 00:01:08 -07001435 rt->rt6i_metric = cfg->fc_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436
1437 /* We cannot add true routes via loopback here,
1438 they would result in kernel looping; promote them to reject routes
1439 */
Thomas Graf86872cb2006-08-22 00:01:08 -07001440 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05001441 (dev && (dev->flags & IFF_LOOPBACK) &&
1442 !(addr_type & IPV6_ADDR_LOOPBACK) &&
1443 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08001445 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 if (dev) {
1447 dev_put(dev);
1448 in6_dev_put(idev);
1449 }
Daniel Lezcano55786892008-03-04 13:47:47 -08001450 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 dev_hold(dev);
1452 idev = in6_dev_get(dev);
1453 if (!idev) {
1454 err = -ENODEV;
1455 goto out;
1456 }
1457 }
Changli Gaod8d1f302010-06-10 23:31:35 -07001458 rt->dst.output = ip6_pkt_discard_out;
1459 rt->dst.input = ip6_pkt_discard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001461 switch (cfg->fc_type) {
1462 case RTN_BLACKHOLE:
1463 rt->dst.error = -EINVAL;
1464 break;
1465 case RTN_PROHIBIT:
1466 rt->dst.error = -EACCES;
1467 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00001468 case RTN_THROW:
1469 rt->dst.error = -EAGAIN;
1470 break;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001471 default:
1472 rt->dst.error = -ENETUNREACH;
1473 break;
1474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 goto install_route;
1476 }
1477
Thomas Graf86872cb2006-08-22 00:01:08 -07001478 if (cfg->fc_flags & RTF_GATEWAY) {
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001479 const struct in6_addr *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 int gwa_type;
1481
Thomas Graf86872cb2006-08-22 00:01:08 -07001482 gw_addr = &cfg->fc_gateway;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001483 rt->rt6i_gateway = *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 gwa_type = ipv6_addr_type(gw_addr);
1485
1486 if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
1487 struct rt6_info *grt;
1488
1489 /* IPv6 strictly inhibits using not link-local
1490 addresses as nexthop address.
1491 Otherwise, router will not able to send redirects.
1492 It is very good, but in some (rare!) circumstances
1493 (SIT, PtP, NBMA NOARP links) it is handy to allow
1494 some exceptions. --ANK
1495 */
1496 err = -EINVAL;
David S. Miller38308472011-12-03 18:02:47 -05001497 if (!(gwa_type & IPV6_ADDR_UNICAST))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 goto out;
1499
Daniel Lezcano55786892008-03-04 13:47:47 -08001500 grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501
1502 err = -EHOSTUNREACH;
David S. Miller38308472011-12-03 18:02:47 -05001503 if (!grt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 goto out;
1505 if (dev) {
David S. Millerd1918542011-12-28 20:19:20 -05001506 if (dev != grt->dst.dev) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00001507 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 goto out;
1509 }
1510 } else {
David S. Millerd1918542011-12-28 20:19:20 -05001511 dev = grt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 idev = grt->rt6i_idev;
1513 dev_hold(dev);
1514 in6_dev_hold(grt->rt6i_idev);
1515 }
David S. Miller38308472011-12-03 18:02:47 -05001516 if (!(grt->rt6i_flags & RTF_GATEWAY))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 err = 0;
Amerigo Wang94e187c2012-10-29 00:13:19 +00001518 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519
1520 if (err)
1521 goto out;
1522 }
1523 err = -EINVAL;
David S. Miller38308472011-12-03 18:02:47 -05001524 if (!dev || (dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 goto out;
1526 }
1527
1528 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05001529 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 goto out;
1531
Daniel Walterc3968a82011-04-13 21:10:57 +00001532 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
1533 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
1534 err = -EINVAL;
1535 goto out;
1536 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001537 rt->rt6i_prefsrc.addr = cfg->fc_prefsrc;
Daniel Walterc3968a82011-04-13 21:10:57 +00001538 rt->rt6i_prefsrc.plen = 128;
1539 } else
1540 rt->rt6i_prefsrc.plen = 0;
1541
Thomas Graf86872cb2006-08-22 00:01:08 -07001542 rt->rt6i_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543
1544install_route:
Thomas Graf86872cb2006-08-22 00:01:08 -07001545 if (cfg->fc_mx) {
1546 struct nlattr *nla;
1547 int remaining;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548
Thomas Graf86872cb2006-08-22 00:01:08 -07001549 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
Thomas Graf8f4c1f92007-09-12 14:44:36 +02001550 int type = nla_type(nla);
Thomas Graf86872cb2006-08-22 00:01:08 -07001551
1552 if (type) {
1553 if (type > RTAX_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 err = -EINVAL;
1555 goto out;
1556 }
Thomas Graf86872cb2006-08-22 00:01:08 -07001557
David S. Millerdefb3512010-12-08 21:16:57 -08001558 dst_metric_set(&rt->dst, type, nla_get_u32(nla));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 }
1561 }
1562
Changli Gaod8d1f302010-06-10 23:31:35 -07001563 rt->dst.dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 rt->rt6i_idev = idev;
Thomas Grafc71099a2006-08-04 23:20:06 -07001565 rt->rt6i_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001566
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001567 cfg->fc_nlinfo.nl_net = dev_net(dev);
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001568
Thomas Graf86872cb2006-08-22 00:01:08 -07001569 return __ip6_ins_rt(rt, &cfg->fc_nlinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570
1571out:
1572 if (dev)
1573 dev_put(dev);
1574 if (idev)
1575 in6_dev_put(idev);
1576 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07001577 dst_free(&rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 return err;
1579}
1580
Thomas Graf86872cb2006-08-22 00:01:08 -07001581static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582{
1583 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07001584 struct fib6_table *table;
David S. Millerd1918542011-12-28 20:19:20 -05001585 struct net *net = dev_net(rt->dst.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586
Gao feng6825a262012-09-19 19:25:34 +00001587 if (rt == net->ipv6.ip6_null_entry) {
1588 err = -ENOENT;
1589 goto out;
1590 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07001591
Thomas Grafc71099a2006-08-04 23:20:06 -07001592 table = rt->rt6i_table;
1593 write_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07001594 err = fib6_del(rt, info);
Thomas Grafc71099a2006-08-04 23:20:06 -07001595 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596
Gao feng6825a262012-09-19 19:25:34 +00001597out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00001598 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 return err;
1600}
1601
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001602int ip6_del_rt(struct rt6_info *rt)
1603{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08001604 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -05001605 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08001606 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08001607 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001608}
1609
Thomas Graf86872cb2006-08-22 00:01:08 -07001610static int ip6_route_del(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611{
Thomas Grafc71099a2006-08-04 23:20:06 -07001612 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 struct fib6_node *fn;
1614 struct rt6_info *rt;
1615 int err = -ESRCH;
1616
Daniel Lezcano55786892008-03-04 13:47:47 -08001617 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001618 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001619 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620
Thomas Grafc71099a2006-08-04 23:20:06 -07001621 read_lock_bh(&table->tb6_lock);
1622
1623 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07001624 &cfg->fc_dst, cfg->fc_dst_len,
1625 &cfg->fc_src, cfg->fc_src_len);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001626
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 if (fn) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001628 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
Thomas Graf86872cb2006-08-22 00:01:08 -07001629 if (cfg->fc_ifindex &&
David S. Millerd1918542011-12-28 20:19:20 -05001630 (!rt->dst.dev ||
1631 rt->dst.dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001633 if (cfg->fc_flags & RTF_GATEWAY &&
1634 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001636 if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07001638 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07001639 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640
Thomas Graf86872cb2006-08-22 00:01:08 -07001641 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 }
1643 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001644 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645
1646 return err;
1647}
1648
David S. Miller6700c272012-07-17 03:29:28 -07001649static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001650{
David S. Millere8599ff2012-07-11 23:43:53 -07001651 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001652 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07001653 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07001654 struct ndisc_options ndopts;
1655 struct inet6_dev *in6_dev;
1656 struct neighbour *neigh;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001657 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07001658 int optlen, on_link;
1659 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07001660
Simon Horman29a3cad2013-05-28 20:34:26 +00001661 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001662 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07001663
1664 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07001665 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001666 return;
1667 }
1668
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001669 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07001670
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001671 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07001672 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001673 return;
1674 }
1675
David S. Miller6e157b62012-07-12 00:05:02 -07001676 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001677 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07001678 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001679 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07001680 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07001681 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001682 return;
1683 }
1684
1685 in6_dev = __in6_dev_get(skb->dev);
1686 if (!in6_dev)
1687 return;
1688 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
1689 return;
1690
1691 /* RFC2461 8.1:
1692 * The IP source address of the Redirect MUST be the same as the current
1693 * first-hop router for the specified ICMP Destination Address.
1694 */
1695
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001696 if (!ndisc_parse_options(msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07001697 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
1698 return;
1699 }
David S. Miller6e157b62012-07-12 00:05:02 -07001700
1701 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07001702 if (ndopts.nd_opts_tgt_lladdr) {
1703 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
1704 skb->dev);
1705 if (!lladdr) {
1706 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
1707 return;
1708 }
1709 }
1710
David S. Miller6e157b62012-07-12 00:05:02 -07001711 rt = (struct rt6_info *) dst;
1712 if (rt == net->ipv6.ip6_null_entry) {
1713 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
1714 return;
1715 }
1716
1717 /* Redirect received -> path was valid.
1718 * Look, redirects are sent only in response to data packets,
1719 * so that this nexthop apparently is reachable. --ANK
1720 */
1721 dst_confirm(&rt->dst);
1722
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001723 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07001724 if (!neigh)
1725 return;
1726
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 /*
1728 * We have finally decided to accept it.
1729 */
1730
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001731 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1733 NEIGH_UPDATE_F_OVERRIDE|
1734 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1735 NEIGH_UPDATE_F_ISROUTER))
1736 );
1737
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001738 nrt = ip6_rt_copy(rt, &msg->dest);
David S. Miller38308472011-12-03 18:02:47 -05001739 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 goto out;
1741
1742 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
1743 if (on_link)
1744 nrt->rt6i_flags &= ~RTF_GATEWAY;
1745
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001746 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747
Thomas Graf40e22e82006-08-22 00:00:45 -07001748 if (ip6_ins_rt(nrt))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 goto out;
1750
Changli Gaod8d1f302010-06-10 23:31:35 -07001751 netevent.old = &rt->dst;
1752 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001753 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00001754 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07001755 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
1756
David S. Miller38308472011-12-03 18:02:47 -05001757 if (rt->rt6i_flags & RTF_CACHE) {
David S. Miller6e157b62012-07-12 00:05:02 -07001758 rt = (struct rt6_info *) dst_clone(&rt->dst);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001759 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 }
1761
1762out:
David S. Millere8599ff2012-07-11 23:43:53 -07001763 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07001764}
1765
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 * Misc support functions
1768 */
1769
Gao feng1716a962012-04-06 00:13:10 +00001770static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
Eric Dumazet21efcfa2011-07-19 20:18:36 +00001771 const struct in6_addr *dest)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772{
David S. Millerd1918542011-12-28 20:19:20 -05001773 struct net *net = dev_net(ort->dst.dev);
David S. Miller8b96d222012-06-11 02:01:56 -07001774 struct rt6_info *rt = ip6_dst_alloc(net, ort->dst.dev, 0,
1775 ort->rt6i_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776
1777 if (rt) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001778 rt->dst.input = ort->dst.input;
1779 rt->dst.output = ort->dst.output;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001780 rt->dst.flags |= DST_HOST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001782 rt->rt6i_dst.addr = *dest;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001783 rt->rt6i_dst.plen = 128;
David S. Millerdefb3512010-12-08 21:16:57 -08001784 dst_copy_metrics(&rt->dst, &ort->dst);
Changli Gaod8d1f302010-06-10 23:31:35 -07001785 rt->dst.error = ort->dst.error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 rt->rt6i_idev = ort->rt6i_idev;
1787 if (rt->rt6i_idev)
1788 in6_dev_hold(rt->rt6i_idev);
Changli Gaod8d1f302010-06-10 23:31:35 -07001789 rt->dst.lastuse = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001791 rt->rt6i_gateway = ort->rt6i_gateway;
Gao feng1716a962012-04-06 00:13:10 +00001792 rt->rt6i_flags = ort->rt6i_flags;
1793 if ((ort->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) ==
1794 (RTF_DEFAULT | RTF_ADDRCONF))
1795 rt6_set_from(rt, ort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 rt->rt6i_metric = 0;
1797
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798#ifdef CONFIG_IPV6_SUBTREES
1799 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1800#endif
Florian Westphal0f6c6392011-05-20 11:27:24 +00001801 memcpy(&rt->rt6i_prefsrc, &ort->rt6i_prefsrc, sizeof(struct rt6key));
Thomas Grafc71099a2006-08-04 23:20:06 -07001802 rt->rt6i_table = ort->rt6i_table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 }
1804 return rt;
1805}
1806
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001807#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001808static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001809 const struct in6_addr *prefix, int prefixlen,
1810 const struct in6_addr *gwaddr, int ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001811{
1812 struct fib6_node *fn;
1813 struct rt6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001814 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001815
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001816 table = fib6_get_table(net, RT6_TABLE_INFO);
David S. Miller38308472011-12-03 18:02:47 -05001817 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001818 return NULL;
1819
Li RongQing5744dd92012-09-11 21:59:01 +00001820 read_lock_bh(&table->tb6_lock);
Thomas Grafc71099a2006-08-04 23:20:06 -07001821 fn = fib6_locate(&table->tb6_root, prefix ,prefixlen, NULL, 0);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001822 if (!fn)
1823 goto out;
1824
Changli Gaod8d1f302010-06-10 23:31:35 -07001825 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05001826 if (rt->dst.dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001827 continue;
1828 if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
1829 continue;
1830 if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
1831 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07001832 dst_hold(&rt->dst);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001833 break;
1834 }
1835out:
Li RongQing5744dd92012-09-11 21:59:01 +00001836 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001837 return rt;
1838}
1839
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001840static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001841 const struct in6_addr *prefix, int prefixlen,
1842 const struct in6_addr *gwaddr, int ifindex,
Eric Dumazet95c96172012-04-15 05:58:06 +00001843 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001844{
Thomas Graf86872cb2006-08-22 00:01:08 -07001845 struct fib6_config cfg = {
1846 .fc_table = RT6_TABLE_INFO,
Rami Rosen238fc7e2008-02-09 23:43:11 -08001847 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07001848 .fc_ifindex = ifindex,
1849 .fc_dst_len = prefixlen,
1850 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
1851 RTF_UP | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00001852 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001853 .fc_nlinfo.nlh = NULL,
1854 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07001855 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001856
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001857 cfg.fc_dst = *prefix;
1858 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07001859
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08001860 /* We should treat it as a default route if prefix length is 0. */
1861 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07001862 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001863
Thomas Graf86872cb2006-08-22 00:01:08 -07001864 ip6_route_add(&cfg);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001865
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001866 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001867}
1868#endif
1869
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001870struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001871{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001873 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001875 table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05001876 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001877 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878
Li RongQing5744dd92012-09-11 21:59:01 +00001879 read_lock_bh(&table->tb6_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001880 for (rt = table->tb6_root.leaf; rt; rt=rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05001881 if (dev == rt->dst.dev &&
YOSHIFUJI Hideaki045927f2006-03-20 17:00:48 -08001882 ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 ipv6_addr_equal(&rt->rt6i_gateway, addr))
1884 break;
1885 }
1886 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07001887 dst_hold(&rt->dst);
Li RongQing5744dd92012-09-11 21:59:01 +00001888 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 return rt;
1890}
1891
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001892struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001893 struct net_device *dev,
1894 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895{
Thomas Graf86872cb2006-08-22 00:01:08 -07001896 struct fib6_config cfg = {
1897 .fc_table = RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08001898 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07001899 .fc_ifindex = dev->ifindex,
1900 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
1901 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00001902 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08001903 .fc_nlinfo.nlh = NULL,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001904 .fc_nlinfo.nl_net = dev_net(dev),
Thomas Graf86872cb2006-08-22 00:01:08 -07001905 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001907 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908
Thomas Graf86872cb2006-08-22 00:01:08 -07001909 ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 return rt6_get_dflt_router(gwaddr, dev);
1912}
1913
Daniel Lezcano7b4da532008-03-04 13:47:14 -08001914void rt6_purge_dflt_routers(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915{
1916 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001917 struct fib6_table *table;
1918
1919 /* NOTE: Keep consistent with rt6_get_dflt_router */
Daniel Lezcano7b4da532008-03-04 13:47:14 -08001920 table = fib6_get_table(net, RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05001921 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001922 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923
1924restart:
Thomas Grafc71099a2006-08-04 23:20:06 -07001925 read_lock_bh(&table->tb6_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001926 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
Lorenzo Colitti3e8b0ac2013-03-03 20:46:46 +00001927 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
1928 (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001929 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07001930 read_unlock_bh(&table->tb6_lock);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001931 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 goto restart;
1933 }
1934 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001935 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936}
1937
Daniel Lezcano55786892008-03-04 13:47:47 -08001938static void rtmsg_to_fib6_config(struct net *net,
1939 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07001940 struct fib6_config *cfg)
1941{
1942 memset(cfg, 0, sizeof(*cfg));
1943
1944 cfg->fc_table = RT6_TABLE_MAIN;
1945 cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
1946 cfg->fc_metric = rtmsg->rtmsg_metric;
1947 cfg->fc_expires = rtmsg->rtmsg_info;
1948 cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
1949 cfg->fc_src_len = rtmsg->rtmsg_src_len;
1950 cfg->fc_flags = rtmsg->rtmsg_flags;
1951
Daniel Lezcano55786892008-03-04 13:47:47 -08001952 cfg->fc_nlinfo.nl_net = net;
Benjamin Theryf1243c22008-02-26 18:10:03 -08001953
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001954 cfg->fc_dst = rtmsg->rtmsg_dst;
1955 cfg->fc_src = rtmsg->rtmsg_src;
1956 cfg->fc_gateway = rtmsg->rtmsg_gateway;
Thomas Graf86872cb2006-08-22 00:01:08 -07001957}
1958
Daniel Lezcano55786892008-03-04 13:47:47 -08001959int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960{
Thomas Graf86872cb2006-08-22 00:01:08 -07001961 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 struct in6_rtmsg rtmsg;
1963 int err;
1964
1965 switch(cmd) {
1966 case SIOCADDRT: /* Add a route */
1967 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00001968 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 return -EPERM;
1970 err = copy_from_user(&rtmsg, arg,
1971 sizeof(struct in6_rtmsg));
1972 if (err)
1973 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07001974
Daniel Lezcano55786892008-03-04 13:47:47 -08001975 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07001976
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 rtnl_lock();
1978 switch (cmd) {
1979 case SIOCADDRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07001980 err = ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 break;
1982 case SIOCDELRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07001983 err = ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 break;
1985 default:
1986 err = -EINVAL;
1987 }
1988 rtnl_unlock();
1989
1990 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001991 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992
1993 return -EINVAL;
1994}
1995
1996/*
1997 * Drop the packet on the floor
1998 */
1999
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07002000static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002002 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00002003 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002004 switch (ipstats_mib_noroutes) {
2005 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07002006 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00002007 if (type == IPV6_ADDR_ANY) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002008 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2009 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002010 break;
2011 }
2012 /* FALLTHROUGH */
2013 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002014 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2015 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002016 break;
2017 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002018 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 kfree_skb(skb);
2020 return 0;
2021}
2022
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002023static int ip6_pkt_discard(struct sk_buff *skb)
2024{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002025 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002026}
2027
Arnaldo Carvalho de Melo20380732005-08-16 02:18:02 -03002028static int ip6_pkt_discard_out(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029{
Eric Dumazetadf30902009-06-02 05:19:30 +00002030 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002031 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032}
2033
David S. Miller6723ab52006-10-18 21:20:57 -07002034#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2035
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002036static int ip6_pkt_prohibit(struct sk_buff *skb)
2037{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002038 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002039}
2040
2041static int ip6_pkt_prohibit_out(struct sk_buff *skb)
2042{
Eric Dumazetadf30902009-06-02 05:19:30 +00002043 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002044 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002045}
2046
David S. Miller6723ab52006-10-18 21:20:57 -07002047#endif
2048
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049/*
2050 * Allocate a dst for local (unicast / anycast) address.
2051 */
2052
2053struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
2054 const struct in6_addr *addr,
David S. Miller8f031512011-12-06 16:48:14 -05002055 bool anycast)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002057 struct net *net = dev_net(idev->dev);
David S. Miller8b96d222012-06-11 02:01:56 -07002058 struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev, 0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059
David S. Miller38308472011-12-03 18:02:47 -05002060 if (!rt) {
Joe Perchesf3213832012-05-15 14:11:53 +00002061 net_warn_ratelimited("Maximum number of routes reached, consider increasing route/max_size\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 return ERR_PTR(-ENOMEM);
Ben Greear40385652010-11-08 12:33:48 +00002063 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 in6_dev_hold(idev);
2066
David S. Miller11d53b42011-06-24 15:23:34 -07002067 rt->dst.flags |= DST_HOST;
Changli Gaod8d1f302010-06-10 23:31:35 -07002068 rt->dst.input = ip6_input;
2069 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 rt->rt6i_idev = idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071
2072 rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +09002073 if (anycast)
2074 rt->rt6i_flags |= RTF_ANYCAST;
2075 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 rt->rt6i_flags |= RTF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002078 rt->rt6i_dst.addr = *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 rt->rt6i_dst.plen = 128;
Daniel Lezcano55786892008-03-04 13:47:47 -08002080 rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081
Changli Gaod8d1f302010-06-10 23:31:35 -07002082 atomic_set(&rt->dst.__refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083
2084 return rt;
2085}
2086
Daniel Walterc3968a82011-04-13 21:10:57 +00002087int ip6_route_get_saddr(struct net *net,
2088 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002089 const struct in6_addr *daddr,
Daniel Walterc3968a82011-04-13 21:10:57 +00002090 unsigned int prefs,
2091 struct in6_addr *saddr)
2092{
2093 struct inet6_dev *idev = ip6_dst_idev((struct dst_entry*)rt);
2094 int err = 0;
2095 if (rt->rt6i_prefsrc.plen)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002096 *saddr = rt->rt6i_prefsrc.addr;
Daniel Walterc3968a82011-04-13 21:10:57 +00002097 else
2098 err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
2099 daddr, prefs, saddr);
2100 return err;
2101}
2102
2103/* remove deleted ip from prefsrc entries */
2104struct arg_dev_net_ip {
2105 struct net_device *dev;
2106 struct net *net;
2107 struct in6_addr *addr;
2108};
2109
2110static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
2111{
2112 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
2113 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
2114 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
2115
David S. Millerd1918542011-12-28 20:19:20 -05002116 if (((void *)rt->dst.dev == dev || !dev) &&
Daniel Walterc3968a82011-04-13 21:10:57 +00002117 rt != net->ipv6.ip6_null_entry &&
2118 ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
2119 /* remove prefsrc entry */
2120 rt->rt6i_prefsrc.plen = 0;
2121 }
2122 return 0;
2123}
2124
2125void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
2126{
2127 struct net *net = dev_net(ifp->idev->dev);
2128 struct arg_dev_net_ip adni = {
2129 .dev = ifp->idev->dev,
2130 .net = net,
2131 .addr = &ifp->addr,
2132 };
2133 fib6_clean_all(net, fib6_remove_prefsrc, 0, &adni);
2134}
2135
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002136struct arg_dev_net {
2137 struct net_device *dev;
2138 struct net *net;
2139};
2140
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141static int fib6_ifdown(struct rt6_info *rt, void *arg)
2142{
stephen hemmingerbc3ef662010-12-16 17:42:40 +00002143 const struct arg_dev_net *adn = arg;
2144 const struct net_device *dev = adn->dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002145
David S. Millerd1918542011-12-28 20:19:20 -05002146 if ((rt->dst.dev == dev || !dev) &&
David S. Millerc159d302011-12-26 15:24:36 -05002147 rt != adn->net->ipv6.ip6_null_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 return -1;
David S. Millerc159d302011-12-26 15:24:36 -05002149
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 return 0;
2151}
2152
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002153void rt6_ifdown(struct net *net, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002155 struct arg_dev_net adn = {
2156 .dev = dev,
2157 .net = net,
2158 };
2159
2160 fib6_clean_all(net, fib6_ifdown, 0, &adn);
David S. Miller1e493d12008-09-10 17:27:15 -07002161 icmp6_clean_all(fib6_ifdown, &adn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162}
2163
Eric Dumazet95c96172012-04-15 05:58:06 +00002164struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00002166 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167};
2168
2169static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
2170{
2171 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
2172 struct inet6_dev *idev;
2173
2174 /* In IPv6 pmtu discovery is not optional,
2175 so that RTAX_MTU lock cannot disable it.
2176 We still use this lock to block changes
2177 caused by addrconf/ndisc.
2178 */
2179
2180 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05002181 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 return 0;
2183
2184 /* For administrative MTU increase, there is no way to discover
2185 IPv6 PMTU increase, so PMTU increase should be updated here.
2186 Since RFC 1981 doesn't include administrative MTU increase
2187 update PMTU increase is a MUST. (i.e. jumbo frame)
2188 */
2189 /*
2190 If new MTU is less than route PMTU, this new MTU will be the
2191 lowest MTU in the path, update the route PMTU to reflect PMTU
2192 decreases; if new MTU is greater than route PMTU, and the
2193 old MTU is the lowest MTU in the path, update the route PMTU
2194 to reflect the increase. In this case if the other nodes' MTU
2195 also have the lowest MTU, TOO BIG MESSAGE will be lead to
2196 PMTU discouvery.
2197 */
David S. Millerd1918542011-12-28 20:19:20 -05002198 if (rt->dst.dev == arg->dev &&
Changli Gaod8d1f302010-06-10 23:31:35 -07002199 !dst_metric_locked(&rt->dst, RTAX_MTU) &&
2200 (dst_mtu(&rt->dst) >= arg->mtu ||
2201 (dst_mtu(&rt->dst) < arg->mtu &&
2202 dst_mtu(&rt->dst) == idev->cnf.mtu6))) {
David S. Millerdefb3512010-12-08 21:16:57 -08002203 dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu);
Simon Arlott566cfd82007-07-26 00:09:55 -07002204 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 return 0;
2206}
2207
Eric Dumazet95c96172012-04-15 05:58:06 +00002208void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209{
Thomas Grafc71099a2006-08-04 23:20:06 -07002210 struct rt6_mtu_change_arg arg = {
2211 .dev = dev,
2212 .mtu = mtu,
2213 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002215 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, 0, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216}
2217
Patrick McHardyef7c79e2007-06-05 12:38:30 -07002218static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07002219 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07002220 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07002221 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002222 [RTA_PRIORITY] = { .type = NLA_U32 },
2223 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002224 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Thomas Graf86872cb2006-08-22 00:01:08 -07002225};
2226
2227static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
2228 struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229{
Thomas Graf86872cb2006-08-22 00:01:08 -07002230 struct rtmsg *rtm;
2231 struct nlattr *tb[RTA_MAX+1];
2232 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233
Thomas Graf86872cb2006-08-22 00:01:08 -07002234 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2235 if (err < 0)
2236 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237
Thomas Graf86872cb2006-08-22 00:01:08 -07002238 err = -EINVAL;
2239 rtm = nlmsg_data(nlh);
2240 memset(cfg, 0, sizeof(*cfg));
2241
2242 cfg->fc_table = rtm->rtm_table;
2243 cfg->fc_dst_len = rtm->rtm_dst_len;
2244 cfg->fc_src_len = rtm->rtm_src_len;
2245 cfg->fc_flags = RTF_UP;
2246 cfg->fc_protocol = rtm->rtm_protocol;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002247 cfg->fc_type = rtm->rtm_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07002248
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002249 if (rtm->rtm_type == RTN_UNREACHABLE ||
2250 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002251 rtm->rtm_type == RTN_PROHIBIT ||
2252 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07002253 cfg->fc_flags |= RTF_REJECT;
2254
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002255 if (rtm->rtm_type == RTN_LOCAL)
2256 cfg->fc_flags |= RTF_LOCAL;
2257
Eric W. Biederman15e47302012-09-07 20:12:54 +00002258 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
Thomas Graf86872cb2006-08-22 00:01:08 -07002259 cfg->fc_nlinfo.nlh = nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002260 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
Thomas Graf86872cb2006-08-22 00:01:08 -07002261
2262 if (tb[RTA_GATEWAY]) {
2263 nla_memcpy(&cfg->fc_gateway, tb[RTA_GATEWAY], 16);
2264 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002266
2267 if (tb[RTA_DST]) {
2268 int plen = (rtm->rtm_dst_len + 7) >> 3;
2269
2270 if (nla_len(tb[RTA_DST]) < plen)
2271 goto errout;
2272
2273 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002275
2276 if (tb[RTA_SRC]) {
2277 int plen = (rtm->rtm_src_len + 7) >> 3;
2278
2279 if (nla_len(tb[RTA_SRC]) < plen)
2280 goto errout;
2281
2282 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002284
Daniel Walterc3968a82011-04-13 21:10:57 +00002285 if (tb[RTA_PREFSRC])
2286 nla_memcpy(&cfg->fc_prefsrc, tb[RTA_PREFSRC], 16);
2287
Thomas Graf86872cb2006-08-22 00:01:08 -07002288 if (tb[RTA_OIF])
2289 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
2290
2291 if (tb[RTA_PRIORITY])
2292 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
2293
2294 if (tb[RTA_METRICS]) {
2295 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
2296 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002298
2299 if (tb[RTA_TABLE])
2300 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
2301
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002302 if (tb[RTA_MULTIPATH]) {
2303 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
2304 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
2305 }
2306
Thomas Graf86872cb2006-08-22 00:01:08 -07002307 err = 0;
2308errout:
2309 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310}
2311
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002312static int ip6_route_multipath(struct fib6_config *cfg, int add)
2313{
2314 struct fib6_config r_cfg;
2315 struct rtnexthop *rtnh;
2316 int remaining;
2317 int attrlen;
2318 int err = 0, last_err = 0;
2319
2320beginning:
2321 rtnh = (struct rtnexthop *)cfg->fc_mp;
2322 remaining = cfg->fc_mp_len;
2323
2324 /* Parse a Multipath Entry */
2325 while (rtnh_ok(rtnh, remaining)) {
2326 memcpy(&r_cfg, cfg, sizeof(*cfg));
2327 if (rtnh->rtnh_ifindex)
2328 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
2329
2330 attrlen = rtnh_attrlen(rtnh);
2331 if (attrlen > 0) {
2332 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
2333
2334 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
2335 if (nla) {
2336 nla_memcpy(&r_cfg.fc_gateway, nla, 16);
2337 r_cfg.fc_flags |= RTF_GATEWAY;
2338 }
2339 }
2340 err = add ? ip6_route_add(&r_cfg) : ip6_route_del(&r_cfg);
2341 if (err) {
2342 last_err = err;
2343 /* If we are trying to remove a route, do not stop the
2344 * loop when ip6_route_del() fails (because next hop is
2345 * already gone), we should try to remove all next hops.
2346 */
2347 if (add) {
2348 /* If add fails, we should try to delete all
2349 * next hops that have been already added.
2350 */
2351 add = 0;
2352 goto beginning;
2353 }
2354 }
Nicolas Dichtel1a724182012-11-01 22:58:22 +00002355 /* Because each route is added like a single route we remove
2356 * this flag after the first nexthop (if there is a collision,
2357 * we have already fail to add the first nexthop:
2358 * fib6_add_rt2node() has reject it).
2359 */
2360 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~NLM_F_EXCL;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002361 rtnh = rtnh_next(rtnh, &remaining);
2362 }
2363
2364 return last_err;
2365}
2366
Thomas Graf661d2962013-03-21 07:45:29 +00002367static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368{
Thomas Graf86872cb2006-08-22 00:01:08 -07002369 struct fib6_config cfg;
2370 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371
Thomas Graf86872cb2006-08-22 00:01:08 -07002372 err = rtm_to_fib6_config(skb, nlh, &cfg);
2373 if (err < 0)
2374 return err;
2375
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002376 if (cfg.fc_mp)
2377 return ip6_route_multipath(&cfg, 0);
2378 else
2379 return ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380}
2381
Thomas Graf661d2962013-03-21 07:45:29 +00002382static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383{
Thomas Graf86872cb2006-08-22 00:01:08 -07002384 struct fib6_config cfg;
2385 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386
Thomas Graf86872cb2006-08-22 00:01:08 -07002387 err = rtm_to_fib6_config(skb, nlh, &cfg);
2388 if (err < 0)
2389 return err;
2390
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002391 if (cfg.fc_mp)
2392 return ip6_route_multipath(&cfg, 1);
2393 else
2394 return ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395}
2396
Thomas Graf339bf982006-11-10 14:10:15 -08002397static inline size_t rt6_nlmsg_size(void)
2398{
2399 return NLMSG_ALIGN(sizeof(struct rtmsg))
2400 + nla_total_size(16) /* RTA_SRC */
2401 + nla_total_size(16) /* RTA_DST */
2402 + nla_total_size(16) /* RTA_GATEWAY */
2403 + nla_total_size(16) /* RTA_PREFSRC */
2404 + nla_total_size(4) /* RTA_TABLE */
2405 + nla_total_size(4) /* RTA_IIF */
2406 + nla_total_size(4) /* RTA_OIF */
2407 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08002408 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Thomas Graf339bf982006-11-10 14:10:15 -08002409 + nla_total_size(sizeof(struct rta_cacheinfo));
2410}
2411
Brian Haley191cd582008-08-14 15:33:21 -07002412static int rt6_fill_node(struct net *net,
2413 struct sk_buff *skb, struct rt6_info *rt,
Jamal Hadi Salim0d51aa82005-06-21 13:51:04 -07002414 struct in6_addr *dst, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002415 int iif, int type, u32 portid, u32 seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002416 int prefix, int nowait, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417{
2418 struct rtmsg *rtm;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002419 struct nlmsghdr *nlh;
Thomas Grafe3703b32006-11-27 09:27:07 -08002420 long expires;
Patrick McHardy9e762a42006-08-10 23:09:48 -07002421 u32 table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422
2423 if (prefix) { /* user wants prefix routes only */
2424 if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
2425 /* success since this is not a prefix route */
2426 return 1;
2427 }
2428 }
2429
Eric W. Biederman15e47302012-09-07 20:12:54 +00002430 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05002431 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08002432 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002433
2434 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 rtm->rtm_family = AF_INET6;
2436 rtm->rtm_dst_len = rt->rt6i_dst.plen;
2437 rtm->rtm_src_len = rt->rt6i_src.plen;
2438 rtm->rtm_tos = 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07002439 if (rt->rt6i_table)
Patrick McHardy9e762a42006-08-10 23:09:48 -07002440 table = rt->rt6i_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07002441 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07002442 table = RT6_TABLE_UNSPEC;
2443 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04002444 if (nla_put_u32(skb, RTA_TABLE, table))
2445 goto nla_put_failure;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002446 if (rt->rt6i_flags & RTF_REJECT) {
2447 switch (rt->dst.error) {
2448 case -EINVAL:
2449 rtm->rtm_type = RTN_BLACKHOLE;
2450 break;
2451 case -EACCES:
2452 rtm->rtm_type = RTN_PROHIBIT;
2453 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002454 case -EAGAIN:
2455 rtm->rtm_type = RTN_THROW;
2456 break;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002457 default:
2458 rtm->rtm_type = RTN_UNREACHABLE;
2459 break;
2460 }
2461 }
David S. Miller38308472011-12-03 18:02:47 -05002462 else if (rt->rt6i_flags & RTF_LOCAL)
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002463 rtm->rtm_type = RTN_LOCAL;
David S. Millerd1918542011-12-28 20:19:20 -05002464 else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 rtm->rtm_type = RTN_LOCAL;
2466 else
2467 rtm->rtm_type = RTN_UNICAST;
2468 rtm->rtm_flags = 0;
2469 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
2470 rtm->rtm_protocol = rt->rt6i_protocol;
David S. Miller38308472011-12-03 18:02:47 -05002471 if (rt->rt6i_flags & RTF_DYNAMIC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 rtm->rtm_protocol = RTPROT_REDIRECT;
Denis Ovsienkof0396f602012-07-10 04:45:50 +00002473 else if (rt->rt6i_flags & RTF_ADDRCONF) {
2474 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ROUTEINFO))
2475 rtm->rtm_protocol = RTPROT_RA;
2476 else
2477 rtm->rtm_protocol = RTPROT_KERNEL;
2478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479
David S. Miller38308472011-12-03 18:02:47 -05002480 if (rt->rt6i_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 rtm->rtm_flags |= RTM_F_CLONED;
2482
2483 if (dst) {
David S. Millerc78679e2012-04-01 20:27:33 -04002484 if (nla_put(skb, RTA_DST, 16, dst))
2485 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002486 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 } else if (rtm->rtm_dst_len)
David S. Millerc78679e2012-04-01 20:27:33 -04002488 if (nla_put(skb, RTA_DST, 16, &rt->rt6i_dst.addr))
2489 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490#ifdef CONFIG_IPV6_SUBTREES
2491 if (src) {
David S. Millerc78679e2012-04-01 20:27:33 -04002492 if (nla_put(skb, RTA_SRC, 16, src))
2493 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002494 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04002495 } else if (rtm->rtm_src_len &&
2496 nla_put(skb, RTA_SRC, 16, &rt->rt6i_src.addr))
2497 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002499 if (iif) {
2500#ifdef CONFIG_IPV6_MROUTE
2501 if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
Benjamin Thery8229efd2008-12-10 16:30:15 -08002502 int err = ip6mr_get_route(net, skb, rtm, nowait);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002503 if (err <= 0) {
2504 if (!nowait) {
2505 if (err == 0)
2506 return 0;
2507 goto nla_put_failure;
2508 } else {
2509 if (err == -EMSGSIZE)
2510 goto nla_put_failure;
2511 }
2512 }
2513 } else
2514#endif
David S. Millerc78679e2012-04-01 20:27:33 -04002515 if (nla_put_u32(skb, RTA_IIF, iif))
2516 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002517 } else if (dst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 struct in6_addr saddr_buf;
David S. Millerc78679e2012-04-01 20:27:33 -04002519 if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0 &&
2520 nla_put(skb, RTA_PREFSRC, 16, &saddr_buf))
2521 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07002523
Daniel Walterc3968a82011-04-13 21:10:57 +00002524 if (rt->rt6i_prefsrc.plen) {
2525 struct in6_addr saddr_buf;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002526 saddr_buf = rt->rt6i_prefsrc.addr;
David S. Millerc78679e2012-04-01 20:27:33 -04002527 if (nla_put(skb, RTA_PREFSRC, 16, &saddr_buf))
2528 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00002529 }
2530
David S. Millerdefb3512010-12-08 21:16:57 -08002531 if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07002532 goto nla_put_failure;
2533
YOSHIFUJI Hideaki / 吉藤英明dd0cbf22013-01-17 12:53:15 +00002534 if (rt->rt6i_flags & RTF_GATEWAY) {
2535 if (nla_put(skb, RTA_GATEWAY, 16, &rt->rt6i_gateway) < 0)
Eric Dumazet94f826b2012-03-27 09:53:52 +00002536 goto nla_put_failure;
Eric Dumazet94f826b2012-03-27 09:53:52 +00002537 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07002538
David S. Millerc78679e2012-04-01 20:27:33 -04002539 if (rt->dst.dev &&
2540 nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex))
2541 goto nla_put_failure;
2542 if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric))
2543 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00002544
2545 expires = (rt->rt6i_flags & RTF_EXPIRES) ? rt->dst.expires - jiffies : 0;
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07002546
David S. Miller87a50692012-07-10 05:06:14 -07002547 if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, rt->dst.error) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08002548 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549
Thomas Graf2d7202b2006-08-22 00:01:27 -07002550 return nlmsg_end(skb, nlh);
2551
2552nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002553 nlmsg_cancel(skb, nlh);
2554 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555}
2556
Patrick McHardy1b43af52006-08-10 23:11:17 -07002557int rt6_dump_route(struct rt6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558{
2559 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
2560 int prefix;
2561
Thomas Graf2d7202b2006-08-22 00:01:27 -07002562 if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
2563 struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0;
2565 } else
2566 prefix = 0;
2567
Brian Haley191cd582008-08-14 15:33:21 -07002568 return rt6_fill_node(arg->net,
2569 arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002570 NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002571 prefix, 0, NLM_F_MULTI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572}
2573
Thomas Graf661d2962013-03-21 07:45:29 +00002574static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002576 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07002577 struct nlattr *tb[RTA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07002579 struct sk_buff *skb;
2580 struct rtmsg *rtm;
David S. Miller4c9483b2011-03-12 16:22:43 -05002581 struct flowi6 fl6;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002582 int err, iif = 0, oif = 0;
Thomas Grafab364a62006-08-22 00:01:47 -07002583
2584 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2585 if (err < 0)
2586 goto errout;
2587
2588 err = -EINVAL;
David S. Miller4c9483b2011-03-12 16:22:43 -05002589 memset(&fl6, 0, sizeof(fl6));
Thomas Grafab364a62006-08-22 00:01:47 -07002590
2591 if (tb[RTA_SRC]) {
2592 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
2593 goto errout;
2594
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002595 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07002596 }
2597
2598 if (tb[RTA_DST]) {
2599 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
2600 goto errout;
2601
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002602 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07002603 }
2604
2605 if (tb[RTA_IIF])
2606 iif = nla_get_u32(tb[RTA_IIF]);
2607
2608 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002609 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07002610
2611 if (iif) {
2612 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002613 int flags = 0;
2614
Daniel Lezcano55786892008-03-04 13:47:47 -08002615 dev = __dev_get_by_index(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07002616 if (!dev) {
2617 err = -ENODEV;
2618 goto errout;
2619 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002620
2621 fl6.flowi6_iif = iif;
2622
2623 if (!ipv6_addr_any(&fl6.saddr))
2624 flags |= RT6_LOOKUP_F_HAS_SADDR;
2625
2626 rt = (struct rt6_info *)ip6_route_input_lookup(net, dev, &fl6,
2627 flags);
2628 } else {
2629 fl6.flowi6_oif = oif;
2630
2631 rt = (struct rt6_info *)ip6_route_output(net, NULL, &fl6);
Thomas Grafab364a62006-08-22 00:01:47 -07002632 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633
2634 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05002635 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00002636 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07002637 err = -ENOBUFS;
2638 goto errout;
2639 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640
2641 /* Reserve room for dummy headers, this skb can pass
2642 through good chunk of routing engine.
2643 */
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07002644 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
2646
Changli Gaod8d1f302010-06-10 23:31:35 -07002647 skb_dst_set(skb, &rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648
David S. Miller4c9483b2011-03-12 16:22:43 -05002649 err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002650 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002651 nlh->nlmsg_seq, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07002653 kfree_skb(skb);
2654 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 }
2656
Eric W. Biederman15e47302012-09-07 20:12:54 +00002657 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07002658errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660}
2661
Thomas Graf86872cb2006-08-22 00:01:08 -07002662void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663{
2664 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08002665 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002666 u32 seq;
2667 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002669 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05002670 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07002671
Thomas Graf339bf982006-11-10 14:10:15 -08002672 skb = nlmsg_new(rt6_nlmsg_size(), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05002673 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07002674 goto errout;
2675
Brian Haley191cd582008-08-14 15:33:21 -07002676 err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002677 event, info->portid, seq, 0, 0, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08002678 if (err < 0) {
2679 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
2680 WARN_ON(err == -EMSGSIZE);
2681 kfree_skb(skb);
2682 goto errout;
2683 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00002684 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08002685 info->nlh, gfp_any());
2686 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07002687errout:
2688 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08002689 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690}
2691
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002692static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00002693 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002694{
Jiri Pirko351638e2013-05-28 01:30:21 +00002695 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002696 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002697
2698 if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002699 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002700 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
2701#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07002702 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002703 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07002704 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002705 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
2706#endif
2707 }
2708
2709 return NOTIFY_OK;
2710}
2711
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712/*
2713 * /proc
2714 */
2715
2716#ifdef CONFIG_PROC_FS
2717
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718struct rt6_proc_arg
2719{
2720 char *buffer;
2721 int offset;
2722 int length;
2723 int skip;
2724 int len;
2725};
2726
2727static int rt6_info_route(struct rt6_info *rt, void *p_arg)
2728{
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002729 struct seq_file *m = p_arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730
Harvey Harrison4b7a4272008-10-29 12:50:24 -07002731 seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732
2733#ifdef CONFIG_IPV6_SUBTREES
Harvey Harrison4b7a4272008-10-29 12:50:24 -07002734 seq_printf(m, "%pi6 %02x ", &rt->rt6i_src.addr, rt->rt6i_src.plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735#else
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002736 seq_puts(m, "00000000000000000000000000000000 00 ");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737#endif
YOSHIFUJI Hideaki / 吉藤英明dd0cbf22013-01-17 12:53:15 +00002738 if (rt->rt6i_flags & RTF_GATEWAY) {
2739 seq_printf(m, "%pi6", &rt->rt6i_gateway);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 } else {
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002741 seq_puts(m, "00000000000000000000000000000000");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 }
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002743 seq_printf(m, " %08x %08x %08x %08x %8s\n",
Changli Gaod8d1f302010-06-10 23:31:35 -07002744 rt->rt6i_metric, atomic_read(&rt->dst.__refcnt),
2745 rt->dst.__use, rt->rt6i_flags,
David S. Millerd1918542011-12-28 20:19:20 -05002746 rt->dst.dev ? rt->dst.dev->name : "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 return 0;
2748}
2749
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002750static int ipv6_route_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751{
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002752 struct net *net = (struct net *)m->private;
Josh Hunt32b293a2011-12-28 13:23:07 +00002753 fib6_clean_all_ro(net, rt6_info_route, 0, m);
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002754 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755}
2756
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002757static int ipv6_route_open(struct inode *inode, struct file *file)
2758{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07002759 return single_open_net(inode, file, ipv6_route_show);
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002760}
2761
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002762static const struct file_operations ipv6_route_proc_fops = {
2763 .owner = THIS_MODULE,
2764 .open = ipv6_route_open,
2765 .read = seq_read,
2766 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07002767 .release = single_release_net,
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002768};
2769
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770static int rt6_stats_seq_show(struct seq_file *seq, void *v)
2771{
Daniel Lezcano69ddb8052008-03-04 13:46:23 -08002772 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb8052008-03-04 13:46:23 -08002774 net->ipv6.rt6_stats->fib_nodes,
2775 net->ipv6.rt6_stats->fib_route_nodes,
2776 net->ipv6.rt6_stats->fib_rt_alloc,
2777 net->ipv6.rt6_stats->fib_rt_entries,
2778 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00002779 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb8052008-03-04 13:46:23 -08002780 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781
2782 return 0;
2783}
2784
2785static int rt6_stats_seq_open(struct inode *inode, struct file *file)
2786{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07002787 return single_open_net(inode, file, rt6_stats_seq_show);
Daniel Lezcano69ddb8052008-03-04 13:46:23 -08002788}
2789
Arjan van de Ven9a321442007-02-12 00:55:35 -08002790static const struct file_operations rt6_stats_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 .owner = THIS_MODULE,
2792 .open = rt6_stats_seq_open,
2793 .read = seq_read,
2794 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07002795 .release = single_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796};
2797#endif /* CONFIG_PROC_FS */
2798
2799#ifdef CONFIG_SYSCTL
2800
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801static
Joe Perchesfe2c6332013-06-11 23:04:25 -07002802int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 void __user *buffer, size_t *lenp, loff_t *ppos)
2804{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00002805 struct net *net;
2806 int delay;
2807 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00002809
2810 net = (struct net *)ctl->extra1;
2811 delay = net->ipv6.sysctl.flush_delay;
2812 proc_dointvec(ctl, write, buffer, lenp, ppos);
2813 fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net);
2814 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815}
2816
Joe Perchesfe2c6332013-06-11 23:04:25 -07002817struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002818 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08002820 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07002822 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002823 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 },
2825 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08002827 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 .maxlen = sizeof(int),
2829 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002830 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 },
2832 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08002834 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 .maxlen = sizeof(int),
2836 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002837 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 },
2839 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08002841 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 .maxlen = sizeof(int),
2843 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002844 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 },
2846 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08002848 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 .maxlen = sizeof(int),
2850 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002851 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 },
2853 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08002855 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 .maxlen = sizeof(int),
2857 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002858 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 },
2860 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08002862 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 .maxlen = sizeof(int),
2864 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07002865 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 },
2867 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08002869 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 .maxlen = sizeof(int),
2871 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002872 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 },
2874 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08002876 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 .maxlen = sizeof(int),
2878 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07002879 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880 },
2881 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08002883 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 .maxlen = sizeof(int),
2885 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002886 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002888 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889};
2890
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002891struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08002892{
2893 struct ctl_table *table;
2894
2895 table = kmemdup(ipv6_route_table_template,
2896 sizeof(ipv6_route_table_template),
2897 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09002898
2899 if (table) {
2900 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00002901 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00002902 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09002903 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
2904 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
2905 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
2906 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
2907 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
2908 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
2909 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08002910 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
Eric W. Biederman464dc802012-11-16 03:02:59 +00002911
2912 /* Don't export sysctls to unprivileged users */
2913 if (net->user_ns != &init_user_ns)
2914 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09002915 }
2916
Daniel Lezcano760f2d02008-01-10 02:53:43 -08002917 return table;
2918}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919#endif
2920
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002921static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08002922{
Pavel Emelyanov633d4242008-04-21 14:25:23 -07002923 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002924
Alexey Dobriyan86393e52009-08-29 01:34:49 +00002925 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
2926 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08002927
Eric Dumazetfc66f952010-10-08 06:37:34 +00002928 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
2929 goto out_ip6_dst_ops;
2930
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002931 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
2932 sizeof(*net->ipv6.ip6_null_entry),
2933 GFP_KERNEL);
2934 if (!net->ipv6.ip6_null_entry)
Eric Dumazetfc66f952010-10-08 06:37:34 +00002935 goto out_ip6_dst_entries;
Changli Gaod8d1f302010-06-10 23:31:35 -07002936 net->ipv6.ip6_null_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002937 (struct dst_entry *)net->ipv6.ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002938 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08002939 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
2940 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002941
2942#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2943 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
2944 sizeof(*net->ipv6.ip6_prohibit_entry),
2945 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07002946 if (!net->ipv6.ip6_prohibit_entry)
2947 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002948 net->ipv6.ip6_prohibit_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002949 (struct dst_entry *)net->ipv6.ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002950 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08002951 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
2952 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002953
2954 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
2955 sizeof(*net->ipv6.ip6_blk_hole_entry),
2956 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07002957 if (!net->ipv6.ip6_blk_hole_entry)
2958 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002959 net->ipv6.ip6_blk_hole_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002960 (struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002961 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08002962 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
2963 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002964#endif
2965
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07002966 net->ipv6.sysctl.flush_delay = 0;
2967 net->ipv6.sysctl.ip6_rt_max_size = 4096;
2968 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
2969 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
2970 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
2971 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
2972 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
2973 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
2974
Benjamin Thery6891a342008-03-04 13:49:47 -08002975 net->ipv6.ip6_rt_gc_expire = 30*HZ;
2976
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002977 ret = 0;
2978out:
2979 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08002980
Peter Zijlstra68fffc62008-10-07 14:12:10 -07002981#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2982out_ip6_prohibit_entry:
2983 kfree(net->ipv6.ip6_prohibit_entry);
2984out_ip6_null_entry:
2985 kfree(net->ipv6.ip6_null_entry);
2986#endif
Eric Dumazetfc66f952010-10-08 06:37:34 +00002987out_ip6_dst_entries:
2988 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08002989out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08002990 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08002991}
2992
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002993static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08002994{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002995 kfree(net->ipv6.ip6_null_entry);
2996#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2997 kfree(net->ipv6.ip6_prohibit_entry);
2998 kfree(net->ipv6.ip6_blk_hole_entry);
2999#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003000 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003001}
3002
Thomas Grafd1896342012-06-18 12:08:33 +00003003static int __net_init ip6_route_net_init_late(struct net *net)
3004{
3005#ifdef CONFIG_PROC_FS
Gao fengd4beaa62013-02-18 01:34:54 +00003006 proc_create("ipv6_route", 0, net->proc_net, &ipv6_route_proc_fops);
3007 proc_create("rt6_stats", S_IRUGO, net->proc_net, &rt6_stats_seq_fops);
Thomas Grafd1896342012-06-18 12:08:33 +00003008#endif
3009 return 0;
3010}
3011
3012static void __net_exit ip6_route_net_exit_late(struct net *net)
3013{
3014#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00003015 remove_proc_entry("ipv6_route", net->proc_net);
3016 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00003017#endif
3018}
3019
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003020static struct pernet_operations ip6_route_net_ops = {
3021 .init = ip6_route_net_init,
3022 .exit = ip6_route_net_exit,
3023};
3024
David S. Millerc3426b42012-06-09 16:27:05 -07003025static int __net_init ipv6_inetpeer_init(struct net *net)
3026{
3027 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
3028
3029 if (!bp)
3030 return -ENOMEM;
3031 inet_peer_base_init(bp);
3032 net->ipv6.peers = bp;
3033 return 0;
3034}
3035
3036static void __net_exit ipv6_inetpeer_exit(struct net *net)
3037{
3038 struct inet_peer_base *bp = net->ipv6.peers;
3039
3040 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07003041 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07003042 kfree(bp);
3043}
3044
David S. Miller2b823f72012-06-09 19:00:16 -07003045static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07003046 .init = ipv6_inetpeer_init,
3047 .exit = ipv6_inetpeer_exit,
3048};
3049
Thomas Grafd1896342012-06-18 12:08:33 +00003050static struct pernet_operations ip6_route_net_late_ops = {
3051 .init = ip6_route_net_init_late,
3052 .exit = ip6_route_net_exit_late,
3053};
3054
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003055static struct notifier_block ip6_route_dev_notifier = {
3056 .notifier_call = ip6_route_dev_notify,
3057 .priority = 0,
3058};
3059
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003060int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003062 int ret;
3063
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003064 ret = -ENOMEM;
3065 ip6_dst_ops_template.kmem_cachep =
3066 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
3067 SLAB_HWCACHE_ALIGN, NULL);
3068 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08003069 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07003070
Eric Dumazetfc66f952010-10-08 06:37:34 +00003071 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003072 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003073 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003074
David S. Millerc3426b42012-06-09 16:27:05 -07003075 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
3076 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003077 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00003078
David S. Miller7e52b332012-06-15 15:51:55 -07003079 ret = register_pernet_subsys(&ip6_route_net_ops);
3080 if (ret)
3081 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07003082
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07003083 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
3084
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003085 /* Registering of the loopback is done before this portion of code,
3086 * the loopback reference in rt6_info will not be taken, do it
3087 * manually for init_net */
Changli Gaod8d1f302010-06-10 23:31:35 -07003088 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003089 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3090 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07003091 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003092 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07003093 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003094 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3095 #endif
David S. Millere8803b62012-06-16 01:12:19 -07003096 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003097 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003098 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003099
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003100 ret = xfrm6_init();
3101 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003102 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08003103
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003104 ret = fib6_rules_init();
3105 if (ret)
3106 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08003107
Thomas Grafd1896342012-06-18 12:08:33 +00003108 ret = register_pernet_subsys(&ip6_route_net_late_ops);
3109 if (ret)
3110 goto fib6_rules_init;
3111
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003112 ret = -ENOBUFS;
Greg Rosec7ac8672011-06-10 01:27:09 +00003113 if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) ||
3114 __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) ||
3115 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL))
Thomas Grafd1896342012-06-18 12:08:33 +00003116 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003117
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003118 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003119 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00003120 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003121
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003122out:
3123 return ret;
3124
Thomas Grafd1896342012-06-18 12:08:33 +00003125out_register_late_subsys:
3126 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003127fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003128 fib6_rules_cleanup();
3129xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003130 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00003131out_fib6_init:
3132 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003133out_register_subsys:
3134 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07003135out_register_inetpeer:
3136 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00003137out_dst_entries:
3138 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003139out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003140 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003141 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142}
3143
3144void ip6_route_cleanup(void)
3145{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003146 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00003147 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07003148 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07003151 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003152 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003153 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003154 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155}