blob: c52c5190888186c6d7c1937583ecd4b4ce8ce2c4 [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>
Jiri Benc904af042015-08-20 13:56:31 +020057#include <net/dst_metadata.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#include <net/xfrm.h>
Tom Tucker8d717402006-07-30 20:43:36 -070059#include <net/netevent.h>
Thomas Graf21713eb2006-08-15 00:35:24 -070060#include <net/netlink.h>
Nicolas Dichtel51ebd312012-10-22 03:42:09 +000061#include <net/nexthop.h>
Roopa Prabhu19e42e42015-07-21 10:43:48 +020062#include <net/lwtunnel.h>
Jiri Benc904af042015-08-20 13:56:31 +020063#include <net/ip_tunnels.h>
David Ahernca254492015-10-12 11:47:10 -070064#include <net/l3mdev.h>
David Ahernb8115802015-11-19 12:24:22 -080065#include <trace/events/fib6.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080067#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69#ifdef CONFIG_SYSCTL
70#include <linux/sysctl.h>
71#endif
72
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +020073enum rt6_nud_state {
Jiri Benc7e980562013-12-11 13:48:20 +010074 RT6_NUD_FAIL_HARD = -3,
75 RT6_NUD_FAIL_PROBE = -2,
76 RT6_NUD_FAIL_DO_RR = -1,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +020077 RT6_NUD_SUCCEED = 1
78};
79
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -070080static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort);
Linus Torvalds1da177e2005-04-16 15:20:36 -070081static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
David S. Miller0dbaee32010-12-13 12:52:14 -080082static unsigned int ip6_default_advmss(const struct dst_entry *dst);
Steffen Klassertebb762f2011-11-23 02:12:51 +000083static unsigned int ip6_mtu(const struct dst_entry *dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084static struct dst_entry *ip6_negative_advice(struct dst_entry *);
85static void ip6_dst_destroy(struct dst_entry *);
86static void ip6_dst_ifdown(struct dst_entry *,
87 struct net_device *dev, int how);
Daniel Lezcano569d3642008-01-18 03:56:57 -080088static int ip6_dst_gc(struct dst_ops *ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90static int ip6_pkt_discard(struct sk_buff *skb);
Eric W. Biedermanede20592015-10-07 16:48:47 -050091static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb);
Kamala R7150aed2013-12-02 19:55:21 +053092static int ip6_pkt_prohibit(struct sk_buff *skb);
Eric W. Biedermanede20592015-10-07 16:48:47 -050093static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070094static void ip6_link_failure(struct sk_buff *skb);
David S. Miller6700c272012-07-17 03:29:28 -070095static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
96 struct sk_buff *skb, u32 mtu);
97static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
98 struct sk_buff *skb);
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -070099static void rt6_dst_from_metrics_check(struct rt6_info *rt);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200100static int rt6_score_route(struct rt6_info *rt, int oif, int strict);
David Ahern16a16cd2017-02-02 12:37:11 -0800101static size_t rt6_nlmsg_size(struct rt6_info *rt);
102static int rt6_fill_node(struct net *net,
103 struct sk_buff *skb, struct rt6_info *rt,
104 struct in6_addr *dst, struct in6_addr *src,
105 int iif, int type, u32 portid, u32 seq,
106 unsigned int flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800108#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800109static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000110 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -0700111 const struct in6_addr *gwaddr,
112 struct net_device *dev,
Eric Dumazet95c96172012-04-15 05:58:06 +0000113 unsigned int pref);
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -0800114static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000115 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -0700116 const struct in6_addr *gwaddr,
117 struct net_device *dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800118#endif
119
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700120struct uncached_list {
121 spinlock_t lock;
122 struct list_head head;
123};
124
125static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list);
126
127static void rt6_uncached_list_add(struct rt6_info *rt)
128{
129 struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);
130
131 rt->dst.flags |= DST_NOCACHE;
132 rt->rt6i_uncached_list = ul;
133
134 spin_lock_bh(&ul->lock);
135 list_add_tail(&rt->rt6i_uncached, &ul->head);
136 spin_unlock_bh(&ul->lock);
137}
138
139static void rt6_uncached_list_del(struct rt6_info *rt)
140{
141 if (!list_empty(&rt->rt6i_uncached)) {
142 struct uncached_list *ul = rt->rt6i_uncached_list;
143
144 spin_lock_bh(&ul->lock);
145 list_del(&rt->rt6i_uncached);
146 spin_unlock_bh(&ul->lock);
147 }
148}
149
150static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev)
151{
152 struct net_device *loopback_dev = net->loopback_dev;
153 int cpu;
154
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500155 if (dev == loopback_dev)
156 return;
157
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700158 for_each_possible_cpu(cpu) {
159 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
160 struct rt6_info *rt;
161
162 spin_lock_bh(&ul->lock);
163 list_for_each_entry(rt, &ul->head, rt6i_uncached) {
164 struct inet6_dev *rt_idev = rt->rt6i_idev;
165 struct net_device *rt_dev = rt->dst.dev;
166
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500167 if (rt_idev->dev == dev) {
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700168 rt->rt6i_idev = in6_dev_get(loopback_dev);
169 in6_dev_put(rt_idev);
170 }
171
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500172 if (rt_dev == dev) {
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700173 rt->dst.dev = loopback_dev;
174 dev_hold(rt->dst.dev);
175 dev_put(rt_dev);
176 }
177 }
178 spin_unlock_bh(&ul->lock);
179 }
180}
181
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700182static u32 *rt6_pcpu_cow_metrics(struct rt6_info *rt)
183{
184 return dst_metrics_write_ptr(rt->dst.from);
185}
186
David S. Miller06582542011-01-27 14:58:42 -0800187static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
188{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700189 struct rt6_info *rt = (struct rt6_info *)dst;
David S. Miller06582542011-01-27 14:58:42 -0800190
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700191 if (rt->rt6i_flags & RTF_PCPU)
192 return rt6_pcpu_cow_metrics(rt);
193 else if (rt->rt6i_flags & RTF_CACHE)
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700194 return NULL;
195 else
Martin KaFai Lau3b471172015-02-12 16:14:08 -0800196 return dst_cow_metrics_generic(dst, old);
David S. Miller06582542011-01-27 14:58:42 -0800197}
198
David S. Millerf894cbf2012-07-02 21:52:24 -0700199static inline const void *choose_neigh_daddr(struct rt6_info *rt,
200 struct sk_buff *skb,
201 const void *daddr)
David S. Miller39232972012-01-26 15:22:32 -0500202{
203 struct in6_addr *p = &rt->rt6i_gateway;
204
David S. Millera7563f32012-01-26 16:29:16 -0500205 if (!ipv6_addr_any(p))
David S. Miller39232972012-01-26 15:22:32 -0500206 return (const void *) p;
David S. Millerf894cbf2012-07-02 21:52:24 -0700207 else if (skb)
208 return &ipv6_hdr(skb)->daddr;
David S. Miller39232972012-01-26 15:22:32 -0500209 return daddr;
210}
211
David S. Millerf894cbf2012-07-02 21:52:24 -0700212static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst,
213 struct sk_buff *skb,
214 const void *daddr)
David S. Millerd3aaeb32011-07-18 00:40:17 -0700215{
David S. Miller39232972012-01-26 15:22:32 -0500216 struct rt6_info *rt = (struct rt6_info *) dst;
217 struct neighbour *n;
218
David S. Millerf894cbf2012-07-02 21:52:24 -0700219 daddr = choose_neigh_daddr(rt, skb, daddr);
YOSHIFUJI Hideaki / 吉藤英明8e022ee2013-01-17 12:53:09 +0000220 n = __ipv6_neigh_lookup(dst->dev, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500221 if (n)
222 return n;
223 return neigh_create(&nd_tbl, daddr, dst->dev);
224}
225
Julian Anastasov63fca652017-02-06 23:14:15 +0200226static void ip6_confirm_neigh(const struct dst_entry *dst, const void *daddr)
227{
228 struct net_device *dev = dst->dev;
229 struct rt6_info *rt = (struct rt6_info *)dst;
230
231 daddr = choose_neigh_daddr(rt, NULL, daddr);
232 if (!daddr)
233 return;
234 if (dev->flags & (IFF_NOARP | IFF_LOOPBACK))
235 return;
236 if (ipv6_addr_is_multicast((const struct in6_addr *)daddr))
237 return;
238 __ipv6_confirm_neigh(dev, daddr);
239}
240
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -0800241static struct dst_ops ip6_dst_ops_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 .family = AF_INET6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 .gc = ip6_dst_gc,
244 .gc_thresh = 1024,
245 .check = ip6_dst_check,
David S. Miller0dbaee32010-12-13 12:52:14 -0800246 .default_advmss = ip6_default_advmss,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000247 .mtu = ip6_mtu,
David S. Miller06582542011-01-27 14:58:42 -0800248 .cow_metrics = ipv6_cow_metrics,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 .destroy = ip6_dst_destroy,
250 .ifdown = ip6_dst_ifdown,
251 .negative_advice = ip6_negative_advice,
252 .link_failure = ip6_link_failure,
253 .update_pmtu = ip6_rt_update_pmtu,
David S. Miller6e157b62012-07-12 00:05:02 -0700254 .redirect = rt6_do_redirect,
Eric W. Biederman9f8955c2015-10-07 16:48:39 -0500255 .local_out = __ip6_local_out,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700256 .neigh_lookup = ip6_neigh_lookup,
Julian Anastasov63fca652017-02-06 23:14:15 +0200257 .confirm_neigh = ip6_confirm_neigh,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258};
259
Steffen Klassertebb762f2011-11-23 02:12:51 +0000260static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
Roland Dreierec831ea2011-01-31 13:16:00 -0800261{
Steffen Klassert618f9bc2011-11-23 02:13:31 +0000262 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
263
264 return mtu ? : dst->dev->mtu;
Roland Dreierec831ea2011-01-31 13:16:00 -0800265}
266
David S. Miller6700c272012-07-17 03:29:28 -0700267static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
268 struct sk_buff *skb, u32 mtu)
David S. Miller14e50e52007-05-24 18:17:54 -0700269{
270}
271
David S. Miller6700c272012-07-17 03:29:28 -0700272static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
273 struct sk_buff *skb)
David S. Millerb587ee32012-07-12 00:39:24 -0700274{
275}
276
David S. Miller14e50e52007-05-24 18:17:54 -0700277static struct dst_ops ip6_dst_blackhole_ops = {
278 .family = AF_INET6,
David S. Miller14e50e52007-05-24 18:17:54 -0700279 .destroy = ip6_dst_destroy,
280 .check = ip6_dst_check,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000281 .mtu = ip6_blackhole_mtu,
Eric Dumazet214f45c2011-02-18 11:39:01 -0800282 .default_advmss = ip6_default_advmss,
David S. Miller14e50e52007-05-24 18:17:54 -0700283 .update_pmtu = ip6_rt_blackhole_update_pmtu,
David S. Millerb587ee32012-07-12 00:39:24 -0700284 .redirect = ip6_rt_blackhole_redirect,
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -0700285 .cow_metrics = dst_cow_metrics_generic,
David S. Millerd3aaeb32011-07-18 00:40:17 -0700286 .neigh_lookup = ip6_neigh_lookup,
David S. Miller14e50e52007-05-24 18:17:54 -0700287};
288
David S. Miller62fa8a82011-01-26 20:51:05 -0800289static const u32 ip6_template_metrics[RTAX_MAX] = {
Li RongQing14edd872012-10-24 14:01:18 +0800290 [RTAX_HOPLIMIT - 1] = 0,
David S. Miller62fa8a82011-01-26 20:51:05 -0800291};
292
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000293static const struct rt6_info ip6_null_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700294 .dst = {
295 .__refcnt = ATOMIC_INIT(1),
296 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000297 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700298 .error = -ENETUNREACH,
Changli Gaod8d1f302010-06-10 23:31:35 -0700299 .input = ip6_pkt_discard,
300 .output = ip6_pkt_discard_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 },
302 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700303 .rt6i_protocol = RTPROT_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 .rt6i_metric = ~(u32) 0,
305 .rt6i_ref = ATOMIC_INIT(1),
306};
307
Thomas Graf101367c2006-08-04 03:39:02 -0700308#ifdef CONFIG_IPV6_MULTIPLE_TABLES
309
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000310static const struct rt6_info ip6_prohibit_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700311 .dst = {
312 .__refcnt = ATOMIC_INIT(1),
313 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000314 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700315 .error = -EACCES,
Changli Gaod8d1f302010-06-10 23:31:35 -0700316 .input = ip6_pkt_prohibit,
317 .output = ip6_pkt_prohibit_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700318 },
319 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700320 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700321 .rt6i_metric = ~(u32) 0,
322 .rt6i_ref = ATOMIC_INIT(1),
323};
324
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000325static const struct rt6_info ip6_blk_hole_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700326 .dst = {
327 .__refcnt = ATOMIC_INIT(1),
328 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000329 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700330 .error = -EINVAL,
Changli Gaod8d1f302010-06-10 23:31:35 -0700331 .input = dst_discard,
Eric W. Biedermanede20592015-10-07 16:48:47 -0500332 .output = dst_discard_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700333 },
334 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Jean-Mickael Guerin4f724272009-05-20 17:38:59 -0700335 .rt6i_protocol = RTPROT_KERNEL,
Thomas Graf101367c2006-08-04 03:39:02 -0700336 .rt6i_metric = ~(u32) 0,
337 .rt6i_ref = ATOMIC_INIT(1),
338};
339
340#endif
341
Martin KaFai Lauebfa45f2015-10-15 16:39:57 -0700342static void rt6_info_init(struct rt6_info *rt)
343{
344 struct dst_entry *dst = &rt->dst;
345
346 memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
347 INIT_LIST_HEAD(&rt->rt6i_siblings);
348 INIT_LIST_HEAD(&rt->rt6i_uncached);
349}
350
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351/* allocate dst with ip6_dst_ops */
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700352static struct rt6_info *__ip6_dst_alloc(struct net *net,
353 struct net_device *dev,
Martin KaFai Lauad706862015-08-14 11:05:52 -0700354 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355{
David S. Miller97bab732012-06-09 22:36:36 -0700356 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
Wei Wang1cfb71e2017-06-17 10:42:33 -0700357 1, DST_OBSOLETE_FORCE_CHK, flags);
David S. Millercf911662011-04-28 14:31:47 -0700358
Martin KaFai Lauebfa45f2015-10-15 16:39:57 -0700359 if (rt)
360 rt6_info_init(rt);
Steffen Klassert81048912012-07-05 23:37:09 +0000361
David S. Millercf911662011-04-28 14:31:47 -0700362 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363}
364
David Ahern9ab179d2016-04-07 11:10:06 -0700365struct rt6_info *ip6_dst_alloc(struct net *net,
366 struct net_device *dev,
367 int flags)
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700368{
Martin KaFai Lauad706862015-08-14 11:05:52 -0700369 struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700370
371 if (rt) {
372 rt->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, GFP_ATOMIC);
373 if (rt->rt6i_pcpu) {
374 int cpu;
375
376 for_each_possible_cpu(cpu) {
377 struct rt6_info **p;
378
379 p = per_cpu_ptr(rt->rt6i_pcpu, cpu);
380 /* no one shares rt */
381 *p = NULL;
382 }
383 } else {
Wei Wang1cfb71e2017-06-17 10:42:33 -0700384 dst_release(&rt->dst);
385 if (!(flags & DST_NOCACHE))
386 dst_destroy((struct dst_entry *)rt);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700387 return NULL;
388 }
389 }
390
391 return rt;
392}
David Ahern9ab179d2016-04-07 11:10:06 -0700393EXPORT_SYMBOL(ip6_dst_alloc);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700394
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395static void ip6_dst_destroy(struct dst_entry *dst)
396{
397 struct rt6_info *rt = (struct rt6_info *)dst;
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000398 struct dst_entry *from = dst->from;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700399 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700401 dst_destroy_metrics_generic(dst);
Markus Elfring87775312015-07-02 16:30:24 +0200402 free_percpu(rt->rt6i_pcpu);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700403 rt6_uncached_list_del(rt);
404
405 idev = rt->rt6i_idev;
David S. Miller38308472011-12-03 18:02:47 -0500406 if (idev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 rt->rt6i_idev = NULL;
408 in6_dev_put(idev);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900409 }
Gao feng1716a962012-04-06 00:13:10 +0000410
YOSHIFUJI Hideaki / 吉藤英明ecd98832013-02-20 00:29:08 +0000411 dst->from = NULL;
412 dst_release(from);
David S. Millerb3419362010-11-30 12:27:11 -0800413}
414
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
416 int how)
417{
418 struct rt6_info *rt = (struct rt6_info *)dst;
419 struct inet6_dev *idev = rt->rt6i_idev;
Denis V. Lunev5a3e55d2007-12-07 00:38:10 -0800420 struct net_device *loopback_dev =
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900421 dev_net(dev)->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422
David S. Miller97cac082012-07-02 22:43:47 -0700423 if (dev != loopback_dev) {
424 if (idev && idev->dev == dev) {
425 struct inet6_dev *loopback_idev =
426 in6_dev_get(loopback_dev);
427 if (loopback_idev) {
428 rt->rt6i_idev = loopback_idev;
429 in6_dev_put(idev);
430 }
431 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 }
433}
434
Martin KaFai Lau5973fb12015-11-11 11:51:07 -0800435static bool __rt6_check_expired(const struct rt6_info *rt)
436{
437 if (rt->rt6i_flags & RTF_EXPIRES)
438 return time_after(jiffies, rt->dst.expires);
439 else
440 return false;
441}
442
Eric Dumazeta50feda2012-05-18 18:57:34 +0000443static bool rt6_check_expired(const struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444{
Gao feng1716a962012-04-06 00:13:10 +0000445 if (rt->rt6i_flags & RTF_EXPIRES) {
446 if (time_after(jiffies, rt->dst.expires))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000447 return true;
Gao feng1716a962012-04-06 00:13:10 +0000448 } else if (rt->dst.from) {
Li RongQing3fd91fb2012-09-13 19:54:57 +0000449 return rt6_check_expired((struct rt6_info *) rt->dst.from);
Gao feng1716a962012-04-06 00:13:10 +0000450 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000451 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452}
453
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000454/* Multipath route selection:
455 * Hash based function using packet header and flowlabel.
456 * Adapted from fib_info_hashfn()
457 */
458static int rt6_info_hash_nhsfn(unsigned int candidate_count,
459 const struct flowi6 *fl6)
460{
Tom Herbert644d0e62015-09-23 14:13:35 -0700461 return get_hash_from_flowi6(fl6) % candidate_count;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000462}
463
464static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200465 struct flowi6 *fl6, int oif,
466 int strict)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000467{
468 struct rt6_info *sibling, *next_sibling;
469 int route_choosen;
470
471 route_choosen = rt6_info_hash_nhsfn(match->rt6i_nsiblings + 1, fl6);
472 /* Don't change the route, if route_choosen == 0
473 * (siblings does not include ourself)
474 */
475 if (route_choosen)
476 list_for_each_entry_safe(sibling, next_sibling,
477 &match->rt6i_siblings, rt6i_siblings) {
478 route_choosen--;
479 if (route_choosen == 0) {
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200480 if (rt6_score_route(sibling, oif, strict) < 0)
481 break;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000482 match = sibling;
483 break;
484 }
485 }
486 return match;
487}
488
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489/*
Thomas Grafc71099a2006-08-04 23:20:06 -0700490 * Route lookup. Any table->tb6_lock is implied.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 */
492
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800493static inline struct rt6_info *rt6_device_match(struct net *net,
494 struct rt6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000495 const struct in6_addr *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 int oif,
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700497 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498{
499 struct rt6_info *local = NULL;
500 struct rt6_info *sprt;
501
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900502 if (!oif && ipv6_addr_any(saddr))
503 goto out;
504
Changli Gaod8d1f302010-06-10 23:31:35 -0700505 for (sprt = rt; sprt; sprt = sprt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -0500506 struct net_device *dev = sprt->dst.dev;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900507
508 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 if (dev->ifindex == oif)
510 return sprt;
511 if (dev->flags & IFF_LOOPBACK) {
David S. Miller38308472011-12-03 18:02:47 -0500512 if (!sprt->rt6i_idev ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 sprt->rt6i_idev->dev->ifindex != oif) {
David Ahern17fb0b22015-09-25 15:22:54 -0600514 if (flags & RT6_LOOKUP_F_IFACE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 continue;
David Ahern17fb0b22015-09-25 15:22:54 -0600516 if (local &&
517 local->rt6i_idev->dev->ifindex == oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 continue;
519 }
520 local = sprt;
521 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900522 } else {
523 if (ipv6_chk_addr(net, saddr, dev,
524 flags & RT6_LOOKUP_F_IFACE))
525 return sprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900527 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900529 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 if (local)
531 return local;
532
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700533 if (flags & RT6_LOOKUP_F_IFACE)
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800534 return net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900536out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 return rt;
538}
539
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800540#ifdef CONFIG_IPV6_ROUTER_PREF
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200541struct __rt6_probe_work {
542 struct work_struct work;
543 struct in6_addr target;
544 struct net_device *dev;
545};
546
547static void rt6_probe_deferred(struct work_struct *w)
548{
549 struct in6_addr mcaddr;
550 struct __rt6_probe_work *work =
551 container_of(w, struct __rt6_probe_work, work);
552
553 addrconf_addr_solict_mult(&work->target, &mcaddr);
Erik Nordmarkadc176c2016-12-02 14:00:08 -0800554 ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL, 0);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200555 dev_put(work->dev);
Michael Büsch662f5532015-02-08 10:14:07 +0100556 kfree(work);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200557}
558
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800559static void rt6_probe(struct rt6_info *rt)
560{
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700561 struct __rt6_probe_work *work;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000562 struct neighbour *neigh;
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800563 /*
564 * Okay, this does not seem to be appropriate
565 * for now, however, we need to check if it
566 * is really so; aka Router Reachability Probing.
567 *
568 * Router Reachability Probe MUST be rate-limited
569 * to no more than one per minute.
570 */
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000571 if (!rt || !(rt->rt6i_flags & RTF_GATEWAY))
Amerigo Wangfdd66812012-09-10 02:48:44 +0000572 return;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000573 rcu_read_lock_bh();
574 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
575 if (neigh) {
Martin KaFai Lau8d6c31b2015-07-24 09:57:43 -0700576 if (neigh->nud_state & NUD_VALID)
577 goto out;
578
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700579 work = NULL;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000580 write_lock(&neigh->lock);
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700581 if (!(neigh->nud_state & NUD_VALID) &&
582 time_after(jiffies,
583 neigh->updated +
584 rt->rt6i_idev->cnf.rtr_probe_interval)) {
585 work = kmalloc(sizeof(*work), GFP_ATOMIC);
586 if (work)
587 __neigh_set_probe_once(neigh);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200588 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000589 write_unlock(&neigh->lock);
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700590 } else {
591 work = kmalloc(sizeof(*work), GFP_ATOMIC);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000592 }
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700593
594 if (work) {
595 INIT_WORK(&work->work, rt6_probe_deferred);
596 work->target = rt->rt6i_gateway;
597 dev_hold(rt->dst.dev);
598 work->dev = rt->dst.dev;
599 schedule_work(&work->work);
600 }
601
Martin KaFai Lau8d6c31b2015-07-24 09:57:43 -0700602out:
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000603 rcu_read_unlock_bh();
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800604}
605#else
606static inline void rt6_probe(struct rt6_info *rt)
607{
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800608}
609#endif
610
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611/*
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800612 * Default Router Selection (RFC 2461 6.3.6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 */
Dave Jonesb6f99a22007-03-22 12:27:49 -0700614static inline int rt6_check_dev(struct rt6_info *rt, int oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615{
David S. Millerd1918542011-12-28 20:19:20 -0500616 struct net_device *dev = rt->dst.dev;
David S. Miller161980f2007-04-06 11:42:27 -0700617 if (!oif || dev->ifindex == oif)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800618 return 2;
David S. Miller161980f2007-04-06 11:42:27 -0700619 if ((dev->flags & IFF_LOOPBACK) &&
620 rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
621 return 1;
622 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623}
624
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200625static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626{
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000627 struct neighbour *neigh;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200628 enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000629
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700630 if (rt->rt6i_flags & RTF_NONEXTHOP ||
631 !(rt->rt6i_flags & RTF_GATEWAY))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200632 return RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000633
634 rcu_read_lock_bh();
635 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
636 if (neigh) {
637 read_lock(&neigh->lock);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800638 if (neigh->nud_state & NUD_VALID)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200639 ret = RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800640#ifdef CONFIG_IPV6_ROUTER_PREF
Paul Marksa5a81f02012-12-03 10:26:54 +0000641 else if (!(neigh->nud_state & NUD_FAILED))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200642 ret = RT6_NUD_SUCCEED;
Jiri Benc7e980562013-12-11 13:48:20 +0100643 else
644 ret = RT6_NUD_FAIL_PROBE;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800645#endif
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000646 read_unlock(&neigh->lock);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200647 } else {
648 ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
Jiri Benc7e980562013-12-11 13:48:20 +0100649 RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR;
Paul Marksa5a81f02012-12-03 10:26:54 +0000650 }
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000651 rcu_read_unlock_bh();
652
Paul Marksa5a81f02012-12-03 10:26:54 +0000653 return ret;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800654}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800656static int rt6_score_route(struct rt6_info *rt, int oif,
657 int strict)
658{
Paul Marksa5a81f02012-12-03 10:26:54 +0000659 int m;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900660
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700661 m = rt6_check_dev(rt, oif);
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700662 if (!m && (strict & RT6_LOOKUP_F_IFACE))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200663 return RT6_NUD_FAIL_HARD;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800664#ifdef CONFIG_IPV6_ROUTER_PREF
665 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
666#endif
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200667 if (strict & RT6_LOOKUP_F_REACHABLE) {
668 int n = rt6_check_neigh(rt);
669 if (n < 0)
670 return n;
671 }
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800672 return m;
673}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674
David S. Millerf11e6652007-03-24 20:36:25 -0700675static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200676 int *mpri, struct rt6_info *match,
677 bool *do_rr)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800678{
David S. Millerf11e6652007-03-24 20:36:25 -0700679 int m;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200680 bool match_do_rr = false;
Andy Gospodarek35103d12015-08-13 10:39:01 -0400681 struct inet6_dev *idev = rt->rt6i_idev;
682 struct net_device *dev = rt->dst.dev;
683
684 if (dev && !netif_carrier_ok(dev) &&
David Ahernd5d32e42016-10-24 12:27:23 -0700685 idev->cnf.ignore_routes_with_linkdown &&
686 !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE))
Andy Gospodarek35103d12015-08-13 10:39:01 -0400687 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700688
689 if (rt6_check_expired(rt))
690 goto out;
691
692 m = rt6_score_route(rt, oif, strict);
Jiri Benc7e980562013-12-11 13:48:20 +0100693 if (m == RT6_NUD_FAIL_DO_RR) {
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200694 match_do_rr = true;
695 m = 0; /* lowest valid score */
Jiri Benc7e980562013-12-11 13:48:20 +0100696 } else if (m == RT6_NUD_FAIL_HARD) {
David S. Millerf11e6652007-03-24 20:36:25 -0700697 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700698 }
699
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200700 if (strict & RT6_LOOKUP_F_REACHABLE)
701 rt6_probe(rt);
702
Jiri Benc7e980562013-12-11 13:48:20 +0100703 /* note that m can be RT6_NUD_FAIL_PROBE at this point */
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200704 if (m > *mpri) {
705 *do_rr = match_do_rr;
706 *mpri = m;
707 match = rt;
708 }
David S. Millerf11e6652007-03-24 20:36:25 -0700709out:
710 return match;
711}
712
713static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
714 struct rt6_info *rr_head,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200715 u32 metric, int oif, int strict,
716 bool *do_rr)
David S. Millerf11e6652007-03-24 20:36:25 -0700717{
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700718 struct rt6_info *rt, *match, *cont;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800719 int mpri = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
David S. Millerf11e6652007-03-24 20:36:25 -0700721 match = NULL;
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700722 cont = NULL;
723 for (rt = rr_head; rt; rt = rt->dst.rt6_next) {
724 if (rt->rt6i_metric != metric) {
725 cont = rt;
726 break;
727 }
728
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200729 match = find_match(rt, oif, strict, &mpri, match, do_rr);
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700730 }
731
732 for (rt = fn->leaf; rt && rt != rr_head; rt = rt->dst.rt6_next) {
733 if (rt->rt6i_metric != metric) {
734 cont = rt;
735 break;
736 }
737
738 match = find_match(rt, oif, strict, &mpri, match, do_rr);
739 }
740
741 if (match || !cont)
742 return match;
743
744 for (rt = cont; rt; rt = rt->dst.rt6_next)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200745 match = find_match(rt, oif, strict, &mpri, match, do_rr);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800746
David S. Millerf11e6652007-03-24 20:36:25 -0700747 return match;
748}
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800749
David S. Millerf11e6652007-03-24 20:36:25 -0700750static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
751{
752 struct rt6_info *match, *rt0;
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800753 struct net *net;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200754 bool do_rr = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755
David S. Millerf11e6652007-03-24 20:36:25 -0700756 rt0 = fn->rr_ptr;
757 if (!rt0)
758 fn->rr_ptr = rt0 = fn->leaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200760 match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict,
761 &do_rr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200763 if (do_rr) {
Changli Gaod8d1f302010-06-10 23:31:35 -0700764 struct rt6_info *next = rt0->dst.rt6_next;
David S. Millerf11e6652007-03-24 20:36:25 -0700765
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800766 /* no entries matched; do round-robin */
David S. Millerf11e6652007-03-24 20:36:25 -0700767 if (!next || next->rt6i_metric != rt0->rt6i_metric)
768 next = fn->leaf;
769
770 if (next != rt0)
771 fn->rr_ptr = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 }
773
David S. Millerd1918542011-12-28 20:19:20 -0500774 net = dev_net(rt0->dst.dev);
Eric Dumazeta02cec22010-09-22 20:43:57 +0000775 return match ? match : net->ipv6.ip6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776}
777
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700778static bool rt6_is_gw_or_nonexthop(const struct rt6_info *rt)
779{
780 return (rt->rt6i_flags & (RTF_NONEXTHOP | RTF_GATEWAY));
781}
782
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800783#ifdef CONFIG_IPV6_ROUTE_INFO
784int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000785 const struct in6_addr *gwaddr)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800786{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900787 struct net *net = dev_net(dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800788 struct route_info *rinfo = (struct route_info *) opt;
789 struct in6_addr prefix_buf, *prefix;
790 unsigned int pref;
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900791 unsigned long lifetime;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800792 struct rt6_info *rt;
793
794 if (len < sizeof(struct route_info)) {
795 return -EINVAL;
796 }
797
798 /* Sanity check for prefix_len and length */
799 if (rinfo->length > 3) {
800 return -EINVAL;
801 } else if (rinfo->prefix_len > 128) {
802 return -EINVAL;
803 } else if (rinfo->prefix_len > 64) {
804 if (rinfo->length < 2) {
805 return -EINVAL;
806 }
807 } else if (rinfo->prefix_len > 0) {
808 if (rinfo->length < 1) {
809 return -EINVAL;
810 }
811 }
812
813 pref = rinfo->route_pref;
814 if (pref == ICMPV6_ROUTER_PREF_INVALID)
Jens Rosenboom3933fc92009-09-10 06:25:11 +0000815 return -EINVAL;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800816
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900817 lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800818
819 if (rinfo->length == 3)
820 prefix = (struct in6_addr *)rinfo->prefix;
821 else {
822 /* this function is safe */
823 ipv6_addr_prefix(&prefix_buf,
824 (struct in6_addr *)rinfo->prefix,
825 rinfo->prefix_len);
826 prefix = &prefix_buf;
827 }
828
Duan Jiongf104a562013-11-08 09:56:53 +0800829 if (rinfo->prefix_len == 0)
830 rt = rt6_get_dflt_router(gwaddr, dev);
831 else
832 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len,
David Ahern830218c2016-10-24 10:52:35 -0700833 gwaddr, dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800834
835 if (rt && !lifetime) {
Thomas Grafe0a1ad732006-08-22 00:00:21 -0700836 ip6_del_rt(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800837 rt = NULL;
838 }
839
840 if (!rt && lifetime)
David Ahern830218c2016-10-24 10:52:35 -0700841 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr,
842 dev, pref);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800843 else if (rt)
844 rt->rt6i_flags = RTF_ROUTEINFO |
845 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
846
847 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +0000848 if (!addrconf_finite_timeout(lifetime))
849 rt6_clean_expires(rt);
850 else
851 rt6_set_expires(rt, jiffies + HZ * lifetime);
852
Amerigo Wang94e187c2012-10-29 00:13:19 +0000853 ip6_rt_put(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800854 }
855 return 0;
856}
857#endif
858
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700859static struct fib6_node* fib6_backtrack(struct fib6_node *fn,
860 struct in6_addr *saddr)
861{
862 struct fib6_node *pn;
863 while (1) {
864 if (fn->fn_flags & RTN_TL_ROOT)
865 return NULL;
866 pn = fn->parent;
867 if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn)
868 fn = fib6_lookup(FIB6_SUBTREE(pn), NULL, saddr);
869 else
870 fn = pn;
871 if (fn->fn_flags & RTN_RTINFO)
872 return fn;
873 }
874}
Thomas Grafc71099a2006-08-04 23:20:06 -0700875
Daniel Lezcano8ed67782008-03-04 13:48:30 -0800876static struct rt6_info *ip6_pol_route_lookup(struct net *net,
877 struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -0500878 struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879{
880 struct fib6_node *fn;
881 struct rt6_info *rt;
882
Thomas Grafc71099a2006-08-04 23:20:06 -0700883 read_lock_bh(&table->tb6_lock);
David S. Miller4c9483b2011-03-12 16:22:43 -0500884 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -0700885restart:
886 rt = fn->leaf;
David S. Miller4c9483b2011-03-12 16:22:43 -0500887 rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000888 if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0)
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +0200889 rt = rt6_multipath_select(rt, fl6, fl6->flowi6_oif, flags);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -0700890 if (rt == net->ipv6.ip6_null_entry) {
891 fn = fib6_backtrack(fn, &fl6->saddr);
892 if (fn)
893 goto restart;
894 }
Changli Gaod8d1f302010-06-10 23:31:35 -0700895 dst_use(&rt->dst, jiffies);
Thomas Grafc71099a2006-08-04 23:20:06 -0700896 read_unlock_bh(&table->tb6_lock);
David Ahernb8115802015-11-19 12:24:22 -0800897
898 trace_fib6_table_lookup(net, rt, table->tb6_id, fl6);
899
Thomas Grafc71099a2006-08-04 23:20:06 -0700900 return rt;
901
902}
903
Ian Morris67ba4152014-08-24 21:53:10 +0100904struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
Florian Westphalea6e5742011-09-05 16:05:44 +0200905 int flags)
906{
907 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup);
908}
909EXPORT_SYMBOL_GPL(ip6_route_lookup);
910
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +0900911struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
912 const struct in6_addr *saddr, int oif, int strict)
Thomas Grafc71099a2006-08-04 23:20:06 -0700913{
David S. Miller4c9483b2011-03-12 16:22:43 -0500914 struct flowi6 fl6 = {
915 .flowi6_oif = oif,
916 .daddr = *daddr,
Thomas Grafc71099a2006-08-04 23:20:06 -0700917 };
918 struct dst_entry *dst;
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700919 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
Thomas Grafc71099a2006-08-04 23:20:06 -0700920
Thomas Grafadaa70b2006-10-13 15:01:03 -0700921 if (saddr) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500922 memcpy(&fl6.saddr, saddr, sizeof(*saddr));
Thomas Grafadaa70b2006-10-13 15:01:03 -0700923 flags |= RT6_LOOKUP_F_HAS_SADDR;
924 }
925
David S. Miller4c9483b2011-03-12 16:22:43 -0500926 dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup);
Thomas Grafc71099a2006-08-04 23:20:06 -0700927 if (dst->error == 0)
928 return (struct rt6_info *) dst;
929
930 dst_release(dst);
931
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 return NULL;
933}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900934EXPORT_SYMBOL(rt6_lookup);
935
Thomas Grafc71099a2006-08-04 23:20:06 -0700936/* ip6_ins_rt is called with FREE table->tb6_lock.
Wei Wang1cfb71e2017-06-17 10:42:33 -0700937 * It takes new route entry, the addition fails by any reason the
938 * route is released.
939 * Caller must hold dst before calling it.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 */
941
Michal Kubečeke5fd3872014-03-27 13:04:08 +0100942static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info,
David Ahern333c4302017-05-21 10:12:04 -0600943 struct mx6_config *mxc,
944 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945{
946 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -0700947 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
Thomas Grafc71099a2006-08-04 23:20:06 -0700949 table = rt->rt6i_table;
950 write_lock_bh(&table->tb6_lock);
David Ahern333c4302017-05-21 10:12:04 -0600951 err = fib6_add(&table->tb6_root, rt, info, mxc, extack);
Thomas Grafc71099a2006-08-04 23:20:06 -0700952 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
954 return err;
955}
956
Thomas Graf40e22e82006-08-22 00:00:45 -0700957int ip6_ins_rt(struct rt6_info *rt)
958{
Florian Westphale715b6d2015-01-05 23:57:44 +0100959 struct nl_info info = { .nl_net = dev_net(rt->dst.dev), };
960 struct mx6_config mxc = { .mx = NULL, };
961
Wei Wang1cfb71e2017-06-17 10:42:33 -0700962 /* Hold dst to account for the reference from the fib6 tree */
963 dst_hold(&rt->dst);
David Ahern333c4302017-05-21 10:12:04 -0600964 return __ip6_ins_rt(rt, &info, &mxc, NULL);
Thomas Graf40e22e82006-08-22 00:00:45 -0700965}
966
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700967static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort,
968 const struct in6_addr *daddr,
969 const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 struct rt6_info *rt;
972
973 /*
974 * Clone the route.
975 */
976
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700977 if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU))
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700978 ort = (struct rt6_info *)ort->dst.from;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
Martin KaFai Lauad706862015-08-14 11:05:52 -0700980 rt = __ip6_dst_alloc(dev_net(ort->dst.dev), ort->dst.dev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700982 if (!rt)
983 return NULL;
984
985 ip6_rt_copy_init(rt, ort);
986 rt->rt6i_flags |= RTF_CACHE;
987 rt->rt6i_metric = 0;
988 rt->dst.flags |= DST_HOST;
989 rt->rt6i_dst.addr = *daddr;
990 rt->rt6i_dst.plen = 128;
991
992 if (!rt6_is_gw_or_nonexthop(ort)) {
993 if (ort->rt6i_dst.plen != 128 &&
994 ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
995 rt->rt6i_flags |= RTF_ANYCAST;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -0700997 if (rt->rt6i_src.plen && saddr) {
998 rt->rt6i_src.addr = *saddr;
999 rt->rt6i_src.plen = 128;
Martin KaFai Lau8b9df262015-05-22 20:55:59 -07001000 }
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001001#endif
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -08001002 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -08001004 return rt;
1005}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001007static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt)
1008{
1009 struct rt6_info *pcpu_rt;
1010
1011 pcpu_rt = __ip6_dst_alloc(dev_net(rt->dst.dev),
Martin KaFai Lauad706862015-08-14 11:05:52 -07001012 rt->dst.dev, rt->dst.flags);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001013
1014 if (!pcpu_rt)
1015 return NULL;
1016 ip6_rt_copy_init(pcpu_rt, rt);
1017 pcpu_rt->rt6i_protocol = rt->rt6i_protocol;
1018 pcpu_rt->rt6i_flags |= RTF_PCPU;
1019 return pcpu_rt;
1020}
1021
1022/* It should be called with read_lock_bh(&tb6_lock) acquired */
1023static struct rt6_info *rt6_get_pcpu_route(struct rt6_info *rt)
1024{
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001025 struct rt6_info *pcpu_rt, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001026
1027 p = this_cpu_ptr(rt->rt6i_pcpu);
1028 pcpu_rt = *p;
1029
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001030 if (pcpu_rt) {
1031 dst_hold(&pcpu_rt->dst);
1032 rt6_dst_from_metrics_check(pcpu_rt);
1033 }
1034 return pcpu_rt;
1035}
1036
1037static struct rt6_info *rt6_make_pcpu_route(struct rt6_info *rt)
1038{
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001039 struct fib6_table *table = rt->rt6i_table;
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001040 struct rt6_info *pcpu_rt, *prev, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001041
1042 pcpu_rt = ip6_rt_pcpu_alloc(rt);
1043 if (!pcpu_rt) {
1044 struct net *net = dev_net(rt->dst.dev);
1045
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001046 dst_hold(&net->ipv6.ip6_null_entry->dst);
1047 return net->ipv6.ip6_null_entry;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001048 }
1049
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001050 read_lock_bh(&table->tb6_lock);
1051 if (rt->rt6i_pcpu) {
1052 p = this_cpu_ptr(rt->rt6i_pcpu);
1053 prev = cmpxchg(p, NULL, pcpu_rt);
1054 if (prev) {
1055 /* If someone did it before us, return prev instead */
Wei Wang1cfb71e2017-06-17 10:42:33 -07001056 dst_release(&pcpu_rt->dst);
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001057 dst_destroy(&pcpu_rt->dst);
1058 pcpu_rt = prev;
1059 }
1060 } else {
1061 /* rt has been removed from the fib6 tree
1062 * before we have a chance to acquire the read_lock.
1063 * In this case, don't brother to create a pcpu rt
1064 * since rt is going away anyway. The next
1065 * dst_check() will trigger a re-lookup.
1066 */
Wei Wang1cfb71e2017-06-17 10:42:33 -07001067 dst_release(&pcpu_rt->dst);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001068 dst_destroy(&pcpu_rt->dst);
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001069 pcpu_rt = rt;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001070 }
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001071 dst_hold(&pcpu_rt->dst);
1072 rt6_dst_from_metrics_check(pcpu_rt);
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001073 read_unlock_bh(&table->tb6_lock);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001074 return pcpu_rt;
1075}
1076
David Ahern9ff74382016-06-13 13:44:19 -07001077struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
1078 int oif, struct flowi6 *fl6, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079{
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001080 struct fib6_node *fn, *saved_fn;
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001081 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001082 int strict = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001084 strict |= flags & RT6_LOOKUP_F_IFACE;
David Ahernd5d32e42016-10-24 12:27:23 -07001085 strict |= flags & RT6_LOOKUP_F_IGNORE_LINKSTATE;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001086 if (net->ipv6.devconf_all->forwarding == 0)
1087 strict |= RT6_LOOKUP_F_REACHABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
Thomas Grafc71099a2006-08-04 23:20:06 -07001089 read_lock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090
David S. Miller4c9483b2011-03-12 16:22:43 -05001091 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001092 saved_fn = fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093
David Ahernca254492015-10-12 11:47:10 -07001094 if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
1095 oif = 0;
1096
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001097redo_rt6_select:
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001098 rt = rt6_select(fn, oif, strict);
Nicolas Dichtel52bd4c02013-06-28 17:35:48 +02001099 if (rt->rt6i_nsiblings)
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001100 rt = rt6_multipath_select(rt, fl6, oif, strict);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001101 if (rt == net->ipv6.ip6_null_entry) {
1102 fn = fib6_backtrack(fn, &fl6->saddr);
1103 if (fn)
1104 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001105 else if (strict & RT6_LOOKUP_F_REACHABLE) {
1106 /* also consider unreachable route */
1107 strict &= ~RT6_LOOKUP_F_REACHABLE;
1108 fn = saved_fn;
1109 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001110 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001111 }
1112
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -08001113
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001114 if (rt == net->ipv6.ip6_null_entry || (rt->rt6i_flags & RTF_CACHE)) {
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001115 dst_use(&rt->dst, jiffies);
1116 read_unlock_bh(&table->tb6_lock);
1117
1118 rt6_dst_from_metrics_check(rt);
David Ahernb8115802015-11-19 12:24:22 -08001119
1120 trace_fib6_table_lookup(net, rt, table->tb6_id, fl6);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001121 return rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001122 } else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) &&
1123 !(rt->rt6i_flags & RTF_GATEWAY))) {
1124 /* Create a RTF_CACHE clone which will not be
1125 * owned by the fib6 tree. It is for the special case where
1126 * the daddr in the skb during the neighbor look-up is different
1127 * from the fl6->daddr used to look-up route here.
1128 */
Thomas Grafc71099a2006-08-04 23:20:06 -07001129
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001130 struct rt6_info *uncached_rt;
1131
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001132 dst_use(&rt->dst, jiffies);
1133 read_unlock_bh(&table->tb6_lock);
1134
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001135 uncached_rt = ip6_rt_cache_alloc(rt, &fl6->daddr, NULL);
1136 dst_release(&rt->dst);
1137
Wei Wang1cfb71e2017-06-17 10:42:33 -07001138 if (uncached_rt) {
1139 /* Uncached_rt's refcnt is taken during ip6_rt_cache_alloc()
1140 * No need for another dst_hold()
1141 */
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07001142 rt6_uncached_list_add(uncached_rt);
Wei Wang1cfb71e2017-06-17 10:42:33 -07001143 } else {
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001144 uncached_rt = net->ipv6.ip6_null_entry;
Wei Wang1cfb71e2017-06-17 10:42:33 -07001145 dst_hold(&uncached_rt->dst);
1146 }
David Ahernb8115802015-11-19 12:24:22 -08001147
1148 trace_fib6_table_lookup(net, uncached_rt, table->tb6_id, fl6);
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001149 return uncached_rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001150
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001151 } else {
1152 /* Get a percpu copy */
1153
1154 struct rt6_info *pcpu_rt;
1155
1156 rt->dst.lastuse = jiffies;
1157 rt->dst.__use++;
1158 pcpu_rt = rt6_get_pcpu_route(rt);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001159
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001160 if (pcpu_rt) {
1161 read_unlock_bh(&table->tb6_lock);
1162 } else {
1163 /* We have to do the read_unlock first
1164 * because rt6_make_pcpu_route() may trigger
1165 * ip6_dst_gc() which will take the write_lock.
1166 */
1167 dst_hold(&rt->dst);
1168 read_unlock_bh(&table->tb6_lock);
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001169 pcpu_rt = rt6_make_pcpu_route(rt);
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001170 dst_release(&rt->dst);
1171 }
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001172
David Ahernb8115802015-11-19 12:24:22 -08001173 trace_fib6_table_lookup(net, pcpu_rt, table->tb6_id, fl6);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001174 return pcpu_rt;
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001175
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001176 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001177}
David Ahern9ff74382016-06-13 13:44:19 -07001178EXPORT_SYMBOL_GPL(ip6_pol_route);
Thomas Grafc71099a2006-08-04 23:20:06 -07001179
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001180static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -05001181 struct flowi6 *fl6, int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001182{
David S. Miller4c9483b2011-03-12 16:22:43 -05001183 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001184}
1185
Mahesh Bandeward409b842016-09-16 12:59:08 -07001186struct dst_entry *ip6_route_input_lookup(struct net *net,
1187 struct net_device *dev,
1188 struct flowi6 *fl6, int flags)
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001189{
1190 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
1191 flags |= RT6_LOOKUP_F_IFACE;
1192
1193 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_input);
1194}
Mahesh Bandeward409b842016-09-16 12:59:08 -07001195EXPORT_SYMBOL_GPL(ip6_route_input_lookup);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001196
Thomas Grafc71099a2006-08-04 23:20:06 -07001197void ip6_route_input(struct sk_buff *skb)
1198{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001199 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001200 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001201 int flags = RT6_LOOKUP_F_HAS_SADDR;
Jiri Benc904af042015-08-20 13:56:31 +02001202 struct ip_tunnel_info *tun_info;
David S. Miller4c9483b2011-03-12 16:22:43 -05001203 struct flowi6 fl6 = {
David Aherne0d56fd2016-09-10 12:09:57 -07001204 .flowi6_iif = skb->dev->ifindex,
David S. Miller4c9483b2011-03-12 16:22:43 -05001205 .daddr = iph->daddr,
1206 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001207 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -05001208 .flowi6_mark = skb->mark,
1209 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -07001210 };
Thomas Grafadaa70b2006-10-13 15:01:03 -07001211
Jiri Benc904af042015-08-20 13:56:31 +02001212 tun_info = skb_tunnel_info(skb);
Jiri Benc46fa0622015-08-28 20:48:19 +02001213 if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX))
Jiri Benc904af042015-08-20 13:56:31 +02001214 fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id;
Jiri Benc06e9d042015-08-20 13:56:26 +02001215 skb_dst_drop(skb);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001216 skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -07001217}
1218
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001219static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
David S. Miller4c9483b2011-03-12 16:22:43 -05001220 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07001221{
David S. Miller4c9483b2011-03-12 16:22:43 -05001222 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -07001223}
1224
Paolo Abeni6f21c962016-01-29 12:30:19 +01001225struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk,
1226 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07001227{
David Ahernd46a9d62015-10-21 08:42:22 -07001228 bool any_src;
Thomas Grafc71099a2006-08-04 23:20:06 -07001229
David Ahern4c1feac2016-09-10 12:09:56 -07001230 if (rt6_need_strict(&fl6->daddr)) {
1231 struct dst_entry *dst;
1232
1233 dst = l3mdev_link_scope_lookup(net, fl6);
1234 if (dst)
1235 return dst;
1236 }
David Ahernca254492015-10-12 11:47:10 -07001237
Pavel Emelyanov1fb94892012-08-08 21:53:36 +00001238 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +00001239
David Ahernd46a9d62015-10-21 08:42:22 -07001240 any_src = ipv6_addr_any(&fl6->saddr);
David Ahern741a11d2015-09-28 10:12:13 -07001241 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) ||
David Ahernd46a9d62015-10-21 08:42:22 -07001242 (fl6->flowi6_oif && any_src))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001243 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -07001244
David Ahernd46a9d62015-10-21 08:42:22 -07001245 if (!any_src)
Thomas Grafadaa70b2006-10-13 15:01:03 -07001246 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +00001247 else if (sk)
1248 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -07001249
David S. Miller4c9483b2011-03-12 16:22:43 -05001250 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251}
Paolo Abeni6f21c962016-01-29 12:30:19 +01001252EXPORT_SYMBOL_GPL(ip6_route_output_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
David S. Miller2774c132011-03-01 14:59:04 -08001254struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -07001255{
David S. Miller5c1e6aa2011-04-28 14:13:38 -07001256 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
Wei Wang1dbe32522017-06-17 10:42:26 -07001257 struct net_device *loopback_dev = net->loopback_dev;
David S. Miller14e50e52007-05-24 18:17:54 -07001258 struct dst_entry *new = NULL;
1259
Wei Wang1dbe32522017-06-17 10:42:26 -07001260
1261 rt = dst_alloc(&ip6_dst_blackhole_ops, loopback_dev, 1,
1262 DST_OBSOLETE_NONE, 0);
David S. Miller14e50e52007-05-24 18:17:54 -07001263 if (rt) {
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07001264 rt6_info_init(rt);
1265
Changli Gaod8d1f302010-06-10 23:31:35 -07001266 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -07001267 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08001268 new->input = dst_discard;
Eric W. Biedermanede20592015-10-07 16:48:47 -05001269 new->output = dst_discard_out;
David S. Miller14e50e52007-05-24 18:17:54 -07001270
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07001271 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07001272
Wei Wang1dbe32522017-06-17 10:42:26 -07001273 rt->rt6i_idev = in6_dev_get(loopback_dev);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001274 rt->rt6i_gateway = ort->rt6i_gateway;
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07001275 rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU;
David S. Miller14e50e52007-05-24 18:17:54 -07001276 rt->rt6i_metric = 0;
1277
1278 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
1279#ifdef CONFIG_IPV6_SUBTREES
1280 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1281#endif
1282
1283 dst_free(new);
1284 }
1285
David S. Miller69ead7a2011-03-01 14:45:33 -08001286 dst_release(dst_orig);
1287 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07001288}
David S. Miller14e50e52007-05-24 18:17:54 -07001289
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290/*
1291 * Destination cache support functions
1292 */
1293
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001294static void rt6_dst_from_metrics_check(struct rt6_info *rt)
1295{
1296 if (rt->dst.from &&
1297 dst_metrics_ptr(&rt->dst) != dst_metrics_ptr(rt->dst.from))
1298 dst_init_metrics(&rt->dst, dst_metrics_ptr(rt->dst.from), true);
1299}
1300
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001301static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie)
1302{
1303 if (!rt->rt6i_node || (rt->rt6i_node->fn_sernum != cookie))
1304 return NULL;
1305
1306 if (rt6_check_expired(rt))
1307 return NULL;
1308
1309 return &rt->dst;
1310}
1311
1312static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, u32 cookie)
1313{
Martin KaFai Lau5973fb12015-11-11 11:51:07 -08001314 if (!__rt6_check_expired(rt) &&
1315 rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001316 rt6_check((struct rt6_info *)(rt->dst.from), cookie))
1317 return &rt->dst;
1318 else
1319 return NULL;
1320}
1321
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
1323{
1324 struct rt6_info *rt;
1325
1326 rt = (struct rt6_info *) dst;
1327
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00001328 /* All IPV6 dsts are created with ->obsolete set to the value
1329 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
1330 * into this function always.
1331 */
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02001332
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001333 rt6_dst_from_metrics_check(rt);
1334
Martin KaFai Lau02bcf4e2015-11-11 11:51:08 -08001335 if (rt->rt6i_flags & RTF_PCPU ||
1336 (unlikely(dst->flags & DST_NOCACHE) && rt->dst.from))
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001337 return rt6_dst_from_check(rt, cookie);
1338 else
1339 return rt6_check(rt, cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340}
1341
1342static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
1343{
1344 struct rt6_info *rt = (struct rt6_info *) dst;
1345
1346 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001347 if (rt->rt6i_flags & RTF_CACHE) {
1348 if (rt6_check_expired(rt)) {
1349 ip6_del_rt(rt);
1350 dst = NULL;
1351 }
1352 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001354 dst = NULL;
1355 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00001357 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358}
1359
1360static void ip6_link_failure(struct sk_buff *skb)
1361{
1362 struct rt6_info *rt;
1363
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00001364 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
Eric Dumazetadf30902009-06-02 05:19:30 +00001366 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 if (rt) {
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001368 if (rt->rt6i_flags & RTF_CACHE) {
Wei Wangad65a2f2017-06-17 10:42:35 -07001369 if (dst_hold_safe(&rt->dst))
1370 ip6_del_rt(rt);
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001371 } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 rt->rt6i_node->fn_sernum = -1;
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02001373 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 }
1375}
1376
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001377static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
1378{
1379 struct net *net = dev_net(rt->dst.dev);
1380
1381 rt->rt6i_flags |= RTF_MODIFIED;
1382 rt->rt6i_pmtu = mtu;
1383 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
1384}
1385
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08001386static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
1387{
1388 return !(rt->rt6i_flags & RTF_CACHE) &&
1389 (rt->rt6i_flags & RTF_PCPU || rt->rt6i_node);
1390}
1391
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001392static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
1393 const struct ipv6hdr *iph, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394{
Julian Anastasov0dec8792017-02-06 23:14:16 +02001395 const struct in6_addr *daddr, *saddr;
Ian Morris67ba4152014-08-24 21:53:10 +01001396 struct rt6_info *rt6 = (struct rt6_info *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001398 if (rt6->rt6i_flags & RTF_LOCAL)
1399 return;
1400
Xin Long19bda362016-10-28 18:18:01 +08001401 if (dst_metric_locked(dst, RTAX_MTU))
1402 return;
1403
Julian Anastasov0dec8792017-02-06 23:14:16 +02001404 if (iph) {
1405 daddr = &iph->daddr;
1406 saddr = &iph->saddr;
1407 } else if (sk) {
1408 daddr = &sk->sk_v6_daddr;
1409 saddr = &inet6_sk(sk)->saddr;
1410 } else {
1411 daddr = NULL;
1412 saddr = NULL;
1413 }
1414 dst_confirm_neigh(dst, daddr);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001415 mtu = max_t(u32, mtu, IPV6_MIN_MTU);
1416 if (mtu >= dst_mtu(dst))
1417 return;
David S. Miller81aded22012-06-15 14:54:11 -07001418
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08001419 if (!rt6_cache_allowed_for_pmtu(rt6)) {
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001420 rt6_do_update_pmtu(rt6, mtu);
Julian Anastasov0dec8792017-02-06 23:14:16 +02001421 } else if (daddr) {
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001422 struct rt6_info *nrt6;
Hagen Paul Pfeifer9d289712015-01-15 22:34:25 +01001423
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001424 nrt6 = ip6_rt_cache_alloc(rt6, daddr, saddr);
1425 if (nrt6) {
1426 rt6_do_update_pmtu(nrt6, mtu);
1427
1428 /* ip6_ins_rt(nrt6) will bump the
1429 * rt6->rt6i_node->fn_sernum
1430 * which will fail the next rt6_check() and
1431 * invalidate the sk->sk_dst_cache.
1432 */
1433 ip6_ins_rt(nrt6);
Wei Wang1cfb71e2017-06-17 10:42:33 -07001434 /* Release the reference taken in
1435 * ip6_rt_cache_alloc()
1436 */
1437 dst_release(&nrt6->dst);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001438 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 }
1440}
1441
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001442static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
1443 struct sk_buff *skb, u32 mtu)
1444{
1445 __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu);
1446}
1447
David S. Miller42ae66c2012-06-15 20:01:57 -07001448void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001449 int oif, u32 mark, kuid_t uid)
David S. Miller81aded22012-06-15 14:54:11 -07001450{
1451 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1452 struct dst_entry *dst;
1453 struct flowi6 fl6;
1454
1455 memset(&fl6, 0, sizeof(fl6));
1456 fl6.flowi6_oif = oif;
Lorenzo Colitti1b3c61d2014-05-13 10:17:34 -07001457 fl6.flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark);
David S. Miller81aded22012-06-15 14:54:11 -07001458 fl6.daddr = iph->daddr;
1459 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001460 fl6.flowlabel = ip6_flowinfo(iph);
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001461 fl6.flowi6_uid = uid;
David S. Miller81aded22012-06-15 14:54:11 -07001462
1463 dst = ip6_route_output(net, NULL, &fl6);
1464 if (!dst->error)
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07001465 __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07001466 dst_release(dst);
1467}
1468EXPORT_SYMBOL_GPL(ip6_update_pmtu);
1469
1470void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
1471{
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07001472 struct dst_entry *dst;
1473
David S. Miller81aded22012-06-15 14:54:11 -07001474 ip6_update_pmtu(skb, sock_net(sk), mtu,
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001475 sk->sk_bound_dev_if, sk->sk_mark, sk->sk_uid);
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07001476
1477 dst = __sk_dst_get(sk);
1478 if (!dst || !dst->obsolete ||
1479 dst->ops->check(dst, inet6_sk(sk)->dst_cookie))
1480 return;
1481
1482 bh_lock_sock(sk);
1483 if (!sock_owned_by_user(sk) && !ipv6_addr_v4mapped(&sk->sk_v6_daddr))
1484 ip6_datagram_dst_update(sk, false);
1485 bh_unlock_sock(sk);
David S. Miller81aded22012-06-15 14:54:11 -07001486}
1487EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
1488
Duan Jiongb55b76b2013-09-04 19:44:21 +08001489/* Handle redirects */
1490struct ip6rd_flowi {
1491 struct flowi6 fl6;
1492 struct in6_addr gateway;
1493};
1494
1495static struct rt6_info *__ip6_route_redirect(struct net *net,
1496 struct fib6_table *table,
1497 struct flowi6 *fl6,
1498 int flags)
1499{
1500 struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
1501 struct rt6_info *rt;
1502 struct fib6_node *fn;
1503
1504 /* Get the "current" route for this destination and
Alexander Alemayhu67c408c2017-01-07 23:53:00 +01001505 * check if the redirect has come from appropriate router.
Duan Jiongb55b76b2013-09-04 19:44:21 +08001506 *
1507 * RFC 4861 specifies that redirects should only be
1508 * accepted if they come from the nexthop to the target.
1509 * Due to the way the routes are chosen, this notion
1510 * is a bit fuzzy and one might need to check all possible
1511 * routes.
1512 */
1513
1514 read_lock_bh(&table->tb6_lock);
1515 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
1516restart:
1517 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
1518 if (rt6_check_expired(rt))
1519 continue;
1520 if (rt->dst.error)
1521 break;
1522 if (!(rt->rt6i_flags & RTF_GATEWAY))
1523 continue;
1524 if (fl6->flowi6_oif != rt->dst.dev->ifindex)
1525 continue;
1526 if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway))
1527 continue;
1528 break;
1529 }
1530
1531 if (!rt)
1532 rt = net->ipv6.ip6_null_entry;
1533 else if (rt->dst.error) {
1534 rt = net->ipv6.ip6_null_entry;
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001535 goto out;
1536 }
1537
1538 if (rt == net->ipv6.ip6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001539 fn = fib6_backtrack(fn, &fl6->saddr);
1540 if (fn)
1541 goto restart;
Duan Jiongb55b76b2013-09-04 19:44:21 +08001542 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001543
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08001544out:
Duan Jiongb55b76b2013-09-04 19:44:21 +08001545 dst_hold(&rt->dst);
1546
1547 read_unlock_bh(&table->tb6_lock);
1548
David Ahernb8115802015-11-19 12:24:22 -08001549 trace_fib6_table_lookup(net, rt, table->tb6_id, fl6);
Duan Jiongb55b76b2013-09-04 19:44:21 +08001550 return rt;
1551};
1552
1553static struct dst_entry *ip6_route_redirect(struct net *net,
1554 const struct flowi6 *fl6,
1555 const struct in6_addr *gateway)
1556{
1557 int flags = RT6_LOOKUP_F_HAS_SADDR;
1558 struct ip6rd_flowi rdfl;
1559
1560 rdfl.fl6 = *fl6;
1561 rdfl.gateway = *gateway;
1562
1563 return fib6_rule_lookup(net, &rdfl.fl6,
1564 flags, __ip6_route_redirect);
1565}
1566
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001567void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark,
1568 kuid_t uid)
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001569{
1570 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
1571 struct dst_entry *dst;
1572 struct flowi6 fl6;
1573
1574 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001575 fl6.flowi6_iif = LOOPBACK_IFINDEX;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001576 fl6.flowi6_oif = oif;
1577 fl6.flowi6_mark = mark;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001578 fl6.daddr = iph->daddr;
1579 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00001580 fl6.flowlabel = ip6_flowinfo(iph);
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001581 fl6.flowi6_uid = uid;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001582
Duan Jiongb55b76b2013-09-04 19:44:21 +08001583 dst = ip6_route_redirect(net, &fl6, &ipv6_hdr(skb)->saddr);
1584 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001585 dst_release(dst);
1586}
1587EXPORT_SYMBOL_GPL(ip6_redirect);
1588
Duan Jiongc92a59e2013-08-22 12:07:35 +08001589void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
1590 u32 mark)
1591{
1592 const struct ipv6hdr *iph = ipv6_hdr(skb);
1593 const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
1594 struct dst_entry *dst;
1595 struct flowi6 fl6;
1596
1597 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03001598 fl6.flowi6_iif = LOOPBACK_IFINDEX;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001599 fl6.flowi6_oif = oif;
1600 fl6.flowi6_mark = mark;
Duan Jiongc92a59e2013-08-22 12:07:35 +08001601 fl6.daddr = msg->dest;
1602 fl6.saddr = iph->daddr;
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001603 fl6.flowi6_uid = sock_net_uid(net, NULL);
Duan Jiongc92a59e2013-08-22 12:07:35 +08001604
Duan Jiongb55b76b2013-09-04 19:44:21 +08001605 dst = ip6_route_redirect(net, &fl6, &iph->saddr);
1606 rt6_do_redirect(dst, NULL, skb);
Duan Jiongc92a59e2013-08-22 12:07:35 +08001607 dst_release(dst);
1608}
1609
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001610void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
1611{
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09001612 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark,
1613 sk->sk_uid);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07001614}
1615EXPORT_SYMBOL_GPL(ip6_sk_redirect);
1616
David S. Miller0dbaee32010-12-13 12:52:14 -08001617static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618{
David S. Miller0dbaee32010-12-13 12:52:14 -08001619 struct net_device *dev = dst->dev;
1620 unsigned int mtu = dst_mtu(dst);
1621 struct net *net = dev_net(dev);
1622
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
1624
Daniel Lezcano55786892008-03-04 13:47:47 -08001625 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
1626 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627
1628 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001629 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
1630 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
1631 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 * rely only on pmtu discovery"
1633 */
1634 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
1635 mtu = IPV6_MAXPLEN;
1636 return mtu;
1637}
1638
Steffen Klassertebb762f2011-11-23 02:12:51 +00001639static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08001640{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001641 const struct rt6_info *rt = (const struct rt6_info *)dst;
1642 unsigned int mtu = rt->rt6i_pmtu;
David S. Millerd33e4552010-12-14 13:01:14 -08001643 struct inet6_dev *idev;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001644
1645 if (mtu)
Eric Dumazet30f78d82014-04-10 21:23:36 -07001646 goto out;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001647
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07001648 mtu = dst_metric_raw(dst, RTAX_MTU);
1649 if (mtu)
1650 goto out;
1651
Steffen Klassert618f9bc2011-11-23 02:13:31 +00001652 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08001653
1654 rcu_read_lock();
1655 idev = __in6_dev_get(dst->dev);
1656 if (idev)
1657 mtu = idev->cnf.mtu6;
1658 rcu_read_unlock();
1659
Eric Dumazet30f78d82014-04-10 21:23:36 -07001660out:
Roopa Prabhu14972cb2016-08-24 20:10:43 -07001661 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
1662
1663 return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
David S. Millerd33e4552010-12-14 13:01:14 -08001664}
1665
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001666static struct dst_entry *icmp6_dst_gc_list;
1667static DEFINE_SPINLOCK(icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001668
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001669struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05001670 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671{
David S. Miller87a11572011-12-06 17:04:13 -05001672 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 struct rt6_info *rt;
1674 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001675 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676
David S. Miller38308472011-12-03 18:02:47 -05001677 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00001678 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679
Martin KaFai Lauad706862015-08-14 11:05:52 -07001680 rt = ip6_dst_alloc(net, dev, 0);
David S. Miller38308472011-12-03 18:02:47 -05001681 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05001683 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 goto out;
1685 }
1686
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001687 rt->dst.flags |= DST_HOST;
1688 rt->dst.output = ip6_output;
Julian Anastasov550bab42013-10-20 15:43:04 +03001689 rt->rt6i_gateway = fl6->daddr;
David S. Miller87a11572011-12-06 17:04:13 -05001690 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00001691 rt->rt6i_dst.plen = 128;
1692 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08001693 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001695 spin_lock_bh(&icmp6_dst_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07001696 rt->dst.next = icmp6_dst_gc_list;
1697 icmp6_dst_gc_list = &rt->dst;
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001698 spin_unlock_bh(&icmp6_dst_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699
Daniel Lezcano55786892008-03-04 13:47:47 -08001700 fib6_force_start_gc(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701
David S. Miller87a11572011-12-06 17:04:13 -05001702 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
1703
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704out:
David S. Miller87a11572011-12-06 17:04:13 -05001705 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706}
1707
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001708int icmp6_dst_gc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709{
Hagen Paul Pfeifere9476e952011-02-25 05:45:19 +00001710 struct dst_entry *dst, **pprev;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001711 int more = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001713 spin_lock_bh(&icmp6_dst_lock);
1714 pprev = &icmp6_dst_gc_list;
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001715
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 while ((dst = *pprev) != NULL) {
1717 if (!atomic_read(&dst->__refcnt)) {
1718 *pprev = dst->next;
1719 dst_free(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 } else {
1721 pprev = &dst->next;
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001722 ++more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 }
1724 }
1725
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08001726 spin_unlock_bh(&icmp6_dst_lock);
Thomas Graf5d0bbee2006-08-04 03:37:36 -07001727
Stephen Hemminger3d0f24a2008-07-22 14:35:50 -07001728 return more;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729}
1730
David S. Miller1e493d12008-09-10 17:27:15 -07001731static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg),
1732 void *arg)
1733{
1734 struct dst_entry *dst, **pprev;
1735
1736 spin_lock_bh(&icmp6_dst_lock);
1737 pprev = &icmp6_dst_gc_list;
1738 while ((dst = *pprev) != NULL) {
1739 struct rt6_info *rt = (struct rt6_info *) dst;
1740 if (func(rt, arg)) {
1741 *pprev = dst->next;
1742 dst_free(dst);
1743 } else {
1744 pprev = &dst->next;
1745 }
1746 }
1747 spin_unlock_bh(&icmp6_dst_lock);
1748}
1749
Daniel Lezcano569d3642008-01-18 03:56:57 -08001750static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751{
Alexey Dobriyan86393e52009-08-29 01:34:49 +00001752 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08001753 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
1754 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
1755 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
1756 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
1757 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001758 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759
Eric Dumazetfc66f952010-10-08 06:37:34 +00001760 entries = dst_entries_get_fast(ops);
Michal Kubeček49a18d82013-08-01 10:04:24 +02001761 if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00001762 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 goto out;
1764
Benjamin Thery6891a342008-03-04 13:49:47 -08001765 net->ipv6.ip6_rt_gc_expire++;
Li RongQing14956642014-05-19 17:30:28 +08001766 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
Eric Dumazetfc66f952010-10-08 06:37:34 +00001767 entries = dst_entries_get_slow(ops);
1768 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08001769 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08001771 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00001772 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773}
1774
Florian Westphale715b6d2015-01-05 23:57:44 +01001775static int ip6_convert_metrics(struct mx6_config *mxc,
1776 const struct fib6_config *cfg)
1777{
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001778 bool ecn_ca = false;
Florian Westphale715b6d2015-01-05 23:57:44 +01001779 struct nlattr *nla;
1780 int remaining;
1781 u32 *mp;
1782
Ian Morris63159f22015-03-29 14:00:04 +01001783 if (!cfg->fc_mx)
Florian Westphale715b6d2015-01-05 23:57:44 +01001784 return 0;
1785
1786 mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
1787 if (unlikely(!mp))
1788 return -ENOMEM;
1789
1790 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
1791 int type = nla_type(nla);
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001792 u32 val;
Florian Westphale715b6d2015-01-05 23:57:44 +01001793
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001794 if (!type)
1795 continue;
1796 if (unlikely(type > RTAX_MAX))
1797 goto err;
Daniel Borkmannea697632015-01-05 23:57:47 +01001798
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001799 if (type == RTAX_CC_ALGO) {
1800 char tmp[TCP_CA_NAME_MAX];
1801
1802 nla_strlcpy(tmp, nla, sizeof(tmp));
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001803 val = tcp_ca_get_key_by_name(tmp, &ecn_ca);
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001804 if (val == TCP_CA_UNSPEC)
Florian Westphale715b6d2015-01-05 23:57:44 +01001805 goto err;
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001806 } else {
1807 val = nla_get_u32(nla);
Florian Westphale715b6d2015-01-05 23:57:44 +01001808 }
Paolo Abeni626abd52016-05-13 18:33:41 +02001809 if (type == RTAX_HOPLIMIT && val > 255)
1810 val = 255;
Daniel Borkmannb8d3e412015-08-31 15:58:46 +02001811 if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK))
1812 goto err;
Daniel Borkmann1bb14802015-08-31 15:58:45 +02001813
1814 mp[type - 1] = val;
1815 __set_bit(type - 1, mxc->mx_valid);
Florian Westphale715b6d2015-01-05 23:57:44 +01001816 }
1817
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001818 if (ecn_ca) {
1819 __set_bit(RTAX_FEATURES - 1, mxc->mx_valid);
1820 mp[RTAX_FEATURES - 1] |= DST_FEATURE_ECN_CA;
1821 }
Florian Westphale715b6d2015-01-05 23:57:44 +01001822
Daniel Borkmannc3a8d942015-08-31 15:58:47 +02001823 mxc->mx = mp;
Florian Westphale715b6d2015-01-05 23:57:44 +01001824 return 0;
1825 err:
1826 kfree(mp);
1827 return -EINVAL;
1828}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829
David Ahern8c145862016-04-24 21:26:04 -07001830static struct rt6_info *ip6_nh_lookup_table(struct net *net,
1831 struct fib6_config *cfg,
1832 const struct in6_addr *gw_addr)
1833{
1834 struct flowi6 fl6 = {
1835 .flowi6_oif = cfg->fc_ifindex,
1836 .daddr = *gw_addr,
1837 .saddr = cfg->fc_prefsrc,
1838 };
1839 struct fib6_table *table;
1840 struct rt6_info *rt;
David Ahernd5d32e42016-10-24 12:27:23 -07001841 int flags = RT6_LOOKUP_F_IFACE | RT6_LOOKUP_F_IGNORE_LINKSTATE;
David Ahern8c145862016-04-24 21:26:04 -07001842
1843 table = fib6_get_table(net, cfg->fc_table);
1844 if (!table)
1845 return NULL;
1846
1847 if (!ipv6_addr_any(&cfg->fc_prefsrc))
1848 flags |= RT6_LOOKUP_F_HAS_SADDR;
1849
1850 rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, flags);
1851
1852 /* if table lookup failed, fall back to full lookup */
1853 if (rt == net->ipv6.ip6_null_entry) {
1854 ip6_rt_put(rt);
1855 rt = NULL;
1856 }
1857
1858 return rt;
1859}
1860
David Ahern333c4302017-05-21 10:12:04 -06001861static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
1862 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863{
Daniel Lezcano55786892008-03-04 13:47:47 -08001864 struct net *net = cfg->fc_nlinfo.nl_net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 struct rt6_info *rt = NULL;
1866 struct net_device *dev = NULL;
1867 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07001868 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 int addr_type;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07001870 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871
David Ahern557c44b2017-04-19 14:19:43 -07001872 /* RTF_PCPU is an internal flag; can not be set by userspace */
David Ahernd5d531c2017-05-21 10:12:05 -06001873 if (cfg->fc_flags & RTF_PCPU) {
1874 NL_SET_ERR_MSG(extack, "Userspace can not set RTF_PCPU");
David Ahern557c44b2017-04-19 14:19:43 -07001875 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06001876 }
David Ahern557c44b2017-04-19 14:19:43 -07001877
David Ahernd5d531c2017-05-21 10:12:05 -06001878 if (cfg->fc_dst_len > 128) {
1879 NL_SET_ERR_MSG(extack, "Invalid prefix length");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07001880 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06001881 }
1882 if (cfg->fc_src_len > 128) {
1883 NL_SET_ERR_MSG(extack, "Invalid source address length");
1884 goto out;
1885 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886#ifndef CONFIG_IPV6_SUBTREES
David Ahernd5d531c2017-05-21 10:12:05 -06001887 if (cfg->fc_src_len) {
1888 NL_SET_ERR_MSG(extack,
1889 "Specifying source address requires IPV6_SUBTREES to be enabled");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07001890 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06001891 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07001893 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08001895 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 if (!dev)
1897 goto out;
1898 idev = in6_dev_get(dev);
1899 if (!idev)
1900 goto out;
1901 }
1902
Thomas Graf86872cb2006-08-22 00:01:08 -07001903 if (cfg->fc_metric == 0)
1904 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905
Matti Vaittinend71314b2011-11-14 00:14:49 +00001906 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05001907 if (cfg->fc_nlinfo.nlh &&
1908 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00001909 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05001910 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00001911 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00001912 table = fib6_new_table(net, cfg->fc_table);
1913 }
1914 } else {
1915 table = fib6_new_table(net, cfg->fc_table);
1916 }
David S. Miller38308472011-12-03 18:02:47 -05001917
1918 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07001919 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07001920
Martin KaFai Lauad706862015-08-14 11:05:52 -07001921 rt = ip6_dst_alloc(net, NULL,
1922 (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923
David S. Miller38308472011-12-03 18:02:47 -05001924 if (!rt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 err = -ENOMEM;
1926 goto out;
1927 }
1928
Gao feng1716a962012-04-06 00:13:10 +00001929 if (cfg->fc_flags & RTF_EXPIRES)
1930 rt6_set_expires(rt, jiffies +
1931 clock_t_to_jiffies(cfg->fc_expires));
1932 else
1933 rt6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934
Thomas Graf86872cb2006-08-22 00:01:08 -07001935 if (cfg->fc_protocol == RTPROT_UNSPEC)
1936 cfg->fc_protocol = RTPROT_BOOT;
1937 rt->rt6i_protocol = cfg->fc_protocol;
1938
1939 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940
1941 if (addr_type & IPV6_ADDR_MULTICAST)
Changli Gaod8d1f302010-06-10 23:31:35 -07001942 rt->dst.input = ip6_mc_input;
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00001943 else if (cfg->fc_flags & RTF_LOCAL)
1944 rt->dst.input = ip6_input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 else
Changli Gaod8d1f302010-06-10 23:31:35 -07001946 rt->dst.input = ip6_forward;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947
Changli Gaod8d1f302010-06-10 23:31:35 -07001948 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949
Roopa Prabhu19e42e42015-07-21 10:43:48 +02001950 if (cfg->fc_encap) {
1951 struct lwtunnel_state *lwtstate;
1952
David Ahern30357d72017-01-30 12:07:37 -08001953 err = lwtunnel_build_state(cfg->fc_encap_type,
Tom Herbert127eb7c2015-08-24 09:45:41 -07001954 cfg->fc_encap, AF_INET6, cfg,
David Ahern9ae28722017-05-27 16:19:28 -06001955 &lwtstate, extack);
Roopa Prabhu19e42e42015-07-21 10:43:48 +02001956 if (err)
1957 goto out;
Jiri Benc61adedf2015-08-20 13:56:25 +02001958 rt->dst.lwtstate = lwtstate_get(lwtstate);
1959 if (lwtunnel_output_redirect(rt->dst.lwtstate)) {
1960 rt->dst.lwtstate->orig_output = rt->dst.output;
1961 rt->dst.output = lwtunnel_output;
Tom Herbert25368622015-08-17 13:42:24 -07001962 }
Jiri Benc61adedf2015-08-20 13:56:25 +02001963 if (lwtunnel_input_redirect(rt->dst.lwtstate)) {
1964 rt->dst.lwtstate->orig_input = rt->dst.input;
1965 rt->dst.input = lwtunnel_input;
Tom Herbert25368622015-08-17 13:42:24 -07001966 }
Roopa Prabhu19e42e42015-07-21 10:43:48 +02001967 }
1968
Thomas Graf86872cb2006-08-22 00:01:08 -07001969 ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
1970 rt->rt6i_dst.plen = cfg->fc_dst_len;
Martin KaFai Lauafc4eef2015-04-28 13:03:07 -07001971 if (rt->rt6i_dst.plen == 128)
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001972 rt->dst.flags |= DST_HOST;
Michal Kubečeke5fd3872014-03-27 13:04:08 +01001973
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974#ifdef CONFIG_IPV6_SUBTREES
Thomas Graf86872cb2006-08-22 00:01:08 -07001975 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
1976 rt->rt6i_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977#endif
1978
Thomas Graf86872cb2006-08-22 00:01:08 -07001979 rt->rt6i_metric = cfg->fc_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980
1981 /* We cannot add true routes via loopback here,
1982 they would result in kernel looping; promote them to reject routes
1983 */
Thomas Graf86872cb2006-08-22 00:01:08 -07001984 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05001985 (dev && (dev->flags & IFF_LOOPBACK) &&
1986 !(addr_type & IPV6_ADDR_LOOPBACK) &&
1987 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08001989 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 if (dev) {
1991 dev_put(dev);
1992 in6_dev_put(idev);
1993 }
Daniel Lezcano55786892008-03-04 13:47:47 -08001994 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 dev_hold(dev);
1996 idev = in6_dev_get(dev);
1997 if (!idev) {
1998 err = -ENODEV;
1999 goto out;
2000 }
2001 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002003 switch (cfg->fc_type) {
2004 case RTN_BLACKHOLE:
2005 rt->dst.error = -EINVAL;
Eric W. Biedermanede20592015-10-07 16:48:47 -05002006 rt->dst.output = dst_discard_out;
Kamala R7150aed2013-12-02 19:55:21 +05302007 rt->dst.input = dst_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002008 break;
2009 case RTN_PROHIBIT:
2010 rt->dst.error = -EACCES;
Kamala R7150aed2013-12-02 19:55:21 +05302011 rt->dst.output = ip6_pkt_prohibit_out;
2012 rt->dst.input = ip6_pkt_prohibit;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002013 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002014 case RTN_THROW:
Nikola Forró0315e382015-09-17 16:01:32 +02002015 case RTN_UNREACHABLE:
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002016 default:
Kamala R7150aed2013-12-02 19:55:21 +05302017 rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN
Nikola Forró0315e382015-09-17 16:01:32 +02002018 : (cfg->fc_type == RTN_UNREACHABLE)
2019 ? -EHOSTUNREACH : -ENETUNREACH;
Kamala R7150aed2013-12-02 19:55:21 +05302020 rt->dst.output = ip6_pkt_discard_out;
2021 rt->dst.input = ip6_pkt_discard;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002022 break;
2023 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 goto install_route;
2025 }
2026
Thomas Graf86872cb2006-08-22 00:01:08 -07002027 if (cfg->fc_flags & RTF_GATEWAY) {
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002028 const struct in6_addr *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 int gwa_type;
2030
Thomas Graf86872cb2006-08-22 00:01:08 -07002031 gw_addr = &cfg->fc_gateway;
Florian Westphal330567b2015-08-07 10:54:28 +02002032 gwa_type = ipv6_addr_type(gw_addr);
Florian Westphal48ed7b22015-05-21 00:25:41 +02002033
2034 /* if gw_addr is local we will fail to detect this in case
2035 * address is still TENTATIVE (DAD in progress). rt6_lookup()
2036 * will return already-added prefix route via interface that
2037 * prefix route was assigned to, which might be non-loopback.
2038 */
2039 err = -EINVAL;
Florian Westphal330567b2015-08-07 10:54:28 +02002040 if (ipv6_chk_addr_and_flags(net, gw_addr,
2041 gwa_type & IPV6_ADDR_LINKLOCAL ?
David Ahernd5d531c2017-05-21 10:12:05 -06002042 dev : NULL, 0, 0)) {
2043 NL_SET_ERR_MSG(extack, "Invalid gateway address");
Florian Westphal48ed7b22015-05-21 00:25:41 +02002044 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002045 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002046 rt->rt6i_gateway = *gw_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047
2048 if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
David Ahern8c145862016-04-24 21:26:04 -07002049 struct rt6_info *grt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050
2051 /* IPv6 strictly inhibits using not link-local
2052 addresses as nexthop address.
2053 Otherwise, router will not able to send redirects.
2054 It is very good, but in some (rare!) circumstances
2055 (SIT, PtP, NBMA NOARP links) it is handy to allow
2056 some exceptions. --ANK
Erik Nordmark96d58222016-12-03 20:57:09 -08002057 We allow IPv4-mapped nexthops to support RFC4798-type
2058 addressing
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 */
Erik Nordmark96d58222016-12-03 20:57:09 -08002060 if (!(gwa_type & (IPV6_ADDR_UNICAST |
David Ahernd5d531c2017-05-21 10:12:05 -06002061 IPV6_ADDR_MAPPED))) {
2062 NL_SET_ERR_MSG(extack,
2063 "Invalid gateway address");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002065 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066
Vincent Bernata435a072016-09-18 17:46:07 +02002067 if (cfg->fc_table) {
David Ahern8c145862016-04-24 21:26:04 -07002068 grt = ip6_nh_lookup_table(net, cfg, gw_addr);
2069
Vincent Bernata435a072016-09-18 17:46:07 +02002070 if (grt) {
2071 if (grt->rt6i_flags & RTF_GATEWAY ||
2072 (dev && dev != grt->dst.dev)) {
2073 ip6_rt_put(grt);
2074 grt = NULL;
2075 }
2076 }
2077 }
2078
David Ahern8c145862016-04-24 21:26:04 -07002079 if (!grt)
2080 grt = rt6_lookup(net, gw_addr, NULL,
2081 cfg->fc_ifindex, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082
2083 err = -EHOSTUNREACH;
David S. Miller38308472011-12-03 18:02:47 -05002084 if (!grt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 goto out;
2086 if (dev) {
David S. Millerd1918542011-12-28 20:19:20 -05002087 if (dev != grt->dst.dev) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00002088 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 goto out;
2090 }
2091 } else {
David S. Millerd1918542011-12-28 20:19:20 -05002092 dev = grt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 idev = grt->rt6i_idev;
2094 dev_hold(dev);
2095 in6_dev_hold(grt->rt6i_idev);
2096 }
David S. Miller38308472011-12-03 18:02:47 -05002097 if (!(grt->rt6i_flags & RTF_GATEWAY))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 err = 0;
Amerigo Wang94e187c2012-10-29 00:13:19 +00002099 ip6_rt_put(grt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100
2101 if (err)
2102 goto out;
2103 }
2104 err = -EINVAL;
David Ahernd5d531c2017-05-21 10:12:05 -06002105 if (!dev) {
2106 NL_SET_ERR_MSG(extack, "Egress device not specified");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002108 } else if (dev->flags & IFF_LOOPBACK) {
2109 NL_SET_ERR_MSG(extack,
2110 "Egress device can not be loopback device for this route");
2111 goto out;
2112 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 }
2114
2115 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05002116 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 goto out;
2118
Daniel Walterc3968a82011-04-13 21:10:57 +00002119 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
2120 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
David Ahernd5d531c2017-05-21 10:12:05 -06002121 NL_SET_ERR_MSG(extack, "Invalid source address");
Daniel Walterc3968a82011-04-13 21:10:57 +00002122 err = -EINVAL;
2123 goto out;
2124 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002125 rt->rt6i_prefsrc.addr = cfg->fc_prefsrc;
Daniel Walterc3968a82011-04-13 21:10:57 +00002126 rt->rt6i_prefsrc.plen = 128;
2127 } else
2128 rt->rt6i_prefsrc.plen = 0;
2129
Thomas Graf86872cb2006-08-22 00:01:08 -07002130 rt->rt6i_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131
2132install_route:
Changli Gaod8d1f302010-06-10 23:31:35 -07002133 rt->dst.dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 rt->rt6i_idev = idev;
Thomas Grafc71099a2006-08-04 23:20:06 -07002135 rt->rt6i_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08002136
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002137 cfg->fc_nlinfo.nl_net = dev_net(dev);
Daniel Lezcano63152fc2008-03-03 23:31:11 -08002138
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002139 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140out:
2141 if (dev)
2142 dev_put(dev);
2143 if (idev)
2144 in6_dev_put(idev);
Wei Wang1cfb71e2017-06-17 10:42:33 -07002145 if (rt) {
2146 dst_release(&rt->dst);
Changli Gaod8d1f302010-06-10 23:31:35 -07002147 dst_free(&rt->dst);
Wei Wang1cfb71e2017-06-17 10:42:33 -07002148 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002149
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002150 return ERR_PTR(err);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002151}
2152
David Ahern333c4302017-05-21 10:12:04 -06002153int ip6_route_add(struct fib6_config *cfg,
2154 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002155{
2156 struct mx6_config mxc = { .mx = NULL, };
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002157 struct rt6_info *rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002158 int err;
2159
David Ahern333c4302017-05-21 10:12:04 -06002160 rt = ip6_route_info_create(cfg, extack);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002161 if (IS_ERR(rt)) {
2162 err = PTR_ERR(rt);
2163 rt = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002164 goto out;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002165 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002166
2167 err = ip6_convert_metrics(&mxc, cfg);
2168 if (err)
2169 goto out;
2170
David Ahern333c4302017-05-21 10:12:04 -06002171 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, &mxc, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002172
2173 kfree(mxc.mx);
2174
2175 return err;
2176out:
Wei Wang1cfb71e2017-06-17 10:42:33 -07002177 if (rt) {
2178 dst_release(&rt->dst);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002179 dst_free(&rt->dst);
Wei Wang1cfb71e2017-06-17 10:42:33 -07002180 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07002181
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 return err;
2183}
2184
Thomas Graf86872cb2006-08-22 00:01:08 -07002185static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186{
2187 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07002188 struct fib6_table *table;
David S. Millerd1918542011-12-28 20:19:20 -05002189 struct net *net = dev_net(rt->dst.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190
Martin KaFai Lau8e3d5be2015-09-15 14:30:08 -07002191 if (rt == net->ipv6.ip6_null_entry ||
2192 rt->dst.flags & DST_NOCACHE) {
Gao feng6825a262012-09-19 19:25:34 +00002193 err = -ENOENT;
2194 goto out;
2195 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07002196
Thomas Grafc71099a2006-08-04 23:20:06 -07002197 table = rt->rt6i_table;
2198 write_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07002199 err = fib6_del(rt, info);
Thomas Grafc71099a2006-08-04 23:20:06 -07002200 write_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201
Gao feng6825a262012-09-19 19:25:34 +00002202out:
Amerigo Wang94e187c2012-10-29 00:13:19 +00002203 ip6_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 return err;
2205}
2206
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002207int ip6_del_rt(struct rt6_info *rt)
2208{
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08002209 struct nl_info info = {
David S. Millerd1918542011-12-28 20:19:20 -05002210 .nl_net = dev_net(rt->dst.dev),
Denis V. Lunev4d1169c2008-01-10 03:26:13 -08002211 };
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08002212 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002213}
2214
David Ahern0ae81332017-02-02 12:37:08 -08002215static int __ip6_del_rt_siblings(struct rt6_info *rt, struct fib6_config *cfg)
2216{
2217 struct nl_info *info = &cfg->fc_nlinfo;
WANG Conge3330032017-02-27 16:07:43 -08002218 struct net *net = info->nl_net;
David Ahern16a16cd2017-02-02 12:37:11 -08002219 struct sk_buff *skb = NULL;
David Ahern0ae81332017-02-02 12:37:08 -08002220 struct fib6_table *table;
WANG Conge3330032017-02-27 16:07:43 -08002221 int err = -ENOENT;
David Ahern0ae81332017-02-02 12:37:08 -08002222
WANG Conge3330032017-02-27 16:07:43 -08002223 if (rt == net->ipv6.ip6_null_entry)
2224 goto out_put;
David Ahern0ae81332017-02-02 12:37:08 -08002225 table = rt->rt6i_table;
2226 write_lock_bh(&table->tb6_lock);
2227
2228 if (rt->rt6i_nsiblings && cfg->fc_delete_all_nh) {
2229 struct rt6_info *sibling, *next_sibling;
2230
David Ahern16a16cd2017-02-02 12:37:11 -08002231 /* prefer to send a single notification with all hops */
2232 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
2233 if (skb) {
2234 u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
2235
WANG Conge3330032017-02-27 16:07:43 -08002236 if (rt6_fill_node(net, skb, rt,
David Ahern16a16cd2017-02-02 12:37:11 -08002237 NULL, NULL, 0, RTM_DELROUTE,
2238 info->portid, seq, 0) < 0) {
2239 kfree_skb(skb);
2240 skb = NULL;
2241 } else
2242 info->skip_notify = 1;
2243 }
2244
David Ahern0ae81332017-02-02 12:37:08 -08002245 list_for_each_entry_safe(sibling, next_sibling,
2246 &rt->rt6i_siblings,
2247 rt6i_siblings) {
2248 err = fib6_del(sibling, info);
2249 if (err)
WANG Conge3330032017-02-27 16:07:43 -08002250 goto out_unlock;
David Ahern0ae81332017-02-02 12:37:08 -08002251 }
2252 }
2253
2254 err = fib6_del(rt, info);
WANG Conge3330032017-02-27 16:07:43 -08002255out_unlock:
David Ahern0ae81332017-02-02 12:37:08 -08002256 write_unlock_bh(&table->tb6_lock);
WANG Conge3330032017-02-27 16:07:43 -08002257out_put:
David Ahern0ae81332017-02-02 12:37:08 -08002258 ip6_rt_put(rt);
David Ahern16a16cd2017-02-02 12:37:11 -08002259
2260 if (skb) {
WANG Conge3330032017-02-27 16:07:43 -08002261 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
David Ahern16a16cd2017-02-02 12:37:11 -08002262 info->nlh, gfp_any());
2263 }
David Ahern0ae81332017-02-02 12:37:08 -08002264 return err;
2265}
2266
David Ahern333c4302017-05-21 10:12:04 -06002267static int ip6_route_del(struct fib6_config *cfg,
2268 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269{
Thomas Grafc71099a2006-08-04 23:20:06 -07002270 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 struct fib6_node *fn;
2272 struct rt6_info *rt;
2273 int err = -ESRCH;
2274
Daniel Lezcano55786892008-03-04 13:47:47 -08002275 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David Ahernd5d531c2017-05-21 10:12:05 -06002276 if (!table) {
2277 NL_SET_ERR_MSG(extack, "FIB table does not exist");
Thomas Grafc71099a2006-08-04 23:20:06 -07002278 return err;
David Ahernd5d531c2017-05-21 10:12:05 -06002279 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280
Thomas Grafc71099a2006-08-04 23:20:06 -07002281 read_lock_bh(&table->tb6_lock);
2282
2283 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07002284 &cfg->fc_dst, cfg->fc_dst_len,
2285 &cfg->fc_src, cfg->fc_src_len);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002286
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 if (fn) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002288 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
Martin KaFai Lau1f56a01f2015-04-28 13:03:03 -07002289 if ((rt->rt6i_flags & RTF_CACHE) &&
2290 !(cfg->fc_flags & RTF_CACHE))
2291 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002292 if (cfg->fc_ifindex &&
David S. Millerd1918542011-12-28 20:19:20 -05002293 (!rt->dst.dev ||
2294 rt->dst.dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002296 if (cfg->fc_flags & RTF_GATEWAY &&
2297 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07002299 if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 continue;
Mantas Mc2ed1882016-12-16 10:30:59 +02002301 if (cfg->fc_protocol && cfg->fc_protocol != rt->rt6i_protocol)
2302 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07002303 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07002304 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305
David Ahern0ae81332017-02-02 12:37:08 -08002306 /* if gateway was specified only delete the one hop */
2307 if (cfg->fc_flags & RTF_GATEWAY)
2308 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
2309
2310 return __ip6_del_rt_siblings(rt, cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 }
2312 }
Thomas Grafc71099a2006-08-04 23:20:06 -07002313 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314
2315 return err;
2316}
2317
David S. Miller6700c272012-07-17 03:29:28 -07002318static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07002319{
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07002320 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07002321 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07002322 struct ndisc_options ndopts;
2323 struct inet6_dev *in6_dev;
2324 struct neighbour *neigh;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002325 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07002326 int optlen, on_link;
2327 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07002328
Simon Horman29a3cad2013-05-28 20:34:26 +00002329 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002330 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07002331
2332 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07002333 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002334 return;
2335 }
2336
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002337 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07002338
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002339 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07002340 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002341 return;
2342 }
2343
David S. Miller6e157b62012-07-12 00:05:02 -07002344 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002345 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07002346 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002347 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07002348 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07002349 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07002350 return;
2351 }
2352
2353 in6_dev = __in6_dev_get(skb->dev);
2354 if (!in6_dev)
2355 return;
2356 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
2357 return;
2358
2359 /* RFC2461 8.1:
2360 * The IP source address of the Redirect MUST be the same as the current
2361 * first-hop router for the specified ICMP Destination Address.
2362 */
2363
Alexander Aringf997c552016-06-15 21:20:23 +02002364 if (!ndisc_parse_options(skb->dev, msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07002365 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
2366 return;
2367 }
David S. Miller6e157b62012-07-12 00:05:02 -07002368
2369 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07002370 if (ndopts.nd_opts_tgt_lladdr) {
2371 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
2372 skb->dev);
2373 if (!lladdr) {
2374 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
2375 return;
2376 }
2377 }
2378
David S. Miller6e157b62012-07-12 00:05:02 -07002379 rt = (struct rt6_info *) dst;
Matthias Schifferec13ad12015-11-02 01:24:38 +01002380 if (rt->rt6i_flags & RTF_REJECT) {
David S. Miller6e157b62012-07-12 00:05:02 -07002381 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
2382 return;
2383 }
2384
2385 /* Redirect received -> path was valid.
2386 * Look, redirects are sent only in response to data packets,
2387 * so that this nexthop apparently is reachable. --ANK
2388 */
Julian Anastasov0dec8792017-02-06 23:14:16 +02002389 dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
David S. Miller6e157b62012-07-12 00:05:02 -07002390
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002391 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07002392 if (!neigh)
2393 return;
2394
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 /*
2396 * We have finally decided to accept it.
2397 */
2398
Alexander Aringf997c552016-06-15 21:20:23 +02002399 ndisc_update(skb->dev, neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 NEIGH_UPDATE_F_WEAK_OVERRIDE|
2401 NEIGH_UPDATE_F_OVERRIDE|
2402 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
Alexander Aringf997c552016-06-15 21:20:23 +02002403 NEIGH_UPDATE_F_ISROUTER)),
2404 NDISC_REDIRECT, &ndopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002406 nrt = ip6_rt_cache_alloc(rt, &msg->dest, NULL);
David S. Miller38308472011-12-03 18:02:47 -05002407 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 goto out;
2409
2410 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
2411 if (on_link)
2412 nrt->rt6i_flags &= ~RTF_GATEWAY;
2413
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002414 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415
Thomas Graf40e22e82006-08-22 00:00:45 -07002416 if (ip6_ins_rt(nrt))
Wei Wang1cfb71e2017-06-17 10:42:33 -07002417 goto out_release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418
Changli Gaod8d1f302010-06-10 23:31:35 -07002419 netevent.old = &rt->dst;
2420 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00002421 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00002422 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07002423 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
2424
David S. Miller38308472011-12-03 18:02:47 -05002425 if (rt->rt6i_flags & RTF_CACHE) {
David S. Miller6e157b62012-07-12 00:05:02 -07002426 rt = (struct rt6_info *) dst_clone(&rt->dst);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002427 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 }
2429
Wei Wang1cfb71e2017-06-17 10:42:33 -07002430out_release:
2431 /* Release the reference taken in
2432 * ip6_rt_cache_alloc()
2433 */
2434 dst_release(&nrt->dst);
2435
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436out:
David S. Millere8599ff2012-07-11 23:43:53 -07002437 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07002438}
2439
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 * Misc support functions
2442 */
2443
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002444static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from)
2445{
2446 BUG_ON(from->dst.from);
2447
2448 rt->rt6i_flags &= ~RTF_EXPIRES;
2449 dst_hold(&from->dst);
2450 rt->dst.from = &from->dst;
2451 dst_init_metrics(&rt->dst, dst_metrics_ptr(&from->dst), true);
2452}
2453
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002454static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455{
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002456 rt->dst.input = ort->dst.input;
2457 rt->dst.output = ort->dst.output;
2458 rt->rt6i_dst = ort->rt6i_dst;
2459 rt->dst.error = ort->dst.error;
2460 rt->rt6i_idev = ort->rt6i_idev;
2461 if (rt->rt6i_idev)
2462 in6_dev_hold(rt->rt6i_idev);
2463 rt->dst.lastuse = jiffies;
2464 rt->rt6i_gateway = ort->rt6i_gateway;
2465 rt->rt6i_flags = ort->rt6i_flags;
2466 rt6_set_from(rt, ort);
2467 rt->rt6i_metric = ort->rt6i_metric;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002469 rt->rt6i_src = ort->rt6i_src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470#endif
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07002471 rt->rt6i_prefsrc = ort->rt6i_prefsrc;
2472 rt->rt6i_table = ort->rt6i_table;
Jiri Benc61adedf2015-08-20 13:56:25 +02002473 rt->dst.lwtstate = lwtstate_get(ort->dst.lwtstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474}
2475
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002476#ifdef CONFIG_IPV6_ROUTE_INFO
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002477static struct rt6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002478 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07002479 const struct in6_addr *gwaddr,
2480 struct net_device *dev)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002481{
David Ahern830218c2016-10-24 10:52:35 -07002482 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO;
2483 int ifindex = dev->ifindex;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002484 struct fib6_node *fn;
2485 struct rt6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07002486 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002487
David Ahern830218c2016-10-24 10:52:35 -07002488 table = fib6_get_table(net, tb_id);
David S. Miller38308472011-12-03 18:02:47 -05002489 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002490 return NULL;
2491
Li RongQing5744dd92012-09-11 21:59:01 +00002492 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01002493 fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002494 if (!fn)
2495 goto out;
2496
Changli Gaod8d1f302010-06-10 23:31:35 -07002497 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05002498 if (rt->dst.dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002499 continue;
2500 if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
2501 continue;
2502 if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
2503 continue;
Changli Gaod8d1f302010-06-10 23:31:35 -07002504 dst_hold(&rt->dst);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002505 break;
2506 }
2507out:
Li RongQing5744dd92012-09-11 21:59:01 +00002508 read_unlock_bh(&table->tb6_lock);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002509 return rt;
2510}
2511
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002512static struct rt6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002513 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07002514 const struct in6_addr *gwaddr,
2515 struct net_device *dev,
Eric Dumazet95c96172012-04-15 05:58:06 +00002516 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002517{
Thomas Graf86872cb2006-08-22 00:01:08 -07002518 struct fib6_config cfg = {
Rami Rosen238fc7e2008-02-09 23:43:11 -08002519 .fc_metric = IP6_RT_PRIO_USER,
David Ahern830218c2016-10-24 10:52:35 -07002520 .fc_ifindex = dev->ifindex,
Thomas Graf86872cb2006-08-22 00:01:08 -07002521 .fc_dst_len = prefixlen,
2522 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
2523 RTF_UP | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00002524 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08002525 .fc_nlinfo.nlh = NULL,
2526 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07002527 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002528
David Ahern830218c2016-10-24 10:52:35 -07002529 cfg.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO,
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002530 cfg.fc_dst = *prefix;
2531 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07002532
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08002533 /* We should treat it as a default route if prefix length is 0. */
2534 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07002535 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002536
David Ahern333c4302017-05-21 10:12:04 -06002537 ip6_route_add(&cfg, NULL);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002538
David Ahern830218c2016-10-24 10:52:35 -07002539 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08002540}
2541#endif
2542
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002543struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002544{
David Ahern830218c2016-10-24 10:52:35 -07002545 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 struct rt6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07002547 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548
David Ahern830218c2016-10-24 10:52:35 -07002549 table = fib6_get_table(dev_net(dev), tb_id);
David S. Miller38308472011-12-03 18:02:47 -05002550 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07002551 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552
Li RongQing5744dd92012-09-11 21:59:01 +00002553 read_lock_bh(&table->tb6_lock);
Ian Morris67ba4152014-08-24 21:53:10 +01002554 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
David S. Millerd1918542011-12-28 20:19:20 -05002555 if (dev == rt->dst.dev &&
YOSHIFUJI Hideaki045927f2006-03-20 17:00:48 -08002556 ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 ipv6_addr_equal(&rt->rt6i_gateway, addr))
2558 break;
2559 }
2560 if (rt)
Changli Gaod8d1f302010-06-10 23:31:35 -07002561 dst_hold(&rt->dst);
Li RongQing5744dd92012-09-11 21:59:01 +00002562 read_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 return rt;
2564}
2565
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002566struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08002567 struct net_device *dev,
2568 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569{
Thomas Graf86872cb2006-08-22 00:01:08 -07002570 struct fib6_config cfg = {
David Ahernca254492015-10-12 11:47:10 -07002571 .fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08002572 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07002573 .fc_ifindex = dev->ifindex,
2574 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
2575 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Eric W. Biederman15e47302012-09-07 20:12:54 +00002576 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08002577 .fc_nlinfo.nlh = NULL,
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002578 .fc_nlinfo.nl_net = dev_net(dev),
Thomas Graf86872cb2006-08-22 00:01:08 -07002579 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002581 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582
David Ahern333c4302017-05-21 10:12:04 -06002583 if (!ip6_route_add(&cfg, NULL)) {
David Ahern830218c2016-10-24 10:52:35 -07002584 struct fib6_table *table;
2585
2586 table = fib6_get_table(dev_net(dev), cfg.fc_table);
2587 if (table)
2588 table->flags |= RT6_TABLE_HAS_DFLT_ROUTER;
2589 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 return rt6_get_dflt_router(gwaddr, dev);
2592}
2593
David Ahern830218c2016-10-24 10:52:35 -07002594static void __rt6_purge_dflt_routers(struct fib6_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595{
2596 struct rt6_info *rt;
2597
2598restart:
Thomas Grafc71099a2006-08-04 23:20:06 -07002599 read_lock_bh(&table->tb6_lock);
Changli Gaod8d1f302010-06-10 23:31:35 -07002600 for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
Lorenzo Colitti3e8b0ac2013-03-03 20:46:46 +00002601 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
2602 (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) {
Changli Gaod8d1f302010-06-10 23:31:35 -07002603 dst_hold(&rt->dst);
Thomas Grafc71099a2006-08-04 23:20:06 -07002604 read_unlock_bh(&table->tb6_lock);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07002605 ip6_del_rt(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 goto restart;
2607 }
2608 }
Thomas Grafc71099a2006-08-04 23:20:06 -07002609 read_unlock_bh(&table->tb6_lock);
David Ahern830218c2016-10-24 10:52:35 -07002610
2611 table->flags &= ~RT6_TABLE_HAS_DFLT_ROUTER;
2612}
2613
2614void rt6_purge_dflt_routers(struct net *net)
2615{
2616 struct fib6_table *table;
2617 struct hlist_head *head;
2618 unsigned int h;
2619
2620 rcu_read_lock();
2621
2622 for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
2623 head = &net->ipv6.fib_table_hash[h];
2624 hlist_for_each_entry_rcu(table, head, tb6_hlist) {
2625 if (table->flags & RT6_TABLE_HAS_DFLT_ROUTER)
2626 __rt6_purge_dflt_routers(table);
2627 }
2628 }
2629
2630 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631}
2632
Daniel Lezcano55786892008-03-04 13:47:47 -08002633static void rtmsg_to_fib6_config(struct net *net,
2634 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07002635 struct fib6_config *cfg)
2636{
2637 memset(cfg, 0, sizeof(*cfg));
2638
David Ahernca254492015-10-12 11:47:10 -07002639 cfg->fc_table = l3mdev_fib_table_by_index(net, rtmsg->rtmsg_ifindex) ?
2640 : RT6_TABLE_MAIN;
Thomas Graf86872cb2006-08-22 00:01:08 -07002641 cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
2642 cfg->fc_metric = rtmsg->rtmsg_metric;
2643 cfg->fc_expires = rtmsg->rtmsg_info;
2644 cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
2645 cfg->fc_src_len = rtmsg->rtmsg_src_len;
2646 cfg->fc_flags = rtmsg->rtmsg_flags;
2647
Daniel Lezcano55786892008-03-04 13:47:47 -08002648 cfg->fc_nlinfo.nl_net = net;
Benjamin Theryf1243c22008-02-26 18:10:03 -08002649
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002650 cfg->fc_dst = rtmsg->rtmsg_dst;
2651 cfg->fc_src = rtmsg->rtmsg_src;
2652 cfg->fc_gateway = rtmsg->rtmsg_gateway;
Thomas Graf86872cb2006-08-22 00:01:08 -07002653}
2654
Daniel Lezcano55786892008-03-04 13:47:47 -08002655int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656{
Thomas Graf86872cb2006-08-22 00:01:08 -07002657 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 struct in6_rtmsg rtmsg;
2659 int err;
2660
Ian Morris67ba4152014-08-24 21:53:10 +01002661 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 case SIOCADDRT: /* Add a route */
2663 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00002664 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 return -EPERM;
2666 err = copy_from_user(&rtmsg, arg,
2667 sizeof(struct in6_rtmsg));
2668 if (err)
2669 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07002670
Daniel Lezcano55786892008-03-04 13:47:47 -08002671 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07002672
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 rtnl_lock();
2674 switch (cmd) {
2675 case SIOCADDRT:
David Ahern333c4302017-05-21 10:12:04 -06002676 err = ip6_route_add(&cfg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 break;
2678 case SIOCDELRT:
David Ahern333c4302017-05-21 10:12:04 -06002679 err = ip6_route_del(&cfg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 break;
2681 default:
2682 err = -EINVAL;
2683 }
2684 rtnl_unlock();
2685
2686 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07002687 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688
2689 return -EINVAL;
2690}
2691
2692/*
2693 * Drop the packet on the floor
2694 */
2695
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07002696static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002698 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00002699 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002700 switch (ipstats_mib_noroutes) {
2701 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07002702 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00002703 if (type == IPV6_ADDR_ANY) {
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002704 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2705 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002706 break;
2707 }
2708 /* FALLTHROUGH */
2709 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07002710 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
2711 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002712 break;
2713 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002714 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 kfree_skb(skb);
2716 return 0;
2717}
2718
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002719static int ip6_pkt_discard(struct sk_buff *skb)
2720{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002721 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002722}
2723
Eric W. Biedermanede20592015-10-07 16:48:47 -05002724static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725{
Eric Dumazetadf30902009-06-02 05:19:30 +00002726 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002727 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728}
2729
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002730static int ip6_pkt_prohibit(struct sk_buff *skb)
2731{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002732 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002733}
2734
Eric W. Biedermanede20592015-10-07 16:48:47 -05002735static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002736{
Eric Dumazetadf30902009-06-02 05:19:30 +00002737 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07002738 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07002739}
2740
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741/*
2742 * Allocate a dst for local (unicast / anycast) address.
2743 */
2744
2745struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
2746 const struct in6_addr *addr,
David S. Miller8f031512011-12-06 16:48:14 -05002747 bool anycast)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748{
David Ahernca254492015-10-12 11:47:10 -07002749 u32 tb_id;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002750 struct net *net = dev_net(idev->dev);
David Ahern5f02ce242016-09-10 12:09:54 -07002751 struct net_device *dev = net->loopback_dev;
2752 struct rt6_info *rt;
2753
2754 /* use L3 Master device as loopback for host routes if device
2755 * is enslaved and address is not link local or multicast
2756 */
2757 if (!rt6_need_strict(addr))
2758 dev = l3mdev_master_dev_rcu(idev->dev) ? : dev;
2759
2760 rt = ip6_dst_alloc(net, dev, DST_NOCOUNT);
Hannes Frederic Sowaa3300ef2013-12-07 03:33:45 +01002761 if (!rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 return ERR_PTR(-ENOMEM);
2763
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 in6_dev_hold(idev);
2765
David S. Miller11d53b42011-06-24 15:23:34 -07002766 rt->dst.flags |= DST_HOST;
Changli Gaod8d1f302010-06-10 23:31:35 -07002767 rt->dst.input = ip6_input;
2768 rt->dst.output = ip6_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 rt->rt6i_idev = idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770
David Ahern94b5e0f2017-02-02 08:52:21 -08002771 rt->rt6i_protocol = RTPROT_KERNEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
YOSHIFUJI Hideaki58c4fb82005-12-21 22:56:42 +09002773 if (anycast)
2774 rt->rt6i_flags |= RTF_ANYCAST;
2775 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 rt->rt6i_flags |= RTF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777
Julian Anastasov550bab42013-10-20 15:43:04 +03002778 rt->rt6i_gateway = *addr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002779 rt->rt6i_dst.addr = *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 rt->rt6i_dst.plen = 128;
David Ahernca254492015-10-12 11:47:10 -07002781 tb_id = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL;
2782 rt->rt6i_table = fib6_get_table(net, tb_id);
Martin KaFai Lau8e3d5be2015-09-15 14:30:08 -07002783 rt->dst.flags |= DST_NOCACHE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 return rt;
2786}
2787
Daniel Walterc3968a82011-04-13 21:10:57 +00002788/* remove deleted ip from prefsrc entries */
2789struct arg_dev_net_ip {
2790 struct net_device *dev;
2791 struct net *net;
2792 struct in6_addr *addr;
2793};
2794
2795static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
2796{
2797 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
2798 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
2799 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
2800
David S. Millerd1918542011-12-28 20:19:20 -05002801 if (((void *)rt->dst.dev == dev || !dev) &&
Daniel Walterc3968a82011-04-13 21:10:57 +00002802 rt != net->ipv6.ip6_null_entry &&
2803 ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
2804 /* remove prefsrc entry */
2805 rt->rt6i_prefsrc.plen = 0;
2806 }
2807 return 0;
2808}
2809
2810void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
2811{
2812 struct net *net = dev_net(ifp->idev->dev);
2813 struct arg_dev_net_ip adni = {
2814 .dev = ifp->idev->dev,
2815 .net = net,
2816 .addr = &ifp->addr,
2817 };
Li RongQing0c3584d2013-12-27 16:32:38 +08002818 fib6_clean_all(net, fib6_remove_prefsrc, &adni);
Daniel Walterc3968a82011-04-13 21:10:57 +00002819}
2820
Duan Jiongbe7a0102014-05-15 15:56:14 +08002821#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY)
2822#define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE)
2823
2824/* Remove routers and update dst entries when gateway turn into host. */
2825static int fib6_clean_tohost(struct rt6_info *rt, void *arg)
2826{
2827 struct in6_addr *gateway = (struct in6_addr *)arg;
2828
2829 if ((((rt->rt6i_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) ||
2830 ((rt->rt6i_flags & RTF_CACHE_GATEWAY) == RTF_CACHE_GATEWAY)) &&
2831 ipv6_addr_equal(gateway, &rt->rt6i_gateway)) {
2832 return -1;
2833 }
2834 return 0;
2835}
2836
2837void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
2838{
2839 fib6_clean_all(net, fib6_clean_tohost, gateway);
2840}
2841
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002842struct arg_dev_net {
2843 struct net_device *dev;
2844 struct net *net;
2845};
2846
David Aherna1a22c12017-01-18 07:40:36 -08002847/* called with write lock held for table with rt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848static int fib6_ifdown(struct rt6_info *rt, void *arg)
2849{
stephen hemmingerbc3ef662010-12-16 17:42:40 +00002850 const struct arg_dev_net *adn = arg;
2851 const struct net_device *dev = adn->dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002852
David S. Millerd1918542011-12-28 20:19:20 -05002853 if ((rt->dst.dev == dev || !dev) &&
David Aherna1a22c12017-01-18 07:40:36 -08002854 rt != adn->net->ipv6.ip6_null_entry &&
2855 (rt->rt6i_nsiblings == 0 ||
David Ahern8397ed32017-06-07 12:26:23 -06002856 (dev && netdev_unregistering(dev)) ||
David Aherna1a22c12017-01-18 07:40:36 -08002857 !rt->rt6i_idev->cnf.ignore_routes_with_linkdown))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 return -1;
David S. Millerc159d302011-12-26 15:24:36 -05002859
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 return 0;
2861}
2862
Daniel Lezcanof3db4852008-03-03 23:27:06 -08002863void rt6_ifdown(struct net *net, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08002865 struct arg_dev_net adn = {
2866 .dev = dev,
2867 .net = net,
2868 };
2869
Li RongQing0c3584d2013-12-27 16:32:38 +08002870 fib6_clean_all(net, fib6_ifdown, &adn);
David S. Miller1e493d12008-09-10 17:27:15 -07002871 icmp6_clean_all(fib6_ifdown, &adn);
Eric W. Biedermane332bc62015-10-12 11:02:08 -05002872 if (dev)
2873 rt6_uncached_list_flush_dev(net, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874}
2875
Eric Dumazet95c96172012-04-15 05:58:06 +00002876struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00002878 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879};
2880
2881static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
2882{
2883 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
2884 struct inet6_dev *idev;
2885
2886 /* In IPv6 pmtu discovery is not optional,
2887 so that RTAX_MTU lock cannot disable it.
2888 We still use this lock to block changes
2889 caused by addrconf/ndisc.
2890 */
2891
2892 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05002893 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 return 0;
2895
2896 /* For administrative MTU increase, there is no way to discover
2897 IPv6 PMTU increase, so PMTU increase should be updated here.
2898 Since RFC 1981 doesn't include administrative MTU increase
2899 update PMTU increase is a MUST. (i.e. jumbo frame)
2900 */
2901 /*
2902 If new MTU is less than route PMTU, this new MTU will be the
2903 lowest MTU in the path, update the route PMTU to reflect PMTU
2904 decreases; if new MTU is greater than route PMTU, and the
2905 old MTU is the lowest MTU in the path, update the route PMTU
2906 to reflect the increase. In this case if the other nodes' MTU
2907 also have the lowest MTU, TOO BIG MESSAGE will be lead to
Alexander Alemayhu67c408c2017-01-07 23:53:00 +01002908 PMTU discovery.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 */
David S. Millerd1918542011-12-28 20:19:20 -05002910 if (rt->dst.dev == arg->dev &&
Maciej Żenczykowskifb56be82016-11-04 14:51:54 -07002911 dst_metric_raw(&rt->dst, RTAX_MTU) &&
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002912 !dst_metric_locked(&rt->dst, RTAX_MTU)) {
2913 if (rt->rt6i_flags & RTF_CACHE) {
2914 /* For RTF_CACHE with rt6i_pmtu == 0
2915 * (i.e. a redirected route),
2916 * the metrics of its rt->dst.from has already
2917 * been updated.
2918 */
2919 if (rt->rt6i_pmtu && rt->rt6i_pmtu > arg->mtu)
2920 rt->rt6i_pmtu = arg->mtu;
2921 } else if (dst_mtu(&rt->dst) >= arg->mtu ||
2922 (dst_mtu(&rt->dst) < arg->mtu &&
2923 dst_mtu(&rt->dst) == idev->cnf.mtu6)) {
2924 dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu);
2925 }
Simon Arlott566cfd82007-07-26 00:09:55 -07002926 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 return 0;
2928}
2929
Eric Dumazet95c96172012-04-15 05:58:06 +00002930void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931{
Thomas Grafc71099a2006-08-04 23:20:06 -07002932 struct rt6_mtu_change_arg arg = {
2933 .dev = dev,
2934 .mtu = mtu,
2935 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936
Li RongQing0c3584d2013-12-27 16:32:38 +08002937 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938}
2939
Patrick McHardyef7c79e2007-06-05 12:38:30 -07002940static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07002941 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07002942 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07002943 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002944 [RTA_PRIORITY] = { .type = NLA_U32 },
2945 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00002946 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002947 [RTA_PREF] = { .type = NLA_U8 },
Roopa Prabhu19e42e42015-07-21 10:43:48 +02002948 [RTA_ENCAP_TYPE] = { .type = NLA_U16 },
2949 [RTA_ENCAP] = { .type = NLA_NESTED },
Xin Long32bc2012015-12-16 17:50:11 +08002950 [RTA_EXPIRES] = { .type = NLA_U32 },
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09002951 [RTA_UID] = { .type = NLA_U32 },
Liping Zhang3b45a412017-02-27 20:59:39 +08002952 [RTA_MARK] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07002953};
2954
2955static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
David Ahern333c4302017-05-21 10:12:04 -06002956 struct fib6_config *cfg,
2957 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958{
Thomas Graf86872cb2006-08-22 00:01:08 -07002959 struct rtmsg *rtm;
2960 struct nlattr *tb[RTA_MAX+1];
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01002961 unsigned int pref;
Thomas Graf86872cb2006-08-22 00:01:08 -07002962 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963
Johannes Bergfceb6432017-04-12 14:34:07 +02002964 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
2965 NULL);
Thomas Graf86872cb2006-08-22 00:01:08 -07002966 if (err < 0)
2967 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968
Thomas Graf86872cb2006-08-22 00:01:08 -07002969 err = -EINVAL;
2970 rtm = nlmsg_data(nlh);
2971 memset(cfg, 0, sizeof(*cfg));
2972
2973 cfg->fc_table = rtm->rtm_table;
2974 cfg->fc_dst_len = rtm->rtm_dst_len;
2975 cfg->fc_src_len = rtm->rtm_src_len;
2976 cfg->fc_flags = RTF_UP;
2977 cfg->fc_protocol = rtm->rtm_protocol;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002978 cfg->fc_type = rtm->rtm_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07002979
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00002980 if (rtm->rtm_type == RTN_UNREACHABLE ||
2981 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00002982 rtm->rtm_type == RTN_PROHIBIT ||
2983 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07002984 cfg->fc_flags |= RTF_REJECT;
2985
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00002986 if (rtm->rtm_type == RTN_LOCAL)
2987 cfg->fc_flags |= RTF_LOCAL;
2988
Martin KaFai Lau1f56a01f2015-04-28 13:03:03 -07002989 if (rtm->rtm_flags & RTM_F_CLONED)
2990 cfg->fc_flags |= RTF_CACHE;
2991
Eric W. Biederman15e47302012-09-07 20:12:54 +00002992 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
Thomas Graf86872cb2006-08-22 00:01:08 -07002993 cfg->fc_nlinfo.nlh = nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002994 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
Thomas Graf86872cb2006-08-22 00:01:08 -07002995
2996 if (tb[RTA_GATEWAY]) {
Jiri Benc67b61f62015-03-29 16:59:26 +02002997 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
Thomas Graf86872cb2006-08-22 00:01:08 -07002998 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 }
Thomas Graf86872cb2006-08-22 00:01:08 -07003000
3001 if (tb[RTA_DST]) {
3002 int plen = (rtm->rtm_dst_len + 7) >> 3;
3003
3004 if (nla_len(tb[RTA_DST]) < plen)
3005 goto errout;
3006
3007 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 }
Thomas Graf86872cb2006-08-22 00:01:08 -07003009
3010 if (tb[RTA_SRC]) {
3011 int plen = (rtm->rtm_src_len + 7) >> 3;
3012
3013 if (nla_len(tb[RTA_SRC]) < plen)
3014 goto errout;
3015
3016 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 }
Thomas Graf86872cb2006-08-22 00:01:08 -07003018
Daniel Walterc3968a82011-04-13 21:10:57 +00003019 if (tb[RTA_PREFSRC])
Jiri Benc67b61f62015-03-29 16:59:26 +02003020 cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]);
Daniel Walterc3968a82011-04-13 21:10:57 +00003021
Thomas Graf86872cb2006-08-22 00:01:08 -07003022 if (tb[RTA_OIF])
3023 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
3024
3025 if (tb[RTA_PRIORITY])
3026 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
3027
3028 if (tb[RTA_METRICS]) {
3029 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
3030 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 }
Thomas Graf86872cb2006-08-22 00:01:08 -07003032
3033 if (tb[RTA_TABLE])
3034 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
3035
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003036 if (tb[RTA_MULTIPATH]) {
3037 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
3038 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
David Ahern9ed59592017-01-17 14:57:36 -08003039
3040 err = lwtunnel_valid_encap_type_attr(cfg->fc_mp,
David Ahernc255bd62017-05-27 16:19:27 -06003041 cfg->fc_mp_len, extack);
David Ahern9ed59592017-01-17 14:57:36 -08003042 if (err < 0)
3043 goto errout;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003044 }
3045
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01003046 if (tb[RTA_PREF]) {
3047 pref = nla_get_u8(tb[RTA_PREF]);
3048 if (pref != ICMPV6_ROUTER_PREF_LOW &&
3049 pref != ICMPV6_ROUTER_PREF_HIGH)
3050 pref = ICMPV6_ROUTER_PREF_MEDIUM;
3051 cfg->fc_flags |= RTF_PREF(pref);
3052 }
3053
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003054 if (tb[RTA_ENCAP])
3055 cfg->fc_encap = tb[RTA_ENCAP];
3056
David Ahern9ed59592017-01-17 14:57:36 -08003057 if (tb[RTA_ENCAP_TYPE]) {
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003058 cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]);
3059
David Ahernc255bd62017-05-27 16:19:27 -06003060 err = lwtunnel_valid_encap_type(cfg->fc_encap_type, extack);
David Ahern9ed59592017-01-17 14:57:36 -08003061 if (err < 0)
3062 goto errout;
3063 }
3064
Xin Long32bc2012015-12-16 17:50:11 +08003065 if (tb[RTA_EXPIRES]) {
3066 unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ);
3067
3068 if (addrconf_finite_timeout(timeout)) {
3069 cfg->fc_expires = jiffies_to_clock_t(timeout * HZ);
3070 cfg->fc_flags |= RTF_EXPIRES;
3071 }
3072 }
3073
Thomas Graf86872cb2006-08-22 00:01:08 -07003074 err = 0;
3075errout:
3076 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077}
3078
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003079struct rt6_nh {
3080 struct rt6_info *rt6_info;
3081 struct fib6_config r_cfg;
3082 struct mx6_config mxc;
3083 struct list_head next;
3084};
3085
3086static void ip6_print_replace_route_err(struct list_head *rt6_nh_list)
3087{
3088 struct rt6_nh *nh;
3089
3090 list_for_each_entry(nh, rt6_nh_list, next) {
David Ahern7d4d5062017-02-02 12:37:12 -08003091 pr_warn("IPV6: multipath route replace failed (check consistency of installed routes): %pI6c nexthop %pI6c ifi %d\n",
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003092 &nh->r_cfg.fc_dst, &nh->r_cfg.fc_gateway,
3093 nh->r_cfg.fc_ifindex);
3094 }
3095}
3096
3097static int ip6_route_info_append(struct list_head *rt6_nh_list,
3098 struct rt6_info *rt, struct fib6_config *r_cfg)
3099{
3100 struct rt6_nh *nh;
3101 struct rt6_info *rtnh;
3102 int err = -EEXIST;
3103
3104 list_for_each_entry(nh, rt6_nh_list, next) {
3105 /* check if rt6_info already exists */
3106 rtnh = nh->rt6_info;
3107
3108 if (rtnh->dst.dev == rt->dst.dev &&
3109 rtnh->rt6i_idev == rt->rt6i_idev &&
3110 ipv6_addr_equal(&rtnh->rt6i_gateway,
3111 &rt->rt6i_gateway))
3112 return err;
3113 }
3114
3115 nh = kzalloc(sizeof(*nh), GFP_KERNEL);
3116 if (!nh)
3117 return -ENOMEM;
3118 nh->rt6_info = rt;
3119 err = ip6_convert_metrics(&nh->mxc, r_cfg);
3120 if (err) {
3121 kfree(nh);
3122 return err;
3123 }
3124 memcpy(&nh->r_cfg, r_cfg, sizeof(*r_cfg));
3125 list_add_tail(&nh->next, rt6_nh_list);
3126
3127 return 0;
3128}
3129
David Ahern3b1137f2017-02-02 12:37:10 -08003130static void ip6_route_mpath_notify(struct rt6_info *rt,
3131 struct rt6_info *rt_last,
3132 struct nl_info *info,
3133 __u16 nlflags)
3134{
3135 /* if this is an APPEND route, then rt points to the first route
3136 * inserted and rt_last points to last route inserted. Userspace
3137 * wants a consistent dump of the route which starts at the first
3138 * nexthop. Since sibling routes are always added at the end of
3139 * the list, find the first sibling of the last route appended
3140 */
3141 if ((nlflags & NLM_F_APPEND) && rt_last && rt_last->rt6i_nsiblings) {
3142 rt = list_first_entry(&rt_last->rt6i_siblings,
3143 struct rt6_info,
3144 rt6i_siblings);
3145 }
3146
3147 if (rt)
3148 inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
3149}
3150
David Ahern333c4302017-05-21 10:12:04 -06003151static int ip6_route_multipath_add(struct fib6_config *cfg,
3152 struct netlink_ext_ack *extack)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003153{
David Ahern3b1137f2017-02-02 12:37:10 -08003154 struct rt6_info *rt_notif = NULL, *rt_last = NULL;
3155 struct nl_info *info = &cfg->fc_nlinfo;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003156 struct fib6_config r_cfg;
3157 struct rtnexthop *rtnh;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003158 struct rt6_info *rt;
3159 struct rt6_nh *err_nh;
3160 struct rt6_nh *nh, *nh_safe;
David Ahern3b1137f2017-02-02 12:37:10 -08003161 __u16 nlflags;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003162 int remaining;
3163 int attrlen;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003164 int err = 1;
3165 int nhn = 0;
3166 int replace = (cfg->fc_nlinfo.nlh &&
3167 (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE));
3168 LIST_HEAD(rt6_nh_list);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003169
David Ahern3b1137f2017-02-02 12:37:10 -08003170 nlflags = replace ? NLM_F_REPLACE : NLM_F_CREATE;
3171 if (info->nlh && info->nlh->nlmsg_flags & NLM_F_APPEND)
3172 nlflags |= NLM_F_APPEND;
3173
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02003174 remaining = cfg->fc_mp_len;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003175 rtnh = (struct rtnexthop *)cfg->fc_mp;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003176
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003177 /* Parse a Multipath Entry and build a list (rt6_nh_list) of
3178 * rt6_info structs per nexthop
3179 */
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003180 while (rtnh_ok(rtnh, remaining)) {
3181 memcpy(&r_cfg, cfg, sizeof(*cfg));
3182 if (rtnh->rtnh_ifindex)
3183 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
3184
3185 attrlen = rtnh_attrlen(rtnh);
3186 if (attrlen > 0) {
3187 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
3188
3189 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
3190 if (nla) {
Jiri Benc67b61f62015-03-29 16:59:26 +02003191 r_cfg.fc_gateway = nla_get_in6_addr(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003192 r_cfg.fc_flags |= RTF_GATEWAY;
3193 }
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003194 r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
3195 nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
3196 if (nla)
3197 r_cfg.fc_encap_type = nla_get_u16(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003198 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003199
David Ahern333c4302017-05-21 10:12:04 -06003200 rt = ip6_route_info_create(&r_cfg, extack);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003201 if (IS_ERR(rt)) {
3202 err = PTR_ERR(rt);
3203 rt = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003204 goto cleanup;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003205 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003206
3207 err = ip6_route_info_append(&rt6_nh_list, rt, &r_cfg);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003208 if (err) {
Wei Wang1cfb71e2017-06-17 10:42:33 -07003209 dst_release(&rt->dst);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003210 dst_free(&rt->dst);
3211 goto cleanup;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003212 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003213
3214 rtnh = rtnh_next(rtnh, &remaining);
3215 }
3216
David Ahern3b1137f2017-02-02 12:37:10 -08003217 /* for add and replace send one notification with all nexthops.
3218 * Skip the notification in fib6_add_rt2node and send one with
3219 * the full route when done
3220 */
3221 info->skip_notify = 1;
3222
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003223 err_nh = NULL;
3224 list_for_each_entry(nh, &rt6_nh_list, next) {
David Ahern3b1137f2017-02-02 12:37:10 -08003225 rt_last = nh->rt6_info;
David Ahern333c4302017-05-21 10:12:04 -06003226 err = __ip6_ins_rt(nh->rt6_info, info, &nh->mxc, extack);
David Ahern3b1137f2017-02-02 12:37:10 -08003227 /* save reference to first route for notification */
3228 if (!rt_notif && !err)
3229 rt_notif = nh->rt6_info;
3230
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003231 /* nh->rt6_info is used or freed at this point, reset to NULL*/
3232 nh->rt6_info = NULL;
3233 if (err) {
3234 if (replace && nhn)
3235 ip6_print_replace_route_err(&rt6_nh_list);
3236 err_nh = nh;
3237 goto add_errout;
3238 }
3239
Nicolas Dichtel1a724182012-11-01 22:58:22 +00003240 /* Because each route is added like a single route we remove
Michal Kubeček27596472015-05-18 20:54:00 +02003241 * these flags after the first nexthop: if there is a collision,
3242 * we have already failed to add the first nexthop:
3243 * fib6_add_rt2node() has rejected it; when replacing, old
3244 * nexthops have been replaced by first new, the rest should
3245 * be added to it.
Nicolas Dichtel1a724182012-11-01 22:58:22 +00003246 */
Michal Kubeček27596472015-05-18 20:54:00 +02003247 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
3248 NLM_F_REPLACE);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003249 nhn++;
3250 }
3251
David Ahern3b1137f2017-02-02 12:37:10 -08003252 /* success ... tell user about new route */
3253 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003254 goto cleanup;
3255
3256add_errout:
David Ahern3b1137f2017-02-02 12:37:10 -08003257 /* send notification for routes that were added so that
3258 * the delete notifications sent by ip6_route_del are
3259 * coherent
3260 */
3261 if (rt_notif)
3262 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
3263
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003264 /* Delete routes that were already added */
3265 list_for_each_entry(nh, &rt6_nh_list, next) {
3266 if (err_nh == nh)
3267 break;
David Ahern333c4302017-05-21 10:12:04 -06003268 ip6_route_del(&nh->r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003269 }
3270
3271cleanup:
3272 list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) {
Wei Wang1cfb71e2017-06-17 10:42:33 -07003273 if (nh->rt6_info) {
3274 dst_release(&nh->rt6_info->dst);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003275 dst_free(&nh->rt6_info->dst);
Wei Wang1cfb71e2017-06-17 10:42:33 -07003276 }
Wu Fengguang52fe51f2015-09-10 06:57:12 +08003277 kfree(nh->mxc.mx);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003278 list_del(&nh->next);
3279 kfree(nh);
3280 }
3281
3282 return err;
3283}
3284
David Ahern333c4302017-05-21 10:12:04 -06003285static int ip6_route_multipath_del(struct fib6_config *cfg,
3286 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003287{
3288 struct fib6_config r_cfg;
3289 struct rtnexthop *rtnh;
3290 int remaining;
3291 int attrlen;
3292 int err = 1, last_err = 0;
3293
3294 remaining = cfg->fc_mp_len;
3295 rtnh = (struct rtnexthop *)cfg->fc_mp;
3296
3297 /* Parse a Multipath Entry */
3298 while (rtnh_ok(rtnh, remaining)) {
3299 memcpy(&r_cfg, cfg, sizeof(*cfg));
3300 if (rtnh->rtnh_ifindex)
3301 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
3302
3303 attrlen = rtnh_attrlen(rtnh);
3304 if (attrlen > 0) {
3305 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
3306
3307 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
3308 if (nla) {
3309 nla_memcpy(&r_cfg.fc_gateway, nla, 16);
3310 r_cfg.fc_flags |= RTF_GATEWAY;
3311 }
3312 }
David Ahern333c4302017-05-21 10:12:04 -06003313 err = ip6_route_del(&r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003314 if (err)
3315 last_err = err;
3316
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003317 rtnh = rtnh_next(rtnh, &remaining);
3318 }
3319
3320 return last_err;
3321}
3322
David Ahernc21ef3e2017-04-16 09:48:24 -07003323static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
3324 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325{
Thomas Graf86872cb2006-08-22 00:01:08 -07003326 struct fib6_config cfg;
3327 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328
David Ahern333c4302017-05-21 10:12:04 -06003329 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07003330 if (err < 0)
3331 return err;
3332
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003333 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06003334 return ip6_route_multipath_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08003335 else {
3336 cfg.fc_delete_all_nh = 1;
David Ahern333c4302017-05-21 10:12:04 -06003337 return ip6_route_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08003338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339}
3340
David Ahernc21ef3e2017-04-16 09:48:24 -07003341static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
3342 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343{
Thomas Graf86872cb2006-08-22 00:01:08 -07003344 struct fib6_config cfg;
3345 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346
David Ahern333c4302017-05-21 10:12:04 -06003347 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07003348 if (err < 0)
3349 return err;
3350
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003351 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06003352 return ip6_route_multipath_add(&cfg, extack);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00003353 else
David Ahern333c4302017-05-21 10:12:04 -06003354 return ip6_route_add(&cfg, extack);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355}
3356
David Ahernbeb1afac52017-02-02 12:37:09 -08003357static size_t rt6_nlmsg_size(struct rt6_info *rt)
Thomas Graf339bf982006-11-10 14:10:15 -08003358{
David Ahernbeb1afac52017-02-02 12:37:09 -08003359 int nexthop_len = 0;
3360
3361 if (rt->rt6i_nsiblings) {
3362 nexthop_len = nla_total_size(0) /* RTA_MULTIPATH */
3363 + NLA_ALIGN(sizeof(struct rtnexthop))
3364 + nla_total_size(16) /* RTA_GATEWAY */
David Ahernbeb1afac52017-02-02 12:37:09 -08003365 + lwtunnel_get_encap_size(rt->dst.lwtstate);
3366
3367 nexthop_len *= rt->rt6i_nsiblings;
3368 }
3369
Thomas Graf339bf982006-11-10 14:10:15 -08003370 return NLMSG_ALIGN(sizeof(struct rtmsg))
3371 + nla_total_size(16) /* RTA_SRC */
3372 + nla_total_size(16) /* RTA_DST */
3373 + nla_total_size(16) /* RTA_GATEWAY */
3374 + nla_total_size(16) /* RTA_PREFSRC */
3375 + nla_total_size(4) /* RTA_TABLE */
3376 + nla_total_size(4) /* RTA_IIF */
3377 + nla_total_size(4) /* RTA_OIF */
3378 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08003379 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Daniel Borkmannea697632015-01-05 23:57:47 +01003380 + nla_total_size(sizeof(struct rta_cacheinfo))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01003381 + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003382 + nla_total_size(1) /* RTA_PREF */
David Ahernbeb1afac52017-02-02 12:37:09 -08003383 + lwtunnel_get_encap_size(rt->dst.lwtstate)
3384 + nexthop_len;
3385}
3386
3387static int rt6_nexthop_info(struct sk_buff *skb, struct rt6_info *rt,
David Ahern5be083c2017-03-06 15:57:31 -08003388 unsigned int *flags, bool skip_oif)
David Ahernbeb1afac52017-02-02 12:37:09 -08003389{
3390 if (!netif_running(rt->dst.dev) || !netif_carrier_ok(rt->dst.dev)) {
3391 *flags |= RTNH_F_LINKDOWN;
3392 if (rt->rt6i_idev->cnf.ignore_routes_with_linkdown)
3393 *flags |= RTNH_F_DEAD;
3394 }
3395
3396 if (rt->rt6i_flags & RTF_GATEWAY) {
3397 if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->rt6i_gateway) < 0)
3398 goto nla_put_failure;
3399 }
3400
David Ahern5be083c2017-03-06 15:57:31 -08003401 /* not needed for multipath encoding b/c it has a rtnexthop struct */
3402 if (!skip_oif && rt->dst.dev &&
David Ahernbeb1afac52017-02-02 12:37:09 -08003403 nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex))
3404 goto nla_put_failure;
3405
3406 if (rt->dst.lwtstate &&
3407 lwtunnel_fill_encap(skb, rt->dst.lwtstate) < 0)
3408 goto nla_put_failure;
3409
3410 return 0;
3411
3412nla_put_failure:
3413 return -EMSGSIZE;
3414}
3415
David Ahern5be083c2017-03-06 15:57:31 -08003416/* add multipath next hop */
David Ahernbeb1afac52017-02-02 12:37:09 -08003417static int rt6_add_nexthop(struct sk_buff *skb, struct rt6_info *rt)
3418{
3419 struct rtnexthop *rtnh;
3420 unsigned int flags = 0;
3421
3422 rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh));
3423 if (!rtnh)
3424 goto nla_put_failure;
3425
3426 rtnh->rtnh_hops = 0;
3427 rtnh->rtnh_ifindex = rt->dst.dev ? rt->dst.dev->ifindex : 0;
3428
David Ahern5be083c2017-03-06 15:57:31 -08003429 if (rt6_nexthop_info(skb, rt, &flags, true) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08003430 goto nla_put_failure;
3431
3432 rtnh->rtnh_flags = flags;
3433
3434 /* length of rtnetlink header + attributes */
3435 rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *)rtnh;
3436
3437 return 0;
3438
3439nla_put_failure:
3440 return -EMSGSIZE;
Thomas Graf339bf982006-11-10 14:10:15 -08003441}
3442
Brian Haley191cd582008-08-14 15:33:21 -07003443static int rt6_fill_node(struct net *net,
3444 struct sk_buff *skb, struct rt6_info *rt,
Jamal Hadi Salim0d51aa82005-06-21 13:51:04 -07003445 struct in6_addr *dst, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003446 int iif, int type, u32 portid, u32 seq,
David Ahernf8cfe2c2017-01-17 15:51:08 -08003447 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448{
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07003449 u32 metrics[RTAX_MAX];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 struct rtmsg *rtm;
Thomas Graf2d7202b2006-08-22 00:01:27 -07003451 struct nlmsghdr *nlh;
Thomas Grafe3703b32006-11-27 09:27:07 -08003452 long expires;
Patrick McHardy9e762a42006-08-10 23:09:48 -07003453 u32 table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454
Eric W. Biederman15e47302012-09-07 20:12:54 +00003455 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05003456 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08003457 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07003458
3459 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 rtm->rtm_family = AF_INET6;
3461 rtm->rtm_dst_len = rt->rt6i_dst.plen;
3462 rtm->rtm_src_len = rt->rt6i_src.plen;
3463 rtm->rtm_tos = 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07003464 if (rt->rt6i_table)
Patrick McHardy9e762a42006-08-10 23:09:48 -07003465 table = rt->rt6i_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07003466 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07003467 table = RT6_TABLE_UNSPEC;
3468 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04003469 if (nla_put_u32(skb, RTA_TABLE, table))
3470 goto nla_put_failure;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00003471 if (rt->rt6i_flags & RTF_REJECT) {
3472 switch (rt->dst.error) {
3473 case -EINVAL:
3474 rtm->rtm_type = RTN_BLACKHOLE;
3475 break;
3476 case -EACCES:
3477 rtm->rtm_type = RTN_PROHIBIT;
3478 break;
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00003479 case -EAGAIN:
3480 rtm->rtm_type = RTN_THROW;
3481 break;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00003482 default:
3483 rtm->rtm_type = RTN_UNREACHABLE;
3484 break;
3485 }
3486 }
David S. Miller38308472011-12-03 18:02:47 -05003487 else if (rt->rt6i_flags & RTF_LOCAL)
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00003488 rtm->rtm_type = RTN_LOCAL;
David Ahern4ee39732017-03-15 18:14:33 -07003489 else if (rt->rt6i_flags & RTF_ANYCAST)
3490 rtm->rtm_type = RTN_ANYCAST;
David S. Millerd1918542011-12-28 20:19:20 -05003491 else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492 rtm->rtm_type = RTN_LOCAL;
3493 else
3494 rtm->rtm_type = RTN_UNICAST;
3495 rtm->rtm_flags = 0;
3496 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
3497 rtm->rtm_protocol = rt->rt6i_protocol;
David S. Miller38308472011-12-03 18:02:47 -05003498 if (rt->rt6i_flags & RTF_DYNAMIC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499 rtm->rtm_protocol = RTPROT_REDIRECT;
Denis Ovsienkof0396f602012-07-10 04:45:50 +00003500 else if (rt->rt6i_flags & RTF_ADDRCONF) {
3501 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ROUTEINFO))
3502 rtm->rtm_protocol = RTPROT_RA;
3503 else
3504 rtm->rtm_protocol = RTPROT_KERNEL;
3505 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506
David S. Miller38308472011-12-03 18:02:47 -05003507 if (rt->rt6i_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508 rtm->rtm_flags |= RTM_F_CLONED;
3509
3510 if (dst) {
Jiri Benc930345e2015-03-29 16:59:25 +02003511 if (nla_put_in6_addr(skb, RTA_DST, dst))
David S. Millerc78679e2012-04-01 20:27:33 -04003512 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003513 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 } else if (rtm->rtm_dst_len)
Jiri Benc930345e2015-03-29 16:59:25 +02003515 if (nla_put_in6_addr(skb, RTA_DST, &rt->rt6i_dst.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04003516 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517#ifdef CONFIG_IPV6_SUBTREES
3518 if (src) {
Jiri Benc930345e2015-03-29 16:59:25 +02003519 if (nla_put_in6_addr(skb, RTA_SRC, src))
David S. Millerc78679e2012-04-01 20:27:33 -04003520 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003521 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04003522 } else if (rtm->rtm_src_len &&
Jiri Benc930345e2015-03-29 16:59:25 +02003523 nla_put_in6_addr(skb, RTA_SRC, &rt->rt6i_src.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04003524 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003526 if (iif) {
3527#ifdef CONFIG_IPV6_MROUTE
3528 if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
David Ahernfd61c6b2017-01-17 15:51:07 -08003529 int err = ip6mr_get_route(net, skb, rtm, portid);
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02003530
David Ahernfd61c6b2017-01-17 15:51:07 -08003531 if (err == 0)
3532 return 0;
3533 if (err < 0)
3534 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003535 } else
3536#endif
David S. Millerc78679e2012-04-01 20:27:33 -04003537 if (nla_put_u32(skb, RTA_IIF, iif))
3538 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09003539 } else if (dst) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 struct in6_addr saddr_buf;
David S. Millerc78679e2012-04-01 20:27:33 -04003541 if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0 &&
Jiri Benc930345e2015-03-29 16:59:25 +02003542 nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04003543 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07003545
Daniel Walterc3968a82011-04-13 21:10:57 +00003546 if (rt->rt6i_prefsrc.plen) {
3547 struct in6_addr saddr_buf;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003548 saddr_buf = rt->rt6i_prefsrc.addr;
Jiri Benc930345e2015-03-29 16:59:25 +02003549 if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04003550 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00003551 }
3552
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07003553 memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics));
3554 if (rt->rt6i_pmtu)
3555 metrics[RTAX_MTU - 1] = rt->rt6i_pmtu;
3556 if (rtnetlink_put_metrics(skb, metrics) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07003557 goto nla_put_failure;
3558
David S. Millerc78679e2012-04-01 20:27:33 -04003559 if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric))
3560 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00003561
David Ahernbeb1afac52017-02-02 12:37:09 -08003562 /* For multipath routes, walk the siblings list and add
3563 * each as a nexthop within RTA_MULTIPATH.
3564 */
3565 if (rt->rt6i_nsiblings) {
3566 struct rt6_info *sibling, *next_sibling;
3567 struct nlattr *mp;
3568
3569 mp = nla_nest_start(skb, RTA_MULTIPATH);
3570 if (!mp)
3571 goto nla_put_failure;
3572
3573 if (rt6_add_nexthop(skb, rt) < 0)
3574 goto nla_put_failure;
3575
3576 list_for_each_entry_safe(sibling, next_sibling,
3577 &rt->rt6i_siblings, rt6i_siblings) {
3578 if (rt6_add_nexthop(skb, sibling) < 0)
3579 goto nla_put_failure;
3580 }
3581
3582 nla_nest_end(skb, mp);
3583 } else {
David Ahern5be083c2017-03-06 15:57:31 -08003584 if (rt6_nexthop_info(skb, rt, &rtm->rtm_flags, false) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08003585 goto nla_put_failure;
3586 }
3587
Li Wei82539472012-07-29 16:01:30 +00003588 expires = (rt->rt6i_flags & RTF_EXPIRES) ? rt->dst.expires - jiffies : 0;
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07003589
David S. Miller87a50692012-07-10 05:06:14 -07003590 if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, rt->dst.error) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08003591 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01003593 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags)))
3594 goto nla_put_failure;
3595
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003596
Johannes Berg053c0952015-01-16 22:09:00 +01003597 nlmsg_end(skb, nlh);
3598 return 0;
Thomas Graf2d7202b2006-08-22 00:01:27 -07003599
3600nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08003601 nlmsg_cancel(skb, nlh);
3602 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603}
3604
Patrick McHardy1b43af52006-08-10 23:11:17 -07003605int rt6_dump_route(struct rt6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606{
3607 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
David Ahern1f17e2f2017-01-26 13:54:08 -08003608 struct net *net = arg->net;
3609
3610 if (rt == net->ipv6.ip6_null_entry)
3611 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612
Thomas Graf2d7202b2006-08-22 00:01:27 -07003613 if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
3614 struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
David Ahernf8cfe2c2017-01-17 15:51:08 -08003615
3616 /* user wants prefix routes only */
3617 if (rtm->rtm_flags & RTM_F_PREFIX &&
3618 !(rt->rt6i_flags & RTF_PREFIX_RT)) {
3619 /* success since this is not a prefix route */
3620 return 1;
3621 }
3622 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623
David Ahern1f17e2f2017-01-26 13:54:08 -08003624 return rt6_fill_node(net,
Brian Haley191cd582008-08-14 15:33:21 -07003625 arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003626 NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq,
David Ahernf8cfe2c2017-01-17 15:51:08 -08003627 NLM_F_MULTI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628}
3629
David Ahernc21ef3e2017-04-16 09:48:24 -07003630static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
3631 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09003633 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07003634 struct nlattr *tb[RTA_MAX+1];
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003635 int err, iif = 0, oif = 0;
3636 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07003638 struct sk_buff *skb;
3639 struct rtmsg *rtm;
David S. Miller4c9483b2011-03-12 16:22:43 -05003640 struct flowi6 fl6;
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003641 bool fibmatch;
Thomas Grafab364a62006-08-22 00:01:47 -07003642
Johannes Bergfceb6432017-04-12 14:34:07 +02003643 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
David Ahernc21ef3e2017-04-16 09:48:24 -07003644 extack);
Thomas Grafab364a62006-08-22 00:01:47 -07003645 if (err < 0)
3646 goto errout;
3647
3648 err = -EINVAL;
David S. Miller4c9483b2011-03-12 16:22:43 -05003649 memset(&fl6, 0, sizeof(fl6));
Hannes Frederic Sowa38b70972016-06-11 20:08:19 +02003650 rtm = nlmsg_data(nlh);
3651 fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003652 fibmatch = !!(rtm->rtm_flags & RTM_F_FIB_MATCH);
Thomas Grafab364a62006-08-22 00:01:47 -07003653
3654 if (tb[RTA_SRC]) {
3655 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
3656 goto errout;
3657
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003658 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07003659 }
3660
3661 if (tb[RTA_DST]) {
3662 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
3663 goto errout;
3664
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003665 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07003666 }
3667
3668 if (tb[RTA_IIF])
3669 iif = nla_get_u32(tb[RTA_IIF]);
3670
3671 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003672 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07003673
Lorenzo Colitti2e47b292014-05-15 16:38:41 -07003674 if (tb[RTA_MARK])
3675 fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
3676
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09003677 if (tb[RTA_UID])
3678 fl6.flowi6_uid = make_kuid(current_user_ns(),
3679 nla_get_u32(tb[RTA_UID]));
3680 else
3681 fl6.flowi6_uid = iif ? INVALID_UID : current_uid();
3682
Thomas Grafab364a62006-08-22 00:01:47 -07003683 if (iif) {
3684 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003685 int flags = 0;
3686
Daniel Lezcano55786892008-03-04 13:47:47 -08003687 dev = __dev_get_by_index(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07003688 if (!dev) {
3689 err = -ENODEV;
3690 goto errout;
3691 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003692
3693 fl6.flowi6_iif = iif;
3694
3695 if (!ipv6_addr_any(&fl6.saddr))
3696 flags |= RT6_LOOKUP_F_HAS_SADDR;
3697
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003698 if (!fibmatch)
3699 dst = ip6_route_input_lookup(net, dev, &fl6, flags);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00003700 } else {
3701 fl6.flowi6_oif = oif;
3702
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003703 if (!fibmatch)
3704 dst = ip6_route_output(net, NULL, &fl6);
3705 }
3706
3707 if (fibmatch)
3708 dst = ip6_route_lookup(net, &fl6, 0);
3709
3710 rt = container_of(dst, struct rt6_info, dst);
3711 if (rt->dst.error) {
3712 err = rt->dst.error;
3713 ip6_rt_put(rt);
3714 goto errout;
Thomas Grafab364a62006-08-22 00:01:47 -07003715 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716
WANG Cong9d6acb32017-03-01 20:48:39 -08003717 if (rt == net->ipv6.ip6_null_entry) {
3718 err = rt->dst.error;
3719 ip6_rt_put(rt);
3720 goto errout;
3721 }
3722
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05003724 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00003725 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07003726 err = -ENOBUFS;
3727 goto errout;
3728 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729
Changli Gaod8d1f302010-06-10 23:31:35 -07003730 skb_dst_set(skb, &rt->dst);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07003731 if (fibmatch)
3732 err = rt6_fill_node(net, skb, rt, NULL, NULL, iif,
3733 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
3734 nlh->nlmsg_seq, 0);
3735 else
3736 err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
3737 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
3738 nlh->nlmsg_seq, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07003740 kfree_skb(skb);
3741 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742 }
3743
Eric W. Biederman15e47302012-09-07 20:12:54 +00003744 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07003745errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747}
3748
Roopa Prabhu37a1d362015-09-13 10:18:33 -07003749void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info,
3750 unsigned int nlm_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751{
3752 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08003753 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003754 u32 seq;
3755 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003757 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05003758 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07003759
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003760 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05003761 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07003762 goto errout;
3763
Brian Haley191cd582008-08-14 15:33:21 -07003764 err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
David Ahernf8cfe2c2017-01-17 15:51:08 -08003765 event, info->portid, seq, nlm_flags);
Patrick McHardy26932562007-01-31 23:16:40 -08003766 if (err < 0) {
3767 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
3768 WARN_ON(err == -EMSGSIZE);
3769 kfree_skb(skb);
3770 goto errout;
3771 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00003772 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08003773 info->nlh, gfp_any());
3774 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07003775errout:
3776 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08003777 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778}
3779
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003780static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00003781 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003782{
Jiri Pirko351638e2013-05-28 01:30:21 +00003783 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09003784 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003785
WANG Cong242d3a42017-05-08 10:12:13 -07003786 if (!(dev->flags & IFF_LOOPBACK))
3787 return NOTIFY_OK;
3788
3789 if (event == NETDEV_REGISTER) {
Changli Gaod8d1f302010-06-10 23:31:35 -07003790 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003791 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
3792#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07003793 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003794 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07003795 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003796 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
3797#endif
WANG Cong242d3a42017-05-08 10:12:13 -07003798 } else if (event == NETDEV_UNREGISTER) {
3799 in6_dev_put(net->ipv6.ip6_null_entry->rt6i_idev);
3800#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3801 in6_dev_put(net->ipv6.ip6_prohibit_entry->rt6i_idev);
3802 in6_dev_put(net->ipv6.ip6_blk_hole_entry->rt6i_idev);
3803#endif
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003804 }
3805
3806 return NOTIFY_OK;
3807}
3808
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809/*
3810 * /proc
3811 */
3812
3813#ifdef CONFIG_PROC_FS
3814
Alexey Dobriyan33120b32007-11-06 05:27:11 -08003815static const struct file_operations ipv6_route_proc_fops = {
3816 .owner = THIS_MODULE,
3817 .open = ipv6_route_open,
3818 .read = seq_read,
3819 .llseek = seq_lseek,
Hannes Frederic Sowa8d2ca1d2013-09-21 16:55:59 +02003820 .release = seq_release_net,
Alexey Dobriyan33120b32007-11-06 05:27:11 -08003821};
3822
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823static int rt6_stats_seq_show(struct seq_file *seq, void *v)
3824{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003825 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003827 net->ipv6.rt6_stats->fib_nodes,
3828 net->ipv6.rt6_stats->fib_route_nodes,
3829 net->ipv6.rt6_stats->fib_rt_alloc,
3830 net->ipv6.rt6_stats->fib_rt_entries,
3831 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00003832 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003833 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834
3835 return 0;
3836}
3837
3838static int rt6_stats_seq_open(struct inode *inode, struct file *file)
3839{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07003840 return single_open_net(inode, file, rt6_stats_seq_show);
Daniel Lezcano69ddb802008-03-04 13:46:23 -08003841}
3842
Arjan van de Ven9a321442007-02-12 00:55:35 -08003843static const struct file_operations rt6_stats_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844 .owner = THIS_MODULE,
3845 .open = rt6_stats_seq_open,
3846 .read = seq_read,
3847 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07003848 .release = single_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849};
3850#endif /* CONFIG_PROC_FS */
3851
3852#ifdef CONFIG_SYSCTL
3853
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854static
Joe Perchesfe2c6332013-06-11 23:04:25 -07003855int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856 void __user *buffer, size_t *lenp, loff_t *ppos)
3857{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003858 struct net *net;
3859 int delay;
3860 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003862
3863 net = (struct net *)ctl->extra1;
3864 delay = net->ipv6.sysctl.flush_delay;
3865 proc_dointvec(ctl, write, buffer, lenp, ppos);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02003866 fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003867 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868}
3869
Joe Perchesfe2c6332013-06-11 23:04:25 -07003870struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003871 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08003873 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07003875 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003876 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 },
3878 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08003880 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 .maxlen = sizeof(int),
3882 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003883 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 },
3885 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08003887 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 .maxlen = sizeof(int),
3889 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003890 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891 },
3892 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08003894 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 .maxlen = sizeof(int),
3896 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003897 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003898 },
3899 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08003901 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 .maxlen = sizeof(int),
3903 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003904 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 },
3906 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08003908 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909 .maxlen = sizeof(int),
3910 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003911 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 },
3913 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08003915 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916 .maxlen = sizeof(int),
3917 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003918 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919 },
3920 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003921 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08003922 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003923 .maxlen = sizeof(int),
3924 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003925 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926 },
3927 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08003929 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930 .maxlen = sizeof(int),
3931 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07003932 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933 },
3934 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08003936 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937 .maxlen = sizeof(int),
3938 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003939 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08003941 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942};
3943
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003944struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003945{
3946 struct ctl_table *table;
3947
3948 table = kmemdup(ipv6_route_table_template,
3949 sizeof(ipv6_route_table_template),
3950 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003951
3952 if (table) {
3953 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00003954 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003955 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003956 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
3957 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
3958 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
3959 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
3960 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
3961 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
3962 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08003963 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
Eric W. Biederman464dc802012-11-16 03:02:59 +00003964
3965 /* Don't export sysctls to unprivileged users */
3966 if (net->user_ns != &init_user_ns)
3967 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09003968 }
3969
Daniel Lezcano760f2d02008-01-10 02:53:43 -08003970 return table;
3971}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972#endif
3973
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00003974static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08003975{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07003976 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003977
Alexey Dobriyan86393e52009-08-29 01:34:49 +00003978 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
3979 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08003980
Eric Dumazetfc66f952010-10-08 06:37:34 +00003981 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
3982 goto out_ip6_dst_ops;
3983
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003984 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
3985 sizeof(*net->ipv6.ip6_null_entry),
3986 GFP_KERNEL);
3987 if (!net->ipv6.ip6_null_entry)
Eric Dumazetfc66f952010-10-08 06:37:34 +00003988 goto out_ip6_dst_entries;
Changli Gaod8d1f302010-06-10 23:31:35 -07003989 net->ipv6.ip6_null_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003990 (struct dst_entry *)net->ipv6.ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07003991 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08003992 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
3993 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08003994
3995#ifdef CONFIG_IPV6_MULTIPLE_TABLES
3996 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
3997 sizeof(*net->ipv6.ip6_prohibit_entry),
3998 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07003999 if (!net->ipv6.ip6_prohibit_entry)
4000 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07004001 net->ipv6.ip6_prohibit_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004002 (struct dst_entry *)net->ipv6.ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07004003 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08004004 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
4005 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004006
4007 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
4008 sizeof(*net->ipv6.ip6_blk_hole_entry),
4009 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07004010 if (!net->ipv6.ip6_blk_hole_entry)
4011 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07004012 net->ipv6.ip6_blk_hole_entry->dst.path =
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004013 (struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07004014 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08004015 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
4016 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004017#endif
4018
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07004019 net->ipv6.sysctl.flush_delay = 0;
4020 net->ipv6.sysctl.ip6_rt_max_size = 4096;
4021 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
4022 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
4023 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
4024 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
4025 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
4026 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
4027
Benjamin Thery6891a342008-03-04 13:49:47 -08004028 net->ipv6.ip6_rt_gc_expire = 30*HZ;
4029
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004030 ret = 0;
4031out:
4032 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004033
Peter Zijlstra68fffc62008-10-07 14:12:10 -07004034#ifdef CONFIG_IPV6_MULTIPLE_TABLES
4035out_ip6_prohibit_entry:
4036 kfree(net->ipv6.ip6_prohibit_entry);
4037out_ip6_null_entry:
4038 kfree(net->ipv6.ip6_null_entry);
4039#endif
Eric Dumazetfc66f952010-10-08 06:37:34 +00004040out_ip6_dst_entries:
4041 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004042out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004043 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004044}
4045
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00004046static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004047{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004048 kfree(net->ipv6.ip6_null_entry);
4049#ifdef CONFIG_IPV6_MULTIPLE_TABLES
4050 kfree(net->ipv6.ip6_prohibit_entry);
4051 kfree(net->ipv6.ip6_blk_hole_entry);
4052#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00004053 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004054}
4055
Thomas Grafd1896342012-06-18 12:08:33 +00004056static int __net_init ip6_route_net_init_late(struct net *net)
4057{
4058#ifdef CONFIG_PROC_FS
Gao fengd4beaa62013-02-18 01:34:54 +00004059 proc_create("ipv6_route", 0, net->proc_net, &ipv6_route_proc_fops);
4060 proc_create("rt6_stats", S_IRUGO, net->proc_net, &rt6_stats_seq_fops);
Thomas Grafd1896342012-06-18 12:08:33 +00004061#endif
4062 return 0;
4063}
4064
4065static void __net_exit ip6_route_net_exit_late(struct net *net)
4066{
4067#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00004068 remove_proc_entry("ipv6_route", net->proc_net);
4069 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00004070#endif
4071}
4072
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004073static struct pernet_operations ip6_route_net_ops = {
4074 .init = ip6_route_net_init,
4075 .exit = ip6_route_net_exit,
4076};
4077
David S. Millerc3426b42012-06-09 16:27:05 -07004078static int __net_init ipv6_inetpeer_init(struct net *net)
4079{
4080 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
4081
4082 if (!bp)
4083 return -ENOMEM;
4084 inet_peer_base_init(bp);
4085 net->ipv6.peers = bp;
4086 return 0;
4087}
4088
4089static void __net_exit ipv6_inetpeer_exit(struct net *net)
4090{
4091 struct inet_peer_base *bp = net->ipv6.peers;
4092
4093 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07004094 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07004095 kfree(bp);
4096}
4097
David S. Miller2b823f72012-06-09 19:00:16 -07004098static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07004099 .init = ipv6_inetpeer_init,
4100 .exit = ipv6_inetpeer_exit,
4101};
4102
Thomas Grafd1896342012-06-18 12:08:33 +00004103static struct pernet_operations ip6_route_net_late_ops = {
4104 .init = ip6_route_net_init_late,
4105 .exit = ip6_route_net_exit_late,
4106};
4107
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004108static struct notifier_block ip6_route_dev_notifier = {
4109 .notifier_call = ip6_route_dev_notify,
WANG Cong242d3a42017-05-08 10:12:13 -07004110 .priority = ADDRCONF_NOTIFY_PRIORITY - 10,
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004111};
4112
WANG Cong2f460932017-05-03 22:07:31 -07004113void __init ip6_route_init_special_entries(void)
4114{
4115 /* Registering of the loopback is done before this portion of code,
4116 * the loopback reference in rt6_info will not be taken, do it
4117 * manually for init_net */
4118 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
4119 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
4120 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
4121 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
4122 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
4123 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
4124 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
4125 #endif
4126}
4127
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004128int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004130 int ret;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07004131 int cpu;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004132
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08004133 ret = -ENOMEM;
4134 ip6_dst_ops_template.kmem_cachep =
4135 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
4136 SLAB_HWCACHE_ALIGN, NULL);
4137 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08004138 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07004139
Eric Dumazetfc66f952010-10-08 06:37:34 +00004140 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004141 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08004142 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08004143
David S. Millerc3426b42012-06-09 16:27:05 -07004144 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
4145 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07004146 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00004147
David S. Miller7e52b332012-06-15 15:51:55 -07004148 ret = register_pernet_subsys(&ip6_route_net_ops);
4149 if (ret)
4150 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07004151
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07004152 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
4153
David S. Millere8803b62012-06-16 01:12:19 -07004154 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004155 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004156 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004157
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004158 ret = xfrm6_init();
4159 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07004160 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08004161
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004162 ret = fib6_rules_init();
4163 if (ret)
4164 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08004165
Thomas Grafd1896342012-06-18 12:08:33 +00004166 ret = register_pernet_subsys(&ip6_route_net_late_ops);
4167 if (ret)
4168 goto fib6_rules_init;
4169
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004170 ret = -ENOBUFS;
Greg Rosec7ac8672011-06-10 01:27:09 +00004171 if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) ||
4172 __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) ||
4173 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL))
Thomas Grafd1896342012-06-18 12:08:33 +00004174 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004175
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004176 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08004177 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00004178 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004179
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07004180 for_each_possible_cpu(cpu) {
4181 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
4182
4183 INIT_LIST_HEAD(&ul->head);
4184 spin_lock_init(&ul->lock);
4185 }
4186
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004187out:
4188 return ret;
4189
Thomas Grafd1896342012-06-18 12:08:33 +00004190out_register_late_subsys:
4191 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004192fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004193 fib6_rules_cleanup();
4194xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004195 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00004196out_fib6_init:
4197 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004198out_register_subsys:
4199 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07004200out_register_inetpeer:
4201 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00004202out_dst_entries:
4203 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004204out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004205 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08004206 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207}
4208
4209void ip6_route_cleanup(void)
4210{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004211 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00004212 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07004213 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07004216 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004217 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00004218 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08004219 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220}