blob: 8d9a93ed9c5926924b809b5bb68b267c07f3ca61 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Linux INET6 implementation
3 * FIB front-end.
4 *
5 * Authors:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09006 * Pedro Roque <roque@di.fc.ul.pt>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
13
14/* Changes:
15 *
16 * YOSHIFUJI Hideaki @USAGI
17 * reworked default router selection.
18 * - respect outgoing interface
19 * - select from (probably) reachable routers (i.e.
20 * routers in REACHABLE, STALE, DELAY or PROBE states).
21 * - always select the same router if it is (probably)
22 * reachable. otherwise, round-robin the list.
YOSHIFUJI Hideakic0bece92006-08-23 17:23:25 -070023 * Ville Nuorvala
24 * Fixed routing subtrees.
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 */
26
Joe Perchesf3213832012-05-15 14:11:53 +000027#define pr_fmt(fmt) "IPv6: " fmt
28
Randy Dunlap4fc268d2006-01-11 12:17:47 -080029#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/errno.h>
Paul Gortmakerbc3b2d72011-07-15 11:47:34 -040031#include <linux/export.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/types.h>
33#include <linux/times.h>
34#include <linux/socket.h>
35#include <linux/sockios.h>
36#include <linux/net.h>
37#include <linux/route.h>
38#include <linux/netdevice.h>
39#include <linux/in6.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090040#include <linux/mroute6.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <linux/if_arp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/proc_fs.h>
44#include <linux/seq_file.h>
Daniel Lezcano5b7c9312008-03-03 23:28:58 -080045#include <linux/nsproxy.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090046#include <linux/slab.h>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020047#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <net/snmp.h>
49#include <net/ipv6.h>
50#include <net/ip6_fib.h>
51#include <net/ip6_route.h>
52#include <net/ndisc.h>
53#include <net/addrconf.h>
54#include <net/tcp.h>
55#include <linux/rtnetlink.h>
56#include <net/dst.h>
57#include <net/xfrm.h>
Tom Tucker8d717402006-07-30 20:43:36 -070058#include <net/netevent.h>
Thomas Graf21713eb2006-08-15 00:35:24 -070059#include <net/netlink.h>
Nicolas Dichtel51ebd312012-10-22 03:42:09 +000060#include <net/nexthop.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
62#include <asm/uaccess.h>
63
64#ifdef CONFIG_SYSCTL
65#include <linux/sysctl.h>
66#endif
67
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +020068enum rt6_nud_state {
69 RT6_NUD_FAIL_HARD = -2,
70 RT6_NUD_FAIL_SOFT = -1,
71 RT6_NUD_SUCCEED = 1
72};
73
Gao feng1716a962012-04-06 00:13:10 +000074static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
Eric Dumazet21efcfa2011-07-19 20:18:36 +000075 const struct in6_addr *dest);
Linus Torvalds1da177e2005-04-16 15:20:36 -070076static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
David S. Miller0dbaee32010-12-13 12:52:14 -080077static unsigned int ip6_default_advmss(const struct dst_entry *dst);
Steffen Klassertebb762f2011-11-23 02:12:51 +000078static unsigned int ip6_mtu(const struct dst_entry *dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079static struct dst_entry *ip6_negative_advice(struct dst_entry *);
80static void ip6_dst_destroy(struct dst_entry *);
81static void ip6_dst_ifdown(struct dst_entry *,
82 struct net_device *dev, int how);
Daniel Lezcano569d3642008-01-18 03:56:57 -080083static int ip6_dst_gc(struct dst_ops *ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
85static int ip6_pkt_discard(struct sk_buff *skb);
86static int ip6_pkt_discard_out(struct sk_buff *skb);
87static void ip6_link_failure(struct sk_buff *skb);
David S. Miller6700c272012-07-17 03:29:28 -070088static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
89 struct sk_buff *skb, u32 mtu);
90static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
91 struct sk_buff *skb);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +020092static int rt6_score_route(struct rt6_info *rt, int oif, int strict);
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -080094#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -080095static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +000096 const struct in6_addr *prefix, int prefixlen,
97 const struct in6_addr *gwaddr, int ifindex,
Eric Dumazet95c96172012-04-15 05:58:06 +000098 unsigned int pref);
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -080099static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000100 const struct in6_addr *prefix, int prefixlen,
101 const struct in6_addr *gwaddr, int ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800102#endif
103
David S. Miller06582542011-01-27 14:58:42 -0800104static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
105{
106 struct rt6_info *rt = (struct rt6_info *) dst;
107 struct inet_peer *peer;
108 u32 *p = NULL;
109
Yan, Zheng8e2ec632011-09-05 21:34:30 +0000110 if (!(rt->dst.flags & DST_HOST))
111 return NULL;
112
David S. Millerfbfe95a2012-06-08 23:24:18 -0700113 peer = rt6_get_peer_create(rt);
David S. Miller06582542011-01-27 14:58:42 -0800114 if (peer) {
115 u32 *old_p = __DST_METRICS_PTR(old);
116 unsigned long prev, new;
117
118 p = peer->metrics;
119 if (inet_metrics_new(peer))
120 memcpy(p, old_p, sizeof(u32) * RTAX_MAX);
121
122 new = (unsigned long) p;
123 prev = cmpxchg(&dst->_metrics, old, new);
124
125 if (prev != old) {
126 p = __DST_METRICS_PTR(prev);
127 if (prev & DST_METRICS_READ_ONLY)
128 p = NULL;
129 }
130 }
131 return p;
132}
133
David S. Millerf894cbf2012-07-02 21:52:24 -0700134static inline const void *choose_neigh_daddr(struct rt6_info *rt,
135 struct sk_buff *skb,
136 const void *daddr)
David S. Miller39232972012-01-26 15:22:32 -0500137{
138 struct in6_addr *p = &rt->rt6i_gateway;
139
David S. Millera7563f32012-01-26 16:29:16 -0500140 if (!ipv6_addr_any(p))
David S. Miller39232972012-01-26 15:22:32 -0500141 return (const void *) p;
David S. Millerf894cbf2012-07-02 21:52:24 -0700142 else if (skb)
143 return &ipv6_hdr(skb)->daddr;
David S. Miller39232972012-01-26 15:22:32 -0500144 return daddr;
145}
146
David S. Millerf894cbf2012-07-02 21:52:24 -0700147static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst,
148 struct sk_buff *skb,
149 const void *daddr)
David S. Millerd3aaeb32011-07-18 00:40:17 -0700150{
David S. Miller39232972012-01-26 15:22:32 -0500151 struct rt6_info *rt = (struct rt6_info *) dst;
152 struct neighbour *n;
153
David S. Millerf894cbf2012-07-02 21:52:24 -0700154 daddr = choose_neigh_daddr(rt, skb, daddr);
YOSHIFUJI Hideaki / 吉藤英明8e022ee2013-01-17 12:53:09 +0000155 n = __ipv6_neigh_lookup(dst->dev, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500156 if (n)
157 return n;
158 return neigh_create(&nd_tbl, daddr, dst->dev);
159}
160
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -0800161static struct dst_ops ip6_dst_ops_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 .family = AF_INET6,
Harvey Harrison09640e632009-02-01 00:45:17 -0800163 .protocol = cpu_to_be16(ETH_P_IPV6),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 .gc = ip6_dst_gc,
165 .gc_thresh = 1024,
166 .check = ip6_dst_check,
David S. Miller0dbaee32010-12-13 12:52:14 -0800167 .default_advmss = ip6_default_advmss,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000168 .mtu = ip6_mtu,
David S. Miller06582542011-01-27 14:58:42 -0800169 .cow_metrics = ipv6_cow_metrics,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 .destroy = ip6_dst_destroy,
171 .ifdown = ip6_dst_ifdown,
172 .negative_advice = ip6_negative_advice,
173 .link_failure = ip6_link_failure,
174 .update_pmtu = ip6_rt_update_pmtu,
David S. Miller6e157b62012-07-12 00:05:02 -0700175 .redirect = rt6_do_redirect,
Herbert Xu1ac06e02008-05-20 14:32:14 -0700176 .local_out = __ip6_local_out,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700177 .neigh_lookup = ip6_neigh_lookup,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178};
179
Steffen Klassertebb762f2011-11-23 02:12:51 +0000180static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
Roland Dreierec831ea2011-01-31 13:16:00 -0800181{
Steffen Klassert618f9bc2011-11-23 02:13:31 +0000182 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
183
184 return mtu ? : dst->dev->mtu;
Roland Dreierec831ea2011-01-31 13:16:00 -0800185}
186
David S. Miller6700c272012-07-17 03:29:28 -0700187static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
188 struct sk_buff *skb, u32 mtu)
David S. Miller14e50e52007-05-24 18:17:54 -0700189{
190}
191
David S. Miller6700c272012-07-17 03:29:28 -0700192static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
193 struct sk_buff *skb)
David S. Millerb587ee32012-07-12 00:39:24 -0700194{
195}
196
Held Bernhard0972ddb2011-04-24 22:07:32 +0000197static u32 *ip6_rt_blackhole_cow_metrics(struct dst_entry *dst,
198 unsigned long old)
199{
200 return NULL;
201}
202
David S. Miller14e50e52007-05-24 18:17:54 -0700203static struct dst_ops ip6_dst_blackhole_ops = {
204 .family = AF_INET6,
Harvey Harrison09640e632009-02-01 00:45:17 -0800205 .protocol = cpu_to_be16(ETH_P_IPV6),
David S. Miller14e50e52007-05-24 18:17:54 -0700206 .destroy = ip6_dst_destroy,
207 .check = ip6_dst_check,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000208 .mtu = ip6_blackhole_mtu,
Eric Dumazet214f45c2011-02-18 11:39:01 -0800209 .default_advmss = ip6_default_advmss,
David S. Miller14e50e52007-05-24 18:17:54 -0700210 .update_pmtu = ip6_rt_blackhole_update_pmtu,
David S. Millerb587ee32012-07-12 00:39:24 -0700211 .redirect = ip6_rt_blackhole_redirect,
Held Bernhard0972ddb2011-04-24 22:07:32 +0000212 .cow_metrics = ip6_rt_blackhole_cow_metrics,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700213 .neigh_lookup = ip6_neigh_lookup,
David S. Miller14e50e52007-05-24 18:17:54 -0700214};
215
David S. Miller62fa8a82011-01-26 20:51:05 -0800216static const u32 ip6_template_metrics[RTAX_MAX] = {
Li RongQing14edd872012-10-24 14:01:18 +0800217 [RTAX_HOPLIMIT - 1] = 0,
David S. Miller62fa8a82011-01-26 20:51:05 -0800218};
219
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000220static const struct rt6_info ip6_null_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700221 .dst = {
222 .__refcnt = ATOMIC_INIT(1),
223 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000224 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700225 .error = -ENETUNREACH,
Changli Gaod8d1f302010-06-10 23:31:35 -0700226 .input = ip6_pkt_discard,
227 .output = ip6_pkt_discard_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 },
229 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700230 .rt6i_protocol = RTPROT_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 .rt6i_metric = ~(u32) 0,
232 .rt6i_ref = ATOMIC_INIT(1),
233};
234
Thomas Graf101367c2006-08-04 03:39:02 -0700235#ifdef CONFIG_IPV6_MULTIPLE_TABLES
236
David S. Miller6723ab52006-10-18 21:20:57 -0700237static int ip6_pkt_prohibit(struct sk_buff *skb);
238static int ip6_pkt_prohibit_out(struct sk_buff *skb);
David S. Miller6723ab52006-10-18 21:20:57 -0700239
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000240static const struct rt6_info ip6_prohibit_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700241 .dst = {
242 .__refcnt = ATOMIC_INIT(1),
243 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000244 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700245 .error = -EACCES,
Changli Gaod8d1f302010-06-10 23:31:35 -0700246 .input = ip6_pkt_prohibit,
247 .output = ip6_pkt_prohibit_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700248 },
249 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700250 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700251 .rt6i_metric = ~(u32) 0,
252 .rt6i_ref = ATOMIC_INIT(1),
253};
254
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000255static const struct rt6_info ip6_blk_hole_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700256 .dst = {
257 .__refcnt = ATOMIC_INIT(1),
258 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000259 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700260 .error = -EINVAL,
Changli Gaod8d1f302010-06-10 23:31:35 -0700261 .input = dst_discard,
262 .output = dst_discard,
Thomas Graf101367c2006-08-04 03:39:02 -0700263 },
264 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700265 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700266 .rt6i_metric = ~(u32) 0,
267 .rt6i_ref = ATOMIC_INIT(1),
268};
269
270#endif
271
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272/* allocate dst with ip6_dst_ops */
David S. Miller97bab732012-06-09 22:36:36 -0700273static inline struct rt6_info *ip6_dst_alloc(struct net *net,
David S. Miller957c6652011-06-24 15:25:00 -0700274 struct net_device *dev,
David S. Miller8b96d222012-06-11 02:01:56 -0700275 int flags,
276 struct fib6_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277{
David S. Miller97bab732012-06-09 22:36:36 -0700278 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +0000279 0, DST_OBSOLETE_FORCE_CHK, flags);
David S. Millercf911662011-04-28 14:31:47 -0700280
David S. Miller97bab732012-06-09 22:36:36 -0700281 if (rt) {
Steffen Klassert81048912012-07-05 23:37:09 +0000282 struct dst_entry *dst = &rt->dst;
283
284 memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
David S. Miller8b96d222012-06-11 02:01:56 -0700285 rt6_init_peer(rt, table ? &table->tb6_peers : net->ipv6.peers);
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +0000286 rt->rt6i_genid = rt_genid(net);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000287 INIT_LIST_HEAD(&rt->rt6i_siblings);
288 rt->rt6i_nsiblings = 0;
David S. Miller97bab732012-06-09 22:36:36 -0700289 }
David S. Millercf911662011-04-28 14:31:47 -0700290 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291}
292
293static void ip6_dst_destroy(struct dst_entry *dst)
294{
295 struct rt6_info *rt = (struct rt6_info *)dst;
296 struct inet6_dev *idev = rt->rt6i_idev;
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000297 struct dst_entry *from = dst->from;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
Yan, Zheng8e2ec632011-09-05 21:34:30 +0000299 if (!(rt->dst.flags & DST_HOST))
300 dst_destroy_metrics_generic(dst);
301
David S. Miller38308472011-12-03 18:02:47 -0500302 if (idev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 rt->rt6i_idev = NULL;
304 in6_dev_put(idev);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900305 }
Gao feng1716a962012-04-06 00:13:10 +0000306
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000307 dst->from = NULL;
308 dst_release(from);
Gao feng1716a962012-04-06 00:13:10 +0000309
David S. Miller97bab732012-06-09 22:36:36 -0700310 if (rt6_has_peer(rt)) {
311 struct inet_peer *peer = rt6_peer_ptr(rt);
David S. Millerb3419362010-11-30 12:27:11 -0800312 inet_putpeer(peer);
313 }
314}
315
316void rt6_bind_peer(struct rt6_info *rt, int create)
317{
David S. Miller97bab732012-06-09 22:36:36 -0700318 struct inet_peer_base *base;
David S. Millerb3419362010-11-30 12:27:11 -0800319 struct inet_peer *peer;
320
David S. Miller97bab732012-06-09 22:36:36 -0700321 base = inetpeer_base_ptr(rt->_rt6i_peer);
322 if (!base)
323 return;
324
325 peer = inet_getpeer_v6(base, &rt->rt6i_dst.addr, create);
David S. Miller7b34ca22012-06-11 04:13:57 -0700326 if (peer) {
327 if (!rt6_set_peer(rt, peer))
328 inet_putpeer(peer);
David S. Miller7b34ca22012-06-11 04:13:57 -0700329 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330}
331
332static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
333 int how)
334{
335 struct rt6_info *rt = (struct rt6_info *)dst;
336 struct inet6_dev *idev = rt->rt6i_idev;
Denis V. Lunev5a3e55d2007-12-07 00:38:10 -0800337 struct net_device *loopback_dev =
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900338 dev_net(dev)->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
David S. Miller97cac082012-07-02 22:43:47 -0700340 if (dev != loopback_dev) {
341 if (idev && idev->dev == dev) {
342 struct inet6_dev *loopback_idev =
343 in6_dev_get(loopback_dev);
344 if (loopback_idev) {
345 rt->rt6i_idev = loopback_idev;
346 in6_dev_put(idev);
347 }
348 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 }
350}
351
Eric Dumazeta50feda2012-05-18 18:57:34 +0000352static bool rt6_check_expired(const struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353{
Gao feng1716a962012-04-06 00:13:10 +0000354 if (rt->rt6i_flags & RTF_EXPIRES) {
355 if (time_after(jiffies, rt->dst.expires))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000356 return true;
Gao feng1716a962012-04-06 00:13:10 +0000357 } else if (rt->dst.from) {
Li RongQing3fd91fb2012-09-13 19:54:57 +0000358 return rt6_check_expired((struct rt6_info *) rt->dst.from);
Gao feng1716a962012-04-06 00:13:10 +0000359 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000360 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361}
362
Eric Dumazeta50feda2012-05-18 18:57:34 +0000363static bool rt6_need_strict(const struct in6_addr *daddr)
Thomas Grafc71099a2006-08-04 23:20:06 -0700364{
Eric Dumazeta02cec22010-09-22 20:43:57 +0000365 return ipv6_addr_type(daddr) &
366 (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK);
Thomas Grafc71099a2006-08-04 23:20:06 -0700367}
368
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000369/* Multipath route selection:
370 * Hash based function using packet header and flowlabel.
371 * Adapted from fib_info_hashfn()
372 */
373static int rt6_info_hash_nhsfn(unsigned int candidate_count,
374 const struct flowi6 *fl6)
375{
376 unsigned int val = fl6->flowi6_proto;
377
YOSHIFUJI Hideaki / 吉藤英明c08977b2013-01-13 05:02:29 +0000378 val ^= ipv6_addr_hash(&fl6->daddr);
379 val ^= ipv6_addr_hash(&fl6->saddr);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000380
381 /* Work only if this not encapsulated */
382 switch (fl6->flowi6_proto) {
383 case IPPROTO_UDP:
384 case IPPROTO_TCP:
385 case IPPROTO_SCTP:
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000386 val ^= (__force u16)fl6->fl6_sport;
387 val ^= (__force u16)fl6->fl6_dport;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000388 break;
389
390 case IPPROTO_ICMPV6:
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000391 val ^= (__force u16)fl6->fl6_icmp_type;
392 val ^= (__force u16)fl6->fl6_icmp_code;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000393 break;
394 }
395 /* RFC6438 recommands to use flowlabel */
Nicolas Dichtelb3ce5ae2012-10-22 23:35:06 +0000396 val ^= (__force u32)fl6->flowlabel;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000397
398 /* Perhaps, we need to tune, this function? */
399 val = val ^ (val >> 7) ^ (val >> 12);
400 return val % candidate_count;
401}
402
403static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200404 struct flowi6 *fl6, int oif,
405 int strict)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000406{
407 struct rt6_info *sibling, *next_sibling;
408 int route_choosen;
409
410 route_choosen = rt6_info_hash_nhsfn(match->rt6i_nsiblings + 1, fl6);
411 /* Don't change the route, if route_choosen == 0
412 * (siblings does not include ourself)
413 */
414 if (route_choosen)
415 list_for_each_entry_safe(sibling, next_sibling,
416 &match->rt6i_siblings, rt6i_siblings) {
417 route_choosen--;
418 if (route_choosen == 0) {
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200419 if (rt6_score_route(sibling, oif, strict) < 0)
420 break;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000421 match = sibling;
422 break;
423 }
424 }
425 return match;
426}
427
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428/*
Thomas Grafc71099a2006-08-04 23:20:06 -0700429 * Route lookup. Any table->tb6_lock is implied.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 */
431
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800432static inline struct rt6_info *rt6_device_match(struct net *net,
433 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000434 const struct in6_addr *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 int oif,
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700436 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437{
438 struct rt6_info *local = NULL;
439 struct rt6_info *sprt;
440
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900441 if (!oif && ipv6_addr_any(saddr))
442 goto out;
443
Changli Gaod8d1f302010-06-10 23:31:35 -0700444 for (sprt = rt; sprt; sprt = sprt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -0500445 struct net_device *dev = sprt->dst.dev;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900446
447 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 if (dev->ifindex == oif)
449 return sprt;
450 if (dev->flags & IFF_LOOPBACK) {
David S. Miller38308472011-12-03 18:02:47 -0500451 if (!sprt->rt6i_idev ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 sprt->rt6i_idev->dev->ifindex != oif) {
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700453 if (flags & RT6_LOOKUP_F_IFACE && oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 continue;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900455 if (local && (!oif ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 local->rt6i_idev->dev->ifindex == oif))
457 continue;
458 }
459 local = sprt;
460 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900461 } else {
462 if (ipv6_chk_addr(net, saddr, dev,
463 flags & RT6_LOOKUP_F_IFACE))
464 return sprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900466 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900468 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 if (local)
470 return local;
471
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700472 if (flags & RT6_LOOKUP_F_IFACE)
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800473 return net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900475out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 return rt;
477}
478
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800479#ifdef CONFIG_IPV6_ROUTER_PREF
480static void rt6_probe(struct rt6_info *rt)
481{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000482 struct neighbour *neigh;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800483 /*
484 * Okay, this does not seem to be appropriate
485 * for now, however, we need to check if it
486 * is really so; aka Router Reachability Probing.
487 *
488 * Router Reachability Probe MUST be rate-limited
489 * to no more than one per minute.
490 */
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000491 if (!rt || !(rt->rt6i_flags & RTF_GATEWAY))
Amerigo Wangfdd66812012-09-10 02:48:44 +0000492 return;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000493 rcu_read_lock_bh();
494 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
495 if (neigh) {
496 write_lock(&neigh->lock);
497 if (neigh->nud_state & NUD_VALID)
498 goto out;
YOSHIFUJI Hideaki / 吉藤英明7ff74a52013-01-17 12:53:02 +0000499 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000500
501 if (!neigh ||
YOSHIFUJI Hideaki52e163562006-03-20 17:05:47 -0800502 time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) {
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800503 struct in6_addr mcaddr;
504 struct in6_addr *target;
505
YOSHIFUJI Hideaki / 吉藤英明b820bb62013-01-21 09:58:50 +0000506 if (neigh) {
507 neigh->updated = jiffies;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000508 write_unlock(&neigh->lock);
YOSHIFUJI Hideaki / 吉藤英明b820bb62013-01-21 09:58:50 +0000509 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000510
511 target = (struct in6_addr *)&rt->rt6i_gateway;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800512 addrconf_addr_solict_mult(target, &mcaddr);
David S. Millerd1918542011-12-28 20:19:20 -0500513 ndisc_send_ns(rt->dst.dev, NULL, target, &mcaddr, NULL);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000514 } else {
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000515out:
516 write_unlock(&neigh->lock);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000517 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000518 rcu_read_unlock_bh();
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800519}
520#else
521static inline void rt6_probe(struct rt6_info *rt)
522{
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800523}
524#endif
525
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526/*
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800527 * Default Router Selection (RFC 2461 6.3.6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 */
Dave Jonesb6f99a22007-03-22 12:27:49 -0700529static inline int rt6_check_dev(struct rt6_info *rt, int oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530{
David S. Millerd1918542011-12-28 20:19:20 -0500531 struct net_device *dev = rt->dst.dev;
David S. Miller161980f2007-04-06 11:42:27 -0700532 if (!oif || dev->ifindex == oif)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800533 return 2;
David S. Miller161980f2007-04-06 11:42:27 -0700534 if ((dev->flags & IFF_LOOPBACK) &&
535 rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
536 return 1;
537 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538}
539
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200540static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000542 struct neighbour *neigh;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200543 enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000544
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700545 if (rt->rt6i_flags & RTF_NONEXTHOP ||
546 !(rt->rt6i_flags & RTF_GATEWAY))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200547 return RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000548
549 rcu_read_lock_bh();
550 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
551 if (neigh) {
552 read_lock(&neigh->lock);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800553 if (neigh->nud_state & NUD_VALID)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200554 ret = RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800555#ifdef CONFIG_IPV6_ROUTER_PREF
Paul Marksa5a81f02012-12-03 10:26:54 +0000556 else if (!(neigh->nud_state & NUD_FAILED))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200557 ret = RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800558#endif
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000559 read_unlock(&neigh->lock);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200560 } else {
561 ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
562 RT6_NUD_SUCCEED : RT6_NUD_FAIL_SOFT;
Paul Marksa5a81f02012-12-03 10:26:54 +0000563 }
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000564 rcu_read_unlock_bh();
565
Paul Marksa5a81f02012-12-03 10:26:54 +0000566 return ret;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800567}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800569static int rt6_score_route(struct rt6_info *rt, int oif,
570 int strict)
571{
Paul Marksa5a81f02012-12-03 10:26:54 +0000572 int m;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900573
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700574 m = rt6_check_dev(rt, oif);
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700575 if (!m && (strict & RT6_LOOKUP_F_IFACE))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200576 return RT6_NUD_FAIL_HARD;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800577#ifdef CONFIG_IPV6_ROUTER_PREF
578 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
579#endif
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200580 if (strict & RT6_LOOKUP_F_REACHABLE) {
581 int n = rt6_check_neigh(rt);
582 if (n < 0)
583 return n;
584 }
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800585 return m;
586}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
David S. Millerf11e6652007-03-24 20:36:25 -0700588static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200589 int *mpri, struct rt6_info *match,
590 bool *do_rr)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800591{
David S. Millerf11e6652007-03-24 20:36:25 -0700592 int m;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200593 bool match_do_rr = false;
David S. Millerf11e6652007-03-24 20:36:25 -0700594
595 if (rt6_check_expired(rt))
596 goto out;
597
598 m = rt6_score_route(rt, oif, strict);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200599 if (m == RT6_NUD_FAIL_SOFT && !IS_ENABLED(CONFIG_IPV6_ROUTER_PREF)) {
600 match_do_rr = true;
601 m = 0; /* lowest valid score */
602 } else if (m < 0) {
David S. Millerf11e6652007-03-24 20:36:25 -0700603 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700604 }
605
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200606 if (strict & RT6_LOOKUP_F_REACHABLE)
607 rt6_probe(rt);
608
609 if (m > *mpri) {
610 *do_rr = match_do_rr;
611 *mpri = m;
612 match = rt;
613 }
David S. Millerf11e6652007-03-24 20:36:25 -0700614out:
615 return match;
616}
617
618static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
619 struct rt6_info *rr_head,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200620 u32 metric, int oif, int strict,
621 bool *do_rr)
David S. Millerf11e6652007-03-24 20:36:25 -0700622{
623 struct rt6_info *rt, *match;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800624 int mpri = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
David S. Millerf11e6652007-03-24 20:36:25 -0700626 match = NULL;
627 for (rt = rr_head; rt && rt->rt6i_metric == metric;
Changli Gaod8d1f302010-06-10 23:31:35 -0700628 rt = rt->dst.rt6_next)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200629 match = find_match(rt, oif, strict, &mpri, match, do_rr);
David S. Millerf11e6652007-03-24 20:36:25 -0700630 for (rt = fn->leaf; rt && rt != rr_head && rt->rt6i_metric == metric;
Changli Gaod8d1f302010-06-10 23:31:35 -0700631 rt = rt->dst.rt6_next)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200632 match = find_match(rt, oif, strict, &mpri, match, do_rr);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800633
David S. Millerf11e6652007-03-24 20:36:25 -0700634 return match;
635}
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800636
David S. Millerf11e6652007-03-24 20:36:25 -0700637static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
638{
639 struct rt6_info *match, *rt0;
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800640 struct net *net;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200641 bool do_rr = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
David S. Millerf11e6652007-03-24 20:36:25 -0700643 rt0 = fn->rr_ptr;
644 if (!rt0)
645 fn->rr_ptr = rt0 = fn->leaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200647 match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict,
648 &do_rr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200650 if (do_rr) {
Changli Gaod8d1f302010-06-10 23:31:35 -0700651 struct rt6_info *next = rt0->dst.rt6_next;
David S. Millerf11e6652007-03-24 20:36:25 -0700652
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800653 /* no entries matched; do round-robin */
David S. Millerf11e6652007-03-24 20:36:25 -0700654 if (!next || next->rt6i_metric != rt0->rt6i_metric)
655 next = fn->leaf;
656
657 if (next != rt0)
658 fn->rr_ptr = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 }
660
David S. Millerd1918542011-12-28 20:19:20 -0500661 net = dev_net(rt0->dst.dev);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000662 return match ? match : net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663}
664
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800665#ifdef CONFIG_IPV6_ROUTE_INFO
666int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000667 const struct in6_addr *gwaddr)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800668{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900669 struct net *net = dev_net(dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800670 struct route_info *rinfo = (struct route_info *) opt;
671 struct in6_addr prefix_buf, *prefix;
672 unsigned int pref;
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900673 unsigned long lifetime;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800674 struct rt6_info *rt;
675
676 if (len < sizeof(struct route_info)) {
677 return -EINVAL;
678 }
679
680 /* Sanity check for prefix_len and length */
681 if (rinfo->length > 3) {
682 return -EINVAL;
683 } else if (rinfo->prefix_len > 128) {
684 return -EINVAL;
685 } else if (rinfo->prefix_len > 64) {
686 if (rinfo->length < 2) {
687 return -EINVAL;
688 }
689 } else if (rinfo->prefix_len > 0) {
690 if (rinfo->length < 1) {
691 return -EINVAL;
692 }
693 }
694
695 pref = rinfo->route_pref;
696 if (pref == ICMPV6_ROUTER_PREF_INVALID)
Jens Rosenboom3933fc92009-09-10 06:25:11 +0000697 return -EINVAL;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800698
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900699 lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800700
701 if (rinfo->length == 3)
702 prefix = (struct in6_addr *)rinfo->prefix;
703 else {
704 /* this function is safe */
705 ipv6_addr_prefix(&prefix_buf,
706 (struct in6_addr *)rinfo->prefix,
707 rinfo->prefix_len);
708 prefix = &prefix_buf;
709 }
710
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800711 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, gwaddr,
712 dev->ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800713
714 if (rt && !lifetime) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -0700715 ip6_del_rt(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800716 rt = NULL;
717 }
718
719 if (!rt && lifetime)
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800720 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800721 pref);
722 else if (rt)
723 rt->rt6i_flags = RTF_ROUTEINFO |
724 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
725
726 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +0000727 if (!addrconf_finite_timeout(lifetime))
728 rt6_clean_expires(rt);
729 else
730 rt6_set_expires(rt, jiffies + HZ * lifetime);
731
Amerigo Wang94e187c2012-10-29 00:13:19 +0000732 ip6_rt_put(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800733 }
734 return 0;
735}
736#endif
737
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800738#define BACKTRACK(__net, saddr) \
YOSHIFUJI Hideaki982f56f2006-08-23 17:22:39 -0700739do { \
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800740 if (rt == __net->ipv6.ip6_null_entry) { \
YOSHIFUJI Hideaki982f56f2006-08-23 17:22:39 -0700741 struct fib6_node *pn; \
Ville Nuorvalae0eda7b2006-10-16 22:11:11 -0700742 while (1) { \
YOSHIFUJI Hideaki982f56f2006-08-23 17:22:39 -0700743 if (fn->fn_flags & RTN_TL_ROOT) \
744 goto out; \
745 pn = fn->parent; \
746 if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn) \
Kim Nordlund8bce65b2006-12-13 16:38:29 -0800747 fn = fib6_lookup(FIB6_SUBTREE(pn), NULL, saddr); \
YOSHIFUJI Hideaki982f56f2006-08-23 17:22:39 -0700748 else \
749 fn = pn; \
750 if (fn->fn_flags & RTN_RTINFO) \
751 goto restart; \
Thomas Grafc71099a2006-08-04 23:20:06 -0700752 } \
Thomas Grafc71099a2006-08-04 23:20:06 -0700753 } \
David S. Miller38308472011-12-03 18:02:47 -0500754} while (0)
Thomas Grafc71099a2006-08-04 23:20:06 -0700755
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800756static struct rt6_info *ip6_pol_route_lookup(struct net *net,
757 struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500758 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759{
760 struct fib6_node *fn;
761 struct rt6_info *rt;
762
Thomas Grafc71099a2006-08-04 23:20:06 -0700763 read_lock_bh(&table->tb6_lock);
David S. Miller4c9483b2011-03-12 16:22:43 -0500764 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -0700765restart:
766 rt = fn->leaf;
David S. Miller4c9483b2011-03-12 16:22:43 -0500767 rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000768 if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0)
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200769 rt = rt6_multipath_select(rt, fl6, fl6->flowi6_oif, flags);
David S. Miller4c9483b2011-03-12 16:22:43 -0500770 BACKTRACK(net, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -0700771out:
Changli Gaod8d1f302010-06-10 23:31:35 -0700772 dst_use(&rt->dst, jiffies);
Thomas Grafc71099a2006-08-04 23:20:06 -0700773 read_unlock_bh(&table->tb6_lock);
Thomas Grafc71099a2006-08-04 23:20:06 -0700774 return rt;
775
776}
777
Florian Westphalea6e5742011-09-05 16:05:44 +0200778struct dst_entry * ip6_route_lookup(struct net *net, struct flowi6 *fl6,
779 int flags)
780{
781 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup);
782}
783EXPORT_SYMBOL_GPL(ip6_route_lookup);
784
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900785struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
786 const struct in6_addr *saddr, int oif, int strict)
Thomas Grafc71099a2006-08-04 23:20:06 -0700787{
David S. Miller4c9483b2011-03-12 16:22:43 -0500788 struct flowi6 fl6 = {
789 .flowi6_oif = oif,
790 .daddr = *daddr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700791 };
792 struct dst_entry *dst;
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700793 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
Thomas Grafc71099a2006-08-04 23:20:06 -0700794
Thomas Grafadaa70b2006-10-13 15:01:03 -0700795 if (saddr) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500796 memcpy(&fl6.saddr, saddr, sizeof(*saddr));
Thomas Grafadaa70b2006-10-13 15:01:03 -0700797 flags |= RT6_LOOKUP_F_HAS_SADDR;
798 }
799
David S. Miller4c9483b2011-03-12 16:22:43 -0500800 dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup);
Thomas Grafc71099a2006-08-04 23:20:06 -0700801 if (dst->error == 0)
802 return (struct rt6_info *) dst;
803
804 dst_release(dst);
805
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 return NULL;
807}
808
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900809EXPORT_SYMBOL(rt6_lookup);
810
Thomas Grafc71099a2006-08-04 23:20:06 -0700811/* ip6_ins_rt is called with FREE table->tb6_lock.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 It takes new route entry, the addition fails by any reason the
813 route is freed. In any case, if caller does not hold it, it may
814 be destroyed.
815 */
816
Thomas Graf86872cb2006-08-22 00:01:08 -0700817static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818{
819 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -0700820 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821
Thomas Grafc71099a2006-08-04 23:20:06 -0700822 table = rt->rt6i_table;
823 write_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -0700824 err = fib6_add(&table->tb6_root, rt, info);
Thomas Grafc71099a2006-08-04 23:20:06 -0700825 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826
827 return err;
828}
829
Thomas Graf40e22e82006-08-22 00:00:45 -0700830int ip6_ins_rt(struct rt6_info *rt)
831{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -0800832 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -0500833 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -0800834 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -0800835 return __ip6_ins_rt(rt, &info);
Thomas Graf40e22e82006-08-22 00:00:45 -0700836}
837
Gao feng1716a962012-04-06 00:13:10 +0000838static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort,
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000839 const struct in6_addr *daddr,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000840 const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 struct rt6_info *rt;
843
844 /*
845 * Clone the route.
846 */
847
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000848 rt = ip6_rt_copy(ort, daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849
850 if (rt) {
David S. Miller38308472011-12-03 18:02:47 -0500851 if (!(rt->rt6i_flags & RTF_GATEWAY)) {
David S. Millerbb3c3682011-12-13 17:35:06 -0500852 if (ort->rt6i_dst.plen != 128 &&
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000853 ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +0900854 rt->rt6i_flags |= RTF_ANYCAST;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000855 rt->rt6i_gateway = *daddr;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +0900856 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 rt->rt6i_flags |= RTF_CACHE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859
860#ifdef CONFIG_IPV6_SUBTREES
861 if (rt->rt6i_src.plen && saddr) {
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000862 rt->rt6i_src.addr = *saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 rt->rt6i_src.plen = 128;
864 }
865#endif
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800866 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800868 return rt;
869}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000871static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort,
872 const struct in6_addr *daddr)
YOSHIFUJI Hideaki299d9932006-03-20 16:58:32 -0800873{
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000874 struct rt6_info *rt = ip6_rt_copy(ort, daddr);
875
YOSHIFUJI Hideaki / 吉藤英明887c95c2013-01-17 12:54:05 +0000876 if (rt)
YOSHIFUJI Hideaki299d9932006-03-20 16:58:32 -0800877 rt->rt6i_flags |= RTF_CACHE;
YOSHIFUJI Hideaki299d9932006-03-20 16:58:32 -0800878 return rt;
879}
880
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800881static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif,
David S. Miller4c9483b2011-03-12 16:22:43 -0500882 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883{
884 struct fib6_node *fn;
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800885 struct rt6_info *rt, *nrt;
Thomas Grafc71099a2006-08-04 23:20:06 -0700886 int strict = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 int attempts = 3;
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800888 int err;
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700889 int reachable = net->ipv6.devconf_all->forwarding ? 0 : RT6_LOOKUP_F_REACHABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700891 strict |= flags & RT6_LOOKUP_F_IFACE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892
893relookup:
Thomas Grafc71099a2006-08-04 23:20:06 -0700894 read_lock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895
YOSHIFUJI Hideaki8238dd02006-03-20 17:04:35 -0800896restart_2:
David S. Miller4c9483b2011-03-12 16:22:43 -0500897 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898
899restart:
Pavel Emelyanov4acad722007-10-15 13:02:51 -0700900 rt = rt6_select(fn, oif, strict | reachable);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200901 if (rt->rt6i_nsiblings)
902 rt = rt6_multipath_select(rt, fl6, oif, strict | reachable);
David S. Miller4c9483b2011-03-12 16:22:43 -0500903 BACKTRACK(net, &fl6->saddr);
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800904 if (rt == net->ipv6.ip6_null_entry ||
YOSHIFUJI Hideaki8238dd02006-03-20 17:04:35 -0800905 rt->rt6i_flags & RTF_CACHE)
YOSHIFUJI Hideaki1ddef0442006-03-20 17:01:24 -0800906 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
Changli Gaod8d1f302010-06-10 23:31:35 -0700908 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -0700909 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -0800910
YOSHIFUJI Hideaki / 吉藤英明c440f162013-01-17 12:53:32 +0000911 if (!(rt->rt6i_flags & (RTF_NONEXTHOP | RTF_GATEWAY)))
David S. Miller4c9483b2011-03-12 16:22:43 -0500912 nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr);
David S. Miller7343ff32011-03-09 19:55:25 -0800913 else if (!(rt->dst.flags & DST_HOST))
David S. Miller4c9483b2011-03-12 16:22:43 -0500914 nrt = rt6_alloc_clone(rt, &fl6->daddr);
David S. Miller7343ff32011-03-09 19:55:25 -0800915 else
916 goto out2;
YOSHIFUJI Hideakie40cf352006-03-20 16:59:27 -0800917
Amerigo Wang94e187c2012-10-29 00:13:19 +0000918 ip6_rt_put(rt);
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800919 rt = nrt ? : net->ipv6.ip6_null_entry;
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800920
Changli Gaod8d1f302010-06-10 23:31:35 -0700921 dst_hold(&rt->dst);
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800922 if (nrt) {
Thomas Graf40e22e82006-08-22 00:00:45 -0700923 err = ip6_ins_rt(nrt);
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800924 if (!err)
925 goto out2;
926 }
927
928 if (--attempts <= 0)
929 goto out2;
930
931 /*
Thomas Grafc71099a2006-08-04 23:20:06 -0700932 * Race condition! In the gap, when table->tb6_lock was
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800933 * released someone could insert this route. Relookup.
934 */
Amerigo Wang94e187c2012-10-29 00:13:19 +0000935 ip6_rt_put(rt);
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800936 goto relookup;
937
938out:
YOSHIFUJI Hideaki8238dd02006-03-20 17:04:35 -0800939 if (reachable) {
940 reachable = 0;
941 goto restart_2;
942 }
Changli Gaod8d1f302010-06-10 23:31:35 -0700943 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -0700944 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945out2:
Changli Gaod8d1f302010-06-10 23:31:35 -0700946 rt->dst.lastuse = jiffies;
947 rt->dst.__use++;
Thomas Grafc71099a2006-08-04 23:20:06 -0700948
949 return rt;
950}
951
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800952static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500953 struct flowi6 *fl6, int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -0700954{
David S. Miller4c9483b2011-03-12 16:22:43 -0500955 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -0700956}
957
Shmulik Ladkani72331bc2012-04-01 04:03:45 +0000958static struct dst_entry *ip6_route_input_lookup(struct net *net,
959 struct net_device *dev,
960 struct flowi6 *fl6, int flags)
961{
962 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
963 flags |= RT6_LOOKUP_F_IFACE;
964
965 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_input);
966}
967
Thomas Grafc71099a2006-08-04 23:20:06 -0700968void ip6_route_input(struct sk_buff *skb)
969{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000970 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900971 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -0700972 int flags = RT6_LOOKUP_F_HAS_SADDR;
David S. Miller4c9483b2011-03-12 16:22:43 -0500973 struct flowi6 fl6 = {
974 .flowi6_iif = skb->dev->ifindex,
975 .daddr = iph->daddr,
976 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +0000977 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -0500978 .flowi6_mark = skb->mark,
979 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700980 };
Thomas Grafadaa70b2006-10-13 15:01:03 -0700981
Shmulik Ladkani72331bc2012-04-01 04:03:45 +0000982 skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -0700983}
984
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800985static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500986 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -0700987{
David S. Miller4c9483b2011-03-12 16:22:43 -0500988 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -0700989}
990
Florian Westphal9c7a4f9c2011-03-22 19:17:36 -0700991struct dst_entry * ip6_route_output(struct net *net, const struct sock *sk,
David S. Miller4c9483b2011-03-12 16:22:43 -0500992 struct flowi6 *fl6)
Thomas Grafc71099a2006-08-04 23:20:06 -0700993{
994 int flags = 0;
995
Pavel Emelyanov1fb94892012-08-08 21:53:36 +0000996 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +0000997
David S. Miller4c9483b2011-03-12 16:22:43 -0500998 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700999 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -07001000
David S. Miller4c9483b2011-03-12 16:22:43 -05001001 if (!ipv6_addr_any(&fl6->saddr))
Thomas Grafadaa70b2006-10-13 15:01:03 -07001002 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +00001003 else if (sk)
1004 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001005
David S. Miller4c9483b2011-03-12 16:22:43 -05001006 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007}
1008
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +09001009EXPORT_SYMBOL(ip6_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010
David S. Miller2774c132011-03-01 14:59:04 -08001011struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -07001012{
David S. Miller5c1e6aa2011-04-28 14:13:38 -07001013 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
David S. Miller14e50e52007-05-24 18:17:54 -07001014 struct dst_entry *new = NULL;
1015
David S. Millerf5b0a872012-07-19 12:31:33 -07001016 rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, DST_OBSOLETE_NONE, 0);
David S. Miller14e50e52007-05-24 18:17:54 -07001017 if (rt) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001018 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -07001019
Steffen Klassert81048912012-07-05 23:37:09 +00001020 memset(new + 1, 0, sizeof(*rt) - sizeof(*new));
1021 rt6_init_peer(rt, net->ipv6.peers);
1022
David S. Miller14e50e52007-05-24 18:17:54 -07001023 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08001024 new->input = dst_discard;
1025 new->output = dst_discard;
David S. Miller14e50e52007-05-24 18:17:54 -07001026
Eric Dumazet21efcfa2011-07-19 20:18:36 +00001027 if (dst_metrics_read_only(&ort->dst))
1028 new->_metrics = ort->dst._metrics;
1029 else
1030 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07001031 rt->rt6i_idev = ort->rt6i_idev;
1032 if (rt->rt6i_idev)
1033 in6_dev_hold(rt->rt6i_idev);
David S. Miller14e50e52007-05-24 18:17:54 -07001034
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001035 rt->rt6i_gateway = ort->rt6i_gateway;
Gao feng1716a962012-04-06 00:13:10 +00001036 rt->rt6i_flags = ort->rt6i_flags;
David S. Miller14e50e52007-05-24 18:17:54 -07001037 rt->rt6i_metric = 0;
1038
1039 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
1040#ifdef CONFIG_IPV6_SUBTREES
1041 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1042#endif
1043
1044 dst_free(new);
1045 }
1046
David S. Miller69ead7a2011-03-01 14:45:33 -08001047 dst_release(dst_orig);
1048 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07001049}
David S. Miller14e50e52007-05-24 18:17:54 -07001050
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051/*
1052 * Destination cache support functions
1053 */
1054
1055static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
1056{
1057 struct rt6_info *rt;
1058
1059 rt = (struct rt6_info *) dst;
1060
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00001061 /* All IPV6 dsts are created with ->obsolete set to the value
1062 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
1063 * into this function always.
1064 */
1065 if (rt->rt6i_genid != rt_genid(dev_net(rt->dst.dev)))
1066 return NULL;
1067
Li RongQinga4477c42012-11-07 21:56:33 +00001068 if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 return dst;
Li RongQinga4477c42012-11-07 21:56:33 +00001070
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 return NULL;
1072}
1073
1074static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
1075{
1076 struct rt6_info *rt = (struct rt6_info *) dst;
1077
1078 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001079 if (rt->rt6i_flags & RTF_CACHE) {
1080 if (rt6_check_expired(rt)) {
1081 ip6_del_rt(rt);
1082 dst = NULL;
1083 }
1084 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001086 dst = NULL;
1087 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001089 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090}
1091
1092static void ip6_link_failure(struct sk_buff *skb)
1093{
1094 struct rt6_info *rt;
1095
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00001096 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097
Eric Dumazetadf30902009-06-02 05:19:30 +00001098 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 if (rt) {
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001100 if (rt->rt6i_flags & RTF_CACHE) {
1101 dst_hold(&rt->dst);
1102 if (ip6_del_rt(rt))
1103 dst_free(&rt->dst);
1104 } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 rt->rt6i_node->fn_sernum = -1;
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001106 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 }
1108}
1109
David S. Miller6700c272012-07-17 03:29:28 -07001110static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
1111 struct sk_buff *skb, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112{
1113 struct rt6_info *rt6 = (struct rt6_info*)dst;
1114
David S. Miller81aded22012-06-15 14:54:11 -07001115 dst_confirm(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 if (mtu < dst_mtu(dst) && rt6->rt6i_dst.plen == 128) {
David S. Miller81aded22012-06-15 14:54:11 -07001117 struct net *net = dev_net(dst->dev);
1118
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 rt6->rt6i_flags |= RTF_MODIFIED;
1120 if (mtu < IPV6_MIN_MTU) {
David S. Millerdefb3512010-12-08 21:16:57 -08001121 u32 features = dst_metric(dst, RTAX_FEATURES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 mtu = IPV6_MIN_MTU;
David S. Millerdefb3512010-12-08 21:16:57 -08001123 features |= RTAX_FEATURE_ALLFRAG;
1124 dst_metric_set(dst, RTAX_FEATURES, features);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 }
David S. Millerdefb3512010-12-08 21:16:57 -08001126 dst_metric_set(dst, RTAX_MTU, mtu);
David S. Miller81aded22012-06-15 14:54:11 -07001127 rt6_update_expires(rt6, net->ipv6.sysctl.ip6_rt_mtu_expires);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 }
1129}
1130
David S. Miller42ae66c2012-06-15 20:01:57 -07001131void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
1132 int oif, u32 mark)
David S. Miller81aded22012-06-15 14:54:11 -07001133{
1134 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1135 struct dst_entry *dst;
1136 struct flowi6 fl6;
1137
1138 memset(&fl6, 0, sizeof(fl6));
1139 fl6.flowi6_oif = oif;
1140 fl6.flowi6_mark = mark;
David S. Miller3e129392012-07-10 04:01:57 -07001141 fl6.flowi6_flags = 0;
David S. Miller81aded22012-06-15 14:54:11 -07001142 fl6.daddr = iph->daddr;
1143 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001144 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller81aded22012-06-15 14:54:11 -07001145
1146 dst = ip6_route_output(net, NULL, &fl6);
1147 if (!dst->error)
David S. Miller6700c272012-07-17 03:29:28 -07001148 ip6_rt_update_pmtu(dst, NULL, skb, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07001149 dst_release(dst);
1150}
1151EXPORT_SYMBOL_GPL(ip6_update_pmtu);
1152
1153void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
1154{
1155 ip6_update_pmtu(skb, sock_net(sk), mtu,
1156 sk->sk_bound_dev_if, sk->sk_mark);
1157}
1158EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
1159
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001160void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark)
1161{
1162 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1163 struct dst_entry *dst;
1164 struct flowi6 fl6;
1165
1166 memset(&fl6, 0, sizeof(fl6));
1167 fl6.flowi6_oif = oif;
1168 fl6.flowi6_mark = mark;
1169 fl6.flowi6_flags = 0;
1170 fl6.daddr = iph->daddr;
1171 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001172 fl6.flowlabel = ip6_flowinfo(iph);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001173
1174 dst = ip6_route_output(net, NULL, &fl6);
1175 if (!dst->error)
David S. Miller6700c272012-07-17 03:29:28 -07001176 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001177 dst_release(dst);
1178}
1179EXPORT_SYMBOL_GPL(ip6_redirect);
1180
Duan Jiongc92a59e2013-08-22 12:07:35 +08001181void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
1182 u32 mark)
1183{
1184 const struct ipv6hdr *iph = ipv6_hdr(skb);
1185 const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
1186 struct dst_entry *dst;
1187 struct flowi6 fl6;
1188
1189 memset(&fl6, 0, sizeof(fl6));
1190 fl6.flowi6_oif = oif;
1191 fl6.flowi6_mark = mark;
1192 fl6.flowi6_flags = 0;
1193 fl6.daddr = msg->dest;
1194 fl6.saddr = iph->daddr;
1195
1196 dst = ip6_route_output(net, NULL, &fl6);
1197 if (!dst->error)
1198 rt6_do_redirect(dst, NULL, skb);
1199 dst_release(dst);
1200}
1201
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001202void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
1203{
1204 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark);
1205}
1206EXPORT_SYMBOL_GPL(ip6_sk_redirect);
1207
David S. Miller0dbaee32010-12-13 12:52:14 -08001208static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209{
David S. Miller0dbaee32010-12-13 12:52:14 -08001210 struct net_device *dev = dst->dev;
1211 unsigned int mtu = dst_mtu(dst);
1212 struct net *net = dev_net(dev);
1213
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
1215
Daniel Lezcano55786892008-03-04 13:47:47 -08001216 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
1217 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
1219 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001220 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
1221 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
1222 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 * rely only on pmtu discovery"
1224 */
1225 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
1226 mtu = IPV6_MAXPLEN;
1227 return mtu;
1228}
1229
Steffen Klassertebb762f2011-11-23 02:12:51 +00001230static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08001231{
David S. Millerd33e4552010-12-14 13:01:14 -08001232 struct inet6_dev *idev;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001233 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
1234
1235 if (mtu)
1236 return mtu;
1237
1238 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08001239
1240 rcu_read_lock();
1241 idev = __in6_dev_get(dst->dev);
1242 if (idev)
1243 mtu = idev->cnf.mtu6;
1244 rcu_read_unlock();
1245
1246 return mtu;
1247}
1248
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001249static struct dst_entry *icmp6_dst_gc_list;
1250static DEFINE_SPINLOCK(icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001251
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001252struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05001253 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254{
David S. Miller87a11572011-12-06 17:04:13 -05001255 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 struct rt6_info *rt;
1257 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001258 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259
David S. Miller38308472011-12-03 18:02:47 -05001260 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00001261 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262
David S. Miller8b96d222012-06-11 02:01:56 -07001263 rt = ip6_dst_alloc(net, dev, 0, NULL);
David S. Miller38308472011-12-03 18:02:47 -05001264 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05001266 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 goto out;
1268 }
1269
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001270 rt->dst.flags |= DST_HOST;
1271 rt->dst.output = ip6_output;
Changli Gaod8d1f302010-06-10 23:31:35 -07001272 atomic_set(&rt->dst.__refcnt, 1);
David S. Miller87a11572011-12-06 17:04:13 -05001273 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001274 rt->rt6i_dst.plen = 128;
1275 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08001276 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001278 spin_lock_bh(&icmp6_dst_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001279 rt->dst.next = icmp6_dst_gc_list;
1280 icmp6_dst_gc_list = &rt->dst;
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001281 spin_unlock_bh(&icmp6_dst_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282
Daniel Lezcano55786892008-03-04 13:47:47 -08001283 fib6_force_start_gc(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284
David S. Miller87a11572011-12-06 17:04:13 -05001285 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
1286
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287out:
David S. Miller87a11572011-12-06 17:04:13 -05001288 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289}
1290
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001291int icmp6_dst_gc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292{
Hagen Paul Pfeifere9476e952011-02-25 05:45:19 +00001293 struct dst_entry *dst, **pprev;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001294 int more = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001296 spin_lock_bh(&icmp6_dst_lock);
1297 pprev = &icmp6_dst_gc_list;
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001298
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 while ((dst = *pprev) != NULL) {
1300 if (!atomic_read(&dst->__refcnt)) {
1301 *pprev = dst->next;
1302 dst_free(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 } else {
1304 pprev = &dst->next;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001305 ++more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 }
1307 }
1308
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001309 spin_unlock_bh(&icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001310
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001311 return more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312}
1313
David S. Miller1e493d12008-09-10 17:27:15 -07001314static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg),
1315 void *arg)
1316{
1317 struct dst_entry *dst, **pprev;
1318
1319 spin_lock_bh(&icmp6_dst_lock);
1320 pprev = &icmp6_dst_gc_list;
1321 while ((dst = *pprev) != NULL) {
1322 struct rt6_info *rt = (struct rt6_info *) dst;
1323 if (func(rt, arg)) {
1324 *pprev = dst->next;
1325 dst_free(dst);
1326 } else {
1327 pprev = &dst->next;
1328 }
1329 }
1330 spin_unlock_bh(&icmp6_dst_lock);
1331}
1332
Daniel Lezcano569d3642008-01-18 03:56:57 -08001333static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334{
Alexey Dobriyan86393e52009-08-29 01:34:49 +00001335 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08001336 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
1337 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
1338 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
1339 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
1340 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001341 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342
Eric Dumazetfc66f952010-10-08 06:37:34 +00001343 entries = dst_entries_get_fast(ops);
Michal Kubeček49a18d82013-08-01 10:04:24 +02001344 if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00001345 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 goto out;
1347
Benjamin Thery6891a342008-03-04 13:49:47 -08001348 net->ipv6.ip6_rt_gc_expire++;
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02001349 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, entries > rt_max_size);
Eric Dumazetfc66f952010-10-08 06:37:34 +00001350 entries = dst_entries_get_slow(ops);
1351 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08001352 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08001354 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001355 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356}
1357
YOSHIFUJI Hideaki6b75d092008-03-10 06:00:30 -04001358int ip6_dst_hoplimit(struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359{
David S. Miller5170ae82010-12-12 21:35:57 -08001360 int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT);
David S. Millera02e4b72010-12-12 21:39:02 -08001361 if (hoplimit == 0) {
YOSHIFUJI Hideaki6b75d092008-03-10 06:00:30 -04001362 struct net_device *dev = dst->dev;
Eric Dumazetc68f24c2010-06-14 04:46:20 +00001363 struct inet6_dev *idev;
1364
1365 rcu_read_lock();
1366 idev = __in6_dev_get(dev);
1367 if (idev)
YOSHIFUJI Hideaki6b75d092008-03-10 06:00:30 -04001368 hoplimit = idev->cnf.hop_limit;
Eric Dumazetc68f24c2010-06-14 04:46:20 +00001369 else
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -07001370 hoplimit = dev_net(dev)->ipv6.devconf_all->hop_limit;
Eric Dumazetc68f24c2010-06-14 04:46:20 +00001371 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 }
1373 return hoplimit;
1374}
David S. Millerabbf46a2010-12-12 21:14:46 -08001375EXPORT_SYMBOL(ip6_dst_hoplimit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376
1377/*
1378 *
1379 */
1380
Thomas Graf86872cb2006-08-22 00:01:08 -07001381int ip6_route_add(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382{
1383 int err;
Daniel Lezcano55786892008-03-04 13:47:47 -08001384 struct net *net = cfg->fc_nlinfo.nl_net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 struct rt6_info *rt = NULL;
1386 struct net_device *dev = NULL;
1387 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001388 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 int addr_type;
1390
Thomas Graf86872cb2006-08-22 00:01:08 -07001391 if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 return -EINVAL;
1393#ifndef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001394 if (cfg->fc_src_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 return -EINVAL;
1396#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07001397 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08001399 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 if (!dev)
1401 goto out;
1402 idev = in6_dev_get(dev);
1403 if (!idev)
1404 goto out;
1405 }
1406
Thomas Graf86872cb2006-08-22 00:01:08 -07001407 if (cfg->fc_metric == 0)
1408 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409
Matti Vaittinend71314b2011-11-14 00:14:49 +00001410 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05001411 if (cfg->fc_nlinfo.nlh &&
1412 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00001413 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001414 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00001415 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00001416 table = fib6_new_table(net, cfg->fc_table);
1417 }
1418 } else {
1419 table = fib6_new_table(net, cfg->fc_table);
1420 }
David S. Miller38308472011-12-03 18:02:47 -05001421
1422 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001423 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07001424
David S. Miller8b96d222012-06-11 02:01:56 -07001425 rt = ip6_dst_alloc(net, NULL, DST_NOCOUNT, table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426
David S. Miller38308472011-12-03 18:02:47 -05001427 if (!rt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 err = -ENOMEM;
1429 goto out;
1430 }
1431
Gao feng1716a962012-04-06 00:13:10 +00001432 if (cfg->fc_flags & RTF_EXPIRES)
1433 rt6_set_expires(rt, jiffies +
1434 clock_t_to_jiffies(cfg->fc_expires));
1435 else
1436 rt6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437
Thomas Graf86872cb2006-08-22 00:01:08 -07001438 if (cfg->fc_protocol == RTPROT_UNSPEC)
1439 cfg->fc_protocol = RTPROT_BOOT;
1440 rt->rt6i_protocol = cfg->fc_protocol;
1441
1442 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443
1444 if (addr_type & IPV6_ADDR_MULTICAST)
Changli Gaod8d1f302010-06-10 23:31:35 -07001445 rt->dst.input = ip6_mc_input;
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00001446 else if (cfg->fc_flags & RTF_LOCAL)
1447 rt->dst.input = ip6_input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 else
Changli Gaod8d1f302010-06-10 23:31:35 -07001449 rt->dst.input = ip6_forward;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450
Changli Gaod8d1f302010-06-10 23:31:35 -07001451 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452
Thomas Graf86872cb2006-08-22 00:01:08 -07001453 ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
1454 rt->rt6i_dst.plen = cfg->fc_dst_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 if (rt->rt6i_dst.plen == 128)
David S. Miller11d53b42011-06-24 15:23:34 -07001456 rt->dst.flags |= DST_HOST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001458 if (!(rt->dst.flags & DST_HOST) && cfg->fc_mx) {
1459 u32 *metrics = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
1460 if (!metrics) {
1461 err = -ENOMEM;
1462 goto out;
1463 }
1464 dst_init_metrics(&rt->dst, metrics, 0);
1465 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466#ifdef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001467 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
1468 rt->rt6i_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469#endif
1470
Thomas Graf86872cb2006-08-22 00:01:08 -07001471 rt->rt6i_metric = cfg->fc_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472
1473 /* We cannot add true routes via loopback here,
1474 they would result in kernel looping; promote them to reject routes
1475 */
Thomas Graf86872cb2006-08-22 00:01:08 -07001476 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05001477 (dev && (dev->flags & IFF_LOOPBACK) &&
1478 !(addr_type & IPV6_ADDR_LOOPBACK) &&
1479 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08001481 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 if (dev) {
1483 dev_put(dev);
1484 in6_dev_put(idev);
1485 }
Daniel Lezcano55786892008-03-04 13:47:47 -08001486 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 dev_hold(dev);
1488 idev = in6_dev_get(dev);
1489 if (!idev) {
1490 err = -ENODEV;
1491 goto out;
1492 }
1493 }
Changli Gaod8d1f302010-06-10 23:31:35 -07001494 rt->dst.output = ip6_pkt_discard_out;
1495 rt->dst.input = ip6_pkt_discard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001497 switch (cfg->fc_type) {
1498 case RTN_BLACKHOLE:
1499 rt->dst.error = -EINVAL;
1500 break;
1501 case RTN_PROHIBIT:
1502 rt->dst.error = -EACCES;
1503 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00001504 case RTN_THROW:
1505 rt->dst.error = -EAGAIN;
1506 break;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00001507 default:
1508 rt->dst.error = -ENETUNREACH;
1509 break;
1510 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 goto install_route;
1512 }
1513
Thomas Graf86872cb2006-08-22 00:01:08 -07001514 if (cfg->fc_flags & RTF_GATEWAY) {
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001515 const struct in6_addr *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 int gwa_type;
1517
Thomas Graf86872cb2006-08-22 00:01:08 -07001518 gw_addr = &cfg->fc_gateway;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001519 rt->rt6i_gateway = *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 gwa_type = ipv6_addr_type(gw_addr);
1521
1522 if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
1523 struct rt6_info *grt;
1524
1525 /* IPv6 strictly inhibits using not link-local
1526 addresses as nexthop address.
1527 Otherwise, router will not able to send redirects.
1528 It is very good, but in some (rare!) circumstances
1529 (SIT, PtP, NBMA NOARP links) it is handy to allow
1530 some exceptions. --ANK
1531 */
1532 err = -EINVAL;
David S. Miller38308472011-12-03 18:02:47 -05001533 if (!(gwa_type & IPV6_ADDR_UNICAST))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 goto out;
1535
Daniel Lezcano55786892008-03-04 13:47:47 -08001536 grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537
1538 err = -EHOSTUNREACH;
David S. Miller38308472011-12-03 18:02:47 -05001539 if (!grt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 goto out;
1541 if (dev) {
David S. Millerd1918542011-12-28 20:19:20 -05001542 if (dev != grt->dst.dev) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00001543 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 goto out;
1545 }
1546 } else {
David S. Millerd1918542011-12-28 20:19:20 -05001547 dev = grt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 idev = grt->rt6i_idev;
1549 dev_hold(dev);
1550 in6_dev_hold(grt->rt6i_idev);
1551 }
David S. Miller38308472011-12-03 18:02:47 -05001552 if (!(grt->rt6i_flags & RTF_GATEWAY))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 err = 0;
Amerigo Wang94e187c2012-10-29 00:13:19 +00001554 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555
1556 if (err)
1557 goto out;
1558 }
1559 err = -EINVAL;
David S. Miller38308472011-12-03 18:02:47 -05001560 if (!dev || (dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 goto out;
1562 }
1563
1564 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05001565 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 goto out;
1567
Daniel Walterc3968a82011-04-13 21:10:57 +00001568 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
1569 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
1570 err = -EINVAL;
1571 goto out;
1572 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001573 rt->rt6i_prefsrc.addr = cfg->fc_prefsrc;
Daniel Walterc3968a82011-04-13 21:10:57 +00001574 rt->rt6i_prefsrc.plen = 128;
1575 } else
1576 rt->rt6i_prefsrc.plen = 0;
1577
Thomas Graf86872cb2006-08-22 00:01:08 -07001578 rt->rt6i_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579
1580install_route:
Thomas Graf86872cb2006-08-22 00:01:08 -07001581 if (cfg->fc_mx) {
1582 struct nlattr *nla;
1583 int remaining;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584
Thomas Graf86872cb2006-08-22 00:01:08 -07001585 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
Thomas Graf8f4c1f92007-09-12 14:44:36 +02001586 int type = nla_type(nla);
Thomas Graf86872cb2006-08-22 00:01:08 -07001587
1588 if (type) {
1589 if (type > RTAX_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 err = -EINVAL;
1591 goto out;
1592 }
Thomas Graf86872cb2006-08-22 00:01:08 -07001593
David S. Millerdefb3512010-12-08 21:16:57 -08001594 dst_metric_set(&rt->dst, type, nla_get_u32(nla));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 }
1597 }
1598
Changli Gaod8d1f302010-06-10 23:31:35 -07001599 rt->dst.dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 rt->rt6i_idev = idev;
Thomas Grafc71099a2006-08-04 23:20:06 -07001601 rt->rt6i_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001602
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001603 cfg->fc_nlinfo.nl_net = dev_net(dev);
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001604
Thomas Graf86872cb2006-08-22 00:01:08 -07001605 return __ip6_ins_rt(rt, &cfg->fc_nlinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606
1607out:
1608 if (dev)
1609 dev_put(dev);
1610 if (idev)
1611 in6_dev_put(idev);
1612 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07001613 dst_free(&rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 return err;
1615}
1616
Thomas Graf86872cb2006-08-22 00:01:08 -07001617static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618{
1619 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07001620 struct fib6_table *table;
David S. Millerd1918542011-12-28 20:19:20 -05001621 struct net *net = dev_net(rt->dst.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622
Gao feng6825a262012-09-19 19:25:34 +00001623 if (rt == net->ipv6.ip6_null_entry) {
1624 err = -ENOENT;
1625 goto out;
1626 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07001627
Thomas Grafc71099a2006-08-04 23:20:06 -07001628 table = rt->rt6i_table;
1629 write_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07001630 err = fib6_del(rt, info);
Thomas Grafc71099a2006-08-04 23:20:06 -07001631 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632
Gao feng6825a262012-09-19 19:25:34 +00001633out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00001634 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 return err;
1636}
1637
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001638int ip6_del_rt(struct rt6_info *rt)
1639{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08001640 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -05001641 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08001642 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08001643 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001644}
1645
Thomas Graf86872cb2006-08-22 00:01:08 -07001646static int ip6_route_del(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647{
Thomas Grafc71099a2006-08-04 23:20:06 -07001648 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 struct fib6_node *fn;
1650 struct rt6_info *rt;
1651 int err = -ESRCH;
1652
Daniel Lezcano55786892008-03-04 13:47:47 -08001653 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001654 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001655 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656
Thomas Grafc71099a2006-08-04 23:20:06 -07001657 read_lock_bh(&table->tb6_lock);
1658
1659 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07001660 &cfg->fc_dst, cfg->fc_dst_len,
1661 &cfg->fc_src, cfg->fc_src_len);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001662
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 if (fn) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001664 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
Thomas Graf86872cb2006-08-22 00:01:08 -07001665 if (cfg->fc_ifindex &&
David S. Millerd1918542011-12-28 20:19:20 -05001666 (!rt->dst.dev ||
1667 rt->dst.dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001669 if (cfg->fc_flags & RTF_GATEWAY &&
1670 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001672 if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07001674 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07001675 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676
Thomas Graf86872cb2006-08-22 00:01:08 -07001677 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 }
1679 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001680 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681
1682 return err;
1683}
1684
David S. Miller6700c272012-07-17 03:29:28 -07001685static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001686{
David S. Millere8599ff2012-07-11 23:43:53 -07001687 struct net *net = dev_net(skb->dev);
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001688 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07001689 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07001690 struct ndisc_options ndopts;
1691 struct inet6_dev *in6_dev;
1692 struct neighbour *neigh;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001693 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07001694 int optlen, on_link;
1695 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07001696
Simon Horman29a3cad2013-05-28 20:34:26 +00001697 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001698 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07001699
1700 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07001701 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001702 return;
1703 }
1704
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001705 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07001706
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001707 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07001708 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001709 return;
1710 }
1711
David S. Miller6e157b62012-07-12 00:05:02 -07001712 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001713 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07001714 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001715 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07001716 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07001717 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07001718 return;
1719 }
1720
1721 in6_dev = __in6_dev_get(skb->dev);
1722 if (!in6_dev)
1723 return;
1724 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
1725 return;
1726
1727 /* RFC2461 8.1:
1728 * The IP source address of the Redirect MUST be the same as the current
1729 * first-hop router for the specified ICMP Destination Address.
1730 */
1731
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001732 if (!ndisc_parse_options(msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07001733 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
1734 return;
1735 }
David S. Miller6e157b62012-07-12 00:05:02 -07001736
1737 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07001738 if (ndopts.nd_opts_tgt_lladdr) {
1739 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
1740 skb->dev);
1741 if (!lladdr) {
1742 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
1743 return;
1744 }
1745 }
1746
David S. Miller6e157b62012-07-12 00:05:02 -07001747 rt = (struct rt6_info *) dst;
1748 if (rt == net->ipv6.ip6_null_entry) {
1749 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
1750 return;
1751 }
1752
1753 /* Redirect received -> path was valid.
1754 * Look, redirects are sent only in response to data packets,
1755 * so that this nexthop apparently is reachable. --ANK
1756 */
1757 dst_confirm(&rt->dst);
1758
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001759 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07001760 if (!neigh)
1761 return;
1762
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 /*
1764 * We have finally decided to accept it.
1765 */
1766
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001767 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1769 NEIGH_UPDATE_F_OVERRIDE|
1770 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1771 NEIGH_UPDATE_F_ISROUTER))
1772 );
1773
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001774 nrt = ip6_rt_copy(rt, &msg->dest);
David S. Miller38308472011-12-03 18:02:47 -05001775 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 goto out;
1777
1778 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
1779 if (on_link)
1780 nrt->rt6i_flags &= ~RTF_GATEWAY;
1781
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001782 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783
Thomas Graf40e22e82006-08-22 00:00:45 -07001784 if (ip6_ins_rt(nrt))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 goto out;
1786
Changli Gaod8d1f302010-06-10 23:31:35 -07001787 netevent.old = &rt->dst;
1788 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00001789 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00001790 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07001791 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
1792
David S. Miller38308472011-12-03 18:02:47 -05001793 if (rt->rt6i_flags & RTF_CACHE) {
David S. Miller6e157b62012-07-12 00:05:02 -07001794 rt = (struct rt6_info *) dst_clone(&rt->dst);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001795 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 }
1797
1798out:
David S. Millere8599ff2012-07-11 23:43:53 -07001799 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07001800}
1801
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 * Misc support functions
1804 */
1805
Gao feng1716a962012-04-06 00:13:10 +00001806static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
Eric Dumazet21efcfa2011-07-19 20:18:36 +00001807 const struct in6_addr *dest)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808{
David S. Millerd1918542011-12-28 20:19:20 -05001809 struct net *net = dev_net(ort->dst.dev);
David S. Miller8b96d222012-06-11 02:01:56 -07001810 struct rt6_info *rt = ip6_dst_alloc(net, ort->dst.dev, 0,
1811 ort->rt6i_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812
1813 if (rt) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001814 rt->dst.input = ort->dst.input;
1815 rt->dst.output = ort->dst.output;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001816 rt->dst.flags |= DST_HOST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001818 rt->rt6i_dst.addr = *dest;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001819 rt->rt6i_dst.plen = 128;
David S. Millerdefb3512010-12-08 21:16:57 -08001820 dst_copy_metrics(&rt->dst, &ort->dst);
Changli Gaod8d1f302010-06-10 23:31:35 -07001821 rt->dst.error = ort->dst.error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 rt->rt6i_idev = ort->rt6i_idev;
1823 if (rt->rt6i_idev)
1824 in6_dev_hold(rt->rt6i_idev);
Changli Gaod8d1f302010-06-10 23:31:35 -07001825 rt->dst.lastuse = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001827 rt->rt6i_gateway = ort->rt6i_gateway;
Gao feng1716a962012-04-06 00:13:10 +00001828 rt->rt6i_flags = ort->rt6i_flags;
1829 if ((ort->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) ==
1830 (RTF_DEFAULT | RTF_ADDRCONF))
1831 rt6_set_from(rt, ort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 rt->rt6i_metric = 0;
1833
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834#ifdef CONFIG_IPV6_SUBTREES
1835 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1836#endif
Florian Westphal0f6c6392011-05-20 11:27:24 +00001837 memcpy(&rt->rt6i_prefsrc, &ort->rt6i_prefsrc, sizeof(struct rt6key));
Thomas Grafc71099a2006-08-04 23:20:06 -07001838 rt->rt6i_table = ort->rt6i_table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 }
1840 return rt;
1841}
1842
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001843#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001844static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001845 const struct in6_addr *prefix, int prefixlen,
1846 const struct in6_addr *gwaddr, int ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001847{
1848 struct fib6_node *fn;
1849 struct rt6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001850 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001851
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001852 table = fib6_get_table(net, RT6_TABLE_INFO);
David S. Miller38308472011-12-03 18:02:47 -05001853 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001854 return NULL;
1855
Li RongQing5744dd92012-09-11 21:59:01 +00001856 read_lock_bh(&table->tb6_lock);
Thomas Grafc71099a2006-08-04 23:20:06 -07001857 fn = fib6_locate(&table->tb6_root, prefix ,prefixlen, NULL, 0);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001858 if (!fn)
1859 goto out;
1860
Changli Gaod8d1f302010-06-10 23:31:35 -07001861 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05001862 if (rt->dst.dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001863 continue;
1864 if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
1865 continue;
1866 if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
1867 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07001868 dst_hold(&rt->dst);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001869 break;
1870 }
1871out:
Li RongQing5744dd92012-09-11 21:59:01 +00001872 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001873 return rt;
1874}
1875
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001876static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001877 const struct in6_addr *prefix, int prefixlen,
1878 const struct in6_addr *gwaddr, int ifindex,
Eric Dumazet95c96172012-04-15 05:58:06 +00001879 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001880{
Thomas Graf86872cb2006-08-22 00:01:08 -07001881 struct fib6_config cfg = {
1882 .fc_table = RT6_TABLE_INFO,
Rami Rosen238fc7e2008-02-09 23:43:11 -08001883 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07001884 .fc_ifindex = ifindex,
1885 .fc_dst_len = prefixlen,
1886 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
1887 RTF_UP | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00001888 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001889 .fc_nlinfo.nlh = NULL,
1890 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07001891 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001892
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001893 cfg.fc_dst = *prefix;
1894 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07001895
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08001896 /* We should treat it as a default route if prefix length is 0. */
1897 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07001898 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001899
Thomas Graf86872cb2006-08-22 00:01:08 -07001900 ip6_route_add(&cfg);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001901
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001902 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001903}
1904#endif
1905
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001906struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001907{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001909 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001911 table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05001912 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001913 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914
Li RongQing5744dd92012-09-11 21:59:01 +00001915 read_lock_bh(&table->tb6_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001916 for (rt = table->tb6_root.leaf; rt; rt=rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05001917 if (dev == rt->dst.dev &&
YOSHIFUJI Hideaki045927f2006-03-20 17:00:48 -08001918 ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 ipv6_addr_equal(&rt->rt6i_gateway, addr))
1920 break;
1921 }
1922 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07001923 dst_hold(&rt->dst);
Li RongQing5744dd92012-09-11 21:59:01 +00001924 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 return rt;
1926}
1927
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001928struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001929 struct net_device *dev,
1930 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931{
Thomas Graf86872cb2006-08-22 00:01:08 -07001932 struct fib6_config cfg = {
1933 .fc_table = RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08001934 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07001935 .fc_ifindex = dev->ifindex,
1936 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
1937 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00001938 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08001939 .fc_nlinfo.nlh = NULL,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001940 .fc_nlinfo.nl_net = dev_net(dev),
Thomas Graf86872cb2006-08-22 00:01:08 -07001941 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001943 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944
Thomas Graf86872cb2006-08-22 00:01:08 -07001945 ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 return rt6_get_dflt_router(gwaddr, dev);
1948}
1949
Daniel Lezcano7b4da532008-03-04 13:47:14 -08001950void rt6_purge_dflt_routers(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951{
1952 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001953 struct fib6_table *table;
1954
1955 /* NOTE: Keep consistent with rt6_get_dflt_router */
Daniel Lezcano7b4da532008-03-04 13:47:14 -08001956 table = fib6_get_table(net, RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05001957 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001958 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959
1960restart:
Thomas Grafc71099a2006-08-04 23:20:06 -07001961 read_lock_bh(&table->tb6_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001962 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
Lorenzo Colitti3e8b0ac2013-03-03 20:46:46 +00001963 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
1964 (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001965 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07001966 read_unlock_bh(&table->tb6_lock);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001967 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 goto restart;
1969 }
1970 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001971 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972}
1973
Daniel Lezcano55786892008-03-04 13:47:47 -08001974static void rtmsg_to_fib6_config(struct net *net,
1975 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07001976 struct fib6_config *cfg)
1977{
1978 memset(cfg, 0, sizeof(*cfg));
1979
1980 cfg->fc_table = RT6_TABLE_MAIN;
1981 cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
1982 cfg->fc_metric = rtmsg->rtmsg_metric;
1983 cfg->fc_expires = rtmsg->rtmsg_info;
1984 cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
1985 cfg->fc_src_len = rtmsg->rtmsg_src_len;
1986 cfg->fc_flags = rtmsg->rtmsg_flags;
1987
Daniel Lezcano55786892008-03-04 13:47:47 -08001988 cfg->fc_nlinfo.nl_net = net;
Benjamin Theryf1243c22008-02-26 18:10:03 -08001989
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001990 cfg->fc_dst = rtmsg->rtmsg_dst;
1991 cfg->fc_src = rtmsg->rtmsg_src;
1992 cfg->fc_gateway = rtmsg->rtmsg_gateway;
Thomas Graf86872cb2006-08-22 00:01:08 -07001993}
1994
Daniel Lezcano55786892008-03-04 13:47:47 -08001995int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996{
Thomas Graf86872cb2006-08-22 00:01:08 -07001997 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 struct in6_rtmsg rtmsg;
1999 int err;
2000
2001 switch(cmd) {
2002 case SIOCADDRT: /* Add a route */
2003 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00002004 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 return -EPERM;
2006 err = copy_from_user(&rtmsg, arg,
2007 sizeof(struct in6_rtmsg));
2008 if (err)
2009 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07002010
Daniel Lezcano55786892008-03-04 13:47:47 -08002011 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07002012
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 rtnl_lock();
2014 switch (cmd) {
2015 case SIOCADDRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07002016 err = ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 break;
2018 case SIOCDELRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07002019 err = ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 break;
2021 default:
2022 err = -EINVAL;
2023 }
2024 rtnl_unlock();
2025
2026 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07002027 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028
2029 return -EINVAL;
2030}
2031
2032/*
2033 * Drop the packet on the floor
2034 */
2035
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07002036static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002038 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00002039 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002040 switch (ipstats_mib_noroutes) {
2041 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07002042 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00002043 if (type == IPV6_ADDR_ANY) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002044 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2045 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002046 break;
2047 }
2048 /* FALLTHROUGH */
2049 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002050 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2051 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002052 break;
2053 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002054 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 kfree_skb(skb);
2056 return 0;
2057}
2058
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002059static int ip6_pkt_discard(struct sk_buff *skb)
2060{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002061 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002062}
2063
Arnaldo Carvalho de Melo20380732005-08-16 02:18:02 -03002064static int ip6_pkt_discard_out(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065{
Eric Dumazetadf30902009-06-02 05:19:30 +00002066 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002067 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068}
2069
David S. Miller6723ab52006-10-18 21:20:57 -07002070#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2071
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002072static int ip6_pkt_prohibit(struct sk_buff *skb)
2073{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002074 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002075}
2076
2077static int ip6_pkt_prohibit_out(struct sk_buff *skb)
2078{
Eric Dumazetadf30902009-06-02 05:19:30 +00002079 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002080 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002081}
2082
David S. Miller6723ab52006-10-18 21:20:57 -07002083#endif
2084
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085/*
2086 * Allocate a dst for local (unicast / anycast) address.
2087 */
2088
2089struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
2090 const struct in6_addr *addr,
David S. Miller8f031512011-12-06 16:48:14 -05002091 bool anycast)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002093 struct net *net = dev_net(idev->dev);
David S. Miller8b96d222012-06-11 02:01:56 -07002094 struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev, 0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095
David S. Miller38308472011-12-03 18:02:47 -05002096 if (!rt) {
Joe Perchesf3213832012-05-15 14:11:53 +00002097 net_warn_ratelimited("Maximum number of routes reached, consider increasing route/max_size\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 return ERR_PTR(-ENOMEM);
Ben Greear40385652010-11-08 12:33:48 +00002099 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 in6_dev_hold(idev);
2102
David S. Miller11d53b42011-06-24 15:23:34 -07002103 rt->dst.flags |= DST_HOST;
Changli Gaod8d1f302010-06-10 23:31:35 -07002104 rt->dst.input = ip6_input;
2105 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 rt->rt6i_idev = idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107
2108 rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +09002109 if (anycast)
2110 rt->rt6i_flags |= RTF_ANYCAST;
2111 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 rt->rt6i_flags |= RTF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002114 rt->rt6i_dst.addr = *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 rt->rt6i_dst.plen = 128;
Daniel Lezcano55786892008-03-04 13:47:47 -08002116 rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117
Changli Gaod8d1f302010-06-10 23:31:35 -07002118 atomic_set(&rt->dst.__refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119
2120 return rt;
2121}
2122
Daniel Walterc3968a82011-04-13 21:10:57 +00002123int ip6_route_get_saddr(struct net *net,
2124 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002125 const struct in6_addr *daddr,
Daniel Walterc3968a82011-04-13 21:10:57 +00002126 unsigned int prefs,
2127 struct in6_addr *saddr)
2128{
2129 struct inet6_dev *idev = ip6_dst_idev((struct dst_entry*)rt);
2130 int err = 0;
2131 if (rt->rt6i_prefsrc.plen)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002132 *saddr = rt->rt6i_prefsrc.addr;
Daniel Walterc3968a82011-04-13 21:10:57 +00002133 else
2134 err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
2135 daddr, prefs, saddr);
2136 return err;
2137}
2138
2139/* remove deleted ip from prefsrc entries */
2140struct arg_dev_net_ip {
2141 struct net_device *dev;
2142 struct net *net;
2143 struct in6_addr *addr;
2144};
2145
2146static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
2147{
2148 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
2149 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
2150 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
2151
David S. Millerd1918542011-12-28 20:19:20 -05002152 if (((void *)rt->dst.dev == dev || !dev) &&
Daniel Walterc3968a82011-04-13 21:10:57 +00002153 rt != net->ipv6.ip6_null_entry &&
2154 ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
2155 /* remove prefsrc entry */
2156 rt->rt6i_prefsrc.plen = 0;
2157 }
2158 return 0;
2159}
2160
2161void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
2162{
2163 struct net *net = dev_net(ifp->idev->dev);
2164 struct arg_dev_net_ip adni = {
2165 .dev = ifp->idev->dev,
2166 .net = net,
2167 .addr = &ifp->addr,
2168 };
2169 fib6_clean_all(net, fib6_remove_prefsrc, 0, &adni);
2170}
2171
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002172struct arg_dev_net {
2173 struct net_device *dev;
2174 struct net *net;
2175};
2176
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177static int fib6_ifdown(struct rt6_info *rt, void *arg)
2178{
stephen hemmingerbc3ef662010-12-16 17:42:40 +00002179 const struct arg_dev_net *adn = arg;
2180 const struct net_device *dev = adn->dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002181
David S. Millerd1918542011-12-28 20:19:20 -05002182 if ((rt->dst.dev == dev || !dev) &&
David S. Millerc159d302011-12-26 15:24:36 -05002183 rt != adn->net->ipv6.ip6_null_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 return -1;
David S. Millerc159d302011-12-26 15:24:36 -05002185
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 return 0;
2187}
2188
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002189void rt6_ifdown(struct net *net, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002191 struct arg_dev_net adn = {
2192 .dev = dev,
2193 .net = net,
2194 };
2195
2196 fib6_clean_all(net, fib6_ifdown, 0, &adn);
David S. Miller1e493d12008-09-10 17:27:15 -07002197 icmp6_clean_all(fib6_ifdown, &adn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198}
2199
Eric Dumazet95c96172012-04-15 05:58:06 +00002200struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00002202 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203};
2204
2205static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
2206{
2207 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
2208 struct inet6_dev *idev;
2209
2210 /* In IPv6 pmtu discovery is not optional,
2211 so that RTAX_MTU lock cannot disable it.
2212 We still use this lock to block changes
2213 caused by addrconf/ndisc.
2214 */
2215
2216 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05002217 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 return 0;
2219
2220 /* For administrative MTU increase, there is no way to discover
2221 IPv6 PMTU increase, so PMTU increase should be updated here.
2222 Since RFC 1981 doesn't include administrative MTU increase
2223 update PMTU increase is a MUST. (i.e. jumbo frame)
2224 */
2225 /*
2226 If new MTU is less than route PMTU, this new MTU will be the
2227 lowest MTU in the path, update the route PMTU to reflect PMTU
2228 decreases; if new MTU is greater than route PMTU, and the
2229 old MTU is the lowest MTU in the path, update the route PMTU
2230 to reflect the increase. In this case if the other nodes' MTU
2231 also have the lowest MTU, TOO BIG MESSAGE will be lead to
2232 PMTU discouvery.
2233 */
David S. Millerd1918542011-12-28 20:19:20 -05002234 if (rt->dst.dev == arg->dev &&
Changli Gaod8d1f302010-06-10 23:31:35 -07002235 !dst_metric_locked(&rt->dst, RTAX_MTU) &&
2236 (dst_mtu(&rt->dst) >= arg->mtu ||
2237 (dst_mtu(&rt->dst) < arg->mtu &&
2238 dst_mtu(&rt->dst) == idev->cnf.mtu6))) {
David S. Millerdefb3512010-12-08 21:16:57 -08002239 dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu);
Simon Arlott566cfd82007-07-26 00:09:55 -07002240 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 return 0;
2242}
2243
Eric Dumazet95c96172012-04-15 05:58:06 +00002244void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245{
Thomas Grafc71099a2006-08-04 23:20:06 -07002246 struct rt6_mtu_change_arg arg = {
2247 .dev = dev,
2248 .mtu = mtu,
2249 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002251 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, 0, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252}
2253
Patrick McHardyef7c79e2007-06-05 12:38:30 -07002254static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07002255 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07002256 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07002257 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002258 [RTA_PRIORITY] = { .type = NLA_U32 },
2259 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002260 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Thomas Graf86872cb2006-08-22 00:01:08 -07002261};
2262
2263static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
2264 struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265{
Thomas Graf86872cb2006-08-22 00:01:08 -07002266 struct rtmsg *rtm;
2267 struct nlattr *tb[RTA_MAX+1];
2268 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269
Thomas Graf86872cb2006-08-22 00:01:08 -07002270 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2271 if (err < 0)
2272 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273
Thomas Graf86872cb2006-08-22 00:01:08 -07002274 err = -EINVAL;
2275 rtm = nlmsg_data(nlh);
2276 memset(cfg, 0, sizeof(*cfg));
2277
2278 cfg->fc_table = rtm->rtm_table;
2279 cfg->fc_dst_len = rtm->rtm_dst_len;
2280 cfg->fc_src_len = rtm->rtm_src_len;
2281 cfg->fc_flags = RTF_UP;
2282 cfg->fc_protocol = rtm->rtm_protocol;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002283 cfg->fc_type = rtm->rtm_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07002284
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002285 if (rtm->rtm_type == RTN_UNREACHABLE ||
2286 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002287 rtm->rtm_type == RTN_PROHIBIT ||
2288 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07002289 cfg->fc_flags |= RTF_REJECT;
2290
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002291 if (rtm->rtm_type == RTN_LOCAL)
2292 cfg->fc_flags |= RTF_LOCAL;
2293
Eric W. Biederman15e47302012-09-07 20:12:54 +00002294 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
Thomas Graf86872cb2006-08-22 00:01:08 -07002295 cfg->fc_nlinfo.nlh = nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002296 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
Thomas Graf86872cb2006-08-22 00:01:08 -07002297
2298 if (tb[RTA_GATEWAY]) {
2299 nla_memcpy(&cfg->fc_gateway, tb[RTA_GATEWAY], 16);
2300 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002302
2303 if (tb[RTA_DST]) {
2304 int plen = (rtm->rtm_dst_len + 7) >> 3;
2305
2306 if (nla_len(tb[RTA_DST]) < plen)
2307 goto errout;
2308
2309 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002311
2312 if (tb[RTA_SRC]) {
2313 int plen = (rtm->rtm_src_len + 7) >> 3;
2314
2315 if (nla_len(tb[RTA_SRC]) < plen)
2316 goto errout;
2317
2318 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002320
Daniel Walterc3968a82011-04-13 21:10:57 +00002321 if (tb[RTA_PREFSRC])
2322 nla_memcpy(&cfg->fc_prefsrc, tb[RTA_PREFSRC], 16);
2323
Thomas Graf86872cb2006-08-22 00:01:08 -07002324 if (tb[RTA_OIF])
2325 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
2326
2327 if (tb[RTA_PRIORITY])
2328 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
2329
2330 if (tb[RTA_METRICS]) {
2331 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
2332 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002334
2335 if (tb[RTA_TABLE])
2336 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
2337
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002338 if (tb[RTA_MULTIPATH]) {
2339 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
2340 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
2341 }
2342
Thomas Graf86872cb2006-08-22 00:01:08 -07002343 err = 0;
2344errout:
2345 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346}
2347
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002348static int ip6_route_multipath(struct fib6_config *cfg, int add)
2349{
2350 struct fib6_config r_cfg;
2351 struct rtnexthop *rtnh;
2352 int remaining;
2353 int attrlen;
2354 int err = 0, last_err = 0;
2355
2356beginning:
2357 rtnh = (struct rtnexthop *)cfg->fc_mp;
2358 remaining = cfg->fc_mp_len;
2359
2360 /* Parse a Multipath Entry */
2361 while (rtnh_ok(rtnh, remaining)) {
2362 memcpy(&r_cfg, cfg, sizeof(*cfg));
2363 if (rtnh->rtnh_ifindex)
2364 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
2365
2366 attrlen = rtnh_attrlen(rtnh);
2367 if (attrlen > 0) {
2368 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
2369
2370 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
2371 if (nla) {
2372 nla_memcpy(&r_cfg.fc_gateway, nla, 16);
2373 r_cfg.fc_flags |= RTF_GATEWAY;
2374 }
2375 }
2376 err = add ? ip6_route_add(&r_cfg) : ip6_route_del(&r_cfg);
2377 if (err) {
2378 last_err = err;
2379 /* If we are trying to remove a route, do not stop the
2380 * loop when ip6_route_del() fails (because next hop is
2381 * already gone), we should try to remove all next hops.
2382 */
2383 if (add) {
2384 /* If add fails, we should try to delete all
2385 * next hops that have been already added.
2386 */
2387 add = 0;
2388 goto beginning;
2389 }
2390 }
Nicolas Dichtel1a724182012-11-01 22:58:22 +00002391 /* Because each route is added like a single route we remove
2392 * this flag after the first nexthop (if there is a collision,
2393 * we have already fail to add the first nexthop:
2394 * fib6_add_rt2node() has reject it).
2395 */
2396 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~NLM_F_EXCL;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002397 rtnh = rtnh_next(rtnh, &remaining);
2398 }
2399
2400 return last_err;
2401}
2402
Thomas Graf661d2962013-03-21 07:45:29 +00002403static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404{
Thomas Graf86872cb2006-08-22 00:01:08 -07002405 struct fib6_config cfg;
2406 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407
Thomas Graf86872cb2006-08-22 00:01:08 -07002408 err = rtm_to_fib6_config(skb, nlh, &cfg);
2409 if (err < 0)
2410 return err;
2411
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002412 if (cfg.fc_mp)
2413 return ip6_route_multipath(&cfg, 0);
2414 else
2415 return ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416}
2417
Thomas Graf661d2962013-03-21 07:45:29 +00002418static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419{
Thomas Graf86872cb2006-08-22 00:01:08 -07002420 struct fib6_config cfg;
2421 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422
Thomas Graf86872cb2006-08-22 00:01:08 -07002423 err = rtm_to_fib6_config(skb, nlh, &cfg);
2424 if (err < 0)
2425 return err;
2426
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002427 if (cfg.fc_mp)
2428 return ip6_route_multipath(&cfg, 1);
2429 else
2430 return ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431}
2432
Thomas Graf339bf982006-11-10 14:10:15 -08002433static inline size_t rt6_nlmsg_size(void)
2434{
2435 return NLMSG_ALIGN(sizeof(struct rtmsg))
2436 + nla_total_size(16) /* RTA_SRC */
2437 + nla_total_size(16) /* RTA_DST */
2438 + nla_total_size(16) /* RTA_GATEWAY */
2439 + nla_total_size(16) /* RTA_PREFSRC */
2440 + nla_total_size(4) /* RTA_TABLE */
2441 + nla_total_size(4) /* RTA_IIF */
2442 + nla_total_size(4) /* RTA_OIF */
2443 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08002444 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Thomas Graf339bf982006-11-10 14:10:15 -08002445 + nla_total_size(sizeof(struct rta_cacheinfo));
2446}
2447
Brian Haley191cd582008-08-14 15:33:21 -07002448static int rt6_fill_node(struct net *net,
2449 struct sk_buff *skb, struct rt6_info *rt,
Jamal Hadi Salim0d51aa82005-06-21 13:51:04 -07002450 struct in6_addr *dst, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002451 int iif, int type, u32 portid, u32 seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002452 int prefix, int nowait, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453{
2454 struct rtmsg *rtm;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002455 struct nlmsghdr *nlh;
Thomas Grafe3703b32006-11-27 09:27:07 -08002456 long expires;
Patrick McHardy9e762a42006-08-10 23:09:48 -07002457 u32 table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458
2459 if (prefix) { /* user wants prefix routes only */
2460 if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
2461 /* success since this is not a prefix route */
2462 return 1;
2463 }
2464 }
2465
Eric W. Biederman15e47302012-09-07 20:12:54 +00002466 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05002467 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08002468 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002469
2470 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 rtm->rtm_family = AF_INET6;
2472 rtm->rtm_dst_len = rt->rt6i_dst.plen;
2473 rtm->rtm_src_len = rt->rt6i_src.plen;
2474 rtm->rtm_tos = 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07002475 if (rt->rt6i_table)
Patrick McHardy9e762a42006-08-10 23:09:48 -07002476 table = rt->rt6i_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07002477 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07002478 table = RT6_TABLE_UNSPEC;
2479 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04002480 if (nla_put_u32(skb, RTA_TABLE, table))
2481 goto nla_put_failure;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002482 if (rt->rt6i_flags & RTF_REJECT) {
2483 switch (rt->dst.error) {
2484 case -EINVAL:
2485 rtm->rtm_type = RTN_BLACKHOLE;
2486 break;
2487 case -EACCES:
2488 rtm->rtm_type = RTN_PROHIBIT;
2489 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002490 case -EAGAIN:
2491 rtm->rtm_type = RTN_THROW;
2492 break;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002493 default:
2494 rtm->rtm_type = RTN_UNREACHABLE;
2495 break;
2496 }
2497 }
David S. Miller38308472011-12-03 18:02:47 -05002498 else if (rt->rt6i_flags & RTF_LOCAL)
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002499 rtm->rtm_type = RTN_LOCAL;
David S. Millerd1918542011-12-28 20:19:20 -05002500 else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 rtm->rtm_type = RTN_LOCAL;
2502 else
2503 rtm->rtm_type = RTN_UNICAST;
2504 rtm->rtm_flags = 0;
2505 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
2506 rtm->rtm_protocol = rt->rt6i_protocol;
David S. Miller38308472011-12-03 18:02:47 -05002507 if (rt->rt6i_flags & RTF_DYNAMIC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 rtm->rtm_protocol = RTPROT_REDIRECT;
Denis Ovsienkof0396f602012-07-10 04:45:50 +00002509 else if (rt->rt6i_flags & RTF_ADDRCONF) {
2510 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ROUTEINFO))
2511 rtm->rtm_protocol = RTPROT_RA;
2512 else
2513 rtm->rtm_protocol = RTPROT_KERNEL;
2514 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
David S. Miller38308472011-12-03 18:02:47 -05002516 if (rt->rt6i_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 rtm->rtm_flags |= RTM_F_CLONED;
2518
2519 if (dst) {
David S. Millerc78679e2012-04-01 20:27:33 -04002520 if (nla_put(skb, RTA_DST, 16, dst))
2521 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002522 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 } else if (rtm->rtm_dst_len)
David S. Millerc78679e2012-04-01 20:27:33 -04002524 if (nla_put(skb, RTA_DST, 16, &rt->rt6i_dst.addr))
2525 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526#ifdef CONFIG_IPV6_SUBTREES
2527 if (src) {
David S. Millerc78679e2012-04-01 20:27:33 -04002528 if (nla_put(skb, RTA_SRC, 16, src))
2529 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002530 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04002531 } else if (rtm->rtm_src_len &&
2532 nla_put(skb, RTA_SRC, 16, &rt->rt6i_src.addr))
2533 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002535 if (iif) {
2536#ifdef CONFIG_IPV6_MROUTE
2537 if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
Benjamin Thery8229efd2008-12-10 16:30:15 -08002538 int err = ip6mr_get_route(net, skb, rtm, nowait);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002539 if (err <= 0) {
2540 if (!nowait) {
2541 if (err == 0)
2542 return 0;
2543 goto nla_put_failure;
2544 } else {
2545 if (err == -EMSGSIZE)
2546 goto nla_put_failure;
2547 }
2548 }
2549 } else
2550#endif
David S. Millerc78679e2012-04-01 20:27:33 -04002551 if (nla_put_u32(skb, RTA_IIF, iif))
2552 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002553 } else if (dst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 struct in6_addr saddr_buf;
David S. Millerc78679e2012-04-01 20:27:33 -04002555 if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0 &&
2556 nla_put(skb, RTA_PREFSRC, 16, &saddr_buf))
2557 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07002559
Daniel Walterc3968a82011-04-13 21:10:57 +00002560 if (rt->rt6i_prefsrc.plen) {
2561 struct in6_addr saddr_buf;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002562 saddr_buf = rt->rt6i_prefsrc.addr;
David S. Millerc78679e2012-04-01 20:27:33 -04002563 if (nla_put(skb, RTA_PREFSRC, 16, &saddr_buf))
2564 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00002565 }
2566
David S. Millerdefb3512010-12-08 21:16:57 -08002567 if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07002568 goto nla_put_failure;
2569
YOSHIFUJI Hideaki / 吉藤英明dd0cbf22013-01-17 12:53:15 +00002570 if (rt->rt6i_flags & RTF_GATEWAY) {
2571 if (nla_put(skb, RTA_GATEWAY, 16, &rt->rt6i_gateway) < 0)
Eric Dumazet94f826b2012-03-27 09:53:52 +00002572 goto nla_put_failure;
Eric Dumazet94f826b2012-03-27 09:53:52 +00002573 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07002574
David S. Millerc78679e2012-04-01 20:27:33 -04002575 if (rt->dst.dev &&
2576 nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex))
2577 goto nla_put_failure;
2578 if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric))
2579 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00002580
2581 expires = (rt->rt6i_flags & RTF_EXPIRES) ? rt->dst.expires - jiffies : 0;
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07002582
David S. Miller87a50692012-07-10 05:06:14 -07002583 if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, rt->dst.error) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08002584 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585
Thomas Graf2d7202b2006-08-22 00:01:27 -07002586 return nlmsg_end(skb, nlh);
2587
2588nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002589 nlmsg_cancel(skb, nlh);
2590 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591}
2592
Patrick McHardy1b43af52006-08-10 23:11:17 -07002593int rt6_dump_route(struct rt6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594{
2595 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
2596 int prefix;
2597
Thomas Graf2d7202b2006-08-22 00:01:27 -07002598 if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
2599 struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0;
2601 } else
2602 prefix = 0;
2603
Brian Haley191cd582008-08-14 15:33:21 -07002604 return rt6_fill_node(arg->net,
2605 arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002606 NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002607 prefix, 0, NLM_F_MULTI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608}
2609
Thomas Graf661d2962013-03-21 07:45:29 +00002610static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002612 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07002613 struct nlattr *tb[RTA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07002615 struct sk_buff *skb;
2616 struct rtmsg *rtm;
David S. Miller4c9483b2011-03-12 16:22:43 -05002617 struct flowi6 fl6;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002618 int err, iif = 0, oif = 0;
Thomas Grafab364a62006-08-22 00:01:47 -07002619
2620 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2621 if (err < 0)
2622 goto errout;
2623
2624 err = -EINVAL;
David S. Miller4c9483b2011-03-12 16:22:43 -05002625 memset(&fl6, 0, sizeof(fl6));
Thomas Grafab364a62006-08-22 00:01:47 -07002626
2627 if (tb[RTA_SRC]) {
2628 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
2629 goto errout;
2630
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002631 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07002632 }
2633
2634 if (tb[RTA_DST]) {
2635 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
2636 goto errout;
2637
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002638 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07002639 }
2640
2641 if (tb[RTA_IIF])
2642 iif = nla_get_u32(tb[RTA_IIF]);
2643
2644 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002645 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07002646
2647 if (iif) {
2648 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002649 int flags = 0;
2650
Daniel Lezcano55786892008-03-04 13:47:47 -08002651 dev = __dev_get_by_index(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07002652 if (!dev) {
2653 err = -ENODEV;
2654 goto errout;
2655 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002656
2657 fl6.flowi6_iif = iif;
2658
2659 if (!ipv6_addr_any(&fl6.saddr))
2660 flags |= RT6_LOOKUP_F_HAS_SADDR;
2661
2662 rt = (struct rt6_info *)ip6_route_input_lookup(net, dev, &fl6,
2663 flags);
2664 } else {
2665 fl6.flowi6_oif = oif;
2666
2667 rt = (struct rt6_info *)ip6_route_output(net, NULL, &fl6);
Thomas Grafab364a62006-08-22 00:01:47 -07002668 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669
2670 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05002671 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00002672 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07002673 err = -ENOBUFS;
2674 goto errout;
2675 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676
2677 /* Reserve room for dummy headers, this skb can pass
2678 through good chunk of routing engine.
2679 */
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07002680 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
2682
Changli Gaod8d1f302010-06-10 23:31:35 -07002683 skb_dst_set(skb, &rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684
David S. Miller4c9483b2011-03-12 16:22:43 -05002685 err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002686 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002687 nlh->nlmsg_seq, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07002689 kfree_skb(skb);
2690 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 }
2692
Eric W. Biederman15e47302012-09-07 20:12:54 +00002693 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07002694errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696}
2697
Thomas Graf86872cb2006-08-22 00:01:08 -07002698void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699{
2700 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08002701 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002702 u32 seq;
2703 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002705 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05002706 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07002707
Thomas Graf339bf982006-11-10 14:10:15 -08002708 skb = nlmsg_new(rt6_nlmsg_size(), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05002709 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07002710 goto errout;
2711
Brian Haley191cd582008-08-14 15:33:21 -07002712 err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002713 event, info->portid, seq, 0, 0, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08002714 if (err < 0) {
2715 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
2716 WARN_ON(err == -EMSGSIZE);
2717 kfree_skb(skb);
2718 goto errout;
2719 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00002720 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08002721 info->nlh, gfp_any());
2722 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07002723errout:
2724 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08002725 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726}
2727
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002728static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00002729 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002730{
Jiri Pirko351638e2013-05-28 01:30:21 +00002731 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002732 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002733
2734 if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002735 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002736 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
2737#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07002738 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002739 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07002740 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002741 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
2742#endif
2743 }
2744
2745 return NOTIFY_OK;
2746}
2747
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748/*
2749 * /proc
2750 */
2751
2752#ifdef CONFIG_PROC_FS
2753
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754struct rt6_proc_arg
2755{
2756 char *buffer;
2757 int offset;
2758 int length;
2759 int skip;
2760 int len;
2761};
2762
2763static int rt6_info_route(struct rt6_info *rt, void *p_arg)
2764{
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002765 struct seq_file *m = p_arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766
Harvey Harrison4b7a4272008-10-29 12:50:24 -07002767 seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768
2769#ifdef CONFIG_IPV6_SUBTREES
Harvey Harrison4b7a4272008-10-29 12:50:24 -07002770 seq_printf(m, "%pi6 %02x ", &rt->rt6i_src.addr, rt->rt6i_src.plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771#else
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002772 seq_puts(m, "00000000000000000000000000000000 00 ");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773#endif
YOSHIFUJI Hideaki / 吉藤英明dd0cbf22013-01-17 12:53:15 +00002774 if (rt->rt6i_flags & RTF_GATEWAY) {
2775 seq_printf(m, "%pi6", &rt->rt6i_gateway);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 } else {
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002777 seq_puts(m, "00000000000000000000000000000000");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 }
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002779 seq_printf(m, " %08x %08x %08x %08x %8s\n",
Changli Gaod8d1f302010-06-10 23:31:35 -07002780 rt->rt6i_metric, atomic_read(&rt->dst.__refcnt),
2781 rt->dst.__use, rt->rt6i_flags,
David S. Millerd1918542011-12-28 20:19:20 -05002782 rt->dst.dev ? rt->dst.dev->name : "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 return 0;
2784}
2785
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002786static int ipv6_route_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787{
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002788 struct net *net = (struct net *)m->private;
Josh Hunt32b293a2011-12-28 13:23:07 +00002789 fib6_clean_all_ro(net, rt6_info_route, 0, m);
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002790 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791}
2792
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002793static int ipv6_route_open(struct inode *inode, struct file *file)
2794{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07002795 return single_open_net(inode, file, ipv6_route_show);
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002796}
2797
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002798static const struct file_operations ipv6_route_proc_fops = {
2799 .owner = THIS_MODULE,
2800 .open = ipv6_route_open,
2801 .read = seq_read,
2802 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07002803 .release = single_release_net,
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002804};
2805
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806static int rt6_stats_seq_show(struct seq_file *seq, void *v)
2807{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002808 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002810 net->ipv6.rt6_stats->fib_nodes,
2811 net->ipv6.rt6_stats->fib_route_nodes,
2812 net->ipv6.rt6_stats->fib_rt_alloc,
2813 net->ipv6.rt6_stats->fib_rt_entries,
2814 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00002815 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002816 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817
2818 return 0;
2819}
2820
2821static int rt6_stats_seq_open(struct inode *inode, struct file *file)
2822{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07002823 return single_open_net(inode, file, rt6_stats_seq_show);
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002824}
2825
Arjan van de Ven9a321442007-02-12 00:55:35 -08002826static const struct file_operations rt6_stats_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827 .owner = THIS_MODULE,
2828 .open = rt6_stats_seq_open,
2829 .read = seq_read,
2830 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07002831 .release = single_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832};
2833#endif /* CONFIG_PROC_FS */
2834
2835#ifdef CONFIG_SYSCTL
2836
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837static
Joe Perchesfe2c6332013-06-11 23:04:25 -07002838int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 void __user *buffer, size_t *lenp, loff_t *ppos)
2840{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00002841 struct net *net;
2842 int delay;
2843 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00002845
2846 net = (struct net *)ctl->extra1;
2847 delay = net->ipv6.sysctl.flush_delay;
2848 proc_dointvec(ctl, write, buffer, lenp, ppos);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02002849 fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00002850 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851}
2852
Joe Perchesfe2c6332013-06-11 23:04:25 -07002853struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002854 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08002856 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07002858 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002859 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 },
2861 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08002863 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 .maxlen = sizeof(int),
2865 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002866 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 },
2868 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08002870 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 .maxlen = sizeof(int),
2872 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002873 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 },
2875 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08002877 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 .maxlen = sizeof(int),
2879 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002880 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 },
2882 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08002884 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 .maxlen = sizeof(int),
2886 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002887 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 },
2889 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08002891 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 .maxlen = sizeof(int),
2893 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002894 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 },
2896 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08002898 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 .maxlen = sizeof(int),
2900 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07002901 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 },
2903 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08002905 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 .maxlen = sizeof(int),
2907 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002908 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 },
2910 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08002912 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 .maxlen = sizeof(int),
2914 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07002915 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 },
2917 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08002919 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 .maxlen = sizeof(int),
2921 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002922 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002924 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925};
2926
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002927struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08002928{
2929 struct ctl_table *table;
2930
2931 table = kmemdup(ipv6_route_table_template,
2932 sizeof(ipv6_route_table_template),
2933 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09002934
2935 if (table) {
2936 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00002937 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00002938 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09002939 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
2940 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
2941 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
2942 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
2943 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
2944 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
2945 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08002946 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
Eric W. Biederman464dc802012-11-16 03:02:59 +00002947
2948 /* Don't export sysctls to unprivileged users */
2949 if (net->user_ns != &init_user_ns)
2950 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09002951 }
2952
Daniel Lezcano760f2d02008-01-10 02:53:43 -08002953 return table;
2954}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955#endif
2956
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002957static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08002958{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07002959 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002960
Alexey Dobriyan86393e52009-08-29 01:34:49 +00002961 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
2962 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08002963
Eric Dumazetfc66f952010-10-08 06:37:34 +00002964 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
2965 goto out_ip6_dst_ops;
2966
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002967 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
2968 sizeof(*net->ipv6.ip6_null_entry),
2969 GFP_KERNEL);
2970 if (!net->ipv6.ip6_null_entry)
Eric Dumazetfc66f952010-10-08 06:37:34 +00002971 goto out_ip6_dst_entries;
Changli Gaod8d1f302010-06-10 23:31:35 -07002972 net->ipv6.ip6_null_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002973 (struct dst_entry *)net->ipv6.ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002974 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08002975 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
2976 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002977
2978#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2979 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
2980 sizeof(*net->ipv6.ip6_prohibit_entry),
2981 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07002982 if (!net->ipv6.ip6_prohibit_entry)
2983 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002984 net->ipv6.ip6_prohibit_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002985 (struct dst_entry *)net->ipv6.ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002986 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08002987 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
2988 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002989
2990 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
2991 sizeof(*net->ipv6.ip6_blk_hole_entry),
2992 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07002993 if (!net->ipv6.ip6_blk_hole_entry)
2994 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002995 net->ipv6.ip6_blk_hole_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002996 (struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002997 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08002998 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
2999 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003000#endif
3001
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07003002 net->ipv6.sysctl.flush_delay = 0;
3003 net->ipv6.sysctl.ip6_rt_max_size = 4096;
3004 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
3005 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
3006 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
3007 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
3008 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
3009 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
3010
Benjamin Thery6891a342008-03-04 13:49:47 -08003011 net->ipv6.ip6_rt_gc_expire = 30*HZ;
3012
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003013 ret = 0;
3014out:
3015 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003016
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003017#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3018out_ip6_prohibit_entry:
3019 kfree(net->ipv6.ip6_prohibit_entry);
3020out_ip6_null_entry:
3021 kfree(net->ipv6.ip6_null_entry);
3022#endif
Eric Dumazetfc66f952010-10-08 06:37:34 +00003023out_ip6_dst_entries:
3024 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003025out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003026 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003027}
3028
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003029static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003030{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003031 kfree(net->ipv6.ip6_null_entry);
3032#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3033 kfree(net->ipv6.ip6_prohibit_entry);
3034 kfree(net->ipv6.ip6_blk_hole_entry);
3035#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003036 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003037}
3038
Thomas Grafd1896342012-06-18 12:08:33 +00003039static int __net_init ip6_route_net_init_late(struct net *net)
3040{
3041#ifdef CONFIG_PROC_FS
Gao fengd4beaa62013-02-18 01:34:54 +00003042 proc_create("ipv6_route", 0, net->proc_net, &ipv6_route_proc_fops);
3043 proc_create("rt6_stats", S_IRUGO, net->proc_net, &rt6_stats_seq_fops);
Thomas Grafd1896342012-06-18 12:08:33 +00003044#endif
3045 return 0;
3046}
3047
3048static void __net_exit ip6_route_net_exit_late(struct net *net)
3049{
3050#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00003051 remove_proc_entry("ipv6_route", net->proc_net);
3052 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00003053#endif
3054}
3055
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003056static struct pernet_operations ip6_route_net_ops = {
3057 .init = ip6_route_net_init,
3058 .exit = ip6_route_net_exit,
3059};
3060
David S. Millerc3426b42012-06-09 16:27:05 -07003061static int __net_init ipv6_inetpeer_init(struct net *net)
3062{
3063 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
3064
3065 if (!bp)
3066 return -ENOMEM;
3067 inet_peer_base_init(bp);
3068 net->ipv6.peers = bp;
3069 return 0;
3070}
3071
3072static void __net_exit ipv6_inetpeer_exit(struct net *net)
3073{
3074 struct inet_peer_base *bp = net->ipv6.peers;
3075
3076 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07003077 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07003078 kfree(bp);
3079}
3080
David S. Miller2b823f72012-06-09 19:00:16 -07003081static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07003082 .init = ipv6_inetpeer_init,
3083 .exit = ipv6_inetpeer_exit,
3084};
3085
Thomas Grafd1896342012-06-18 12:08:33 +00003086static struct pernet_operations ip6_route_net_late_ops = {
3087 .init = ip6_route_net_init_late,
3088 .exit = ip6_route_net_exit_late,
3089};
3090
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003091static struct notifier_block ip6_route_dev_notifier = {
3092 .notifier_call = ip6_route_dev_notify,
3093 .priority = 0,
3094};
3095
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003096int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003098 int ret;
3099
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003100 ret = -ENOMEM;
3101 ip6_dst_ops_template.kmem_cachep =
3102 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
3103 SLAB_HWCACHE_ALIGN, NULL);
3104 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08003105 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07003106
Eric Dumazetfc66f952010-10-08 06:37:34 +00003107 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003108 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003109 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003110
David S. Millerc3426b42012-06-09 16:27:05 -07003111 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
3112 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003113 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00003114
David S. Miller7e52b332012-06-15 15:51:55 -07003115 ret = register_pernet_subsys(&ip6_route_net_ops);
3116 if (ret)
3117 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07003118
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07003119 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
3120
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003121 /* Registering of the loopback is done before this portion of code,
3122 * the loopback reference in rt6_info will not be taken, do it
3123 * manually for init_net */
Changli Gaod8d1f302010-06-10 23:31:35 -07003124 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003125 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3126 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07003127 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003128 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07003129 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003130 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3131 #endif
David S. Millere8803b62012-06-16 01:12:19 -07003132 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003133 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003134 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003135
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003136 ret = xfrm6_init();
3137 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07003138 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08003139
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003140 ret = fib6_rules_init();
3141 if (ret)
3142 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08003143
Thomas Grafd1896342012-06-18 12:08:33 +00003144 ret = register_pernet_subsys(&ip6_route_net_late_ops);
3145 if (ret)
3146 goto fib6_rules_init;
3147
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003148 ret = -ENOBUFS;
Greg Rosec7ac8672011-06-10 01:27:09 +00003149 if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) ||
3150 __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) ||
3151 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL))
Thomas Grafd1896342012-06-18 12:08:33 +00003152 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003153
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003154 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003155 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00003156 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003157
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003158out:
3159 return ret;
3160
Thomas Grafd1896342012-06-18 12:08:33 +00003161out_register_late_subsys:
3162 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003163fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003164 fib6_rules_cleanup();
3165xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003166 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00003167out_fib6_init:
3168 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003169out_register_subsys:
3170 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07003171out_register_inetpeer:
3172 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00003173out_dst_entries:
3174 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003175out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003176 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003177 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178}
3179
3180void ip6_route_cleanup(void)
3181{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003182 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00003183 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07003184 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07003187 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003188 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003189 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003190 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191}