blob: 9ff0b78a9c15d8a7703aeb69c0877171dd15394e [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);
Paul Marksa5a81f02012-12-03 10:26:54 +0000554 }
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000555 rcu_read_unlock_bh();
556
Paul Marksa5a81f02012-12-03 10:26:54 +0000557 return ret;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800558}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800560static int rt6_score_route(struct rt6_info *rt, int oif,
561 int strict)
562{
Paul Marksa5a81f02012-12-03 10:26:54 +0000563 int m;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900564
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700565 m = rt6_check_dev(rt, oif);
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700566 if (!m && (strict & RT6_LOOKUP_F_IFACE))
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800567 return -1;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800568#ifdef CONFIG_IPV6_ROUTER_PREF
569 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
570#endif
Paul Marksa5a81f02012-12-03 10:26:54 +0000571 if (!rt6_check_neigh(rt) && (strict & RT6_LOOKUP_F_REACHABLE))
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800572 return -1;
573 return m;
574}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
David S. Millerf11e6652007-03-24 20:36:25 -0700576static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
577 int *mpri, struct rt6_info *match)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800578{
David S. Millerf11e6652007-03-24 20:36:25 -0700579 int m;
580
581 if (rt6_check_expired(rt))
582 goto out;
583
584 m = rt6_score_route(rt, oif, strict);
585 if (m < 0)
586 goto out;
587
588 if (m > *mpri) {
589 if (strict & RT6_LOOKUP_F_REACHABLE)
590 rt6_probe(match);
591 *mpri = m;
592 match = rt;
593 } else if (strict & RT6_LOOKUP_F_REACHABLE) {
594 rt6_probe(rt);
595 }
596
597out:
598 return match;
599}
600
601static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
602 struct rt6_info *rr_head,
603 u32 metric, int oif, int strict)
604{
605 struct rt6_info *rt, *match;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800606 int mpri = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
David S. Millerf11e6652007-03-24 20:36:25 -0700608 match = NULL;
609 for (rt = rr_head; rt && rt->rt6i_metric == metric;
Changli Gaod8d1f302010-06-10 23:31:35 -0700610 rt = rt->dst.rt6_next)
David S. Millerf11e6652007-03-24 20:36:25 -0700611 match = find_match(rt, oif, strict, &mpri, match);
612 for (rt = fn->leaf; rt && rt != rr_head && rt->rt6i_metric == metric;
Changli Gaod8d1f302010-06-10 23:31:35 -0700613 rt = rt->dst.rt6_next)
David S. Millerf11e6652007-03-24 20:36:25 -0700614 match = find_match(rt, oif, strict, &mpri, match);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800615
David S. Millerf11e6652007-03-24 20:36:25 -0700616 return match;
617}
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800618
David S. Millerf11e6652007-03-24 20:36:25 -0700619static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
620{
621 struct rt6_info *match, *rt0;
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800622 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623
David S. Millerf11e6652007-03-24 20:36:25 -0700624 rt0 = fn->rr_ptr;
625 if (!rt0)
626 fn->rr_ptr = rt0 = fn->leaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
David S. Millerf11e6652007-03-24 20:36:25 -0700628 match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800630 if (!match &&
David S. Millerf11e6652007-03-24 20:36:25 -0700631 (strict & RT6_LOOKUP_F_REACHABLE)) {
Changli Gaod8d1f302010-06-10 23:31:35 -0700632 struct rt6_info *next = rt0->dst.rt6_next;
David S. Millerf11e6652007-03-24 20:36:25 -0700633
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800634 /* no entries matched; do round-robin */
David S. Millerf11e6652007-03-24 20:36:25 -0700635 if (!next || next->rt6i_metric != rt0->rt6i_metric)
636 next = fn->leaf;
637
638 if (next != rt0)
639 fn->rr_ptr = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 }
641
David S. Millerd1918542011-12-28 20:19:20 -0500642 net = dev_net(rt0->dst.dev);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000643 return match ? match : net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644}
645
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800646#ifdef CONFIG_IPV6_ROUTE_INFO
647int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000648 const struct in6_addr *gwaddr)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800649{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900650 struct net *net = dev_net(dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800651 struct route_info *rinfo = (struct route_info *) opt;
652 struct in6_addr prefix_buf, *prefix;
653 unsigned int pref;
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900654 unsigned long lifetime;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800655 struct rt6_info *rt;
656
657 if (len < sizeof(struct route_info)) {
658 return -EINVAL;
659 }
660
661 /* Sanity check for prefix_len and length */
662 if (rinfo->length > 3) {
663 return -EINVAL;
664 } else if (rinfo->prefix_len > 128) {
665 return -EINVAL;
666 } else if (rinfo->prefix_len > 64) {
667 if (rinfo->length < 2) {
668 return -EINVAL;
669 }
670 } else if (rinfo->prefix_len > 0) {
671 if (rinfo->length < 1) {
672 return -EINVAL;
673 }
674 }
675
676 pref = rinfo->route_pref;
677 if (pref == ICMPV6_ROUTER_PREF_INVALID)
Jens Rosenboom3933fc92009-09-10 06:25:11 +0000678 return -EINVAL;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800679
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900680 lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800681
682 if (rinfo->length == 3)
683 prefix = (struct in6_addr *)rinfo->prefix;
684 else {
685 /* this function is safe */
686 ipv6_addr_prefix(&prefix_buf,
687 (struct in6_addr *)rinfo->prefix,
688 rinfo->prefix_len);
689 prefix = &prefix_buf;
690 }
691
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800692 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, gwaddr,
693 dev->ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800694
695 if (rt && !lifetime) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -0700696 ip6_del_rt(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800697 rt = NULL;
698 }
699
700 if (!rt && lifetime)
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800701 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800702 pref);
703 else if (rt)
704 rt->rt6i_flags = RTF_ROUTEINFO |
705 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
706
707 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +0000708 if (!addrconf_finite_timeout(lifetime))
709 rt6_clean_expires(rt);
710 else
711 rt6_set_expires(rt, jiffies + HZ * lifetime);
712
Amerigo Wang94e187c2012-10-29 00:13:19 +0000713 ip6_rt_put(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800714 }
715 return 0;
716}
717#endif
718
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800719#define BACKTRACK(__net, saddr) \
YOSHIFUJI Hideaki982f56f2006-08-23 17:22:39 -0700720do { \
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800721 if (rt == __net->ipv6.ip6_null_entry) { \
YOSHIFUJI Hideaki982f56f2006-08-23 17:22:39 -0700722 struct fib6_node *pn; \
Ville Nuorvalae0eda7b2006-10-16 22:11:11 -0700723 while (1) { \
YOSHIFUJI Hideaki982f56f2006-08-23 17:22:39 -0700724 if (fn->fn_flags & RTN_TL_ROOT) \
725 goto out; \
726 pn = fn->parent; \
727 if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn) \
Kim Nordlund8bce65b2006-12-13 16:38:29 -0800728 fn = fib6_lookup(FIB6_SUBTREE(pn), NULL, saddr); \
YOSHIFUJI Hideaki982f56f2006-08-23 17:22:39 -0700729 else \
730 fn = pn; \
731 if (fn->fn_flags & RTN_RTINFO) \
732 goto restart; \
Thomas Grafc71099a2006-08-04 23:20:06 -0700733 } \
Thomas Grafc71099a2006-08-04 23:20:06 -0700734 } \
David S. Miller38308472011-12-03 18:02:47 -0500735} while (0)
Thomas Grafc71099a2006-08-04 23:20:06 -0700736
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800737static struct rt6_info *ip6_pol_route_lookup(struct net *net,
738 struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500739 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740{
741 struct fib6_node *fn;
742 struct rt6_info *rt;
743
Thomas Grafc71099a2006-08-04 23:20:06 -0700744 read_lock_bh(&table->tb6_lock);
David S. Miller4c9483b2011-03-12 16:22:43 -0500745 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -0700746restart:
747 rt = fn->leaf;
David S. Miller4c9483b2011-03-12 16:22:43 -0500748 rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000749 if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0)
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200750 rt = rt6_multipath_select(rt, fl6, fl6->flowi6_oif, flags);
David S. Miller4c9483b2011-03-12 16:22:43 -0500751 BACKTRACK(net, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -0700752out:
Changli Gaod8d1f302010-06-10 23:31:35 -0700753 dst_use(&rt->dst, jiffies);
Thomas Grafc71099a2006-08-04 23:20:06 -0700754 read_unlock_bh(&table->tb6_lock);
Thomas Grafc71099a2006-08-04 23:20:06 -0700755 return rt;
756
757}
758
Florian Westphalea6e5742011-09-05 16:05:44 +0200759struct dst_entry * ip6_route_lookup(struct net *net, struct flowi6 *fl6,
760 int flags)
761{
762 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup);
763}
764EXPORT_SYMBOL_GPL(ip6_route_lookup);
765
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900766struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
767 const struct in6_addr *saddr, int oif, int strict)
Thomas Grafc71099a2006-08-04 23:20:06 -0700768{
David S. Miller4c9483b2011-03-12 16:22:43 -0500769 struct flowi6 fl6 = {
770 .flowi6_oif = oif,
771 .daddr = *daddr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700772 };
773 struct dst_entry *dst;
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700774 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
Thomas Grafc71099a2006-08-04 23:20:06 -0700775
Thomas Grafadaa70b2006-10-13 15:01:03 -0700776 if (saddr) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500777 memcpy(&fl6.saddr, saddr, sizeof(*saddr));
Thomas Grafadaa70b2006-10-13 15:01:03 -0700778 flags |= RT6_LOOKUP_F_HAS_SADDR;
779 }
780
David S. Miller4c9483b2011-03-12 16:22:43 -0500781 dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup);
Thomas Grafc71099a2006-08-04 23:20:06 -0700782 if (dst->error == 0)
783 return (struct rt6_info *) dst;
784
785 dst_release(dst);
786
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 return NULL;
788}
789
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900790EXPORT_SYMBOL(rt6_lookup);
791
Thomas Grafc71099a2006-08-04 23:20:06 -0700792/* ip6_ins_rt is called with FREE table->tb6_lock.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 It takes new route entry, the addition fails by any reason the
794 route is freed. In any case, if caller does not hold it, it may
795 be destroyed.
796 */
797
Thomas Graf86872cb2006-08-22 00:01:08 -0700798static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799{
800 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -0700801 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802
Thomas Grafc71099a2006-08-04 23:20:06 -0700803 table = rt->rt6i_table;
804 write_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -0700805 err = fib6_add(&table->tb6_root, rt, info);
Thomas Grafc71099a2006-08-04 23:20:06 -0700806 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
808 return err;
809}
810
Thomas Graf40e22e82006-08-22 00:00:45 -0700811int ip6_ins_rt(struct rt6_info *rt)
812{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -0800813 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -0500814 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -0800815 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -0800816 return __ip6_ins_rt(rt, &info);
Thomas Graf40e22e82006-08-22 00:00:45 -0700817}
818
Gao feng1716a962012-04-06 00:13:10 +0000819static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort,
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000820 const struct in6_addr *daddr,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000821 const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 struct rt6_info *rt;
824
825 /*
826 * Clone the route.
827 */
828
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000829 rt = ip6_rt_copy(ort, daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830
831 if (rt) {
David S. Miller38308472011-12-03 18:02:47 -0500832 if (!(rt->rt6i_flags & RTF_GATEWAY)) {
David S. Millerbb3c3682011-12-13 17:35:06 -0500833 if (ort->rt6i_dst.plen != 128 &&
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000834 ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +0900835 rt->rt6i_flags |= RTF_ANYCAST;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000836 rt->rt6i_gateway = *daddr;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +0900837 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 rt->rt6i_flags |= RTF_CACHE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
841#ifdef CONFIG_IPV6_SUBTREES
842 if (rt->rt6i_src.plen && saddr) {
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000843 rt->rt6i_src.addr = *saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 rt->rt6i_src.plen = 128;
845 }
846#endif
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800847 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800849 return rt;
850}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000852static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort,
853 const struct in6_addr *daddr)
YOSHIFUJI Hideaki299d9932006-03-20 16:58:32 -0800854{
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000855 struct rt6_info *rt = ip6_rt_copy(ort, daddr);
856
YOSHIFUJI Hideaki / 吉藤英明887c95c2013-01-17 12:54:05 +0000857 if (rt)
YOSHIFUJI Hideaki299d9932006-03-20 16:58:32 -0800858 rt->rt6i_flags |= RTF_CACHE;
YOSHIFUJI Hideaki299d9932006-03-20 16:58:32 -0800859 return rt;
860}
861
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800862static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif,
David S. Miller4c9483b2011-03-12 16:22:43 -0500863 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864{
865 struct fib6_node *fn;
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800866 struct rt6_info *rt, *nrt;
Thomas Grafc71099a2006-08-04 23:20:06 -0700867 int strict = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 int attempts = 3;
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800869 int err;
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700870 int reachable = net->ipv6.devconf_all->forwarding ? 0 : RT6_LOOKUP_F_REACHABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700872 strict |= flags & RT6_LOOKUP_F_IFACE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873
874relookup:
Thomas Grafc71099a2006-08-04 23:20:06 -0700875 read_lock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876
YOSHIFUJI Hideaki8238dd02006-03-20 17:04:35 -0800877restart_2:
David S. Miller4c9483b2011-03-12 16:22:43 -0500878 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879
880restart:
Pavel Emelyanov4acad722007-10-15 13:02:51 -0700881 rt = rt6_select(fn, oif, strict | reachable);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200882 if (rt->rt6i_nsiblings)
883 rt = rt6_multipath_select(rt, fl6, oif, strict | reachable);
David S. Miller4c9483b2011-03-12 16:22:43 -0500884 BACKTRACK(net, &fl6->saddr);
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800885 if (rt == net->ipv6.ip6_null_entry ||
YOSHIFUJI Hideaki8238dd02006-03-20 17:04:35 -0800886 rt->rt6i_flags & RTF_CACHE)
YOSHIFUJI Hideaki1ddef0442006-03-20 17:01:24 -0800887 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888
Changli Gaod8d1f302010-06-10 23:31:35 -0700889 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -0700890 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -0800891
YOSHIFUJI Hideaki / 吉藤英明c440f162013-01-17 12:53:32 +0000892 if (!(rt->rt6i_flags & (RTF_NONEXTHOP | RTF_GATEWAY)))
David S. Miller4c9483b2011-03-12 16:22:43 -0500893 nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr);
David S. Miller7343ff32011-03-09 19:55:25 -0800894 else if (!(rt->dst.flags & DST_HOST))
David S. Miller4c9483b2011-03-12 16:22:43 -0500895 nrt = rt6_alloc_clone(rt, &fl6->daddr);
David S. Miller7343ff32011-03-09 19:55:25 -0800896 else
897 goto out2;
YOSHIFUJI Hideakie40cf352006-03-20 16:59:27 -0800898
Amerigo Wang94e187c2012-10-29 00:13:19 +0000899 ip6_rt_put(rt);
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800900 rt = nrt ? : net->ipv6.ip6_null_entry;
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800901
Changli Gaod8d1f302010-06-10 23:31:35 -0700902 dst_hold(&rt->dst);
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800903 if (nrt) {
Thomas Graf40e22e82006-08-22 00:00:45 -0700904 err = ip6_ins_rt(nrt);
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800905 if (!err)
906 goto out2;
907 }
908
909 if (--attempts <= 0)
910 goto out2;
911
912 /*
Thomas Grafc71099a2006-08-04 23:20:06 -0700913 * Race condition! In the gap, when table->tb6_lock was
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800914 * released someone could insert this route. Relookup.
915 */
Amerigo Wang94e187c2012-10-29 00:13:19 +0000916 ip6_rt_put(rt);
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800917 goto relookup;
918
919out:
YOSHIFUJI Hideaki8238dd02006-03-20 17:04:35 -0800920 if (reachable) {
921 reachable = 0;
922 goto restart_2;
923 }
Changli Gaod8d1f302010-06-10 23:31:35 -0700924 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -0700925 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926out2:
Changli Gaod8d1f302010-06-10 23:31:35 -0700927 rt->dst.lastuse = jiffies;
928 rt->dst.__use++;
Thomas Grafc71099a2006-08-04 23:20:06 -0700929
930 return rt;
931}
932
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800933static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500934 struct flowi6 *fl6, int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -0700935{
David S. Miller4c9483b2011-03-12 16:22:43 -0500936 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -0700937}
938
Shmulik Ladkani72331bc2012-04-01 04:03:45 +0000939static struct dst_entry *ip6_route_input_lookup(struct net *net,
940 struct net_device *dev,
941 struct flowi6 *fl6, int flags)
942{
943 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
944 flags |= RT6_LOOKUP_F_IFACE;
945
946 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_input);
947}
948
Thomas Grafc71099a2006-08-04 23:20:06 -0700949void ip6_route_input(struct sk_buff *skb)
950{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000951 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900952 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -0700953 int flags = RT6_LOOKUP_F_HAS_SADDR;
David S. Miller4c9483b2011-03-12 16:22:43 -0500954 struct flowi6 fl6 = {
955 .flowi6_iif = skb->dev->ifindex,
956 .daddr = iph->daddr,
957 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +0000958 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -0500959 .flowi6_mark = skb->mark,
960 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700961 };
Thomas Grafadaa70b2006-10-13 15:01:03 -0700962
Shmulik Ladkani72331bc2012-04-01 04:03:45 +0000963 skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -0700964}
965
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800966static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500967 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -0700968{
David S. Miller4c9483b2011-03-12 16:22:43 -0500969 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -0700970}
971
Florian Westphal9c7a4f92011-03-22 19:17:36 -0700972struct dst_entry * ip6_route_output(struct net *net, const struct sock *sk,
David S. Miller4c9483b2011-03-12 16:22:43 -0500973 struct flowi6 *fl6)
Thomas Grafc71099a2006-08-04 23:20:06 -0700974{
975 int flags = 0;
976
Pavel Emelyanov1fb94892012-08-08 21:53:36 +0000977 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +0000978
David S. Miller4c9483b2011-03-12 16:22:43 -0500979 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700980 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -0700981
David S. Miller4c9483b2011-03-12 16:22:43 -0500982 if (!ipv6_addr_any(&fl6->saddr))
Thomas Grafadaa70b2006-10-13 15:01:03 -0700983 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +0000984 else if (sk)
985 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -0700986
David S. Miller4c9483b2011-03-12 16:22:43 -0500987 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988}
989
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900990EXPORT_SYMBOL(ip6_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
David S. Miller2774c132011-03-01 14:59:04 -0800992struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -0700993{
David S. Miller5c1e6aa2011-04-28 14:13:38 -0700994 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
David S. Miller14e50e52007-05-24 18:17:54 -0700995 struct dst_entry *new = NULL;
996
David S. Millerf5b0a872012-07-19 12:31:33 -0700997 rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, DST_OBSOLETE_NONE, 0);
David S. Miller14e50e52007-05-24 18:17:54 -0700998 if (rt) {
Changli Gaod8d1f302010-06-10 23:31:35 -0700999 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -07001000
Steffen Klassert81048912012-07-05 23:37:09 +00001001 memset(new + 1, 0, sizeof(*rt) - sizeof(*new));
1002 rt6_init_peer(rt, net->ipv6.peers);
1003
David S. Miller14e50e52007-05-24 18:17:54 -07001004 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08001005 new->input = dst_discard;
1006 new->output = dst_discard;
David S. Miller14e50e52007-05-24 18:17:54 -07001007
Eric Dumazet21efcfa2011-07-19 20:18:36 +00001008 if (dst_metrics_read_only(&ort->dst))
1009 new->_metrics = ort->dst._metrics;
1010 else
1011 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07001012 rt->rt6i_idev = ort->rt6i_idev;
1013 if (rt->rt6i_idev)
1014 in6_dev_hold(rt->rt6i_idev);
David S. Miller14e50e52007-05-24 18:17:54 -07001015
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001016 rt->rt6i_gateway = ort->rt6i_gateway;
Gao feng1716a962012-04-06 00:13:10 +00001017 rt->rt6i_flags = ort->rt6i_flags;
David S. Miller14e50e52007-05-24 18:17:54 -07001018 rt->rt6i_metric = 0;
1019
1020 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
1021#ifdef CONFIG_IPV6_SUBTREES
1022 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1023#endif
1024
1025 dst_free(new);
1026 }
1027
David S. Miller69ead7a2011-03-01 14:45:33 -08001028 dst_release(dst_orig);
1029 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07001030}
David S. Miller14e50e52007-05-24 18:17:54 -07001031
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032/*
1033 * Destination cache support functions
1034 */
1035
1036static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
1037{
1038 struct rt6_info *rt;
1039
1040 rt = (struct rt6_info *) dst;
1041
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00001042 /* All IPV6 dsts are created with ->obsolete set to the value
1043 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
1044 * into this function always.
1045 */
1046 if (rt->rt6i_genid != rt_genid(dev_net(rt->dst.dev)))
1047 return NULL;
1048
Li RongQinga4477c42012-11-07 21:56:33 +00001049 if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 return dst;
Li RongQinga4477c42012-11-07 21:56:33 +00001051
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 return NULL;
1053}
1054
1055static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
1056{
1057 struct rt6_info *rt = (struct rt6_info *) dst;
1058
1059 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001060 if (rt->rt6i_flags & RTF_CACHE) {
1061 if (rt6_check_expired(rt)) {
1062 ip6_del_rt(rt);
1063 dst = NULL;
1064 }
1065 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001067 dst = NULL;
1068 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001070 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071}
1072
1073static void ip6_link_failure(struct sk_buff *skb)
1074{
1075 struct rt6_info *rt;
1076
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00001077 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078
Eric Dumazetadf30902009-06-02 05:19:30 +00001079 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +00001081 if (rt->rt6i_flags & RTF_CACHE)
1082 rt6_update_expires(rt, 0);
1083 else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 rt->rt6i_node->fn_sernum = -1;
1085 }
1086}
1087
David S. Miller6700c272012-07-17 03:29:28 -07001088static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
1089 struct sk_buff *skb, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090{
1091 struct rt6_info *rt6 = (struct rt6_info*)dst;
1092
David S. Miller81aded22012-06-15 14:54:11 -07001093 dst_confirm(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 if (mtu < dst_mtu(dst) && rt6->rt6i_dst.plen == 128) {
David S. Miller81aded22012-06-15 14:54:11 -07001095 struct net *net = dev_net(dst->dev);
1096
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 rt6->rt6i_flags |= RTF_MODIFIED;
1098 if (mtu < IPV6_MIN_MTU) {
David S. Millerdefb3512010-12-08 21:16:57 -08001099 u32 features = dst_metric(dst, RTAX_FEATURES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 mtu = IPV6_MIN_MTU;
David S. Millerdefb3512010-12-08 21:16:57 -08001101 features |= RTAX_FEATURE_ALLFRAG;
1102 dst_metric_set(dst, RTAX_FEATURES, features);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 }
David S. Millerdefb3512010-12-08 21:16:57 -08001104 dst_metric_set(dst, RTAX_MTU, mtu);
David S. Miller81aded22012-06-15 14:54:11 -07001105 rt6_update_expires(rt6, net->ipv6.sysctl.ip6_rt_mtu_expires);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 }
1107}
1108
David S. Miller42ae66c2012-06-15 20:01:57 -07001109void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
1110 int oif, u32 mark)
David S. Miller81aded22012-06-15 14:54:11 -07001111{
1112 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1113 struct dst_entry *dst;
1114 struct flowi6 fl6;
1115
1116 memset(&fl6, 0, sizeof(fl6));
1117 fl6.flowi6_oif = oif;
1118 fl6.flowi6_mark = mark;
David S. Miller3e129392012-07-10 04:01:57 -07001119 fl6.flowi6_flags = 0;
David S. Miller81aded22012-06-15 14:54:11 -07001120 fl6.daddr = iph->daddr;
1121 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001122 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller81aded22012-06-15 14:54:11 -07001123
1124 dst = ip6_route_output(net, NULL, &fl6);
1125 if (!dst->error)
David S. Miller6700c272012-07-17 03:29:28 -07001126 ip6_rt_update_pmtu(dst, NULL, skb, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07001127 dst_release(dst);
1128}
1129EXPORT_SYMBOL_GPL(ip6_update_pmtu);
1130
1131void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
1132{
1133 ip6_update_pmtu(skb, sock_net(sk), mtu,
1134 sk->sk_bound_dev_if, sk->sk_mark);
1135}
1136EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
1137
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001138void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark)
1139{
1140 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1141 struct dst_entry *dst;
1142 struct flowi6 fl6;
1143
1144 memset(&fl6, 0, sizeof(fl6));
1145 fl6.flowi6_oif = oif;
1146 fl6.flowi6_mark = mark;
1147 fl6.flowi6_flags = 0;
1148 fl6.daddr = iph->daddr;
1149 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001150 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001151
1152 dst = ip6_route_output(net, NULL, &fl6);
1153 if (!dst->error)
David S. Miller6700c272012-07-17 03:29:28 -07001154 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001155 dst_release(dst);
1156}
1157EXPORT_SYMBOL_GPL(ip6_redirect);
1158
1159void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
1160{
1161 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark);
1162}
1163EXPORT_SYMBOL_GPL(ip6_sk_redirect);
1164
David S. Miller0dbaee32010-12-13 12:52:14 -08001165static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166{
David S. Miller0dbaee32010-12-13 12:52:14 -08001167 struct net_device *dev = dst->dev;
1168 unsigned int mtu = dst_mtu(dst);
1169 struct net *net = dev_net(dev);
1170
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
1172
Daniel Lezcano55786892008-03-04 13:47:47 -08001173 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
1174 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175
1176 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001177 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
1178 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
1179 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 * rely only on pmtu discovery"
1181 */
1182 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
1183 mtu = IPV6_MAXPLEN;
1184 return mtu;
1185}
1186
Steffen Klassertebb762f2011-11-23 02:12:51 +00001187static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08001188{
David S. Millerd33e4552010-12-14 13:01:14 -08001189 struct inet6_dev *idev;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001190 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
1191
1192 if (mtu)
1193 return mtu;
1194
1195 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08001196
1197 rcu_read_lock();
1198 idev = __in6_dev_get(dst->dev);
1199 if (idev)
1200 mtu = idev->cnf.mtu6;
1201 rcu_read_unlock();
1202
1203 return mtu;
1204}
1205
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001206static struct dst_entry *icmp6_dst_gc_list;
1207static DEFINE_SPINLOCK(icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001208
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001209struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05001210 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211{
David S. Miller87a11572011-12-06 17:04:13 -05001212 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 struct rt6_info *rt;
1214 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001215 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216
David S. Miller38308472011-12-03 18:02:47 -05001217 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00001218 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219
David S. Miller8b96d222012-06-11 02:01:56 -07001220 rt = ip6_dst_alloc(net, dev, 0, NULL);
David S. Miller38308472011-12-03 18:02:47 -05001221 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05001223 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 goto out;
1225 }
1226
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001227 rt->dst.flags |= DST_HOST;
1228 rt->dst.output = ip6_output;
Changli Gaod8d1f302010-06-10 23:31:35 -07001229 atomic_set(&rt->dst.__refcnt, 1);
David S. Miller87a11572011-12-06 17:04:13 -05001230 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001231 rt->rt6i_dst.plen = 128;
1232 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08001233 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001235 spin_lock_bh(&icmp6_dst_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001236 rt->dst.next = icmp6_dst_gc_list;
1237 icmp6_dst_gc_list = &rt->dst;
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001238 spin_unlock_bh(&icmp6_dst_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239
Daniel Lezcano55786892008-03-04 13:47:47 -08001240 fib6_force_start_gc(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241
David S. Miller87a11572011-12-06 17:04:13 -05001242 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
1243
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244out:
David S. Miller87a11572011-12-06 17:04:13 -05001245 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246}
1247
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001248int icmp6_dst_gc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249{
Hagen Paul Pfeifere9476e92011-02-25 05:45:19 +00001250 struct dst_entry *dst, **pprev;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001251 int more = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001253 spin_lock_bh(&icmp6_dst_lock);
1254 pprev = &icmp6_dst_gc_list;
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001255
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 while ((dst = *pprev) != NULL) {
1257 if (!atomic_read(&dst->__refcnt)) {
1258 *pprev = dst->next;
1259 dst_free(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 } else {
1261 pprev = &dst->next;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001262 ++more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 }
1264 }
1265
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001266 spin_unlock_bh(&icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001267
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001268 return more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269}
1270
David S. Miller1e493d12008-09-10 17:27:15 -07001271static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg),
1272 void *arg)
1273{
1274 struct dst_entry *dst, **pprev;
1275
1276 spin_lock_bh(&icmp6_dst_lock);
1277 pprev = &icmp6_dst_gc_list;
1278 while ((dst = *pprev) != NULL) {
1279 struct rt6_info *rt = (struct rt6_info *) dst;
1280 if (func(rt, arg)) {
1281 *pprev = dst->next;
1282 dst_free(dst);
1283 } else {
1284 pprev = &dst->next;
1285 }
1286 }
1287 spin_unlock_bh(&icmp6_dst_lock);
1288}
1289
Daniel Lezcano569d3642008-01-18 03:56:57 -08001290static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 unsigned long now = jiffies;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00001293 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08001294 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
1295 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
1296 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
1297 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
1298 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001299 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
Eric Dumazetfc66f952010-10-08 06:37:34 +00001301 entries = dst_entries_get_fast(ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08001302 if (time_after(rt_last_gc + rt_min_interval, now) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00001303 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 goto out;
1305
Benjamin Thery6891a342008-03-04 13:49:47 -08001306 net->ipv6.ip6_rt_gc_expire++;
1307 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net);
1308 net->ipv6.ip6_rt_last_gc = now;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001309 entries = dst_entries_get_slow(ops);
1310 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08001311 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08001313 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001314 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315}
1316
YOSHIFUJI Hideaki6b75d092008-03-10 06:00:30 -04001317int ip6_dst_hoplimit(struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318{
David S. Miller5170ae82010-12-12 21:35:57 -08001319 int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT);
David S. Millera02e4b72010-12-12 21:39:02 -08001320 if (hoplimit == 0) {
YOSHIFUJI Hideaki6b75d092008-03-10 06:00:30 -04001321 struct net_device *dev = dst->dev;
Eric Dumazetc68f24c2010-06-14 04:46:20 +00001322 struct inet6_dev *idev;
1323
1324 rcu_read_lock();
1325 idev = __in6_dev_get(dev);
1326 if (idev)
YOSHIFUJI Hideaki6b75d092008-03-10 06:00:30 -04001327 hoplimit = idev->cnf.hop_limit;
Eric Dumazetc68f24c2010-06-14 04:46:20 +00001328 else
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -07001329 hoplimit = dev_net(dev)->ipv6.devconf_all->hop_limit;
Eric Dumazetc68f24c2010-06-14 04:46:20 +00001330 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 }
1332 return hoplimit;
1333}
David S. Millerabbf46a2010-12-12 21:14:46 -08001334EXPORT_SYMBOL(ip6_dst_hoplimit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335
1336/*
1337 *
1338 */
1339
Thomas Graf86872cb2006-08-22 00:01:08 -07001340int ip6_route_add(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341{
1342 int err;
Daniel Lezcano55786892008-03-04 13:47:47 -08001343 struct net *net = cfg->fc_nlinfo.nl_net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 struct rt6_info *rt = NULL;
1345 struct net_device *dev = NULL;
1346 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001347 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 int addr_type;
1349
Thomas Graf86872cb2006-08-22 00:01:08 -07001350 if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 return -EINVAL;
1352#ifndef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001353 if (cfg->fc_src_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 return -EINVAL;
1355#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07001356 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08001358 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 if (!dev)
1360 goto out;
1361 idev = in6_dev_get(dev);
1362 if (!idev)
1363 goto out;
1364 }
1365
Thomas Graf86872cb2006-08-22 00:01:08 -07001366 if (cfg->fc_metric == 0)
1367 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368
Matti Vaittinend71314b2011-11-14 00:14:49 +00001369 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05001370 if (cfg->fc_nlinfo.nlh &&
1371 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00001372 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001373 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00001374 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00001375 table = fib6_new_table(net, cfg->fc_table);
1376 }
1377 } else {
1378 table = fib6_new_table(net, cfg->fc_table);
1379 }
David S. Miller38308472011-12-03 18:02:47 -05001380
1381 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001382 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07001383
David S. Miller8b96d222012-06-11 02:01:56 -07001384 rt = ip6_dst_alloc(net, NULL, DST_NOCOUNT, table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385
David S. Miller38308472011-12-03 18:02:47 -05001386 if (!rt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 err = -ENOMEM;
1388 goto out;
1389 }
1390
Gao feng1716a962012-04-06 00:13:10 +00001391 if (cfg->fc_flags & RTF_EXPIRES)
1392 rt6_set_expires(rt, jiffies +
1393 clock_t_to_jiffies(cfg->fc_expires));
1394 else
1395 rt6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396
Thomas Graf86872cb2006-08-22 00:01:08 -07001397 if (cfg->fc_protocol == RTPROT_UNSPEC)
1398 cfg->fc_protocol = RTPROT_BOOT;
1399 rt->rt6i_protocol = cfg->fc_protocol;
1400
1401 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
1403 if (addr_type & IPV6_ADDR_MULTICAST)
Changli Gaod8d1f302010-06-10 23:31:35 -07001404 rt->dst.input = ip6_mc_input;
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00001405 else if (cfg->fc_flags & RTF_LOCAL)
1406 rt->dst.input = ip6_input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 else
Changli Gaod8d1f302010-06-10 23:31:35 -07001408 rt->dst.input = ip6_forward;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409
Changli Gaod8d1f302010-06-10 23:31:35 -07001410 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411
Thomas Graf86872cb2006-08-22 00:01:08 -07001412 ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
1413 rt->rt6i_dst.plen = cfg->fc_dst_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 if (rt->rt6i_dst.plen == 128)
David S. Miller11d53b42011-06-24 15:23:34 -07001415 rt->dst.flags |= DST_HOST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001417 if (!(rt->dst.flags & DST_HOST) && cfg->fc_mx) {
1418 u32 *metrics = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
1419 if (!metrics) {
1420 err = -ENOMEM;
1421 goto out;
1422 }
1423 dst_init_metrics(&rt->dst, metrics, 0);
1424 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425#ifdef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001426 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
1427 rt->rt6i_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428#endif
1429
Thomas Graf86872cb2006-08-22 00:01:08 -07001430 rt->rt6i_metric = cfg->fc_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431
1432 /* We cannot add true routes via loopback here,
1433 they would result in kernel looping; promote them to reject routes
1434 */
Thomas Graf86872cb2006-08-22 00:01:08 -07001435 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05001436 (dev && (dev->flags & IFF_LOOPBACK) &&
1437 !(addr_type & IPV6_ADDR_LOOPBACK) &&
1438 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08001440 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 if (dev) {
1442 dev_put(dev);
1443 in6_dev_put(idev);
1444 }
Daniel Lezcano55786892008-03-04 13:47:47 -08001445 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 dev_hold(dev);
1447 idev = in6_dev_get(dev);
1448 if (!idev) {
1449 err = -ENODEV;
1450 goto out;
1451 }
1452 }
Changli Gaod8d1f302010-06-10 23:31:35 -07001453 rt->dst.output = ip6_pkt_discard_out;
1454 rt->dst.input = ip6_pkt_discard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001456 switch (cfg->fc_type) {
1457 case RTN_BLACKHOLE:
1458 rt->dst.error = -EINVAL;
1459 break;
1460 case RTN_PROHIBIT:
1461 rt->dst.error = -EACCES;
1462 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00001463 case RTN_THROW:
1464 rt->dst.error = -EAGAIN;
1465 break;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001466 default:
1467 rt->dst.error = -ENETUNREACH;
1468 break;
1469 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 goto install_route;
1471 }
1472
Thomas Graf86872cb2006-08-22 00:01:08 -07001473 if (cfg->fc_flags & RTF_GATEWAY) {
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001474 const struct in6_addr *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 int gwa_type;
1476
Thomas Graf86872cb2006-08-22 00:01:08 -07001477 gw_addr = &cfg->fc_gateway;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001478 rt->rt6i_gateway = *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 gwa_type = ipv6_addr_type(gw_addr);
1480
1481 if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
1482 struct rt6_info *grt;
1483
1484 /* IPv6 strictly inhibits using not link-local
1485 addresses as nexthop address.
1486 Otherwise, router will not able to send redirects.
1487 It is very good, but in some (rare!) circumstances
1488 (SIT, PtP, NBMA NOARP links) it is handy to allow
1489 some exceptions. --ANK
1490 */
1491 err = -EINVAL;
David S. Miller38308472011-12-03 18:02:47 -05001492 if (!(gwa_type & IPV6_ADDR_UNICAST))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 goto out;
1494
Daniel Lezcano55786892008-03-04 13:47:47 -08001495 grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496
1497 err = -EHOSTUNREACH;
David S. Miller38308472011-12-03 18:02:47 -05001498 if (!grt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 goto out;
1500 if (dev) {
David S. Millerd1918542011-12-28 20:19:20 -05001501 if (dev != grt->dst.dev) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00001502 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 goto out;
1504 }
1505 } else {
David S. Millerd1918542011-12-28 20:19:20 -05001506 dev = grt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 idev = grt->rt6i_idev;
1508 dev_hold(dev);
1509 in6_dev_hold(grt->rt6i_idev);
1510 }
David S. Miller38308472011-12-03 18:02:47 -05001511 if (!(grt->rt6i_flags & RTF_GATEWAY))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 err = 0;
Amerigo Wang94e187c2012-10-29 00:13:19 +00001513 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514
1515 if (err)
1516 goto out;
1517 }
1518 err = -EINVAL;
David S. Miller38308472011-12-03 18:02:47 -05001519 if (!dev || (dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 goto out;
1521 }
1522
1523 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05001524 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 goto out;
1526
Daniel Walterc3968a82011-04-13 21:10:57 +00001527 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
1528 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
1529 err = -EINVAL;
1530 goto out;
1531 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001532 rt->rt6i_prefsrc.addr = cfg->fc_prefsrc;
Daniel Walterc3968a82011-04-13 21:10:57 +00001533 rt->rt6i_prefsrc.plen = 128;
1534 } else
1535 rt->rt6i_prefsrc.plen = 0;
1536
Thomas Graf86872cb2006-08-22 00:01:08 -07001537 rt->rt6i_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538
1539install_route:
Thomas Graf86872cb2006-08-22 00:01:08 -07001540 if (cfg->fc_mx) {
1541 struct nlattr *nla;
1542 int remaining;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543
Thomas Graf86872cb2006-08-22 00:01:08 -07001544 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
Thomas Graf8f4c1f92007-09-12 14:44:36 +02001545 int type = nla_type(nla);
Thomas Graf86872cb2006-08-22 00:01:08 -07001546
1547 if (type) {
1548 if (type > RTAX_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 err = -EINVAL;
1550 goto out;
1551 }
Thomas Graf86872cb2006-08-22 00:01:08 -07001552
David S. Millerdefb3512010-12-08 21:16:57 -08001553 dst_metric_set(&rt->dst, type, nla_get_u32(nla));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 }
1556 }
1557
Changli Gaod8d1f302010-06-10 23:31:35 -07001558 rt->dst.dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 rt->rt6i_idev = idev;
Thomas Grafc71099a2006-08-04 23:20:06 -07001560 rt->rt6i_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001561
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001562 cfg->fc_nlinfo.nl_net = dev_net(dev);
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001563
Thomas Graf86872cb2006-08-22 00:01:08 -07001564 return __ip6_ins_rt(rt, &cfg->fc_nlinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565
1566out:
1567 if (dev)
1568 dev_put(dev);
1569 if (idev)
1570 in6_dev_put(idev);
1571 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07001572 dst_free(&rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 return err;
1574}
1575
Thomas Graf86872cb2006-08-22 00:01:08 -07001576static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577{
1578 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07001579 struct fib6_table *table;
David S. Millerd1918542011-12-28 20:19:20 -05001580 struct net *net = dev_net(rt->dst.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581
Gao feng6825a262012-09-19 19:25:34 +00001582 if (rt == net->ipv6.ip6_null_entry) {
1583 err = -ENOENT;
1584 goto out;
1585 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07001586
Thomas Grafc71099a2006-08-04 23:20:06 -07001587 table = rt->rt6i_table;
1588 write_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07001589 err = fib6_del(rt, info);
Thomas Grafc71099a2006-08-04 23:20:06 -07001590 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591
Gao feng6825a262012-09-19 19:25:34 +00001592out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00001593 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 return err;
1595}
1596
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001597int ip6_del_rt(struct rt6_info *rt)
1598{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08001599 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -05001600 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08001601 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08001602 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001603}
1604
Thomas Graf86872cb2006-08-22 00:01:08 -07001605static int ip6_route_del(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606{
Thomas Grafc71099a2006-08-04 23:20:06 -07001607 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 struct fib6_node *fn;
1609 struct rt6_info *rt;
1610 int err = -ESRCH;
1611
Daniel Lezcano55786892008-03-04 13:47:47 -08001612 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001613 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001614 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615
Thomas Grafc71099a2006-08-04 23:20:06 -07001616 read_lock_bh(&table->tb6_lock);
1617
1618 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07001619 &cfg->fc_dst, cfg->fc_dst_len,
1620 &cfg->fc_src, cfg->fc_src_len);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001621
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 if (fn) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001623 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
Thomas Graf86872cb2006-08-22 00:01:08 -07001624 if (cfg->fc_ifindex &&
David S. Millerd1918542011-12-28 20:19:20 -05001625 (!rt->dst.dev ||
1626 rt->dst.dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001628 if (cfg->fc_flags & RTF_GATEWAY &&
1629 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001631 if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07001633 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07001634 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635
Thomas Graf86872cb2006-08-22 00:01:08 -07001636 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 }
1638 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001639 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640
1641 return err;
1642}
1643
David S. Miller6700c272012-07-17 03:29:28 -07001644static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001645{
David S. Millere8599ff2012-07-11 23:43:53 -07001646 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001647 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07001648 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07001649 struct ndisc_options ndopts;
1650 struct inet6_dev *in6_dev;
1651 struct neighbour *neigh;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001652 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07001653 int optlen, on_link;
1654 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07001655
Simon Horman29a3cad2013-05-28 20:34:26 +00001656 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001657 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07001658
1659 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07001660 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001661 return;
1662 }
1663
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001664 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07001665
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001666 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07001667 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001668 return;
1669 }
1670
David S. Miller6e157b62012-07-12 00:05:02 -07001671 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001672 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07001673 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001674 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07001675 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07001676 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001677 return;
1678 }
1679
1680 in6_dev = __in6_dev_get(skb->dev);
1681 if (!in6_dev)
1682 return;
1683 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
1684 return;
1685
1686 /* RFC2461 8.1:
1687 * The IP source address of the Redirect MUST be the same as the current
1688 * first-hop router for the specified ICMP Destination Address.
1689 */
1690
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001691 if (!ndisc_parse_options(msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07001692 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
1693 return;
1694 }
David S. Miller6e157b62012-07-12 00:05:02 -07001695
1696 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07001697 if (ndopts.nd_opts_tgt_lladdr) {
1698 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
1699 skb->dev);
1700 if (!lladdr) {
1701 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
1702 return;
1703 }
1704 }
1705
David S. Miller6e157b62012-07-12 00:05:02 -07001706 rt = (struct rt6_info *) dst;
1707 if (rt == net->ipv6.ip6_null_entry) {
1708 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
1709 return;
1710 }
1711
1712 /* Redirect received -> path was valid.
1713 * Look, redirects are sent only in response to data packets,
1714 * so that this nexthop apparently is reachable. --ANK
1715 */
1716 dst_confirm(&rt->dst);
1717
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001718 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07001719 if (!neigh)
1720 return;
1721
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 /*
1723 * We have finally decided to accept it.
1724 */
1725
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001726 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1728 NEIGH_UPDATE_F_OVERRIDE|
1729 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1730 NEIGH_UPDATE_F_ISROUTER))
1731 );
1732
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001733 nrt = ip6_rt_copy(rt, &msg->dest);
David S. Miller38308472011-12-03 18:02:47 -05001734 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 goto out;
1736
1737 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
1738 if (on_link)
1739 nrt->rt6i_flags &= ~RTF_GATEWAY;
1740
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001741 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742
Thomas Graf40e22e82006-08-22 00:00:45 -07001743 if (ip6_ins_rt(nrt))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 goto out;
1745
Changli Gaod8d1f302010-06-10 23:31:35 -07001746 netevent.old = &rt->dst;
1747 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001748 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00001749 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07001750 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
1751
David S. Miller38308472011-12-03 18:02:47 -05001752 if (rt->rt6i_flags & RTF_CACHE) {
David S. Miller6e157b62012-07-12 00:05:02 -07001753 rt = (struct rt6_info *) dst_clone(&rt->dst);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001754 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 }
1756
1757out:
David S. Millere8599ff2012-07-11 23:43:53 -07001758 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07001759}
1760
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 * Misc support functions
1763 */
1764
Gao feng1716a962012-04-06 00:13:10 +00001765static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
Eric Dumazet21efcfa2011-07-19 20:18:36 +00001766 const struct in6_addr *dest)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767{
David S. Millerd1918542011-12-28 20:19:20 -05001768 struct net *net = dev_net(ort->dst.dev);
David S. Miller8b96d222012-06-11 02:01:56 -07001769 struct rt6_info *rt = ip6_dst_alloc(net, ort->dst.dev, 0,
1770 ort->rt6i_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771
1772 if (rt) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001773 rt->dst.input = ort->dst.input;
1774 rt->dst.output = ort->dst.output;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001775 rt->dst.flags |= DST_HOST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001777 rt->rt6i_dst.addr = *dest;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001778 rt->rt6i_dst.plen = 128;
David S. Millerdefb3512010-12-08 21:16:57 -08001779 dst_copy_metrics(&rt->dst, &ort->dst);
Changli Gaod8d1f302010-06-10 23:31:35 -07001780 rt->dst.error = ort->dst.error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 rt->rt6i_idev = ort->rt6i_idev;
1782 if (rt->rt6i_idev)
1783 in6_dev_hold(rt->rt6i_idev);
Changli Gaod8d1f302010-06-10 23:31:35 -07001784 rt->dst.lastuse = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001786 rt->rt6i_gateway = ort->rt6i_gateway;
Gao feng1716a962012-04-06 00:13:10 +00001787 rt->rt6i_flags = ort->rt6i_flags;
1788 if ((ort->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) ==
1789 (RTF_DEFAULT | RTF_ADDRCONF))
1790 rt6_set_from(rt, ort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 rt->rt6i_metric = 0;
1792
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793#ifdef CONFIG_IPV6_SUBTREES
1794 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1795#endif
Florian Westphal0f6c6392011-05-20 11:27:24 +00001796 memcpy(&rt->rt6i_prefsrc, &ort->rt6i_prefsrc, sizeof(struct rt6key));
Thomas Grafc71099a2006-08-04 23:20:06 -07001797 rt->rt6i_table = ort->rt6i_table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 }
1799 return rt;
1800}
1801
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001802#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001803static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001804 const struct in6_addr *prefix, int prefixlen,
1805 const struct in6_addr *gwaddr, int ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001806{
1807 struct fib6_node *fn;
1808 struct rt6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001809 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001810
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001811 table = fib6_get_table(net, RT6_TABLE_INFO);
David S. Miller38308472011-12-03 18:02:47 -05001812 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001813 return NULL;
1814
Li RongQing5744dd92012-09-11 21:59:01 +00001815 read_lock_bh(&table->tb6_lock);
Thomas Grafc71099a2006-08-04 23:20:06 -07001816 fn = fib6_locate(&table->tb6_root, prefix ,prefixlen, NULL, 0);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001817 if (!fn)
1818 goto out;
1819
Changli Gaod8d1f302010-06-10 23:31:35 -07001820 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05001821 if (rt->dst.dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001822 continue;
1823 if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
1824 continue;
1825 if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
1826 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07001827 dst_hold(&rt->dst);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001828 break;
1829 }
1830out:
Li RongQing5744dd92012-09-11 21:59:01 +00001831 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001832 return rt;
1833}
1834
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001835static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001836 const struct in6_addr *prefix, int prefixlen,
1837 const struct in6_addr *gwaddr, int ifindex,
Eric Dumazet95c96172012-04-15 05:58:06 +00001838 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001839{
Thomas Graf86872cb2006-08-22 00:01:08 -07001840 struct fib6_config cfg = {
1841 .fc_table = RT6_TABLE_INFO,
Rami Rosen238fc7e2008-02-09 23:43:11 -08001842 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07001843 .fc_ifindex = ifindex,
1844 .fc_dst_len = prefixlen,
1845 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
1846 RTF_UP | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00001847 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001848 .fc_nlinfo.nlh = NULL,
1849 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07001850 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001851
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001852 cfg.fc_dst = *prefix;
1853 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07001854
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08001855 /* We should treat it as a default route if prefix length is 0. */
1856 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07001857 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001858
Thomas Graf86872cb2006-08-22 00:01:08 -07001859 ip6_route_add(&cfg);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001860
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001861 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001862}
1863#endif
1864
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001865struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001866{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001868 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001870 table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05001871 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001872 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873
Li RongQing5744dd92012-09-11 21:59:01 +00001874 read_lock_bh(&table->tb6_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001875 for (rt = table->tb6_root.leaf; rt; rt=rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05001876 if (dev == rt->dst.dev &&
YOSHIFUJI Hideaki045927f2006-03-20 17:00:48 -08001877 ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 ipv6_addr_equal(&rt->rt6i_gateway, addr))
1879 break;
1880 }
1881 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07001882 dst_hold(&rt->dst);
Li RongQing5744dd92012-09-11 21:59:01 +00001883 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 return rt;
1885}
1886
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001887struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001888 struct net_device *dev,
1889 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890{
Thomas Graf86872cb2006-08-22 00:01:08 -07001891 struct fib6_config cfg = {
1892 .fc_table = RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08001893 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07001894 .fc_ifindex = dev->ifindex,
1895 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
1896 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00001897 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08001898 .fc_nlinfo.nlh = NULL,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001899 .fc_nlinfo.nl_net = dev_net(dev),
Thomas Graf86872cb2006-08-22 00:01:08 -07001900 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001902 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903
Thomas Graf86872cb2006-08-22 00:01:08 -07001904 ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 return rt6_get_dflt_router(gwaddr, dev);
1907}
1908
Daniel Lezcano7b4da532008-03-04 13:47:14 -08001909void rt6_purge_dflt_routers(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910{
1911 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001912 struct fib6_table *table;
1913
1914 /* NOTE: Keep consistent with rt6_get_dflt_router */
Daniel Lezcano7b4da532008-03-04 13:47:14 -08001915 table = fib6_get_table(net, RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05001916 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001917 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918
1919restart:
Thomas Grafc71099a2006-08-04 23:20:06 -07001920 read_lock_bh(&table->tb6_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001921 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
Lorenzo Colitti3e8b0ac2013-03-03 20:46:46 +00001922 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
1923 (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001924 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07001925 read_unlock_bh(&table->tb6_lock);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001926 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 goto restart;
1928 }
1929 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001930 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931}
1932
Daniel Lezcano55786892008-03-04 13:47:47 -08001933static void rtmsg_to_fib6_config(struct net *net,
1934 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07001935 struct fib6_config *cfg)
1936{
1937 memset(cfg, 0, sizeof(*cfg));
1938
1939 cfg->fc_table = RT6_TABLE_MAIN;
1940 cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
1941 cfg->fc_metric = rtmsg->rtmsg_metric;
1942 cfg->fc_expires = rtmsg->rtmsg_info;
1943 cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
1944 cfg->fc_src_len = rtmsg->rtmsg_src_len;
1945 cfg->fc_flags = rtmsg->rtmsg_flags;
1946
Daniel Lezcano55786892008-03-04 13:47:47 -08001947 cfg->fc_nlinfo.nl_net = net;
Benjamin Theryf1243c22008-02-26 18:10:03 -08001948
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001949 cfg->fc_dst = rtmsg->rtmsg_dst;
1950 cfg->fc_src = rtmsg->rtmsg_src;
1951 cfg->fc_gateway = rtmsg->rtmsg_gateway;
Thomas Graf86872cb2006-08-22 00:01:08 -07001952}
1953
Daniel Lezcano55786892008-03-04 13:47:47 -08001954int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955{
Thomas Graf86872cb2006-08-22 00:01:08 -07001956 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 struct in6_rtmsg rtmsg;
1958 int err;
1959
1960 switch(cmd) {
1961 case SIOCADDRT: /* Add a route */
1962 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00001963 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 return -EPERM;
1965 err = copy_from_user(&rtmsg, arg,
1966 sizeof(struct in6_rtmsg));
1967 if (err)
1968 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07001969
Daniel Lezcano55786892008-03-04 13:47:47 -08001970 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07001971
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 rtnl_lock();
1973 switch (cmd) {
1974 case SIOCADDRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07001975 err = ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 break;
1977 case SIOCDELRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07001978 err = ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 break;
1980 default:
1981 err = -EINVAL;
1982 }
1983 rtnl_unlock();
1984
1985 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001986 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987
1988 return -EINVAL;
1989}
1990
1991/*
1992 * Drop the packet on the floor
1993 */
1994
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07001995static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07001997 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00001998 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07001999 switch (ipstats_mib_noroutes) {
2000 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07002001 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00002002 if (type == IPV6_ADDR_ANY) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002003 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2004 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002005 break;
2006 }
2007 /* FALLTHROUGH */
2008 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002009 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2010 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002011 break;
2012 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002013 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 kfree_skb(skb);
2015 return 0;
2016}
2017
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002018static int ip6_pkt_discard(struct sk_buff *skb)
2019{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002020 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002021}
2022
Arnaldo Carvalho de Melo20380732005-08-16 02:18:02 -03002023static int ip6_pkt_discard_out(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024{
Eric Dumazetadf30902009-06-02 05:19:30 +00002025 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002026 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027}
2028
David S. Miller6723ab52006-10-18 21:20:57 -07002029#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2030
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002031static int ip6_pkt_prohibit(struct sk_buff *skb)
2032{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002033 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002034}
2035
2036static int ip6_pkt_prohibit_out(struct sk_buff *skb)
2037{
Eric Dumazetadf30902009-06-02 05:19:30 +00002038 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002039 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002040}
2041
David S. Miller6723ab52006-10-18 21:20:57 -07002042#endif
2043
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044/*
2045 * Allocate a dst for local (unicast / anycast) address.
2046 */
2047
2048struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
2049 const struct in6_addr *addr,
David S. Miller8f031512011-12-06 16:48:14 -05002050 bool anycast)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002052 struct net *net = dev_net(idev->dev);
David S. Miller8b96d222012-06-11 02:01:56 -07002053 struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev, 0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054
David S. Miller38308472011-12-03 18:02:47 -05002055 if (!rt) {
Joe Perchesf3213832012-05-15 14:11:53 +00002056 net_warn_ratelimited("Maximum number of routes reached, consider increasing route/max_size\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 return ERR_PTR(-ENOMEM);
Ben Greear40385652010-11-08 12:33:48 +00002058 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 in6_dev_hold(idev);
2061
David S. Miller11d53b42011-06-24 15:23:34 -07002062 rt->dst.flags |= DST_HOST;
Changli Gaod8d1f302010-06-10 23:31:35 -07002063 rt->dst.input = ip6_input;
2064 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 rt->rt6i_idev = idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066
2067 rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +09002068 if (anycast)
2069 rt->rt6i_flags |= RTF_ANYCAST;
2070 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 rt->rt6i_flags |= RTF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002073 rt->rt6i_dst.addr = *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 rt->rt6i_dst.plen = 128;
Daniel Lezcano55786892008-03-04 13:47:47 -08002075 rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076
Changli Gaod8d1f302010-06-10 23:31:35 -07002077 atomic_set(&rt->dst.__refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078
2079 return rt;
2080}
2081
Daniel Walterc3968a82011-04-13 21:10:57 +00002082int ip6_route_get_saddr(struct net *net,
2083 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002084 const struct in6_addr *daddr,
Daniel Walterc3968a82011-04-13 21:10:57 +00002085 unsigned int prefs,
2086 struct in6_addr *saddr)
2087{
2088 struct inet6_dev *idev = ip6_dst_idev((struct dst_entry*)rt);
2089 int err = 0;
2090 if (rt->rt6i_prefsrc.plen)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002091 *saddr = rt->rt6i_prefsrc.addr;
Daniel Walterc3968a82011-04-13 21:10:57 +00002092 else
2093 err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
2094 daddr, prefs, saddr);
2095 return err;
2096}
2097
2098/* remove deleted ip from prefsrc entries */
2099struct arg_dev_net_ip {
2100 struct net_device *dev;
2101 struct net *net;
2102 struct in6_addr *addr;
2103};
2104
2105static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
2106{
2107 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
2108 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
2109 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
2110
David S. Millerd1918542011-12-28 20:19:20 -05002111 if (((void *)rt->dst.dev == dev || !dev) &&
Daniel Walterc3968a82011-04-13 21:10:57 +00002112 rt != net->ipv6.ip6_null_entry &&
2113 ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
2114 /* remove prefsrc entry */
2115 rt->rt6i_prefsrc.plen = 0;
2116 }
2117 return 0;
2118}
2119
2120void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
2121{
2122 struct net *net = dev_net(ifp->idev->dev);
2123 struct arg_dev_net_ip adni = {
2124 .dev = ifp->idev->dev,
2125 .net = net,
2126 .addr = &ifp->addr,
2127 };
2128 fib6_clean_all(net, fib6_remove_prefsrc, 0, &adni);
2129}
2130
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002131struct arg_dev_net {
2132 struct net_device *dev;
2133 struct net *net;
2134};
2135
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136static int fib6_ifdown(struct rt6_info *rt, void *arg)
2137{
stephen hemmingerbc3ef662010-12-16 17:42:40 +00002138 const struct arg_dev_net *adn = arg;
2139 const struct net_device *dev = adn->dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002140
David S. Millerd1918542011-12-28 20:19:20 -05002141 if ((rt->dst.dev == dev || !dev) &&
David S. Millerc159d302011-12-26 15:24:36 -05002142 rt != adn->net->ipv6.ip6_null_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 return -1;
David S. Millerc159d302011-12-26 15:24:36 -05002144
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 return 0;
2146}
2147
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002148void rt6_ifdown(struct net *net, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002150 struct arg_dev_net adn = {
2151 .dev = dev,
2152 .net = net,
2153 };
2154
2155 fib6_clean_all(net, fib6_ifdown, 0, &adn);
David S. Miller1e493d12008-09-10 17:27:15 -07002156 icmp6_clean_all(fib6_ifdown, &adn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157}
2158
Eric Dumazet95c96172012-04-15 05:58:06 +00002159struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00002161 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162};
2163
2164static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
2165{
2166 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
2167 struct inet6_dev *idev;
2168
2169 /* In IPv6 pmtu discovery is not optional,
2170 so that RTAX_MTU lock cannot disable it.
2171 We still use this lock to block changes
2172 caused by addrconf/ndisc.
2173 */
2174
2175 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05002176 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 return 0;
2178
2179 /* For administrative MTU increase, there is no way to discover
2180 IPv6 PMTU increase, so PMTU increase should be updated here.
2181 Since RFC 1981 doesn't include administrative MTU increase
2182 update PMTU increase is a MUST. (i.e. jumbo frame)
2183 */
2184 /*
2185 If new MTU is less than route PMTU, this new MTU will be the
2186 lowest MTU in the path, update the route PMTU to reflect PMTU
2187 decreases; if new MTU is greater than route PMTU, and the
2188 old MTU is the lowest MTU in the path, update the route PMTU
2189 to reflect the increase. In this case if the other nodes' MTU
2190 also have the lowest MTU, TOO BIG MESSAGE will be lead to
2191 PMTU discouvery.
2192 */
David S. Millerd1918542011-12-28 20:19:20 -05002193 if (rt->dst.dev == arg->dev &&
Changli Gaod8d1f302010-06-10 23:31:35 -07002194 !dst_metric_locked(&rt->dst, RTAX_MTU) &&
2195 (dst_mtu(&rt->dst) >= arg->mtu ||
2196 (dst_mtu(&rt->dst) < arg->mtu &&
2197 dst_mtu(&rt->dst) == idev->cnf.mtu6))) {
David S. Millerdefb3512010-12-08 21:16:57 -08002198 dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu);
Simon Arlott566cfd82007-07-26 00:09:55 -07002199 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 return 0;
2201}
2202
Eric Dumazet95c96172012-04-15 05:58:06 +00002203void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204{
Thomas Grafc71099a2006-08-04 23:20:06 -07002205 struct rt6_mtu_change_arg arg = {
2206 .dev = dev,
2207 .mtu = mtu,
2208 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002210 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, 0, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211}
2212
Patrick McHardyef7c79e2007-06-05 12:38:30 -07002213static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07002214 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07002215 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07002216 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002217 [RTA_PRIORITY] = { .type = NLA_U32 },
2218 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002219 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Thomas Graf86872cb2006-08-22 00:01:08 -07002220};
2221
2222static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
2223 struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224{
Thomas Graf86872cb2006-08-22 00:01:08 -07002225 struct rtmsg *rtm;
2226 struct nlattr *tb[RTA_MAX+1];
2227 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228
Thomas Graf86872cb2006-08-22 00:01:08 -07002229 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2230 if (err < 0)
2231 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232
Thomas Graf86872cb2006-08-22 00:01:08 -07002233 err = -EINVAL;
2234 rtm = nlmsg_data(nlh);
2235 memset(cfg, 0, sizeof(*cfg));
2236
2237 cfg->fc_table = rtm->rtm_table;
2238 cfg->fc_dst_len = rtm->rtm_dst_len;
2239 cfg->fc_src_len = rtm->rtm_src_len;
2240 cfg->fc_flags = RTF_UP;
2241 cfg->fc_protocol = rtm->rtm_protocol;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002242 cfg->fc_type = rtm->rtm_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07002243
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002244 if (rtm->rtm_type == RTN_UNREACHABLE ||
2245 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002246 rtm->rtm_type == RTN_PROHIBIT ||
2247 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07002248 cfg->fc_flags |= RTF_REJECT;
2249
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002250 if (rtm->rtm_type == RTN_LOCAL)
2251 cfg->fc_flags |= RTF_LOCAL;
2252
Eric W. Biederman15e47302012-09-07 20:12:54 +00002253 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
Thomas Graf86872cb2006-08-22 00:01:08 -07002254 cfg->fc_nlinfo.nlh = nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002255 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
Thomas Graf86872cb2006-08-22 00:01:08 -07002256
2257 if (tb[RTA_GATEWAY]) {
2258 nla_memcpy(&cfg->fc_gateway, tb[RTA_GATEWAY], 16);
2259 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002261
2262 if (tb[RTA_DST]) {
2263 int plen = (rtm->rtm_dst_len + 7) >> 3;
2264
2265 if (nla_len(tb[RTA_DST]) < plen)
2266 goto errout;
2267
2268 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002270
2271 if (tb[RTA_SRC]) {
2272 int plen = (rtm->rtm_src_len + 7) >> 3;
2273
2274 if (nla_len(tb[RTA_SRC]) < plen)
2275 goto errout;
2276
2277 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002279
Daniel Walterc3968a82011-04-13 21:10:57 +00002280 if (tb[RTA_PREFSRC])
2281 nla_memcpy(&cfg->fc_prefsrc, tb[RTA_PREFSRC], 16);
2282
Thomas Graf86872cb2006-08-22 00:01:08 -07002283 if (tb[RTA_OIF])
2284 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
2285
2286 if (tb[RTA_PRIORITY])
2287 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
2288
2289 if (tb[RTA_METRICS]) {
2290 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
2291 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002293
2294 if (tb[RTA_TABLE])
2295 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
2296
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002297 if (tb[RTA_MULTIPATH]) {
2298 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
2299 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
2300 }
2301
Thomas Graf86872cb2006-08-22 00:01:08 -07002302 err = 0;
2303errout:
2304 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305}
2306
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002307static int ip6_route_multipath(struct fib6_config *cfg, int add)
2308{
2309 struct fib6_config r_cfg;
2310 struct rtnexthop *rtnh;
2311 int remaining;
2312 int attrlen;
2313 int err = 0, last_err = 0;
2314
2315beginning:
2316 rtnh = (struct rtnexthop *)cfg->fc_mp;
2317 remaining = cfg->fc_mp_len;
2318
2319 /* Parse a Multipath Entry */
2320 while (rtnh_ok(rtnh, remaining)) {
2321 memcpy(&r_cfg, cfg, sizeof(*cfg));
2322 if (rtnh->rtnh_ifindex)
2323 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
2324
2325 attrlen = rtnh_attrlen(rtnh);
2326 if (attrlen > 0) {
2327 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
2328
2329 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
2330 if (nla) {
2331 nla_memcpy(&r_cfg.fc_gateway, nla, 16);
2332 r_cfg.fc_flags |= RTF_GATEWAY;
2333 }
2334 }
2335 err = add ? ip6_route_add(&r_cfg) : ip6_route_del(&r_cfg);
2336 if (err) {
2337 last_err = err;
2338 /* If we are trying to remove a route, do not stop the
2339 * loop when ip6_route_del() fails (because next hop is
2340 * already gone), we should try to remove all next hops.
2341 */
2342 if (add) {
2343 /* If add fails, we should try to delete all
2344 * next hops that have been already added.
2345 */
2346 add = 0;
2347 goto beginning;
2348 }
2349 }
Nicolas Dichtel1a724182012-11-01 22:58:22 +00002350 /* Because each route is added like a single route we remove
2351 * this flag after the first nexthop (if there is a collision,
2352 * we have already fail to add the first nexthop:
2353 * fib6_add_rt2node() has reject it).
2354 */
2355 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~NLM_F_EXCL;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002356 rtnh = rtnh_next(rtnh, &remaining);
2357 }
2358
2359 return last_err;
2360}
2361
Thomas Graf661d2962013-03-21 07:45:29 +00002362static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363{
Thomas Graf86872cb2006-08-22 00:01:08 -07002364 struct fib6_config cfg;
2365 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366
Thomas Graf86872cb2006-08-22 00:01:08 -07002367 err = rtm_to_fib6_config(skb, nlh, &cfg);
2368 if (err < 0)
2369 return err;
2370
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002371 if (cfg.fc_mp)
2372 return ip6_route_multipath(&cfg, 0);
2373 else
2374 return ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375}
2376
Thomas Graf661d2962013-03-21 07:45:29 +00002377static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378{
Thomas Graf86872cb2006-08-22 00:01:08 -07002379 struct fib6_config cfg;
2380 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381
Thomas Graf86872cb2006-08-22 00:01:08 -07002382 err = rtm_to_fib6_config(skb, nlh, &cfg);
2383 if (err < 0)
2384 return err;
2385
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002386 if (cfg.fc_mp)
2387 return ip6_route_multipath(&cfg, 1);
2388 else
2389 return ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390}
2391
Thomas Graf339bf982006-11-10 14:10:15 -08002392static inline size_t rt6_nlmsg_size(void)
2393{
2394 return NLMSG_ALIGN(sizeof(struct rtmsg))
2395 + nla_total_size(16) /* RTA_SRC */
2396 + nla_total_size(16) /* RTA_DST */
2397 + nla_total_size(16) /* RTA_GATEWAY */
2398 + nla_total_size(16) /* RTA_PREFSRC */
2399 + nla_total_size(4) /* RTA_TABLE */
2400 + nla_total_size(4) /* RTA_IIF */
2401 + nla_total_size(4) /* RTA_OIF */
2402 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08002403 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Thomas Graf339bf982006-11-10 14:10:15 -08002404 + nla_total_size(sizeof(struct rta_cacheinfo));
2405}
2406
Brian Haley191cd582008-08-14 15:33:21 -07002407static int rt6_fill_node(struct net *net,
2408 struct sk_buff *skb, struct rt6_info *rt,
Jamal Hadi Salim0d51aa82005-06-21 13:51:04 -07002409 struct in6_addr *dst, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002410 int iif, int type, u32 portid, u32 seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002411 int prefix, int nowait, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412{
2413 struct rtmsg *rtm;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002414 struct nlmsghdr *nlh;
Thomas Grafe3703b32006-11-27 09:27:07 -08002415 long expires;
Patrick McHardy9e762a42006-08-10 23:09:48 -07002416 u32 table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417
2418 if (prefix) { /* user wants prefix routes only */
2419 if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
2420 /* success since this is not a prefix route */
2421 return 1;
2422 }
2423 }
2424
Eric W. Biederman15e47302012-09-07 20:12:54 +00002425 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05002426 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08002427 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002428
2429 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 rtm->rtm_family = AF_INET6;
2431 rtm->rtm_dst_len = rt->rt6i_dst.plen;
2432 rtm->rtm_src_len = rt->rt6i_src.plen;
2433 rtm->rtm_tos = 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07002434 if (rt->rt6i_table)
Patrick McHardy9e762a42006-08-10 23:09:48 -07002435 table = rt->rt6i_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07002436 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07002437 table = RT6_TABLE_UNSPEC;
2438 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04002439 if (nla_put_u32(skb, RTA_TABLE, table))
2440 goto nla_put_failure;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002441 if (rt->rt6i_flags & RTF_REJECT) {
2442 switch (rt->dst.error) {
2443 case -EINVAL:
2444 rtm->rtm_type = RTN_BLACKHOLE;
2445 break;
2446 case -EACCES:
2447 rtm->rtm_type = RTN_PROHIBIT;
2448 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002449 case -EAGAIN:
2450 rtm->rtm_type = RTN_THROW;
2451 break;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002452 default:
2453 rtm->rtm_type = RTN_UNREACHABLE;
2454 break;
2455 }
2456 }
David S. Miller38308472011-12-03 18:02:47 -05002457 else if (rt->rt6i_flags & RTF_LOCAL)
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002458 rtm->rtm_type = RTN_LOCAL;
David S. Millerd1918542011-12-28 20:19:20 -05002459 else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 rtm->rtm_type = RTN_LOCAL;
2461 else
2462 rtm->rtm_type = RTN_UNICAST;
2463 rtm->rtm_flags = 0;
2464 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
2465 rtm->rtm_protocol = rt->rt6i_protocol;
David S. Miller38308472011-12-03 18:02:47 -05002466 if (rt->rt6i_flags & RTF_DYNAMIC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 rtm->rtm_protocol = RTPROT_REDIRECT;
Denis Ovsienkof0396f602012-07-10 04:45:50 +00002468 else if (rt->rt6i_flags & RTF_ADDRCONF) {
2469 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ROUTEINFO))
2470 rtm->rtm_protocol = RTPROT_RA;
2471 else
2472 rtm->rtm_protocol = RTPROT_KERNEL;
2473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474
David S. Miller38308472011-12-03 18:02:47 -05002475 if (rt->rt6i_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 rtm->rtm_flags |= RTM_F_CLONED;
2477
2478 if (dst) {
David S. Millerc78679e2012-04-01 20:27:33 -04002479 if (nla_put(skb, RTA_DST, 16, dst))
2480 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002481 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 } else if (rtm->rtm_dst_len)
David S. Millerc78679e2012-04-01 20:27:33 -04002483 if (nla_put(skb, RTA_DST, 16, &rt->rt6i_dst.addr))
2484 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485#ifdef CONFIG_IPV6_SUBTREES
2486 if (src) {
David S. Millerc78679e2012-04-01 20:27:33 -04002487 if (nla_put(skb, RTA_SRC, 16, src))
2488 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002489 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04002490 } else if (rtm->rtm_src_len &&
2491 nla_put(skb, RTA_SRC, 16, &rt->rt6i_src.addr))
2492 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002494 if (iif) {
2495#ifdef CONFIG_IPV6_MROUTE
2496 if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
Benjamin Thery8229efd2008-12-10 16:30:15 -08002497 int err = ip6mr_get_route(net, skb, rtm, nowait);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002498 if (err <= 0) {
2499 if (!nowait) {
2500 if (err == 0)
2501 return 0;
2502 goto nla_put_failure;
2503 } else {
2504 if (err == -EMSGSIZE)
2505 goto nla_put_failure;
2506 }
2507 }
2508 } else
2509#endif
David S. Millerc78679e2012-04-01 20:27:33 -04002510 if (nla_put_u32(skb, RTA_IIF, iif))
2511 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002512 } else if (dst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 struct in6_addr saddr_buf;
David S. Millerc78679e2012-04-01 20:27:33 -04002514 if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0 &&
2515 nla_put(skb, RTA_PREFSRC, 16, &saddr_buf))
2516 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07002518
Daniel Walterc3968a82011-04-13 21:10:57 +00002519 if (rt->rt6i_prefsrc.plen) {
2520 struct in6_addr saddr_buf;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002521 saddr_buf = rt->rt6i_prefsrc.addr;
David S. Millerc78679e2012-04-01 20:27:33 -04002522 if (nla_put(skb, RTA_PREFSRC, 16, &saddr_buf))
2523 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00002524 }
2525
David S. Millerdefb3512010-12-08 21:16:57 -08002526 if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07002527 goto nla_put_failure;
2528
YOSHIFUJI Hideaki / 吉藤英明dd0cbf22013-01-17 12:53:15 +00002529 if (rt->rt6i_flags & RTF_GATEWAY) {
2530 if (nla_put(skb, RTA_GATEWAY, 16, &rt->rt6i_gateway) < 0)
Eric Dumazet94f826b2012-03-27 09:53:52 +00002531 goto nla_put_failure;
Eric Dumazet94f826b2012-03-27 09:53:52 +00002532 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07002533
David S. Millerc78679e2012-04-01 20:27:33 -04002534 if (rt->dst.dev &&
2535 nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex))
2536 goto nla_put_failure;
2537 if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric))
2538 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00002539
2540 expires = (rt->rt6i_flags & RTF_EXPIRES) ? rt->dst.expires - jiffies : 0;
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07002541
David S. Miller87a50692012-07-10 05:06:14 -07002542 if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, rt->dst.error) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08002543 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544
Thomas Graf2d7202b2006-08-22 00:01:27 -07002545 return nlmsg_end(skb, nlh);
2546
2547nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002548 nlmsg_cancel(skb, nlh);
2549 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550}
2551
Patrick McHardy1b43af52006-08-10 23:11:17 -07002552int rt6_dump_route(struct rt6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553{
2554 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
2555 int prefix;
2556
Thomas Graf2d7202b2006-08-22 00:01:27 -07002557 if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
2558 struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0;
2560 } else
2561 prefix = 0;
2562
Brian Haley191cd582008-08-14 15:33:21 -07002563 return rt6_fill_node(arg->net,
2564 arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002565 NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002566 prefix, 0, NLM_F_MULTI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567}
2568
Thomas Graf661d2962013-03-21 07:45:29 +00002569static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002571 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07002572 struct nlattr *tb[RTA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07002574 struct sk_buff *skb;
2575 struct rtmsg *rtm;
David S. Miller4c9483b2011-03-12 16:22:43 -05002576 struct flowi6 fl6;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002577 int err, iif = 0, oif = 0;
Thomas Grafab364a62006-08-22 00:01:47 -07002578
2579 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2580 if (err < 0)
2581 goto errout;
2582
2583 err = -EINVAL;
David S. Miller4c9483b2011-03-12 16:22:43 -05002584 memset(&fl6, 0, sizeof(fl6));
Thomas Grafab364a62006-08-22 00:01:47 -07002585
2586 if (tb[RTA_SRC]) {
2587 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
2588 goto errout;
2589
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002590 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07002591 }
2592
2593 if (tb[RTA_DST]) {
2594 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
2595 goto errout;
2596
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002597 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07002598 }
2599
2600 if (tb[RTA_IIF])
2601 iif = nla_get_u32(tb[RTA_IIF]);
2602
2603 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002604 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07002605
2606 if (iif) {
2607 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002608 int flags = 0;
2609
Daniel Lezcano55786892008-03-04 13:47:47 -08002610 dev = __dev_get_by_index(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07002611 if (!dev) {
2612 err = -ENODEV;
2613 goto errout;
2614 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002615
2616 fl6.flowi6_iif = iif;
2617
2618 if (!ipv6_addr_any(&fl6.saddr))
2619 flags |= RT6_LOOKUP_F_HAS_SADDR;
2620
2621 rt = (struct rt6_info *)ip6_route_input_lookup(net, dev, &fl6,
2622 flags);
2623 } else {
2624 fl6.flowi6_oif = oif;
2625
2626 rt = (struct rt6_info *)ip6_route_output(net, NULL, &fl6);
Thomas Grafab364a62006-08-22 00:01:47 -07002627 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628
2629 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05002630 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00002631 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07002632 err = -ENOBUFS;
2633 goto errout;
2634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635
2636 /* Reserve room for dummy headers, this skb can pass
2637 through good chunk of routing engine.
2638 */
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07002639 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
2641
Changli Gaod8d1f302010-06-10 23:31:35 -07002642 skb_dst_set(skb, &rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643
David S. Miller4c9483b2011-03-12 16:22:43 -05002644 err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002645 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002646 nlh->nlmsg_seq, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07002648 kfree_skb(skb);
2649 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 }
2651
Eric W. Biederman15e47302012-09-07 20:12:54 +00002652 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07002653errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655}
2656
Thomas Graf86872cb2006-08-22 00:01:08 -07002657void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658{
2659 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08002660 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002661 u32 seq;
2662 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002664 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05002665 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07002666
Thomas Graf339bf982006-11-10 14:10:15 -08002667 skb = nlmsg_new(rt6_nlmsg_size(), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05002668 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07002669 goto errout;
2670
Brian Haley191cd582008-08-14 15:33:21 -07002671 err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002672 event, info->portid, seq, 0, 0, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08002673 if (err < 0) {
2674 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
2675 WARN_ON(err == -EMSGSIZE);
2676 kfree_skb(skb);
2677 goto errout;
2678 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00002679 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08002680 info->nlh, gfp_any());
2681 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07002682errout:
2683 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08002684 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685}
2686
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002687static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00002688 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002689{
Jiri Pirko351638e2013-05-28 01:30:21 +00002690 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002691 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002692
2693 if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002694 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002695 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
2696#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07002697 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002698 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07002699 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002700 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
2701#endif
2702 }
2703
2704 return NOTIFY_OK;
2705}
2706
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707/*
2708 * /proc
2709 */
2710
2711#ifdef CONFIG_PROC_FS
2712
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713struct rt6_proc_arg
2714{
2715 char *buffer;
2716 int offset;
2717 int length;
2718 int skip;
2719 int len;
2720};
2721
2722static int rt6_info_route(struct rt6_info *rt, void *p_arg)
2723{
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002724 struct seq_file *m = p_arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725
Harvey Harrison4b7a4272008-10-29 12:50:24 -07002726 seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727
2728#ifdef CONFIG_IPV6_SUBTREES
Harvey Harrison4b7a4272008-10-29 12:50:24 -07002729 seq_printf(m, "%pi6 %02x ", &rt->rt6i_src.addr, rt->rt6i_src.plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730#else
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002731 seq_puts(m, "00000000000000000000000000000000 00 ");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732#endif
YOSHIFUJI Hideaki / 吉藤英明dd0cbf22013-01-17 12:53:15 +00002733 if (rt->rt6i_flags & RTF_GATEWAY) {
2734 seq_printf(m, "%pi6", &rt->rt6i_gateway);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 } else {
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002736 seq_puts(m, "00000000000000000000000000000000");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 }
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002738 seq_printf(m, " %08x %08x %08x %08x %8s\n",
Changli Gaod8d1f302010-06-10 23:31:35 -07002739 rt->rt6i_metric, atomic_read(&rt->dst.__refcnt),
2740 rt->dst.__use, rt->rt6i_flags,
David S. Millerd1918542011-12-28 20:19:20 -05002741 rt->dst.dev ? rt->dst.dev->name : "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 return 0;
2743}
2744
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002745static int ipv6_route_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746{
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002747 struct net *net = (struct net *)m->private;
Josh Hunt32b293a2011-12-28 13:23:07 +00002748 fib6_clean_all_ro(net, rt6_info_route, 0, m);
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002749 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750}
2751
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002752static int ipv6_route_open(struct inode *inode, struct file *file)
2753{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07002754 return single_open_net(inode, file, ipv6_route_show);
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002755}
2756
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002757static const struct file_operations ipv6_route_proc_fops = {
2758 .owner = THIS_MODULE,
2759 .open = ipv6_route_open,
2760 .read = seq_read,
2761 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07002762 .release = single_release_net,
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002763};
2764
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765static int rt6_stats_seq_show(struct seq_file *seq, void *v)
2766{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002767 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002769 net->ipv6.rt6_stats->fib_nodes,
2770 net->ipv6.rt6_stats->fib_route_nodes,
2771 net->ipv6.rt6_stats->fib_rt_alloc,
2772 net->ipv6.rt6_stats->fib_rt_entries,
2773 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00002774 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002775 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776
2777 return 0;
2778}
2779
2780static int rt6_stats_seq_open(struct inode *inode, struct file *file)
2781{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07002782 return single_open_net(inode, file, rt6_stats_seq_show);
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002783}
2784
Arjan van de Ven9a321442007-02-12 00:55:35 -08002785static const struct file_operations rt6_stats_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 .owner = THIS_MODULE,
2787 .open = rt6_stats_seq_open,
2788 .read = seq_read,
2789 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07002790 .release = single_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791};
2792#endif /* CONFIG_PROC_FS */
2793
2794#ifdef CONFIG_SYSCTL
2795
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796static
Joe Perchesfe2c6332013-06-11 23:04:25 -07002797int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 void __user *buffer, size_t *lenp, loff_t *ppos)
2799{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00002800 struct net *net;
2801 int delay;
2802 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00002804
2805 net = (struct net *)ctl->extra1;
2806 delay = net->ipv6.sysctl.flush_delay;
2807 proc_dointvec(ctl, write, buffer, lenp, ppos);
2808 fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net);
2809 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810}
2811
Joe Perchesfe2c6332013-06-11 23:04:25 -07002812struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002813 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08002815 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07002817 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002818 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 },
2820 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08002822 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 .maxlen = sizeof(int),
2824 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002825 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 },
2827 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08002829 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 .maxlen = sizeof(int),
2831 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002832 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 },
2834 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08002836 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 .maxlen = sizeof(int),
2838 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002839 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 },
2841 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08002843 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 .maxlen = sizeof(int),
2845 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002846 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 },
2848 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08002850 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 .maxlen = sizeof(int),
2852 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002853 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 },
2855 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08002857 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 .maxlen = sizeof(int),
2859 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07002860 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 },
2862 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08002864 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 .maxlen = sizeof(int),
2866 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002867 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 },
2869 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08002871 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 .maxlen = sizeof(int),
2873 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07002874 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 },
2876 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08002878 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 .maxlen = sizeof(int),
2880 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002881 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002883 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884};
2885
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002886struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08002887{
2888 struct ctl_table *table;
2889
2890 table = kmemdup(ipv6_route_table_template,
2891 sizeof(ipv6_route_table_template),
2892 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09002893
2894 if (table) {
2895 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00002896 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00002897 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09002898 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
2899 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
2900 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
2901 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
2902 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
2903 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
2904 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08002905 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
Eric W. Biederman464dc802012-11-16 03:02:59 +00002906
2907 /* Don't export sysctls to unprivileged users */
2908 if (net->user_ns != &init_user_ns)
2909 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09002910 }
2911
Daniel Lezcano760f2d02008-01-10 02:53:43 -08002912 return table;
2913}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914#endif
2915
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002916static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08002917{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07002918 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002919
Alexey Dobriyan86393e52009-08-29 01:34:49 +00002920 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
2921 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08002922
Eric Dumazetfc66f952010-10-08 06:37:34 +00002923 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
2924 goto out_ip6_dst_ops;
2925
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002926 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
2927 sizeof(*net->ipv6.ip6_null_entry),
2928 GFP_KERNEL);
2929 if (!net->ipv6.ip6_null_entry)
Eric Dumazetfc66f952010-10-08 06:37:34 +00002930 goto out_ip6_dst_entries;
Changli Gaod8d1f302010-06-10 23:31:35 -07002931 net->ipv6.ip6_null_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002932 (struct dst_entry *)net->ipv6.ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002933 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08002934 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
2935 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002936
2937#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2938 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
2939 sizeof(*net->ipv6.ip6_prohibit_entry),
2940 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07002941 if (!net->ipv6.ip6_prohibit_entry)
2942 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002943 net->ipv6.ip6_prohibit_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002944 (struct dst_entry *)net->ipv6.ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002945 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08002946 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
2947 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002948
2949 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
2950 sizeof(*net->ipv6.ip6_blk_hole_entry),
2951 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07002952 if (!net->ipv6.ip6_blk_hole_entry)
2953 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002954 net->ipv6.ip6_blk_hole_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002955 (struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002956 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08002957 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
2958 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002959#endif
2960
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07002961 net->ipv6.sysctl.flush_delay = 0;
2962 net->ipv6.sysctl.ip6_rt_max_size = 4096;
2963 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
2964 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
2965 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
2966 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
2967 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
2968 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
2969
Benjamin Thery6891a342008-03-04 13:49:47 -08002970 net->ipv6.ip6_rt_gc_expire = 30*HZ;
2971
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002972 ret = 0;
2973out:
2974 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08002975
Peter Zijlstra68fffc62008-10-07 14:12:10 -07002976#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2977out_ip6_prohibit_entry:
2978 kfree(net->ipv6.ip6_prohibit_entry);
2979out_ip6_null_entry:
2980 kfree(net->ipv6.ip6_null_entry);
2981#endif
Eric Dumazetfc66f952010-10-08 06:37:34 +00002982out_ip6_dst_entries:
2983 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08002984out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08002985 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08002986}
2987
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002988static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08002989{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002990 kfree(net->ipv6.ip6_null_entry);
2991#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2992 kfree(net->ipv6.ip6_prohibit_entry);
2993 kfree(net->ipv6.ip6_blk_hole_entry);
2994#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00002995 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08002996}
2997
Thomas Grafd1896342012-06-18 12:08:33 +00002998static int __net_init ip6_route_net_init_late(struct net *net)
2999{
3000#ifdef CONFIG_PROC_FS
Gao fengd4beaa62013-02-18 01:34:54 +00003001 proc_create("ipv6_route", 0, net->proc_net, &ipv6_route_proc_fops);
3002 proc_create("rt6_stats", S_IRUGO, net->proc_net, &rt6_stats_seq_fops);
Thomas Grafd1896342012-06-18 12:08:33 +00003003#endif
3004 return 0;
3005}
3006
3007static void __net_exit ip6_route_net_exit_late(struct net *net)
3008{
3009#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00003010 remove_proc_entry("ipv6_route", net->proc_net);
3011 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00003012#endif
3013}
3014
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003015static struct pernet_operations ip6_route_net_ops = {
3016 .init = ip6_route_net_init,
3017 .exit = ip6_route_net_exit,
3018};
3019
David S. Millerc3426b42012-06-09 16:27:05 -07003020static int __net_init ipv6_inetpeer_init(struct net *net)
3021{
3022 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
3023
3024 if (!bp)
3025 return -ENOMEM;
3026 inet_peer_base_init(bp);
3027 net->ipv6.peers = bp;
3028 return 0;
3029}
3030
3031static void __net_exit ipv6_inetpeer_exit(struct net *net)
3032{
3033 struct inet_peer_base *bp = net->ipv6.peers;
3034
3035 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07003036 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07003037 kfree(bp);
3038}
3039
David S. Miller2b823f72012-06-09 19:00:16 -07003040static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07003041 .init = ipv6_inetpeer_init,
3042 .exit = ipv6_inetpeer_exit,
3043};
3044
Thomas Grafd1896342012-06-18 12:08:33 +00003045static struct pernet_operations ip6_route_net_late_ops = {
3046 .init = ip6_route_net_init_late,
3047 .exit = ip6_route_net_exit_late,
3048};
3049
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003050static struct notifier_block ip6_route_dev_notifier = {
3051 .notifier_call = ip6_route_dev_notify,
3052 .priority = 0,
3053};
3054
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003055int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003057 int ret;
3058
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003059 ret = -ENOMEM;
3060 ip6_dst_ops_template.kmem_cachep =
3061 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
3062 SLAB_HWCACHE_ALIGN, NULL);
3063 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08003064 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07003065
Eric Dumazetfc66f952010-10-08 06:37:34 +00003066 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003067 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003068 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003069
David S. Millerc3426b42012-06-09 16:27:05 -07003070 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
3071 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003072 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00003073
David S. Miller7e52b332012-06-15 15:51:55 -07003074 ret = register_pernet_subsys(&ip6_route_net_ops);
3075 if (ret)
3076 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07003077
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07003078 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
3079
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003080 /* Registering of the loopback is done before this portion of code,
3081 * the loopback reference in rt6_info will not be taken, do it
3082 * manually for init_net */
Changli Gaod8d1f302010-06-10 23:31:35 -07003083 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003084 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3085 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07003086 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003087 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07003088 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003089 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3090 #endif
David S. Millere8803b62012-06-16 01:12:19 -07003091 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003092 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003093 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003094
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003095 ret = xfrm6_init();
3096 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003097 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08003098
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003099 ret = fib6_rules_init();
3100 if (ret)
3101 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08003102
Thomas Grafd1896342012-06-18 12:08:33 +00003103 ret = register_pernet_subsys(&ip6_route_net_late_ops);
3104 if (ret)
3105 goto fib6_rules_init;
3106
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003107 ret = -ENOBUFS;
Greg Rosec7ac8672011-06-10 01:27:09 +00003108 if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) ||
3109 __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) ||
3110 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL))
Thomas Grafd1896342012-06-18 12:08:33 +00003111 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003112
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003113 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003114 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00003115 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003116
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003117out:
3118 return ret;
3119
Thomas Grafd1896342012-06-18 12:08:33 +00003120out_register_late_subsys:
3121 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003122fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003123 fib6_rules_cleanup();
3124xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003125 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00003126out_fib6_init:
3127 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003128out_register_subsys:
3129 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07003130out_register_inetpeer:
3131 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00003132out_dst_entries:
3133 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003134out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003135 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003136 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137}
3138
3139void ip6_route_cleanup(void)
3140{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003141 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00003142 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07003143 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07003146 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003147 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003148 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003149 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150}