blob: 515bb51e05a8b2f7eb5882fd2ebdf3a73fcec61e [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 Dichtel51ebd3182012-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);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -080087#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -080088static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +000089 const struct in6_addr *prefix, int prefixlen,
90 const struct in6_addr *gwaddr, int ifindex,
Eric Dumazet95c96172012-04-15 05:58:06 +000091 unsigned int pref);
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -080092static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +000093 const struct in6_addr *prefix, int prefixlen,
94 const struct in6_addr *gwaddr, int ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -080095#endif
96
David S. Miller06582542011-01-27 14:58:42 -080097static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
98{
99 struct rt6_info *rt = (struct rt6_info *) dst;
100 struct inet_peer *peer;
101 u32 *p = NULL;
102
Yan, Zheng8e2ec632011-09-05 21:34:30 +0000103 if (!(rt->dst.flags & DST_HOST))
104 return NULL;
105
David S. Millerfbfe95a2012-06-08 23:24:18 -0700106 peer = rt6_get_peer_create(rt);
David S. Miller06582542011-01-27 14:58:42 -0800107 if (peer) {
108 u32 *old_p = __DST_METRICS_PTR(old);
109 unsigned long prev, new;
110
111 p = peer->metrics;
112 if (inet_metrics_new(peer))
113 memcpy(p, old_p, sizeof(u32) * RTAX_MAX);
114
115 new = (unsigned long) p;
116 prev = cmpxchg(&dst->_metrics, old, new);
117
118 if (prev != old) {
119 p = __DST_METRICS_PTR(prev);
120 if (prev & DST_METRICS_READ_ONLY)
121 p = NULL;
122 }
123 }
124 return p;
125}
126
David S. Millerf894cbf2012-07-02 21:52:24 -0700127static inline const void *choose_neigh_daddr(struct rt6_info *rt,
128 struct sk_buff *skb,
129 const void *daddr)
David S. Miller39232972012-01-26 15:22:32 -0500130{
131 struct in6_addr *p = &rt->rt6i_gateway;
132
David S. Millera7563f32012-01-26 16:29:16 -0500133 if (!ipv6_addr_any(p))
David S. Miller39232972012-01-26 15:22:32 -0500134 return (const void *) p;
David S. Millerf894cbf2012-07-02 21:52:24 -0700135 else if (skb)
136 return &ipv6_hdr(skb)->daddr;
David S. Miller39232972012-01-26 15:22:32 -0500137 return daddr;
138}
139
David S. Millerf894cbf2012-07-02 21:52:24 -0700140static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst,
141 struct sk_buff *skb,
142 const void *daddr)
David S. Millerd3aaeb32011-07-18 00:40:17 -0700143{
David S. Miller39232972012-01-26 15:22:32 -0500144 struct rt6_info *rt = (struct rt6_info *) dst;
145 struct neighbour *n;
146
David S. Millerf894cbf2012-07-02 21:52:24 -0700147 daddr = choose_neigh_daddr(rt, skb, daddr);
YOSHIFUJI Hideaki / 吉藤英明8e022ee2013-01-17 12:53:09 +0000148 n = __ipv6_neigh_lookup(dst->dev, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500149 if (n)
150 return n;
151 return neigh_create(&nd_tbl, daddr, dst->dev);
152}
153
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -0800154static struct dst_ops ip6_dst_ops_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 .family = AF_INET6,
Harvey Harrison09640e632009-02-01 00:45:17 -0800156 .protocol = cpu_to_be16(ETH_P_IPV6),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 .gc = ip6_dst_gc,
158 .gc_thresh = 1024,
159 .check = ip6_dst_check,
David S. Miller0dbaee32010-12-13 12:52:14 -0800160 .default_advmss = ip6_default_advmss,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000161 .mtu = ip6_mtu,
David S. Miller06582542011-01-27 14:58:42 -0800162 .cow_metrics = ipv6_cow_metrics,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 .destroy = ip6_dst_destroy,
164 .ifdown = ip6_dst_ifdown,
165 .negative_advice = ip6_negative_advice,
166 .link_failure = ip6_link_failure,
167 .update_pmtu = ip6_rt_update_pmtu,
David S. Miller6e157b62012-07-12 00:05:02 -0700168 .redirect = rt6_do_redirect,
Herbert Xu1ac06e02008-05-20 14:32:14 -0700169 .local_out = __ip6_local_out,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700170 .neigh_lookup = ip6_neigh_lookup,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171};
172
Steffen Klassertebb762f2011-11-23 02:12:51 +0000173static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
Roland Dreierec831ea2011-01-31 13:16:00 -0800174{
Steffen Klassert618f9bc2011-11-23 02:13:31 +0000175 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
176
177 return mtu ? : dst->dev->mtu;
Roland Dreierec831ea2011-01-31 13:16:00 -0800178}
179
David S. Miller6700c272012-07-17 03:29:28 -0700180static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
181 struct sk_buff *skb, u32 mtu)
David S. Miller14e50e52007-05-24 18:17:54 -0700182{
183}
184
David S. Miller6700c272012-07-17 03:29:28 -0700185static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
186 struct sk_buff *skb)
David S. Millerb587ee32012-07-12 00:39:24 -0700187{
188}
189
Held Bernhard0972ddb2011-04-24 22:07:32 +0000190static u32 *ip6_rt_blackhole_cow_metrics(struct dst_entry *dst,
191 unsigned long old)
192{
193 return NULL;
194}
195
David S. Miller14e50e52007-05-24 18:17:54 -0700196static struct dst_ops ip6_dst_blackhole_ops = {
197 .family = AF_INET6,
Harvey Harrison09640e632009-02-01 00:45:17 -0800198 .protocol = cpu_to_be16(ETH_P_IPV6),
David S. Miller14e50e52007-05-24 18:17:54 -0700199 .destroy = ip6_dst_destroy,
200 .check = ip6_dst_check,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000201 .mtu = ip6_blackhole_mtu,
Eric Dumazet214f45c2011-02-18 11:39:01 -0800202 .default_advmss = ip6_default_advmss,
David S. Miller14e50e52007-05-24 18:17:54 -0700203 .update_pmtu = ip6_rt_blackhole_update_pmtu,
David S. Millerb587ee32012-07-12 00:39:24 -0700204 .redirect = ip6_rt_blackhole_redirect,
Held Bernhard0972ddb2011-04-24 22:07:32 +0000205 .cow_metrics = ip6_rt_blackhole_cow_metrics,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700206 .neigh_lookup = ip6_neigh_lookup,
David S. Miller14e50e52007-05-24 18:17:54 -0700207};
208
David S. Miller62fa8a82011-01-26 20:51:05 -0800209static const u32 ip6_template_metrics[RTAX_MAX] = {
Li RongQing14edd872012-10-24 14:01:18 +0800210 [RTAX_HOPLIMIT - 1] = 0,
David S. Miller62fa8a82011-01-26 20:51:05 -0800211};
212
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000213static const struct rt6_info ip6_null_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700214 .dst = {
215 .__refcnt = ATOMIC_INIT(1),
216 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000217 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700218 .error = -ENETUNREACH,
Changli Gaod8d1f302010-06-10 23:31:35 -0700219 .input = ip6_pkt_discard,
220 .output = ip6_pkt_discard_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 },
222 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700223 .rt6i_protocol = RTPROT_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 .rt6i_metric = ~(u32) 0,
225 .rt6i_ref = ATOMIC_INIT(1),
226};
227
Thomas Graf101367c2006-08-04 03:39:02 -0700228#ifdef CONFIG_IPV6_MULTIPLE_TABLES
229
David S. Miller6723ab52006-10-18 21:20:57 -0700230static int ip6_pkt_prohibit(struct sk_buff *skb);
231static int ip6_pkt_prohibit_out(struct sk_buff *skb);
David S. Miller6723ab52006-10-18 21:20:57 -0700232
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000233static const struct rt6_info ip6_prohibit_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700234 .dst = {
235 .__refcnt = ATOMIC_INIT(1),
236 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000237 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700238 .error = -EACCES,
Changli Gaod8d1f302010-06-10 23:31:35 -0700239 .input = ip6_pkt_prohibit,
240 .output = ip6_pkt_prohibit_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700241 },
242 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700243 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700244 .rt6i_metric = ~(u32) 0,
245 .rt6i_ref = ATOMIC_INIT(1),
246};
247
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000248static const struct rt6_info ip6_blk_hole_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700249 .dst = {
250 .__refcnt = ATOMIC_INIT(1),
251 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000252 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700253 .error = -EINVAL,
Changli Gaod8d1f302010-06-10 23:31:35 -0700254 .input = dst_discard,
255 .output = dst_discard,
Thomas Graf101367c2006-08-04 03:39:02 -0700256 },
257 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700258 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700259 .rt6i_metric = ~(u32) 0,
260 .rt6i_ref = ATOMIC_INIT(1),
261};
262
263#endif
264
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265/* allocate dst with ip6_dst_ops */
David S. Miller97bab732012-06-09 22:36:36 -0700266static inline struct rt6_info *ip6_dst_alloc(struct net *net,
David S. Miller957c6652011-06-24 15:25:00 -0700267 struct net_device *dev,
David S. Miller8b96d222012-06-11 02:01:56 -0700268 int flags,
269 struct fib6_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270{
David S. Miller97bab732012-06-09 22:36:36 -0700271 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +0000272 0, DST_OBSOLETE_FORCE_CHK, flags);
David S. Millercf911662011-04-28 14:31:47 -0700273
David S. Miller97bab732012-06-09 22:36:36 -0700274 if (rt) {
Steffen Klassert81048912012-07-05 23:37:09 +0000275 struct dst_entry *dst = &rt->dst;
276
277 memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
David S. Miller8b96d222012-06-11 02:01:56 -0700278 rt6_init_peer(rt, table ? &table->tb6_peers : net->ipv6.peers);
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +0000279 rt->rt6i_genid = rt_genid(net);
Nicolas Dichtel51ebd3182012-10-22 03:42:09 +0000280 INIT_LIST_HEAD(&rt->rt6i_siblings);
281 rt->rt6i_nsiblings = 0;
David S. Miller97bab732012-06-09 22:36:36 -0700282 }
David S. Millercf911662011-04-28 14:31:47 -0700283 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284}
285
286static void ip6_dst_destroy(struct dst_entry *dst)
287{
288 struct rt6_info *rt = (struct rt6_info *)dst;
289 struct inet6_dev *idev = rt->rt6i_idev;
290
Yan, Zheng8e2ec632011-09-05 21:34:30 +0000291 if (!(rt->dst.flags & DST_HOST))
292 dst_destroy_metrics_generic(dst);
293
David S. Miller38308472011-12-03 18:02:47 -0500294 if (idev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 rt->rt6i_idev = NULL;
296 in6_dev_put(idev);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900297 }
Gao feng1716a962012-04-06 00:13:10 +0000298
299 if (!(rt->rt6i_flags & RTF_EXPIRES) && dst->from)
300 dst_release(dst->from);
301
David S. Miller97bab732012-06-09 22:36:36 -0700302 if (rt6_has_peer(rt)) {
303 struct inet_peer *peer = rt6_peer_ptr(rt);
David S. Millerb3419362010-11-30 12:27:11 -0800304 inet_putpeer(peer);
305 }
306}
307
308void rt6_bind_peer(struct rt6_info *rt, int create)
309{
David S. Miller97bab732012-06-09 22:36:36 -0700310 struct inet_peer_base *base;
David S. Millerb3419362010-11-30 12:27:11 -0800311 struct inet_peer *peer;
312
David S. Miller97bab732012-06-09 22:36:36 -0700313 base = inetpeer_base_ptr(rt->_rt6i_peer);
314 if (!base)
315 return;
316
317 peer = inet_getpeer_v6(base, &rt->rt6i_dst.addr, create);
David S. Miller7b34ca22012-06-11 04:13:57 -0700318 if (peer) {
319 if (!rt6_set_peer(rt, peer))
320 inet_putpeer(peer);
David S. Miller7b34ca22012-06-11 04:13:57 -0700321 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322}
323
324static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
325 int how)
326{
327 struct rt6_info *rt = (struct rt6_info *)dst;
328 struct inet6_dev *idev = rt->rt6i_idev;
Denis V. Lunev5a3e55d2007-12-07 00:38:10 -0800329 struct net_device *loopback_dev =
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900330 dev_net(dev)->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
David S. Miller97cac082012-07-02 22:43:47 -0700332 if (dev != loopback_dev) {
333 if (idev && idev->dev == dev) {
334 struct inet6_dev *loopback_idev =
335 in6_dev_get(loopback_dev);
336 if (loopback_idev) {
337 rt->rt6i_idev = loopback_idev;
338 in6_dev_put(idev);
339 }
340 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 }
342}
343
Eric Dumazeta50feda2012-05-18 18:57:34 +0000344static bool rt6_check_expired(const struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345{
Gao feng1716a962012-04-06 00:13:10 +0000346 if (rt->rt6i_flags & RTF_EXPIRES) {
347 if (time_after(jiffies, rt->dst.expires))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000348 return true;
Gao feng1716a962012-04-06 00:13:10 +0000349 } else if (rt->dst.from) {
Li RongQing3fd91fb2012-09-13 19:54:57 +0000350 return rt6_check_expired((struct rt6_info *) rt->dst.from);
Gao feng1716a962012-04-06 00:13:10 +0000351 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000352 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353}
354
Eric Dumazeta50feda2012-05-18 18:57:34 +0000355static bool rt6_need_strict(const struct in6_addr *daddr)
Thomas Grafc71099a2006-08-04 23:20:06 -0700356{
Eric Dumazeta02cec22010-09-22 20:43:57 +0000357 return ipv6_addr_type(daddr) &
358 (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK);
Thomas Grafc71099a2006-08-04 23:20:06 -0700359}
360
Nicolas Dichtel51ebd3182012-10-22 03:42:09 +0000361/* Multipath route selection:
362 * Hash based function using packet header and flowlabel.
363 * Adapted from fib_info_hashfn()
364 */
365static int rt6_info_hash_nhsfn(unsigned int candidate_count,
366 const struct flowi6 *fl6)
367{
368 unsigned int val = fl6->flowi6_proto;
369
YOSHIFUJI Hideaki / 吉藤英明c08977b2013-01-13 05:02:29 +0000370 val ^= ipv6_addr_hash(&fl6->daddr);
371 val ^= ipv6_addr_hash(&fl6->saddr);
Nicolas Dichtel51ebd3182012-10-22 03:42:09 +0000372
373 /* Work only if this not encapsulated */
374 switch (fl6->flowi6_proto) {
375 case IPPROTO_UDP:
376 case IPPROTO_TCP:
377 case IPPROTO_SCTP:
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000378 val ^= (__force u16)fl6->fl6_sport;
379 val ^= (__force u16)fl6->fl6_dport;
Nicolas Dichtel51ebd3182012-10-22 03:42:09 +0000380 break;
381
382 case IPPROTO_ICMPV6:
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000383 val ^= (__force u16)fl6->fl6_icmp_type;
384 val ^= (__force u16)fl6->fl6_icmp_code;
Nicolas Dichtel51ebd3182012-10-22 03:42:09 +0000385 break;
386 }
387 /* RFC6438 recommands to use flowlabel */
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000388 val ^= (__force u32)fl6->flowlabel;
Nicolas Dichtel51ebd3182012-10-22 03:42:09 +0000389
390 /* Perhaps, we need to tune, this function? */
391 val = val ^ (val >> 7) ^ (val >> 12);
392 return val % candidate_count;
393}
394
395static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
396 struct flowi6 *fl6)
397{
398 struct rt6_info *sibling, *next_sibling;
399 int route_choosen;
400
401 route_choosen = rt6_info_hash_nhsfn(match->rt6i_nsiblings + 1, fl6);
402 /* Don't change the route, if route_choosen == 0
403 * (siblings does not include ourself)
404 */
405 if (route_choosen)
406 list_for_each_entry_safe(sibling, next_sibling,
407 &match->rt6i_siblings, rt6i_siblings) {
408 route_choosen--;
409 if (route_choosen == 0) {
410 match = sibling;
411 break;
412 }
413 }
414 return match;
415}
416
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417/*
Thomas Grafc71099a2006-08-04 23:20:06 -0700418 * Route lookup. Any table->tb6_lock is implied.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 */
420
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800421static inline struct rt6_info *rt6_device_match(struct net *net,
422 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000423 const struct in6_addr *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 int oif,
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700425 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426{
427 struct rt6_info *local = NULL;
428 struct rt6_info *sprt;
429
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900430 if (!oif && ipv6_addr_any(saddr))
431 goto out;
432
Changli Gaod8d1f302010-06-10 23:31:35 -0700433 for (sprt = rt; sprt; sprt = sprt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -0500434 struct net_device *dev = sprt->dst.dev;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900435
436 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 if (dev->ifindex == oif)
438 return sprt;
439 if (dev->flags & IFF_LOOPBACK) {
David S. Miller38308472011-12-03 18:02:47 -0500440 if (!sprt->rt6i_idev ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 sprt->rt6i_idev->dev->ifindex != oif) {
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700442 if (flags & RT6_LOOKUP_F_IFACE && oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 continue;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900444 if (local && (!oif ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 local->rt6i_idev->dev->ifindex == oif))
446 continue;
447 }
448 local = sprt;
449 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900450 } else {
451 if (ipv6_chk_addr(net, saddr, dev,
452 flags & RT6_LOOKUP_F_IFACE))
453 return sprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900457 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 if (local)
459 return local;
460
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700461 if (flags & RT6_LOOKUP_F_IFACE)
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800462 return net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900464out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 return rt;
466}
467
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800468#ifdef CONFIG_IPV6_ROUTER_PREF
469static void rt6_probe(struct rt6_info *rt)
470{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000471 struct neighbour *neigh;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800472 /*
473 * Okay, this does not seem to be appropriate
474 * for now, however, we need to check if it
475 * is really so; aka Router Reachability Probing.
476 *
477 * Router Reachability Probe MUST be rate-limited
478 * to no more than one per minute.
479 */
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000480 if (!rt || !(rt->rt6i_flags & RTF_GATEWAY))
Amerigo Wangfdd66812012-09-10 02:48:44 +0000481 return;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000482 rcu_read_lock_bh();
483 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
484 if (neigh) {
485 write_lock(&neigh->lock);
486 if (neigh->nud_state & NUD_VALID)
487 goto out;
YOSHIFUJI Hideaki / 吉藤英明7ff74a52013-01-17 12:53:02 +0000488 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000489
490 if (!neigh ||
YOSHIFUJI Hideaki52e163562006-03-20 17:05:47 -0800491 time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) {
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800492 struct in6_addr mcaddr;
493 struct in6_addr *target;
494
YOSHIFUJI Hideaki / 吉藤英明b820bb62013-01-21 09:58:50 +0000495 if (neigh) {
496 neigh->updated = jiffies;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000497 write_unlock(&neigh->lock);
YOSHIFUJI Hideaki / 吉藤英明b820bb62013-01-21 09:58:50 +0000498 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000499
500 target = (struct in6_addr *)&rt->rt6i_gateway;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800501 addrconf_addr_solict_mult(target, &mcaddr);
David S. Millerd1918542011-12-28 20:19:20 -0500502 ndisc_send_ns(rt->dst.dev, NULL, target, &mcaddr, NULL);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000503 } else {
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000504out:
505 write_unlock(&neigh->lock);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000506 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000507 rcu_read_unlock_bh();
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800508}
509#else
510static inline void rt6_probe(struct rt6_info *rt)
511{
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800512}
513#endif
514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515/*
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800516 * Default Router Selection (RFC 2461 6.3.6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 */
Dave Jonesb6f99a22007-03-22 12:27:49 -0700518static inline int rt6_check_dev(struct rt6_info *rt, int oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519{
David S. Millerd1918542011-12-28 20:19:20 -0500520 struct net_device *dev = rt->dst.dev;
David S. Miller161980f2007-04-06 11:42:27 -0700521 if (!oif || dev->ifindex == oif)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800522 return 2;
David S. Miller161980f2007-04-06 11:42:27 -0700523 if ((dev->flags & IFF_LOOPBACK) &&
524 rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
525 return 1;
526 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527}
528
Paul Marksa5a81f02012-12-03 10:26:54 +0000529static inline bool rt6_check_neigh(struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000531 struct neighbour *neigh;
Paul Marksa5a81f02012-12-03 10:26:54 +0000532 bool ret = false;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000533
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700534 if (rt->rt6i_flags & RTF_NONEXTHOP ||
535 !(rt->rt6i_flags & RTF_GATEWAY))
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000536 return true;
537
538 rcu_read_lock_bh();
539 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
540 if (neigh) {
541 read_lock(&neigh->lock);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800542 if (neigh->nud_state & NUD_VALID)
Paul Marksa5a81f02012-12-03 10:26:54 +0000543 ret = true;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800544#ifdef CONFIG_IPV6_ROUTER_PREF
Paul Marksa5a81f02012-12-03 10:26:54 +0000545 else if (!(neigh->nud_state & NUD_FAILED))
546 ret = true;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800547#endif
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000548 read_unlock(&neigh->lock);
Paul Marksa5a81f02012-12-03 10:26:54 +0000549 }
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000550 rcu_read_unlock_bh();
551
Paul Marksa5a81f02012-12-03 10:26:54 +0000552 return ret;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800553}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800555static int rt6_score_route(struct rt6_info *rt, int oif,
556 int strict)
557{
Paul Marksa5a81f02012-12-03 10:26:54 +0000558 int m;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900559
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700560 m = rt6_check_dev(rt, oif);
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700561 if (!m && (strict & RT6_LOOKUP_F_IFACE))
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800562 return -1;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800563#ifdef CONFIG_IPV6_ROUTER_PREF
564 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
565#endif
Paul Marksa5a81f02012-12-03 10:26:54 +0000566 if (!rt6_check_neigh(rt) && (strict & RT6_LOOKUP_F_REACHABLE))
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800567 return -1;
568 return m;
569}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
David S. Millerf11e6652007-03-24 20:36:25 -0700571static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
572 int *mpri, struct rt6_info *match)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800573{
David S. Millerf11e6652007-03-24 20:36:25 -0700574 int m;
575
576 if (rt6_check_expired(rt))
577 goto out;
578
579 m = rt6_score_route(rt, oif, strict);
580 if (m < 0)
581 goto out;
582
583 if (m > *mpri) {
584 if (strict & RT6_LOOKUP_F_REACHABLE)
585 rt6_probe(match);
586 *mpri = m;
587 match = rt;
588 } else if (strict & RT6_LOOKUP_F_REACHABLE) {
589 rt6_probe(rt);
590 }
591
592out:
593 return match;
594}
595
596static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
597 struct rt6_info *rr_head,
598 u32 metric, int oif, int strict)
599{
600 struct rt6_info *rt, *match;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800601 int mpri = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602
David S. Millerf11e6652007-03-24 20:36:25 -0700603 match = NULL;
604 for (rt = rr_head; rt && rt->rt6i_metric == metric;
Changli Gaod8d1f302010-06-10 23:31:35 -0700605 rt = rt->dst.rt6_next)
David S. Millerf11e6652007-03-24 20:36:25 -0700606 match = find_match(rt, oif, strict, &mpri, match);
607 for (rt = fn->leaf; rt && rt != rr_head && rt->rt6i_metric == metric;
Changli Gaod8d1f302010-06-10 23:31:35 -0700608 rt = rt->dst.rt6_next)
David S. Millerf11e6652007-03-24 20:36:25 -0700609 match = find_match(rt, oif, strict, &mpri, match);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800610
David S. Millerf11e6652007-03-24 20:36:25 -0700611 return match;
612}
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800613
David S. Millerf11e6652007-03-24 20:36:25 -0700614static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
615{
616 struct rt6_info *match, *rt0;
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800617 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
David S. Millerf11e6652007-03-24 20:36:25 -0700619 rt0 = fn->rr_ptr;
620 if (!rt0)
621 fn->rr_ptr = rt0 = fn->leaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622
David S. Millerf11e6652007-03-24 20:36:25 -0700623 match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800625 if (!match &&
David S. Millerf11e6652007-03-24 20:36:25 -0700626 (strict & RT6_LOOKUP_F_REACHABLE)) {
Changli Gaod8d1f302010-06-10 23:31:35 -0700627 struct rt6_info *next = rt0->dst.rt6_next;
David S. Millerf11e6652007-03-24 20:36:25 -0700628
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800629 /* no entries matched; do round-robin */
David S. Millerf11e6652007-03-24 20:36:25 -0700630 if (!next || next->rt6i_metric != rt0->rt6i_metric)
631 next = fn->leaf;
632
633 if (next != rt0)
634 fn->rr_ptr = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 }
636
David S. Millerd1918542011-12-28 20:19:20 -0500637 net = dev_net(rt0->dst.dev);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000638 return match ? match : net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639}
640
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800641#ifdef CONFIG_IPV6_ROUTE_INFO
642int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000643 const struct in6_addr *gwaddr)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800644{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900645 struct net *net = dev_net(dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800646 struct route_info *rinfo = (struct route_info *) opt;
647 struct in6_addr prefix_buf, *prefix;
648 unsigned int pref;
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900649 unsigned long lifetime;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800650 struct rt6_info *rt;
651
652 if (len < sizeof(struct route_info)) {
653 return -EINVAL;
654 }
655
656 /* Sanity check for prefix_len and length */
657 if (rinfo->length > 3) {
658 return -EINVAL;
659 } else if (rinfo->prefix_len > 128) {
660 return -EINVAL;
661 } else if (rinfo->prefix_len > 64) {
662 if (rinfo->length < 2) {
663 return -EINVAL;
664 }
665 } else if (rinfo->prefix_len > 0) {
666 if (rinfo->length < 1) {
667 return -EINVAL;
668 }
669 }
670
671 pref = rinfo->route_pref;
672 if (pref == ICMPV6_ROUTER_PREF_INVALID)
Jens Rosenboom3933fc92009-09-10 06:25:11 +0000673 return -EINVAL;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800674
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900675 lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800676
677 if (rinfo->length == 3)
678 prefix = (struct in6_addr *)rinfo->prefix;
679 else {
680 /* this function is safe */
681 ipv6_addr_prefix(&prefix_buf,
682 (struct in6_addr *)rinfo->prefix,
683 rinfo->prefix_len);
684 prefix = &prefix_buf;
685 }
686
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800687 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, gwaddr,
688 dev->ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800689
690 if (rt && !lifetime) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -0700691 ip6_del_rt(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800692 rt = NULL;
693 }
694
695 if (!rt && lifetime)
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800696 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800697 pref);
698 else if (rt)
699 rt->rt6i_flags = RTF_ROUTEINFO |
700 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
701
702 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +0000703 if (!addrconf_finite_timeout(lifetime))
704 rt6_clean_expires(rt);
705 else
706 rt6_set_expires(rt, jiffies + HZ * lifetime);
707
Amerigo Wang94e187c2012-10-29 00:13:19 +0000708 ip6_rt_put(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800709 }
710 return 0;
711}
712#endif
713
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800714#define BACKTRACK(__net, saddr) \
YOSHIFUJI Hideaki982f56f2006-08-23 17:22:39 -0700715do { \
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800716 if (rt == __net->ipv6.ip6_null_entry) { \
YOSHIFUJI Hideaki982f56f2006-08-23 17:22:39 -0700717 struct fib6_node *pn; \
Ville Nuorvalae0eda7b2006-10-16 22:11:11 -0700718 while (1) { \
YOSHIFUJI Hideaki982f56f2006-08-23 17:22:39 -0700719 if (fn->fn_flags & RTN_TL_ROOT) \
720 goto out; \
721 pn = fn->parent; \
722 if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn) \
Kim Nordlund8bce65b2006-12-13 16:38:29 -0800723 fn = fib6_lookup(FIB6_SUBTREE(pn), NULL, saddr); \
YOSHIFUJI Hideaki982f56f2006-08-23 17:22:39 -0700724 else \
725 fn = pn; \
726 if (fn->fn_flags & RTN_RTINFO) \
727 goto restart; \
Thomas Grafc71099a2006-08-04 23:20:06 -0700728 } \
Thomas Grafc71099a2006-08-04 23:20:06 -0700729 } \
David S. Miller38308472011-12-03 18:02:47 -0500730} while (0)
Thomas Grafc71099a2006-08-04 23:20:06 -0700731
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800732static struct rt6_info *ip6_pol_route_lookup(struct net *net,
733 struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500734 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735{
736 struct fib6_node *fn;
737 struct rt6_info *rt;
738
Thomas Grafc71099a2006-08-04 23:20:06 -0700739 read_lock_bh(&table->tb6_lock);
David S. Miller4c9483b2011-03-12 16:22:43 -0500740 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -0700741restart:
742 rt = fn->leaf;
David S. Miller4c9483b2011-03-12 16:22:43 -0500743 rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags);
Nicolas Dichtel51ebd3182012-10-22 03:42:09 +0000744 if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0)
745 rt = rt6_multipath_select(rt, fl6);
David S. Miller4c9483b2011-03-12 16:22:43 -0500746 BACKTRACK(net, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -0700747out:
Changli Gaod8d1f302010-06-10 23:31:35 -0700748 dst_use(&rt->dst, jiffies);
Thomas Grafc71099a2006-08-04 23:20:06 -0700749 read_unlock_bh(&table->tb6_lock);
Thomas Grafc71099a2006-08-04 23:20:06 -0700750 return rt;
751
752}
753
Florian Westphalea6e5742011-09-05 16:05:44 +0200754struct dst_entry * ip6_route_lookup(struct net *net, struct flowi6 *fl6,
755 int flags)
756{
757 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup);
758}
759EXPORT_SYMBOL_GPL(ip6_route_lookup);
760
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900761struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
762 const struct in6_addr *saddr, int oif, int strict)
Thomas Grafc71099a2006-08-04 23:20:06 -0700763{
David S. Miller4c9483b2011-03-12 16:22:43 -0500764 struct flowi6 fl6 = {
765 .flowi6_oif = oif,
766 .daddr = *daddr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700767 };
768 struct dst_entry *dst;
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700769 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
Thomas Grafc71099a2006-08-04 23:20:06 -0700770
Thomas Grafadaa70b2006-10-13 15:01:03 -0700771 if (saddr) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500772 memcpy(&fl6.saddr, saddr, sizeof(*saddr));
Thomas Grafadaa70b2006-10-13 15:01:03 -0700773 flags |= RT6_LOOKUP_F_HAS_SADDR;
774 }
775
David S. Miller4c9483b2011-03-12 16:22:43 -0500776 dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup);
Thomas Grafc71099a2006-08-04 23:20:06 -0700777 if (dst->error == 0)
778 return (struct rt6_info *) dst;
779
780 dst_release(dst);
781
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 return NULL;
783}
784
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900785EXPORT_SYMBOL(rt6_lookup);
786
Thomas Grafc71099a2006-08-04 23:20:06 -0700787/* ip6_ins_rt is called with FREE table->tb6_lock.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 It takes new route entry, the addition fails by any reason the
789 route is freed. In any case, if caller does not hold it, it may
790 be destroyed.
791 */
792
Thomas Graf86872cb2006-08-22 00:01:08 -0700793static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794{
795 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -0700796 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
Thomas Grafc71099a2006-08-04 23:20:06 -0700798 table = rt->rt6i_table;
799 write_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -0700800 err = fib6_add(&table->tb6_root, rt, info);
Thomas Grafc71099a2006-08-04 23:20:06 -0700801 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802
803 return err;
804}
805
Thomas Graf40e22e82006-08-22 00:00:45 -0700806int ip6_ins_rt(struct rt6_info *rt)
807{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -0800808 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -0500809 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -0800810 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -0800811 return __ip6_ins_rt(rt, &info);
Thomas Graf40e22e82006-08-22 00:00:45 -0700812}
813
Gao feng1716a962012-04-06 00:13:10 +0000814static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort,
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000815 const struct in6_addr *daddr,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000816 const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 struct rt6_info *rt;
819
820 /*
821 * Clone the route.
822 */
823
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000824 rt = ip6_rt_copy(ort, daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825
826 if (rt) {
David S. Miller38308472011-12-03 18:02:47 -0500827 if (!(rt->rt6i_flags & RTF_GATEWAY)) {
David S. Millerbb3c3682011-12-13 17:35:06 -0500828 if (ort->rt6i_dst.plen != 128 &&
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000829 ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +0900830 rt->rt6i_flags |= RTF_ANYCAST;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000831 rt->rt6i_gateway = *daddr;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +0900832 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 rt->rt6i_flags |= RTF_CACHE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
836#ifdef CONFIG_IPV6_SUBTREES
837 if (rt->rt6i_src.plen && saddr) {
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000838 rt->rt6i_src.addr = *saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 rt->rt6i_src.plen = 128;
840 }
841#endif
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800842 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800844 return rt;
845}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000847static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort,
848 const struct in6_addr *daddr)
YOSHIFUJI Hideaki299d9932006-03-20 16:58:32 -0800849{
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000850 struct rt6_info *rt = ip6_rt_copy(ort, daddr);
851
YOSHIFUJI Hideaki / 吉藤英明887c95c2013-01-17 12:54:05 +0000852 if (rt)
YOSHIFUJI Hideaki299d9932006-03-20 16:58:32 -0800853 rt->rt6i_flags |= RTF_CACHE;
YOSHIFUJI Hideaki299d9932006-03-20 16:58:32 -0800854 return rt;
855}
856
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800857static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif,
David S. Miller4c9483b2011-03-12 16:22:43 -0500858 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859{
860 struct fib6_node *fn;
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800861 struct rt6_info *rt, *nrt;
Thomas Grafc71099a2006-08-04 23:20:06 -0700862 int strict = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 int attempts = 3;
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800864 int err;
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700865 int reachable = net->ipv6.devconf_all->forwarding ? 0 : RT6_LOOKUP_F_REACHABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700867 strict |= flags & RT6_LOOKUP_F_IFACE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868
869relookup:
Thomas Grafc71099a2006-08-04 23:20:06 -0700870 read_lock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871
YOSHIFUJI Hideaki8238dd02006-03-20 17:04:35 -0800872restart_2:
David S. Miller4c9483b2011-03-12 16:22:43 -0500873 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
875restart:
Pavel Emelyanov4acad722007-10-15 13:02:51 -0700876 rt = rt6_select(fn, oif, strict | reachable);
Nicolas Dichtel51ebd3182012-10-22 03:42:09 +0000877 if (rt->rt6i_nsiblings && oif == 0)
878 rt = rt6_multipath_select(rt, fl6);
David S. Miller4c9483b2011-03-12 16:22:43 -0500879 BACKTRACK(net, &fl6->saddr);
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800880 if (rt == net->ipv6.ip6_null_entry ||
YOSHIFUJI Hideaki8238dd02006-03-20 17:04:35 -0800881 rt->rt6i_flags & RTF_CACHE)
YOSHIFUJI Hideaki1ddef0442006-03-20 17:01:24 -0800882 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883
Changli Gaod8d1f302010-06-10 23:31:35 -0700884 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -0700885 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -0800886
YOSHIFUJI Hideaki / 吉藤英明c440f162013-01-17 12:53:32 +0000887 if (!(rt->rt6i_flags & (RTF_NONEXTHOP | RTF_GATEWAY)))
David S. Miller4c9483b2011-03-12 16:22:43 -0500888 nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr);
David S. Miller7343ff32011-03-09 19:55:25 -0800889 else if (!(rt->dst.flags & DST_HOST))
David S. Miller4c9483b2011-03-12 16:22:43 -0500890 nrt = rt6_alloc_clone(rt, &fl6->daddr);
David S. Miller7343ff32011-03-09 19:55:25 -0800891 else
892 goto out2;
YOSHIFUJI Hideakie40cf352006-03-20 16:59:27 -0800893
Amerigo Wang94e187c2012-10-29 00:13:19 +0000894 ip6_rt_put(rt);
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800895 rt = nrt ? : net->ipv6.ip6_null_entry;
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800896
Changli Gaod8d1f302010-06-10 23:31:35 -0700897 dst_hold(&rt->dst);
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800898 if (nrt) {
Thomas Graf40e22e82006-08-22 00:00:45 -0700899 err = ip6_ins_rt(nrt);
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800900 if (!err)
901 goto out2;
902 }
903
904 if (--attempts <= 0)
905 goto out2;
906
907 /*
Thomas Grafc71099a2006-08-04 23:20:06 -0700908 * Race condition! In the gap, when table->tb6_lock was
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800909 * released someone could insert this route. Relookup.
910 */
Amerigo Wang94e187c2012-10-29 00:13:19 +0000911 ip6_rt_put(rt);
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800912 goto relookup;
913
914out:
YOSHIFUJI Hideaki8238dd02006-03-20 17:04:35 -0800915 if (reachable) {
916 reachable = 0;
917 goto restart_2;
918 }
Changli Gaod8d1f302010-06-10 23:31:35 -0700919 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -0700920 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921out2:
Changli Gaod8d1f302010-06-10 23:31:35 -0700922 rt->dst.lastuse = jiffies;
923 rt->dst.__use++;
Thomas Grafc71099a2006-08-04 23:20:06 -0700924
925 return rt;
926}
927
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800928static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500929 struct flowi6 *fl6, int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -0700930{
David S. Miller4c9483b2011-03-12 16:22:43 -0500931 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -0700932}
933
Shmulik Ladkani72331bc2012-04-01 04:03:45 +0000934static struct dst_entry *ip6_route_input_lookup(struct net *net,
935 struct net_device *dev,
936 struct flowi6 *fl6, int flags)
937{
938 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
939 flags |= RT6_LOOKUP_F_IFACE;
940
941 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_input);
942}
943
Thomas Grafc71099a2006-08-04 23:20:06 -0700944void ip6_route_input(struct sk_buff *skb)
945{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000946 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900947 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -0700948 int flags = RT6_LOOKUP_F_HAS_SADDR;
David S. Miller4c9483b2011-03-12 16:22:43 -0500949 struct flowi6 fl6 = {
950 .flowi6_iif = skb->dev->ifindex,
951 .daddr = iph->daddr,
952 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +0000953 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -0500954 .flowi6_mark = skb->mark,
955 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700956 };
Thomas Grafadaa70b2006-10-13 15:01:03 -0700957
Shmulik Ladkani72331bc2012-04-01 04:03:45 +0000958 skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -0700959}
960
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800961static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500962 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -0700963{
David S. Miller4c9483b2011-03-12 16:22:43 -0500964 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -0700965}
966
Florian Westphal9c7a4f9c2011-03-22 19:17:36 -0700967struct dst_entry * ip6_route_output(struct net *net, const struct sock *sk,
David S. Miller4c9483b2011-03-12 16:22:43 -0500968 struct flowi6 *fl6)
Thomas Grafc71099a2006-08-04 23:20:06 -0700969{
970 int flags = 0;
971
Pavel Emelyanov1fb94892012-08-08 21:53:36 +0000972 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +0000973
David S. Miller4c9483b2011-03-12 16:22:43 -0500974 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700975 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -0700976
David S. Miller4c9483b2011-03-12 16:22:43 -0500977 if (!ipv6_addr_any(&fl6->saddr))
Thomas Grafadaa70b2006-10-13 15:01:03 -0700978 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +0000979 else if (sk)
980 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -0700981
David S. Miller4c9483b2011-03-12 16:22:43 -0500982 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983}
984
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900985EXPORT_SYMBOL(ip6_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
David S. Miller2774c132011-03-01 14:59:04 -0800987struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -0700988{
David S. Miller5c1e6aa2011-04-28 14:13:38 -0700989 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
David S. Miller14e50e52007-05-24 18:17:54 -0700990 struct dst_entry *new = NULL;
991
David S. Millerf5b0a872012-07-19 12:31:33 -0700992 rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, DST_OBSOLETE_NONE, 0);
David S. Miller14e50e52007-05-24 18:17:54 -0700993 if (rt) {
Changli Gaod8d1f302010-06-10 23:31:35 -0700994 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -0700995
Steffen Klassert81048912012-07-05 23:37:09 +0000996 memset(new + 1, 0, sizeof(*rt) - sizeof(*new));
997 rt6_init_peer(rt, net->ipv6.peers);
998
David S. Miller14e50e52007-05-24 18:17:54 -0700999 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08001000 new->input = dst_discard;
1001 new->output = dst_discard;
David S. Miller14e50e52007-05-24 18:17:54 -07001002
Eric Dumazet21efcfa2011-07-19 20:18:36 +00001003 if (dst_metrics_read_only(&ort->dst))
1004 new->_metrics = ort->dst._metrics;
1005 else
1006 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07001007 rt->rt6i_idev = ort->rt6i_idev;
1008 if (rt->rt6i_idev)
1009 in6_dev_hold(rt->rt6i_idev);
David S. Miller14e50e52007-05-24 18:17:54 -07001010
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001011 rt->rt6i_gateway = ort->rt6i_gateway;
Gao feng1716a962012-04-06 00:13:10 +00001012 rt->rt6i_flags = ort->rt6i_flags;
1013 rt6_clean_expires(rt);
David S. Miller14e50e52007-05-24 18:17:54 -07001014 rt->rt6i_metric = 0;
1015
1016 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
1017#ifdef CONFIG_IPV6_SUBTREES
1018 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1019#endif
1020
1021 dst_free(new);
1022 }
1023
David S. Miller69ead7a2011-03-01 14:45:33 -08001024 dst_release(dst_orig);
1025 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07001026}
David S. Miller14e50e52007-05-24 18:17:54 -07001027
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028/*
1029 * Destination cache support functions
1030 */
1031
1032static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
1033{
1034 struct rt6_info *rt;
1035
1036 rt = (struct rt6_info *) dst;
1037
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00001038 /* All IPV6 dsts are created with ->obsolete set to the value
1039 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
1040 * into this function always.
1041 */
1042 if (rt->rt6i_genid != rt_genid(dev_net(rt->dst.dev)))
1043 return NULL;
1044
Li RongQinga4477c42012-11-07 21:56:33 +00001045 if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 return dst;
Li RongQinga4477c42012-11-07 21:56:33 +00001047
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 return NULL;
1049}
1050
1051static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
1052{
1053 struct rt6_info *rt = (struct rt6_info *) dst;
1054
1055 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001056 if (rt->rt6i_flags & RTF_CACHE) {
1057 if (rt6_check_expired(rt)) {
1058 ip6_del_rt(rt);
1059 dst = NULL;
1060 }
1061 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001063 dst = NULL;
1064 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001066 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067}
1068
1069static void ip6_link_failure(struct sk_buff *skb)
1070{
1071 struct rt6_info *rt;
1072
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00001073 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
Eric Dumazetadf30902009-06-02 05:19:30 +00001075 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +00001077 if (rt->rt6i_flags & RTF_CACHE)
1078 rt6_update_expires(rt, 0);
1079 else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 rt->rt6i_node->fn_sernum = -1;
1081 }
1082}
1083
David S. Miller6700c272012-07-17 03:29:28 -07001084static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
1085 struct sk_buff *skb, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086{
1087 struct rt6_info *rt6 = (struct rt6_info*)dst;
1088
David S. Miller81aded22012-06-15 14:54:11 -07001089 dst_confirm(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 if (mtu < dst_mtu(dst) && rt6->rt6i_dst.plen == 128) {
David S. Miller81aded22012-06-15 14:54:11 -07001091 struct net *net = dev_net(dst->dev);
1092
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 rt6->rt6i_flags |= RTF_MODIFIED;
1094 if (mtu < IPV6_MIN_MTU) {
David S. Millerdefb3512010-12-08 21:16:57 -08001095 u32 features = dst_metric(dst, RTAX_FEATURES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 mtu = IPV6_MIN_MTU;
David S. Millerdefb3512010-12-08 21:16:57 -08001097 features |= RTAX_FEATURE_ALLFRAG;
1098 dst_metric_set(dst, RTAX_FEATURES, features);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 }
David S. Millerdefb3512010-12-08 21:16:57 -08001100 dst_metric_set(dst, RTAX_MTU, mtu);
David S. Miller81aded22012-06-15 14:54:11 -07001101 rt6_update_expires(rt6, net->ipv6.sysctl.ip6_rt_mtu_expires);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 }
1103}
1104
David S. Miller42ae66c2012-06-15 20:01:57 -07001105void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
1106 int oif, u32 mark)
David S. Miller81aded22012-06-15 14:54:11 -07001107{
1108 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1109 struct dst_entry *dst;
1110 struct flowi6 fl6;
1111
1112 memset(&fl6, 0, sizeof(fl6));
1113 fl6.flowi6_oif = oif;
1114 fl6.flowi6_mark = mark;
David S. Miller3e129392012-07-10 04:01:57 -07001115 fl6.flowi6_flags = 0;
David S. Miller81aded22012-06-15 14:54:11 -07001116 fl6.daddr = iph->daddr;
1117 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001118 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller81aded22012-06-15 14:54:11 -07001119
1120 dst = ip6_route_output(net, NULL, &fl6);
1121 if (!dst->error)
David S. Miller6700c272012-07-17 03:29:28 -07001122 ip6_rt_update_pmtu(dst, NULL, skb, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07001123 dst_release(dst);
1124}
1125EXPORT_SYMBOL_GPL(ip6_update_pmtu);
1126
1127void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
1128{
1129 ip6_update_pmtu(skb, sock_net(sk), mtu,
1130 sk->sk_bound_dev_if, sk->sk_mark);
1131}
1132EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
1133
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001134void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark)
1135{
1136 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1137 struct dst_entry *dst;
1138 struct flowi6 fl6;
1139
1140 memset(&fl6, 0, sizeof(fl6));
1141 fl6.flowi6_oif = oif;
1142 fl6.flowi6_mark = mark;
1143 fl6.flowi6_flags = 0;
1144 fl6.daddr = iph->daddr;
1145 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001146 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001147
1148 dst = ip6_route_output(net, NULL, &fl6);
1149 if (!dst->error)
David S. Miller6700c272012-07-17 03:29:28 -07001150 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001151 dst_release(dst);
1152}
1153EXPORT_SYMBOL_GPL(ip6_redirect);
1154
1155void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
1156{
1157 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark);
1158}
1159EXPORT_SYMBOL_GPL(ip6_sk_redirect);
1160
David S. Miller0dbaee32010-12-13 12:52:14 -08001161static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162{
David S. Miller0dbaee32010-12-13 12:52:14 -08001163 struct net_device *dev = dst->dev;
1164 unsigned int mtu = dst_mtu(dst);
1165 struct net *net = dev_net(dev);
1166
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
1168
Daniel Lezcano55786892008-03-04 13:47:47 -08001169 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
1170 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171
1172 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001173 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
1174 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
1175 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 * rely only on pmtu discovery"
1177 */
1178 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
1179 mtu = IPV6_MAXPLEN;
1180 return mtu;
1181}
1182
Steffen Klassertebb762f2011-11-23 02:12:51 +00001183static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08001184{
David S. Millerd33e4552010-12-14 13:01:14 -08001185 struct inet6_dev *idev;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001186 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
1187
1188 if (mtu)
1189 return mtu;
1190
1191 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08001192
1193 rcu_read_lock();
1194 idev = __in6_dev_get(dst->dev);
1195 if (idev)
1196 mtu = idev->cnf.mtu6;
1197 rcu_read_unlock();
1198
1199 return mtu;
1200}
1201
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001202static struct dst_entry *icmp6_dst_gc_list;
1203static DEFINE_SPINLOCK(icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001204
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001205struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05001206 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207{
David S. Miller87a11572011-12-06 17:04:13 -05001208 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 struct rt6_info *rt;
1210 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001211 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212
David S. Miller38308472011-12-03 18:02:47 -05001213 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00001214 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215
David S. Miller8b96d222012-06-11 02:01:56 -07001216 rt = ip6_dst_alloc(net, dev, 0, NULL);
David S. Miller38308472011-12-03 18:02:47 -05001217 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05001219 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 goto out;
1221 }
1222
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001223 rt->dst.flags |= DST_HOST;
1224 rt->dst.output = ip6_output;
Changli Gaod8d1f302010-06-10 23:31:35 -07001225 atomic_set(&rt->dst.__refcnt, 1);
David S. Miller87a11572011-12-06 17:04:13 -05001226 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001227 rt->rt6i_dst.plen = 128;
1228 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08001229 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001231 spin_lock_bh(&icmp6_dst_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001232 rt->dst.next = icmp6_dst_gc_list;
1233 icmp6_dst_gc_list = &rt->dst;
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001234 spin_unlock_bh(&icmp6_dst_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235
Daniel Lezcano55786892008-03-04 13:47:47 -08001236 fib6_force_start_gc(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237
David S. Miller87a11572011-12-06 17:04:13 -05001238 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
1239
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240out:
David S. Miller87a11572011-12-06 17:04:13 -05001241 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242}
1243
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001244int icmp6_dst_gc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245{
Hagen Paul Pfeifere9476e952011-02-25 05:45:19 +00001246 struct dst_entry *dst, **pprev;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001247 int more = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001249 spin_lock_bh(&icmp6_dst_lock);
1250 pprev = &icmp6_dst_gc_list;
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001251
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 while ((dst = *pprev) != NULL) {
1253 if (!atomic_read(&dst->__refcnt)) {
1254 *pprev = dst->next;
1255 dst_free(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 } else {
1257 pprev = &dst->next;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001258 ++more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 }
1260 }
1261
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001262 spin_unlock_bh(&icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001263
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001264 return more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265}
1266
David S. Miller1e493d12008-09-10 17:27:15 -07001267static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg),
1268 void *arg)
1269{
1270 struct dst_entry *dst, **pprev;
1271
1272 spin_lock_bh(&icmp6_dst_lock);
1273 pprev = &icmp6_dst_gc_list;
1274 while ((dst = *pprev) != NULL) {
1275 struct rt6_info *rt = (struct rt6_info *) dst;
1276 if (func(rt, arg)) {
1277 *pprev = dst->next;
1278 dst_free(dst);
1279 } else {
1280 pprev = &dst->next;
1281 }
1282 }
1283 spin_unlock_bh(&icmp6_dst_lock);
1284}
1285
Daniel Lezcano569d3642008-01-18 03:56:57 -08001286static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 unsigned long now = jiffies;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00001289 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08001290 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
1291 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
1292 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
1293 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
1294 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001295 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296
Eric Dumazetfc66f952010-10-08 06:37:34 +00001297 entries = dst_entries_get_fast(ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08001298 if (time_after(rt_last_gc + rt_min_interval, now) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00001299 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 goto out;
1301
Benjamin Thery6891a342008-03-04 13:49:47 -08001302 net->ipv6.ip6_rt_gc_expire++;
1303 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net);
1304 net->ipv6.ip6_rt_last_gc = now;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001305 entries = dst_entries_get_slow(ops);
1306 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08001307 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08001309 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001310 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311}
1312
YOSHIFUJI Hideaki6b75d092008-03-10 06:00:30 -04001313int ip6_dst_hoplimit(struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314{
David S. Miller5170ae82010-12-12 21:35:57 -08001315 int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT);
David S. Millera02e4b72010-12-12 21:39:02 -08001316 if (hoplimit == 0) {
YOSHIFUJI Hideaki6b75d092008-03-10 06:00:30 -04001317 struct net_device *dev = dst->dev;
Eric Dumazetc68f24c2010-06-14 04:46:20 +00001318 struct inet6_dev *idev;
1319
1320 rcu_read_lock();
1321 idev = __in6_dev_get(dev);
1322 if (idev)
YOSHIFUJI Hideaki6b75d092008-03-10 06:00:30 -04001323 hoplimit = idev->cnf.hop_limit;
Eric Dumazetc68f24c2010-06-14 04:46:20 +00001324 else
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -07001325 hoplimit = dev_net(dev)->ipv6.devconf_all->hop_limit;
Eric Dumazetc68f24c2010-06-14 04:46:20 +00001326 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 }
1328 return hoplimit;
1329}
David S. Millerabbf46a2010-12-12 21:14:46 -08001330EXPORT_SYMBOL(ip6_dst_hoplimit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331
1332/*
1333 *
1334 */
1335
Thomas Graf86872cb2006-08-22 00:01:08 -07001336int ip6_route_add(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337{
1338 int err;
Daniel Lezcano55786892008-03-04 13:47:47 -08001339 struct net *net = cfg->fc_nlinfo.nl_net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 struct rt6_info *rt = NULL;
1341 struct net_device *dev = NULL;
1342 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001343 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 int addr_type;
1345
Thomas Graf86872cb2006-08-22 00:01:08 -07001346 if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 return -EINVAL;
1348#ifndef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001349 if (cfg->fc_src_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 return -EINVAL;
1351#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07001352 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08001354 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 if (!dev)
1356 goto out;
1357 idev = in6_dev_get(dev);
1358 if (!idev)
1359 goto out;
1360 }
1361
Thomas Graf86872cb2006-08-22 00:01:08 -07001362 if (cfg->fc_metric == 0)
1363 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364
Matti Vaittinend71314b2011-11-14 00:14:49 +00001365 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05001366 if (cfg->fc_nlinfo.nlh &&
1367 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00001368 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001369 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00001370 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00001371 table = fib6_new_table(net, cfg->fc_table);
1372 }
1373 } else {
1374 table = fib6_new_table(net, cfg->fc_table);
1375 }
David S. Miller38308472011-12-03 18:02:47 -05001376
1377 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001378 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07001379
David S. Miller8b96d222012-06-11 02:01:56 -07001380 rt = ip6_dst_alloc(net, NULL, DST_NOCOUNT, table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381
David S. Miller38308472011-12-03 18:02:47 -05001382 if (!rt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 err = -ENOMEM;
1384 goto out;
1385 }
1386
Gao feng1716a962012-04-06 00:13:10 +00001387 if (cfg->fc_flags & RTF_EXPIRES)
1388 rt6_set_expires(rt, jiffies +
1389 clock_t_to_jiffies(cfg->fc_expires));
1390 else
1391 rt6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392
Thomas Graf86872cb2006-08-22 00:01:08 -07001393 if (cfg->fc_protocol == RTPROT_UNSPEC)
1394 cfg->fc_protocol = RTPROT_BOOT;
1395 rt->rt6i_protocol = cfg->fc_protocol;
1396
1397 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
1399 if (addr_type & IPV6_ADDR_MULTICAST)
Changli Gaod8d1f302010-06-10 23:31:35 -07001400 rt->dst.input = ip6_mc_input;
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00001401 else if (cfg->fc_flags & RTF_LOCAL)
1402 rt->dst.input = ip6_input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 else
Changli Gaod8d1f302010-06-10 23:31:35 -07001404 rt->dst.input = ip6_forward;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405
Changli Gaod8d1f302010-06-10 23:31:35 -07001406 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407
Thomas Graf86872cb2006-08-22 00:01:08 -07001408 ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
1409 rt->rt6i_dst.plen = cfg->fc_dst_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 if (rt->rt6i_dst.plen == 128)
David S. Miller11d53b42011-06-24 15:23:34 -07001411 rt->dst.flags |= DST_HOST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001413 if (!(rt->dst.flags & DST_HOST) && cfg->fc_mx) {
1414 u32 *metrics = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
1415 if (!metrics) {
1416 err = -ENOMEM;
1417 goto out;
1418 }
1419 dst_init_metrics(&rt->dst, metrics, 0);
1420 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421#ifdef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001422 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
1423 rt->rt6i_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424#endif
1425
Thomas Graf86872cb2006-08-22 00:01:08 -07001426 rt->rt6i_metric = cfg->fc_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427
1428 /* We cannot add true routes via loopback here,
1429 they would result in kernel looping; promote them to reject routes
1430 */
Thomas Graf86872cb2006-08-22 00:01:08 -07001431 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05001432 (dev && (dev->flags & IFF_LOOPBACK) &&
1433 !(addr_type & IPV6_ADDR_LOOPBACK) &&
1434 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08001436 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 if (dev) {
1438 dev_put(dev);
1439 in6_dev_put(idev);
1440 }
Daniel Lezcano55786892008-03-04 13:47:47 -08001441 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 dev_hold(dev);
1443 idev = in6_dev_get(dev);
1444 if (!idev) {
1445 err = -ENODEV;
1446 goto out;
1447 }
1448 }
Changli Gaod8d1f302010-06-10 23:31:35 -07001449 rt->dst.output = ip6_pkt_discard_out;
1450 rt->dst.input = ip6_pkt_discard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001452 switch (cfg->fc_type) {
1453 case RTN_BLACKHOLE:
1454 rt->dst.error = -EINVAL;
1455 break;
1456 case RTN_PROHIBIT:
1457 rt->dst.error = -EACCES;
1458 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00001459 case RTN_THROW:
1460 rt->dst.error = -EAGAIN;
1461 break;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001462 default:
1463 rt->dst.error = -ENETUNREACH;
1464 break;
1465 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 goto install_route;
1467 }
1468
Thomas Graf86872cb2006-08-22 00:01:08 -07001469 if (cfg->fc_flags & RTF_GATEWAY) {
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001470 const struct in6_addr *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 int gwa_type;
1472
Thomas Graf86872cb2006-08-22 00:01:08 -07001473 gw_addr = &cfg->fc_gateway;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001474 rt->rt6i_gateway = *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 gwa_type = ipv6_addr_type(gw_addr);
1476
1477 if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
1478 struct rt6_info *grt;
1479
1480 /* IPv6 strictly inhibits using not link-local
1481 addresses as nexthop address.
1482 Otherwise, router will not able to send redirects.
1483 It is very good, but in some (rare!) circumstances
1484 (SIT, PtP, NBMA NOARP links) it is handy to allow
1485 some exceptions. --ANK
1486 */
1487 err = -EINVAL;
David S. Miller38308472011-12-03 18:02:47 -05001488 if (!(gwa_type & IPV6_ADDR_UNICAST))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 goto out;
1490
Daniel Lezcano55786892008-03-04 13:47:47 -08001491 grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492
1493 err = -EHOSTUNREACH;
David S. Miller38308472011-12-03 18:02:47 -05001494 if (!grt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 goto out;
1496 if (dev) {
David S. Millerd1918542011-12-28 20:19:20 -05001497 if (dev != grt->dst.dev) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00001498 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 goto out;
1500 }
1501 } else {
David S. Millerd1918542011-12-28 20:19:20 -05001502 dev = grt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 idev = grt->rt6i_idev;
1504 dev_hold(dev);
1505 in6_dev_hold(grt->rt6i_idev);
1506 }
David S. Miller38308472011-12-03 18:02:47 -05001507 if (!(grt->rt6i_flags & RTF_GATEWAY))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 err = 0;
Amerigo Wang94e187c2012-10-29 00:13:19 +00001509 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510
1511 if (err)
1512 goto out;
1513 }
1514 err = -EINVAL;
David S. Miller38308472011-12-03 18:02:47 -05001515 if (!dev || (dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 goto out;
1517 }
1518
1519 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05001520 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 goto out;
1522
Daniel Walterc3968a82011-04-13 21:10:57 +00001523 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
1524 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
1525 err = -EINVAL;
1526 goto out;
1527 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001528 rt->rt6i_prefsrc.addr = cfg->fc_prefsrc;
Daniel Walterc3968a82011-04-13 21:10:57 +00001529 rt->rt6i_prefsrc.plen = 128;
1530 } else
1531 rt->rt6i_prefsrc.plen = 0;
1532
Thomas Graf86872cb2006-08-22 00:01:08 -07001533 rt->rt6i_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534
1535install_route:
Thomas Graf86872cb2006-08-22 00:01:08 -07001536 if (cfg->fc_mx) {
1537 struct nlattr *nla;
1538 int remaining;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539
Thomas Graf86872cb2006-08-22 00:01:08 -07001540 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
Thomas Graf8f4c1f92007-09-12 14:44:36 +02001541 int type = nla_type(nla);
Thomas Graf86872cb2006-08-22 00:01:08 -07001542
1543 if (type) {
1544 if (type > RTAX_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 err = -EINVAL;
1546 goto out;
1547 }
Thomas Graf86872cb2006-08-22 00:01:08 -07001548
David S. Millerdefb3512010-12-08 21:16:57 -08001549 dst_metric_set(&rt->dst, type, nla_get_u32(nla));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 }
1552 }
1553
Changli Gaod8d1f302010-06-10 23:31:35 -07001554 rt->dst.dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 rt->rt6i_idev = idev;
Thomas Grafc71099a2006-08-04 23:20:06 -07001556 rt->rt6i_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001557
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001558 cfg->fc_nlinfo.nl_net = dev_net(dev);
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001559
Thomas Graf86872cb2006-08-22 00:01:08 -07001560 return __ip6_ins_rt(rt, &cfg->fc_nlinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561
1562out:
1563 if (dev)
1564 dev_put(dev);
1565 if (idev)
1566 in6_dev_put(idev);
1567 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07001568 dst_free(&rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 return err;
1570}
1571
Thomas Graf86872cb2006-08-22 00:01:08 -07001572static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573{
1574 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07001575 struct fib6_table *table;
David S. Millerd1918542011-12-28 20:19:20 -05001576 struct net *net = dev_net(rt->dst.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577
Gao feng6825a262012-09-19 19:25:34 +00001578 if (rt == net->ipv6.ip6_null_entry) {
1579 err = -ENOENT;
1580 goto out;
1581 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07001582
Thomas Grafc71099a2006-08-04 23:20:06 -07001583 table = rt->rt6i_table;
1584 write_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07001585 err = fib6_del(rt, info);
Thomas Grafc71099a2006-08-04 23:20:06 -07001586 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587
Gao feng6825a262012-09-19 19:25:34 +00001588out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00001589 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 return err;
1591}
1592
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001593int ip6_del_rt(struct rt6_info *rt)
1594{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08001595 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -05001596 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08001597 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08001598 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001599}
1600
Thomas Graf86872cb2006-08-22 00:01:08 -07001601static int ip6_route_del(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602{
Thomas Grafc71099a2006-08-04 23:20:06 -07001603 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 struct fib6_node *fn;
1605 struct rt6_info *rt;
1606 int err = -ESRCH;
1607
Daniel Lezcano55786892008-03-04 13:47:47 -08001608 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001609 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001610 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611
Thomas Grafc71099a2006-08-04 23:20:06 -07001612 read_lock_bh(&table->tb6_lock);
1613
1614 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07001615 &cfg->fc_dst, cfg->fc_dst_len,
1616 &cfg->fc_src, cfg->fc_src_len);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001617
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 if (fn) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001619 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
Thomas Graf86872cb2006-08-22 00:01:08 -07001620 if (cfg->fc_ifindex &&
David S. Millerd1918542011-12-28 20:19:20 -05001621 (!rt->dst.dev ||
1622 rt->dst.dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001624 if (cfg->fc_flags & RTF_GATEWAY &&
1625 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001627 if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07001629 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07001630 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631
Thomas Graf86872cb2006-08-22 00:01:08 -07001632 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 }
1634 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001635 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636
1637 return err;
1638}
1639
David S. Miller6700c272012-07-17 03:29:28 -07001640static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001641{
David S. Millere8599ff2012-07-11 23:43:53 -07001642 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001643 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07001644 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07001645 struct ndisc_options ndopts;
1646 struct inet6_dev *in6_dev;
1647 struct neighbour *neigh;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001648 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07001649 int optlen, on_link;
1650 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07001651
1652 optlen = skb->tail - skb->transport_header;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001653 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07001654
1655 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07001656 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001657 return;
1658 }
1659
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001660 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07001661
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001662 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07001663 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001664 return;
1665 }
1666
David S. Miller6e157b62012-07-12 00:05:02 -07001667 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001668 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07001669 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001670 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07001671 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07001672 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001673 return;
1674 }
1675
1676 in6_dev = __in6_dev_get(skb->dev);
1677 if (!in6_dev)
1678 return;
1679 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
1680 return;
1681
1682 /* RFC2461 8.1:
1683 * The IP source address of the Redirect MUST be the same as the current
1684 * first-hop router for the specified ICMP Destination Address.
1685 */
1686
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001687 if (!ndisc_parse_options(msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07001688 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
1689 return;
1690 }
David S. Miller6e157b62012-07-12 00:05:02 -07001691
1692 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07001693 if (ndopts.nd_opts_tgt_lladdr) {
1694 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
1695 skb->dev);
1696 if (!lladdr) {
1697 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
1698 return;
1699 }
1700 }
1701
David S. Miller6e157b62012-07-12 00:05:02 -07001702 rt = (struct rt6_info *) dst;
1703 if (rt == net->ipv6.ip6_null_entry) {
1704 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
1705 return;
1706 }
1707
1708 /* Redirect received -> path was valid.
1709 * Look, redirects are sent only in response to data packets,
1710 * so that this nexthop apparently is reachable. --ANK
1711 */
1712 dst_confirm(&rt->dst);
1713
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001714 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07001715 if (!neigh)
1716 return;
1717
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 /*
1719 * We have finally decided to accept it.
1720 */
1721
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001722 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1724 NEIGH_UPDATE_F_OVERRIDE|
1725 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1726 NEIGH_UPDATE_F_ISROUTER))
1727 );
1728
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001729 nrt = ip6_rt_copy(rt, &msg->dest);
David S. Miller38308472011-12-03 18:02:47 -05001730 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 goto out;
1732
1733 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
1734 if (on_link)
1735 nrt->rt6i_flags &= ~RTF_GATEWAY;
1736
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001737 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738
Thomas Graf40e22e82006-08-22 00:00:45 -07001739 if (ip6_ins_rt(nrt))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 goto out;
1741
Changli Gaod8d1f302010-06-10 23:31:35 -07001742 netevent.old = &rt->dst;
1743 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001744 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00001745 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07001746 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
1747
David S. Miller38308472011-12-03 18:02:47 -05001748 if (rt->rt6i_flags & RTF_CACHE) {
David S. Miller6e157b62012-07-12 00:05:02 -07001749 rt = (struct rt6_info *) dst_clone(&rt->dst);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001750 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 }
1752
1753out:
David S. Millere8599ff2012-07-11 23:43:53 -07001754 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07001755}
1756
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 * Misc support functions
1759 */
1760
Gao feng1716a962012-04-06 00:13:10 +00001761static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
Eric Dumazet21efcfa2011-07-19 20:18:36 +00001762 const struct in6_addr *dest)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763{
David S. Millerd1918542011-12-28 20:19:20 -05001764 struct net *net = dev_net(ort->dst.dev);
David S. Miller8b96d222012-06-11 02:01:56 -07001765 struct rt6_info *rt = ip6_dst_alloc(net, ort->dst.dev, 0,
1766 ort->rt6i_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767
1768 if (rt) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001769 rt->dst.input = ort->dst.input;
1770 rt->dst.output = ort->dst.output;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001771 rt->dst.flags |= DST_HOST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001773 rt->rt6i_dst.addr = *dest;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001774 rt->rt6i_dst.plen = 128;
David S. Millerdefb3512010-12-08 21:16:57 -08001775 dst_copy_metrics(&rt->dst, &ort->dst);
Changli Gaod8d1f302010-06-10 23:31:35 -07001776 rt->dst.error = ort->dst.error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 rt->rt6i_idev = ort->rt6i_idev;
1778 if (rt->rt6i_idev)
1779 in6_dev_hold(rt->rt6i_idev);
Changli Gaod8d1f302010-06-10 23:31:35 -07001780 rt->dst.lastuse = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001782 rt->rt6i_gateway = ort->rt6i_gateway;
Gao feng1716a962012-04-06 00:13:10 +00001783 rt->rt6i_flags = ort->rt6i_flags;
1784 if ((ort->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) ==
1785 (RTF_DEFAULT | RTF_ADDRCONF))
1786 rt6_set_from(rt, ort);
1787 else
1788 rt6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 rt->rt6i_metric = 0;
1790
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791#ifdef CONFIG_IPV6_SUBTREES
1792 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1793#endif
Florian Westphal0f6c6392011-05-20 11:27:24 +00001794 memcpy(&rt->rt6i_prefsrc, &ort->rt6i_prefsrc, sizeof(struct rt6key));
Thomas Grafc71099a2006-08-04 23:20:06 -07001795 rt->rt6i_table = ort->rt6i_table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 }
1797 return rt;
1798}
1799
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001800#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001801static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001802 const struct in6_addr *prefix, int prefixlen,
1803 const struct in6_addr *gwaddr, int ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001804{
1805 struct fib6_node *fn;
1806 struct rt6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001807 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001808
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001809 table = fib6_get_table(net, RT6_TABLE_INFO);
David S. Miller38308472011-12-03 18:02:47 -05001810 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001811 return NULL;
1812
Li RongQing5744dd92012-09-11 21:59:01 +00001813 read_lock_bh(&table->tb6_lock);
Thomas Grafc71099a2006-08-04 23:20:06 -07001814 fn = fib6_locate(&table->tb6_root, prefix ,prefixlen, NULL, 0);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001815 if (!fn)
1816 goto out;
1817
Changli Gaod8d1f302010-06-10 23:31:35 -07001818 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05001819 if (rt->dst.dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001820 continue;
1821 if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
1822 continue;
1823 if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
1824 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07001825 dst_hold(&rt->dst);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001826 break;
1827 }
1828out:
Li RongQing5744dd92012-09-11 21:59:01 +00001829 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001830 return rt;
1831}
1832
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001833static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001834 const struct in6_addr *prefix, int prefixlen,
1835 const struct in6_addr *gwaddr, int ifindex,
Eric Dumazet95c96172012-04-15 05:58:06 +00001836 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001837{
Thomas Graf86872cb2006-08-22 00:01:08 -07001838 struct fib6_config cfg = {
1839 .fc_table = RT6_TABLE_INFO,
Rami Rosen238fc7e2008-02-09 23:43:11 -08001840 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07001841 .fc_ifindex = ifindex,
1842 .fc_dst_len = prefixlen,
1843 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
1844 RTF_UP | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00001845 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001846 .fc_nlinfo.nlh = NULL,
1847 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07001848 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001849
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001850 cfg.fc_dst = *prefix;
1851 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07001852
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08001853 /* We should treat it as a default route if prefix length is 0. */
1854 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07001855 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001856
Thomas Graf86872cb2006-08-22 00:01:08 -07001857 ip6_route_add(&cfg);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001858
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001859 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001860}
1861#endif
1862
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001863struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001864{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001866 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001868 table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05001869 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001870 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871
Li RongQing5744dd92012-09-11 21:59:01 +00001872 read_lock_bh(&table->tb6_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001873 for (rt = table->tb6_root.leaf; rt; rt=rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05001874 if (dev == rt->dst.dev &&
YOSHIFUJI Hideaki045927f2006-03-20 17:00:48 -08001875 ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 ipv6_addr_equal(&rt->rt6i_gateway, addr))
1877 break;
1878 }
1879 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07001880 dst_hold(&rt->dst);
Li RongQing5744dd92012-09-11 21:59:01 +00001881 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 return rt;
1883}
1884
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001885struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001886 struct net_device *dev,
1887 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888{
Thomas Graf86872cb2006-08-22 00:01:08 -07001889 struct fib6_config cfg = {
1890 .fc_table = RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08001891 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07001892 .fc_ifindex = dev->ifindex,
1893 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
1894 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00001895 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08001896 .fc_nlinfo.nlh = NULL,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001897 .fc_nlinfo.nl_net = dev_net(dev),
Thomas Graf86872cb2006-08-22 00:01:08 -07001898 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001900 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901
Thomas Graf86872cb2006-08-22 00:01:08 -07001902 ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 return rt6_get_dflt_router(gwaddr, dev);
1905}
1906
Daniel Lezcano7b4da532008-03-04 13:47:14 -08001907void rt6_purge_dflt_routers(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908{
1909 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001910 struct fib6_table *table;
1911
1912 /* NOTE: Keep consistent with rt6_get_dflt_router */
Daniel Lezcano7b4da532008-03-04 13:47:14 -08001913 table = fib6_get_table(net, RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05001914 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001915 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916
1917restart:
Thomas Grafc71099a2006-08-04 23:20:06 -07001918 read_lock_bh(&table->tb6_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001919 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001921 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07001922 read_unlock_bh(&table->tb6_lock);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001923 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 goto restart;
1925 }
1926 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001927 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928}
1929
Daniel Lezcano55786892008-03-04 13:47:47 -08001930static void rtmsg_to_fib6_config(struct net *net,
1931 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07001932 struct fib6_config *cfg)
1933{
1934 memset(cfg, 0, sizeof(*cfg));
1935
1936 cfg->fc_table = RT6_TABLE_MAIN;
1937 cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
1938 cfg->fc_metric = rtmsg->rtmsg_metric;
1939 cfg->fc_expires = rtmsg->rtmsg_info;
1940 cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
1941 cfg->fc_src_len = rtmsg->rtmsg_src_len;
1942 cfg->fc_flags = rtmsg->rtmsg_flags;
1943
Daniel Lezcano55786892008-03-04 13:47:47 -08001944 cfg->fc_nlinfo.nl_net = net;
Benjamin Theryf1243c22008-02-26 18:10:03 -08001945
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001946 cfg->fc_dst = rtmsg->rtmsg_dst;
1947 cfg->fc_src = rtmsg->rtmsg_src;
1948 cfg->fc_gateway = rtmsg->rtmsg_gateway;
Thomas Graf86872cb2006-08-22 00:01:08 -07001949}
1950
Daniel Lezcano55786892008-03-04 13:47:47 -08001951int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952{
Thomas Graf86872cb2006-08-22 00:01:08 -07001953 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 struct in6_rtmsg rtmsg;
1955 int err;
1956
1957 switch(cmd) {
1958 case SIOCADDRT: /* Add a route */
1959 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00001960 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 return -EPERM;
1962 err = copy_from_user(&rtmsg, arg,
1963 sizeof(struct in6_rtmsg));
1964 if (err)
1965 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07001966
Daniel Lezcano55786892008-03-04 13:47:47 -08001967 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07001968
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 rtnl_lock();
1970 switch (cmd) {
1971 case SIOCADDRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07001972 err = ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 break;
1974 case SIOCDELRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07001975 err = ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 break;
1977 default:
1978 err = -EINVAL;
1979 }
1980 rtnl_unlock();
1981
1982 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001983 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984
1985 return -EINVAL;
1986}
1987
1988/*
1989 * Drop the packet on the floor
1990 */
1991
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07001992static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07001994 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00001995 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07001996 switch (ipstats_mib_noroutes) {
1997 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001998 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00001999 if (type == IPV6_ADDR_ANY) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002000 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2001 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002002 break;
2003 }
2004 /* FALLTHROUGH */
2005 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002006 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2007 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002008 break;
2009 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002010 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 kfree_skb(skb);
2012 return 0;
2013}
2014
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002015static int ip6_pkt_discard(struct sk_buff *skb)
2016{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002017 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002018}
2019
Arnaldo Carvalho de Melo20380732005-08-16 02:18:02 -03002020static int ip6_pkt_discard_out(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021{
Eric Dumazetadf30902009-06-02 05:19:30 +00002022 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002023 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024}
2025
David S. Miller6723ab52006-10-18 21:20:57 -07002026#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2027
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002028static int ip6_pkt_prohibit(struct sk_buff *skb)
2029{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002030 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002031}
2032
2033static int ip6_pkt_prohibit_out(struct sk_buff *skb)
2034{
Eric Dumazetadf30902009-06-02 05:19:30 +00002035 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002036 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002037}
2038
David S. Miller6723ab52006-10-18 21:20:57 -07002039#endif
2040
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041/*
2042 * Allocate a dst for local (unicast / anycast) address.
2043 */
2044
2045struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
2046 const struct in6_addr *addr,
David S. Miller8f031512011-12-06 16:48:14 -05002047 bool anycast)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002049 struct net *net = dev_net(idev->dev);
David S. Miller8b96d222012-06-11 02:01:56 -07002050 struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev, 0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051
David S. Miller38308472011-12-03 18:02:47 -05002052 if (!rt) {
Joe Perchesf3213832012-05-15 14:11:53 +00002053 net_warn_ratelimited("Maximum number of routes reached, consider increasing route/max_size\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 return ERR_PTR(-ENOMEM);
Ben Greear40385652010-11-08 12:33:48 +00002055 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 in6_dev_hold(idev);
2058
David S. Miller11d53b42011-06-24 15:23:34 -07002059 rt->dst.flags |= DST_HOST;
Changli Gaod8d1f302010-06-10 23:31:35 -07002060 rt->dst.input = ip6_input;
2061 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 rt->rt6i_idev = idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063
2064 rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +09002065 if (anycast)
2066 rt->rt6i_flags |= RTF_ANYCAST;
2067 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 rt->rt6i_flags |= RTF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002070 rt->rt6i_dst.addr = *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 rt->rt6i_dst.plen = 128;
Daniel Lezcano55786892008-03-04 13:47:47 -08002072 rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073
Changli Gaod8d1f302010-06-10 23:31:35 -07002074 atomic_set(&rt->dst.__refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075
2076 return rt;
2077}
2078
Daniel Walterc3968a82011-04-13 21:10:57 +00002079int ip6_route_get_saddr(struct net *net,
2080 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002081 const struct in6_addr *daddr,
Daniel Walterc3968a82011-04-13 21:10:57 +00002082 unsigned int prefs,
2083 struct in6_addr *saddr)
2084{
2085 struct inet6_dev *idev = ip6_dst_idev((struct dst_entry*)rt);
2086 int err = 0;
2087 if (rt->rt6i_prefsrc.plen)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002088 *saddr = rt->rt6i_prefsrc.addr;
Daniel Walterc3968a82011-04-13 21:10:57 +00002089 else
2090 err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
2091 daddr, prefs, saddr);
2092 return err;
2093}
2094
2095/* remove deleted ip from prefsrc entries */
2096struct arg_dev_net_ip {
2097 struct net_device *dev;
2098 struct net *net;
2099 struct in6_addr *addr;
2100};
2101
2102static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
2103{
2104 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
2105 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
2106 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
2107
David S. Millerd1918542011-12-28 20:19:20 -05002108 if (((void *)rt->dst.dev == dev || !dev) &&
Daniel Walterc3968a82011-04-13 21:10:57 +00002109 rt != net->ipv6.ip6_null_entry &&
2110 ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
2111 /* remove prefsrc entry */
2112 rt->rt6i_prefsrc.plen = 0;
2113 }
2114 return 0;
2115}
2116
2117void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
2118{
2119 struct net *net = dev_net(ifp->idev->dev);
2120 struct arg_dev_net_ip adni = {
2121 .dev = ifp->idev->dev,
2122 .net = net,
2123 .addr = &ifp->addr,
2124 };
2125 fib6_clean_all(net, fib6_remove_prefsrc, 0, &adni);
2126}
2127
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002128struct arg_dev_net {
2129 struct net_device *dev;
2130 struct net *net;
2131};
2132
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133static int fib6_ifdown(struct rt6_info *rt, void *arg)
2134{
stephen hemmingerbc3ef662010-12-16 17:42:40 +00002135 const struct arg_dev_net *adn = arg;
2136 const struct net_device *dev = adn->dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002137
David S. Millerd1918542011-12-28 20:19:20 -05002138 if ((rt->dst.dev == dev || !dev) &&
David S. Millerc159d302011-12-26 15:24:36 -05002139 rt != adn->net->ipv6.ip6_null_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 return -1;
David S. Millerc159d302011-12-26 15:24:36 -05002141
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 return 0;
2143}
2144
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002145void rt6_ifdown(struct net *net, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002147 struct arg_dev_net adn = {
2148 .dev = dev,
2149 .net = net,
2150 };
2151
2152 fib6_clean_all(net, fib6_ifdown, 0, &adn);
David S. Miller1e493d12008-09-10 17:27:15 -07002153 icmp6_clean_all(fib6_ifdown, &adn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154}
2155
Eric Dumazet95c96172012-04-15 05:58:06 +00002156struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00002158 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159};
2160
2161static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
2162{
2163 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
2164 struct inet6_dev *idev;
2165
2166 /* In IPv6 pmtu discovery is not optional,
2167 so that RTAX_MTU lock cannot disable it.
2168 We still use this lock to block changes
2169 caused by addrconf/ndisc.
2170 */
2171
2172 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05002173 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 return 0;
2175
2176 /* For administrative MTU increase, there is no way to discover
2177 IPv6 PMTU increase, so PMTU increase should be updated here.
2178 Since RFC 1981 doesn't include administrative MTU increase
2179 update PMTU increase is a MUST. (i.e. jumbo frame)
2180 */
2181 /*
2182 If new MTU is less than route PMTU, this new MTU will be the
2183 lowest MTU in the path, update the route PMTU to reflect PMTU
2184 decreases; if new MTU is greater than route PMTU, and the
2185 old MTU is the lowest MTU in the path, update the route PMTU
2186 to reflect the increase. In this case if the other nodes' MTU
2187 also have the lowest MTU, TOO BIG MESSAGE will be lead to
2188 PMTU discouvery.
2189 */
David S. Millerd1918542011-12-28 20:19:20 -05002190 if (rt->dst.dev == arg->dev &&
Changli Gaod8d1f302010-06-10 23:31:35 -07002191 !dst_metric_locked(&rt->dst, RTAX_MTU) &&
2192 (dst_mtu(&rt->dst) >= arg->mtu ||
2193 (dst_mtu(&rt->dst) < arg->mtu &&
2194 dst_mtu(&rt->dst) == idev->cnf.mtu6))) {
David S. Millerdefb3512010-12-08 21:16:57 -08002195 dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu);
Simon Arlott566cfd82007-07-26 00:09:55 -07002196 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 return 0;
2198}
2199
Eric Dumazet95c96172012-04-15 05:58:06 +00002200void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201{
Thomas Grafc71099a2006-08-04 23:20:06 -07002202 struct rt6_mtu_change_arg arg = {
2203 .dev = dev,
2204 .mtu = mtu,
2205 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002207 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, 0, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208}
2209
Patrick McHardyef7c79e2007-06-05 12:38:30 -07002210static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07002211 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07002212 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07002213 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002214 [RTA_PRIORITY] = { .type = NLA_U32 },
2215 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd3182012-10-22 03:42:09 +00002216 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Thomas Graf86872cb2006-08-22 00:01:08 -07002217};
2218
2219static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
2220 struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221{
Thomas Graf86872cb2006-08-22 00:01:08 -07002222 struct rtmsg *rtm;
2223 struct nlattr *tb[RTA_MAX+1];
2224 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225
Thomas Graf86872cb2006-08-22 00:01:08 -07002226 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2227 if (err < 0)
2228 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229
Thomas Graf86872cb2006-08-22 00:01:08 -07002230 err = -EINVAL;
2231 rtm = nlmsg_data(nlh);
2232 memset(cfg, 0, sizeof(*cfg));
2233
2234 cfg->fc_table = rtm->rtm_table;
2235 cfg->fc_dst_len = rtm->rtm_dst_len;
2236 cfg->fc_src_len = rtm->rtm_src_len;
2237 cfg->fc_flags = RTF_UP;
2238 cfg->fc_protocol = rtm->rtm_protocol;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002239 cfg->fc_type = rtm->rtm_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07002240
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002241 if (rtm->rtm_type == RTN_UNREACHABLE ||
2242 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002243 rtm->rtm_type == RTN_PROHIBIT ||
2244 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07002245 cfg->fc_flags |= RTF_REJECT;
2246
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002247 if (rtm->rtm_type == RTN_LOCAL)
2248 cfg->fc_flags |= RTF_LOCAL;
2249
Eric W. Biederman15e47302012-09-07 20:12:54 +00002250 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
Thomas Graf86872cb2006-08-22 00:01:08 -07002251 cfg->fc_nlinfo.nlh = nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002252 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
Thomas Graf86872cb2006-08-22 00:01:08 -07002253
2254 if (tb[RTA_GATEWAY]) {
2255 nla_memcpy(&cfg->fc_gateway, tb[RTA_GATEWAY], 16);
2256 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002258
2259 if (tb[RTA_DST]) {
2260 int plen = (rtm->rtm_dst_len + 7) >> 3;
2261
2262 if (nla_len(tb[RTA_DST]) < plen)
2263 goto errout;
2264
2265 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002267
2268 if (tb[RTA_SRC]) {
2269 int plen = (rtm->rtm_src_len + 7) >> 3;
2270
2271 if (nla_len(tb[RTA_SRC]) < plen)
2272 goto errout;
2273
2274 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002276
Daniel Walterc3968a82011-04-13 21:10:57 +00002277 if (tb[RTA_PREFSRC])
2278 nla_memcpy(&cfg->fc_prefsrc, tb[RTA_PREFSRC], 16);
2279
Thomas Graf86872cb2006-08-22 00:01:08 -07002280 if (tb[RTA_OIF])
2281 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
2282
2283 if (tb[RTA_PRIORITY])
2284 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
2285
2286 if (tb[RTA_METRICS]) {
2287 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
2288 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002290
2291 if (tb[RTA_TABLE])
2292 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
2293
Nicolas Dichtel51ebd3182012-10-22 03:42:09 +00002294 if (tb[RTA_MULTIPATH]) {
2295 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
2296 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
2297 }
2298
Thomas Graf86872cb2006-08-22 00:01:08 -07002299 err = 0;
2300errout:
2301 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302}
2303
Nicolas Dichtel51ebd3182012-10-22 03:42:09 +00002304static int ip6_route_multipath(struct fib6_config *cfg, int add)
2305{
2306 struct fib6_config r_cfg;
2307 struct rtnexthop *rtnh;
2308 int remaining;
2309 int attrlen;
2310 int err = 0, last_err = 0;
2311
2312beginning:
2313 rtnh = (struct rtnexthop *)cfg->fc_mp;
2314 remaining = cfg->fc_mp_len;
2315
2316 /* Parse a Multipath Entry */
2317 while (rtnh_ok(rtnh, remaining)) {
2318 memcpy(&r_cfg, cfg, sizeof(*cfg));
2319 if (rtnh->rtnh_ifindex)
2320 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
2321
2322 attrlen = rtnh_attrlen(rtnh);
2323 if (attrlen > 0) {
2324 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
2325
2326 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
2327 if (nla) {
2328 nla_memcpy(&r_cfg.fc_gateway, nla, 16);
2329 r_cfg.fc_flags |= RTF_GATEWAY;
2330 }
2331 }
2332 err = add ? ip6_route_add(&r_cfg) : ip6_route_del(&r_cfg);
2333 if (err) {
2334 last_err = err;
2335 /* If we are trying to remove a route, do not stop the
2336 * loop when ip6_route_del() fails (because next hop is
2337 * already gone), we should try to remove all next hops.
2338 */
2339 if (add) {
2340 /* If add fails, we should try to delete all
2341 * next hops that have been already added.
2342 */
2343 add = 0;
2344 goto beginning;
2345 }
2346 }
Nicolas Dichtel1a724182012-11-01 22:58:22 +00002347 /* Because each route is added like a single route we remove
2348 * this flag after the first nexthop (if there is a collision,
2349 * we have already fail to add the first nexthop:
2350 * fib6_add_rt2node() has reject it).
2351 */
2352 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~NLM_F_EXCL;
Nicolas Dichtel51ebd3182012-10-22 03:42:09 +00002353 rtnh = rtnh_next(rtnh, &remaining);
2354 }
2355
2356 return last_err;
2357}
2358
Thomas Grafc127ea22007-03-22 11:58:32 -07002359static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360{
Thomas Graf86872cb2006-08-22 00:01:08 -07002361 struct fib6_config cfg;
2362 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363
Thomas Graf86872cb2006-08-22 00:01:08 -07002364 err = rtm_to_fib6_config(skb, nlh, &cfg);
2365 if (err < 0)
2366 return err;
2367
Nicolas Dichtel51ebd3182012-10-22 03:42:09 +00002368 if (cfg.fc_mp)
2369 return ip6_route_multipath(&cfg, 0);
2370 else
2371 return ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372}
2373
Thomas Grafc127ea22007-03-22 11:58:32 -07002374static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375{
Thomas Graf86872cb2006-08-22 00:01:08 -07002376 struct fib6_config cfg;
2377 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378
Thomas Graf86872cb2006-08-22 00:01:08 -07002379 err = rtm_to_fib6_config(skb, nlh, &cfg);
2380 if (err < 0)
2381 return err;
2382
Nicolas Dichtel51ebd3182012-10-22 03:42:09 +00002383 if (cfg.fc_mp)
2384 return ip6_route_multipath(&cfg, 1);
2385 else
2386 return ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387}
2388
Thomas Graf339bf982006-11-10 14:10:15 -08002389static inline size_t rt6_nlmsg_size(void)
2390{
2391 return NLMSG_ALIGN(sizeof(struct rtmsg))
2392 + nla_total_size(16) /* RTA_SRC */
2393 + nla_total_size(16) /* RTA_DST */
2394 + nla_total_size(16) /* RTA_GATEWAY */
2395 + nla_total_size(16) /* RTA_PREFSRC */
2396 + nla_total_size(4) /* RTA_TABLE */
2397 + nla_total_size(4) /* RTA_IIF */
2398 + nla_total_size(4) /* RTA_OIF */
2399 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08002400 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Thomas Graf339bf982006-11-10 14:10:15 -08002401 + nla_total_size(sizeof(struct rta_cacheinfo));
2402}
2403
Brian Haley191cd582008-08-14 15:33:21 -07002404static int rt6_fill_node(struct net *net,
2405 struct sk_buff *skb, struct rt6_info *rt,
Jamal Hadi Salim0d51aa82005-06-21 13:51:04 -07002406 struct in6_addr *dst, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002407 int iif, int type, u32 portid, u32 seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002408 int prefix, int nowait, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409{
2410 struct rtmsg *rtm;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002411 struct nlmsghdr *nlh;
Thomas Grafe3703b32006-11-27 09:27:07 -08002412 long expires;
Patrick McHardy9e762a42006-08-10 23:09:48 -07002413 u32 table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414
2415 if (prefix) { /* user wants prefix routes only */
2416 if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
2417 /* success since this is not a prefix route */
2418 return 1;
2419 }
2420 }
2421
Eric W. Biederman15e47302012-09-07 20:12:54 +00002422 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05002423 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08002424 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002425
2426 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 rtm->rtm_family = AF_INET6;
2428 rtm->rtm_dst_len = rt->rt6i_dst.plen;
2429 rtm->rtm_src_len = rt->rt6i_src.plen;
2430 rtm->rtm_tos = 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07002431 if (rt->rt6i_table)
Patrick McHardy9e762a42006-08-10 23:09:48 -07002432 table = rt->rt6i_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07002433 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07002434 table = RT6_TABLE_UNSPEC;
2435 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04002436 if (nla_put_u32(skb, RTA_TABLE, table))
2437 goto nla_put_failure;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002438 if (rt->rt6i_flags & RTF_REJECT) {
2439 switch (rt->dst.error) {
2440 case -EINVAL:
2441 rtm->rtm_type = RTN_BLACKHOLE;
2442 break;
2443 case -EACCES:
2444 rtm->rtm_type = RTN_PROHIBIT;
2445 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002446 case -EAGAIN:
2447 rtm->rtm_type = RTN_THROW;
2448 break;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002449 default:
2450 rtm->rtm_type = RTN_UNREACHABLE;
2451 break;
2452 }
2453 }
David S. Miller38308472011-12-03 18:02:47 -05002454 else if (rt->rt6i_flags & RTF_LOCAL)
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002455 rtm->rtm_type = RTN_LOCAL;
David S. Millerd1918542011-12-28 20:19:20 -05002456 else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 rtm->rtm_type = RTN_LOCAL;
2458 else
2459 rtm->rtm_type = RTN_UNICAST;
2460 rtm->rtm_flags = 0;
2461 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
2462 rtm->rtm_protocol = rt->rt6i_protocol;
David S. Miller38308472011-12-03 18:02:47 -05002463 if (rt->rt6i_flags & RTF_DYNAMIC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 rtm->rtm_protocol = RTPROT_REDIRECT;
Denis Ovsienkof0396f602012-07-10 04:45:50 +00002465 else if (rt->rt6i_flags & RTF_ADDRCONF) {
2466 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ROUTEINFO))
2467 rtm->rtm_protocol = RTPROT_RA;
2468 else
2469 rtm->rtm_protocol = RTPROT_KERNEL;
2470 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471
David S. Miller38308472011-12-03 18:02:47 -05002472 if (rt->rt6i_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 rtm->rtm_flags |= RTM_F_CLONED;
2474
2475 if (dst) {
David S. Millerc78679e2012-04-01 20:27:33 -04002476 if (nla_put(skb, RTA_DST, 16, dst))
2477 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002478 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 } else if (rtm->rtm_dst_len)
David S. Millerc78679e2012-04-01 20:27:33 -04002480 if (nla_put(skb, RTA_DST, 16, &rt->rt6i_dst.addr))
2481 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482#ifdef CONFIG_IPV6_SUBTREES
2483 if (src) {
David S. Millerc78679e2012-04-01 20:27:33 -04002484 if (nla_put(skb, RTA_SRC, 16, src))
2485 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002486 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04002487 } else if (rtm->rtm_src_len &&
2488 nla_put(skb, RTA_SRC, 16, &rt->rt6i_src.addr))
2489 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002491 if (iif) {
2492#ifdef CONFIG_IPV6_MROUTE
2493 if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
Benjamin Thery8229efd2008-12-10 16:30:15 -08002494 int err = ip6mr_get_route(net, skb, rtm, nowait);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002495 if (err <= 0) {
2496 if (!nowait) {
2497 if (err == 0)
2498 return 0;
2499 goto nla_put_failure;
2500 } else {
2501 if (err == -EMSGSIZE)
2502 goto nla_put_failure;
2503 }
2504 }
2505 } else
2506#endif
David S. Millerc78679e2012-04-01 20:27:33 -04002507 if (nla_put_u32(skb, RTA_IIF, iif))
2508 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002509 } else if (dst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 struct in6_addr saddr_buf;
David S. Millerc78679e2012-04-01 20:27:33 -04002511 if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0 &&
2512 nla_put(skb, RTA_PREFSRC, 16, &saddr_buf))
2513 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07002515
Daniel Walterc3968a82011-04-13 21:10:57 +00002516 if (rt->rt6i_prefsrc.plen) {
2517 struct in6_addr saddr_buf;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002518 saddr_buf = rt->rt6i_prefsrc.addr;
David S. Millerc78679e2012-04-01 20:27:33 -04002519 if (nla_put(skb, RTA_PREFSRC, 16, &saddr_buf))
2520 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00002521 }
2522
David S. Millerdefb3512010-12-08 21:16:57 -08002523 if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07002524 goto nla_put_failure;
2525
YOSHIFUJI Hideaki / 吉藤英明dd0cbf22013-01-17 12:53:15 +00002526 if (rt->rt6i_flags & RTF_GATEWAY) {
2527 if (nla_put(skb, RTA_GATEWAY, 16, &rt->rt6i_gateway) < 0)
Eric Dumazet94f826b2012-03-27 09:53:52 +00002528 goto nla_put_failure;
Eric Dumazet94f826b2012-03-27 09:53:52 +00002529 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07002530
David S. Millerc78679e2012-04-01 20:27:33 -04002531 if (rt->dst.dev &&
2532 nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex))
2533 goto nla_put_failure;
2534 if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric))
2535 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00002536
2537 expires = (rt->rt6i_flags & RTF_EXPIRES) ? rt->dst.expires - jiffies : 0;
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07002538
David S. Miller87a50692012-07-10 05:06:14 -07002539 if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, rt->dst.error) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08002540 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541
Thomas Graf2d7202b2006-08-22 00:01:27 -07002542 return nlmsg_end(skb, nlh);
2543
2544nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002545 nlmsg_cancel(skb, nlh);
2546 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547}
2548
Patrick McHardy1b43af52006-08-10 23:11:17 -07002549int rt6_dump_route(struct rt6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550{
2551 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
2552 int prefix;
2553
Thomas Graf2d7202b2006-08-22 00:01:27 -07002554 if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
2555 struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0;
2557 } else
2558 prefix = 0;
2559
Brian Haley191cd582008-08-14 15:33:21 -07002560 return rt6_fill_node(arg->net,
2561 arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002562 NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002563 prefix, 0, NLM_F_MULTI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564}
2565
Thomas Grafc127ea22007-03-22 11:58:32 -07002566static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002568 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07002569 struct nlattr *tb[RTA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07002571 struct sk_buff *skb;
2572 struct rtmsg *rtm;
David S. Miller4c9483b2011-03-12 16:22:43 -05002573 struct flowi6 fl6;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002574 int err, iif = 0, oif = 0;
Thomas Grafab364a62006-08-22 00:01:47 -07002575
2576 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2577 if (err < 0)
2578 goto errout;
2579
2580 err = -EINVAL;
David S. Miller4c9483b2011-03-12 16:22:43 -05002581 memset(&fl6, 0, sizeof(fl6));
Thomas Grafab364a62006-08-22 00:01:47 -07002582
2583 if (tb[RTA_SRC]) {
2584 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
2585 goto errout;
2586
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002587 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07002588 }
2589
2590 if (tb[RTA_DST]) {
2591 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
2592 goto errout;
2593
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002594 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07002595 }
2596
2597 if (tb[RTA_IIF])
2598 iif = nla_get_u32(tb[RTA_IIF]);
2599
2600 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002601 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07002602
2603 if (iif) {
2604 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002605 int flags = 0;
2606
Daniel Lezcano55786892008-03-04 13:47:47 -08002607 dev = __dev_get_by_index(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07002608 if (!dev) {
2609 err = -ENODEV;
2610 goto errout;
2611 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002612
2613 fl6.flowi6_iif = iif;
2614
2615 if (!ipv6_addr_any(&fl6.saddr))
2616 flags |= RT6_LOOKUP_F_HAS_SADDR;
2617
2618 rt = (struct rt6_info *)ip6_route_input_lookup(net, dev, &fl6,
2619 flags);
2620 } else {
2621 fl6.flowi6_oif = oif;
2622
2623 rt = (struct rt6_info *)ip6_route_output(net, NULL, &fl6);
Thomas Grafab364a62006-08-22 00:01:47 -07002624 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625
2626 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05002627 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00002628 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07002629 err = -ENOBUFS;
2630 goto errout;
2631 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632
2633 /* Reserve room for dummy headers, this skb can pass
2634 through good chunk of routing engine.
2635 */
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07002636 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
2638
Changli Gaod8d1f302010-06-10 23:31:35 -07002639 skb_dst_set(skb, &rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640
David S. Miller4c9483b2011-03-12 16:22:43 -05002641 err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002642 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002643 nlh->nlmsg_seq, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07002645 kfree_skb(skb);
2646 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 }
2648
Eric W. Biederman15e47302012-09-07 20:12:54 +00002649 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07002650errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652}
2653
Thomas Graf86872cb2006-08-22 00:01:08 -07002654void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655{
2656 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08002657 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002658 u32 seq;
2659 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002661 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05002662 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07002663
Thomas Graf339bf982006-11-10 14:10:15 -08002664 skb = nlmsg_new(rt6_nlmsg_size(), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05002665 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07002666 goto errout;
2667
Brian Haley191cd582008-08-14 15:33:21 -07002668 err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002669 event, info->portid, seq, 0, 0, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08002670 if (err < 0) {
2671 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
2672 WARN_ON(err == -EMSGSIZE);
2673 kfree_skb(skb);
2674 goto errout;
2675 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00002676 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08002677 info->nlh, gfp_any());
2678 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07002679errout:
2680 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08002681 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682}
2683
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002684static int ip6_route_dev_notify(struct notifier_block *this,
2685 unsigned long event, void *data)
2686{
2687 struct net_device *dev = (struct net_device *)data;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002688 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002689
2690 if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002691 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002692 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
2693#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07002694 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002695 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07002696 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002697 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
2698#endif
2699 }
2700
2701 return NOTIFY_OK;
2702}
2703
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704/*
2705 * /proc
2706 */
2707
2708#ifdef CONFIG_PROC_FS
2709
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710struct rt6_proc_arg
2711{
2712 char *buffer;
2713 int offset;
2714 int length;
2715 int skip;
2716 int len;
2717};
2718
2719static int rt6_info_route(struct rt6_info *rt, void *p_arg)
2720{
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002721 struct seq_file *m = p_arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722
Harvey Harrison4b7a4272008-10-29 12:50:24 -07002723 seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724
2725#ifdef CONFIG_IPV6_SUBTREES
Harvey Harrison4b7a4272008-10-29 12:50:24 -07002726 seq_printf(m, "%pi6 %02x ", &rt->rt6i_src.addr, rt->rt6i_src.plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727#else
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002728 seq_puts(m, "00000000000000000000000000000000 00 ");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729#endif
YOSHIFUJI Hideaki / 吉藤英明dd0cbf22013-01-17 12:53:15 +00002730 if (rt->rt6i_flags & RTF_GATEWAY) {
2731 seq_printf(m, "%pi6", &rt->rt6i_gateway);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 } else {
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002733 seq_puts(m, "00000000000000000000000000000000");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 }
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002735 seq_printf(m, " %08x %08x %08x %08x %8s\n",
Changli Gaod8d1f302010-06-10 23:31:35 -07002736 rt->rt6i_metric, atomic_read(&rt->dst.__refcnt),
2737 rt->dst.__use, rt->rt6i_flags,
David S. Millerd1918542011-12-28 20:19:20 -05002738 rt->dst.dev ? rt->dst.dev->name : "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 return 0;
2740}
2741
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002742static int ipv6_route_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743{
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002744 struct net *net = (struct net *)m->private;
Josh Hunt32b293a2011-12-28 13:23:07 +00002745 fib6_clean_all_ro(net, rt6_info_route, 0, m);
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002746 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747}
2748
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002749static int ipv6_route_open(struct inode *inode, struct file *file)
2750{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07002751 return single_open_net(inode, file, ipv6_route_show);
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002752}
2753
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002754static const struct file_operations ipv6_route_proc_fops = {
2755 .owner = THIS_MODULE,
2756 .open = ipv6_route_open,
2757 .read = seq_read,
2758 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07002759 .release = single_release_net,
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002760};
2761
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762static int rt6_stats_seq_show(struct seq_file *seq, void *v)
2763{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002764 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002766 net->ipv6.rt6_stats->fib_nodes,
2767 net->ipv6.rt6_stats->fib_route_nodes,
2768 net->ipv6.rt6_stats->fib_rt_alloc,
2769 net->ipv6.rt6_stats->fib_rt_entries,
2770 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00002771 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002772 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773
2774 return 0;
2775}
2776
2777static int rt6_stats_seq_open(struct inode *inode, struct file *file)
2778{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07002779 return single_open_net(inode, file, rt6_stats_seq_show);
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002780}
2781
Arjan van de Ven9a321442007-02-12 00:55:35 -08002782static const struct file_operations rt6_stats_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 .owner = THIS_MODULE,
2784 .open = rt6_stats_seq_open,
2785 .read = seq_read,
2786 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07002787 .release = single_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788};
2789#endif /* CONFIG_PROC_FS */
2790
2791#ifdef CONFIG_SYSCTL
2792
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793static
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002794int ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 void __user *buffer, size_t *lenp, loff_t *ppos)
2796{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00002797 struct net *net;
2798 int delay;
2799 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00002801
2802 net = (struct net *)ctl->extra1;
2803 delay = net->ipv6.sysctl.flush_delay;
2804 proc_dointvec(ctl, write, buffer, lenp, ppos);
2805 fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net);
2806 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807}
2808
Daniel Lezcano760f2d02008-01-10 02:53:43 -08002809ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002810 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08002812 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07002814 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002815 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 },
2817 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08002819 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 .maxlen = sizeof(int),
2821 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002822 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 },
2824 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08002826 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827 .maxlen = sizeof(int),
2828 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002829 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 },
2831 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08002833 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 .maxlen = sizeof(int),
2835 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002836 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 },
2838 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08002840 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 .maxlen = sizeof(int),
2842 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002843 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 },
2845 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08002847 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 .maxlen = sizeof(int),
2849 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002850 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 },
2852 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08002854 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 .maxlen = sizeof(int),
2856 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07002857 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 },
2859 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08002861 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 .maxlen = sizeof(int),
2863 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002864 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 },
2866 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08002868 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 .maxlen = sizeof(int),
2870 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07002871 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 },
2873 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08002875 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 .maxlen = sizeof(int),
2877 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002878 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002880 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881};
2882
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002883struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08002884{
2885 struct ctl_table *table;
2886
2887 table = kmemdup(ipv6_route_table_template,
2888 sizeof(ipv6_route_table_template),
2889 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09002890
2891 if (table) {
2892 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00002893 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00002894 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09002895 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
2896 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
2897 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
2898 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
2899 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
2900 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
2901 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08002902 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
Eric W. Biederman464dc802012-11-16 03:02:59 +00002903
2904 /* Don't export sysctls to unprivileged users */
2905 if (net->user_ns != &init_user_ns)
2906 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09002907 }
2908
Daniel Lezcano760f2d02008-01-10 02:53:43 -08002909 return table;
2910}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911#endif
2912
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002913static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08002914{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07002915 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002916
Alexey Dobriyan86393e52009-08-29 01:34:49 +00002917 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
2918 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08002919
Eric Dumazetfc66f952010-10-08 06:37:34 +00002920 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
2921 goto out_ip6_dst_ops;
2922
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002923 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
2924 sizeof(*net->ipv6.ip6_null_entry),
2925 GFP_KERNEL);
2926 if (!net->ipv6.ip6_null_entry)
Eric Dumazetfc66f952010-10-08 06:37:34 +00002927 goto out_ip6_dst_entries;
Changli Gaod8d1f302010-06-10 23:31:35 -07002928 net->ipv6.ip6_null_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002929 (struct dst_entry *)net->ipv6.ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002930 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08002931 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
2932 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002933
2934#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2935 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
2936 sizeof(*net->ipv6.ip6_prohibit_entry),
2937 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07002938 if (!net->ipv6.ip6_prohibit_entry)
2939 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002940 net->ipv6.ip6_prohibit_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002941 (struct dst_entry *)net->ipv6.ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002942 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08002943 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
2944 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002945
2946 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
2947 sizeof(*net->ipv6.ip6_blk_hole_entry),
2948 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07002949 if (!net->ipv6.ip6_blk_hole_entry)
2950 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002951 net->ipv6.ip6_blk_hole_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002952 (struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002953 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08002954 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
2955 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002956#endif
2957
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07002958 net->ipv6.sysctl.flush_delay = 0;
2959 net->ipv6.sysctl.ip6_rt_max_size = 4096;
2960 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
2961 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
2962 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
2963 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
2964 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
2965 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
2966
Benjamin Thery6891a342008-03-04 13:49:47 -08002967 net->ipv6.ip6_rt_gc_expire = 30*HZ;
2968
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002969 ret = 0;
2970out:
2971 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08002972
Peter Zijlstra68fffc62008-10-07 14:12:10 -07002973#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2974out_ip6_prohibit_entry:
2975 kfree(net->ipv6.ip6_prohibit_entry);
2976out_ip6_null_entry:
2977 kfree(net->ipv6.ip6_null_entry);
2978#endif
Eric Dumazetfc66f952010-10-08 06:37:34 +00002979out_ip6_dst_entries:
2980 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08002981out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08002982 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08002983}
2984
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002985static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08002986{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002987 kfree(net->ipv6.ip6_null_entry);
2988#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2989 kfree(net->ipv6.ip6_prohibit_entry);
2990 kfree(net->ipv6.ip6_blk_hole_entry);
2991#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00002992 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08002993}
2994
Thomas Grafd1896342012-06-18 12:08:33 +00002995static int __net_init ip6_route_net_init_late(struct net *net)
2996{
2997#ifdef CONFIG_PROC_FS
Gao fengd4beaa62013-02-18 01:34:54 +00002998 proc_create("ipv6_route", 0, net->proc_net, &ipv6_route_proc_fops);
2999 proc_create("rt6_stats", S_IRUGO, net->proc_net, &rt6_stats_seq_fops);
Thomas Grafd1896342012-06-18 12:08:33 +00003000#endif
3001 return 0;
3002}
3003
3004static void __net_exit ip6_route_net_exit_late(struct net *net)
3005{
3006#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00003007 remove_proc_entry("ipv6_route", net->proc_net);
3008 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00003009#endif
3010}
3011
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003012static struct pernet_operations ip6_route_net_ops = {
3013 .init = ip6_route_net_init,
3014 .exit = ip6_route_net_exit,
3015};
3016
David S. Millerc3426b42012-06-09 16:27:05 -07003017static int __net_init ipv6_inetpeer_init(struct net *net)
3018{
3019 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
3020
3021 if (!bp)
3022 return -ENOMEM;
3023 inet_peer_base_init(bp);
3024 net->ipv6.peers = bp;
3025 return 0;
3026}
3027
3028static void __net_exit ipv6_inetpeer_exit(struct net *net)
3029{
3030 struct inet_peer_base *bp = net->ipv6.peers;
3031
3032 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07003033 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07003034 kfree(bp);
3035}
3036
David S. Miller2b823f72012-06-09 19:00:16 -07003037static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07003038 .init = ipv6_inetpeer_init,
3039 .exit = ipv6_inetpeer_exit,
3040};
3041
Thomas Grafd1896342012-06-18 12:08:33 +00003042static struct pernet_operations ip6_route_net_late_ops = {
3043 .init = ip6_route_net_init_late,
3044 .exit = ip6_route_net_exit_late,
3045};
3046
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003047static struct notifier_block ip6_route_dev_notifier = {
3048 .notifier_call = ip6_route_dev_notify,
3049 .priority = 0,
3050};
3051
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003052int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003054 int ret;
3055
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003056 ret = -ENOMEM;
3057 ip6_dst_ops_template.kmem_cachep =
3058 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
3059 SLAB_HWCACHE_ALIGN, NULL);
3060 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08003061 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07003062
Eric Dumazetfc66f952010-10-08 06:37:34 +00003063 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003064 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003065 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003066
David S. Millerc3426b42012-06-09 16:27:05 -07003067 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
3068 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003069 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00003070
David S. Miller7e52b332012-06-15 15:51:55 -07003071 ret = register_pernet_subsys(&ip6_route_net_ops);
3072 if (ret)
3073 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07003074
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07003075 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
3076
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003077 /* Registering of the loopback is done before this portion of code,
3078 * the loopback reference in rt6_info will not be taken, do it
3079 * manually for init_net */
Changli Gaod8d1f302010-06-10 23:31:35 -07003080 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003081 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3082 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07003083 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003084 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07003085 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003086 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3087 #endif
David S. Millere8803b62012-06-16 01:12:19 -07003088 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003089 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003090 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003091
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003092 ret = xfrm6_init();
3093 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003094 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08003095
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003096 ret = fib6_rules_init();
3097 if (ret)
3098 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08003099
Thomas Grafd1896342012-06-18 12:08:33 +00003100 ret = register_pernet_subsys(&ip6_route_net_late_ops);
3101 if (ret)
3102 goto fib6_rules_init;
3103
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003104 ret = -ENOBUFS;
Greg Rosec7ac8672011-06-10 01:27:09 +00003105 if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) ||
3106 __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) ||
3107 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL))
Thomas Grafd1896342012-06-18 12:08:33 +00003108 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003109
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003110 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003111 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00003112 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003113
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003114out:
3115 return ret;
3116
Thomas Grafd1896342012-06-18 12:08:33 +00003117out_register_late_subsys:
3118 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003119fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003120 fib6_rules_cleanup();
3121xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003122 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00003123out_fib6_init:
3124 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003125out_register_subsys:
3126 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07003127out_register_inetpeer:
3128 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00003129out_dst_entries:
3130 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003131out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003132 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003133 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134}
3135
3136void ip6_route_cleanup(void)
3137{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003138 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00003139 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07003140 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07003143 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003144 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003145 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003146 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147}