blob: 17a9b8687f2927d354b57884cf10af50d5349e03 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
61#include <asm/uaccess.h>
62
63#ifdef CONFIG_SYSCTL
64#include <linux/sysctl.h>
65#endif
66
Gao feng1716a962012-04-06 00:13:10 +000067static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
Eric Dumazet21efcfa2011-07-19 20:18:36 +000068 const struct in6_addr *dest);
Linus Torvalds1da177e2005-04-16 15:20:36 -070069static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
David S. Miller0dbaee32010-12-13 12:52:14 -080070static unsigned int ip6_default_advmss(const struct dst_entry *dst);
Steffen Klassertebb762f2011-11-23 02:12:51 +000071static unsigned int ip6_mtu(const struct dst_entry *dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -070072static struct dst_entry *ip6_negative_advice(struct dst_entry *);
73static void ip6_dst_destroy(struct dst_entry *);
74static void ip6_dst_ifdown(struct dst_entry *,
75 struct net_device *dev, int how);
Daniel Lezcano569d3642008-01-18 03:56:57 -080076static int ip6_dst_gc(struct dst_ops *ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
78static int ip6_pkt_discard(struct sk_buff *skb);
79static int ip6_pkt_discard_out(struct sk_buff *skb);
80static void ip6_link_failure(struct sk_buff *skb);
81static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
82
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -080083#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -080084static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +000085 const struct in6_addr *prefix, int prefixlen,
86 const struct in6_addr *gwaddr, int ifindex,
Eric Dumazet95c96172012-04-15 05:58:06 +000087 unsigned int pref);
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -080088static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +000089 const struct in6_addr *prefix, int prefixlen,
90 const struct in6_addr *gwaddr, int ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -080091#endif
92
David S. Miller06582542011-01-27 14:58:42 -080093static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
94{
95 struct rt6_info *rt = (struct rt6_info *) dst;
96 struct inet_peer *peer;
97 u32 *p = NULL;
98
Yan, Zheng8e2ec632011-09-05 21:34:30 +000099 if (!(rt->dst.flags & DST_HOST))
100 return NULL;
101
David S. Millerfbfe95a2012-06-08 23:24:18 -0700102 peer = rt6_get_peer_create(rt);
David S. Miller06582542011-01-27 14:58:42 -0800103 if (peer) {
104 u32 *old_p = __DST_METRICS_PTR(old);
105 unsigned long prev, new;
106
107 p = peer->metrics;
108 if (inet_metrics_new(peer))
109 memcpy(p, old_p, sizeof(u32) * RTAX_MAX);
110
111 new = (unsigned long) p;
112 prev = cmpxchg(&dst->_metrics, old, new);
113
114 if (prev != old) {
115 p = __DST_METRICS_PTR(prev);
116 if (prev & DST_METRICS_READ_ONLY)
117 p = NULL;
118 }
119 }
120 return p;
121}
122
David S. Miller39232972012-01-26 15:22:32 -0500123static inline const void *choose_neigh_daddr(struct rt6_info *rt, const void *daddr)
124{
125 struct in6_addr *p = &rt->rt6i_gateway;
126
David S. Millera7563f32012-01-26 16:29:16 -0500127 if (!ipv6_addr_any(p))
David S. Miller39232972012-01-26 15:22:32 -0500128 return (const void *) p;
129 return daddr;
130}
131
David S. Millerd3aaeb32011-07-18 00:40:17 -0700132static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst, const void *daddr)
133{
David S. Miller39232972012-01-26 15:22:32 -0500134 struct rt6_info *rt = (struct rt6_info *) dst;
135 struct neighbour *n;
136
137 daddr = choose_neigh_daddr(rt, daddr);
138 n = __ipv6_neigh_lookup(&nd_tbl, dst->dev, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500139 if (n)
140 return n;
141 return neigh_create(&nd_tbl, daddr, dst->dev);
142}
143
David S. Miller8ade06c2011-12-29 18:51:57 -0500144static int rt6_bind_neighbour(struct rt6_info *rt, struct net_device *dev)
David S. Millerf83c7792011-12-28 15:41:23 -0500145{
David S. Miller8ade06c2011-12-29 18:51:57 -0500146 struct neighbour *n = __ipv6_neigh_lookup(&nd_tbl, dev, &rt->rt6i_gateway);
147 if (!n) {
148 n = neigh_create(&nd_tbl, &rt->rt6i_gateway, dev);
149 if (IS_ERR(n))
150 return PTR_ERR(n);
151 }
David S. Millerf83c7792011-12-28 15:41:23 -0500152 dst_set_neighbour(&rt->dst, n);
153
154 return 0;
David S. Millerd3aaeb32011-07-18 00:40:17 -0700155}
156
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -0800157static struct dst_ops ip6_dst_ops_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 .family = AF_INET6,
Harvey Harrison09640e62009-02-01 00:45:17 -0800159 .protocol = cpu_to_be16(ETH_P_IPV6),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 .gc = ip6_dst_gc,
161 .gc_thresh = 1024,
162 .check = ip6_dst_check,
David S. Miller0dbaee32010-12-13 12:52:14 -0800163 .default_advmss = ip6_default_advmss,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000164 .mtu = ip6_mtu,
David S. Miller06582542011-01-27 14:58:42 -0800165 .cow_metrics = ipv6_cow_metrics,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 .destroy = ip6_dst_destroy,
167 .ifdown = ip6_dst_ifdown,
168 .negative_advice = ip6_negative_advice,
169 .link_failure = ip6_link_failure,
170 .update_pmtu = ip6_rt_update_pmtu,
Herbert Xu1ac06e02008-05-20 14:32:14 -0700171 .local_out = __ip6_local_out,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700172 .neigh_lookup = ip6_neigh_lookup,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173};
174
Steffen Klassertebb762f2011-11-23 02:12:51 +0000175static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
Roland Dreierec831ea2011-01-31 13:16:00 -0800176{
Steffen Klassert618f9bc2011-11-23 02:13:31 +0000177 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
178
179 return mtu ? : dst->dev->mtu;
Roland Dreierec831ea2011-01-31 13:16:00 -0800180}
181
David S. Miller14e50e52007-05-24 18:17:54 -0700182static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
183{
184}
185
Held Bernhard0972ddb2011-04-24 22:07:32 +0000186static u32 *ip6_rt_blackhole_cow_metrics(struct dst_entry *dst,
187 unsigned long old)
188{
189 return NULL;
190}
191
David S. Miller14e50e52007-05-24 18:17:54 -0700192static struct dst_ops ip6_dst_blackhole_ops = {
193 .family = AF_INET6,
Harvey Harrison09640e62009-02-01 00:45:17 -0800194 .protocol = cpu_to_be16(ETH_P_IPV6),
David S. Miller14e50e52007-05-24 18:17:54 -0700195 .destroy = ip6_dst_destroy,
196 .check = ip6_dst_check,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000197 .mtu = ip6_blackhole_mtu,
Eric Dumazet214f45c2011-02-18 11:39:01 -0800198 .default_advmss = ip6_default_advmss,
David S. Miller14e50e52007-05-24 18:17:54 -0700199 .update_pmtu = ip6_rt_blackhole_update_pmtu,
Held Bernhard0972ddb2011-04-24 22:07:32 +0000200 .cow_metrics = ip6_rt_blackhole_cow_metrics,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700201 .neigh_lookup = ip6_neigh_lookup,
David S. Miller14e50e52007-05-24 18:17:54 -0700202};
203
David S. Miller62fa8a82011-01-26 20:51:05 -0800204static const u32 ip6_template_metrics[RTAX_MAX] = {
205 [RTAX_HOPLIMIT - 1] = 255,
206};
207
Daniel Lezcanobdb32892008-03-04 13:48:10 -0800208static struct rt6_info ip6_null_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700209 .dst = {
210 .__refcnt = ATOMIC_INIT(1),
211 .__use = 1,
212 .obsolete = -1,
213 .error = -ENETUNREACH,
Changli Gaod8d1f302010-06-10 23:31:35 -0700214 .input = ip6_pkt_discard,
215 .output = ip6_pkt_discard_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 },
217 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700218 .rt6i_protocol = RTPROT_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 .rt6i_metric = ~(u32) 0,
220 .rt6i_ref = ATOMIC_INIT(1),
221};
222
Thomas Graf101367c2006-08-04 03:39:02 -0700223#ifdef CONFIG_IPV6_MULTIPLE_TABLES
224
David S. Miller6723ab52006-10-18 21:20:57 -0700225static int ip6_pkt_prohibit(struct sk_buff *skb);
226static int ip6_pkt_prohibit_out(struct sk_buff *skb);
David S. Miller6723ab52006-10-18 21:20:57 -0700227
Adrian Bunk280a34c2008-04-21 02:29:32 -0700228static struct rt6_info ip6_prohibit_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700229 .dst = {
230 .__refcnt = ATOMIC_INIT(1),
231 .__use = 1,
232 .obsolete = -1,
233 .error = -EACCES,
Changli Gaod8d1f302010-06-10 23:31:35 -0700234 .input = ip6_pkt_prohibit,
235 .output = ip6_pkt_prohibit_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700236 },
237 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700238 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700239 .rt6i_metric = ~(u32) 0,
240 .rt6i_ref = ATOMIC_INIT(1),
241};
242
Daniel Lezcanobdb32892008-03-04 13:48:10 -0800243static struct rt6_info ip6_blk_hole_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700244 .dst = {
245 .__refcnt = ATOMIC_INIT(1),
246 .__use = 1,
247 .obsolete = -1,
248 .error = -EINVAL,
Changli Gaod8d1f302010-06-10 23:31:35 -0700249 .input = dst_discard,
250 .output = dst_discard,
Thomas Graf101367c2006-08-04 03:39:02 -0700251 },
252 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700253 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700254 .rt6i_metric = ~(u32) 0,
255 .rt6i_ref = ATOMIC_INIT(1),
256};
257
258#endif
259
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260/* allocate dst with ip6_dst_ops */
David S. Miller97bab732012-06-09 22:36:36 -0700261static inline struct rt6_info *ip6_dst_alloc(struct net *net,
David S. Miller957c6652011-06-24 15:25:00 -0700262 struct net_device *dev,
263 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264{
David S. Miller97bab732012-06-09 22:36:36 -0700265 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
266 0, 0, flags);
David S. Millercf911662011-04-28 14:31:47 -0700267
David S. Miller97bab732012-06-09 22:36:36 -0700268 if (rt) {
Madalin Bucurfbe58182011-09-26 07:04:56 +0000269 memset(&rt->rt6i_table, 0,
David S. Miller38308472011-12-03 18:02:47 -0500270 sizeof(*rt) - sizeof(struct dst_entry));
David S. Miller97bab732012-06-09 22:36:36 -0700271 rt6_init_peer(rt, net->ipv6.peers);
272 }
David S. Millercf911662011-04-28 14:31:47 -0700273 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274}
275
276static void ip6_dst_destroy(struct dst_entry *dst)
277{
278 struct rt6_info *rt = (struct rt6_info *)dst;
279 struct inet6_dev *idev = rt->rt6i_idev;
280
Yan, Zheng8e2ec632011-09-05 21:34:30 +0000281 if (!(rt->dst.flags & DST_HOST))
282 dst_destroy_metrics_generic(dst);
283
David S. Miller38308472011-12-03 18:02:47 -0500284 if (idev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 rt->rt6i_idev = NULL;
286 in6_dev_put(idev);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900287 }
Gao feng1716a962012-04-06 00:13:10 +0000288
289 if (!(rt->rt6i_flags & RTF_EXPIRES) && dst->from)
290 dst_release(dst->from);
291
David S. Miller97bab732012-06-09 22:36:36 -0700292 if (rt6_has_peer(rt)) {
293 struct inet_peer *peer = rt6_peer_ptr(rt);
David S. Millerb3419362010-11-30 12:27:11 -0800294 inet_putpeer(peer);
295 }
296}
297
David S. Miller6431cbc2011-02-07 20:38:06 -0800298static atomic_t __rt6_peer_genid = ATOMIC_INIT(0);
299
300static u32 rt6_peer_genid(void)
301{
302 return atomic_read(&__rt6_peer_genid);
303}
304
David S. Millerb3419362010-11-30 12:27:11 -0800305void rt6_bind_peer(struct rt6_info *rt, int create)
306{
David S. Miller97bab732012-06-09 22:36:36 -0700307 struct inet_peer_base *base;
David S. Millerb3419362010-11-30 12:27:11 -0800308 struct inet_peer *peer;
309
David S. Miller97bab732012-06-09 22:36:36 -0700310 base = inetpeer_base_ptr(rt->_rt6i_peer);
311 if (!base)
312 return;
313
314 peer = inet_getpeer_v6(base, &rt->rt6i_dst.addr, create);
315 if (!rt6_set_peer(rt, peer))
David S. Millerb3419362010-11-30 12:27:11 -0800316 inet_putpeer(peer);
David S. Miller6431cbc2011-02-07 20:38:06 -0800317 else
318 rt->rt6i_peer_genid = rt6_peer_genid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319}
320
321static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
322 int how)
323{
324 struct rt6_info *rt = (struct rt6_info *)dst;
325 struct inet6_dev *idev = rt->rt6i_idev;
Denis V. Lunev5a3e55d2007-12-07 00:38:10 -0800326 struct net_device *loopback_dev =
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900327 dev_net(dev)->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
David S. Miller38308472011-12-03 18:02:47 -0500329 if (dev != loopback_dev && idev && idev->dev == dev) {
Denis V. Lunev5a3e55d2007-12-07 00:38:10 -0800330 struct inet6_dev *loopback_idev =
331 in6_dev_get(loopback_dev);
David S. Miller38308472011-12-03 18:02:47 -0500332 if (loopback_idev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 rt->rt6i_idev = loopback_idev;
334 in6_dev_put(idev);
335 }
336 }
337}
338
Eric Dumazeta50feda2012-05-18 18:57:34 +0000339static bool rt6_check_expired(const struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340{
Gao feng1716a962012-04-06 00:13:10 +0000341 struct rt6_info *ort = NULL;
342
343 if (rt->rt6i_flags & RTF_EXPIRES) {
344 if (time_after(jiffies, rt->dst.expires))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000345 return true;
Gao feng1716a962012-04-06 00:13:10 +0000346 } else if (rt->dst.from) {
347 ort = (struct rt6_info *) rt->dst.from;
348 return (ort->rt6i_flags & RTF_EXPIRES) &&
349 time_after(jiffies, ort->dst.expires);
350 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000351 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352}
353
Eric Dumazeta50feda2012-05-18 18:57:34 +0000354static bool rt6_need_strict(const struct in6_addr *daddr)
Thomas Grafc71099a2006-08-04 23:20:06 -0700355{
Eric Dumazeta02cec22010-09-22 20:43:57 +0000356 return ipv6_addr_type(daddr) &
357 (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK);
Thomas Grafc71099a2006-08-04 23:20:06 -0700358}
359
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360/*
Thomas Grafc71099a2006-08-04 23:20:06 -0700361 * Route lookup. Any table->tb6_lock is implied.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 */
363
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800364static inline struct rt6_info *rt6_device_match(struct net *net,
365 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000366 const struct in6_addr *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 int oif,
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700368 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369{
370 struct rt6_info *local = NULL;
371 struct rt6_info *sprt;
372
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900373 if (!oif && ipv6_addr_any(saddr))
374 goto out;
375
Changli Gaod8d1f302010-06-10 23:31:35 -0700376 for (sprt = rt; sprt; sprt = sprt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -0500377 struct net_device *dev = sprt->dst.dev;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900378
379 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 if (dev->ifindex == oif)
381 return sprt;
382 if (dev->flags & IFF_LOOPBACK) {
David S. Miller38308472011-12-03 18:02:47 -0500383 if (!sprt->rt6i_idev ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 sprt->rt6i_idev->dev->ifindex != oif) {
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700385 if (flags & RT6_LOOKUP_F_IFACE && oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 continue;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900387 if (local && (!oif ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 local->rt6i_idev->dev->ifindex == oif))
389 continue;
390 }
391 local = sprt;
392 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900393 } else {
394 if (ipv6_chk_addr(net, saddr, dev,
395 flags & RT6_LOOKUP_F_IFACE))
396 return sprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900398 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900400 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 if (local)
402 return local;
403
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700404 if (flags & RT6_LOOKUP_F_IFACE)
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800405 return net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900407out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 return rt;
409}
410
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800411#ifdef CONFIG_IPV6_ROUTER_PREF
412static void rt6_probe(struct rt6_info *rt)
413{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000414 struct neighbour *neigh;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800415 /*
416 * Okay, this does not seem to be appropriate
417 * for now, however, we need to check if it
418 * is really so; aka Router Reachability Probing.
419 *
420 * Router Reachability Probe MUST be rate-limited
421 * to no more than one per minute.
422 */
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000423 rcu_read_lock();
David Miller27217452011-12-02 16:52:08 +0000424 neigh = rt ? dst_get_neighbour_noref(&rt->dst) : NULL;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800425 if (!neigh || (neigh->nud_state & NUD_VALID))
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000426 goto out;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800427 read_lock_bh(&neigh->lock);
428 if (!(neigh->nud_state & NUD_VALID) &&
YOSHIFUJI Hideaki52e16352006-03-20 17:05:47 -0800429 time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) {
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800430 struct in6_addr mcaddr;
431 struct in6_addr *target;
432
433 neigh->updated = jiffies;
434 read_unlock_bh(&neigh->lock);
435
436 target = (struct in6_addr *)&neigh->primary_key;
437 addrconf_addr_solict_mult(target, &mcaddr);
David S. Millerd1918542011-12-28 20:19:20 -0500438 ndisc_send_ns(rt->dst.dev, NULL, target, &mcaddr, NULL);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000439 } else {
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800440 read_unlock_bh(&neigh->lock);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000441 }
442out:
443 rcu_read_unlock();
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800444}
445#else
446static inline void rt6_probe(struct rt6_info *rt)
447{
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800448}
449#endif
450
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451/*
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800452 * Default Router Selection (RFC 2461 6.3.6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 */
Dave Jonesb6f99a22007-03-22 12:27:49 -0700454static inline int rt6_check_dev(struct rt6_info *rt, int oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455{
David S. Millerd1918542011-12-28 20:19:20 -0500456 struct net_device *dev = rt->dst.dev;
David S. Miller161980f2007-04-06 11:42:27 -0700457 if (!oif || dev->ifindex == oif)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800458 return 2;
David S. Miller161980f2007-04-06 11:42:27 -0700459 if ((dev->flags & IFF_LOOPBACK) &&
460 rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
461 return 1;
462 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463}
464
Dave Jonesb6f99a22007-03-22 12:27:49 -0700465static inline int rt6_check_neigh(struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000467 struct neighbour *neigh;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800468 int m;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000469
470 rcu_read_lock();
David Miller27217452011-12-02 16:52:08 +0000471 neigh = dst_get_neighbour_noref(&rt->dst);
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700472 if (rt->rt6i_flags & RTF_NONEXTHOP ||
473 !(rt->rt6i_flags & RTF_GATEWAY))
474 m = 1;
475 else if (neigh) {
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800476 read_lock_bh(&neigh->lock);
477 if (neigh->nud_state & NUD_VALID)
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700478 m = 2;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800479#ifdef CONFIG_IPV6_ROUTER_PREF
480 else if (neigh->nud_state & NUD_FAILED)
481 m = 0;
482#endif
483 else
YOSHIFUJI Hideakiea73ee22006-11-06 09:45:44 -0800484 m = 1;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800485 read_unlock_bh(&neigh->lock);
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800486 } else
487 m = 0;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000488 rcu_read_unlock();
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800489 return m;
490}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800492static int rt6_score_route(struct rt6_info *rt, int oif,
493 int strict)
494{
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700495 int m, n;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900496
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700497 m = rt6_check_dev(rt, oif);
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700498 if (!m && (strict & RT6_LOOKUP_F_IFACE))
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800499 return -1;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800500#ifdef CONFIG_IPV6_ROUTER_PREF
501 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
502#endif
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700503 n = rt6_check_neigh(rt);
YOSHIFUJI Hideaki557e92e2006-11-06 09:45:45 -0800504 if (!n && (strict & RT6_LOOKUP_F_REACHABLE))
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800505 return -1;
506 return m;
507}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
David S. Millerf11e6652007-03-24 20:36:25 -0700509static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
510 int *mpri, struct rt6_info *match)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800511{
David S. Millerf11e6652007-03-24 20:36:25 -0700512 int m;
513
514 if (rt6_check_expired(rt))
515 goto out;
516
517 m = rt6_score_route(rt, oif, strict);
518 if (m < 0)
519 goto out;
520
521 if (m > *mpri) {
522 if (strict & RT6_LOOKUP_F_REACHABLE)
523 rt6_probe(match);
524 *mpri = m;
525 match = rt;
526 } else if (strict & RT6_LOOKUP_F_REACHABLE) {
527 rt6_probe(rt);
528 }
529
530out:
531 return match;
532}
533
534static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
535 struct rt6_info *rr_head,
536 u32 metric, int oif, int strict)
537{
538 struct rt6_info *rt, *match;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800539 int mpri = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
David S. Millerf11e6652007-03-24 20:36:25 -0700541 match = NULL;
542 for (rt = rr_head; rt && rt->rt6i_metric == metric;
Changli Gaod8d1f302010-06-10 23:31:35 -0700543 rt = rt->dst.rt6_next)
David S. Millerf11e6652007-03-24 20:36:25 -0700544 match = find_match(rt, oif, strict, &mpri, match);
545 for (rt = fn->leaf; rt && rt != rr_head && rt->rt6i_metric == metric;
Changli Gaod8d1f302010-06-10 23:31:35 -0700546 rt = rt->dst.rt6_next)
David S. Millerf11e6652007-03-24 20:36:25 -0700547 match = find_match(rt, oif, strict, &mpri, match);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800548
David S. Millerf11e6652007-03-24 20:36:25 -0700549 return match;
550}
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800551
David S. Millerf11e6652007-03-24 20:36:25 -0700552static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
553{
554 struct rt6_info *match, *rt0;
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800555 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
David S. Millerf11e6652007-03-24 20:36:25 -0700557 rt0 = fn->rr_ptr;
558 if (!rt0)
559 fn->rr_ptr = rt0 = fn->leaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560
David S. Millerf11e6652007-03-24 20:36:25 -0700561 match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800563 if (!match &&
David S. Millerf11e6652007-03-24 20:36:25 -0700564 (strict & RT6_LOOKUP_F_REACHABLE)) {
Changli Gaod8d1f302010-06-10 23:31:35 -0700565 struct rt6_info *next = rt0->dst.rt6_next;
David S. Millerf11e6652007-03-24 20:36:25 -0700566
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800567 /* no entries matched; do round-robin */
David S. Millerf11e6652007-03-24 20:36:25 -0700568 if (!next || next->rt6i_metric != rt0->rt6i_metric)
569 next = fn->leaf;
570
571 if (next != rt0)
572 fn->rr_ptr = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 }
574
David S. Millerd1918542011-12-28 20:19:20 -0500575 net = dev_net(rt0->dst.dev);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000576 return match ? match : net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577}
578
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800579#ifdef CONFIG_IPV6_ROUTE_INFO
580int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000581 const struct in6_addr *gwaddr)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800582{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900583 struct net *net = dev_net(dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800584 struct route_info *rinfo = (struct route_info *) opt;
585 struct in6_addr prefix_buf, *prefix;
586 unsigned int pref;
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900587 unsigned long lifetime;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800588 struct rt6_info *rt;
589
590 if (len < sizeof(struct route_info)) {
591 return -EINVAL;
592 }
593
594 /* Sanity check for prefix_len and length */
595 if (rinfo->length > 3) {
596 return -EINVAL;
597 } else if (rinfo->prefix_len > 128) {
598 return -EINVAL;
599 } else if (rinfo->prefix_len > 64) {
600 if (rinfo->length < 2) {
601 return -EINVAL;
602 }
603 } else if (rinfo->prefix_len > 0) {
604 if (rinfo->length < 1) {
605 return -EINVAL;
606 }
607 }
608
609 pref = rinfo->route_pref;
610 if (pref == ICMPV6_ROUTER_PREF_INVALID)
Jens Rosenboom3933fc92009-09-10 06:25:11 +0000611 return -EINVAL;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800612
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900613 lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800614
615 if (rinfo->length == 3)
616 prefix = (struct in6_addr *)rinfo->prefix;
617 else {
618 /* this function is safe */
619 ipv6_addr_prefix(&prefix_buf,
620 (struct in6_addr *)rinfo->prefix,
621 rinfo->prefix_len);
622 prefix = &prefix_buf;
623 }
624
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800625 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, gwaddr,
626 dev->ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800627
628 if (rt && !lifetime) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -0700629 ip6_del_rt(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800630 rt = NULL;
631 }
632
633 if (!rt && lifetime)
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800634 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800635 pref);
636 else if (rt)
637 rt->rt6i_flags = RTF_ROUTEINFO |
638 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
639
640 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +0000641 if (!addrconf_finite_timeout(lifetime))
642 rt6_clean_expires(rt);
643 else
644 rt6_set_expires(rt, jiffies + HZ * lifetime);
645
Changli Gaod8d1f302010-06-10 23:31:35 -0700646 dst_release(&rt->dst);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800647 }
648 return 0;
649}
650#endif
651
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800652#define BACKTRACK(__net, saddr) \
YOSHIFUJI Hideaki982f56f2006-08-23 17:22:39 -0700653do { \
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800654 if (rt == __net->ipv6.ip6_null_entry) { \
YOSHIFUJI Hideaki982f56f2006-08-23 17:22:39 -0700655 struct fib6_node *pn; \
Ville Nuorvalae0eda7b2006-10-16 22:11:11 -0700656 while (1) { \
YOSHIFUJI Hideaki982f56f2006-08-23 17:22:39 -0700657 if (fn->fn_flags & RTN_TL_ROOT) \
658 goto out; \
659 pn = fn->parent; \
660 if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn) \
Kim Nordlund8bce65b2006-12-13 16:38:29 -0800661 fn = fib6_lookup(FIB6_SUBTREE(pn), NULL, saddr); \
YOSHIFUJI Hideaki982f56f2006-08-23 17:22:39 -0700662 else \
663 fn = pn; \
664 if (fn->fn_flags & RTN_RTINFO) \
665 goto restart; \
Thomas Grafc71099a2006-08-04 23:20:06 -0700666 } \
Thomas Grafc71099a2006-08-04 23:20:06 -0700667 } \
David S. Miller38308472011-12-03 18:02:47 -0500668} while (0)
Thomas Grafc71099a2006-08-04 23:20:06 -0700669
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800670static struct rt6_info *ip6_pol_route_lookup(struct net *net,
671 struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500672 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673{
674 struct fib6_node *fn;
675 struct rt6_info *rt;
676
Thomas Grafc71099a2006-08-04 23:20:06 -0700677 read_lock_bh(&table->tb6_lock);
David S. Miller4c9483b2011-03-12 16:22:43 -0500678 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -0700679restart:
680 rt = fn->leaf;
David S. Miller4c9483b2011-03-12 16:22:43 -0500681 rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags);
682 BACKTRACK(net, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -0700683out:
Changli Gaod8d1f302010-06-10 23:31:35 -0700684 dst_use(&rt->dst, jiffies);
Thomas Grafc71099a2006-08-04 23:20:06 -0700685 read_unlock_bh(&table->tb6_lock);
Thomas Grafc71099a2006-08-04 23:20:06 -0700686 return rt;
687
688}
689
Florian Westphalea6e5742011-09-05 16:05:44 +0200690struct dst_entry * ip6_route_lookup(struct net *net, struct flowi6 *fl6,
691 int flags)
692{
693 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup);
694}
695EXPORT_SYMBOL_GPL(ip6_route_lookup);
696
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900697struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
698 const struct in6_addr *saddr, int oif, int strict)
Thomas Grafc71099a2006-08-04 23:20:06 -0700699{
David S. Miller4c9483b2011-03-12 16:22:43 -0500700 struct flowi6 fl6 = {
701 .flowi6_oif = oif,
702 .daddr = *daddr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700703 };
704 struct dst_entry *dst;
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700705 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
Thomas Grafc71099a2006-08-04 23:20:06 -0700706
Thomas Grafadaa70b2006-10-13 15:01:03 -0700707 if (saddr) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500708 memcpy(&fl6.saddr, saddr, sizeof(*saddr));
Thomas Grafadaa70b2006-10-13 15:01:03 -0700709 flags |= RT6_LOOKUP_F_HAS_SADDR;
710 }
711
David S. Miller4c9483b2011-03-12 16:22:43 -0500712 dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup);
Thomas Grafc71099a2006-08-04 23:20:06 -0700713 if (dst->error == 0)
714 return (struct rt6_info *) dst;
715
716 dst_release(dst);
717
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 return NULL;
719}
720
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900721EXPORT_SYMBOL(rt6_lookup);
722
Thomas Grafc71099a2006-08-04 23:20:06 -0700723/* ip6_ins_rt is called with FREE table->tb6_lock.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 It takes new route entry, the addition fails by any reason the
725 route is freed. In any case, if caller does not hold it, it may
726 be destroyed.
727 */
728
Thomas Graf86872cb2006-08-22 00:01:08 -0700729static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730{
731 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -0700732 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
Thomas Grafc71099a2006-08-04 23:20:06 -0700734 table = rt->rt6i_table;
735 write_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -0700736 err = fib6_add(&table->tb6_root, rt, info);
Thomas Grafc71099a2006-08-04 23:20:06 -0700737 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
739 return err;
740}
741
Thomas Graf40e22e82006-08-22 00:00:45 -0700742int ip6_ins_rt(struct rt6_info *rt)
743{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -0800744 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -0500745 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -0800746 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -0800747 return __ip6_ins_rt(rt, &info);
Thomas Graf40e22e82006-08-22 00:00:45 -0700748}
749
Gao feng1716a962012-04-06 00:13:10 +0000750static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort,
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000751 const struct in6_addr *daddr,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000752 const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 struct rt6_info *rt;
755
756 /*
757 * Clone the route.
758 */
759
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000760 rt = ip6_rt_copy(ort, daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
762 if (rt) {
David S. Miller14deae42009-01-04 16:04:39 -0800763 int attempts = !in_softirq();
764
David S. Miller38308472011-12-03 18:02:47 -0500765 if (!(rt->rt6i_flags & RTF_GATEWAY)) {
David S. Millerbb3c3682011-12-13 17:35:06 -0500766 if (ort->rt6i_dst.plen != 128 &&
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000767 ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +0900768 rt->rt6i_flags |= RTF_ANYCAST;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000769 rt->rt6i_gateway = *daddr;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +0900770 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 rt->rt6i_flags |= RTF_CACHE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773
774#ifdef CONFIG_IPV6_SUBTREES
775 if (rt->rt6i_src.plen && saddr) {
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000776 rt->rt6i_src.addr = *saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 rt->rt6i_src.plen = 128;
778 }
779#endif
780
David S. Miller14deae42009-01-04 16:04:39 -0800781 retry:
David S. Miller8ade06c2011-12-29 18:51:57 -0500782 if (rt6_bind_neighbour(rt, rt->dst.dev)) {
David S. Millerd1918542011-12-28 20:19:20 -0500783 struct net *net = dev_net(rt->dst.dev);
David S. Miller14deae42009-01-04 16:04:39 -0800784 int saved_rt_min_interval =
785 net->ipv6.sysctl.ip6_rt_gc_min_interval;
786 int saved_rt_elasticity =
787 net->ipv6.sysctl.ip6_rt_gc_elasticity;
788
789 if (attempts-- > 0) {
790 net->ipv6.sysctl.ip6_rt_gc_elasticity = 1;
791 net->ipv6.sysctl.ip6_rt_gc_min_interval = 0;
792
Alexey Dobriyan86393e52009-08-29 01:34:49 +0000793 ip6_dst_gc(&net->ipv6.ip6_dst_ops);
David S. Miller14deae42009-01-04 16:04:39 -0800794
795 net->ipv6.sysctl.ip6_rt_gc_elasticity =
796 saved_rt_elasticity;
797 net->ipv6.sysctl.ip6_rt_gc_min_interval =
798 saved_rt_min_interval;
799 goto retry;
800 }
801
Joe Perchesf3213832012-05-15 14:11:53 +0000802 net_warn_ratelimited("Neighbour table overflow\n");
Changli Gaod8d1f302010-06-10 23:31:35 -0700803 dst_free(&rt->dst);
David S. Miller14deae42009-01-04 16:04:39 -0800804 return NULL;
805 }
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800806 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -0800808 return rt;
809}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000811static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort,
812 const struct in6_addr *daddr)
YOSHIFUJI Hideaki299d9932006-03-20 16:58:32 -0800813{
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000814 struct rt6_info *rt = ip6_rt_copy(ort, daddr);
815
YOSHIFUJI Hideaki299d9932006-03-20 16:58:32 -0800816 if (rt) {
YOSHIFUJI Hideaki299d9932006-03-20 16:58:32 -0800817 rt->rt6i_flags |= RTF_CACHE;
David Miller27217452011-12-02 16:52:08 +0000818 dst_set_neighbour(&rt->dst, neigh_clone(dst_get_neighbour_noref_raw(&ort->dst)));
YOSHIFUJI Hideaki299d9932006-03-20 16:58:32 -0800819 }
820 return rt;
821}
822
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800823static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif,
David S. Miller4c9483b2011-03-12 16:22:43 -0500824 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825{
826 struct fib6_node *fn;
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800827 struct rt6_info *rt, *nrt;
Thomas Grafc71099a2006-08-04 23:20:06 -0700828 int strict = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 int attempts = 3;
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800830 int err;
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -0700831 int reachable = net->ipv6.devconf_all->forwarding ? 0 : RT6_LOOKUP_F_REACHABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700833 strict |= flags & RT6_LOOKUP_F_IFACE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834
835relookup:
Thomas Grafc71099a2006-08-04 23:20:06 -0700836 read_lock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
YOSHIFUJI Hideaki8238dd02006-03-20 17:04:35 -0800838restart_2:
David S. Miller4c9483b2011-03-12 16:22:43 -0500839 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
841restart:
Pavel Emelyanov4acad722007-10-15 13:02:51 -0700842 rt = rt6_select(fn, oif, strict | reachable);
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800843
David S. Miller4c9483b2011-03-12 16:22:43 -0500844 BACKTRACK(net, &fl6->saddr);
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800845 if (rt == net->ipv6.ip6_null_entry ||
YOSHIFUJI Hideaki8238dd02006-03-20 17:04:35 -0800846 rt->rt6i_flags & RTF_CACHE)
YOSHIFUJI Hideaki1ddef0442006-03-20 17:01:24 -0800847 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848
Changli Gaod8d1f302010-06-10 23:31:35 -0700849 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -0700850 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -0800851
David Miller27217452011-12-02 16:52:08 +0000852 if (!dst_get_neighbour_noref_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP))
David S. Miller4c9483b2011-03-12 16:22:43 -0500853 nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr);
David S. Miller7343ff32011-03-09 19:55:25 -0800854 else if (!(rt->dst.flags & DST_HOST))
David S. Miller4c9483b2011-03-12 16:22:43 -0500855 nrt = rt6_alloc_clone(rt, &fl6->daddr);
David S. Miller7343ff32011-03-09 19:55:25 -0800856 else
857 goto out2;
YOSHIFUJI Hideakie40cf352006-03-20 16:59:27 -0800858
Changli Gaod8d1f302010-06-10 23:31:35 -0700859 dst_release(&rt->dst);
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800860 rt = nrt ? : net->ipv6.ip6_null_entry;
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800861
Changli Gaod8d1f302010-06-10 23:31:35 -0700862 dst_hold(&rt->dst);
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800863 if (nrt) {
Thomas Graf40e22e82006-08-22 00:00:45 -0700864 err = ip6_ins_rt(nrt);
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800865 if (!err)
866 goto out2;
867 }
868
869 if (--attempts <= 0)
870 goto out2;
871
872 /*
Thomas Grafc71099a2006-08-04 23:20:06 -0700873 * Race condition! In the gap, when table->tb6_lock was
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800874 * released someone could insert this route. Relookup.
875 */
Changli Gaod8d1f302010-06-10 23:31:35 -0700876 dst_release(&rt->dst);
YOSHIFUJI Hideaki519fbd82006-03-20 17:00:05 -0800877 goto relookup;
878
879out:
YOSHIFUJI Hideaki8238dd02006-03-20 17:04:35 -0800880 if (reachable) {
881 reachable = 0;
882 goto restart_2;
883 }
Changli Gaod8d1f302010-06-10 23:31:35 -0700884 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -0700885 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886out2:
Changli Gaod8d1f302010-06-10 23:31:35 -0700887 rt->dst.lastuse = jiffies;
888 rt->dst.__use++;
Thomas Grafc71099a2006-08-04 23:20:06 -0700889
890 return rt;
891}
892
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800893static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500894 struct flowi6 *fl6, int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -0700895{
David S. Miller4c9483b2011-03-12 16:22:43 -0500896 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -0700897}
898
Shmulik Ladkani72331bc2012-04-01 04:03:45 +0000899static struct dst_entry *ip6_route_input_lookup(struct net *net,
900 struct net_device *dev,
901 struct flowi6 *fl6, int flags)
902{
903 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
904 flags |= RT6_LOOKUP_F_IFACE;
905
906 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_input);
907}
908
Thomas Grafc71099a2006-08-04 23:20:06 -0700909void ip6_route_input(struct sk_buff *skb)
910{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000911 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900912 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -0700913 int flags = RT6_LOOKUP_F_HAS_SADDR;
David S. Miller4c9483b2011-03-12 16:22:43 -0500914 struct flowi6 fl6 = {
915 .flowi6_iif = skb->dev->ifindex,
916 .daddr = iph->daddr,
917 .saddr = iph->saddr,
David S. Miller38308472011-12-03 18:02:47 -0500918 .flowlabel = (* (__be32 *) iph) & IPV6_FLOWINFO_MASK,
David S. Miller4c9483b2011-03-12 16:22:43 -0500919 .flowi6_mark = skb->mark,
920 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700921 };
Thomas Grafadaa70b2006-10-13 15:01:03 -0700922
Shmulik Ladkani72331bc2012-04-01 04:03:45 +0000923 skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -0700924}
925
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800926static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500927 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -0700928{
David S. Miller4c9483b2011-03-12 16:22:43 -0500929 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -0700930}
931
Florian Westphal9c7a4f92011-03-22 19:17:36 -0700932struct dst_entry * ip6_route_output(struct net *net, const struct sock *sk,
David S. Miller4c9483b2011-03-12 16:22:43 -0500933 struct flowi6 *fl6)
Thomas Grafc71099a2006-08-04 23:20:06 -0700934{
935 int flags = 0;
936
David S. Miller4c9483b2011-03-12 16:22:43 -0500937 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700938 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -0700939
David S. Miller4c9483b2011-03-12 16:22:43 -0500940 if (!ipv6_addr_any(&fl6->saddr))
Thomas Grafadaa70b2006-10-13 15:01:03 -0700941 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +0000942 else if (sk)
943 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -0700944
David S. Miller4c9483b2011-03-12 16:22:43 -0500945 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946}
947
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900948EXPORT_SYMBOL(ip6_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
David S. Miller2774c132011-03-01 14:59:04 -0800950struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -0700951{
David S. Miller5c1e6aa2011-04-28 14:13:38 -0700952 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
David S. Miller14e50e52007-05-24 18:17:54 -0700953 struct dst_entry *new = NULL;
954
David S. Miller5c1e6aa2011-04-28 14:13:38 -0700955 rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, 0, 0);
David S. Miller14e50e52007-05-24 18:17:54 -0700956 if (rt) {
David S. Millercf911662011-04-28 14:31:47 -0700957 memset(&rt->rt6i_table, 0, sizeof(*rt) - sizeof(struct dst_entry));
David S. Miller97bab732012-06-09 22:36:36 -0700958 rt6_init_peer(rt, net->ipv6.peers);
David S. Millercf911662011-04-28 14:31:47 -0700959
Changli Gaod8d1f302010-06-10 23:31:35 -0700960 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -0700961
David S. Miller14e50e52007-05-24 18:17:54 -0700962 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -0800963 new->input = dst_discard;
964 new->output = dst_discard;
David S. Miller14e50e52007-05-24 18:17:54 -0700965
Eric Dumazet21efcfa2011-07-19 20:18:36 +0000966 if (dst_metrics_read_only(&ort->dst))
967 new->_metrics = ort->dst._metrics;
968 else
969 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -0700970 rt->rt6i_idev = ort->rt6i_idev;
971 if (rt->rt6i_idev)
972 in6_dev_hold(rt->rt6i_idev);
David S. Miller14e50e52007-05-24 18:17:54 -0700973
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000974 rt->rt6i_gateway = ort->rt6i_gateway;
Gao feng1716a962012-04-06 00:13:10 +0000975 rt->rt6i_flags = ort->rt6i_flags;
976 rt6_clean_expires(rt);
David S. Miller14e50e52007-05-24 18:17:54 -0700977 rt->rt6i_metric = 0;
978
979 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
980#ifdef CONFIG_IPV6_SUBTREES
981 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
982#endif
983
984 dst_free(new);
985 }
986
David S. Miller69ead7a2011-03-01 14:45:33 -0800987 dst_release(dst_orig);
988 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -0700989}
David S. Miller14e50e52007-05-24 18:17:54 -0700990
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991/*
992 * Destination cache support functions
993 */
994
995static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
996{
997 struct rt6_info *rt;
998
999 rt = (struct rt6_info *) dst;
1000
David S. Miller6431cbc2011-02-07 20:38:06 -08001001 if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) {
1002 if (rt->rt6i_peer_genid != rt6_peer_genid()) {
David S. Miller97bab732012-06-09 22:36:36 -07001003 if (!rt6_has_peer(rt))
David S. Miller6431cbc2011-02-07 20:38:06 -08001004 rt6_bind_peer(rt, 0);
1005 rt->rt6i_peer_genid = rt6_peer_genid();
1006 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 return dst;
David S. Miller6431cbc2011-02-07 20:38:06 -08001008 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 return NULL;
1010}
1011
1012static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
1013{
1014 struct rt6_info *rt = (struct rt6_info *) dst;
1015
1016 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001017 if (rt->rt6i_flags & RTF_CACHE) {
1018 if (rt6_check_expired(rt)) {
1019 ip6_del_rt(rt);
1020 dst = NULL;
1021 }
1022 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001024 dst = NULL;
1025 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001027 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028}
1029
1030static void ip6_link_failure(struct sk_buff *skb)
1031{
1032 struct rt6_info *rt;
1033
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00001034 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035
Eric Dumazetadf30902009-06-02 05:19:30 +00001036 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +00001038 if (rt->rt6i_flags & RTF_CACHE)
1039 rt6_update_expires(rt, 0);
1040 else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 rt->rt6i_node->fn_sernum = -1;
1042 }
1043}
1044
1045static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
1046{
1047 struct rt6_info *rt6 = (struct rt6_info*)dst;
1048
1049 if (mtu < dst_mtu(dst) && rt6->rt6i_dst.plen == 128) {
1050 rt6->rt6i_flags |= RTF_MODIFIED;
1051 if (mtu < IPV6_MIN_MTU) {
David S. Millerdefb3512010-12-08 21:16:57 -08001052 u32 features = dst_metric(dst, RTAX_FEATURES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 mtu = IPV6_MIN_MTU;
David S. Millerdefb3512010-12-08 21:16:57 -08001054 features |= RTAX_FEATURE_ALLFRAG;
1055 dst_metric_set(dst, RTAX_FEATURES, features);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 }
David S. Millerdefb3512010-12-08 21:16:57 -08001057 dst_metric_set(dst, RTAX_MTU, mtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 }
1059}
1060
David S. Miller0dbaee32010-12-13 12:52:14 -08001061static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062{
David S. Miller0dbaee32010-12-13 12:52:14 -08001063 struct net_device *dev = dst->dev;
1064 unsigned int mtu = dst_mtu(dst);
1065 struct net *net = dev_net(dev);
1066
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
1068
Daniel Lezcano55786892008-03-04 13:47:47 -08001069 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
1070 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
1072 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001073 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
1074 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
1075 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 * rely only on pmtu discovery"
1077 */
1078 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
1079 mtu = IPV6_MAXPLEN;
1080 return mtu;
1081}
1082
Steffen Klassertebb762f2011-11-23 02:12:51 +00001083static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08001084{
David S. Millerd33e4552010-12-14 13:01:14 -08001085 struct inet6_dev *idev;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001086 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
1087
1088 if (mtu)
1089 return mtu;
1090
1091 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08001092
1093 rcu_read_lock();
1094 idev = __in6_dev_get(dst->dev);
1095 if (idev)
1096 mtu = idev->cnf.mtu6;
1097 rcu_read_unlock();
1098
1099 return mtu;
1100}
1101
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001102static struct dst_entry *icmp6_dst_gc_list;
1103static DEFINE_SPINLOCK(icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001104
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001105struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 struct neighbour *neigh,
David S. Miller87a11572011-12-06 17:04:13 -05001107 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108{
David S. Miller87a11572011-12-06 17:04:13 -05001109 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 struct rt6_info *rt;
1111 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001112 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113
David S. Miller38308472011-12-03 18:02:47 -05001114 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00001115 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116
David S. Miller97bab732012-06-09 22:36:36 -07001117 rt = ip6_dst_alloc(net, dev, 0);
David S. Miller38308472011-12-03 18:02:47 -05001118 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05001120 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 goto out;
1122 }
1123
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 if (neigh)
1125 neigh_hold(neigh);
David S. Miller14deae42009-01-04 16:04:39 -08001126 else {
David S. Millerf83c7792011-12-28 15:41:23 -05001127 neigh = ip6_neigh_lookup(&rt->dst, &fl6->daddr);
David S. Millerb43faac2011-12-13 16:48:21 -05001128 if (IS_ERR(neigh)) {
RongQing.Li252c3d82012-01-12 22:33:46 +00001129 in6_dev_put(idev);
David S. Millerb43faac2011-12-13 16:48:21 -05001130 dst_free(&rt->dst);
1131 return ERR_CAST(neigh);
1132 }
David S. Miller14deae42009-01-04 16:04:39 -08001133 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001135 rt->dst.flags |= DST_HOST;
1136 rt->dst.output = ip6_output;
David S. Miller69cce1d2011-07-17 23:09:49 -07001137 dst_set_neighbour(&rt->dst, neigh);
Changli Gaod8d1f302010-06-10 23:31:35 -07001138 atomic_set(&rt->dst.__refcnt, 1);
David S. Miller87a11572011-12-06 17:04:13 -05001139 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001140 rt->rt6i_dst.plen = 128;
1141 rt->rt6i_idev = idev;
Gao feng70116872011-10-28 02:46:57 +00001142 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001144 spin_lock_bh(&icmp6_dst_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001145 rt->dst.next = icmp6_dst_gc_list;
1146 icmp6_dst_gc_list = &rt->dst;
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001147 spin_unlock_bh(&icmp6_dst_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148
Daniel Lezcano55786892008-03-04 13:47:47 -08001149 fib6_force_start_gc(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
David S. Miller87a11572011-12-06 17:04:13 -05001151 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
1152
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153out:
David S. Miller87a11572011-12-06 17:04:13 -05001154 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155}
1156
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001157int icmp6_dst_gc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158{
Hagen Paul Pfeifere9476e92011-02-25 05:45:19 +00001159 struct dst_entry *dst, **pprev;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001160 int more = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001162 spin_lock_bh(&icmp6_dst_lock);
1163 pprev = &icmp6_dst_gc_list;
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001164
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 while ((dst = *pprev) != NULL) {
1166 if (!atomic_read(&dst->__refcnt)) {
1167 *pprev = dst->next;
1168 dst_free(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 } else {
1170 pprev = &dst->next;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001171 ++more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 }
1173 }
1174
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001175 spin_unlock_bh(&icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001176
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001177 return more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178}
1179
David S. Miller1e493d12008-09-10 17:27:15 -07001180static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg),
1181 void *arg)
1182{
1183 struct dst_entry *dst, **pprev;
1184
1185 spin_lock_bh(&icmp6_dst_lock);
1186 pprev = &icmp6_dst_gc_list;
1187 while ((dst = *pprev) != NULL) {
1188 struct rt6_info *rt = (struct rt6_info *) dst;
1189 if (func(rt, arg)) {
1190 *pprev = dst->next;
1191 dst_free(dst);
1192 } else {
1193 pprev = &dst->next;
1194 }
1195 }
1196 spin_unlock_bh(&icmp6_dst_lock);
1197}
1198
Daniel Lezcano569d3642008-01-18 03:56:57 -08001199static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 unsigned long now = jiffies;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00001202 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08001203 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
1204 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
1205 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
1206 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
1207 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001208 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209
Eric Dumazetfc66f952010-10-08 06:37:34 +00001210 entries = dst_entries_get_fast(ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08001211 if (time_after(rt_last_gc + rt_min_interval, now) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00001212 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 goto out;
1214
Benjamin Thery6891a342008-03-04 13:49:47 -08001215 net->ipv6.ip6_rt_gc_expire++;
1216 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net);
1217 net->ipv6.ip6_rt_last_gc = now;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001218 entries = dst_entries_get_slow(ops);
1219 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08001220 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08001222 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001223 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224}
1225
1226/* Clean host part of a prefix. Not necessary in radix tree,
1227 but results in cleaner routing tables.
1228
1229 Remove it only when all the things will work!
1230 */
1231
YOSHIFUJI Hideaki6b75d092008-03-10 06:00:30 -04001232int ip6_dst_hoplimit(struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233{
David S. Miller5170ae82010-12-12 21:35:57 -08001234 int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT);
David S. Millera02e4b72010-12-12 21:39:02 -08001235 if (hoplimit == 0) {
YOSHIFUJI Hideaki6b75d092008-03-10 06:00:30 -04001236 struct net_device *dev = dst->dev;
Eric Dumazetc68f24c2010-06-14 04:46:20 +00001237 struct inet6_dev *idev;
1238
1239 rcu_read_lock();
1240 idev = __in6_dev_get(dev);
1241 if (idev)
YOSHIFUJI Hideaki6b75d092008-03-10 06:00:30 -04001242 hoplimit = idev->cnf.hop_limit;
Eric Dumazetc68f24c2010-06-14 04:46:20 +00001243 else
YOSHIFUJI Hideaki53b79972008-07-19 22:35:03 -07001244 hoplimit = dev_net(dev)->ipv6.devconf_all->hop_limit;
Eric Dumazetc68f24c2010-06-14 04:46:20 +00001245 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 }
1247 return hoplimit;
1248}
David S. Millerabbf46a2010-12-12 21:14:46 -08001249EXPORT_SYMBOL(ip6_dst_hoplimit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250
1251/*
1252 *
1253 */
1254
Thomas Graf86872cb2006-08-22 00:01:08 -07001255int ip6_route_add(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256{
1257 int err;
Daniel Lezcano55786892008-03-04 13:47:47 -08001258 struct net *net = cfg->fc_nlinfo.nl_net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 struct rt6_info *rt = NULL;
1260 struct net_device *dev = NULL;
1261 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001262 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 int addr_type;
1264
Thomas Graf86872cb2006-08-22 00:01:08 -07001265 if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 return -EINVAL;
1267#ifndef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001268 if (cfg->fc_src_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 return -EINVAL;
1270#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07001271 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08001273 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 if (!dev)
1275 goto out;
1276 idev = in6_dev_get(dev);
1277 if (!idev)
1278 goto out;
1279 }
1280
Thomas Graf86872cb2006-08-22 00:01:08 -07001281 if (cfg->fc_metric == 0)
1282 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283
Matti Vaittinend71314b2011-11-14 00:14:49 +00001284 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05001285 if (cfg->fc_nlinfo.nlh &&
1286 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00001287 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001288 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00001289 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00001290 table = fib6_new_table(net, cfg->fc_table);
1291 }
1292 } else {
1293 table = fib6_new_table(net, cfg->fc_table);
1294 }
David S. Miller38308472011-12-03 18:02:47 -05001295
1296 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001297 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07001298
David S. Miller97bab732012-06-09 22:36:36 -07001299 rt = ip6_dst_alloc(net, NULL, DST_NOCOUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
David S. Miller38308472011-12-03 18:02:47 -05001301 if (!rt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 err = -ENOMEM;
1303 goto out;
1304 }
1305
Changli Gaod8d1f302010-06-10 23:31:35 -07001306 rt->dst.obsolete = -1;
Gao feng1716a962012-04-06 00:13:10 +00001307
1308 if (cfg->fc_flags & RTF_EXPIRES)
1309 rt6_set_expires(rt, jiffies +
1310 clock_t_to_jiffies(cfg->fc_expires));
1311 else
1312 rt6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313
Thomas Graf86872cb2006-08-22 00:01:08 -07001314 if (cfg->fc_protocol == RTPROT_UNSPEC)
1315 cfg->fc_protocol = RTPROT_BOOT;
1316 rt->rt6i_protocol = cfg->fc_protocol;
1317
1318 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319
1320 if (addr_type & IPV6_ADDR_MULTICAST)
Changli Gaod8d1f302010-06-10 23:31:35 -07001321 rt->dst.input = ip6_mc_input;
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00001322 else if (cfg->fc_flags & RTF_LOCAL)
1323 rt->dst.input = ip6_input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 else
Changli Gaod8d1f302010-06-10 23:31:35 -07001325 rt->dst.input = ip6_forward;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326
Changli Gaod8d1f302010-06-10 23:31:35 -07001327 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328
Thomas Graf86872cb2006-08-22 00:01:08 -07001329 ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
1330 rt->rt6i_dst.plen = cfg->fc_dst_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 if (rt->rt6i_dst.plen == 128)
David S. Miller11d53b42011-06-24 15:23:34 -07001332 rt->dst.flags |= DST_HOST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001334 if (!(rt->dst.flags & DST_HOST) && cfg->fc_mx) {
1335 u32 *metrics = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
1336 if (!metrics) {
1337 err = -ENOMEM;
1338 goto out;
1339 }
1340 dst_init_metrics(&rt->dst, metrics, 0);
1341 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342#ifdef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001343 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
1344 rt->rt6i_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345#endif
1346
Thomas Graf86872cb2006-08-22 00:01:08 -07001347 rt->rt6i_metric = cfg->fc_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348
1349 /* We cannot add true routes via loopback here,
1350 they would result in kernel looping; promote them to reject routes
1351 */
Thomas Graf86872cb2006-08-22 00:01:08 -07001352 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05001353 (dev && (dev->flags & IFF_LOOPBACK) &&
1354 !(addr_type & IPV6_ADDR_LOOPBACK) &&
1355 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08001357 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 if (dev) {
1359 dev_put(dev);
1360 in6_dev_put(idev);
1361 }
Daniel Lezcano55786892008-03-04 13:47:47 -08001362 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 dev_hold(dev);
1364 idev = in6_dev_get(dev);
1365 if (!idev) {
1366 err = -ENODEV;
1367 goto out;
1368 }
1369 }
Changli Gaod8d1f302010-06-10 23:31:35 -07001370 rt->dst.output = ip6_pkt_discard_out;
1371 rt->dst.input = ip6_pkt_discard;
1372 rt->dst.error = -ENETUNREACH;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
1374 goto install_route;
1375 }
1376
Thomas Graf86872cb2006-08-22 00:01:08 -07001377 if (cfg->fc_flags & RTF_GATEWAY) {
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001378 const struct in6_addr *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 int gwa_type;
1380
Thomas Graf86872cb2006-08-22 00:01:08 -07001381 gw_addr = &cfg->fc_gateway;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001382 rt->rt6i_gateway = *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 gwa_type = ipv6_addr_type(gw_addr);
1384
1385 if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
1386 struct rt6_info *grt;
1387
1388 /* IPv6 strictly inhibits using not link-local
1389 addresses as nexthop address.
1390 Otherwise, router will not able to send redirects.
1391 It is very good, but in some (rare!) circumstances
1392 (SIT, PtP, NBMA NOARP links) it is handy to allow
1393 some exceptions. --ANK
1394 */
1395 err = -EINVAL;
David S. Miller38308472011-12-03 18:02:47 -05001396 if (!(gwa_type & IPV6_ADDR_UNICAST))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 goto out;
1398
Daniel Lezcano55786892008-03-04 13:47:47 -08001399 grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400
1401 err = -EHOSTUNREACH;
David S. Miller38308472011-12-03 18:02:47 -05001402 if (!grt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 goto out;
1404 if (dev) {
David S. Millerd1918542011-12-28 20:19:20 -05001405 if (dev != grt->dst.dev) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001406 dst_release(&grt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 goto out;
1408 }
1409 } else {
David S. Millerd1918542011-12-28 20:19:20 -05001410 dev = grt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 idev = grt->rt6i_idev;
1412 dev_hold(dev);
1413 in6_dev_hold(grt->rt6i_idev);
1414 }
David S. Miller38308472011-12-03 18:02:47 -05001415 if (!(grt->rt6i_flags & RTF_GATEWAY))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 err = 0;
Changli Gaod8d1f302010-06-10 23:31:35 -07001417 dst_release(&grt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418
1419 if (err)
1420 goto out;
1421 }
1422 err = -EINVAL;
David S. Miller38308472011-12-03 18:02:47 -05001423 if (!dev || (dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 goto out;
1425 }
1426
1427 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05001428 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 goto out;
1430
Daniel Walterc3968a82011-04-13 21:10:57 +00001431 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
1432 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
1433 err = -EINVAL;
1434 goto out;
1435 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001436 rt->rt6i_prefsrc.addr = cfg->fc_prefsrc;
Daniel Walterc3968a82011-04-13 21:10:57 +00001437 rt->rt6i_prefsrc.plen = 128;
1438 } else
1439 rt->rt6i_prefsrc.plen = 0;
1440
Thomas Graf86872cb2006-08-22 00:01:08 -07001441 if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) {
David S. Miller8ade06c2011-12-29 18:51:57 -05001442 err = rt6_bind_neighbour(rt, dev);
David S. Millerf83c7792011-12-28 15:41:23 -05001443 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 }
1446
Thomas Graf86872cb2006-08-22 00:01:08 -07001447 rt->rt6i_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448
1449install_route:
Thomas Graf86872cb2006-08-22 00:01:08 -07001450 if (cfg->fc_mx) {
1451 struct nlattr *nla;
1452 int remaining;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453
Thomas Graf86872cb2006-08-22 00:01:08 -07001454 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
Thomas Graf8f4c1f92007-09-12 14:44:36 +02001455 int type = nla_type(nla);
Thomas Graf86872cb2006-08-22 00:01:08 -07001456
1457 if (type) {
1458 if (type > RTAX_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 err = -EINVAL;
1460 goto out;
1461 }
Thomas Graf86872cb2006-08-22 00:01:08 -07001462
David S. Millerdefb3512010-12-08 21:16:57 -08001463 dst_metric_set(&rt->dst, type, nla_get_u32(nla));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 }
1466 }
1467
Changli Gaod8d1f302010-06-10 23:31:35 -07001468 rt->dst.dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 rt->rt6i_idev = idev;
Thomas Grafc71099a2006-08-04 23:20:06 -07001470 rt->rt6i_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001471
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001472 cfg->fc_nlinfo.nl_net = dev_net(dev);
Daniel Lezcano63152fc2008-03-03 23:31:11 -08001473
Thomas Graf86872cb2006-08-22 00:01:08 -07001474 return __ip6_ins_rt(rt, &cfg->fc_nlinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475
1476out:
1477 if (dev)
1478 dev_put(dev);
1479 if (idev)
1480 in6_dev_put(idev);
1481 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07001482 dst_free(&rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 return err;
1484}
1485
Thomas Graf86872cb2006-08-22 00:01:08 -07001486static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487{
1488 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07001489 struct fib6_table *table;
David S. Millerd1918542011-12-28 20:19:20 -05001490 struct net *net = dev_net(rt->dst.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001492 if (rt == net->ipv6.ip6_null_entry)
Patrick McHardy6c813a72006-08-06 22:22:47 -07001493 return -ENOENT;
1494
Thomas Grafc71099a2006-08-04 23:20:06 -07001495 table = rt->rt6i_table;
1496 write_lock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497
Thomas Graf86872cb2006-08-22 00:01:08 -07001498 err = fib6_del(rt, info);
Changli Gaod8d1f302010-06-10 23:31:35 -07001499 dst_release(&rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500
Thomas Grafc71099a2006-08-04 23:20:06 -07001501 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502
1503 return err;
1504}
1505
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001506int ip6_del_rt(struct rt6_info *rt)
1507{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08001508 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -05001509 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08001510 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08001511 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001512}
1513
Thomas Graf86872cb2006-08-22 00:01:08 -07001514static int ip6_route_del(struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515{
Thomas Grafc71099a2006-08-04 23:20:06 -07001516 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 struct fib6_node *fn;
1518 struct rt6_info *rt;
1519 int err = -ESRCH;
1520
Daniel Lezcano55786892008-03-04 13:47:47 -08001521 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001522 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001523 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524
Thomas Grafc71099a2006-08-04 23:20:06 -07001525 read_lock_bh(&table->tb6_lock);
1526
1527 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07001528 &cfg->fc_dst, cfg->fc_dst_len,
1529 &cfg->fc_src, cfg->fc_src_len);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001530
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 if (fn) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001532 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
Thomas Graf86872cb2006-08-22 00:01:08 -07001533 if (cfg->fc_ifindex &&
David S. Millerd1918542011-12-28 20:19:20 -05001534 (!rt->dst.dev ||
1535 rt->dst.dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001537 if (cfg->fc_flags & RTF_GATEWAY &&
1538 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07001540 if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07001542 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07001543 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544
Thomas Graf86872cb2006-08-22 00:01:08 -07001545 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 }
1547 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001548 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549
1550 return err;
1551}
1552
1553/*
1554 * Handle redirects
1555 */
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001556struct ip6rd_flowi {
David S. Miller4c9483b2011-03-12 16:22:43 -05001557 struct flowi6 fl6;
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001558 struct in6_addr gateway;
1559};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001561static struct rt6_info *__ip6_route_redirect(struct net *net,
1562 struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -05001563 struct flowi6 *fl6,
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001564 int flags)
1565{
David S. Miller4c9483b2011-03-12 16:22:43 -05001566 struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001567 struct rt6_info *rt;
1568 struct fib6_node *fn;
Thomas Grafc71099a2006-08-04 23:20:06 -07001569
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 /*
YOSHIFUJI Hideakie843b9e2006-03-20 17:07:49 -08001571 * Get the "current" route for this destination and
1572 * check if the redirect has come from approriate router.
1573 *
1574 * RFC 2461 specifies that redirects should only be
1575 * accepted if they come from the nexthop to the target.
1576 * Due to the way the routes are chosen, this notion
1577 * is a bit fuzzy and one might need to check all possible
1578 * routes.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580
Thomas Grafc71099a2006-08-04 23:20:06 -07001581 read_lock_bh(&table->tb6_lock);
David S. Miller4c9483b2011-03-12 16:22:43 -05001582 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
YOSHIFUJI Hideakie843b9e2006-03-20 17:07:49 -08001583restart:
Changli Gaod8d1f302010-06-10 23:31:35 -07001584 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
YOSHIFUJI Hideakie843b9e2006-03-20 17:07:49 -08001585 /*
1586 * Current route is on-link; redirect is always invalid.
1587 *
1588 * Seems, previous statement is not true. It could
1589 * be node, which looks for us as on-link (f.e. proxy ndisc)
1590 * But then router serving it might decide, that we should
1591 * know truth 8)8) --ANK (980726).
1592 */
1593 if (rt6_check_expired(rt))
1594 continue;
1595 if (!(rt->rt6i_flags & RTF_GATEWAY))
1596 continue;
David S. Millerd1918542011-12-28 20:19:20 -05001597 if (fl6->flowi6_oif != rt->dst.dev->ifindex)
YOSHIFUJI Hideakie843b9e2006-03-20 17:07:49 -08001598 continue;
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001599 if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway))
YOSHIFUJI Hideakie843b9e2006-03-20 17:07:49 -08001600 continue;
1601 break;
1602 }
YOSHIFUJI Hideakie843b9e2006-03-20 17:07:49 -08001603
YOSHIFUJI Hideakicb15d9c2006-08-23 17:23:11 -07001604 if (!rt)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001605 rt = net->ipv6.ip6_null_entry;
David S. Miller4c9483b2011-03-12 16:22:43 -05001606 BACKTRACK(net, &fl6->saddr);
YOSHIFUJI Hideakicb15d9c2006-08-23 17:23:11 -07001607out:
Changli Gaod8d1f302010-06-10 23:31:35 -07001608 dst_hold(&rt->dst);
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001609
1610 read_unlock_bh(&table->tb6_lock);
1611
1612 return rt;
1613};
1614
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001615static struct rt6_info *ip6_route_redirect(const struct in6_addr *dest,
1616 const struct in6_addr *src,
1617 const struct in6_addr *gateway,
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001618 struct net_device *dev)
1619{
Thomas Grafadaa70b2006-10-13 15:01:03 -07001620 int flags = RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001621 struct net *net = dev_net(dev);
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001622 struct ip6rd_flowi rdfl = {
David S. Miller4c9483b2011-03-12 16:22:43 -05001623 .fl6 = {
1624 .flowi6_oif = dev->ifindex,
1625 .daddr = *dest,
1626 .saddr = *src,
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001627 },
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001628 };
Thomas Grafadaa70b2006-10-13 15:01:03 -07001629
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001630 rdfl.gateway = *gateway;
Brian Haley86c36ce2009-10-07 13:58:01 -07001631
Thomas Grafadaa70b2006-10-13 15:01:03 -07001632 if (rt6_need_strict(dest))
1633 flags |= RT6_LOOKUP_F_IFACE;
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001634
David S. Miller4c9483b2011-03-12 16:22:43 -05001635 return (struct rt6_info *)fib6_rule_lookup(net, &rdfl.fl6,
Daniel Lezcano58f09b72008-03-03 23:25:27 -08001636 flags, __ip6_route_redirect);
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001637}
1638
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001639void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src,
1640 const struct in6_addr *saddr,
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001641 struct neighbour *neigh, u8 *lladdr, int on_link)
1642{
1643 struct rt6_info *rt, *nrt = NULL;
1644 struct netevent_redirect netevent;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001645 struct net *net = dev_net(neigh->dev);
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001646
1647 rt = ip6_route_redirect(dest, src, saddr, neigh->dev);
1648
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001649 if (rt == net->ipv6.ip6_null_entry) {
Joe Perchese87cc472012-05-13 21:56:26 +00001650 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07001651 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 }
1653
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 /*
1655 * We have finally decided to accept it.
1656 */
1657
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001658 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 NEIGH_UPDATE_F_WEAK_OVERRIDE|
1660 NEIGH_UPDATE_F_OVERRIDE|
1661 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
1662 NEIGH_UPDATE_F_ISROUTER))
1663 );
1664
1665 /*
1666 * Redirect received -> path was valid.
1667 * Look, redirects are sent only in response to data packets,
1668 * so that this nexthop apparently is reachable. --ANK
1669 */
Changli Gaod8d1f302010-06-10 23:31:35 -07001670 dst_confirm(&rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671
1672 /* Duplicate redirect: silently ignore. */
David Miller27217452011-12-02 16:52:08 +00001673 if (neigh == dst_get_neighbour_noref_raw(&rt->dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 goto out;
1675
Eric Dumazet21efcfa2011-07-19 20:18:36 +00001676 nrt = ip6_rt_copy(rt, dest);
David S. Miller38308472011-12-03 18:02:47 -05001677 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 goto out;
1679
1680 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
1681 if (on_link)
1682 nrt->rt6i_flags &= ~RTF_GATEWAY;
1683
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001684 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
David S. Miller69cce1d2011-07-17 23:09:49 -07001685 dst_set_neighbour(&nrt->dst, neigh_clone(neigh));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686
Thomas Graf40e22e82006-08-22 00:00:45 -07001687 if (ip6_ins_rt(nrt))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 goto out;
1689
Changli Gaod8d1f302010-06-10 23:31:35 -07001690 netevent.old = &rt->dst;
1691 netevent.new = &nrt->dst;
Tom Tucker8d717402006-07-30 20:43:36 -07001692 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
1693
David S. Miller38308472011-12-03 18:02:47 -05001694 if (rt->rt6i_flags & RTF_CACHE) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001695 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 return;
1697 }
1698
1699out:
Changli Gaod8d1f302010-06-10 23:31:35 -07001700 dst_release(&rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701}
1702
1703/*
1704 * Handle ICMP "packet too big" messages
1705 * i.e. Path MTU discovery
1706 */
1707
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001708static void rt6_do_pmtu_disc(const struct in6_addr *daddr, const struct in6_addr *saddr,
Maciej Żenczykowskiae878ae2010-10-03 14:49:00 -07001709 struct net *net, u32 pmtu, int ifindex)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710{
1711 struct rt6_info *rt, *nrt;
1712 int allfrag = 0;
Andrey Vagind3052b52010-12-11 15:20:11 +00001713again:
Maciej Żenczykowskiae878ae2010-10-03 14:49:00 -07001714 rt = rt6_lookup(net, daddr, saddr, ifindex, 0);
David S. Miller38308472011-12-03 18:02:47 -05001715 if (!rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 return;
1717
Andrey Vagind3052b52010-12-11 15:20:11 +00001718 if (rt6_check_expired(rt)) {
1719 ip6_del_rt(rt);
1720 goto again;
1721 }
1722
Changli Gaod8d1f302010-06-10 23:31:35 -07001723 if (pmtu >= dst_mtu(&rt->dst))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 goto out;
1725
1726 if (pmtu < IPV6_MIN_MTU) {
1727 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001728 * According to RFC2460, PMTU is set to the IPv6 Minimum Link
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 * MTU (1280) and a fragment header should always be included
1730 * after a node receiving Too Big message reporting PMTU is
1731 * less than the IPv6 Minimum Link MTU.
1732 */
1733 pmtu = IPV6_MIN_MTU;
1734 allfrag = 1;
1735 }
1736
1737 /* New mtu received -> path was valid.
1738 They are sent only in response to data packets,
1739 so that this nexthop apparently is reachable. --ANK
1740 */
Changli Gaod8d1f302010-06-10 23:31:35 -07001741 dst_confirm(&rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742
1743 /* Host route. If it is static, it would be better
1744 not to override it, but add new one, so that
1745 when cache entry will expire old pmtu
1746 would return automatically.
1747 */
1748 if (rt->rt6i_flags & RTF_CACHE) {
David S. Millerdefb3512010-12-08 21:16:57 -08001749 dst_metric_set(&rt->dst, RTAX_MTU, pmtu);
1750 if (allfrag) {
1751 u32 features = dst_metric(&rt->dst, RTAX_FEATURES);
1752 features |= RTAX_FEATURE_ALLFRAG;
1753 dst_metric_set(&rt->dst, RTAX_FEATURES, features);
1754 }
Gao feng1716a962012-04-06 00:13:10 +00001755 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
1756 rt->rt6i_flags |= RTF_MODIFIED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 goto out;
1758 }
1759
1760 /* Network route.
1761 Two cases are possible:
1762 1. It is connected route. Action: COW
1763 2. It is gatewayed route or NONEXTHOP route. Action: clone it.
1764 */
David Miller27217452011-12-02 16:52:08 +00001765 if (!dst_get_neighbour_noref_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP))
YOSHIFUJI Hideakia1e78362006-03-20 16:56:32 -08001766 nrt = rt6_alloc_cow(rt, daddr, saddr);
YOSHIFUJI Hideakid5315b52006-03-20 16:58:48 -08001767 else
1768 nrt = rt6_alloc_clone(rt, daddr);
YOSHIFUJI Hideakia1e78362006-03-20 16:56:32 -08001769
YOSHIFUJI Hideakid5315b52006-03-20 16:58:48 -08001770 if (nrt) {
David S. Millerdefb3512010-12-08 21:16:57 -08001771 dst_metric_set(&nrt->dst, RTAX_MTU, pmtu);
1772 if (allfrag) {
1773 u32 features = dst_metric(&nrt->dst, RTAX_FEATURES);
1774 features |= RTAX_FEATURE_ALLFRAG;
1775 dst_metric_set(&nrt->dst, RTAX_FEATURES, features);
1776 }
YOSHIFUJI Hideakia1e78362006-03-20 16:56:32 -08001777
1778 /* According to RFC 1981, detecting PMTU increase shouldn't be
1779 * happened within 5 mins, the recommended timer is 10 mins.
1780 * Here this route expiration time is set to ip6_rt_mtu_expires
1781 * which is 10 mins. After 10 mins the decreased pmtu is expired
1782 * and detecting PMTU increase will be automatically happened.
1783 */
Gao feng1716a962012-04-06 00:13:10 +00001784 rt6_update_expires(nrt, net->ipv6.sysctl.ip6_rt_mtu_expires);
1785 nrt->rt6i_flags |= RTF_DYNAMIC;
Thomas Graf40e22e82006-08-22 00:00:45 -07001786 ip6_ins_rt(nrt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788out:
Changli Gaod8d1f302010-06-10 23:31:35 -07001789 dst_release(&rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790}
1791
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001792void rt6_pmtu_discovery(const struct in6_addr *daddr, const struct in6_addr *saddr,
Maciej Żenczykowskiae878ae2010-10-03 14:49:00 -07001793 struct net_device *dev, u32 pmtu)
1794{
1795 struct net *net = dev_net(dev);
1796
1797 /*
1798 * RFC 1981 states that a node "MUST reduce the size of the packets it
1799 * is sending along the path" that caused the Packet Too Big message.
1800 * Since it's not possible in the general case to determine which
1801 * interface was used to send the original packet, we update the MTU
1802 * on the interface that will be used to send future packets. We also
1803 * update the MTU on the interface that received the Packet Too Big in
1804 * case the original packet was forced out that interface with
1805 * SO_BINDTODEVICE or similar. This is the next best thing to the
1806 * correct behaviour, which would be to update the MTU on all
1807 * interfaces.
1808 */
1809 rt6_do_pmtu_disc(daddr, saddr, net, pmtu, 0);
1810 rt6_do_pmtu_disc(daddr, saddr, net, pmtu, dev->ifindex);
1811}
1812
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813/*
1814 * Misc support functions
1815 */
1816
Gao feng1716a962012-04-06 00:13:10 +00001817static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
Eric Dumazet21efcfa2011-07-19 20:18:36 +00001818 const struct in6_addr *dest)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819{
David S. Millerd1918542011-12-28 20:19:20 -05001820 struct net *net = dev_net(ort->dst.dev);
David S. Miller97bab732012-06-09 22:36:36 -07001821 struct rt6_info *rt = ip6_dst_alloc(net, ort->dst.dev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822
1823 if (rt) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001824 rt->dst.input = ort->dst.input;
1825 rt->dst.output = ort->dst.output;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001826 rt->dst.flags |= DST_HOST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001828 rt->rt6i_dst.addr = *dest;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001829 rt->rt6i_dst.plen = 128;
David S. Millerdefb3512010-12-08 21:16:57 -08001830 dst_copy_metrics(&rt->dst, &ort->dst);
Changli Gaod8d1f302010-06-10 23:31:35 -07001831 rt->dst.error = ort->dst.error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 rt->rt6i_idev = ort->rt6i_idev;
1833 if (rt->rt6i_idev)
1834 in6_dev_hold(rt->rt6i_idev);
Changli Gaod8d1f302010-06-10 23:31:35 -07001835 rt->dst.lastuse = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001837 rt->rt6i_gateway = ort->rt6i_gateway;
Gao feng1716a962012-04-06 00:13:10 +00001838 rt->rt6i_flags = ort->rt6i_flags;
1839 if ((ort->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) ==
1840 (RTF_DEFAULT | RTF_ADDRCONF))
1841 rt6_set_from(rt, ort);
1842 else
1843 rt6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 rt->rt6i_metric = 0;
1845
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846#ifdef CONFIG_IPV6_SUBTREES
1847 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1848#endif
Florian Westphal0f6c6392011-05-20 11:27:24 +00001849 memcpy(&rt->rt6i_prefsrc, &ort->rt6i_prefsrc, sizeof(struct rt6key));
Thomas Grafc71099a2006-08-04 23:20:06 -07001850 rt->rt6i_table = ort->rt6i_table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 }
1852 return rt;
1853}
1854
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001855#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001856static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001857 const struct in6_addr *prefix, int prefixlen,
1858 const struct in6_addr *gwaddr, int ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001859{
1860 struct fib6_node *fn;
1861 struct rt6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001862 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001863
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001864 table = fib6_get_table(net, RT6_TABLE_INFO);
David S. Miller38308472011-12-03 18:02:47 -05001865 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001866 return NULL;
1867
1868 write_lock_bh(&table->tb6_lock);
1869 fn = fib6_locate(&table->tb6_root, prefix ,prefixlen, NULL, 0);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001870 if (!fn)
1871 goto out;
1872
Changli Gaod8d1f302010-06-10 23:31:35 -07001873 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05001874 if (rt->dst.dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001875 continue;
1876 if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
1877 continue;
1878 if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
1879 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07001880 dst_hold(&rt->dst);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001881 break;
1882 }
1883out:
Thomas Grafc71099a2006-08-04 23:20:06 -07001884 write_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001885 return rt;
1886}
1887
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001888static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001889 const struct in6_addr *prefix, int prefixlen,
1890 const struct in6_addr *gwaddr, int ifindex,
Eric Dumazet95c96172012-04-15 05:58:06 +00001891 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001892{
Thomas Graf86872cb2006-08-22 00:01:08 -07001893 struct fib6_config cfg = {
1894 .fc_table = RT6_TABLE_INFO,
Rami Rosen238fc7e2008-02-09 23:43:11 -08001895 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07001896 .fc_ifindex = ifindex,
1897 .fc_dst_len = prefixlen,
1898 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
1899 RTF_UP | RTF_PREF(pref),
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001900 .fc_nlinfo.pid = 0,
1901 .fc_nlinfo.nlh = NULL,
1902 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07001903 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001904
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001905 cfg.fc_dst = *prefix;
1906 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07001907
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08001908 /* We should treat it as a default route if prefix length is 0. */
1909 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07001910 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001911
Thomas Graf86872cb2006-08-22 00:01:08 -07001912 ip6_route_add(&cfg);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001913
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08001914 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08001915}
1916#endif
1917
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001918struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001919{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001921 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001923 table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05001924 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001925 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926
Thomas Grafc71099a2006-08-04 23:20:06 -07001927 write_lock_bh(&table->tb6_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001928 for (rt = table->tb6_root.leaf; rt; rt=rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05001929 if (dev == rt->dst.dev &&
YOSHIFUJI Hideaki045927f2006-03-20 17:00:48 -08001930 ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 ipv6_addr_equal(&rt->rt6i_gateway, addr))
1932 break;
1933 }
1934 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07001935 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07001936 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 return rt;
1938}
1939
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001940struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08001941 struct net_device *dev,
1942 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943{
Thomas Graf86872cb2006-08-22 00:01:08 -07001944 struct fib6_config cfg = {
1945 .fc_table = RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08001946 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07001947 .fc_ifindex = dev->ifindex,
1948 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
1949 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Daniel Lezcano55786892008-03-04 13:47:47 -08001950 .fc_nlinfo.pid = 0,
1951 .fc_nlinfo.nlh = NULL,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001952 .fc_nlinfo.nl_net = dev_net(dev),
Thomas Graf86872cb2006-08-22 00:01:08 -07001953 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001955 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956
Thomas Graf86872cb2006-08-22 00:01:08 -07001957 ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 return rt6_get_dflt_router(gwaddr, dev);
1960}
1961
Daniel Lezcano7b4da532008-03-04 13:47:14 -08001962void rt6_purge_dflt_routers(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963{
1964 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001965 struct fib6_table *table;
1966
1967 /* NOTE: Keep consistent with rt6_get_dflt_router */
Daniel Lezcano7b4da532008-03-04 13:47:14 -08001968 table = fib6_get_table(net, RT6_TABLE_DFLT);
David S. Miller38308472011-12-03 18:02:47 -05001969 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001970 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971
1972restart:
Thomas Grafc71099a2006-08-04 23:20:06 -07001973 read_lock_bh(&table->tb6_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001974 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07001976 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07001977 read_unlock_bh(&table->tb6_lock);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07001978 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 goto restart;
1980 }
1981 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001982 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983}
1984
Daniel Lezcano55786892008-03-04 13:47:47 -08001985static void rtmsg_to_fib6_config(struct net *net,
1986 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07001987 struct fib6_config *cfg)
1988{
1989 memset(cfg, 0, sizeof(*cfg));
1990
1991 cfg->fc_table = RT6_TABLE_MAIN;
1992 cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
1993 cfg->fc_metric = rtmsg->rtmsg_metric;
1994 cfg->fc_expires = rtmsg->rtmsg_info;
1995 cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
1996 cfg->fc_src_len = rtmsg->rtmsg_src_len;
1997 cfg->fc_flags = rtmsg->rtmsg_flags;
1998
Daniel Lezcano55786892008-03-04 13:47:47 -08001999 cfg->fc_nlinfo.nl_net = net;
Benjamin Theryf1243c22008-02-26 18:10:03 -08002000
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002001 cfg->fc_dst = rtmsg->rtmsg_dst;
2002 cfg->fc_src = rtmsg->rtmsg_src;
2003 cfg->fc_gateway = rtmsg->rtmsg_gateway;
Thomas Graf86872cb2006-08-22 00:01:08 -07002004}
2005
Daniel Lezcano55786892008-03-04 13:47:47 -08002006int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007{
Thomas Graf86872cb2006-08-22 00:01:08 -07002008 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 struct in6_rtmsg rtmsg;
2010 int err;
2011
2012 switch(cmd) {
2013 case SIOCADDRT: /* Add a route */
2014 case SIOCDELRT: /* Delete a route */
2015 if (!capable(CAP_NET_ADMIN))
2016 return -EPERM;
2017 err = copy_from_user(&rtmsg, arg,
2018 sizeof(struct in6_rtmsg));
2019 if (err)
2020 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07002021
Daniel Lezcano55786892008-03-04 13:47:47 -08002022 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07002023
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 rtnl_lock();
2025 switch (cmd) {
2026 case SIOCADDRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07002027 err = ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 break;
2029 case SIOCDELRT:
Thomas Graf86872cb2006-08-22 00:01:08 -07002030 err = ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 break;
2032 default:
2033 err = -EINVAL;
2034 }
2035 rtnl_unlock();
2036
2037 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07002038 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039
2040 return -EINVAL;
2041}
2042
2043/*
2044 * Drop the packet on the floor
2045 */
2046
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07002047static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002049 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00002050 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002051 switch (ipstats_mib_noroutes) {
2052 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07002053 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00002054 if (type == IPV6_ADDR_ANY) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002055 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2056 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002057 break;
2058 }
2059 /* FALLTHROUGH */
2060 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002061 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2062 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002063 break;
2064 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002065 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 kfree_skb(skb);
2067 return 0;
2068}
2069
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002070static int ip6_pkt_discard(struct sk_buff *skb)
2071{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002072 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002073}
2074
Arnaldo Carvalho de Melo20380732005-08-16 02:18:02 -03002075static int ip6_pkt_discard_out(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076{
Eric Dumazetadf30902009-06-02 05:19:30 +00002077 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002078 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079}
2080
David S. Miller6723ab52006-10-18 21:20:57 -07002081#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2082
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002083static int ip6_pkt_prohibit(struct sk_buff *skb)
2084{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002085 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002086}
2087
2088static int ip6_pkt_prohibit_out(struct sk_buff *skb)
2089{
Eric Dumazetadf30902009-06-02 05:19:30 +00002090 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002091 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002092}
2093
David S. Miller6723ab52006-10-18 21:20:57 -07002094#endif
2095
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096/*
2097 * Allocate a dst for local (unicast / anycast) address.
2098 */
2099
2100struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
2101 const struct in6_addr *addr,
David S. Miller8f031512011-12-06 16:48:14 -05002102 bool anycast)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002104 struct net *net = dev_net(idev->dev);
David S. Miller97bab732012-06-09 22:36:36 -07002105 struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev, 0);
David S. Millerf83c7792011-12-28 15:41:23 -05002106 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107
David S. Miller38308472011-12-03 18:02:47 -05002108 if (!rt) {
Joe Perchesf3213832012-05-15 14:11:53 +00002109 net_warn_ratelimited("Maximum number of routes reached, consider increasing route/max_size\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 return ERR_PTR(-ENOMEM);
Ben Greear40385652010-11-08 12:33:48 +00002111 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 in6_dev_hold(idev);
2114
David S. Miller11d53b42011-06-24 15:23:34 -07002115 rt->dst.flags |= DST_HOST;
Changli Gaod8d1f302010-06-10 23:31:35 -07002116 rt->dst.input = ip6_input;
2117 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 rt->rt6i_idev = idev;
Changli Gaod8d1f302010-06-10 23:31:35 -07002119 rt->dst.obsolete = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120
2121 rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +09002122 if (anycast)
2123 rt->rt6i_flags |= RTF_ANYCAST;
2124 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 rt->rt6i_flags |= RTF_LOCAL;
David S. Miller8ade06c2011-12-29 18:51:57 -05002126 err = rt6_bind_neighbour(rt, rt->dst.dev);
David S. Millerf83c7792011-12-28 15:41:23 -05002127 if (err) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002128 dst_free(&rt->dst);
David S. Millerf83c7792011-12-28 15:41:23 -05002129 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 }
2131
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002132 rt->rt6i_dst.addr = *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 rt->rt6i_dst.plen = 128;
Daniel Lezcano55786892008-03-04 13:47:47 -08002134 rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135
Changli Gaod8d1f302010-06-10 23:31:35 -07002136 atomic_set(&rt->dst.__refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137
2138 return rt;
2139}
2140
Daniel Walterc3968a82011-04-13 21:10:57 +00002141int ip6_route_get_saddr(struct net *net,
2142 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002143 const struct in6_addr *daddr,
Daniel Walterc3968a82011-04-13 21:10:57 +00002144 unsigned int prefs,
2145 struct in6_addr *saddr)
2146{
2147 struct inet6_dev *idev = ip6_dst_idev((struct dst_entry*)rt);
2148 int err = 0;
2149 if (rt->rt6i_prefsrc.plen)
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002150 *saddr = rt->rt6i_prefsrc.addr;
Daniel Walterc3968a82011-04-13 21:10:57 +00002151 else
2152 err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
2153 daddr, prefs, saddr);
2154 return err;
2155}
2156
2157/* remove deleted ip from prefsrc entries */
2158struct arg_dev_net_ip {
2159 struct net_device *dev;
2160 struct net *net;
2161 struct in6_addr *addr;
2162};
2163
2164static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
2165{
2166 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
2167 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
2168 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
2169
David S. Millerd1918542011-12-28 20:19:20 -05002170 if (((void *)rt->dst.dev == dev || !dev) &&
Daniel Walterc3968a82011-04-13 21:10:57 +00002171 rt != net->ipv6.ip6_null_entry &&
2172 ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
2173 /* remove prefsrc entry */
2174 rt->rt6i_prefsrc.plen = 0;
2175 }
2176 return 0;
2177}
2178
2179void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
2180{
2181 struct net *net = dev_net(ifp->idev->dev);
2182 struct arg_dev_net_ip adni = {
2183 .dev = ifp->idev->dev,
2184 .net = net,
2185 .addr = &ifp->addr,
2186 };
2187 fib6_clean_all(net, fib6_remove_prefsrc, 0, &adni);
2188}
2189
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002190struct arg_dev_net {
2191 struct net_device *dev;
2192 struct net *net;
2193};
2194
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195static int fib6_ifdown(struct rt6_info *rt, void *arg)
2196{
stephen hemmingerbc3ef662010-12-16 17:42:40 +00002197 const struct arg_dev_net *adn = arg;
2198 const struct net_device *dev = adn->dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002199
David S. Millerd1918542011-12-28 20:19:20 -05002200 if ((rt->dst.dev == dev || !dev) &&
David S. Millerc159d302011-12-26 15:24:36 -05002201 rt != adn->net->ipv6.ip6_null_entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 return -1;
David S. Millerc159d302011-12-26 15:24:36 -05002203
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 return 0;
2205}
2206
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002207void rt6_ifdown(struct net *net, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002209 struct arg_dev_net adn = {
2210 .dev = dev,
2211 .net = net,
2212 };
2213
2214 fib6_clean_all(net, fib6_ifdown, 0, &adn);
David S. Miller1e493d12008-09-10 17:27:15 -07002215 icmp6_clean_all(fib6_ifdown, &adn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216}
2217
Eric Dumazet95c96172012-04-15 05:58:06 +00002218struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00002220 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221};
2222
2223static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
2224{
2225 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
2226 struct inet6_dev *idev;
2227
2228 /* In IPv6 pmtu discovery is not optional,
2229 so that RTAX_MTU lock cannot disable it.
2230 We still use this lock to block changes
2231 caused by addrconf/ndisc.
2232 */
2233
2234 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05002235 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 return 0;
2237
2238 /* For administrative MTU increase, there is no way to discover
2239 IPv6 PMTU increase, so PMTU increase should be updated here.
2240 Since RFC 1981 doesn't include administrative MTU increase
2241 update PMTU increase is a MUST. (i.e. jumbo frame)
2242 */
2243 /*
2244 If new MTU is less than route PMTU, this new MTU will be the
2245 lowest MTU in the path, update the route PMTU to reflect PMTU
2246 decreases; if new MTU is greater than route PMTU, and the
2247 old MTU is the lowest MTU in the path, update the route PMTU
2248 to reflect the increase. In this case if the other nodes' MTU
2249 also have the lowest MTU, TOO BIG MESSAGE will be lead to
2250 PMTU discouvery.
2251 */
David S. Millerd1918542011-12-28 20:19:20 -05002252 if (rt->dst.dev == arg->dev &&
Changli Gaod8d1f302010-06-10 23:31:35 -07002253 !dst_metric_locked(&rt->dst, RTAX_MTU) &&
2254 (dst_mtu(&rt->dst) >= arg->mtu ||
2255 (dst_mtu(&rt->dst) < arg->mtu &&
2256 dst_mtu(&rt->dst) == idev->cnf.mtu6))) {
David S. Millerdefb3512010-12-08 21:16:57 -08002257 dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu);
Simon Arlott566cfd82007-07-26 00:09:55 -07002258 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 return 0;
2260}
2261
Eric Dumazet95c96172012-04-15 05:58:06 +00002262void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263{
Thomas Grafc71099a2006-08-04 23:20:06 -07002264 struct rt6_mtu_change_arg arg = {
2265 .dev = dev,
2266 .mtu = mtu,
2267 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002269 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, 0, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270}
2271
Patrick McHardyef7c79e2007-06-05 12:38:30 -07002272static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07002273 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07002274 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07002275 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002276 [RTA_PRIORITY] = { .type = NLA_U32 },
2277 [RTA_METRICS] = { .type = NLA_NESTED },
2278};
2279
2280static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
2281 struct fib6_config *cfg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282{
Thomas Graf86872cb2006-08-22 00:01:08 -07002283 struct rtmsg *rtm;
2284 struct nlattr *tb[RTA_MAX+1];
2285 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286
Thomas Graf86872cb2006-08-22 00:01:08 -07002287 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2288 if (err < 0)
2289 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290
Thomas Graf86872cb2006-08-22 00:01:08 -07002291 err = -EINVAL;
2292 rtm = nlmsg_data(nlh);
2293 memset(cfg, 0, sizeof(*cfg));
2294
2295 cfg->fc_table = rtm->rtm_table;
2296 cfg->fc_dst_len = rtm->rtm_dst_len;
2297 cfg->fc_src_len = rtm->rtm_src_len;
2298 cfg->fc_flags = RTF_UP;
2299 cfg->fc_protocol = rtm->rtm_protocol;
2300
2301 if (rtm->rtm_type == RTN_UNREACHABLE)
2302 cfg->fc_flags |= RTF_REJECT;
2303
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002304 if (rtm->rtm_type == RTN_LOCAL)
2305 cfg->fc_flags |= RTF_LOCAL;
2306
Thomas Graf86872cb2006-08-22 00:01:08 -07002307 cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid;
2308 cfg->fc_nlinfo.nlh = nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002309 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
Thomas Graf86872cb2006-08-22 00:01:08 -07002310
2311 if (tb[RTA_GATEWAY]) {
2312 nla_memcpy(&cfg->fc_gateway, tb[RTA_GATEWAY], 16);
2313 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002315
2316 if (tb[RTA_DST]) {
2317 int plen = (rtm->rtm_dst_len + 7) >> 3;
2318
2319 if (nla_len(tb[RTA_DST]) < plen)
2320 goto errout;
2321
2322 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002324
2325 if (tb[RTA_SRC]) {
2326 int plen = (rtm->rtm_src_len + 7) >> 3;
2327
2328 if (nla_len(tb[RTA_SRC]) < plen)
2329 goto errout;
2330
2331 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002333
Daniel Walterc3968a82011-04-13 21:10:57 +00002334 if (tb[RTA_PREFSRC])
2335 nla_memcpy(&cfg->fc_prefsrc, tb[RTA_PREFSRC], 16);
2336
Thomas Graf86872cb2006-08-22 00:01:08 -07002337 if (tb[RTA_OIF])
2338 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
2339
2340 if (tb[RTA_PRIORITY])
2341 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
2342
2343 if (tb[RTA_METRICS]) {
2344 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
2345 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 }
Thomas Graf86872cb2006-08-22 00:01:08 -07002347
2348 if (tb[RTA_TABLE])
2349 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
2350
2351 err = 0;
2352errout:
2353 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354}
2355
Thomas Grafc127ea22007-03-22 11:58:32 -07002356static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357{
Thomas Graf86872cb2006-08-22 00:01:08 -07002358 struct fib6_config cfg;
2359 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360
Thomas Graf86872cb2006-08-22 00:01:08 -07002361 err = rtm_to_fib6_config(skb, nlh, &cfg);
2362 if (err < 0)
2363 return err;
2364
2365 return ip6_route_del(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366}
2367
Thomas Grafc127ea22007-03-22 11:58:32 -07002368static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369{
Thomas Graf86872cb2006-08-22 00:01:08 -07002370 struct fib6_config cfg;
2371 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372
Thomas Graf86872cb2006-08-22 00:01:08 -07002373 err = rtm_to_fib6_config(skb, nlh, &cfg);
2374 if (err < 0)
2375 return err;
2376
2377 return ip6_route_add(&cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378}
2379
Thomas Graf339bf982006-11-10 14:10:15 -08002380static inline size_t rt6_nlmsg_size(void)
2381{
2382 return NLMSG_ALIGN(sizeof(struct rtmsg))
2383 + nla_total_size(16) /* RTA_SRC */
2384 + nla_total_size(16) /* RTA_DST */
2385 + nla_total_size(16) /* RTA_GATEWAY */
2386 + nla_total_size(16) /* RTA_PREFSRC */
2387 + nla_total_size(4) /* RTA_TABLE */
2388 + nla_total_size(4) /* RTA_IIF */
2389 + nla_total_size(4) /* RTA_OIF */
2390 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08002391 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Thomas Graf339bf982006-11-10 14:10:15 -08002392 + nla_total_size(sizeof(struct rta_cacheinfo));
2393}
2394
Brian Haley191cd582008-08-14 15:33:21 -07002395static int rt6_fill_node(struct net *net,
2396 struct sk_buff *skb, struct rt6_info *rt,
Jamal Hadi Salim0d51aa82005-06-21 13:51:04 -07002397 struct in6_addr *dst, struct in6_addr *src,
2398 int iif, int type, u32 pid, u32 seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002399 int prefix, int nowait, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400{
David S. Miller346f8702011-12-29 15:22:33 -05002401 const struct inet_peer *peer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 struct rtmsg *rtm;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002403 struct nlmsghdr *nlh;
Thomas Grafe3703b32006-11-27 09:27:07 -08002404 long expires;
Patrick McHardy9e762a42006-08-10 23:09:48 -07002405 u32 table;
Eric Dumazetf2c31e32011-07-29 19:00:53 +00002406 struct neighbour *n;
David S. Miller346f8702011-12-29 15:22:33 -05002407 u32 ts, tsage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408
2409 if (prefix) { /* user wants prefix routes only */
2410 if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
2411 /* success since this is not a prefix route */
2412 return 1;
2413 }
2414 }
2415
Thomas Graf2d7202b2006-08-22 00:01:27 -07002416 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05002417 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08002418 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07002419
2420 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 rtm->rtm_family = AF_INET6;
2422 rtm->rtm_dst_len = rt->rt6i_dst.plen;
2423 rtm->rtm_src_len = rt->rt6i_src.plen;
2424 rtm->rtm_tos = 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07002425 if (rt->rt6i_table)
Patrick McHardy9e762a42006-08-10 23:09:48 -07002426 table = rt->rt6i_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07002427 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07002428 table = RT6_TABLE_UNSPEC;
2429 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04002430 if (nla_put_u32(skb, RTA_TABLE, table))
2431 goto nla_put_failure;
David S. Miller38308472011-12-03 18:02:47 -05002432 if (rt->rt6i_flags & RTF_REJECT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 rtm->rtm_type = RTN_UNREACHABLE;
David S. Miller38308472011-12-03 18:02:47 -05002434 else if (rt->rt6i_flags & RTF_LOCAL)
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002435 rtm->rtm_type = RTN_LOCAL;
David S. Millerd1918542011-12-28 20:19:20 -05002436 else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 rtm->rtm_type = RTN_LOCAL;
2438 else
2439 rtm->rtm_type = RTN_UNICAST;
2440 rtm->rtm_flags = 0;
2441 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
2442 rtm->rtm_protocol = rt->rt6i_protocol;
David S. Miller38308472011-12-03 18:02:47 -05002443 if (rt->rt6i_flags & RTF_DYNAMIC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 rtm->rtm_protocol = RTPROT_REDIRECT;
2445 else if (rt->rt6i_flags & RTF_ADDRCONF)
2446 rtm->rtm_protocol = RTPROT_KERNEL;
David S. Miller38308472011-12-03 18:02:47 -05002447 else if (rt->rt6i_flags & RTF_DEFAULT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 rtm->rtm_protocol = RTPROT_RA;
2449
David S. Miller38308472011-12-03 18:02:47 -05002450 if (rt->rt6i_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 rtm->rtm_flags |= RTM_F_CLONED;
2452
2453 if (dst) {
David S. Millerc78679e2012-04-01 20:27:33 -04002454 if (nla_put(skb, RTA_DST, 16, dst))
2455 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002456 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 } else if (rtm->rtm_dst_len)
David S. Millerc78679e2012-04-01 20:27:33 -04002458 if (nla_put(skb, RTA_DST, 16, &rt->rt6i_dst.addr))
2459 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460#ifdef CONFIG_IPV6_SUBTREES
2461 if (src) {
David S. Millerc78679e2012-04-01 20:27:33 -04002462 if (nla_put(skb, RTA_SRC, 16, src))
2463 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002464 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04002465 } else if (rtm->rtm_src_len &&
2466 nla_put(skb, RTA_SRC, 16, &rt->rt6i_src.addr))
2467 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002469 if (iif) {
2470#ifdef CONFIG_IPV6_MROUTE
2471 if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
Benjamin Thery8229efd2008-12-10 16:30:15 -08002472 int err = ip6mr_get_route(net, skb, rtm, nowait);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002473 if (err <= 0) {
2474 if (!nowait) {
2475 if (err == 0)
2476 return 0;
2477 goto nla_put_failure;
2478 } else {
2479 if (err == -EMSGSIZE)
2480 goto nla_put_failure;
2481 }
2482 }
2483 } else
2484#endif
David S. Millerc78679e2012-04-01 20:27:33 -04002485 if (nla_put_u32(skb, RTA_IIF, iif))
2486 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002487 } else if (dst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 struct in6_addr saddr_buf;
David S. Millerc78679e2012-04-01 20:27:33 -04002489 if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0 &&
2490 nla_put(skb, RTA_PREFSRC, 16, &saddr_buf))
2491 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07002493
Daniel Walterc3968a82011-04-13 21:10:57 +00002494 if (rt->rt6i_prefsrc.plen) {
2495 struct in6_addr saddr_buf;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002496 saddr_buf = rt->rt6i_prefsrc.addr;
David S. Millerc78679e2012-04-01 20:27:33 -04002497 if (nla_put(skb, RTA_PREFSRC, 16, &saddr_buf))
2498 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00002499 }
2500
David S. Millerdefb3512010-12-08 21:16:57 -08002501 if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07002502 goto nla_put_failure;
2503
Eric Dumazetf2c31e32011-07-29 19:00:53 +00002504 rcu_read_lock();
David Miller27217452011-12-02 16:52:08 +00002505 n = dst_get_neighbour_noref(&rt->dst);
Eric Dumazet94f826b2012-03-27 09:53:52 +00002506 if (n) {
2507 if (nla_put(skb, RTA_GATEWAY, 16, &n->primary_key) < 0) {
2508 rcu_read_unlock();
2509 goto nla_put_failure;
2510 }
2511 }
Eric Dumazetf2c31e32011-07-29 19:00:53 +00002512 rcu_read_unlock();
Thomas Graf2d7202b2006-08-22 00:01:27 -07002513
David S. Millerc78679e2012-04-01 20:27:33 -04002514 if (rt->dst.dev &&
2515 nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex))
2516 goto nla_put_failure;
2517 if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric))
2518 goto nla_put_failure;
YOSHIFUJI Hideaki36e3dea2008-05-13 02:52:55 +09002519 if (!(rt->rt6i_flags & RTF_EXPIRES))
2520 expires = 0;
David S. Millerd1918542011-12-28 20:19:20 -05002521 else if (rt->dst.expires - jiffies < INT_MAX)
2522 expires = rt->dst.expires - jiffies;
YOSHIFUJI Hideaki36e3dea2008-05-13 02:52:55 +09002523 else
2524 expires = INT_MAX;
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07002525
David S. Miller97bab732012-06-09 22:36:36 -07002526 peer = NULL;
2527 if (rt6_has_peer(rt))
2528 peer = rt6_peer_ptr(rt);
David S. Miller346f8702011-12-29 15:22:33 -05002529 ts = tsage = 0;
2530 if (peer && peer->tcp_ts_stamp) {
2531 ts = peer->tcp_ts;
2532 tsage = get_seconds() - peer->tcp_ts_stamp;
2533 }
2534
2535 if (rtnl_put_cacheinfo(skb, &rt->dst, 0, ts, tsage,
Changli Gaod8d1f302010-06-10 23:31:35 -07002536 expires, rt->dst.error) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08002537 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538
Thomas Graf2d7202b2006-08-22 00:01:27 -07002539 return nlmsg_end(skb, nlh);
2540
2541nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002542 nlmsg_cancel(skb, nlh);
2543 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544}
2545
Patrick McHardy1b43af52006-08-10 23:11:17 -07002546int rt6_dump_route(struct rt6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547{
2548 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
2549 int prefix;
2550
Thomas Graf2d7202b2006-08-22 00:01:27 -07002551 if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
2552 struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0;
2554 } else
2555 prefix = 0;
2556
Brian Haley191cd582008-08-14 15:33:21 -07002557 return rt6_fill_node(arg->net,
2558 arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002560 prefix, 0, NLM_F_MULTI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561}
2562
Thomas Grafc127ea22007-03-22 11:58:32 -07002563static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002565 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07002566 struct nlattr *tb[RTA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07002568 struct sk_buff *skb;
2569 struct rtmsg *rtm;
David S. Miller4c9483b2011-03-12 16:22:43 -05002570 struct flowi6 fl6;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002571 int err, iif = 0, oif = 0;
Thomas Grafab364a62006-08-22 00:01:47 -07002572
2573 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2574 if (err < 0)
2575 goto errout;
2576
2577 err = -EINVAL;
David S. Miller4c9483b2011-03-12 16:22:43 -05002578 memset(&fl6, 0, sizeof(fl6));
Thomas Grafab364a62006-08-22 00:01:47 -07002579
2580 if (tb[RTA_SRC]) {
2581 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
2582 goto errout;
2583
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002584 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07002585 }
2586
2587 if (tb[RTA_DST]) {
2588 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
2589 goto errout;
2590
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002591 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07002592 }
2593
2594 if (tb[RTA_IIF])
2595 iif = nla_get_u32(tb[RTA_IIF]);
2596
2597 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002598 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07002599
2600 if (iif) {
2601 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002602 int flags = 0;
2603
Daniel Lezcano55786892008-03-04 13:47:47 -08002604 dev = __dev_get_by_index(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07002605 if (!dev) {
2606 err = -ENODEV;
2607 goto errout;
2608 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00002609
2610 fl6.flowi6_iif = iif;
2611
2612 if (!ipv6_addr_any(&fl6.saddr))
2613 flags |= RT6_LOOKUP_F_HAS_SADDR;
2614
2615 rt = (struct rt6_info *)ip6_route_input_lookup(net, dev, &fl6,
2616 flags);
2617 } else {
2618 fl6.flowi6_oif = oif;
2619
2620 rt = (struct rt6_info *)ip6_route_output(net, NULL, &fl6);
Thomas Grafab364a62006-08-22 00:01:47 -07002621 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622
2623 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05002624 if (!skb) {
Shmulik Ladkani2173bff2012-04-03 23:13:00 +00002625 dst_release(&rt->dst);
Thomas Grafab364a62006-08-22 00:01:47 -07002626 err = -ENOBUFS;
2627 goto errout;
2628 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629
2630 /* Reserve room for dummy headers, this skb can pass
2631 through good chunk of routing engine.
2632 */
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07002633 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
2635
Changli Gaod8d1f302010-06-10 23:31:35 -07002636 skb_dst_set(skb, &rt->dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637
David S. Miller4c9483b2011-03-12 16:22:43 -05002638 err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 RTM_NEWROUTE, NETLINK_CB(in_skb).pid,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002640 nlh->nlmsg_seq, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07002642 kfree_skb(skb);
2643 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 }
2645
Daniel Lezcano55786892008-03-04 13:47:47 -08002646 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid);
Thomas Grafab364a62006-08-22 00:01:47 -07002647errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649}
2650
Thomas Graf86872cb2006-08-22 00:01:08 -07002651void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652{
2653 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08002654 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002655 u32 seq;
2656 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002658 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05002659 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07002660
Thomas Graf339bf982006-11-10 14:10:15 -08002661 skb = nlmsg_new(rt6_nlmsg_size(), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05002662 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07002663 goto errout;
2664
Brian Haley191cd582008-08-14 15:33:21 -07002665 err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002666 event, info->pid, seq, 0, 0, 0);
Patrick McHardy26932562007-01-31 23:16:40 -08002667 if (err < 0) {
2668 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
2669 WARN_ON(err == -EMSGSIZE);
2670 kfree_skb(skb);
2671 goto errout;
2672 }
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08002673 rtnl_notify(skb, net, info->pid, RTNLGRP_IPV6_ROUTE,
2674 info->nlh, gfp_any());
2675 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07002676errout:
2677 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08002678 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679}
2680
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002681static int ip6_route_dev_notify(struct notifier_block *this,
2682 unsigned long event, void *data)
2683{
2684 struct net_device *dev = (struct net_device *)data;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002685 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002686
2687 if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002688 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002689 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
2690#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07002691 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002692 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07002693 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002694 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
2695#endif
2696 }
2697
2698 return NOTIFY_OK;
2699}
2700
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701/*
2702 * /proc
2703 */
2704
2705#ifdef CONFIG_PROC_FS
2706
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707struct rt6_proc_arg
2708{
2709 char *buffer;
2710 int offset;
2711 int length;
2712 int skip;
2713 int len;
2714};
2715
2716static int rt6_info_route(struct rt6_info *rt, void *p_arg)
2717{
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002718 struct seq_file *m = p_arg;
David S. Miller69cce1d2011-07-17 23:09:49 -07002719 struct neighbour *n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720
Harvey Harrison4b7a4272008-10-29 12:50:24 -07002721 seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722
2723#ifdef CONFIG_IPV6_SUBTREES
Harvey Harrison4b7a4272008-10-29 12:50:24 -07002724 seq_printf(m, "%pi6 %02x ", &rt->rt6i_src.addr, rt->rt6i_src.plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725#else
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002726 seq_puts(m, "00000000000000000000000000000000 00 ");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727#endif
Eric Dumazetf2c31e32011-07-29 19:00:53 +00002728 rcu_read_lock();
David Miller27217452011-12-02 16:52:08 +00002729 n = dst_get_neighbour_noref(&rt->dst);
David S. Miller69cce1d2011-07-17 23:09:49 -07002730 if (n) {
2731 seq_printf(m, "%pi6", n->primary_key);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 } else {
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002733 seq_puts(m, "00000000000000000000000000000000");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 }
Eric Dumazetf2c31e32011-07-29 19:00:53 +00002735 rcu_read_unlock();
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002736 seq_printf(m, " %08x %08x %08x %08x %8s\n",
Changli Gaod8d1f302010-06-10 23:31:35 -07002737 rt->rt6i_metric, atomic_read(&rt->dst.__refcnt),
2738 rt->dst.__use, rt->rt6i_flags,
David S. Millerd1918542011-12-28 20:19:20 -05002739 rt->dst.dev ? rt->dst.dev->name : "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 return 0;
2741}
2742
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002743static int ipv6_route_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744{
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002745 struct net *net = (struct net *)m->private;
Josh Hunt32b293a2011-12-28 13:23:07 +00002746 fib6_clean_all_ro(net, rt6_info_route, 0, m);
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002747 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748}
2749
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002750static int ipv6_route_open(struct inode *inode, struct file *file)
2751{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07002752 return single_open_net(inode, file, ipv6_route_show);
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002753}
2754
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002755static const struct file_operations ipv6_route_proc_fops = {
2756 .owner = THIS_MODULE,
2757 .open = ipv6_route_open,
2758 .read = seq_read,
2759 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07002760 .release = single_release_net,
Alexey Dobriyan33120b32007-11-06 05:27:11 -08002761};
2762
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763static int rt6_stats_seq_show(struct seq_file *seq, void *v)
2764{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002765 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002767 net->ipv6.rt6_stats->fib_nodes,
2768 net->ipv6.rt6_stats->fib_route_nodes,
2769 net->ipv6.rt6_stats->fib_rt_alloc,
2770 net->ipv6.rt6_stats->fib_rt_entries,
2771 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00002772 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002773 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774
2775 return 0;
2776}
2777
2778static int rt6_stats_seq_open(struct inode *inode, struct file *file)
2779{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07002780 return single_open_net(inode, file, rt6_stats_seq_show);
Daniel Lezcano69ddb802008-03-04 13:46:23 -08002781}
2782
Arjan van de Ven9a321442007-02-12 00:55:35 -08002783static const struct file_operations rt6_stats_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 .owner = THIS_MODULE,
2785 .open = rt6_stats_seq_open,
2786 .read = seq_read,
2787 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07002788 .release = single_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789};
2790#endif /* CONFIG_PROC_FS */
2791
2792#ifdef CONFIG_SYSCTL
2793
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794static
Alexey Dobriyan8d65af72009-09-23 15:57:19 -07002795int ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 void __user *buffer, size_t *lenp, loff_t *ppos)
2797{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00002798 struct net *net;
2799 int delay;
2800 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00002802
2803 net = (struct net *)ctl->extra1;
2804 delay = net->ipv6.sysctl.flush_delay;
2805 proc_dointvec(ctl, write, buffer, lenp, ppos);
2806 fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net);
2807 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808}
2809
Daniel Lezcano760f2d02008-01-10 02:53:43 -08002810ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002811 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08002813 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07002815 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002816 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 },
2818 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08002820 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 .maxlen = sizeof(int),
2822 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002823 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 },
2825 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08002827 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 .maxlen = sizeof(int),
2829 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002830 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 },
2832 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08002834 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 .maxlen = sizeof(int),
2836 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002837 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 },
2839 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08002841 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 .maxlen = sizeof(int),
2843 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002844 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 },
2846 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08002848 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 .maxlen = sizeof(int),
2850 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002851 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 },
2853 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08002855 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 .maxlen = sizeof(int),
2857 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07002858 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 },
2860 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08002862 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 .maxlen = sizeof(int),
2864 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002865 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 },
2867 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08002869 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 .maxlen = sizeof(int),
2871 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07002872 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 },
2874 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08002876 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 .maxlen = sizeof(int),
2878 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002879 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002881 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882};
2883
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002884struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08002885{
2886 struct ctl_table *table;
2887
2888 table = kmemdup(ipv6_route_table_template,
2889 sizeof(ipv6_route_table_template),
2890 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09002891
2892 if (table) {
2893 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00002894 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00002895 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09002896 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
2897 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
2898 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
2899 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
2900 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
2901 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
2902 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08002903 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09002904 }
2905
Daniel Lezcano760f2d02008-01-10 02:53:43 -08002906 return table;
2907}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908#endif
2909
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002910static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08002911{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07002912 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002913
Alexey Dobriyan86393e52009-08-29 01:34:49 +00002914 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
2915 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08002916
Eric Dumazetfc66f952010-10-08 06:37:34 +00002917 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
2918 goto out_ip6_dst_ops;
2919
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002920 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
2921 sizeof(*net->ipv6.ip6_null_entry),
2922 GFP_KERNEL);
2923 if (!net->ipv6.ip6_null_entry)
Eric Dumazetfc66f952010-10-08 06:37:34 +00002924 goto out_ip6_dst_entries;
Changli Gaod8d1f302010-06-10 23:31:35 -07002925 net->ipv6.ip6_null_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002926 (struct dst_entry *)net->ipv6.ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002927 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08002928 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
2929 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002930
2931#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2932 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
2933 sizeof(*net->ipv6.ip6_prohibit_entry),
2934 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07002935 if (!net->ipv6.ip6_prohibit_entry)
2936 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002937 net->ipv6.ip6_prohibit_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002938 (struct dst_entry *)net->ipv6.ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002939 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08002940 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
2941 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002942
2943 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
2944 sizeof(*net->ipv6.ip6_blk_hole_entry),
2945 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07002946 if (!net->ipv6.ip6_blk_hole_entry)
2947 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002948 net->ipv6.ip6_blk_hole_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002949 (struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07002950 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08002951 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
2952 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002953#endif
2954
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07002955 net->ipv6.sysctl.flush_delay = 0;
2956 net->ipv6.sysctl.ip6_rt_max_size = 4096;
2957 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
2958 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
2959 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
2960 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
2961 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
2962 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
2963
Daniel Lezcanocdb18762008-03-04 13:45:33 -08002964#ifdef CONFIG_PROC_FS
2965 proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops);
2966 proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops);
2967#endif
Benjamin Thery6891a342008-03-04 13:49:47 -08002968 net->ipv6.ip6_rt_gc_expire = 30*HZ;
2969
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002970 ret = 0;
2971out:
2972 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08002973
Peter Zijlstra68fffc62008-10-07 14:12:10 -07002974#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2975out_ip6_prohibit_entry:
2976 kfree(net->ipv6.ip6_prohibit_entry);
2977out_ip6_null_entry:
2978 kfree(net->ipv6.ip6_null_entry);
2979#endif
Eric Dumazetfc66f952010-10-08 06:37:34 +00002980out_ip6_dst_entries:
2981 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08002982out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08002983 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08002984}
2985
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002986static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08002987{
2988#ifdef CONFIG_PROC_FS
2989 proc_net_remove(net, "ipv6_route");
2990 proc_net_remove(net, "rt6_stats");
2991#endif
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002992 kfree(net->ipv6.ip6_null_entry);
2993#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2994 kfree(net->ipv6.ip6_prohibit_entry);
2995 kfree(net->ipv6.ip6_blk_hole_entry);
2996#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00002997 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08002998}
2999
3000static struct pernet_operations ip6_route_net_ops = {
3001 .init = ip6_route_net_init,
3002 .exit = ip6_route_net_exit,
3003};
3004
David S. Millerc3426b42012-06-09 16:27:05 -07003005static int __net_init ipv6_inetpeer_init(struct net *net)
3006{
3007 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
3008
3009 if (!bp)
3010 return -ENOMEM;
3011 inet_peer_base_init(bp);
3012 net->ipv6.peers = bp;
3013 return 0;
3014}
3015
3016static void __net_exit ipv6_inetpeer_exit(struct net *net)
3017{
3018 struct inet_peer_base *bp = net->ipv6.peers;
3019
3020 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07003021 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07003022 kfree(bp);
3023}
3024
David S. Miller2b823f72012-06-09 19:00:16 -07003025static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07003026 .init = ipv6_inetpeer_init,
3027 .exit = ipv6_inetpeer_exit,
3028};
3029
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003030static struct notifier_block ip6_route_dev_notifier = {
3031 .notifier_call = ip6_route_dev_notify,
3032 .priority = 0,
3033};
3034
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003035int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003037 int ret;
3038
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003039 ret = -ENOMEM;
3040 ip6_dst_ops_template.kmem_cachep =
3041 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
3042 SLAB_HWCACHE_ALIGN, NULL);
3043 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08003044 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07003045
Eric Dumazetfc66f952010-10-08 06:37:34 +00003046 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003047 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003048 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08003049
Eric Dumazetfc66f952010-10-08 06:37:34 +00003050 ret = register_pernet_subsys(&ip6_route_net_ops);
3051 if (ret)
3052 goto out_dst_entries;
3053
David S. Millerc3426b42012-06-09 16:27:05 -07003054 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
3055 if (ret)
3056 goto out_register_subsys;
3057
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07003058 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
3059
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003060 /* Registering of the loopback is done before this portion of code,
3061 * the loopback reference in rt6_info will not be taken, do it
3062 * manually for init_net */
Changli Gaod8d1f302010-06-10 23:31:35 -07003063 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003064 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3065 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07003066 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003067 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07003068 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003069 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3070 #endif
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003071 ret = fib6_init();
3072 if (ret)
David S. Millerc3426b42012-06-09 16:27:05 -07003073 goto out_register_inetpeer;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003074
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003075 ret = xfrm6_init();
3076 if (ret)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003077 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08003078
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003079 ret = fib6_rules_init();
3080 if (ret)
3081 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08003082
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003083 ret = -ENOBUFS;
Greg Rosec7ac8672011-06-10 01:27:09 +00003084 if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) ||
3085 __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) ||
3086 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL))
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003087 goto fib6_rules_init;
3088
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003089 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003090 if (ret)
3091 goto fib6_rules_init;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003092
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003093out:
3094 return ret;
3095
3096fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003097 fib6_rules_cleanup();
3098xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003099 xfrm6_fini();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003100out_fib6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003101 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07003102out_register_inetpeer:
3103 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003104out_register_subsys:
3105 unregister_pernet_subsys(&ip6_route_net_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00003106out_dst_entries:
3107 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003108out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003109 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08003110 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111}
3112
3113void ip6_route_cleanup(void)
3114{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003115 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Graf101367c2006-08-04 03:39:02 -07003116 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07003119 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003120 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00003121 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003122 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123}