blob: 86a0e4333d42212d03f53e0d54fcf4e03a328607 [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>
Wei Wang35732d02017-10-06 12:05:57 -070047#include <linux/jhash.h>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020048#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <net/snmp.h>
50#include <net/ipv6.h>
51#include <net/ip6_fib.h>
52#include <net/ip6_route.h>
53#include <net/ndisc.h>
54#include <net/addrconf.h>
55#include <net/tcp.h>
56#include <linux/rtnetlink.h>
57#include <net/dst.h>
Jiri Benc904af042015-08-20 13:56:31 +020058#include <net/dst_metadata.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#include <net/xfrm.h>
Tom Tucker8d717402006-07-30 20:43:36 -070060#include <net/netevent.h>
Thomas Graf21713eb2006-08-15 00:35:24 -070061#include <net/netlink.h>
Nicolas Dichtel51ebd312012-10-22 03:42:09 +000062#include <net/nexthop.h>
Roopa Prabhu19e42e42015-07-21 10:43:48 +020063#include <net/lwtunnel.h>
Jiri Benc904af042015-08-20 13:56:31 +020064#include <net/ip_tunnels.h>
David Ahernca254492015-10-12 11:47:10 -070065#include <net/l3mdev.h>
Roopa Prabhueacb9382018-05-22 14:03:28 -070066#include <net/ip.h>
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
David Ahern30d444d2018-05-23 17:08:48 -070073static int ip6_rt_type_to_error(u8 fib6_type);
74
75#define CREATE_TRACE_POINTS
76#include <trace/events/fib6.h>
77EXPORT_TRACEPOINT_SYMBOL_GPL(fib6_table_lookup);
78#undef CREATE_TRACE_POINTS
79
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +020080enum rt6_nud_state {
Jiri Benc7e980562013-12-11 13:48:20 +010081 RT6_NUD_FAIL_HARD = -3,
82 RT6_NUD_FAIL_PROBE = -2,
83 RT6_NUD_FAIL_DO_RR = -1,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +020084 RT6_NUD_SUCCEED = 1
85};
86
Linus Torvalds1da177e2005-04-16 15:20:36 -070087static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
David S. Miller0dbaee32010-12-13 12:52:14 -080088static unsigned int ip6_default_advmss(const struct dst_entry *dst);
Steffen Klassertebb762f2011-11-23 02:12:51 +000089static unsigned int ip6_mtu(const struct dst_entry *dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -070090static struct dst_entry *ip6_negative_advice(struct dst_entry *);
91static void ip6_dst_destroy(struct dst_entry *);
92static void ip6_dst_ifdown(struct dst_entry *,
93 struct net_device *dev, int how);
Daniel Lezcano569d3642008-01-18 03:56:57 -080094static int ip6_dst_gc(struct dst_ops *ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
96static int ip6_pkt_discard(struct sk_buff *skb);
Eric W. Biedermanede20592015-10-07 16:48:47 -050097static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb);
Kamala R7150aed2013-12-02 19:55:21 +053098static int ip6_pkt_prohibit(struct sk_buff *skb);
Eric W. Biedermanede20592015-10-07 16:48:47 -050099static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100static void ip6_link_failure(struct sk_buff *skb);
David S. Miller6700c272012-07-17 03:29:28 -0700101static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
102 struct sk_buff *skb, u32 mtu);
103static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
104 struct sk_buff *skb);
David Ahern8d1c8022018-04-17 17:33:26 -0700105static int rt6_score_route(struct fib6_info *rt, int oif, int strict);
106static size_t rt6_nlmsg_size(struct fib6_info *rt);
David Ahernd4ead6b2018-04-17 17:33:16 -0700107static int rt6_fill_node(struct net *net, struct sk_buff *skb,
David Ahern8d1c8022018-04-17 17:33:26 -0700108 struct fib6_info *rt, struct dst_entry *dst,
David Ahernd4ead6b2018-04-17 17:33:16 -0700109 struct in6_addr *dest, struct in6_addr *src,
David Ahern16a16cd2017-02-02 12:37:11 -0800110 int iif, int type, u32 portid, u32 seq,
111 unsigned int flags);
David Ahern8d1c8022018-04-17 17:33:26 -0700112static struct rt6_info *rt6_find_cached_rt(struct fib6_info *rt,
Wei Wang35732d02017-10-06 12:05:57 -0700113 struct in6_addr *daddr,
114 struct in6_addr *saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800116#ifdef CONFIG_IPV6_ROUTE_INFO
David Ahern8d1c8022018-04-17 17:33:26 -0700117static struct fib6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000118 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -0700119 const struct in6_addr *gwaddr,
120 struct net_device *dev,
Eric Dumazet95c96172012-04-15 05:58:06 +0000121 unsigned int pref);
David Ahern8d1c8022018-04-17 17:33:26 -0700122static struct fib6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000123 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -0700124 const struct in6_addr *gwaddr,
125 struct net_device *dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800126#endif
127
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700128struct uncached_list {
129 spinlock_t lock;
130 struct list_head head;
131};
132
133static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list);
134
Xin Long510c3212018-02-14 19:06:02 +0800135void rt6_uncached_list_add(struct rt6_info *rt)
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700136{
137 struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);
138
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700139 rt->rt6i_uncached_list = ul;
140
141 spin_lock_bh(&ul->lock);
142 list_add_tail(&rt->rt6i_uncached, &ul->head);
143 spin_unlock_bh(&ul->lock);
144}
145
Xin Long510c3212018-02-14 19:06:02 +0800146void rt6_uncached_list_del(struct rt6_info *rt)
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700147{
148 if (!list_empty(&rt->rt6i_uncached)) {
149 struct uncached_list *ul = rt->rt6i_uncached_list;
Wei Wang81eb8442017-10-06 12:06:11 -0700150 struct net *net = dev_net(rt->dst.dev);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700151
152 spin_lock_bh(&ul->lock);
153 list_del(&rt->rt6i_uncached);
Wei Wang81eb8442017-10-06 12:06:11 -0700154 atomic_dec(&net->ipv6.rt6_stats->fib_rt_uncache);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700155 spin_unlock_bh(&ul->lock);
156 }
157}
158
159static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev)
160{
161 struct net_device *loopback_dev = net->loopback_dev;
162 int cpu;
163
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500164 if (dev == loopback_dev)
165 return;
166
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700167 for_each_possible_cpu(cpu) {
168 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
169 struct rt6_info *rt;
170
171 spin_lock_bh(&ul->lock);
172 list_for_each_entry(rt, &ul->head, rt6i_uncached) {
173 struct inet6_dev *rt_idev = rt->rt6i_idev;
174 struct net_device *rt_dev = rt->dst.dev;
175
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500176 if (rt_idev->dev == dev) {
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700177 rt->rt6i_idev = in6_dev_get(loopback_dev);
178 in6_dev_put(rt_idev);
179 }
180
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500181 if (rt_dev == dev) {
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700182 rt->dst.dev = loopback_dev;
183 dev_hold(rt->dst.dev);
184 dev_put(rt_dev);
185 }
186 }
187 spin_unlock_bh(&ul->lock);
188 }
189}
190
David Ahernf8a1b432018-04-17 17:33:21 -0700191static inline const void *choose_neigh_daddr(const struct in6_addr *p,
David S. Millerf894cbf2012-07-02 21:52:24 -0700192 struct sk_buff *skb,
193 const void *daddr)
David S. Miller39232972012-01-26 15:22:32 -0500194{
David S. Millera7563f32012-01-26 16:29:16 -0500195 if (!ipv6_addr_any(p))
David S. Miller39232972012-01-26 15:22:32 -0500196 return (const void *) p;
David S. Millerf894cbf2012-07-02 21:52:24 -0700197 else if (skb)
198 return &ipv6_hdr(skb)->daddr;
David S. Miller39232972012-01-26 15:22:32 -0500199 return daddr;
200}
201
David Ahernf8a1b432018-04-17 17:33:21 -0700202struct neighbour *ip6_neigh_lookup(const struct in6_addr *gw,
203 struct net_device *dev,
204 struct sk_buff *skb,
205 const void *daddr)
David S. Millerd3aaeb32011-07-18 00:40:17 -0700206{
David S. Miller39232972012-01-26 15:22:32 -0500207 struct neighbour *n;
208
David Ahernf8a1b432018-04-17 17:33:21 -0700209 daddr = choose_neigh_daddr(gw, skb, daddr);
210 n = __ipv6_neigh_lookup(dev, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500211 if (n)
212 return n;
David Ahernf8a1b432018-04-17 17:33:21 -0700213 return neigh_create(&nd_tbl, daddr, dev);
214}
215
216static struct neighbour *ip6_dst_neigh_lookup(const struct dst_entry *dst,
217 struct sk_buff *skb,
218 const void *daddr)
219{
220 const struct rt6_info *rt = container_of(dst, struct rt6_info, dst);
221
222 return ip6_neigh_lookup(&rt->rt6i_gateway, dst->dev, skb, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500223}
224
Julian Anastasov63fca652017-02-06 23:14:15 +0200225static void ip6_confirm_neigh(const struct dst_entry *dst, const void *daddr)
226{
227 struct net_device *dev = dst->dev;
228 struct rt6_info *rt = (struct rt6_info *)dst;
229
David Ahernf8a1b432018-04-17 17:33:21 -0700230 daddr = choose_neigh_daddr(&rt->rt6i_gateway, NULL, daddr);
Julian Anastasov63fca652017-02-06 23:14:15 +0200231 if (!daddr)
232 return;
233 if (dev->flags & (IFF_NOARP | IFF_LOOPBACK))
234 return;
235 if (ipv6_addr_is_multicast((const struct in6_addr *)daddr))
236 return;
237 __ipv6_confirm_neigh(dev, daddr);
238}
239
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -0800240static struct dst_ops ip6_dst_ops_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 .family = AF_INET6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 .gc = ip6_dst_gc,
243 .gc_thresh = 1024,
244 .check = ip6_dst_check,
David S. Miller0dbaee32010-12-13 12:52:14 -0800245 .default_advmss = ip6_default_advmss,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000246 .mtu = ip6_mtu,
David Ahernd4ead6b2018-04-17 17:33:16 -0700247 .cow_metrics = dst_cow_metrics_generic,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 .destroy = ip6_dst_destroy,
249 .ifdown = ip6_dst_ifdown,
250 .negative_advice = ip6_negative_advice,
251 .link_failure = ip6_link_failure,
252 .update_pmtu = ip6_rt_update_pmtu,
David S. Miller6e157b62012-07-12 00:05:02 -0700253 .redirect = rt6_do_redirect,
Eric W. Biederman9f8955c2015-10-07 16:48:39 -0500254 .local_out = __ip6_local_out,
David Ahernf8a1b432018-04-17 17:33:21 -0700255 .neigh_lookup = ip6_dst_neigh_lookup,
Julian Anastasov63fca652017-02-06 23:14:15 +0200256 .confirm_neigh = ip6_confirm_neigh,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257};
258
Steffen Klassertebb762f2011-11-23 02:12:51 +0000259static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
Roland Dreierec831ea2011-01-31 13:16:00 -0800260{
Steffen Klassert618f9bc2011-11-23 02:13:31 +0000261 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
262
263 return mtu ? : dst->dev->mtu;
Roland Dreierec831ea2011-01-31 13:16:00 -0800264}
265
David S. Miller6700c272012-07-17 03:29:28 -0700266static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
267 struct sk_buff *skb, u32 mtu)
David S. Miller14e50e52007-05-24 18:17:54 -0700268{
269}
270
David S. Miller6700c272012-07-17 03:29:28 -0700271static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
272 struct sk_buff *skb)
David S. Millerb587ee32012-07-12 00:39:24 -0700273{
274}
275
David S. Miller14e50e52007-05-24 18:17:54 -0700276static struct dst_ops ip6_dst_blackhole_ops = {
277 .family = AF_INET6,
David S. Miller14e50e52007-05-24 18:17:54 -0700278 .destroy = ip6_dst_destroy,
279 .check = ip6_dst_check,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000280 .mtu = ip6_blackhole_mtu,
Eric Dumazet214f45c2011-02-18 11:39:01 -0800281 .default_advmss = ip6_default_advmss,
David S. Miller14e50e52007-05-24 18:17:54 -0700282 .update_pmtu = ip6_rt_blackhole_update_pmtu,
David S. Millerb587ee32012-07-12 00:39:24 -0700283 .redirect = ip6_rt_blackhole_redirect,
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -0700284 .cow_metrics = dst_cow_metrics_generic,
David Ahernf8a1b432018-04-17 17:33:21 -0700285 .neigh_lookup = ip6_dst_neigh_lookup,
David S. Miller14e50e52007-05-24 18:17:54 -0700286};
287
David S. Miller62fa8a82011-01-26 20:51:05 -0800288static const u32 ip6_template_metrics[RTAX_MAX] = {
Li RongQing14edd872012-10-24 14:01:18 +0800289 [RTAX_HOPLIMIT - 1] = 0,
David S. Miller62fa8a82011-01-26 20:51:05 -0800290};
291
David Ahern8d1c8022018-04-17 17:33:26 -0700292static const struct fib6_info fib6_null_entry_template = {
David Ahern93c2fb22018-04-18 15:38:59 -0700293 .fib6_flags = (RTF_REJECT | RTF_NONEXTHOP),
294 .fib6_protocol = RTPROT_KERNEL,
295 .fib6_metric = ~(u32)0,
296 .fib6_ref = ATOMIC_INIT(1),
David Ahern421842e2018-04-17 17:33:18 -0700297 .fib6_type = RTN_UNREACHABLE,
298 .fib6_metrics = (struct dst_metrics *)&dst_default_metrics,
299};
300
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000301static const struct rt6_info ip6_null_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700302 .dst = {
303 .__refcnt = ATOMIC_INIT(1),
304 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000305 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700306 .error = -ENETUNREACH,
Changli Gaod8d1f302010-06-10 23:31:35 -0700307 .input = ip6_pkt_discard,
308 .output = ip6_pkt_discard_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 },
310 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311};
312
Thomas Graf101367c2006-08-04 03:39:02 -0700313#ifdef CONFIG_IPV6_MULTIPLE_TABLES
314
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000315static const struct rt6_info ip6_prohibit_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700316 .dst = {
317 .__refcnt = ATOMIC_INIT(1),
318 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000319 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700320 .error = -EACCES,
Changli Gaod8d1f302010-06-10 23:31:35 -0700321 .input = ip6_pkt_prohibit,
322 .output = ip6_pkt_prohibit_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700323 },
324 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Thomas Graf101367c2006-08-04 03:39:02 -0700325};
326
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000327static const struct rt6_info ip6_blk_hole_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700328 .dst = {
329 .__refcnt = ATOMIC_INIT(1),
330 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000331 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700332 .error = -EINVAL,
Changli Gaod8d1f302010-06-10 23:31:35 -0700333 .input = dst_discard,
Eric W. Biedermanede20592015-10-07 16:48:47 -0500334 .output = dst_discard_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700335 },
336 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Thomas Graf101367c2006-08-04 03:39:02 -0700337};
338
339#endif
340
Martin KaFai Lauebfa45f2015-10-15 16:39:57 -0700341static void rt6_info_init(struct rt6_info *rt)
342{
343 struct dst_entry *dst = &rt->dst;
344
345 memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
Martin KaFai Lauebfa45f2015-10-15 16:39:57 -0700346 INIT_LIST_HEAD(&rt->rt6i_uncached);
347}
348
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349/* allocate dst with ip6_dst_ops */
David Ahern93531c62018-04-17 17:33:25 -0700350struct rt6_info *ip6_dst_alloc(struct net *net, struct net_device *dev,
351 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352{
David S. Miller97bab732012-06-09 22:36:36 -0700353 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
Wei Wangb2a9c0e2017-06-17 10:42:41 -0700354 1, DST_OBSOLETE_FORCE_CHK, flags);
David S. Millercf911662011-04-28 14:31:47 -0700355
Wei Wang81eb8442017-10-06 12:06:11 -0700356 if (rt) {
Martin KaFai Lauebfa45f2015-10-15 16:39:57 -0700357 rt6_info_init(rt);
Wei Wang81eb8442017-10-06 12:06:11 -0700358 atomic_inc(&net->ipv6.rt6_stats->fib_rt_alloc);
359 }
Steffen Klassert81048912012-07-05 23:37:09 +0000360
David S. Millercf911662011-04-28 14:31:47 -0700361 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362}
David Ahern9ab179d2016-04-07 11:10:06 -0700363EXPORT_SYMBOL(ip6_dst_alloc);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700364
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365static void ip6_dst_destroy(struct dst_entry *dst)
366{
367 struct rt6_info *rt = (struct rt6_info *)dst;
David Aherna68886a2018-04-20 15:38:02 -0700368 struct fib6_info *from;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700369 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -0700371 dst_destroy_metrics_generic(dst);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700372 rt6_uncached_list_del(rt);
373
374 idev = rt->rt6i_idev;
David S. Miller38308472011-12-03 18:02:47 -0500375 if (idev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 rt->rt6i_idev = NULL;
377 in6_dev_put(idev);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900378 }
Gao feng1716a962012-04-06 00:13:10 +0000379
David Aherna68886a2018-04-20 15:38:02 -0700380 rcu_read_lock();
381 from = rcu_dereference(rt->from);
382 rcu_assign_pointer(rt->from, NULL);
David Ahern93531c62018-04-17 17:33:25 -0700383 fib6_info_release(from);
David Aherna68886a2018-04-20 15:38:02 -0700384 rcu_read_unlock();
David S. Millerb3419362010-11-30 12:27:11 -0800385}
386
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
388 int how)
389{
390 struct rt6_info *rt = (struct rt6_info *)dst;
391 struct inet6_dev *idev = rt->rt6i_idev;
Denis V. Lunev5a3e55d2007-12-07 00:38:10 -0800392 struct net_device *loopback_dev =
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900393 dev_net(dev)->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394
Wei Wange5645f52017-08-14 10:44:59 -0700395 if (idev && idev->dev != loopback_dev) {
396 struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev);
397 if (loopback_idev) {
398 rt->rt6i_idev = loopback_idev;
399 in6_dev_put(idev);
David S. Miller97cac082012-07-02 22:43:47 -0700400 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 }
402}
403
Martin KaFai Lau5973fb12015-11-11 11:51:07 -0800404static bool __rt6_check_expired(const struct rt6_info *rt)
405{
406 if (rt->rt6i_flags & RTF_EXPIRES)
407 return time_after(jiffies, rt->dst.expires);
408 else
409 return false;
410}
411
Eric Dumazeta50feda2012-05-18 18:57:34 +0000412static bool rt6_check_expired(const struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413{
David Aherna68886a2018-04-20 15:38:02 -0700414 struct fib6_info *from;
415
416 from = rcu_dereference(rt->from);
417
Gao feng1716a962012-04-06 00:13:10 +0000418 if (rt->rt6i_flags & RTF_EXPIRES) {
419 if (time_after(jiffies, rt->dst.expires))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000420 return true;
David Aherna68886a2018-04-20 15:38:02 -0700421 } else if (from) {
Xin Long1e2ea8a2017-08-26 20:10:10 +0800422 return rt->dst.obsolete != DST_OBSOLETE_FORCE_CHK ||
David Aherna68886a2018-04-20 15:38:02 -0700423 fib6_check_expired(from);
Gao feng1716a962012-04-06 00:13:10 +0000424 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000425 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426}
427
David Ahern3b290a32018-05-09 20:34:20 -0700428struct fib6_info *fib6_multipath_select(const struct net *net,
429 struct fib6_info *match,
430 struct flowi6 *fl6, int oif,
431 const struct sk_buff *skb,
432 int strict)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000433{
David Ahern8d1c8022018-04-17 17:33:26 -0700434 struct fib6_info *sibling, *next_sibling;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000435
Jakub Sitnickib673d6c2017-08-23 09:58:31 +0200436 /* We might have already computed the hash for ICMPv6 errors. In such
437 * case it will always be non-zero. Otherwise now is the time to do it.
438 */
439 if (!fl6->mp_hash)
David Ahernb4bac172018-03-02 08:32:18 -0800440 fl6->mp_hash = rt6_multipath_hash(net, fl6, skb, NULL);
Jakub Sitnickib673d6c2017-08-23 09:58:31 +0200441
David Ahern5e670d82018-04-17 17:33:14 -0700442 if (fl6->mp_hash <= atomic_read(&match->fib6_nh.nh_upper_bound))
Ido Schimmel3d709f62018-01-09 16:40:27 +0200443 return match;
Ido Schimmelbbfcd772017-11-21 09:50:12 +0200444
David Ahern93c2fb22018-04-18 15:38:59 -0700445 list_for_each_entry_safe(sibling, next_sibling, &match->fib6_siblings,
446 fib6_siblings) {
David Ahern5e670d82018-04-17 17:33:14 -0700447 int nh_upper_bound;
448
449 nh_upper_bound = atomic_read(&sibling->fib6_nh.nh_upper_bound);
450 if (fl6->mp_hash > nh_upper_bound)
Ido Schimmel3d709f62018-01-09 16:40:27 +0200451 continue;
452 if (rt6_score_route(sibling, oif, strict) < 0)
453 break;
454 match = sibling;
455 break;
456 }
457
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000458 return match;
459}
460
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461/*
Wei Wang66f5d6c2017-10-06 12:06:10 -0700462 * Route lookup. rcu_read_lock() should be held.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 */
464
David Ahern8d1c8022018-04-17 17:33:26 -0700465static inline struct fib6_info *rt6_device_match(struct net *net,
466 struct fib6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000467 const struct in6_addr *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 int oif,
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700469 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470{
David Ahern8d1c8022018-04-17 17:33:26 -0700471 struct fib6_info *sprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472
David Ahern5e670d82018-04-17 17:33:14 -0700473 if (!oif && ipv6_addr_any(saddr) &&
474 !(rt->fib6_nh.nh_flags & RTNH_F_DEAD))
Ido Schimmel8067bb82018-01-07 12:45:09 +0200475 return rt;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900476
David Ahern8fb11a92018-05-04 13:54:24 -0700477 for (sprt = rt; sprt; sprt = rcu_dereference(sprt->fib6_next)) {
David Ahern5e670d82018-04-17 17:33:14 -0700478 const struct net_device *dev = sprt->fib6_nh.nh_dev;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900479
David Ahern5e670d82018-04-17 17:33:14 -0700480 if (sprt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel8067bb82018-01-07 12:45:09 +0200481 continue;
482
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900483 if (oif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 if (dev->ifindex == oif)
485 return sprt;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900486 } else {
487 if (ipv6_chk_addr(net, saddr, dev,
488 flags & RT6_LOOKUP_F_IFACE))
489 return sprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 }
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900491 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
David Aherneea68cd2018-04-18 15:39:02 -0700493 if (oif && flags & RT6_LOOKUP_F_IFACE)
494 return net->ipv6.fib6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
David Ahern421842e2018-04-17 17:33:18 -0700496 return rt->fib6_nh.nh_flags & RTNH_F_DEAD ? net->ipv6.fib6_null_entry : rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497}
498
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800499#ifdef CONFIG_IPV6_ROUTER_PREF
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200500struct __rt6_probe_work {
501 struct work_struct work;
502 struct in6_addr target;
503 struct net_device *dev;
504};
505
506static void rt6_probe_deferred(struct work_struct *w)
507{
508 struct in6_addr mcaddr;
509 struct __rt6_probe_work *work =
510 container_of(w, struct __rt6_probe_work, work);
511
512 addrconf_addr_solict_mult(&work->target, &mcaddr);
Erik Nordmarkadc176c2016-12-02 14:00:08 -0800513 ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL, 0);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200514 dev_put(work->dev);
Michael Büsch662f5532015-02-08 10:14:07 +0100515 kfree(work);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200516}
517
David Ahern8d1c8022018-04-17 17:33:26 -0700518static void rt6_probe(struct fib6_info *rt)
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800519{
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700520 struct __rt6_probe_work *work;
David Ahern5e670d82018-04-17 17:33:14 -0700521 const struct in6_addr *nh_gw;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000522 struct neighbour *neigh;
David Ahern5e670d82018-04-17 17:33:14 -0700523 struct net_device *dev;
524
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800525 /*
526 * Okay, this does not seem to be appropriate
527 * for now, however, we need to check if it
528 * is really so; aka Router Reachability Probing.
529 *
530 * Router Reachability Probe MUST be rate-limited
531 * to no more than one per minute.
532 */
David Ahern93c2fb22018-04-18 15:38:59 -0700533 if (!rt || !(rt->fib6_flags & RTF_GATEWAY))
Amerigo Wangfdd66812012-09-10 02:48:44 +0000534 return;
David Ahern5e670d82018-04-17 17:33:14 -0700535
536 nh_gw = &rt->fib6_nh.nh_gw;
537 dev = rt->fib6_nh.nh_dev;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000538 rcu_read_lock_bh();
David Ahern5e670d82018-04-17 17:33:14 -0700539 neigh = __ipv6_neigh_lookup_noref(dev, nh_gw);
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000540 if (neigh) {
David Aherndcd1f572018-04-18 15:39:05 -0700541 struct inet6_dev *idev;
542
Martin KaFai Lau8d6c31b2015-07-24 09:57:43 -0700543 if (neigh->nud_state & NUD_VALID)
544 goto out;
545
David Aherndcd1f572018-04-18 15:39:05 -0700546 idev = __in6_dev_get(dev);
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700547 work = NULL;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000548 write_lock(&neigh->lock);
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700549 if (!(neigh->nud_state & NUD_VALID) &&
550 time_after(jiffies,
David Aherndcd1f572018-04-18 15:39:05 -0700551 neigh->updated + idev->cnf.rtr_probe_interval)) {
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700552 work = kmalloc(sizeof(*work), GFP_ATOMIC);
553 if (work)
554 __neigh_set_probe_once(neigh);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200555 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000556 write_unlock(&neigh->lock);
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700557 } else {
558 work = kmalloc(sizeof(*work), GFP_ATOMIC);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000559 }
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700560
561 if (work) {
562 INIT_WORK(&work->work, rt6_probe_deferred);
David Ahern5e670d82018-04-17 17:33:14 -0700563 work->target = *nh_gw;
564 dev_hold(dev);
565 work->dev = dev;
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700566 schedule_work(&work->work);
567 }
568
Martin KaFai Lau8d6c31b2015-07-24 09:57:43 -0700569out:
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000570 rcu_read_unlock_bh();
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800571}
572#else
David Ahern8d1c8022018-04-17 17:33:26 -0700573static inline void rt6_probe(struct fib6_info *rt)
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800574{
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800575}
576#endif
577
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578/*
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800579 * Default Router Selection (RFC 2461 6.3.6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 */
David Ahern8d1c8022018-04-17 17:33:26 -0700581static inline int rt6_check_dev(struct fib6_info *rt, int oif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582{
David Ahern5e670d82018-04-17 17:33:14 -0700583 const struct net_device *dev = rt->fib6_nh.nh_dev;
584
David S. Miller161980f2007-04-06 11:42:27 -0700585 if (!oif || dev->ifindex == oif)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800586 return 2;
David S. Miller161980f2007-04-06 11:42:27 -0700587 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588}
589
David Ahern8d1c8022018-04-17 17:33:26 -0700590static inline enum rt6_nud_state rt6_check_neigh(struct fib6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591{
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200592 enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
David Ahern5e670d82018-04-17 17:33:14 -0700593 struct neighbour *neigh;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000594
David Ahern93c2fb22018-04-18 15:38:59 -0700595 if (rt->fib6_flags & RTF_NONEXTHOP ||
596 !(rt->fib6_flags & RTF_GATEWAY))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200597 return RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000598
599 rcu_read_lock_bh();
David Ahern5e670d82018-04-17 17:33:14 -0700600 neigh = __ipv6_neigh_lookup_noref(rt->fib6_nh.nh_dev,
601 &rt->fib6_nh.nh_gw);
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000602 if (neigh) {
603 read_lock(&neigh->lock);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800604 if (neigh->nud_state & NUD_VALID)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200605 ret = RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800606#ifdef CONFIG_IPV6_ROUTER_PREF
Paul Marksa5a81f02012-12-03 10:26:54 +0000607 else if (!(neigh->nud_state & NUD_FAILED))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200608 ret = RT6_NUD_SUCCEED;
Jiri Benc7e980562013-12-11 13:48:20 +0100609 else
610 ret = RT6_NUD_FAIL_PROBE;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800611#endif
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000612 read_unlock(&neigh->lock);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200613 } else {
614 ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
Jiri Benc7e980562013-12-11 13:48:20 +0100615 RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR;
Paul Marksa5a81f02012-12-03 10:26:54 +0000616 }
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000617 rcu_read_unlock_bh();
618
Paul Marksa5a81f02012-12-03 10:26:54 +0000619 return ret;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800620}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621
David Ahern8d1c8022018-04-17 17:33:26 -0700622static int rt6_score_route(struct fib6_info *rt, int oif, int strict)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800623{
Paul Marksa5a81f02012-12-03 10:26:54 +0000624 int m;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900625
YOSHIFUJI Hideaki4d0c5912006-05-26 13:23:41 -0700626 m = rt6_check_dev(rt, oif);
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700627 if (!m && (strict & RT6_LOOKUP_F_IFACE))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200628 return RT6_NUD_FAIL_HARD;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800629#ifdef CONFIG_IPV6_ROUTER_PREF
David Ahern93c2fb22018-04-18 15:38:59 -0700630 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->fib6_flags)) << 2;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800631#endif
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200632 if (strict & RT6_LOOKUP_F_REACHABLE) {
633 int n = rt6_check_neigh(rt);
634 if (n < 0)
635 return n;
636 }
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800637 return m;
638}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
David Aherndcd1f572018-04-18 15:39:05 -0700640/* called with rc_read_lock held */
641static inline bool fib6_ignore_linkdown(const struct fib6_info *f6i)
642{
643 const struct net_device *dev = fib6_info_nh_dev(f6i);
644 bool rc = false;
645
646 if (dev) {
647 const struct inet6_dev *idev = __in6_dev_get(dev);
648
649 rc = !!idev->cnf.ignore_routes_with_linkdown;
650 }
651
652 return rc;
653}
654
David Ahern8d1c8022018-04-17 17:33:26 -0700655static struct fib6_info *find_match(struct fib6_info *rt, int oif, int strict,
656 int *mpri, struct fib6_info *match,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200657 bool *do_rr)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800658{
David S. Millerf11e6652007-03-24 20:36:25 -0700659 int m;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200660 bool match_do_rr = false;
Andy Gospodarek35103d12015-08-13 10:39:01 -0400661
David Ahern5e670d82018-04-17 17:33:14 -0700662 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel8067bb82018-01-07 12:45:09 +0200663 goto out;
664
David Aherndcd1f572018-04-18 15:39:05 -0700665 if (fib6_ignore_linkdown(rt) &&
David Ahern5e670d82018-04-17 17:33:14 -0700666 rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN &&
David Ahernd5d32e42016-10-24 12:27:23 -0700667 !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE))
Andy Gospodarek35103d12015-08-13 10:39:01 -0400668 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700669
David Ahern14895682018-04-17 17:33:17 -0700670 if (fib6_check_expired(rt))
David S. Millerf11e6652007-03-24 20:36:25 -0700671 goto out;
672
673 m = rt6_score_route(rt, oif, strict);
Jiri Benc7e980562013-12-11 13:48:20 +0100674 if (m == RT6_NUD_FAIL_DO_RR) {
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200675 match_do_rr = true;
676 m = 0; /* lowest valid score */
Jiri Benc7e980562013-12-11 13:48:20 +0100677 } else if (m == RT6_NUD_FAIL_HARD) {
David S. Millerf11e6652007-03-24 20:36:25 -0700678 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700679 }
680
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200681 if (strict & RT6_LOOKUP_F_REACHABLE)
682 rt6_probe(rt);
683
Jiri Benc7e980562013-12-11 13:48:20 +0100684 /* note that m can be RT6_NUD_FAIL_PROBE at this point */
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200685 if (m > *mpri) {
686 *do_rr = match_do_rr;
687 *mpri = m;
688 match = rt;
689 }
David S. Millerf11e6652007-03-24 20:36:25 -0700690out:
691 return match;
692}
693
David Ahern8d1c8022018-04-17 17:33:26 -0700694static struct fib6_info *find_rr_leaf(struct fib6_node *fn,
695 struct fib6_info *leaf,
696 struct fib6_info *rr_head,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200697 u32 metric, int oif, int strict,
698 bool *do_rr)
David S. Millerf11e6652007-03-24 20:36:25 -0700699{
David Ahern8d1c8022018-04-17 17:33:26 -0700700 struct fib6_info *rt, *match, *cont;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800701 int mpri = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
David S. Millerf11e6652007-03-24 20:36:25 -0700703 match = NULL;
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700704 cont = NULL;
David Ahern8fb11a92018-05-04 13:54:24 -0700705 for (rt = rr_head; rt; rt = rcu_dereference(rt->fib6_next)) {
David Ahern93c2fb22018-04-18 15:38:59 -0700706 if (rt->fib6_metric != metric) {
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700707 cont = rt;
708 break;
709 }
710
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200711 match = find_match(rt, oif, strict, &mpri, match, do_rr);
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700712 }
713
Wei Wang66f5d6c2017-10-06 12:06:10 -0700714 for (rt = leaf; rt && rt != rr_head;
David Ahern8fb11a92018-05-04 13:54:24 -0700715 rt = rcu_dereference(rt->fib6_next)) {
David Ahern93c2fb22018-04-18 15:38:59 -0700716 if (rt->fib6_metric != metric) {
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700717 cont = rt;
718 break;
719 }
720
721 match = find_match(rt, oif, strict, &mpri, match, do_rr);
722 }
723
724 if (match || !cont)
725 return match;
726
David Ahern8fb11a92018-05-04 13:54:24 -0700727 for (rt = cont; rt; rt = rcu_dereference(rt->fib6_next))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200728 match = find_match(rt, oif, strict, &mpri, match, do_rr);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800729
David S. Millerf11e6652007-03-24 20:36:25 -0700730 return match;
731}
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800732
David Ahern8d1c8022018-04-17 17:33:26 -0700733static struct fib6_info *rt6_select(struct net *net, struct fib6_node *fn,
Wei Wang8d1040e2017-10-06 12:06:08 -0700734 int oif, int strict)
David S. Millerf11e6652007-03-24 20:36:25 -0700735{
David Ahern8d1c8022018-04-17 17:33:26 -0700736 struct fib6_info *leaf = rcu_dereference(fn->leaf);
737 struct fib6_info *match, *rt0;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200738 bool do_rr = false;
Wei Wang17ecf592017-10-06 12:06:09 -0700739 int key_plen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740
David Ahern421842e2018-04-17 17:33:18 -0700741 if (!leaf || leaf == net->ipv6.fib6_null_entry)
742 return net->ipv6.fib6_null_entry;
Wei Wang8d1040e2017-10-06 12:06:08 -0700743
Wei Wang66f5d6c2017-10-06 12:06:10 -0700744 rt0 = rcu_dereference(fn->rr_ptr);
David S. Millerf11e6652007-03-24 20:36:25 -0700745 if (!rt0)
Wei Wang66f5d6c2017-10-06 12:06:10 -0700746 rt0 = leaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
Wei Wang17ecf592017-10-06 12:06:09 -0700748 /* Double check to make sure fn is not an intermediate node
749 * and fn->leaf does not points to its child's leaf
750 * (This might happen if all routes under fn are deleted from
751 * the tree and fib6_repair_tree() is called on the node.)
752 */
David Ahern93c2fb22018-04-18 15:38:59 -0700753 key_plen = rt0->fib6_dst.plen;
Wei Wang17ecf592017-10-06 12:06:09 -0700754#ifdef CONFIG_IPV6_SUBTREES
David Ahern93c2fb22018-04-18 15:38:59 -0700755 if (rt0->fib6_src.plen)
756 key_plen = rt0->fib6_src.plen;
Wei Wang17ecf592017-10-06 12:06:09 -0700757#endif
758 if (fn->fn_bit != key_plen)
David Ahern421842e2018-04-17 17:33:18 -0700759 return net->ipv6.fib6_null_entry;
Wei Wang17ecf592017-10-06 12:06:09 -0700760
David Ahern93c2fb22018-04-18 15:38:59 -0700761 match = find_rr_leaf(fn, leaf, rt0, rt0->fib6_metric, oif, strict,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200762 &do_rr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200764 if (do_rr) {
David Ahern8fb11a92018-05-04 13:54:24 -0700765 struct fib6_info *next = rcu_dereference(rt0->fib6_next);
David S. Millerf11e6652007-03-24 20:36:25 -0700766
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800767 /* no entries matched; do round-robin */
David Ahern93c2fb22018-04-18 15:38:59 -0700768 if (!next || next->fib6_metric != rt0->fib6_metric)
Wei Wang8d1040e2017-10-06 12:06:08 -0700769 next = leaf;
David S. Millerf11e6652007-03-24 20:36:25 -0700770
Wei Wang66f5d6c2017-10-06 12:06:10 -0700771 if (next != rt0) {
David Ahern93c2fb22018-04-18 15:38:59 -0700772 spin_lock_bh(&leaf->fib6_table->tb6_lock);
Wei Wang66f5d6c2017-10-06 12:06:10 -0700773 /* make sure next is not being deleted from the tree */
David Ahern93c2fb22018-04-18 15:38:59 -0700774 if (next->fib6_node)
Wei Wang66f5d6c2017-10-06 12:06:10 -0700775 rcu_assign_pointer(fn->rr_ptr, next);
David Ahern93c2fb22018-04-18 15:38:59 -0700776 spin_unlock_bh(&leaf->fib6_table->tb6_lock);
Wei Wang66f5d6c2017-10-06 12:06:10 -0700777 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 }
779
David Ahern421842e2018-04-17 17:33:18 -0700780 return match ? match : net->ipv6.fib6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781}
782
David Ahern8d1c8022018-04-17 17:33:26 -0700783static bool rt6_is_gw_or_nonexthop(const struct fib6_info *rt)
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700784{
David Ahern93c2fb22018-04-18 15:38:59 -0700785 return (rt->fib6_flags & (RTF_NONEXTHOP | RTF_GATEWAY));
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700786}
787
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800788#ifdef CONFIG_IPV6_ROUTE_INFO
789int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000790 const struct in6_addr *gwaddr)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800791{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900792 struct net *net = dev_net(dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800793 struct route_info *rinfo = (struct route_info *) opt;
794 struct in6_addr prefix_buf, *prefix;
795 unsigned int pref;
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900796 unsigned long lifetime;
David Ahern8d1c8022018-04-17 17:33:26 -0700797 struct fib6_info *rt;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800798
799 if (len < sizeof(struct route_info)) {
800 return -EINVAL;
801 }
802
803 /* Sanity check for prefix_len and length */
804 if (rinfo->length > 3) {
805 return -EINVAL;
806 } else if (rinfo->prefix_len > 128) {
807 return -EINVAL;
808 } else if (rinfo->prefix_len > 64) {
809 if (rinfo->length < 2) {
810 return -EINVAL;
811 }
812 } else if (rinfo->prefix_len > 0) {
813 if (rinfo->length < 1) {
814 return -EINVAL;
815 }
816 }
817
818 pref = rinfo->route_pref;
819 if (pref == ICMPV6_ROUTER_PREF_INVALID)
Jens Rosenboom3933fc92009-09-10 06:25:11 +0000820 return -EINVAL;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800821
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900822 lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800823
824 if (rinfo->length == 3)
825 prefix = (struct in6_addr *)rinfo->prefix;
826 else {
827 /* this function is safe */
828 ipv6_addr_prefix(&prefix_buf,
829 (struct in6_addr *)rinfo->prefix,
830 rinfo->prefix_len);
831 prefix = &prefix_buf;
832 }
833
Duan Jiongf104a562013-11-08 09:56:53 +0800834 if (rinfo->prefix_len == 0)
David Ahernafb1d4b52018-04-17 17:33:11 -0700835 rt = rt6_get_dflt_router(net, gwaddr, dev);
Duan Jiongf104a562013-11-08 09:56:53 +0800836 else
837 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len,
David Ahern830218c2016-10-24 10:52:35 -0700838 gwaddr, dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800839
840 if (rt && !lifetime) {
David Ahernafb1d4b52018-04-17 17:33:11 -0700841 ip6_del_rt(net, rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800842 rt = NULL;
843 }
844
845 if (!rt && lifetime)
David Ahern830218c2016-10-24 10:52:35 -0700846 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr,
847 dev, pref);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800848 else if (rt)
David Ahern93c2fb22018-04-18 15:38:59 -0700849 rt->fib6_flags = RTF_ROUTEINFO |
850 (rt->fib6_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800851
852 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +0000853 if (!addrconf_finite_timeout(lifetime))
David Ahern14895682018-04-17 17:33:17 -0700854 fib6_clean_expires(rt);
Gao feng1716a962012-04-06 00:13:10 +0000855 else
David Ahern14895682018-04-17 17:33:17 -0700856 fib6_set_expires(rt, jiffies + HZ * lifetime);
Gao feng1716a962012-04-06 00:13:10 +0000857
David Ahern93531c62018-04-17 17:33:25 -0700858 fib6_info_release(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800859 }
860 return 0;
861}
862#endif
863
David Ahernae90d862018-04-17 17:33:12 -0700864/*
865 * Misc support functions
866 */
867
868/* called with rcu_lock held */
David Ahern8d1c8022018-04-17 17:33:26 -0700869static struct net_device *ip6_rt_get_dev_rcu(struct fib6_info *rt)
David Ahernae90d862018-04-17 17:33:12 -0700870{
David Ahern5e670d82018-04-17 17:33:14 -0700871 struct net_device *dev = rt->fib6_nh.nh_dev;
David Ahernae90d862018-04-17 17:33:12 -0700872
David Ahern93c2fb22018-04-18 15:38:59 -0700873 if (rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) {
David Ahernae90d862018-04-17 17:33:12 -0700874 /* for copies of local routes, dst->dev needs to be the
875 * device if it is a master device, the master device if
876 * device is enslaved, and the loopback as the default
877 */
878 if (netif_is_l3_slave(dev) &&
David Ahern93c2fb22018-04-18 15:38:59 -0700879 !rt6_need_strict(&rt->fib6_dst.addr))
David Ahernae90d862018-04-17 17:33:12 -0700880 dev = l3mdev_master_dev_rcu(dev);
881 else if (!netif_is_l3_master(dev))
882 dev = dev_net(dev)->loopback_dev;
883 /* last case is netif_is_l3_master(dev) is true in which
884 * case we want dev returned to be dev
885 */
886 }
887
888 return dev;
889}
890
David Ahern6edb3c92018-04-17 17:33:15 -0700891static const int fib6_prop[RTN_MAX + 1] = {
892 [RTN_UNSPEC] = 0,
893 [RTN_UNICAST] = 0,
894 [RTN_LOCAL] = 0,
895 [RTN_BROADCAST] = 0,
896 [RTN_ANYCAST] = 0,
897 [RTN_MULTICAST] = 0,
898 [RTN_BLACKHOLE] = -EINVAL,
899 [RTN_UNREACHABLE] = -EHOSTUNREACH,
900 [RTN_PROHIBIT] = -EACCES,
901 [RTN_THROW] = -EAGAIN,
902 [RTN_NAT] = -EINVAL,
903 [RTN_XRESOLVE] = -EINVAL,
904};
905
906static int ip6_rt_type_to_error(u8 fib6_type)
907{
908 return fib6_prop[fib6_type];
909}
910
David Ahern8d1c8022018-04-17 17:33:26 -0700911static unsigned short fib6_info_dst_flags(struct fib6_info *rt)
David Ahern3b6761d2018-04-17 17:33:20 -0700912{
913 unsigned short flags = 0;
914
915 if (rt->dst_nocount)
916 flags |= DST_NOCOUNT;
917 if (rt->dst_nopolicy)
918 flags |= DST_NOPOLICY;
919 if (rt->dst_host)
920 flags |= DST_HOST;
921
922 return flags;
923}
924
David Ahern8d1c8022018-04-17 17:33:26 -0700925static void ip6_rt_init_dst_reject(struct rt6_info *rt, struct fib6_info *ort)
David Ahern6edb3c92018-04-17 17:33:15 -0700926{
927 rt->dst.error = ip6_rt_type_to_error(ort->fib6_type);
928
929 switch (ort->fib6_type) {
930 case RTN_BLACKHOLE:
931 rt->dst.output = dst_discard_out;
932 rt->dst.input = dst_discard;
933 break;
934 case RTN_PROHIBIT:
935 rt->dst.output = ip6_pkt_prohibit_out;
936 rt->dst.input = ip6_pkt_prohibit;
937 break;
938 case RTN_THROW:
939 case RTN_UNREACHABLE:
940 default:
941 rt->dst.output = ip6_pkt_discard_out;
942 rt->dst.input = ip6_pkt_discard;
943 break;
944 }
945}
946
David Ahern8d1c8022018-04-17 17:33:26 -0700947static void ip6_rt_init_dst(struct rt6_info *rt, struct fib6_info *ort)
David Ahern6edb3c92018-04-17 17:33:15 -0700948{
David Ahern3b6761d2018-04-17 17:33:20 -0700949 rt->dst.flags |= fib6_info_dst_flags(ort);
950
David Ahern93c2fb22018-04-18 15:38:59 -0700951 if (ort->fib6_flags & RTF_REJECT) {
David Ahern6edb3c92018-04-17 17:33:15 -0700952 ip6_rt_init_dst_reject(rt, ort);
953 return;
954 }
955
956 rt->dst.error = 0;
957 rt->dst.output = ip6_output;
958
959 if (ort->fib6_type == RTN_LOCAL) {
David Ahern6edb3c92018-04-17 17:33:15 -0700960 rt->dst.input = ip6_input;
David Ahern93c2fb22018-04-18 15:38:59 -0700961 } else if (ipv6_addr_type(&ort->fib6_dst.addr) & IPV6_ADDR_MULTICAST) {
David Ahern6edb3c92018-04-17 17:33:15 -0700962 rt->dst.input = ip6_mc_input;
963 } else {
964 rt->dst.input = ip6_forward;
965 }
966
967 if (ort->fib6_nh.nh_lwtstate) {
968 rt->dst.lwtstate = lwtstate_get(ort->fib6_nh.nh_lwtstate);
969 lwtunnel_set_redirect(&rt->dst);
970 }
971
972 rt->dst.lastuse = jiffies;
973}
974
David Ahern8d1c8022018-04-17 17:33:26 -0700975static void rt6_set_from(struct rt6_info *rt, struct fib6_info *from)
David Ahernae90d862018-04-17 17:33:12 -0700976{
David Ahernae90d862018-04-17 17:33:12 -0700977 rt->rt6i_flags &= ~RTF_EXPIRES;
David Ahern93531c62018-04-17 17:33:25 -0700978 fib6_info_hold(from);
David Aherna68886a2018-04-20 15:38:02 -0700979 rcu_assign_pointer(rt->from, from);
David Ahernd4ead6b2018-04-17 17:33:16 -0700980 dst_init_metrics(&rt->dst, from->fib6_metrics->metrics, true);
981 if (from->fib6_metrics != &dst_default_metrics) {
982 rt->dst._metrics |= DST_METRICS_REFCOUNTED;
983 refcount_inc(&from->fib6_metrics->refcnt);
984 }
David Ahernae90d862018-04-17 17:33:12 -0700985}
986
David Ahern8d1c8022018-04-17 17:33:26 -0700987static void ip6_rt_copy_init(struct rt6_info *rt, struct fib6_info *ort)
David Ahernae90d862018-04-17 17:33:12 -0700988{
David Aherndcd1f572018-04-18 15:39:05 -0700989 struct net_device *dev = fib6_info_nh_dev(ort);
990
David Ahern6edb3c92018-04-17 17:33:15 -0700991 ip6_rt_init_dst(rt, ort);
992
David Ahern93c2fb22018-04-18 15:38:59 -0700993 rt->rt6i_dst = ort->fib6_dst;
David Aherndcd1f572018-04-18 15:39:05 -0700994 rt->rt6i_idev = dev ? in6_dev_get(dev) : NULL;
David Ahern5e670d82018-04-17 17:33:14 -0700995 rt->rt6i_gateway = ort->fib6_nh.nh_gw;
David Ahern93c2fb22018-04-18 15:38:59 -0700996 rt->rt6i_flags = ort->fib6_flags;
David Ahernae90d862018-04-17 17:33:12 -0700997 rt6_set_from(rt, ort);
David Ahernae90d862018-04-17 17:33:12 -0700998#ifdef CONFIG_IPV6_SUBTREES
David Ahern93c2fb22018-04-18 15:38:59 -0700999 rt->rt6i_src = ort->fib6_src;
David Ahernae90d862018-04-17 17:33:12 -07001000#endif
David Ahern93c2fb22018-04-18 15:38:59 -07001001 rt->rt6i_prefsrc = ort->fib6_prefsrc;
David Ahern5e670d82018-04-17 17:33:14 -07001002 rt->dst.lwtstate = lwtstate_get(ort->fib6_nh.nh_lwtstate);
David Ahernae90d862018-04-17 17:33:12 -07001003}
1004
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001005static struct fib6_node* fib6_backtrack(struct fib6_node *fn,
1006 struct in6_addr *saddr)
1007{
Wei Wang66f5d6c2017-10-06 12:06:10 -07001008 struct fib6_node *pn, *sn;
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001009 while (1) {
1010 if (fn->fn_flags & RTN_TL_ROOT)
1011 return NULL;
Wei Wang66f5d6c2017-10-06 12:06:10 -07001012 pn = rcu_dereference(fn->parent);
1013 sn = FIB6_SUBTREE(pn);
1014 if (sn && sn != fn)
David Ahern64547432018-05-09 20:34:19 -07001015 fn = fib6_node_lookup(sn, NULL, saddr);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001016 else
1017 fn = pn;
1018 if (fn->fn_flags & RTN_RTINFO)
1019 return fn;
1020 }
1021}
Thomas Grafc71099a2006-08-04 23:20:06 -07001022
Wei Wangd3843fe2017-10-06 12:06:06 -07001023static bool ip6_hold_safe(struct net *net, struct rt6_info **prt,
1024 bool null_fallback)
1025{
1026 struct rt6_info *rt = *prt;
1027
1028 if (dst_hold_safe(&rt->dst))
1029 return true;
1030 if (null_fallback) {
1031 rt = net->ipv6.ip6_null_entry;
1032 dst_hold(&rt->dst);
1033 } else {
1034 rt = NULL;
1035 }
1036 *prt = rt;
1037 return false;
1038}
1039
David Aherndec9b0e2018-04-17 17:33:19 -07001040/* called with rcu_lock held */
David Ahern8d1c8022018-04-17 17:33:26 -07001041static struct rt6_info *ip6_create_rt_rcu(struct fib6_info *rt)
David Aherndec9b0e2018-04-17 17:33:19 -07001042{
David Ahern3b6761d2018-04-17 17:33:20 -07001043 unsigned short flags = fib6_info_dst_flags(rt);
David Aherndec9b0e2018-04-17 17:33:19 -07001044 struct net_device *dev = rt->fib6_nh.nh_dev;
1045 struct rt6_info *nrt;
1046
David Ahern93531c62018-04-17 17:33:25 -07001047 nrt = ip6_dst_alloc(dev_net(dev), dev, flags);
David Aherndec9b0e2018-04-17 17:33:19 -07001048 if (nrt)
1049 ip6_rt_copy_init(nrt, rt);
1050
1051 return nrt;
1052}
1053
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001054static struct rt6_info *ip6_pol_route_lookup(struct net *net,
1055 struct fib6_table *table,
David Ahernb75cc8f2018-03-02 08:32:17 -08001056 struct flowi6 *fl6,
1057 const struct sk_buff *skb,
1058 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059{
David Ahern8d1c8022018-04-17 17:33:26 -07001060 struct fib6_info *f6i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 struct fib6_node *fn;
David Ahern23fb93a2018-04-17 17:33:23 -07001062 struct rt6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063
David Ahernb6cdbc82018-03-29 17:44:57 -07001064 if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
1065 flags &= ~RT6_LOOKUP_F_IFACE;
1066
Wei Wang66f5d6c2017-10-06 12:06:10 -07001067 rcu_read_lock();
David Ahern64547432018-05-09 20:34:19 -07001068 fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -07001069restart:
David Ahern23fb93a2018-04-17 17:33:23 -07001070 f6i = rcu_dereference(fn->leaf);
1071 if (!f6i) {
1072 f6i = net->ipv6.fib6_null_entry;
Wei Wang66f5d6c2017-10-06 12:06:10 -07001073 } else {
David Ahern23fb93a2018-04-17 17:33:23 -07001074 f6i = rt6_device_match(net, f6i, &fl6->saddr,
Wei Wang66f5d6c2017-10-06 12:06:10 -07001075 fl6->flowi6_oif, flags);
David Ahern93c2fb22018-04-18 15:38:59 -07001076 if (f6i->fib6_nsiblings && fl6->flowi6_oif == 0)
David Ahern3b290a32018-05-09 20:34:20 -07001077 f6i = fib6_multipath_select(net, f6i, fl6,
1078 fl6->flowi6_oif, skb,
1079 flags);
Wei Wang66f5d6c2017-10-06 12:06:10 -07001080 }
David Ahern23fb93a2018-04-17 17:33:23 -07001081 if (f6i == net->ipv6.fib6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001082 fn = fib6_backtrack(fn, &fl6->saddr);
1083 if (fn)
1084 goto restart;
1085 }
Wei Wang2b760fc2017-10-06 12:06:03 -07001086
David Ahernd4bea422018-05-09 20:34:24 -07001087 trace_fib6_table_lookup(net, f6i, table, fl6);
1088
David S. Miller4c9483b2011-03-12 16:22:43 -05001089 /* Search through exception table */
David Ahern23fb93a2018-04-17 17:33:23 -07001090 rt = rt6_find_cached_rt(f6i, &fl6->daddr, &fl6->saddr);
1091 if (rt) {
David Aherndec9b0e2018-04-17 17:33:19 -07001092 if (ip6_hold_safe(net, &rt, true))
1093 dst_use_noref(&rt->dst, jiffies);
David Ahern23fb93a2018-04-17 17:33:23 -07001094 } else if (f6i == net->ipv6.fib6_null_entry) {
David Aherndec9b0e2018-04-17 17:33:19 -07001095 rt = net->ipv6.ip6_null_entry;
1096 dst_hold(&rt->dst);
David Ahern23fb93a2018-04-17 17:33:23 -07001097 } else {
1098 rt = ip6_create_rt_rcu(f6i);
1099 if (!rt) {
1100 rt = net->ipv6.ip6_null_entry;
1101 dst_hold(&rt->dst);
1102 }
David Aherndec9b0e2018-04-17 17:33:19 -07001103 }
Wei Wangd3843fe2017-10-06 12:06:06 -07001104
Wei Wang66f5d6c2017-10-06 12:06:10 -07001105 rcu_read_unlock();
David Ahernb8115802015-11-19 12:24:22 -08001106
Thomas Grafc71099a2006-08-04 23:20:06 -07001107 return rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001108}
1109
Ian Morris67ba4152014-08-24 21:53:10 +01001110struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
David Ahernb75cc8f2018-03-02 08:32:17 -08001111 const struct sk_buff *skb, int flags)
Florian Westphalea6e5742011-09-05 16:05:44 +02001112{
David Ahernb75cc8f2018-03-02 08:32:17 -08001113 return fib6_rule_lookup(net, fl6, skb, flags, ip6_pol_route_lookup);
Florian Westphalea6e5742011-09-05 16:05:44 +02001114}
1115EXPORT_SYMBOL_GPL(ip6_route_lookup);
1116
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +09001117struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
David Ahernb75cc8f2018-03-02 08:32:17 -08001118 const struct in6_addr *saddr, int oif,
1119 const struct sk_buff *skb, int strict)
Thomas Grafc71099a2006-08-04 23:20:06 -07001120{
David S. Miller4c9483b2011-03-12 16:22:43 -05001121 struct flowi6 fl6 = {
1122 .flowi6_oif = oif,
1123 .daddr = *daddr,
Thomas Grafc71099a2006-08-04 23:20:06 -07001124 };
1125 struct dst_entry *dst;
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001126 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07001127
Thomas Grafadaa70b2006-10-13 15:01:03 -07001128 if (saddr) {
David S. Miller4c9483b2011-03-12 16:22:43 -05001129 memcpy(&fl6.saddr, saddr, sizeof(*saddr));
Thomas Grafadaa70b2006-10-13 15:01:03 -07001130 flags |= RT6_LOOKUP_F_HAS_SADDR;
1131 }
1132
David Ahernb75cc8f2018-03-02 08:32:17 -08001133 dst = fib6_rule_lookup(net, &fl6, skb, flags, ip6_pol_route_lookup);
Thomas Grafc71099a2006-08-04 23:20:06 -07001134 if (dst->error == 0)
1135 return (struct rt6_info *) dst;
1136
1137 dst_release(dst);
1138
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 return NULL;
1140}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +09001141EXPORT_SYMBOL(rt6_lookup);
1142
Thomas Grafc71099a2006-08-04 23:20:06 -07001143/* ip6_ins_rt is called with FREE table->tb6_lock.
Wei Wang1cfb71e2017-06-17 10:42:33 -07001144 * It takes new route entry, the addition fails by any reason the
1145 * route is released.
1146 * Caller must hold dst before calling it.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 */
1148
David Ahern8d1c8022018-04-17 17:33:26 -07001149static int __ip6_ins_rt(struct fib6_info *rt, struct nl_info *info,
David Ahern333c4302017-05-21 10:12:04 -06001150 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151{
1152 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07001153 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154
David Ahern93c2fb22018-04-18 15:38:59 -07001155 table = rt->fib6_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07001156 spin_lock_bh(&table->tb6_lock);
David Ahernd4ead6b2018-04-17 17:33:16 -07001157 err = fib6_add(&table->tb6_root, rt, info, extack);
Wei Wang66f5d6c2017-10-06 12:06:10 -07001158 spin_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159
1160 return err;
1161}
1162
David Ahern8d1c8022018-04-17 17:33:26 -07001163int ip6_ins_rt(struct net *net, struct fib6_info *rt)
Thomas Graf40e22e82006-08-22 00:00:45 -07001164{
David Ahernafb1d4b52018-04-17 17:33:11 -07001165 struct nl_info info = { .nl_net = net, };
Florian Westphale715b6d2015-01-05 23:57:44 +01001166
David Ahernd4ead6b2018-04-17 17:33:16 -07001167 return __ip6_ins_rt(rt, &info, NULL);
Thomas Graf40e22e82006-08-22 00:00:45 -07001168}
1169
David Ahern8d1c8022018-04-17 17:33:26 -07001170static struct rt6_info *ip6_rt_cache_alloc(struct fib6_info *ort,
Martin KaFai Lau8b9df262015-05-22 20:55:59 -07001171 const struct in6_addr *daddr,
1172 const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173{
David Ahern4832c302017-08-17 12:17:20 -07001174 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 struct rt6_info *rt;
1176
1177 /*
1178 * Clone the route.
1179 */
1180
David Ahern4832c302017-08-17 12:17:20 -07001181 dev = ip6_rt_get_dev_rcu(ort);
David Ahern93531c62018-04-17 17:33:25 -07001182 rt = ip6_dst_alloc(dev_net(dev), dev, 0);
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001183 if (!rt)
1184 return NULL;
1185
1186 ip6_rt_copy_init(rt, ort);
1187 rt->rt6i_flags |= RTF_CACHE;
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001188 rt->dst.flags |= DST_HOST;
1189 rt->rt6i_dst.addr = *daddr;
1190 rt->rt6i_dst.plen = 128;
1191
1192 if (!rt6_is_gw_or_nonexthop(ort)) {
David Ahern93c2fb22018-04-18 15:38:59 -07001193 if (ort->fib6_dst.plen != 128 &&
1194 ipv6_addr_equal(&ort->fib6_dst.addr, daddr))
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001195 rt->rt6i_flags |= RTF_ANYCAST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001197 if (rt->rt6i_src.plen && saddr) {
1198 rt->rt6i_src.addr = *saddr;
1199 rt->rt6i_src.plen = 128;
Martin KaFai Lau8b9df262015-05-22 20:55:59 -07001200 }
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001201#endif
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -08001202 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -08001204 return rt;
1205}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206
David Ahern8d1c8022018-04-17 17:33:26 -07001207static struct rt6_info *ip6_rt_pcpu_alloc(struct fib6_info *rt)
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001208{
David Ahern3b6761d2018-04-17 17:33:20 -07001209 unsigned short flags = fib6_info_dst_flags(rt);
David Ahern4832c302017-08-17 12:17:20 -07001210 struct net_device *dev;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001211 struct rt6_info *pcpu_rt;
1212
David Ahern4832c302017-08-17 12:17:20 -07001213 rcu_read_lock();
1214 dev = ip6_rt_get_dev_rcu(rt);
David Ahern93531c62018-04-17 17:33:25 -07001215 pcpu_rt = ip6_dst_alloc(dev_net(dev), dev, flags);
David Ahern4832c302017-08-17 12:17:20 -07001216 rcu_read_unlock();
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001217 if (!pcpu_rt)
1218 return NULL;
1219 ip6_rt_copy_init(pcpu_rt, rt);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001220 pcpu_rt->rt6i_flags |= RTF_PCPU;
1221 return pcpu_rt;
1222}
1223
Wei Wang66f5d6c2017-10-06 12:06:10 -07001224/* It should be called with rcu_read_lock() acquired */
David Ahern8d1c8022018-04-17 17:33:26 -07001225static struct rt6_info *rt6_get_pcpu_route(struct fib6_info *rt)
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001226{
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001227 struct rt6_info *pcpu_rt, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001228
1229 p = this_cpu_ptr(rt->rt6i_pcpu);
1230 pcpu_rt = *p;
1231
David Ahernd4ead6b2018-04-17 17:33:16 -07001232 if (pcpu_rt)
1233 ip6_hold_safe(NULL, &pcpu_rt, false);
Wei Wangd3843fe2017-10-06 12:06:06 -07001234
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001235 return pcpu_rt;
1236}
1237
David Ahernafb1d4b52018-04-17 17:33:11 -07001238static struct rt6_info *rt6_make_pcpu_route(struct net *net,
David Ahern8d1c8022018-04-17 17:33:26 -07001239 struct fib6_info *rt)
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001240{
1241 struct rt6_info *pcpu_rt, *prev, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001242
1243 pcpu_rt = ip6_rt_pcpu_alloc(rt);
1244 if (!pcpu_rt) {
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001245 dst_hold(&net->ipv6.ip6_null_entry->dst);
1246 return net->ipv6.ip6_null_entry;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001247 }
1248
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001249 dst_hold(&pcpu_rt->dst);
Wei Wanga94b9362017-10-06 12:06:04 -07001250 p = this_cpu_ptr(rt->rt6i_pcpu);
1251 prev = cmpxchg(p, NULL, pcpu_rt);
Eric Dumazet951f7882017-10-08 21:07:18 -07001252 BUG_ON(prev);
Wei Wanga94b9362017-10-06 12:06:04 -07001253
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001254 return pcpu_rt;
1255}
1256
Wei Wang35732d02017-10-06 12:05:57 -07001257/* exception hash table implementation
1258 */
1259static DEFINE_SPINLOCK(rt6_exception_lock);
1260
1261/* Remove rt6_ex from hash table and free the memory
1262 * Caller must hold rt6_exception_lock
1263 */
1264static void rt6_remove_exception(struct rt6_exception_bucket *bucket,
1265 struct rt6_exception *rt6_ex)
1266{
Colin Ian Kingb2427e62017-10-10 18:01:16 +01001267 struct net *net;
Wei Wang81eb8442017-10-06 12:06:11 -07001268
Wei Wang35732d02017-10-06 12:05:57 -07001269 if (!bucket || !rt6_ex)
1270 return;
Colin Ian Kingb2427e62017-10-10 18:01:16 +01001271
1272 net = dev_net(rt6_ex->rt6i->dst.dev);
Wei Wang35732d02017-10-06 12:05:57 -07001273 hlist_del_rcu(&rt6_ex->hlist);
David Ahern77634cc2018-04-17 17:33:27 -07001274 dst_release(&rt6_ex->rt6i->dst);
Wei Wang35732d02017-10-06 12:05:57 -07001275 kfree_rcu(rt6_ex, rcu);
1276 WARN_ON_ONCE(!bucket->depth);
1277 bucket->depth--;
Wei Wang81eb8442017-10-06 12:06:11 -07001278 net->ipv6.rt6_stats->fib_rt_cache--;
Wei Wang35732d02017-10-06 12:05:57 -07001279}
1280
1281/* Remove oldest rt6_ex in bucket and free the memory
1282 * Caller must hold rt6_exception_lock
1283 */
1284static void rt6_exception_remove_oldest(struct rt6_exception_bucket *bucket)
1285{
1286 struct rt6_exception *rt6_ex, *oldest = NULL;
1287
1288 if (!bucket)
1289 return;
1290
1291 hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
1292 if (!oldest || time_before(rt6_ex->stamp, oldest->stamp))
1293 oldest = rt6_ex;
1294 }
1295 rt6_remove_exception(bucket, oldest);
1296}
1297
1298static u32 rt6_exception_hash(const struct in6_addr *dst,
1299 const struct in6_addr *src)
1300{
1301 static u32 seed __read_mostly;
1302 u32 val;
1303
1304 net_get_random_once(&seed, sizeof(seed));
1305 val = jhash(dst, sizeof(*dst), seed);
1306
1307#ifdef CONFIG_IPV6_SUBTREES
1308 if (src)
1309 val = jhash(src, sizeof(*src), val);
1310#endif
1311 return hash_32(val, FIB6_EXCEPTION_BUCKET_SIZE_SHIFT);
1312}
1313
1314/* Helper function to find the cached rt in the hash table
1315 * and update bucket pointer to point to the bucket for this
1316 * (daddr, saddr) pair
1317 * Caller must hold rt6_exception_lock
1318 */
1319static struct rt6_exception *
1320__rt6_find_exception_spinlock(struct rt6_exception_bucket **bucket,
1321 const struct in6_addr *daddr,
1322 const struct in6_addr *saddr)
1323{
1324 struct rt6_exception *rt6_ex;
1325 u32 hval;
1326
1327 if (!(*bucket) || !daddr)
1328 return NULL;
1329
1330 hval = rt6_exception_hash(daddr, saddr);
1331 *bucket += hval;
1332
1333 hlist_for_each_entry(rt6_ex, &(*bucket)->chain, hlist) {
1334 struct rt6_info *rt6 = rt6_ex->rt6i;
1335 bool matched = ipv6_addr_equal(daddr, &rt6->rt6i_dst.addr);
1336
1337#ifdef CONFIG_IPV6_SUBTREES
1338 if (matched && saddr)
1339 matched = ipv6_addr_equal(saddr, &rt6->rt6i_src.addr);
1340#endif
1341 if (matched)
1342 return rt6_ex;
1343 }
1344 return NULL;
1345}
1346
1347/* Helper function to find the cached rt in the hash table
1348 * and update bucket pointer to point to the bucket for this
1349 * (daddr, saddr) pair
1350 * Caller must hold rcu_read_lock()
1351 */
1352static struct rt6_exception *
1353__rt6_find_exception_rcu(struct rt6_exception_bucket **bucket,
1354 const struct in6_addr *daddr,
1355 const struct in6_addr *saddr)
1356{
1357 struct rt6_exception *rt6_ex;
1358 u32 hval;
1359
1360 WARN_ON_ONCE(!rcu_read_lock_held());
1361
1362 if (!(*bucket) || !daddr)
1363 return NULL;
1364
1365 hval = rt6_exception_hash(daddr, saddr);
1366 *bucket += hval;
1367
1368 hlist_for_each_entry_rcu(rt6_ex, &(*bucket)->chain, hlist) {
1369 struct rt6_info *rt6 = rt6_ex->rt6i;
1370 bool matched = ipv6_addr_equal(daddr, &rt6->rt6i_dst.addr);
1371
1372#ifdef CONFIG_IPV6_SUBTREES
1373 if (matched && saddr)
1374 matched = ipv6_addr_equal(saddr, &rt6->rt6i_src.addr);
1375#endif
1376 if (matched)
1377 return rt6_ex;
1378 }
1379 return NULL;
1380}
1381
David Ahern8d1c8022018-04-17 17:33:26 -07001382static unsigned int fib6_mtu(const struct fib6_info *rt)
Wei Wang35732d02017-10-06 12:05:57 -07001383{
David Ahernd4ead6b2018-04-17 17:33:16 -07001384 unsigned int mtu;
1385
David Aherndcd1f572018-04-18 15:39:05 -07001386 if (rt->fib6_pmtu) {
1387 mtu = rt->fib6_pmtu;
1388 } else {
1389 struct net_device *dev = fib6_info_nh_dev(rt);
1390 struct inet6_dev *idev;
1391
1392 rcu_read_lock();
1393 idev = __in6_dev_get(dev);
1394 mtu = idev->cnf.mtu6;
1395 rcu_read_unlock();
1396 }
1397
David Ahernd4ead6b2018-04-17 17:33:16 -07001398 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
1399
1400 return mtu - lwtunnel_headroom(rt->fib6_nh.nh_lwtstate, mtu);
1401}
1402
Wei Wang35732d02017-10-06 12:05:57 -07001403static int rt6_insert_exception(struct rt6_info *nrt,
David Ahern8d1c8022018-04-17 17:33:26 -07001404 struct fib6_info *ort)
Wei Wang35732d02017-10-06 12:05:57 -07001405{
David Ahern5e670d82018-04-17 17:33:14 -07001406 struct net *net = dev_net(nrt->dst.dev);
Wei Wang35732d02017-10-06 12:05:57 -07001407 struct rt6_exception_bucket *bucket;
1408 struct in6_addr *src_key = NULL;
1409 struct rt6_exception *rt6_ex;
1410 int err = 0;
1411
Wei Wang35732d02017-10-06 12:05:57 -07001412 spin_lock_bh(&rt6_exception_lock);
1413
1414 if (ort->exception_bucket_flushed) {
1415 err = -EINVAL;
1416 goto out;
1417 }
1418
1419 bucket = rcu_dereference_protected(ort->rt6i_exception_bucket,
1420 lockdep_is_held(&rt6_exception_lock));
1421 if (!bucket) {
1422 bucket = kcalloc(FIB6_EXCEPTION_BUCKET_SIZE, sizeof(*bucket),
1423 GFP_ATOMIC);
1424 if (!bucket) {
1425 err = -ENOMEM;
1426 goto out;
1427 }
1428 rcu_assign_pointer(ort->rt6i_exception_bucket, bucket);
1429 }
1430
1431#ifdef CONFIG_IPV6_SUBTREES
1432 /* rt6i_src.plen != 0 indicates ort is in subtree
1433 * and exception table is indexed by a hash of
1434 * both rt6i_dst and rt6i_src.
1435 * Otherwise, the exception table is indexed by
1436 * a hash of only rt6i_dst.
1437 */
David Ahern93c2fb22018-04-18 15:38:59 -07001438 if (ort->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001439 src_key = &nrt->rt6i_src.addr;
1440#endif
Wei Wang60006a42017-10-06 12:05:58 -07001441
1442 /* Update rt6i_prefsrc as it could be changed
1443 * in rt6_remove_prefsrc()
1444 */
David Ahern93c2fb22018-04-18 15:38:59 -07001445 nrt->rt6i_prefsrc = ort->fib6_prefsrc;
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001446 /* rt6_mtu_change() might lower mtu on ort.
1447 * Only insert this exception route if its mtu
1448 * is less than ort's mtu value.
1449 */
David Ahernd4ead6b2018-04-17 17:33:16 -07001450 if (dst_metric_raw(&nrt->dst, RTAX_MTU) >= fib6_mtu(ort)) {
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001451 err = -EINVAL;
1452 goto out;
1453 }
Wei Wang60006a42017-10-06 12:05:58 -07001454
Wei Wang35732d02017-10-06 12:05:57 -07001455 rt6_ex = __rt6_find_exception_spinlock(&bucket, &nrt->rt6i_dst.addr,
1456 src_key);
1457 if (rt6_ex)
1458 rt6_remove_exception(bucket, rt6_ex);
1459
1460 rt6_ex = kzalloc(sizeof(*rt6_ex), GFP_ATOMIC);
1461 if (!rt6_ex) {
1462 err = -ENOMEM;
1463 goto out;
1464 }
1465 rt6_ex->rt6i = nrt;
1466 rt6_ex->stamp = jiffies;
Wei Wang35732d02017-10-06 12:05:57 -07001467 hlist_add_head_rcu(&rt6_ex->hlist, &bucket->chain);
1468 bucket->depth++;
Wei Wang81eb8442017-10-06 12:06:11 -07001469 net->ipv6.rt6_stats->fib_rt_cache++;
Wei Wang35732d02017-10-06 12:05:57 -07001470
1471 if (bucket->depth > FIB6_MAX_DEPTH)
1472 rt6_exception_remove_oldest(bucket);
1473
1474out:
1475 spin_unlock_bh(&rt6_exception_lock);
1476
1477 /* Update fn->fn_sernum to invalidate all cached dst */
Paolo Abenib886d5f2017-10-19 16:07:10 +02001478 if (!err) {
David Ahern93c2fb22018-04-18 15:38:59 -07001479 spin_lock_bh(&ort->fib6_table->tb6_lock);
David Ahern7aef6852018-04-17 17:33:10 -07001480 fib6_update_sernum(net, ort);
David Ahern93c2fb22018-04-18 15:38:59 -07001481 spin_unlock_bh(&ort->fib6_table->tb6_lock);
Paolo Abenib886d5f2017-10-19 16:07:10 +02001482 fib6_force_start_gc(net);
1483 }
Wei Wang35732d02017-10-06 12:05:57 -07001484
1485 return err;
1486}
1487
David Ahern8d1c8022018-04-17 17:33:26 -07001488void rt6_flush_exceptions(struct fib6_info *rt)
Wei Wang35732d02017-10-06 12:05:57 -07001489{
1490 struct rt6_exception_bucket *bucket;
1491 struct rt6_exception *rt6_ex;
1492 struct hlist_node *tmp;
1493 int i;
1494
1495 spin_lock_bh(&rt6_exception_lock);
1496 /* Prevent rt6_insert_exception() to recreate the bucket list */
1497 rt->exception_bucket_flushed = 1;
1498
1499 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1500 lockdep_is_held(&rt6_exception_lock));
1501 if (!bucket)
1502 goto out;
1503
1504 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1505 hlist_for_each_entry_safe(rt6_ex, tmp, &bucket->chain, hlist)
1506 rt6_remove_exception(bucket, rt6_ex);
1507 WARN_ON_ONCE(bucket->depth);
1508 bucket++;
1509 }
1510
1511out:
1512 spin_unlock_bh(&rt6_exception_lock);
1513}
1514
1515/* Find cached rt in the hash table inside passed in rt
1516 * Caller has to hold rcu_read_lock()
1517 */
David Ahern8d1c8022018-04-17 17:33:26 -07001518static struct rt6_info *rt6_find_cached_rt(struct fib6_info *rt,
Wei Wang35732d02017-10-06 12:05:57 -07001519 struct in6_addr *daddr,
1520 struct in6_addr *saddr)
1521{
1522 struct rt6_exception_bucket *bucket;
1523 struct in6_addr *src_key = NULL;
1524 struct rt6_exception *rt6_ex;
1525 struct rt6_info *res = NULL;
1526
1527 bucket = rcu_dereference(rt->rt6i_exception_bucket);
1528
1529#ifdef CONFIG_IPV6_SUBTREES
1530 /* rt6i_src.plen != 0 indicates rt is in subtree
1531 * and exception table is indexed by a hash of
1532 * both rt6i_dst and rt6i_src.
1533 * Otherwise, the exception table is indexed by
1534 * a hash of only rt6i_dst.
1535 */
David Ahern93c2fb22018-04-18 15:38:59 -07001536 if (rt->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001537 src_key = saddr;
1538#endif
1539 rt6_ex = __rt6_find_exception_rcu(&bucket, daddr, src_key);
1540
1541 if (rt6_ex && !rt6_check_expired(rt6_ex->rt6i))
1542 res = rt6_ex->rt6i;
1543
1544 return res;
1545}
1546
1547/* Remove the passed in cached rt from the hash table that contains it */
David Ahern23fb93a2018-04-17 17:33:23 -07001548static int rt6_remove_exception_rt(struct rt6_info *rt)
Wei Wang35732d02017-10-06 12:05:57 -07001549{
Wei Wang35732d02017-10-06 12:05:57 -07001550 struct rt6_exception_bucket *bucket;
1551 struct in6_addr *src_key = NULL;
1552 struct rt6_exception *rt6_ex;
David Ahern8a14e462018-04-23 11:32:07 -07001553 struct fib6_info *from;
Wei Wang35732d02017-10-06 12:05:57 -07001554 int err;
1555
Eric Dumazet091311d2018-04-24 09:22:49 -07001556 from = rcu_dereference(rt->from);
Wei Wang35732d02017-10-06 12:05:57 -07001557 if (!from ||
Colin Ian King442d7132017-10-10 19:10:30 +01001558 !(rt->rt6i_flags & RTF_CACHE))
Wei Wang35732d02017-10-06 12:05:57 -07001559 return -EINVAL;
1560
1561 if (!rcu_access_pointer(from->rt6i_exception_bucket))
1562 return -ENOENT;
1563
1564 spin_lock_bh(&rt6_exception_lock);
1565 bucket = rcu_dereference_protected(from->rt6i_exception_bucket,
1566 lockdep_is_held(&rt6_exception_lock));
1567#ifdef CONFIG_IPV6_SUBTREES
1568 /* rt6i_src.plen != 0 indicates 'from' is in subtree
1569 * and exception table is indexed by a hash of
1570 * both rt6i_dst and rt6i_src.
1571 * Otherwise, the exception table is indexed by
1572 * a hash of only rt6i_dst.
1573 */
David Ahern93c2fb22018-04-18 15:38:59 -07001574 if (from->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001575 src_key = &rt->rt6i_src.addr;
1576#endif
1577 rt6_ex = __rt6_find_exception_spinlock(&bucket,
1578 &rt->rt6i_dst.addr,
1579 src_key);
1580 if (rt6_ex) {
1581 rt6_remove_exception(bucket, rt6_ex);
1582 err = 0;
1583 } else {
1584 err = -ENOENT;
1585 }
1586
1587 spin_unlock_bh(&rt6_exception_lock);
1588 return err;
1589}
1590
1591/* Find rt6_ex which contains the passed in rt cache and
1592 * refresh its stamp
1593 */
1594static void rt6_update_exception_stamp_rt(struct rt6_info *rt)
1595{
Wei Wang35732d02017-10-06 12:05:57 -07001596 struct rt6_exception_bucket *bucket;
David Ahern8d1c8022018-04-17 17:33:26 -07001597 struct fib6_info *from = rt->from;
Wei Wang35732d02017-10-06 12:05:57 -07001598 struct in6_addr *src_key = NULL;
1599 struct rt6_exception *rt6_ex;
1600
1601 if (!from ||
Colin Ian King442d7132017-10-10 19:10:30 +01001602 !(rt->rt6i_flags & RTF_CACHE))
Wei Wang35732d02017-10-06 12:05:57 -07001603 return;
1604
1605 rcu_read_lock();
1606 bucket = rcu_dereference(from->rt6i_exception_bucket);
1607
1608#ifdef CONFIG_IPV6_SUBTREES
1609 /* rt6i_src.plen != 0 indicates 'from' is in subtree
1610 * and exception table is indexed by a hash of
1611 * both rt6i_dst and rt6i_src.
1612 * Otherwise, the exception table is indexed by
1613 * a hash of only rt6i_dst.
1614 */
David Ahern93c2fb22018-04-18 15:38:59 -07001615 if (from->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001616 src_key = &rt->rt6i_src.addr;
1617#endif
1618 rt6_ex = __rt6_find_exception_rcu(&bucket,
1619 &rt->rt6i_dst.addr,
1620 src_key);
1621 if (rt6_ex)
1622 rt6_ex->stamp = jiffies;
1623
1624 rcu_read_unlock();
1625}
1626
David Ahern8d1c8022018-04-17 17:33:26 -07001627static void rt6_exceptions_remove_prefsrc(struct fib6_info *rt)
Wei Wang60006a42017-10-06 12:05:58 -07001628{
1629 struct rt6_exception_bucket *bucket;
1630 struct rt6_exception *rt6_ex;
1631 int i;
1632
1633 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1634 lockdep_is_held(&rt6_exception_lock));
1635
1636 if (bucket) {
1637 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1638 hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
1639 rt6_ex->rt6i->rt6i_prefsrc.plen = 0;
1640 }
1641 bucket++;
1642 }
1643 }
1644}
1645
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001646static bool rt6_mtu_change_route_allowed(struct inet6_dev *idev,
1647 struct rt6_info *rt, int mtu)
1648{
1649 /* If the new MTU is lower than the route PMTU, this new MTU will be the
1650 * lowest MTU in the path: always allow updating the route PMTU to
1651 * reflect PMTU decreases.
1652 *
1653 * If the new MTU is higher, and the route PMTU is equal to the local
1654 * MTU, this means the old MTU is the lowest in the path, so allow
1655 * updating it: if other nodes now have lower MTUs, PMTU discovery will
1656 * handle this.
1657 */
1658
1659 if (dst_mtu(&rt->dst) >= mtu)
1660 return true;
1661
1662 if (dst_mtu(&rt->dst) == idev->cnf.mtu6)
1663 return true;
1664
1665 return false;
1666}
1667
1668static void rt6_exceptions_update_pmtu(struct inet6_dev *idev,
David Ahern8d1c8022018-04-17 17:33:26 -07001669 struct fib6_info *rt, int mtu)
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001670{
1671 struct rt6_exception_bucket *bucket;
1672 struct rt6_exception *rt6_ex;
1673 int i;
1674
1675 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1676 lockdep_is_held(&rt6_exception_lock));
1677
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001678 if (!bucket)
1679 return;
1680
1681 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1682 hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
1683 struct rt6_info *entry = rt6_ex->rt6i;
1684
1685 /* For RTF_CACHE with rt6i_pmtu == 0 (i.e. a redirected
David Ahernd4ead6b2018-04-17 17:33:16 -07001686 * route), the metrics of its rt->from have already
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001687 * been updated.
1688 */
David Ahernd4ead6b2018-04-17 17:33:16 -07001689 if (dst_metric_raw(&entry->dst, RTAX_MTU) &&
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001690 rt6_mtu_change_route_allowed(idev, entry, mtu))
David Ahernd4ead6b2018-04-17 17:33:16 -07001691 dst_metric_set(&entry->dst, RTAX_MTU, mtu);
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001692 }
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001693 bucket++;
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001694 }
1695}
1696
Wei Wangb16cb452017-10-06 12:06:00 -07001697#define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE)
1698
David Ahern8d1c8022018-04-17 17:33:26 -07001699static void rt6_exceptions_clean_tohost(struct fib6_info *rt,
Wei Wangb16cb452017-10-06 12:06:00 -07001700 struct in6_addr *gateway)
1701{
1702 struct rt6_exception_bucket *bucket;
1703 struct rt6_exception *rt6_ex;
1704 struct hlist_node *tmp;
1705 int i;
1706
1707 if (!rcu_access_pointer(rt->rt6i_exception_bucket))
1708 return;
1709
1710 spin_lock_bh(&rt6_exception_lock);
1711 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1712 lockdep_is_held(&rt6_exception_lock));
1713
1714 if (bucket) {
1715 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1716 hlist_for_each_entry_safe(rt6_ex, tmp,
1717 &bucket->chain, hlist) {
1718 struct rt6_info *entry = rt6_ex->rt6i;
1719
1720 if ((entry->rt6i_flags & RTF_CACHE_GATEWAY) ==
1721 RTF_CACHE_GATEWAY &&
1722 ipv6_addr_equal(gateway,
1723 &entry->rt6i_gateway)) {
1724 rt6_remove_exception(bucket, rt6_ex);
1725 }
1726 }
1727 bucket++;
1728 }
1729 }
1730
1731 spin_unlock_bh(&rt6_exception_lock);
1732}
1733
Wei Wangc757faa2017-10-06 12:06:01 -07001734static void rt6_age_examine_exception(struct rt6_exception_bucket *bucket,
1735 struct rt6_exception *rt6_ex,
1736 struct fib6_gc_args *gc_args,
1737 unsigned long now)
1738{
1739 struct rt6_info *rt = rt6_ex->rt6i;
1740
Paolo Abeni1859bac2017-10-19 16:07:11 +02001741 /* we are pruning and obsoleting aged-out and non gateway exceptions
1742 * even if others have still references to them, so that on next
1743 * dst_check() such references can be dropped.
1744 * EXPIRES exceptions - e.g. pmtu-generated ones are pruned when
1745 * expired, independently from their aging, as per RFC 8201 section 4
1746 */
Wei Wang31afeb42018-01-26 11:40:17 -08001747 if (!(rt->rt6i_flags & RTF_EXPIRES)) {
1748 if (time_after_eq(now, rt->dst.lastuse + gc_args->timeout)) {
1749 RT6_TRACE("aging clone %p\n", rt);
1750 rt6_remove_exception(bucket, rt6_ex);
1751 return;
1752 }
1753 } else if (time_after(jiffies, rt->dst.expires)) {
1754 RT6_TRACE("purging expired route %p\n", rt);
Wei Wangc757faa2017-10-06 12:06:01 -07001755 rt6_remove_exception(bucket, rt6_ex);
1756 return;
Wei Wang31afeb42018-01-26 11:40:17 -08001757 }
1758
1759 if (rt->rt6i_flags & RTF_GATEWAY) {
Wei Wangc757faa2017-10-06 12:06:01 -07001760 struct neighbour *neigh;
1761 __u8 neigh_flags = 0;
1762
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001763 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
1764 if (neigh)
Wei Wangc757faa2017-10-06 12:06:01 -07001765 neigh_flags = neigh->flags;
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001766
Wei Wangc757faa2017-10-06 12:06:01 -07001767 if (!(neigh_flags & NTF_ROUTER)) {
1768 RT6_TRACE("purging route %p via non-router but gateway\n",
1769 rt);
1770 rt6_remove_exception(bucket, rt6_ex);
1771 return;
1772 }
1773 }
Wei Wang31afeb42018-01-26 11:40:17 -08001774
Wei Wangc757faa2017-10-06 12:06:01 -07001775 gc_args->more++;
1776}
1777
David Ahern8d1c8022018-04-17 17:33:26 -07001778void rt6_age_exceptions(struct fib6_info *rt,
Wei Wangc757faa2017-10-06 12:06:01 -07001779 struct fib6_gc_args *gc_args,
1780 unsigned long now)
1781{
1782 struct rt6_exception_bucket *bucket;
1783 struct rt6_exception *rt6_ex;
1784 struct hlist_node *tmp;
1785 int i;
1786
1787 if (!rcu_access_pointer(rt->rt6i_exception_bucket))
1788 return;
1789
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001790 rcu_read_lock_bh();
1791 spin_lock(&rt6_exception_lock);
Wei Wangc757faa2017-10-06 12:06:01 -07001792 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1793 lockdep_is_held(&rt6_exception_lock));
1794
1795 if (bucket) {
1796 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1797 hlist_for_each_entry_safe(rt6_ex, tmp,
1798 &bucket->chain, hlist) {
1799 rt6_age_examine_exception(bucket, rt6_ex,
1800 gc_args, now);
1801 }
1802 bucket++;
1803 }
1804 }
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001805 spin_unlock(&rt6_exception_lock);
1806 rcu_read_unlock_bh();
Wei Wangc757faa2017-10-06 12:06:01 -07001807}
1808
David Ahern1d053da2018-05-09 20:34:21 -07001809/* must be called with rcu lock held */
1810struct fib6_info *fib6_table_lookup(struct net *net, struct fib6_table *table,
1811 int oif, struct flowi6 *fl6, int strict)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812{
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001813 struct fib6_node *fn, *saved_fn;
David Ahern8d1c8022018-04-17 17:33:26 -07001814 struct fib6_info *f6i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815
David Ahern64547432018-05-09 20:34:19 -07001816 fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001817 saved_fn = fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818
David Ahernca254492015-10-12 11:47:10 -07001819 if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
1820 oif = 0;
1821
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001822redo_rt6_select:
David Ahern23fb93a2018-04-17 17:33:23 -07001823 f6i = rt6_select(net, fn, oif, strict);
David Ahern23fb93a2018-04-17 17:33:23 -07001824 if (f6i == net->ipv6.fib6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001825 fn = fib6_backtrack(fn, &fl6->saddr);
1826 if (fn)
1827 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001828 else if (strict & RT6_LOOKUP_F_REACHABLE) {
1829 /* also consider unreachable route */
1830 strict &= ~RT6_LOOKUP_F_REACHABLE;
1831 fn = saved_fn;
1832 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001833 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001834 }
1835
David Ahernd4bea422018-05-09 20:34:24 -07001836 trace_fib6_table_lookup(net, f6i, table, fl6);
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -08001837
David Ahern1d053da2018-05-09 20:34:21 -07001838 return f6i;
1839}
1840
1841struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
1842 int oif, struct flowi6 *fl6,
1843 const struct sk_buff *skb, int flags)
1844{
1845 struct fib6_info *f6i;
1846 struct rt6_info *rt;
1847 int strict = 0;
1848
1849 strict |= flags & RT6_LOOKUP_F_IFACE;
1850 strict |= flags & RT6_LOOKUP_F_IGNORE_LINKSTATE;
1851 if (net->ipv6.devconf_all->forwarding == 0)
1852 strict |= RT6_LOOKUP_F_REACHABLE;
1853
1854 rcu_read_lock();
1855
1856 f6i = fib6_table_lookup(net, table, oif, fl6, strict);
1857 if (f6i->fib6_nsiblings)
1858 f6i = fib6_multipath_select(net, f6i, fl6, oif, skb, strict);
1859
David Ahern23fb93a2018-04-17 17:33:23 -07001860 if (f6i == net->ipv6.fib6_null_entry) {
David Ahern421842e2018-04-17 17:33:18 -07001861 rt = net->ipv6.ip6_null_entry;
Wei Wang66f5d6c2017-10-06 12:06:10 -07001862 rcu_read_unlock();
Wei Wangd3843fe2017-10-06 12:06:06 -07001863 dst_hold(&rt->dst);
Wei Wangd3843fe2017-10-06 12:06:06 -07001864 return rt;
David Ahern23fb93a2018-04-17 17:33:23 -07001865 }
1866
1867 /*Search through exception table */
1868 rt = rt6_find_cached_rt(f6i, &fl6->daddr, &fl6->saddr);
1869 if (rt) {
David Ahernd4ead6b2018-04-17 17:33:16 -07001870 if (ip6_hold_safe(net, &rt, true))
Wei Wangd3843fe2017-10-06 12:06:06 -07001871 dst_use_noref(&rt->dst, jiffies);
David Ahernd4ead6b2018-04-17 17:33:16 -07001872
Wei Wang66f5d6c2017-10-06 12:06:10 -07001873 rcu_read_unlock();
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001874 return rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001875 } else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) &&
David Ahern93c2fb22018-04-18 15:38:59 -07001876 !(f6i->fib6_flags & RTF_GATEWAY))) {
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001877 /* Create a RTF_CACHE clone which will not be
1878 * owned by the fib6 tree. It is for the special case where
1879 * the daddr in the skb during the neighbor look-up is different
1880 * from the fl6->daddr used to look-up route here.
1881 */
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001882 struct rt6_info *uncached_rt;
1883
David Ahern23fb93a2018-04-17 17:33:23 -07001884 uncached_rt = ip6_rt_cache_alloc(f6i, &fl6->daddr, NULL);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001885
David Ahern4d85cd02018-04-20 15:37:59 -07001886 rcu_read_unlock();
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001887
Wei Wang1cfb71e2017-06-17 10:42:33 -07001888 if (uncached_rt) {
1889 /* Uncached_rt's refcnt is taken during ip6_rt_cache_alloc()
1890 * No need for another dst_hold()
1891 */
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07001892 rt6_uncached_list_add(uncached_rt);
Wei Wang81eb8442017-10-06 12:06:11 -07001893 atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);
Wei Wang1cfb71e2017-06-17 10:42:33 -07001894 } else {
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001895 uncached_rt = net->ipv6.ip6_null_entry;
Wei Wang1cfb71e2017-06-17 10:42:33 -07001896 dst_hold(&uncached_rt->dst);
1897 }
David Ahernb8115802015-11-19 12:24:22 -08001898
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001899 return uncached_rt;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001900 } else {
1901 /* Get a percpu copy */
1902
1903 struct rt6_info *pcpu_rt;
1904
Eric Dumazet951f7882017-10-08 21:07:18 -07001905 local_bh_disable();
David Ahern23fb93a2018-04-17 17:33:23 -07001906 pcpu_rt = rt6_get_pcpu_route(f6i);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001907
David Ahern93531c62018-04-17 17:33:25 -07001908 if (!pcpu_rt)
1909 pcpu_rt = rt6_make_pcpu_route(net, f6i);
1910
Eric Dumazet951f7882017-10-08 21:07:18 -07001911 local_bh_enable();
1912 rcu_read_unlock();
David Ahernd4bea422018-05-09 20:34:24 -07001913
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001914 return pcpu_rt;
1915 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001916}
David Ahern9ff74382016-06-13 13:44:19 -07001917EXPORT_SYMBOL_GPL(ip6_pol_route);
Thomas Grafc71099a2006-08-04 23:20:06 -07001918
David Ahernb75cc8f2018-03-02 08:32:17 -08001919static struct rt6_info *ip6_pol_route_input(struct net *net,
1920 struct fib6_table *table,
1921 struct flowi6 *fl6,
1922 const struct sk_buff *skb,
1923 int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001924{
David Ahernb75cc8f2018-03-02 08:32:17 -08001925 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, skb, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001926}
1927
Mahesh Bandeward409b842016-09-16 12:59:08 -07001928struct dst_entry *ip6_route_input_lookup(struct net *net,
1929 struct net_device *dev,
David Ahernb75cc8f2018-03-02 08:32:17 -08001930 struct flowi6 *fl6,
1931 const struct sk_buff *skb,
1932 int flags)
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001933{
1934 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
1935 flags |= RT6_LOOKUP_F_IFACE;
1936
David Ahernb75cc8f2018-03-02 08:32:17 -08001937 return fib6_rule_lookup(net, fl6, skb, flags, ip6_pol_route_input);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001938}
Mahesh Bandeward409b842016-09-16 12:59:08 -07001939EXPORT_SYMBOL_GPL(ip6_route_input_lookup);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001940
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001941static void ip6_multipath_l3_keys(const struct sk_buff *skb,
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001942 struct flow_keys *keys,
1943 struct flow_keys *flkeys)
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001944{
1945 const struct ipv6hdr *outer_iph = ipv6_hdr(skb);
1946 const struct ipv6hdr *key_iph = outer_iph;
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001947 struct flow_keys *_flkeys = flkeys;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001948 const struct ipv6hdr *inner_iph;
1949 const struct icmp6hdr *icmph;
1950 struct ipv6hdr _inner_iph;
Eric Dumazetcea67a22018-04-29 09:54:59 -07001951 struct icmp6hdr _icmph;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001952
1953 if (likely(outer_iph->nexthdr != IPPROTO_ICMPV6))
1954 goto out;
1955
Eric Dumazetcea67a22018-04-29 09:54:59 -07001956 icmph = skb_header_pointer(skb, skb_transport_offset(skb),
1957 sizeof(_icmph), &_icmph);
1958 if (!icmph)
1959 goto out;
1960
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001961 if (icmph->icmp6_type != ICMPV6_DEST_UNREACH &&
1962 icmph->icmp6_type != ICMPV6_PKT_TOOBIG &&
1963 icmph->icmp6_type != ICMPV6_TIME_EXCEED &&
1964 icmph->icmp6_type != ICMPV6_PARAMPROB)
1965 goto out;
1966
1967 inner_iph = skb_header_pointer(skb,
1968 skb_transport_offset(skb) + sizeof(*icmph),
1969 sizeof(_inner_iph), &_inner_iph);
1970 if (!inner_iph)
1971 goto out;
1972
1973 key_iph = inner_iph;
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001974 _flkeys = NULL;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001975out:
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001976 if (_flkeys) {
1977 keys->addrs.v6addrs.src = _flkeys->addrs.v6addrs.src;
1978 keys->addrs.v6addrs.dst = _flkeys->addrs.v6addrs.dst;
1979 keys->tags.flow_label = _flkeys->tags.flow_label;
1980 keys->basic.ip_proto = _flkeys->basic.ip_proto;
1981 } else {
1982 keys->addrs.v6addrs.src = key_iph->saddr;
1983 keys->addrs.v6addrs.dst = key_iph->daddr;
Michal Kubecekfa1be7e2018-06-04 11:36:05 +02001984 keys->tags.flow_label = ip6_flowlabel(key_iph);
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001985 keys->basic.ip_proto = key_iph->nexthdr;
1986 }
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001987}
1988
1989/* if skb is set it will be used and fl6 can be NULL */
David Ahernb4bac172018-03-02 08:32:18 -08001990u32 rt6_multipath_hash(const struct net *net, const struct flowi6 *fl6,
1991 const struct sk_buff *skb, struct flow_keys *flkeys)
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001992{
1993 struct flow_keys hash_keys;
David Ahern9a2a5372018-03-02 08:32:15 -08001994 u32 mhash;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001995
David S. Millerbbfa0472018-03-12 11:09:33 -04001996 switch (ip6_multipath_hash_policy(net)) {
David Ahernb4bac172018-03-02 08:32:18 -08001997 case 0:
1998 memset(&hash_keys, 0, sizeof(hash_keys));
1999 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2000 if (skb) {
2001 ip6_multipath_l3_keys(skb, &hash_keys, flkeys);
2002 } else {
2003 hash_keys.addrs.v6addrs.src = fl6->saddr;
2004 hash_keys.addrs.v6addrs.dst = fl6->daddr;
Michal Kubecekfa1be7e2018-06-04 11:36:05 +02002005 hash_keys.tags.flow_label = (__force u32)flowi6_get_flowlabel(fl6);
David Ahernb4bac172018-03-02 08:32:18 -08002006 hash_keys.basic.ip_proto = fl6->flowi6_proto;
2007 }
2008 break;
2009 case 1:
2010 if (skb) {
2011 unsigned int flag = FLOW_DISSECTOR_F_STOP_AT_ENCAP;
2012 struct flow_keys keys;
2013
2014 /* short-circuit if we already have L4 hash present */
2015 if (skb->l4_hash)
2016 return skb_get_hash_raw(skb) >> 1;
2017
2018 memset(&hash_keys, 0, sizeof(hash_keys));
2019
2020 if (!flkeys) {
2021 skb_flow_dissect_flow_keys(skb, &keys, flag);
2022 flkeys = &keys;
2023 }
2024 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2025 hash_keys.addrs.v6addrs.src = flkeys->addrs.v6addrs.src;
2026 hash_keys.addrs.v6addrs.dst = flkeys->addrs.v6addrs.dst;
2027 hash_keys.ports.src = flkeys->ports.src;
2028 hash_keys.ports.dst = flkeys->ports.dst;
2029 hash_keys.basic.ip_proto = flkeys->basic.ip_proto;
2030 } else {
2031 memset(&hash_keys, 0, sizeof(hash_keys));
2032 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2033 hash_keys.addrs.v6addrs.src = fl6->saddr;
2034 hash_keys.addrs.v6addrs.dst = fl6->daddr;
2035 hash_keys.ports.src = fl6->fl6_sport;
2036 hash_keys.ports.dst = fl6->fl6_dport;
2037 hash_keys.basic.ip_proto = fl6->flowi6_proto;
2038 }
2039 break;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002040 }
David Ahern9a2a5372018-03-02 08:32:15 -08002041 mhash = flow_hash_from_keys(&hash_keys);
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002042
David Ahern9a2a5372018-03-02 08:32:15 -08002043 return mhash >> 1;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002044}
2045
Thomas Grafc71099a2006-08-04 23:20:06 -07002046void ip6_route_input(struct sk_buff *skb)
2047{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002048 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002049 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -07002050 int flags = RT6_LOOKUP_F_HAS_SADDR;
Jiri Benc904af042015-08-20 13:56:31 +02002051 struct ip_tunnel_info *tun_info;
David S. Miller4c9483b2011-03-12 16:22:43 -05002052 struct flowi6 fl6 = {
David Aherne0d56fd2016-09-10 12:09:57 -07002053 .flowi6_iif = skb->dev->ifindex,
David S. Miller4c9483b2011-03-12 16:22:43 -05002054 .daddr = iph->daddr,
2055 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00002056 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -05002057 .flowi6_mark = skb->mark,
2058 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -07002059 };
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05002060 struct flow_keys *flkeys = NULL, _flkeys;
Thomas Grafadaa70b2006-10-13 15:01:03 -07002061
Jiri Benc904af042015-08-20 13:56:31 +02002062 tun_info = skb_tunnel_info(skb);
Jiri Benc46fa0622015-08-28 20:48:19 +02002063 if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX))
Jiri Benc904af042015-08-20 13:56:31 +02002064 fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id;
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05002065
2066 if (fib6_rules_early_flow_dissect(net, skb, &fl6, &_flkeys))
2067 flkeys = &_flkeys;
2068
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002069 if (unlikely(fl6.flowi6_proto == IPPROTO_ICMPV6))
David Ahernb4bac172018-03-02 08:32:18 -08002070 fl6.mp_hash = rt6_multipath_hash(net, &fl6, skb, flkeys);
Jiri Benc06e9d042015-08-20 13:56:26 +02002071 skb_dst_drop(skb);
David Ahernb75cc8f2018-03-02 08:32:17 -08002072 skb_dst_set(skb,
2073 ip6_route_input_lookup(net, skb->dev, &fl6, skb, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -07002074}
2075
David Ahernb75cc8f2018-03-02 08:32:17 -08002076static struct rt6_info *ip6_pol_route_output(struct net *net,
2077 struct fib6_table *table,
2078 struct flowi6 *fl6,
2079 const struct sk_buff *skb,
2080 int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07002081{
David Ahernb75cc8f2018-03-02 08:32:17 -08002082 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, skb, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -07002083}
2084
Paolo Abeni6f21c962016-01-29 12:30:19 +01002085struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk,
2086 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07002087{
David Ahernd46a9d62015-10-21 08:42:22 -07002088 bool any_src;
Thomas Grafc71099a2006-08-04 23:20:06 -07002089
David Ahern4c1feac2016-09-10 12:09:56 -07002090 if (rt6_need_strict(&fl6->daddr)) {
2091 struct dst_entry *dst;
2092
2093 dst = l3mdev_link_scope_lookup(net, fl6);
2094 if (dst)
2095 return dst;
2096 }
David Ahernca254492015-10-12 11:47:10 -07002097
Pavel Emelyanov1fb94892012-08-08 21:53:36 +00002098 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +00002099
David Ahernd46a9d62015-10-21 08:42:22 -07002100 any_src = ipv6_addr_any(&fl6->saddr);
David Ahern741a11d2015-09-28 10:12:13 -07002101 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) ||
David Ahernd46a9d62015-10-21 08:42:22 -07002102 (fl6->flowi6_oif && any_src))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07002103 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -07002104
David Ahernd46a9d62015-10-21 08:42:22 -07002105 if (!any_src)
Thomas Grafadaa70b2006-10-13 15:01:03 -07002106 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +00002107 else if (sk)
2108 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -07002109
David Ahernb75cc8f2018-03-02 08:32:17 -08002110 return fib6_rule_lookup(net, fl6, NULL, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111}
Paolo Abeni6f21c962016-01-29 12:30:19 +01002112EXPORT_SYMBOL_GPL(ip6_route_output_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113
David S. Miller2774c132011-03-01 14:59:04 -08002114struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -07002115{
David S. Miller5c1e6aa2011-04-28 14:13:38 -07002116 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
Wei Wang1dbe32522017-06-17 10:42:26 -07002117 struct net_device *loopback_dev = net->loopback_dev;
David S. Miller14e50e52007-05-24 18:17:54 -07002118 struct dst_entry *new = NULL;
2119
Wei Wang1dbe32522017-06-17 10:42:26 -07002120 rt = dst_alloc(&ip6_dst_blackhole_ops, loopback_dev, 1,
Steffen Klassert62cf27e2017-10-09 08:39:43 +02002121 DST_OBSOLETE_DEAD, 0);
David S. Miller14e50e52007-05-24 18:17:54 -07002122 if (rt) {
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002123 rt6_info_init(rt);
Wei Wang81eb8442017-10-06 12:06:11 -07002124 atomic_inc(&net->ipv6.rt6_stats->fib_rt_alloc);
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002125
Changli Gaod8d1f302010-06-10 23:31:35 -07002126 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -07002127 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08002128 new->input = dst_discard;
Eric W. Biedermanede20592015-10-07 16:48:47 -05002129 new->output = dst_discard_out;
David S. Miller14e50e52007-05-24 18:17:54 -07002130
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002131 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07002132
Wei Wang1dbe32522017-06-17 10:42:26 -07002133 rt->rt6i_idev = in6_dev_get(loopback_dev);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002134 rt->rt6i_gateway = ort->rt6i_gateway;
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002135 rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU;
David S. Miller14e50e52007-05-24 18:17:54 -07002136
2137 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
2138#ifdef CONFIG_IPV6_SUBTREES
2139 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
2140#endif
David S. Miller14e50e52007-05-24 18:17:54 -07002141 }
2142
David S. Miller69ead7a2011-03-01 14:45:33 -08002143 dst_release(dst_orig);
2144 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07002145}
David S. Miller14e50e52007-05-24 18:17:54 -07002146
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147/*
2148 * Destination cache support functions
2149 */
2150
David Ahern8d1c8022018-04-17 17:33:26 -07002151static bool fib6_check(struct fib6_info *f6i, u32 cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002152{
Steffen Klassert36143642017-08-25 09:05:42 +02002153 u32 rt_cookie = 0;
Wei Wangc5cff852017-08-21 09:47:10 -07002154
David Ahern8ae86972018-04-20 15:38:03 -07002155 if (!fib6_get_cookie_safe(f6i, &rt_cookie) || rt_cookie != cookie)
David Ahern93531c62018-04-17 17:33:25 -07002156 return false;
2157
2158 if (fib6_check_expired(f6i))
2159 return false;
2160
2161 return true;
2162}
2163
David Aherna68886a2018-04-20 15:38:02 -07002164static struct dst_entry *rt6_check(struct rt6_info *rt,
2165 struct fib6_info *from,
2166 u32 cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002167{
Wei Wangc5cff852017-08-21 09:47:10 -07002168 u32 rt_cookie = 0;
2169
David Aherna68886a2018-04-20 15:38:02 -07002170 if ((from && !fib6_get_cookie_safe(from, &rt_cookie)) ||
David Ahern93531c62018-04-17 17:33:25 -07002171 rt_cookie != cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002172 return NULL;
2173
2174 if (rt6_check_expired(rt))
2175 return NULL;
2176
2177 return &rt->dst;
2178}
2179
David Aherna68886a2018-04-20 15:38:02 -07002180static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt,
2181 struct fib6_info *from,
2182 u32 cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002183{
Martin KaFai Lau5973fb12015-11-11 11:51:07 -08002184 if (!__rt6_check_expired(rt) &&
2185 rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
David Aherna68886a2018-04-20 15:38:02 -07002186 fib6_check(from, cookie))
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002187 return &rt->dst;
2188 else
2189 return NULL;
2190}
2191
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
2193{
David Aherna87b7dc2018-04-20 15:38:00 -07002194 struct dst_entry *dst_ret;
David Aherna68886a2018-04-20 15:38:02 -07002195 struct fib6_info *from;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 struct rt6_info *rt;
2197
David Aherna87b7dc2018-04-20 15:38:00 -07002198 rt = container_of(dst, struct rt6_info, dst);
2199
2200 rcu_read_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00002202 /* All IPV6 dsts are created with ->obsolete set to the value
2203 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
2204 * into this function always.
2205 */
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02002206
David Aherna68886a2018-04-20 15:38:02 -07002207 from = rcu_dereference(rt->from);
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002208
David Aherna68886a2018-04-20 15:38:02 -07002209 if (from && (rt->rt6i_flags & RTF_PCPU ||
2210 unlikely(!list_empty(&rt->rt6i_uncached))))
2211 dst_ret = rt6_dst_from_check(rt, from, cookie);
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002212 else
David Aherna68886a2018-04-20 15:38:02 -07002213 dst_ret = rt6_check(rt, from, cookie);
David Aherna87b7dc2018-04-20 15:38:00 -07002214
2215 rcu_read_unlock();
2216
2217 return dst_ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218}
2219
2220static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
2221{
2222 struct rt6_info *rt = (struct rt6_info *) dst;
2223
2224 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002225 if (rt->rt6i_flags & RTF_CACHE) {
David Ahernc3c14da2018-04-23 11:32:06 -07002226 rcu_read_lock();
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002227 if (rt6_check_expired(rt)) {
David Ahern93531c62018-04-17 17:33:25 -07002228 rt6_remove_exception_rt(rt);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002229 dst = NULL;
2230 }
David Ahernc3c14da2018-04-23 11:32:06 -07002231 rcu_read_unlock();
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002232 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002234 dst = NULL;
2235 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002237 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238}
2239
2240static void ip6_link_failure(struct sk_buff *skb)
2241{
2242 struct rt6_info *rt;
2243
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002244 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245
Eric Dumazetadf30902009-06-02 05:19:30 +00002246 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 if (rt) {
David Ahern8a14e462018-04-23 11:32:07 -07002248 rcu_read_lock();
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02002249 if (rt->rt6i_flags & RTF_CACHE) {
Wei Wangad65a2f2017-06-17 10:42:35 -07002250 if (dst_hold_safe(&rt->dst))
David Ahern93531c62018-04-17 17:33:25 -07002251 rt6_remove_exception_rt(rt);
Wei Wangc5cff852017-08-21 09:47:10 -07002252 } else {
David Aherna68886a2018-04-20 15:38:02 -07002253 struct fib6_info *from;
Wei Wangc5cff852017-08-21 09:47:10 -07002254 struct fib6_node *fn;
2255
David Aherna68886a2018-04-20 15:38:02 -07002256 from = rcu_dereference(rt->from);
2257 if (from) {
2258 fn = rcu_dereference(from->fib6_node);
2259 if (fn && (rt->rt6i_flags & RTF_DEFAULT))
2260 fn->fn_sernum = -1;
2261 }
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02002262 }
David Ahern8a14e462018-04-23 11:32:07 -07002263 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 }
2265}
2266
David Ahern6a3e0302018-04-20 15:37:57 -07002267static void rt6_update_expires(struct rt6_info *rt0, int timeout)
2268{
David Aherna68886a2018-04-20 15:38:02 -07002269 if (!(rt0->rt6i_flags & RTF_EXPIRES)) {
2270 struct fib6_info *from;
2271
2272 rcu_read_lock();
2273 from = rcu_dereference(rt0->from);
2274 if (from)
2275 rt0->dst.expires = from->expires;
2276 rcu_read_unlock();
2277 }
David Ahern6a3e0302018-04-20 15:37:57 -07002278
2279 dst_set_expires(&rt0->dst, timeout);
2280 rt0->rt6i_flags |= RTF_EXPIRES;
2281}
2282
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002283static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
2284{
2285 struct net *net = dev_net(rt->dst.dev);
2286
David Ahernd4ead6b2018-04-17 17:33:16 -07002287 dst_metric_set(&rt->dst, RTAX_MTU, mtu);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002288 rt->rt6i_flags |= RTF_MODIFIED;
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002289 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
2290}
2291
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002292static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
2293{
David Aherna68886a2018-04-20 15:38:02 -07002294 bool from_set;
2295
2296 rcu_read_lock();
2297 from_set = !!rcu_dereference(rt->from);
2298 rcu_read_unlock();
2299
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002300 return !(rt->rt6i_flags & RTF_CACHE) &&
David Aherna68886a2018-04-20 15:38:02 -07002301 (rt->rt6i_flags & RTF_PCPU || from_set);
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002302}
2303
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002304static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
2305 const struct ipv6hdr *iph, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306{
Julian Anastasov0dec8792017-02-06 23:14:16 +02002307 const struct in6_addr *daddr, *saddr;
Ian Morris67ba4152014-08-24 21:53:10 +01002308 struct rt6_info *rt6 = (struct rt6_info *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309
Xin Long19bda362016-10-28 18:18:01 +08002310 if (dst_metric_locked(dst, RTAX_MTU))
2311 return;
2312
Julian Anastasov0dec8792017-02-06 23:14:16 +02002313 if (iph) {
2314 daddr = &iph->daddr;
2315 saddr = &iph->saddr;
2316 } else if (sk) {
2317 daddr = &sk->sk_v6_daddr;
2318 saddr = &inet6_sk(sk)->saddr;
2319 } else {
2320 daddr = NULL;
2321 saddr = NULL;
2322 }
2323 dst_confirm_neigh(dst, daddr);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002324 mtu = max_t(u32, mtu, IPV6_MIN_MTU);
2325 if (mtu >= dst_mtu(dst))
2326 return;
David S. Miller81aded22012-06-15 14:54:11 -07002327
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002328 if (!rt6_cache_allowed_for_pmtu(rt6)) {
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002329 rt6_do_update_pmtu(rt6, mtu);
Wei Wang2b760fc2017-10-06 12:06:03 -07002330 /* update rt6_ex->stamp for cache */
2331 if (rt6->rt6i_flags & RTF_CACHE)
2332 rt6_update_exception_stamp_rt(rt6);
Julian Anastasov0dec8792017-02-06 23:14:16 +02002333 } else if (daddr) {
David Aherna68886a2018-04-20 15:38:02 -07002334 struct fib6_info *from;
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002335 struct rt6_info *nrt6;
Hagen Paul Pfeifer9d289712015-01-15 22:34:25 +01002336
David Ahern4d85cd02018-04-20 15:37:59 -07002337 rcu_read_lock();
David Aherna68886a2018-04-20 15:38:02 -07002338 from = rcu_dereference(rt6->from);
2339 nrt6 = ip6_rt_cache_alloc(from, daddr, saddr);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002340 if (nrt6) {
2341 rt6_do_update_pmtu(nrt6, mtu);
David Aherna68886a2018-04-20 15:38:02 -07002342 if (rt6_insert_exception(nrt6, from))
Wei Wang2b760fc2017-10-06 12:06:03 -07002343 dst_release_immediate(&nrt6->dst);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002344 }
David Aherna68886a2018-04-20 15:38:02 -07002345 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 }
2347}
2348
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002349static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
2350 struct sk_buff *skb, u32 mtu)
2351{
2352 __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu);
2353}
2354
David S. Miller42ae66c2012-06-15 20:01:57 -07002355void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002356 int oif, u32 mark, kuid_t uid)
David S. Miller81aded22012-06-15 14:54:11 -07002357{
2358 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
2359 struct dst_entry *dst;
2360 struct flowi6 fl6;
2361
2362 memset(&fl6, 0, sizeof(fl6));
2363 fl6.flowi6_oif = oif;
Lorenzo Colitti1b3c61d2014-05-13 10:17:34 -07002364 fl6.flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark);
David S. Miller81aded22012-06-15 14:54:11 -07002365 fl6.daddr = iph->daddr;
2366 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00002367 fl6.flowlabel = ip6_flowinfo(iph);
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002368 fl6.flowi6_uid = uid;
David S. Miller81aded22012-06-15 14:54:11 -07002369
2370 dst = ip6_route_output(net, NULL, &fl6);
2371 if (!dst->error)
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002372 __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07002373 dst_release(dst);
2374}
2375EXPORT_SYMBOL_GPL(ip6_update_pmtu);
2376
2377void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
2378{
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07002379 struct dst_entry *dst;
2380
David S. Miller81aded22012-06-15 14:54:11 -07002381 ip6_update_pmtu(skb, sock_net(sk), mtu,
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002382 sk->sk_bound_dev_if, sk->sk_mark, sk->sk_uid);
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07002383
2384 dst = __sk_dst_get(sk);
2385 if (!dst || !dst->obsolete ||
2386 dst->ops->check(dst, inet6_sk(sk)->dst_cookie))
2387 return;
2388
2389 bh_lock_sock(sk);
2390 if (!sock_owned_by_user(sk) && !ipv6_addr_v4mapped(&sk->sk_v6_daddr))
2391 ip6_datagram_dst_update(sk, false);
2392 bh_unlock_sock(sk);
David S. Miller81aded22012-06-15 14:54:11 -07002393}
2394EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
2395
Alexey Kodanev7d6850f2018-04-03 15:00:07 +03002396void ip6_sk_dst_store_flow(struct sock *sk, struct dst_entry *dst,
2397 const struct flowi6 *fl6)
2398{
2399#ifdef CONFIG_IPV6_SUBTREES
2400 struct ipv6_pinfo *np = inet6_sk(sk);
2401#endif
2402
2403 ip6_dst_store(sk, dst,
2404 ipv6_addr_equal(&fl6->daddr, &sk->sk_v6_daddr) ?
2405 &sk->sk_v6_daddr : NULL,
2406#ifdef CONFIG_IPV6_SUBTREES
2407 ipv6_addr_equal(&fl6->saddr, &np->saddr) ?
2408 &np->saddr :
2409#endif
2410 NULL);
2411}
2412
Duan Jiongb55b76b2013-09-04 19:44:21 +08002413/* Handle redirects */
2414struct ip6rd_flowi {
2415 struct flowi6 fl6;
2416 struct in6_addr gateway;
2417};
2418
2419static struct rt6_info *__ip6_route_redirect(struct net *net,
2420 struct fib6_table *table,
2421 struct flowi6 *fl6,
David Ahernb75cc8f2018-03-02 08:32:17 -08002422 const struct sk_buff *skb,
Duan Jiongb55b76b2013-09-04 19:44:21 +08002423 int flags)
2424{
2425 struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
David Ahern23fb93a2018-04-17 17:33:23 -07002426 struct rt6_info *ret = NULL, *rt_cache;
David Ahern8d1c8022018-04-17 17:33:26 -07002427 struct fib6_info *rt;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002428 struct fib6_node *fn;
2429
2430 /* Get the "current" route for this destination and
Alexander Alemayhu67c408c2017-01-07 23:53:00 +01002431 * check if the redirect has come from appropriate router.
Duan Jiongb55b76b2013-09-04 19:44:21 +08002432 *
2433 * RFC 4861 specifies that redirects should only be
2434 * accepted if they come from the nexthop to the target.
2435 * Due to the way the routes are chosen, this notion
2436 * is a bit fuzzy and one might need to check all possible
2437 * routes.
2438 */
2439
Wei Wang66f5d6c2017-10-06 12:06:10 -07002440 rcu_read_lock();
David Ahern64547432018-05-09 20:34:19 -07002441 fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002442restart:
Wei Wang66f5d6c2017-10-06 12:06:10 -07002443 for_each_fib6_node_rt_rcu(fn) {
David Ahern5e670d82018-04-17 17:33:14 -07002444 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel8067bb82018-01-07 12:45:09 +02002445 continue;
David Ahern14895682018-04-17 17:33:17 -07002446 if (fib6_check_expired(rt))
Duan Jiongb55b76b2013-09-04 19:44:21 +08002447 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07002448 if (rt->fib6_flags & RTF_REJECT)
Duan Jiongb55b76b2013-09-04 19:44:21 +08002449 break;
David Ahern93c2fb22018-04-18 15:38:59 -07002450 if (!(rt->fib6_flags & RTF_GATEWAY))
Duan Jiongb55b76b2013-09-04 19:44:21 +08002451 continue;
David Ahern5e670d82018-04-17 17:33:14 -07002452 if (fl6->flowi6_oif != rt->fib6_nh.nh_dev->ifindex)
Duan Jiongb55b76b2013-09-04 19:44:21 +08002453 continue;
Wei Wang2b760fc2017-10-06 12:06:03 -07002454 /* rt_cache's gateway might be different from its 'parent'
2455 * in the case of an ip redirect.
2456 * So we keep searching in the exception table if the gateway
2457 * is different.
2458 */
David Ahern5e670d82018-04-17 17:33:14 -07002459 if (!ipv6_addr_equal(&rdfl->gateway, &rt->fib6_nh.nh_gw)) {
Wei Wang2b760fc2017-10-06 12:06:03 -07002460 rt_cache = rt6_find_cached_rt(rt,
2461 &fl6->daddr,
2462 &fl6->saddr);
2463 if (rt_cache &&
2464 ipv6_addr_equal(&rdfl->gateway,
2465 &rt_cache->rt6i_gateway)) {
David Ahern23fb93a2018-04-17 17:33:23 -07002466 ret = rt_cache;
Wei Wang2b760fc2017-10-06 12:06:03 -07002467 break;
2468 }
Duan Jiongb55b76b2013-09-04 19:44:21 +08002469 continue;
Wei Wang2b760fc2017-10-06 12:06:03 -07002470 }
Duan Jiongb55b76b2013-09-04 19:44:21 +08002471 break;
2472 }
2473
2474 if (!rt)
David Ahern421842e2018-04-17 17:33:18 -07002475 rt = net->ipv6.fib6_null_entry;
David Ahern93c2fb22018-04-18 15:38:59 -07002476 else if (rt->fib6_flags & RTF_REJECT) {
David Ahern23fb93a2018-04-17 17:33:23 -07002477 ret = net->ipv6.ip6_null_entry;
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08002478 goto out;
2479 }
2480
David Ahern421842e2018-04-17 17:33:18 -07002481 if (rt == net->ipv6.fib6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07002482 fn = fib6_backtrack(fn, &fl6->saddr);
2483 if (fn)
2484 goto restart;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002485 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07002486
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08002487out:
David Ahern23fb93a2018-04-17 17:33:23 -07002488 if (ret)
2489 dst_hold(&ret->dst);
2490 else
2491 ret = ip6_create_rt_rcu(rt);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002492
Wei Wang66f5d6c2017-10-06 12:06:10 -07002493 rcu_read_unlock();
Duan Jiongb55b76b2013-09-04 19:44:21 +08002494
Paolo Abenib65f1642017-10-19 09:31:43 +02002495 trace_fib6_table_lookup(net, rt, table, fl6);
David Ahern23fb93a2018-04-17 17:33:23 -07002496 return ret;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002497};
2498
2499static struct dst_entry *ip6_route_redirect(struct net *net,
David Ahernb75cc8f2018-03-02 08:32:17 -08002500 const struct flowi6 *fl6,
2501 const struct sk_buff *skb,
2502 const struct in6_addr *gateway)
Duan Jiongb55b76b2013-09-04 19:44:21 +08002503{
2504 int flags = RT6_LOOKUP_F_HAS_SADDR;
2505 struct ip6rd_flowi rdfl;
2506
2507 rdfl.fl6 = *fl6;
2508 rdfl.gateway = *gateway;
2509
David Ahernb75cc8f2018-03-02 08:32:17 -08002510 return fib6_rule_lookup(net, &rdfl.fl6, skb,
Duan Jiongb55b76b2013-09-04 19:44:21 +08002511 flags, __ip6_route_redirect);
2512}
2513
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002514void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark,
2515 kuid_t uid)
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002516{
2517 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
2518 struct dst_entry *dst;
2519 struct flowi6 fl6;
2520
2521 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03002522 fl6.flowi6_iif = LOOPBACK_IFINDEX;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002523 fl6.flowi6_oif = oif;
2524 fl6.flowi6_mark = mark;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002525 fl6.daddr = iph->daddr;
2526 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00002527 fl6.flowlabel = ip6_flowinfo(iph);
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002528 fl6.flowi6_uid = uid;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002529
David Ahernb75cc8f2018-03-02 08:32:17 -08002530 dst = ip6_route_redirect(net, &fl6, skb, &ipv6_hdr(skb)->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002531 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002532 dst_release(dst);
2533}
2534EXPORT_SYMBOL_GPL(ip6_redirect);
2535
Duan Jiongc92a59e2013-08-22 12:07:35 +08002536void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
2537 u32 mark)
2538{
2539 const struct ipv6hdr *iph = ipv6_hdr(skb);
2540 const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
2541 struct dst_entry *dst;
2542 struct flowi6 fl6;
2543
2544 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03002545 fl6.flowi6_iif = LOOPBACK_IFINDEX;
Duan Jiongc92a59e2013-08-22 12:07:35 +08002546 fl6.flowi6_oif = oif;
2547 fl6.flowi6_mark = mark;
Duan Jiongc92a59e2013-08-22 12:07:35 +08002548 fl6.daddr = msg->dest;
2549 fl6.saddr = iph->daddr;
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002550 fl6.flowi6_uid = sock_net_uid(net, NULL);
Duan Jiongc92a59e2013-08-22 12:07:35 +08002551
David Ahernb75cc8f2018-03-02 08:32:17 -08002552 dst = ip6_route_redirect(net, &fl6, skb, &iph->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002553 rt6_do_redirect(dst, NULL, skb);
Duan Jiongc92a59e2013-08-22 12:07:35 +08002554 dst_release(dst);
2555}
2556
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002557void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
2558{
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002559 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark,
2560 sk->sk_uid);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002561}
2562EXPORT_SYMBOL_GPL(ip6_sk_redirect);
2563
David S. Miller0dbaee32010-12-13 12:52:14 -08002564static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565{
David S. Miller0dbaee32010-12-13 12:52:14 -08002566 struct net_device *dev = dst->dev;
2567 unsigned int mtu = dst_mtu(dst);
2568 struct net *net = dev_net(dev);
2569
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
2571
Daniel Lezcano55786892008-03-04 13:47:47 -08002572 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
2573 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574
2575 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002576 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
2577 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
2578 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579 * rely only on pmtu discovery"
2580 */
2581 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
2582 mtu = IPV6_MAXPLEN;
2583 return mtu;
2584}
2585
Steffen Klassertebb762f2011-11-23 02:12:51 +00002586static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08002587{
David S. Millerd33e4552010-12-14 13:01:14 -08002588 struct inet6_dev *idev;
David Ahernd4ead6b2018-04-17 17:33:16 -07002589 unsigned int mtu;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00002590
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002591 mtu = dst_metric_raw(dst, RTAX_MTU);
2592 if (mtu)
2593 goto out;
2594
Steffen Klassert618f9bc2011-11-23 02:13:31 +00002595 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08002596
2597 rcu_read_lock();
2598 idev = __in6_dev_get(dst->dev);
2599 if (idev)
2600 mtu = idev->cnf.mtu6;
2601 rcu_read_unlock();
2602
Eric Dumazet30f78d82014-04-10 21:23:36 -07002603out:
Roopa Prabhu14972cb2016-08-24 20:10:43 -07002604 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
2605
2606 return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
David S. Millerd33e4552010-12-14 13:01:14 -08002607}
2608
David Ahern901731b2018-05-21 09:08:14 -07002609/* MTU selection:
2610 * 1. mtu on route is locked - use it
2611 * 2. mtu from nexthop exception
2612 * 3. mtu from egress device
2613 *
2614 * based on ip6_dst_mtu_forward and exception logic of
2615 * rt6_find_cached_rt; called with rcu_read_lock
2616 */
2617u32 ip6_mtu_from_fib6(struct fib6_info *f6i, struct in6_addr *daddr,
2618 struct in6_addr *saddr)
2619{
2620 struct rt6_exception_bucket *bucket;
2621 struct rt6_exception *rt6_ex;
2622 struct in6_addr *src_key;
2623 struct inet6_dev *idev;
2624 u32 mtu = 0;
2625
2626 if (unlikely(fib6_metric_locked(f6i, RTAX_MTU))) {
2627 mtu = f6i->fib6_pmtu;
2628 if (mtu)
2629 goto out;
2630 }
2631
2632 src_key = NULL;
2633#ifdef CONFIG_IPV6_SUBTREES
2634 if (f6i->fib6_src.plen)
2635 src_key = saddr;
2636#endif
2637
2638 bucket = rcu_dereference(f6i->rt6i_exception_bucket);
2639 rt6_ex = __rt6_find_exception_rcu(&bucket, daddr, src_key);
2640 if (rt6_ex && !rt6_check_expired(rt6_ex->rt6i))
2641 mtu = dst_metric_raw(&rt6_ex->rt6i->dst, RTAX_MTU);
2642
2643 if (likely(!mtu)) {
2644 struct net_device *dev = fib6_info_nh_dev(f6i);
2645
2646 mtu = IPV6_MIN_MTU;
2647 idev = __in6_dev_get(dev);
2648 if (idev && idev->cnf.mtu6 > mtu)
2649 mtu = idev->cnf.mtu6;
2650 }
2651
2652 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
2653out:
2654 return mtu - lwtunnel_headroom(fib6_info_nh_lwt(f6i), mtu);
2655}
2656
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08002657struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05002658 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659{
David S. Miller87a11572011-12-06 17:04:13 -05002660 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 struct rt6_info *rt;
2662 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002663 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664
David S. Miller38308472011-12-03 18:02:47 -05002665 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00002666 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667
Martin KaFai Lauad706862015-08-14 11:05:52 -07002668 rt = ip6_dst_alloc(net, dev, 0);
David S. Miller38308472011-12-03 18:02:47 -05002669 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05002671 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 goto out;
2673 }
2674
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002675 rt->dst.flags |= DST_HOST;
Brendan McGrath588753f2017-12-13 22:14:57 +11002676 rt->dst.input = ip6_input;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002677 rt->dst.output = ip6_output;
Julian Anastasov550bab42013-10-20 15:43:04 +03002678 rt->rt6i_gateway = fl6->daddr;
David S. Miller87a11572011-12-06 17:04:13 -05002679 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002680 rt->rt6i_dst.plen = 128;
2681 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08002682 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683
Ido Schimmel4c981e22018-01-07 12:45:04 +02002684 /* Add this dst into uncached_list so that rt6_disable_ip() can
Wei Wang587fea72017-06-17 10:42:36 -07002685 * do proper release of the net_device
2686 */
2687 rt6_uncached_list_add(rt);
Wei Wang81eb8442017-10-06 12:06:11 -07002688 atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689
David S. Miller87a11572011-12-06 17:04:13 -05002690 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
2691
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692out:
David S. Miller87a11572011-12-06 17:04:13 -05002693 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694}
2695
Daniel Lezcano569d3642008-01-18 03:56:57 -08002696static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697{
Alexey Dobriyan86393e52009-08-29 01:34:49 +00002698 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08002699 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
2700 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
2701 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
2702 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
2703 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00002704 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705
Eric Dumazetfc66f952010-10-08 06:37:34 +00002706 entries = dst_entries_get_fast(ops);
Michal Kubeček49a18d82013-08-01 10:04:24 +02002707 if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00002708 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 goto out;
2710
Benjamin Thery6891a342008-03-04 13:49:47 -08002711 net->ipv6.ip6_rt_gc_expire++;
Li RongQing14956642014-05-19 17:30:28 +08002712 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
Eric Dumazetfc66f952010-10-08 06:37:34 +00002713 entries = dst_entries_get_slow(ops);
2714 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08002715 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08002717 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00002718 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719}
2720
David Ahern8d1c8022018-04-17 17:33:26 -07002721static int ip6_convert_metrics(struct net *net, struct fib6_info *rt,
David Ahernd4ead6b2018-04-17 17:33:16 -07002722 struct fib6_config *cfg)
Florian Westphale715b6d2015-01-05 23:57:44 +01002723{
Eric Dumazet263243d2018-04-19 09:14:53 -07002724 struct dst_metrics *p;
Florian Westphale715b6d2015-01-05 23:57:44 +01002725
Ian Morris63159f22015-03-29 14:00:04 +01002726 if (!cfg->fc_mx)
Florian Westphale715b6d2015-01-05 23:57:44 +01002727 return 0;
2728
Eric Dumazet263243d2018-04-19 09:14:53 -07002729 p = kzalloc(sizeof(*rt->fib6_metrics), GFP_KERNEL);
2730 if (unlikely(!p))
Florian Westphale715b6d2015-01-05 23:57:44 +01002731 return -ENOMEM;
2732
Eric Dumazet263243d2018-04-19 09:14:53 -07002733 refcount_set(&p->refcnt, 1);
2734 rt->fib6_metrics = p;
Florian Westphale715b6d2015-01-05 23:57:44 +01002735
Eric Dumazet263243d2018-04-19 09:14:53 -07002736 return ip_metrics_convert(net, cfg->fc_mx, cfg->fc_mx_len, p->metrics);
Florian Westphale715b6d2015-01-05 23:57:44 +01002737}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738
David Ahern8c145862016-04-24 21:26:04 -07002739static struct rt6_info *ip6_nh_lookup_table(struct net *net,
2740 struct fib6_config *cfg,
David Ahernf4797b32018-01-25 16:55:08 -08002741 const struct in6_addr *gw_addr,
2742 u32 tbid, int flags)
David Ahern8c145862016-04-24 21:26:04 -07002743{
2744 struct flowi6 fl6 = {
2745 .flowi6_oif = cfg->fc_ifindex,
2746 .daddr = *gw_addr,
2747 .saddr = cfg->fc_prefsrc,
2748 };
2749 struct fib6_table *table;
2750 struct rt6_info *rt;
David Ahern8c145862016-04-24 21:26:04 -07002751
David Ahernf4797b32018-01-25 16:55:08 -08002752 table = fib6_get_table(net, tbid);
David Ahern8c145862016-04-24 21:26:04 -07002753 if (!table)
2754 return NULL;
2755
2756 if (!ipv6_addr_any(&cfg->fc_prefsrc))
2757 flags |= RT6_LOOKUP_F_HAS_SADDR;
2758
David Ahernf4797b32018-01-25 16:55:08 -08002759 flags |= RT6_LOOKUP_F_IGNORE_LINKSTATE;
David Ahernb75cc8f2018-03-02 08:32:17 -08002760 rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, NULL, flags);
David Ahern8c145862016-04-24 21:26:04 -07002761
2762 /* if table lookup failed, fall back to full lookup */
2763 if (rt == net->ipv6.ip6_null_entry) {
2764 ip6_rt_put(rt);
2765 rt = NULL;
2766 }
2767
2768 return rt;
2769}
2770
David Ahernfc1e64e2018-01-25 16:55:09 -08002771static int ip6_route_check_nh_onlink(struct net *net,
2772 struct fib6_config *cfg,
David Ahern9fbb7042018-03-13 08:29:36 -07002773 const struct net_device *dev,
David Ahernfc1e64e2018-01-25 16:55:09 -08002774 struct netlink_ext_ack *extack)
2775{
David Ahern44750f82018-02-06 13:17:06 -08002776 u32 tbid = l3mdev_fib_table(dev) ? : RT_TABLE_MAIN;
David Ahernfc1e64e2018-01-25 16:55:09 -08002777 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2778 u32 flags = RTF_LOCAL | RTF_ANYCAST | RTF_REJECT;
2779 struct rt6_info *grt;
2780 int err;
2781
2782 err = 0;
2783 grt = ip6_nh_lookup_table(net, cfg, gw_addr, tbid, 0);
2784 if (grt) {
David Ahern58e354c2018-02-06 12:14:12 -08002785 if (!grt->dst.error &&
2786 (grt->rt6i_flags & flags || dev != grt->dst.dev)) {
David Ahern44750f82018-02-06 13:17:06 -08002787 NL_SET_ERR_MSG(extack,
2788 "Nexthop has invalid gateway or device mismatch");
David Ahernfc1e64e2018-01-25 16:55:09 -08002789 err = -EINVAL;
2790 }
2791
2792 ip6_rt_put(grt);
2793 }
2794
2795 return err;
2796}
2797
David Ahern1edce992018-01-25 16:55:07 -08002798static int ip6_route_check_nh(struct net *net,
2799 struct fib6_config *cfg,
2800 struct net_device **_dev,
2801 struct inet6_dev **idev)
2802{
2803 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2804 struct net_device *dev = _dev ? *_dev : NULL;
2805 struct rt6_info *grt = NULL;
2806 int err = -EHOSTUNREACH;
2807
2808 if (cfg->fc_table) {
David Ahernf4797b32018-01-25 16:55:08 -08002809 int flags = RT6_LOOKUP_F_IFACE;
2810
2811 grt = ip6_nh_lookup_table(net, cfg, gw_addr,
2812 cfg->fc_table, flags);
David Ahern1edce992018-01-25 16:55:07 -08002813 if (grt) {
2814 if (grt->rt6i_flags & RTF_GATEWAY ||
2815 (dev && dev != grt->dst.dev)) {
2816 ip6_rt_put(grt);
2817 grt = NULL;
2818 }
2819 }
2820 }
2821
2822 if (!grt)
David Ahernb75cc8f2018-03-02 08:32:17 -08002823 grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, NULL, 1);
David Ahern1edce992018-01-25 16:55:07 -08002824
2825 if (!grt)
2826 goto out;
2827
2828 if (dev) {
2829 if (dev != grt->dst.dev) {
2830 ip6_rt_put(grt);
2831 goto out;
2832 }
2833 } else {
2834 *_dev = dev = grt->dst.dev;
2835 *idev = grt->rt6i_idev;
2836 dev_hold(dev);
2837 in6_dev_hold(grt->rt6i_idev);
2838 }
2839
2840 if (!(grt->rt6i_flags & RTF_GATEWAY))
2841 err = 0;
2842
2843 ip6_rt_put(grt);
2844
2845out:
2846 return err;
2847}
2848
David Ahern9fbb7042018-03-13 08:29:36 -07002849static int ip6_validate_gw(struct net *net, struct fib6_config *cfg,
2850 struct net_device **_dev, struct inet6_dev **idev,
2851 struct netlink_ext_ack *extack)
2852{
2853 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2854 int gwa_type = ipv6_addr_type(gw_addr);
David Ahern232378e2018-03-13 08:29:37 -07002855 bool skip_dev = gwa_type & IPV6_ADDR_LINKLOCAL ? false : true;
David Ahern9fbb7042018-03-13 08:29:36 -07002856 const struct net_device *dev = *_dev;
David Ahern232378e2018-03-13 08:29:37 -07002857 bool need_addr_check = !dev;
David Ahern9fbb7042018-03-13 08:29:36 -07002858 int err = -EINVAL;
2859
2860 /* if gw_addr is local we will fail to detect this in case
2861 * address is still TENTATIVE (DAD in progress). rt6_lookup()
2862 * will return already-added prefix route via interface that
2863 * prefix route was assigned to, which might be non-loopback.
2864 */
David Ahern232378e2018-03-13 08:29:37 -07002865 if (dev &&
2866 ipv6_chk_addr_and_flags(net, gw_addr, dev, skip_dev, 0, 0)) {
2867 NL_SET_ERR_MSG(extack, "Gateway can not be a local address");
David Ahern9fbb7042018-03-13 08:29:36 -07002868 goto out;
2869 }
2870
2871 if (gwa_type != (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST)) {
2872 /* IPv6 strictly inhibits using not link-local
2873 * addresses as nexthop address.
2874 * Otherwise, router will not able to send redirects.
2875 * It is very good, but in some (rare!) circumstances
2876 * (SIT, PtP, NBMA NOARP links) it is handy to allow
2877 * some exceptions. --ANK
2878 * We allow IPv4-mapped nexthops to support RFC4798-type
2879 * addressing
2880 */
2881 if (!(gwa_type & (IPV6_ADDR_UNICAST | IPV6_ADDR_MAPPED))) {
2882 NL_SET_ERR_MSG(extack, "Invalid gateway address");
2883 goto out;
2884 }
2885
2886 if (cfg->fc_flags & RTNH_F_ONLINK)
2887 err = ip6_route_check_nh_onlink(net, cfg, dev, extack);
2888 else
2889 err = ip6_route_check_nh(net, cfg, _dev, idev);
2890
2891 if (err)
2892 goto out;
2893 }
2894
2895 /* reload in case device was changed */
2896 dev = *_dev;
2897
2898 err = -EINVAL;
2899 if (!dev) {
2900 NL_SET_ERR_MSG(extack, "Egress device not specified");
2901 goto out;
2902 } else if (dev->flags & IFF_LOOPBACK) {
2903 NL_SET_ERR_MSG(extack,
2904 "Egress device can not be loopback device for this route");
2905 goto out;
2906 }
David Ahern232378e2018-03-13 08:29:37 -07002907
2908 /* if we did not check gw_addr above, do so now that the
2909 * egress device has been resolved.
2910 */
2911 if (need_addr_check &&
2912 ipv6_chk_addr_and_flags(net, gw_addr, dev, skip_dev, 0, 0)) {
2913 NL_SET_ERR_MSG(extack, "Gateway can not be a local address");
2914 goto out;
2915 }
2916
David Ahern9fbb7042018-03-13 08:29:36 -07002917 err = 0;
2918out:
2919 return err;
2920}
2921
David Ahern8d1c8022018-04-17 17:33:26 -07002922static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
David Ahernacb54e32018-04-17 17:33:22 -07002923 gfp_t gfp_flags,
David Ahern333c4302017-05-21 10:12:04 -06002924 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925{
Daniel Lezcano55786892008-03-04 13:47:47 -08002926 struct net *net = cfg->fc_nlinfo.nl_net;
David Ahern8d1c8022018-04-17 17:33:26 -07002927 struct fib6_info *rt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 struct net_device *dev = NULL;
2929 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07002930 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 int addr_type;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002932 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933
David Ahern557c44b2017-04-19 14:19:43 -07002934 /* RTF_PCPU is an internal flag; can not be set by userspace */
David Ahernd5d531c2017-05-21 10:12:05 -06002935 if (cfg->fc_flags & RTF_PCPU) {
2936 NL_SET_ERR_MSG(extack, "Userspace can not set RTF_PCPU");
David Ahern557c44b2017-04-19 14:19:43 -07002937 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002938 }
David Ahern557c44b2017-04-19 14:19:43 -07002939
Wei Wang2ea23522017-10-27 17:30:12 -07002940 /* RTF_CACHE is an internal flag; can not be set by userspace */
2941 if (cfg->fc_flags & RTF_CACHE) {
2942 NL_SET_ERR_MSG(extack, "Userspace can not set RTF_CACHE");
2943 goto out;
2944 }
2945
David Aherne8478e82018-04-17 17:33:13 -07002946 if (cfg->fc_type > RTN_MAX) {
2947 NL_SET_ERR_MSG(extack, "Invalid route type");
2948 goto out;
2949 }
2950
David Ahernd5d531c2017-05-21 10:12:05 -06002951 if (cfg->fc_dst_len > 128) {
2952 NL_SET_ERR_MSG(extack, "Invalid prefix length");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002953 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002954 }
2955 if (cfg->fc_src_len > 128) {
2956 NL_SET_ERR_MSG(extack, "Invalid source address length");
2957 goto out;
2958 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959#ifndef CONFIG_IPV6_SUBTREES
David Ahernd5d531c2017-05-21 10:12:05 -06002960 if (cfg->fc_src_len) {
2961 NL_SET_ERR_MSG(extack,
2962 "Specifying source address requires IPV6_SUBTREES to be enabled");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002963 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002964 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07002966 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08002968 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 if (!dev)
2970 goto out;
2971 idev = in6_dev_get(dev);
2972 if (!idev)
2973 goto out;
2974 }
2975
Thomas Graf86872cb2006-08-22 00:01:08 -07002976 if (cfg->fc_metric == 0)
2977 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978
David Ahernfc1e64e2018-01-25 16:55:09 -08002979 if (cfg->fc_flags & RTNH_F_ONLINK) {
2980 if (!dev) {
2981 NL_SET_ERR_MSG(extack,
2982 "Nexthop device required for onlink");
2983 err = -ENODEV;
2984 goto out;
2985 }
2986
2987 if (!(dev->flags & IFF_UP)) {
2988 NL_SET_ERR_MSG(extack, "Nexthop device is not up");
2989 err = -ENETDOWN;
2990 goto out;
2991 }
2992 }
2993
Matti Vaittinend71314b2011-11-14 00:14:49 +00002994 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05002995 if (cfg->fc_nlinfo.nlh &&
2996 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00002997 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05002998 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00002999 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00003000 table = fib6_new_table(net, cfg->fc_table);
3001 }
3002 } else {
3003 table = fib6_new_table(net, cfg->fc_table);
3004 }
David S. Miller38308472011-12-03 18:02:47 -05003005
3006 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07003007 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07003008
David Ahern93531c62018-04-17 17:33:25 -07003009 err = -ENOMEM;
3010 rt = fib6_info_alloc(gfp_flags);
3011 if (!rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 goto out;
David Ahern93531c62018-04-17 17:33:25 -07003013
3014 if (cfg->fc_flags & RTF_ADDRCONF)
3015 rt->dst_nocount = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016
David Ahernd4ead6b2018-04-17 17:33:16 -07003017 err = ip6_convert_metrics(net, rt, cfg);
3018 if (err < 0)
3019 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020
Gao feng1716a962012-04-06 00:13:10 +00003021 if (cfg->fc_flags & RTF_EXPIRES)
David Ahern14895682018-04-17 17:33:17 -07003022 fib6_set_expires(rt, jiffies +
Gao feng1716a962012-04-06 00:13:10 +00003023 clock_t_to_jiffies(cfg->fc_expires));
3024 else
David Ahern14895682018-04-17 17:33:17 -07003025 fib6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026
Thomas Graf86872cb2006-08-22 00:01:08 -07003027 if (cfg->fc_protocol == RTPROT_UNSPEC)
3028 cfg->fc_protocol = RTPROT_BOOT;
David Ahern93c2fb22018-04-18 15:38:59 -07003029 rt->fib6_protocol = cfg->fc_protocol;
Thomas Graf86872cb2006-08-22 00:01:08 -07003030
3031 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003033 if (cfg->fc_encap) {
3034 struct lwtunnel_state *lwtstate;
3035
David Ahern30357d72017-01-30 12:07:37 -08003036 err = lwtunnel_build_state(cfg->fc_encap_type,
Tom Herbert127eb7c2015-08-24 09:45:41 -07003037 cfg->fc_encap, AF_INET6, cfg,
David Ahern9ae28722017-05-27 16:19:28 -06003038 &lwtstate, extack);
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003039 if (err)
3040 goto out;
David Ahern5e670d82018-04-17 17:33:14 -07003041 rt->fib6_nh.nh_lwtstate = lwtstate_get(lwtstate);
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003042 }
3043
David Ahern93c2fb22018-04-18 15:38:59 -07003044 ipv6_addr_prefix(&rt->fib6_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
3045 rt->fib6_dst.plen = cfg->fc_dst_len;
3046 if (rt->fib6_dst.plen == 128)
David Ahern3b6761d2018-04-17 17:33:20 -07003047 rt->dst_host = true;
Michal Kubečeke5fd3872014-03-27 13:04:08 +01003048
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049#ifdef CONFIG_IPV6_SUBTREES
David Ahern93c2fb22018-04-18 15:38:59 -07003050 ipv6_addr_prefix(&rt->fib6_src.addr, &cfg->fc_src, cfg->fc_src_len);
3051 rt->fib6_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052#endif
3053
David Ahern93c2fb22018-04-18 15:38:59 -07003054 rt->fib6_metric = cfg->fc_metric;
David Ahern5e670d82018-04-17 17:33:14 -07003055 rt->fib6_nh.nh_weight = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056
David Aherne8478e82018-04-17 17:33:13 -07003057 rt->fib6_type = cfg->fc_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058
3059 /* We cannot add true routes via loopback here,
3060 they would result in kernel looping; promote them to reject routes
3061 */
Thomas Graf86872cb2006-08-22 00:01:08 -07003062 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05003063 (dev && (dev->flags & IFF_LOOPBACK) &&
3064 !(addr_type & IPV6_ADDR_LOOPBACK) &&
3065 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08003067 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 if (dev) {
3069 dev_put(dev);
3070 in6_dev_put(idev);
3071 }
Daniel Lezcano55786892008-03-04 13:47:47 -08003072 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 dev_hold(dev);
3074 idev = in6_dev_get(dev);
3075 if (!idev) {
3076 err = -ENODEV;
3077 goto out;
3078 }
3079 }
David Ahern93c2fb22018-04-18 15:38:59 -07003080 rt->fib6_flags = RTF_REJECT|RTF_NONEXTHOP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 goto install_route;
3082 }
3083
Thomas Graf86872cb2006-08-22 00:01:08 -07003084 if (cfg->fc_flags & RTF_GATEWAY) {
David Ahern9fbb7042018-03-13 08:29:36 -07003085 err = ip6_validate_gw(net, cfg, &dev, &idev, extack);
3086 if (err)
Florian Westphal48ed7b22015-05-21 00:25:41 +02003087 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088
David Ahern93531c62018-04-17 17:33:25 -07003089 rt->fib6_nh.nh_gw = cfg->fc_gateway;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 }
3091
3092 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05003093 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094 goto out;
3095
Lorenzo Bianconi428604f2018-03-29 11:02:24 +02003096 if (idev->cnf.disable_ipv6) {
3097 NL_SET_ERR_MSG(extack, "IPv6 is disabled on nexthop device");
3098 err = -EACCES;
3099 goto out;
3100 }
3101
David Ahern955ec4c2018-01-24 19:45:29 -08003102 if (!(dev->flags & IFF_UP)) {
3103 NL_SET_ERR_MSG(extack, "Nexthop device is not up");
3104 err = -ENETDOWN;
3105 goto out;
3106 }
3107
Daniel Walterc3968a82011-04-13 21:10:57 +00003108 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
3109 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
David Ahernd5d531c2017-05-21 10:12:05 -06003110 NL_SET_ERR_MSG(extack, "Invalid source address");
Daniel Walterc3968a82011-04-13 21:10:57 +00003111 err = -EINVAL;
3112 goto out;
3113 }
David Ahern93c2fb22018-04-18 15:38:59 -07003114 rt->fib6_prefsrc.addr = cfg->fc_prefsrc;
3115 rt->fib6_prefsrc.plen = 128;
Daniel Walterc3968a82011-04-13 21:10:57 +00003116 } else
David Ahern93c2fb22018-04-18 15:38:59 -07003117 rt->fib6_prefsrc.plen = 0;
Daniel Walterc3968a82011-04-13 21:10:57 +00003118
David Ahern93c2fb22018-04-18 15:38:59 -07003119 rt->fib6_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120
3121install_route:
David Ahern93c2fb22018-04-18 15:38:59 -07003122 if (!(rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) &&
Ido Schimmel5609b802018-01-07 12:45:06 +02003123 !netif_carrier_ok(dev))
David Ahern5e670d82018-04-17 17:33:14 -07003124 rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN;
3125 rt->fib6_nh.nh_flags |= (cfg->fc_flags & RTNH_F_ONLINK);
David Ahern93531c62018-04-17 17:33:25 -07003126 rt->fib6_nh.nh_dev = dev;
David Ahern93c2fb22018-04-18 15:38:59 -07003127 rt->fib6_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08003128
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09003129 cfg->fc_nlinfo.nl_net = dev_net(dev);
Daniel Lezcano63152fc2008-03-03 23:31:11 -08003130
David Aherndcd1f572018-04-18 15:39:05 -07003131 if (idev)
3132 in6_dev_put(idev);
3133
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003134 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135out:
3136 if (dev)
3137 dev_put(dev);
3138 if (idev)
3139 in6_dev_put(idev);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003140
David Ahern93531c62018-04-17 17:33:25 -07003141 fib6_info_release(rt);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003142 return ERR_PTR(err);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003143}
3144
David Ahernacb54e32018-04-17 17:33:22 -07003145int ip6_route_add(struct fib6_config *cfg, gfp_t gfp_flags,
David Ahern333c4302017-05-21 10:12:04 -06003146 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003147{
David Ahern8d1c8022018-04-17 17:33:26 -07003148 struct fib6_info *rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003149 int err;
3150
David Ahernacb54e32018-04-17 17:33:22 -07003151 rt = ip6_route_info_create(cfg, gfp_flags, extack);
David Ahernd4ead6b2018-04-17 17:33:16 -07003152 if (IS_ERR(rt))
3153 return PTR_ERR(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003154
David Ahernd4ead6b2018-04-17 17:33:16 -07003155 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack);
David Ahern93531c62018-04-17 17:33:25 -07003156 fib6_info_release(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003157
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 return err;
3159}
3160
David Ahern8d1c8022018-04-17 17:33:26 -07003161static int __ip6_del_rt(struct fib6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162{
David Ahernafb1d4b52018-04-17 17:33:11 -07003163 struct net *net = info->nl_net;
Thomas Grafc71099a2006-08-04 23:20:06 -07003164 struct fib6_table *table;
David Ahernafb1d4b52018-04-17 17:33:11 -07003165 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166
David Ahern421842e2018-04-17 17:33:18 -07003167 if (rt == net->ipv6.fib6_null_entry) {
Gao feng6825a262012-09-19 19:25:34 +00003168 err = -ENOENT;
3169 goto out;
3170 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07003171
David Ahern93c2fb22018-04-18 15:38:59 -07003172 table = rt->fib6_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003173 spin_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07003174 err = fib6_del(rt, info);
Wei Wang66f5d6c2017-10-06 12:06:10 -07003175 spin_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176
Gao feng6825a262012-09-19 19:25:34 +00003177out:
David Ahern93531c62018-04-17 17:33:25 -07003178 fib6_info_release(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 return err;
3180}
3181
David Ahern8d1c8022018-04-17 17:33:26 -07003182int ip6_del_rt(struct net *net, struct fib6_info *rt)
Thomas Grafe0a1ad732006-08-22 00:00:21 -07003183{
David Ahernafb1d4b52018-04-17 17:33:11 -07003184 struct nl_info info = { .nl_net = net };
3185
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003186 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07003187}
3188
David Ahern8d1c8022018-04-17 17:33:26 -07003189static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg)
David Ahern0ae81332017-02-02 12:37:08 -08003190{
3191 struct nl_info *info = &cfg->fc_nlinfo;
WANG Conge3330032017-02-27 16:07:43 -08003192 struct net *net = info->nl_net;
David Ahern16a16cd2017-02-02 12:37:11 -08003193 struct sk_buff *skb = NULL;
David Ahern0ae81332017-02-02 12:37:08 -08003194 struct fib6_table *table;
WANG Conge3330032017-02-27 16:07:43 -08003195 int err = -ENOENT;
David Ahern0ae81332017-02-02 12:37:08 -08003196
David Ahern421842e2018-04-17 17:33:18 -07003197 if (rt == net->ipv6.fib6_null_entry)
WANG Conge3330032017-02-27 16:07:43 -08003198 goto out_put;
David Ahern93c2fb22018-04-18 15:38:59 -07003199 table = rt->fib6_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003200 spin_lock_bh(&table->tb6_lock);
David Ahern0ae81332017-02-02 12:37:08 -08003201
David Ahern93c2fb22018-04-18 15:38:59 -07003202 if (rt->fib6_nsiblings && cfg->fc_delete_all_nh) {
David Ahern8d1c8022018-04-17 17:33:26 -07003203 struct fib6_info *sibling, *next_sibling;
David Ahern0ae81332017-02-02 12:37:08 -08003204
David Ahern16a16cd2017-02-02 12:37:11 -08003205 /* prefer to send a single notification with all hops */
3206 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
3207 if (skb) {
3208 u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
3209
David Ahernd4ead6b2018-04-17 17:33:16 -07003210 if (rt6_fill_node(net, skb, rt, NULL,
David Ahern16a16cd2017-02-02 12:37:11 -08003211 NULL, NULL, 0, RTM_DELROUTE,
3212 info->portid, seq, 0) < 0) {
3213 kfree_skb(skb);
3214 skb = NULL;
3215 } else
3216 info->skip_notify = 1;
3217 }
3218
David Ahern0ae81332017-02-02 12:37:08 -08003219 list_for_each_entry_safe(sibling, next_sibling,
David Ahern93c2fb22018-04-18 15:38:59 -07003220 &rt->fib6_siblings,
3221 fib6_siblings) {
David Ahern0ae81332017-02-02 12:37:08 -08003222 err = fib6_del(sibling, info);
3223 if (err)
WANG Conge3330032017-02-27 16:07:43 -08003224 goto out_unlock;
David Ahern0ae81332017-02-02 12:37:08 -08003225 }
3226 }
3227
3228 err = fib6_del(rt, info);
WANG Conge3330032017-02-27 16:07:43 -08003229out_unlock:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003230 spin_unlock_bh(&table->tb6_lock);
WANG Conge3330032017-02-27 16:07:43 -08003231out_put:
David Ahern93531c62018-04-17 17:33:25 -07003232 fib6_info_release(rt);
David Ahern16a16cd2017-02-02 12:37:11 -08003233
3234 if (skb) {
WANG Conge3330032017-02-27 16:07:43 -08003235 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
David Ahern16a16cd2017-02-02 12:37:11 -08003236 info->nlh, gfp_any());
3237 }
David Ahern0ae81332017-02-02 12:37:08 -08003238 return err;
3239}
3240
David Ahern23fb93a2018-04-17 17:33:23 -07003241static int ip6_del_cached_rt(struct rt6_info *rt, struct fib6_config *cfg)
3242{
3243 int rc = -ESRCH;
3244
3245 if (cfg->fc_ifindex && rt->dst.dev->ifindex != cfg->fc_ifindex)
3246 goto out;
3247
3248 if (cfg->fc_flags & RTF_GATEWAY &&
3249 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
3250 goto out;
3251 if (dst_hold_safe(&rt->dst))
3252 rc = rt6_remove_exception_rt(rt);
3253out:
3254 return rc;
3255}
3256
David Ahern333c4302017-05-21 10:12:04 -06003257static int ip6_route_del(struct fib6_config *cfg,
3258 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259{
David Ahern8d1c8022018-04-17 17:33:26 -07003260 struct rt6_info *rt_cache;
Thomas Grafc71099a2006-08-04 23:20:06 -07003261 struct fib6_table *table;
David Ahern8d1c8022018-04-17 17:33:26 -07003262 struct fib6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 struct fib6_node *fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 int err = -ESRCH;
3265
Daniel Lezcano55786892008-03-04 13:47:47 -08003266 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David Ahernd5d531c2017-05-21 10:12:05 -06003267 if (!table) {
3268 NL_SET_ERR_MSG(extack, "FIB table does not exist");
Thomas Grafc71099a2006-08-04 23:20:06 -07003269 return err;
David Ahernd5d531c2017-05-21 10:12:05 -06003270 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271
Wei Wang66f5d6c2017-10-06 12:06:10 -07003272 rcu_read_lock();
Thomas Grafc71099a2006-08-04 23:20:06 -07003273
3274 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07003275 &cfg->fc_dst, cfg->fc_dst_len,
Wei Wang38fbeee2017-10-06 12:06:02 -07003276 &cfg->fc_src, cfg->fc_src_len,
Wei Wang2b760fc2017-10-06 12:06:03 -07003277 !(cfg->fc_flags & RTF_CACHE));
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003278
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 if (fn) {
Wei Wang66f5d6c2017-10-06 12:06:10 -07003280 for_each_fib6_node_rt_rcu(fn) {
Wei Wang2b760fc2017-10-06 12:06:03 -07003281 if (cfg->fc_flags & RTF_CACHE) {
David Ahern23fb93a2018-04-17 17:33:23 -07003282 int rc;
3283
Wei Wang2b760fc2017-10-06 12:06:03 -07003284 rt_cache = rt6_find_cached_rt(rt, &cfg->fc_dst,
3285 &cfg->fc_src);
David Ahern23fb93a2018-04-17 17:33:23 -07003286 if (rt_cache) {
3287 rc = ip6_del_cached_rt(rt_cache, cfg);
Eric Dumazet9e575012018-05-09 10:05:46 -07003288 if (rc != -ESRCH) {
3289 rcu_read_unlock();
David Ahern23fb93a2018-04-17 17:33:23 -07003290 return rc;
Eric Dumazet9e575012018-05-09 10:05:46 -07003291 }
David Ahern23fb93a2018-04-17 17:33:23 -07003292 }
3293 continue;
Wei Wang2b760fc2017-10-06 12:06:03 -07003294 }
Thomas Graf86872cb2006-08-22 00:01:08 -07003295 if (cfg->fc_ifindex &&
David Ahern5e670d82018-04-17 17:33:14 -07003296 (!rt->fib6_nh.nh_dev ||
3297 rt->fib6_nh.nh_dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07003299 if (cfg->fc_flags & RTF_GATEWAY &&
David Ahern5e670d82018-04-17 17:33:14 -07003300 !ipv6_addr_equal(&cfg->fc_gateway, &rt->fib6_nh.nh_gw))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07003302 if (cfg->fc_metric && cfg->fc_metric != rt->fib6_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07003304 if (cfg->fc_protocol && cfg->fc_protocol != rt->fib6_protocol)
Mantas Mc2ed1882016-12-16 10:30:59 +02003305 continue;
David Ahern93531c62018-04-17 17:33:25 -07003306 fib6_info_hold(rt);
Wei Wang66f5d6c2017-10-06 12:06:10 -07003307 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308
David Ahern0ae81332017-02-02 12:37:08 -08003309 /* if gateway was specified only delete the one hop */
3310 if (cfg->fc_flags & RTF_GATEWAY)
3311 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
3312
3313 return __ip6_del_rt_siblings(rt, cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 }
3315 }
Wei Wang66f5d6c2017-10-06 12:06:10 -07003316 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317
3318 return err;
3319}
3320
David S. Miller6700c272012-07-17 03:29:28 -07003321static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07003322{
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07003323 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07003324 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07003325 struct ndisc_options ndopts;
3326 struct inet6_dev *in6_dev;
3327 struct neighbour *neigh;
David Aherna68886a2018-04-20 15:38:02 -07003328 struct fib6_info *from;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003329 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07003330 int optlen, on_link;
3331 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07003332
Simon Horman29a3cad2013-05-28 20:34:26 +00003333 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003334 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07003335
3336 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07003337 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003338 return;
3339 }
3340
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003341 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07003342
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003343 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07003344 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003345 return;
3346 }
3347
David S. Miller6e157b62012-07-12 00:05:02 -07003348 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003349 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07003350 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003351 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07003352 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07003353 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003354 return;
3355 }
3356
3357 in6_dev = __in6_dev_get(skb->dev);
3358 if (!in6_dev)
3359 return;
3360 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
3361 return;
3362
3363 /* RFC2461 8.1:
3364 * The IP source address of the Redirect MUST be the same as the current
3365 * first-hop router for the specified ICMP Destination Address.
3366 */
3367
Alexander Aringf997c552016-06-15 21:20:23 +02003368 if (!ndisc_parse_options(skb->dev, msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07003369 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
3370 return;
3371 }
David S. Miller6e157b62012-07-12 00:05:02 -07003372
3373 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07003374 if (ndopts.nd_opts_tgt_lladdr) {
3375 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
3376 skb->dev);
3377 if (!lladdr) {
3378 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
3379 return;
3380 }
3381 }
3382
David S. Miller6e157b62012-07-12 00:05:02 -07003383 rt = (struct rt6_info *) dst;
Matthias Schifferec13ad12015-11-02 01:24:38 +01003384 if (rt->rt6i_flags & RTF_REJECT) {
David S. Miller6e157b62012-07-12 00:05:02 -07003385 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
3386 return;
3387 }
3388
3389 /* Redirect received -> path was valid.
3390 * Look, redirects are sent only in response to data packets,
3391 * so that this nexthop apparently is reachable. --ANK
3392 */
Julian Anastasov0dec8792017-02-06 23:14:16 +02003393 dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
David S. Miller6e157b62012-07-12 00:05:02 -07003394
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003395 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07003396 if (!neigh)
3397 return;
3398
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 /*
3400 * We have finally decided to accept it.
3401 */
3402
Alexander Aringf997c552016-06-15 21:20:23 +02003403 ndisc_update(skb->dev, neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 NEIGH_UPDATE_F_WEAK_OVERRIDE|
3405 NEIGH_UPDATE_F_OVERRIDE|
3406 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
Alexander Aringf997c552016-06-15 21:20:23 +02003407 NEIGH_UPDATE_F_ISROUTER)),
3408 NDISC_REDIRECT, &ndopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409
David Ahern4d85cd02018-04-20 15:37:59 -07003410 rcu_read_lock();
David Aherna68886a2018-04-20 15:38:02 -07003411 from = rcu_dereference(rt->from);
David Ahern8a14e462018-04-23 11:32:07 -07003412 fib6_info_hold(from);
David Ahern4d85cd02018-04-20 15:37:59 -07003413 rcu_read_unlock();
David Ahern8a14e462018-04-23 11:32:07 -07003414
3415 nrt = ip6_rt_cache_alloc(from, &msg->dest, NULL);
David S. Miller38308472011-12-03 18:02:47 -05003416 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 goto out;
3418
3419 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
3420 if (on_link)
3421 nrt->rt6i_flags &= ~RTF_GATEWAY;
3422
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003423 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424
Wei Wang2b760fc2017-10-06 12:06:03 -07003425 /* No need to remove rt from the exception table if rt is
3426 * a cached route because rt6_insert_exception() will
3427 * takes care of it
3428 */
David Ahern8a14e462018-04-23 11:32:07 -07003429 if (rt6_insert_exception(nrt, from)) {
Wei Wang2b760fc2017-10-06 12:06:03 -07003430 dst_release_immediate(&nrt->dst);
3431 goto out;
3432 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433
Changli Gaod8d1f302010-06-10 23:31:35 -07003434 netevent.old = &rt->dst;
3435 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003436 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00003437 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07003438 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
3439
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440out:
David Ahern8a14e462018-04-23 11:32:07 -07003441 fib6_info_release(from);
David S. Millere8599ff2012-07-11 23:43:53 -07003442 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07003443}
3444
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003445#ifdef CONFIG_IPV6_ROUTE_INFO
David Ahern8d1c8022018-04-17 17:33:26 -07003446static struct fib6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00003447 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07003448 const struct in6_addr *gwaddr,
3449 struct net_device *dev)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003450{
David Ahern830218c2016-10-24 10:52:35 -07003451 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO;
3452 int ifindex = dev->ifindex;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003453 struct fib6_node *fn;
David Ahern8d1c8022018-04-17 17:33:26 -07003454 struct fib6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07003455 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003456
David Ahern830218c2016-10-24 10:52:35 -07003457 table = fib6_get_table(net, tb_id);
David S. Miller38308472011-12-03 18:02:47 -05003458 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07003459 return NULL;
3460
Wei Wang66f5d6c2017-10-06 12:06:10 -07003461 rcu_read_lock();
Wei Wang38fbeee2017-10-06 12:06:02 -07003462 fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0, true);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003463 if (!fn)
3464 goto out;
3465
Wei Wang66f5d6c2017-10-06 12:06:10 -07003466 for_each_fib6_node_rt_rcu(fn) {
David Ahern5e670d82018-04-17 17:33:14 -07003467 if (rt->fib6_nh.nh_dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003468 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07003469 if ((rt->fib6_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003470 continue;
David Ahern5e670d82018-04-17 17:33:14 -07003471 if (!ipv6_addr_equal(&rt->fib6_nh.nh_gw, gwaddr))
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003472 continue;
David Ahern8d1c8022018-04-17 17:33:26 -07003473 fib6_info_hold(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003474 break;
3475 }
3476out:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003477 rcu_read_unlock();
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003478 return rt;
3479}
3480
David Ahern8d1c8022018-04-17 17:33:26 -07003481static struct fib6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00003482 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07003483 const struct in6_addr *gwaddr,
3484 struct net_device *dev,
Eric Dumazet95c96172012-04-15 05:58:06 +00003485 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003486{
Thomas Graf86872cb2006-08-22 00:01:08 -07003487 struct fib6_config cfg = {
Rami Rosen238fc7e2008-02-09 23:43:11 -08003488 .fc_metric = IP6_RT_PRIO_USER,
David Ahern830218c2016-10-24 10:52:35 -07003489 .fc_ifindex = dev->ifindex,
Thomas Graf86872cb2006-08-22 00:01:08 -07003490 .fc_dst_len = prefixlen,
3491 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
3492 RTF_UP | RTF_PREF(pref),
Xin Longb91d5322017-08-03 14:13:46 +08003493 .fc_protocol = RTPROT_RA,
David Aherne8478e82018-04-17 17:33:13 -07003494 .fc_type = RTN_UNICAST,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003495 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08003496 .fc_nlinfo.nlh = NULL,
3497 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07003498 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003499
David Ahern830218c2016-10-24 10:52:35 -07003500 cfg.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO,
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003501 cfg.fc_dst = *prefix;
3502 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07003503
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08003504 /* We should treat it as a default route if prefix length is 0. */
3505 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07003506 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003507
David Ahernacb54e32018-04-17 17:33:22 -07003508 ip6_route_add(&cfg, GFP_ATOMIC, NULL);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003509
David Ahern830218c2016-10-24 10:52:35 -07003510 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003511}
3512#endif
3513
David Ahern8d1c8022018-04-17 17:33:26 -07003514struct fib6_info *rt6_get_dflt_router(struct net *net,
David Ahernafb1d4b52018-04-17 17:33:11 -07003515 const struct in6_addr *addr,
3516 struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003517{
David Ahern830218c2016-10-24 10:52:35 -07003518 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT;
David Ahern8d1c8022018-04-17 17:33:26 -07003519 struct fib6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07003520 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521
David Ahernafb1d4b52018-04-17 17:33:11 -07003522 table = fib6_get_table(net, tb_id);
David S. Miller38308472011-12-03 18:02:47 -05003523 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07003524 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525
Wei Wang66f5d6c2017-10-06 12:06:10 -07003526 rcu_read_lock();
3527 for_each_fib6_node_rt_rcu(&table->tb6_root) {
David Ahern5e670d82018-04-17 17:33:14 -07003528 if (dev == rt->fib6_nh.nh_dev &&
David Ahern93c2fb22018-04-18 15:38:59 -07003529 ((rt->fib6_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
David Ahern5e670d82018-04-17 17:33:14 -07003530 ipv6_addr_equal(&rt->fib6_nh.nh_gw, addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 break;
3532 }
3533 if (rt)
David Ahern8d1c8022018-04-17 17:33:26 -07003534 fib6_info_hold(rt);
Wei Wang66f5d6c2017-10-06 12:06:10 -07003535 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536 return rt;
3537}
3538
David Ahern8d1c8022018-04-17 17:33:26 -07003539struct fib6_info *rt6_add_dflt_router(struct net *net,
David Ahernafb1d4b52018-04-17 17:33:11 -07003540 const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08003541 struct net_device *dev,
3542 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543{
Thomas Graf86872cb2006-08-22 00:01:08 -07003544 struct fib6_config cfg = {
David Ahernca254492015-10-12 11:47:10 -07003545 .fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08003546 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07003547 .fc_ifindex = dev->ifindex,
3548 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
3549 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Xin Longb91d5322017-08-03 14:13:46 +08003550 .fc_protocol = RTPROT_RA,
David Aherne8478e82018-04-17 17:33:13 -07003551 .fc_type = RTN_UNICAST,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003552 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08003553 .fc_nlinfo.nlh = NULL,
David Ahernafb1d4b52018-04-17 17:33:11 -07003554 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07003555 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003557 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558
David Ahernacb54e32018-04-17 17:33:22 -07003559 if (!ip6_route_add(&cfg, GFP_ATOMIC, NULL)) {
David Ahern830218c2016-10-24 10:52:35 -07003560 struct fib6_table *table;
3561
3562 table = fib6_get_table(dev_net(dev), cfg.fc_table);
3563 if (table)
3564 table->flags |= RT6_TABLE_HAS_DFLT_ROUTER;
3565 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566
David Ahernafb1d4b52018-04-17 17:33:11 -07003567 return rt6_get_dflt_router(net, gwaddr, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568}
3569
David Ahernafb1d4b52018-04-17 17:33:11 -07003570static void __rt6_purge_dflt_routers(struct net *net,
3571 struct fib6_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572{
David Ahern8d1c8022018-04-17 17:33:26 -07003573 struct fib6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574
3575restart:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003576 rcu_read_lock();
3577 for_each_fib6_node_rt_rcu(&table->tb6_root) {
David Aherndcd1f572018-04-18 15:39:05 -07003578 struct net_device *dev = fib6_info_nh_dev(rt);
3579 struct inet6_dev *idev = dev ? __in6_dev_get(dev) : NULL;
3580
David Ahern93c2fb22018-04-18 15:38:59 -07003581 if (rt->fib6_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
David Aherndcd1f572018-04-18 15:39:05 -07003582 (!idev || idev->cnf.accept_ra != 2)) {
David Ahern93531c62018-04-17 17:33:25 -07003583 fib6_info_hold(rt);
3584 rcu_read_unlock();
3585 ip6_del_rt(net, rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586 goto restart;
3587 }
3588 }
Wei Wang66f5d6c2017-10-06 12:06:10 -07003589 rcu_read_unlock();
David Ahern830218c2016-10-24 10:52:35 -07003590
3591 table->flags &= ~RT6_TABLE_HAS_DFLT_ROUTER;
3592}
3593
3594void rt6_purge_dflt_routers(struct net *net)
3595{
3596 struct fib6_table *table;
3597 struct hlist_head *head;
3598 unsigned int h;
3599
3600 rcu_read_lock();
3601
3602 for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
3603 head = &net->ipv6.fib_table_hash[h];
3604 hlist_for_each_entry_rcu(table, head, tb6_hlist) {
3605 if (table->flags & RT6_TABLE_HAS_DFLT_ROUTER)
David Ahernafb1d4b52018-04-17 17:33:11 -07003606 __rt6_purge_dflt_routers(net, table);
David Ahern830218c2016-10-24 10:52:35 -07003607 }
3608 }
3609
3610 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611}
3612
Daniel Lezcano55786892008-03-04 13:47:47 -08003613static void rtmsg_to_fib6_config(struct net *net,
3614 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07003615 struct fib6_config *cfg)
3616{
3617 memset(cfg, 0, sizeof(*cfg));
3618
David Ahernca254492015-10-12 11:47:10 -07003619 cfg->fc_table = l3mdev_fib_table_by_index(net, rtmsg->rtmsg_ifindex) ?
3620 : RT6_TABLE_MAIN;
Thomas Graf86872cb2006-08-22 00:01:08 -07003621 cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
3622 cfg->fc_metric = rtmsg->rtmsg_metric;
3623 cfg->fc_expires = rtmsg->rtmsg_info;
3624 cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
3625 cfg->fc_src_len = rtmsg->rtmsg_src_len;
3626 cfg->fc_flags = rtmsg->rtmsg_flags;
David Aherne8478e82018-04-17 17:33:13 -07003627 cfg->fc_type = rtmsg->rtmsg_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07003628
Daniel Lezcano55786892008-03-04 13:47:47 -08003629 cfg->fc_nlinfo.nl_net = net;
Benjamin Theryf1243c22008-02-26 18:10:03 -08003630
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003631 cfg->fc_dst = rtmsg->rtmsg_dst;
3632 cfg->fc_src = rtmsg->rtmsg_src;
3633 cfg->fc_gateway = rtmsg->rtmsg_gateway;
Thomas Graf86872cb2006-08-22 00:01:08 -07003634}
3635
Daniel Lezcano55786892008-03-04 13:47:47 -08003636int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637{
Thomas Graf86872cb2006-08-22 00:01:08 -07003638 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639 struct in6_rtmsg rtmsg;
3640 int err;
3641
Ian Morris67ba4152014-08-24 21:53:10 +01003642 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643 case SIOCADDRT: /* Add a route */
3644 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00003645 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 return -EPERM;
3647 err = copy_from_user(&rtmsg, arg,
3648 sizeof(struct in6_rtmsg));
3649 if (err)
3650 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07003651
Daniel Lezcano55786892008-03-04 13:47:47 -08003652 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07003653
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 rtnl_lock();
3655 switch (cmd) {
3656 case SIOCADDRT:
David Ahernacb54e32018-04-17 17:33:22 -07003657 err = ip6_route_add(&cfg, GFP_KERNEL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658 break;
3659 case SIOCDELRT:
David Ahern333c4302017-05-21 10:12:04 -06003660 err = ip6_route_del(&cfg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 break;
3662 default:
3663 err = -EINVAL;
3664 }
3665 rtnl_unlock();
3666
3667 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07003668 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669
3670 return -EINVAL;
3671}
3672
3673/*
3674 * Drop the packet on the floor
3675 */
3676
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07003677static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003679 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00003680 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003681 switch (ipstats_mib_noroutes) {
3682 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07003683 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00003684 if (type == IPV6_ADDR_ANY) {
Stephen Suryaputrabdb7cc62018-04-16 13:42:16 -04003685 IP6_INC_STATS(dev_net(dst->dev),
3686 __in6_dev_get_safely(skb->dev),
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07003687 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003688 break;
3689 }
3690 /* FALLTHROUGH */
3691 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07003692 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
3693 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003694 break;
3695 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00003696 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697 kfree_skb(skb);
3698 return 0;
3699}
3700
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003701static int ip6_pkt_discard(struct sk_buff *skb)
3702{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003703 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003704}
3705
Eric W. Biedermanede20592015-10-07 16:48:47 -05003706static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707{
Eric Dumazetadf30902009-06-02 05:19:30 +00003708 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003709 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710}
3711
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003712static int ip6_pkt_prohibit(struct sk_buff *skb)
3713{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003714 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003715}
3716
Eric W. Biedermanede20592015-10-07 16:48:47 -05003717static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003718{
Eric Dumazetadf30902009-06-02 05:19:30 +00003719 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003720 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003721}
3722
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723/*
3724 * Allocate a dst for local (unicast / anycast) address.
3725 */
3726
David Ahern360a9882018-04-18 15:39:00 -07003727struct fib6_info *addrconf_f6i_alloc(struct net *net,
3728 struct inet6_dev *idev,
3729 const struct in6_addr *addr,
3730 bool anycast, gfp_t gfp_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731{
David Ahernca254492015-10-12 11:47:10 -07003732 u32 tb_id;
David Ahern4832c302017-08-17 12:17:20 -07003733 struct net_device *dev = idev->dev;
David Ahern360a9882018-04-18 15:39:00 -07003734 struct fib6_info *f6i;
David Ahern5f02ce242016-09-10 12:09:54 -07003735
David Ahern360a9882018-04-18 15:39:00 -07003736 f6i = fib6_info_alloc(gfp_flags);
3737 if (!f6i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738 return ERR_PTR(-ENOMEM);
3739
David Ahern360a9882018-04-18 15:39:00 -07003740 f6i->dst_nocount = true;
David Ahern360a9882018-04-18 15:39:00 -07003741 f6i->dst_host = true;
3742 f6i->fib6_protocol = RTPROT_KERNEL;
3743 f6i->fib6_flags = RTF_UP | RTF_NONEXTHOP;
David Aherne8478e82018-04-17 17:33:13 -07003744 if (anycast) {
David Ahern360a9882018-04-18 15:39:00 -07003745 f6i->fib6_type = RTN_ANYCAST;
3746 f6i->fib6_flags |= RTF_ANYCAST;
David Aherne8478e82018-04-17 17:33:13 -07003747 } else {
David Ahern360a9882018-04-18 15:39:00 -07003748 f6i->fib6_type = RTN_LOCAL;
3749 f6i->fib6_flags |= RTF_LOCAL;
David Aherne8478e82018-04-17 17:33:13 -07003750 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751
David Ahern360a9882018-04-18 15:39:00 -07003752 f6i->fib6_nh.nh_gw = *addr;
David Ahern93531c62018-04-17 17:33:25 -07003753 dev_hold(dev);
David Ahern360a9882018-04-18 15:39:00 -07003754 f6i->fib6_nh.nh_dev = dev;
3755 f6i->fib6_dst.addr = *addr;
3756 f6i->fib6_dst.plen = 128;
David Ahernca254492015-10-12 11:47:10 -07003757 tb_id = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL;
David Ahern360a9882018-04-18 15:39:00 -07003758 f6i->fib6_table = fib6_get_table(net, tb_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759
David Ahern360a9882018-04-18 15:39:00 -07003760 return f6i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761}
3762
Daniel Walterc3968a82011-04-13 21:10:57 +00003763/* remove deleted ip from prefsrc entries */
3764struct arg_dev_net_ip {
3765 struct net_device *dev;
3766 struct net *net;
3767 struct in6_addr *addr;
3768};
3769
David Ahern8d1c8022018-04-17 17:33:26 -07003770static int fib6_remove_prefsrc(struct fib6_info *rt, void *arg)
Daniel Walterc3968a82011-04-13 21:10:57 +00003771{
3772 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
3773 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
3774 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
3775
David Ahern5e670d82018-04-17 17:33:14 -07003776 if (((void *)rt->fib6_nh.nh_dev == dev || !dev) &&
David Ahern421842e2018-04-17 17:33:18 -07003777 rt != net->ipv6.fib6_null_entry &&
David Ahern93c2fb22018-04-18 15:38:59 -07003778 ipv6_addr_equal(addr, &rt->fib6_prefsrc.addr)) {
Wei Wang60006a42017-10-06 12:05:58 -07003779 spin_lock_bh(&rt6_exception_lock);
Daniel Walterc3968a82011-04-13 21:10:57 +00003780 /* remove prefsrc entry */
David Ahern93c2fb22018-04-18 15:38:59 -07003781 rt->fib6_prefsrc.plen = 0;
Wei Wang60006a42017-10-06 12:05:58 -07003782 /* need to update cache as well */
3783 rt6_exceptions_remove_prefsrc(rt);
3784 spin_unlock_bh(&rt6_exception_lock);
Daniel Walterc3968a82011-04-13 21:10:57 +00003785 }
3786 return 0;
3787}
3788
3789void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
3790{
3791 struct net *net = dev_net(ifp->idev->dev);
3792 struct arg_dev_net_ip adni = {
3793 .dev = ifp->idev->dev,
3794 .net = net,
3795 .addr = &ifp->addr,
3796 };
Li RongQing0c3584d2013-12-27 16:32:38 +08003797 fib6_clean_all(net, fib6_remove_prefsrc, &adni);
Daniel Walterc3968a82011-04-13 21:10:57 +00003798}
3799
Duan Jiongbe7a0102014-05-15 15:56:14 +08003800#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY)
Duan Jiongbe7a0102014-05-15 15:56:14 +08003801
3802/* Remove routers and update dst entries when gateway turn into host. */
David Ahern8d1c8022018-04-17 17:33:26 -07003803static int fib6_clean_tohost(struct fib6_info *rt, void *arg)
Duan Jiongbe7a0102014-05-15 15:56:14 +08003804{
3805 struct in6_addr *gateway = (struct in6_addr *)arg;
3806
David Ahern93c2fb22018-04-18 15:38:59 -07003807 if (((rt->fib6_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) &&
David Ahern5e670d82018-04-17 17:33:14 -07003808 ipv6_addr_equal(gateway, &rt->fib6_nh.nh_gw)) {
Duan Jiongbe7a0102014-05-15 15:56:14 +08003809 return -1;
3810 }
Wei Wangb16cb452017-10-06 12:06:00 -07003811
3812 /* Further clean up cached routes in exception table.
3813 * This is needed because cached route may have a different
3814 * gateway than its 'parent' in the case of an ip redirect.
3815 */
3816 rt6_exceptions_clean_tohost(rt, gateway);
3817
Duan Jiongbe7a0102014-05-15 15:56:14 +08003818 return 0;
3819}
3820
3821void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
3822{
3823 fib6_clean_all(net, fib6_clean_tohost, gateway);
3824}
3825
Ido Schimmel2127d952018-01-07 12:45:03 +02003826struct arg_netdev_event {
3827 const struct net_device *dev;
Ido Schimmel4c981e22018-01-07 12:45:04 +02003828 union {
3829 unsigned int nh_flags;
3830 unsigned long event;
3831 };
Ido Schimmel2127d952018-01-07 12:45:03 +02003832};
3833
David Ahern8d1c8022018-04-17 17:33:26 -07003834static struct fib6_info *rt6_multipath_first_sibling(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003835{
David Ahern8d1c8022018-04-17 17:33:26 -07003836 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003837 struct fib6_node *fn;
3838
David Ahern93c2fb22018-04-18 15:38:59 -07003839 fn = rcu_dereference_protected(rt->fib6_node,
3840 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003841 iter = rcu_dereference_protected(fn->leaf,
David Ahern93c2fb22018-04-18 15:38:59 -07003842 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003843 while (iter) {
David Ahern93c2fb22018-04-18 15:38:59 -07003844 if (iter->fib6_metric == rt->fib6_metric &&
David Ahernf34436a2018-05-21 10:26:53 -07003845 iter->fib6_nsiblings)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003846 return iter;
David Ahern8fb11a92018-05-04 13:54:24 -07003847 iter = rcu_dereference_protected(iter->fib6_next,
David Ahern93c2fb22018-04-18 15:38:59 -07003848 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003849 }
3850
3851 return NULL;
3852}
3853
David Ahern8d1c8022018-04-17 17:33:26 -07003854static bool rt6_is_dead(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003855{
David Ahern5e670d82018-04-17 17:33:14 -07003856 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD ||
3857 (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN &&
David Aherndcd1f572018-04-18 15:39:05 -07003858 fib6_ignore_linkdown(rt)))
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003859 return true;
3860
3861 return false;
3862}
3863
David Ahern8d1c8022018-04-17 17:33:26 -07003864static int rt6_multipath_total_weight(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003865{
David Ahern8d1c8022018-04-17 17:33:26 -07003866 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003867 int total = 0;
3868
3869 if (!rt6_is_dead(rt))
David Ahern5e670d82018-04-17 17:33:14 -07003870 total += rt->fib6_nh.nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003871
David Ahern93c2fb22018-04-18 15:38:59 -07003872 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) {
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003873 if (!rt6_is_dead(iter))
David Ahern5e670d82018-04-17 17:33:14 -07003874 total += iter->fib6_nh.nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003875 }
3876
3877 return total;
3878}
3879
David Ahern8d1c8022018-04-17 17:33:26 -07003880static void rt6_upper_bound_set(struct fib6_info *rt, int *weight, int total)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003881{
3882 int upper_bound = -1;
3883
3884 if (!rt6_is_dead(rt)) {
David Ahern5e670d82018-04-17 17:33:14 -07003885 *weight += rt->fib6_nh.nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003886 upper_bound = DIV_ROUND_CLOSEST_ULL((u64) (*weight) << 31,
3887 total) - 1;
3888 }
David Ahern5e670d82018-04-17 17:33:14 -07003889 atomic_set(&rt->fib6_nh.nh_upper_bound, upper_bound);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003890}
3891
David Ahern8d1c8022018-04-17 17:33:26 -07003892static void rt6_multipath_upper_bound_set(struct fib6_info *rt, int total)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003893{
David Ahern8d1c8022018-04-17 17:33:26 -07003894 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003895 int weight = 0;
3896
3897 rt6_upper_bound_set(rt, &weight, total);
3898
David Ahern93c2fb22018-04-18 15:38:59 -07003899 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003900 rt6_upper_bound_set(iter, &weight, total);
3901}
3902
David Ahern8d1c8022018-04-17 17:33:26 -07003903void rt6_multipath_rebalance(struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003904{
David Ahern8d1c8022018-04-17 17:33:26 -07003905 struct fib6_info *first;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003906 int total;
3907
3908 /* In case the entire multipath route was marked for flushing,
3909 * then there is no need to rebalance upon the removal of every
3910 * sibling route.
3911 */
David Ahern93c2fb22018-04-18 15:38:59 -07003912 if (!rt->fib6_nsiblings || rt->should_flush)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003913 return;
3914
3915 /* During lookup routes are evaluated in order, so we need to
3916 * make sure upper bounds are assigned from the first sibling
3917 * onwards.
3918 */
3919 first = rt6_multipath_first_sibling(rt);
3920 if (WARN_ON_ONCE(!first))
3921 return;
3922
3923 total = rt6_multipath_total_weight(first);
3924 rt6_multipath_upper_bound_set(first, total);
3925}
3926
David Ahern8d1c8022018-04-17 17:33:26 -07003927static int fib6_ifup(struct fib6_info *rt, void *p_arg)
Ido Schimmel2127d952018-01-07 12:45:03 +02003928{
3929 const struct arg_netdev_event *arg = p_arg;
David Ahern7aef6852018-04-17 17:33:10 -07003930 struct net *net = dev_net(arg->dev);
Ido Schimmel2127d952018-01-07 12:45:03 +02003931
David Ahern421842e2018-04-17 17:33:18 -07003932 if (rt != net->ipv6.fib6_null_entry && rt->fib6_nh.nh_dev == arg->dev) {
David Ahern5e670d82018-04-17 17:33:14 -07003933 rt->fib6_nh.nh_flags &= ~arg->nh_flags;
David Ahern7aef6852018-04-17 17:33:10 -07003934 fib6_update_sernum_upto_root(net, rt);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003935 rt6_multipath_rebalance(rt);
Ido Schimmel1de178e2018-01-07 12:45:15 +02003936 }
Ido Schimmel2127d952018-01-07 12:45:03 +02003937
3938 return 0;
3939}
3940
3941void rt6_sync_up(struct net_device *dev, unsigned int nh_flags)
3942{
3943 struct arg_netdev_event arg = {
3944 .dev = dev,
Ido Schimmel6802f3a2018-01-12 22:07:36 +02003945 {
3946 .nh_flags = nh_flags,
3947 },
Ido Schimmel2127d952018-01-07 12:45:03 +02003948 };
3949
3950 if (nh_flags & RTNH_F_DEAD && netif_carrier_ok(dev))
3951 arg.nh_flags |= RTNH_F_LINKDOWN;
3952
3953 fib6_clean_all(dev_net(dev), fib6_ifup, &arg);
3954}
3955
David Ahern8d1c8022018-04-17 17:33:26 -07003956static bool rt6_multipath_uses_dev(const struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02003957 const struct net_device *dev)
3958{
David Ahern8d1c8022018-04-17 17:33:26 -07003959 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003960
David Ahern5e670d82018-04-17 17:33:14 -07003961 if (rt->fib6_nh.nh_dev == dev)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003962 return true;
David Ahern93c2fb22018-04-18 15:38:59 -07003963 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahern5e670d82018-04-17 17:33:14 -07003964 if (iter->fib6_nh.nh_dev == dev)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003965 return true;
3966
3967 return false;
3968}
3969
David Ahern8d1c8022018-04-17 17:33:26 -07003970static void rt6_multipath_flush(struct fib6_info *rt)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003971{
David Ahern8d1c8022018-04-17 17:33:26 -07003972 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003973
3974 rt->should_flush = 1;
David Ahern93c2fb22018-04-18 15:38:59 -07003975 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003976 iter->should_flush = 1;
3977}
3978
David Ahern8d1c8022018-04-17 17:33:26 -07003979static unsigned int rt6_multipath_dead_count(const struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02003980 const struct net_device *down_dev)
3981{
David Ahern8d1c8022018-04-17 17:33:26 -07003982 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003983 unsigned int dead = 0;
3984
David Ahern5e670d82018-04-17 17:33:14 -07003985 if (rt->fib6_nh.nh_dev == down_dev ||
3986 rt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003987 dead++;
David Ahern93c2fb22018-04-18 15:38:59 -07003988 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahern5e670d82018-04-17 17:33:14 -07003989 if (iter->fib6_nh.nh_dev == down_dev ||
3990 iter->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003991 dead++;
3992
3993 return dead;
3994}
3995
David Ahern8d1c8022018-04-17 17:33:26 -07003996static void rt6_multipath_nh_flags_set(struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02003997 const struct net_device *dev,
3998 unsigned int nh_flags)
3999{
David Ahern8d1c8022018-04-17 17:33:26 -07004000 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02004001
David Ahern5e670d82018-04-17 17:33:14 -07004002 if (rt->fib6_nh.nh_dev == dev)
4003 rt->fib6_nh.nh_flags |= nh_flags;
David Ahern93c2fb22018-04-18 15:38:59 -07004004 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahern5e670d82018-04-17 17:33:14 -07004005 if (iter->fib6_nh.nh_dev == dev)
4006 iter->fib6_nh.nh_flags |= nh_flags;
Ido Schimmel1de178e2018-01-07 12:45:15 +02004007}
4008
David Aherna1a22c12017-01-18 07:40:36 -08004009/* called with write lock held for table with rt */
David Ahern8d1c8022018-04-17 17:33:26 -07004010static int fib6_ifdown(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011{
Ido Schimmel4c981e22018-01-07 12:45:04 +02004012 const struct arg_netdev_event *arg = p_arg;
4013 const struct net_device *dev = arg->dev;
David Ahern7aef6852018-04-17 17:33:10 -07004014 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004015
David Ahern421842e2018-04-17 17:33:18 -07004016 if (rt == net->ipv6.fib6_null_entry)
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004017 return 0;
4018
4019 switch (arg->event) {
4020 case NETDEV_UNREGISTER:
David Ahern5e670d82018-04-17 17:33:14 -07004021 return rt->fib6_nh.nh_dev == dev ? -1 : 0;
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004022 case NETDEV_DOWN:
Ido Schimmel1de178e2018-01-07 12:45:15 +02004023 if (rt->should_flush)
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004024 return -1;
David Ahern93c2fb22018-04-18 15:38:59 -07004025 if (!rt->fib6_nsiblings)
David Ahern5e670d82018-04-17 17:33:14 -07004026 return rt->fib6_nh.nh_dev == dev ? -1 : 0;
Ido Schimmel1de178e2018-01-07 12:45:15 +02004027 if (rt6_multipath_uses_dev(rt, dev)) {
4028 unsigned int count;
4029
4030 count = rt6_multipath_dead_count(rt, dev);
David Ahern93c2fb22018-04-18 15:38:59 -07004031 if (rt->fib6_nsiblings + 1 == count) {
Ido Schimmel1de178e2018-01-07 12:45:15 +02004032 rt6_multipath_flush(rt);
4033 return -1;
4034 }
4035 rt6_multipath_nh_flags_set(rt, dev, RTNH_F_DEAD |
4036 RTNH_F_LINKDOWN);
David Ahern7aef6852018-04-17 17:33:10 -07004037 fib6_update_sernum(net, rt);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02004038 rt6_multipath_rebalance(rt);
Ido Schimmel1de178e2018-01-07 12:45:15 +02004039 }
4040 return -2;
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004041 case NETDEV_CHANGE:
David Ahern5e670d82018-04-17 17:33:14 -07004042 if (rt->fib6_nh.nh_dev != dev ||
David Ahern93c2fb22018-04-18 15:38:59 -07004043 rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST))
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004044 break;
David Ahern5e670d82018-04-17 17:33:14 -07004045 rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02004046 rt6_multipath_rebalance(rt);
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004047 break;
Ido Schimmel2b241362018-01-07 12:45:02 +02004048 }
David S. Millerc159d302011-12-26 15:24:36 -05004049
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 return 0;
4051}
4052
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004053void rt6_sync_down_dev(struct net_device *dev, unsigned long event)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054{
Ido Schimmel4c981e22018-01-07 12:45:04 +02004055 struct arg_netdev_event arg = {
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004056 .dev = dev,
Ido Schimmel6802f3a2018-01-12 22:07:36 +02004057 {
4058 .event = event,
4059 },
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004060 };
4061
Ido Schimmel4c981e22018-01-07 12:45:04 +02004062 fib6_clean_all(dev_net(dev), fib6_ifdown, &arg);
4063}
4064
4065void rt6_disable_ip(struct net_device *dev, unsigned long event)
4066{
4067 rt6_sync_down_dev(dev, event);
4068 rt6_uncached_list_flush_dev(dev_net(dev), dev);
4069 neigh_ifdown(&nd_tbl, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070}
4071
Eric Dumazet95c96172012-04-15 05:58:06 +00004072struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00004074 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075};
4076
David Ahern8d1c8022018-04-17 17:33:26 -07004077static int rt6_mtu_change_route(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078{
4079 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
4080 struct inet6_dev *idev;
4081
4082 /* In IPv6 pmtu discovery is not optional,
4083 so that RTAX_MTU lock cannot disable it.
4084 We still use this lock to block changes
4085 caused by addrconf/ndisc.
4086 */
4087
4088 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05004089 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090 return 0;
4091
4092 /* For administrative MTU increase, there is no way to discover
4093 IPv6 PMTU increase, so PMTU increase should be updated here.
4094 Since RFC 1981 doesn't include administrative MTU increase
4095 update PMTU increase is a MUST. (i.e. jumbo frame)
4096 */
David Ahern5e670d82018-04-17 17:33:14 -07004097 if (rt->fib6_nh.nh_dev == arg->dev &&
David Ahernd4ead6b2018-04-17 17:33:16 -07004098 !fib6_metric_locked(rt, RTAX_MTU)) {
4099 u32 mtu = rt->fib6_pmtu;
4100
4101 if (mtu >= arg->mtu ||
4102 (mtu < arg->mtu && mtu == idev->cnf.mtu6))
4103 fib6_metric_set(rt, RTAX_MTU, arg->mtu);
4104
Wei Wangf5bbe7e2017-10-06 12:05:59 -07004105 spin_lock_bh(&rt6_exception_lock);
Stefano Brivioe9fa1492018-03-06 11:10:19 +01004106 rt6_exceptions_update_pmtu(idev, rt, arg->mtu);
Wei Wangf5bbe7e2017-10-06 12:05:59 -07004107 spin_unlock_bh(&rt6_exception_lock);
Simon Arlott566cfd82007-07-26 00:09:55 -07004108 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109 return 0;
4110}
4111
Eric Dumazet95c96172012-04-15 05:58:06 +00004112void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113{
Thomas Grafc71099a2006-08-04 23:20:06 -07004114 struct rt6_mtu_change_arg arg = {
4115 .dev = dev,
4116 .mtu = mtu,
4117 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118
Li RongQing0c3584d2013-12-27 16:32:38 +08004119 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120}
4121
Patrick McHardyef7c79e2007-06-05 12:38:30 -07004122static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07004123 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Eric Dumazetaa8f8772018-04-22 18:29:23 -07004124 [RTA_PREFSRC] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07004125 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07004126 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07004127 [RTA_PRIORITY] = { .type = NLA_U32 },
4128 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004129 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004130 [RTA_PREF] = { .type = NLA_U8 },
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004131 [RTA_ENCAP_TYPE] = { .type = NLA_U16 },
4132 [RTA_ENCAP] = { .type = NLA_NESTED },
Xin Long32bc2012015-12-16 17:50:11 +08004133 [RTA_EXPIRES] = { .type = NLA_U32 },
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09004134 [RTA_UID] = { .type = NLA_U32 },
Liping Zhang3b45a412017-02-27 20:59:39 +08004135 [RTA_MARK] = { .type = NLA_U32 },
Eric Dumazetaa8f8772018-04-22 18:29:23 -07004136 [RTA_TABLE] = { .type = NLA_U32 },
Roopa Prabhueacb9382018-05-22 14:03:28 -07004137 [RTA_IP_PROTO] = { .type = NLA_U8 },
4138 [RTA_SPORT] = { .type = NLA_U16 },
4139 [RTA_DPORT] = { .type = NLA_U16 },
Thomas Graf86872cb2006-08-22 00:01:08 -07004140};
4141
4142static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
David Ahern333c4302017-05-21 10:12:04 -06004143 struct fib6_config *cfg,
4144 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145{
Thomas Graf86872cb2006-08-22 00:01:08 -07004146 struct rtmsg *rtm;
4147 struct nlattr *tb[RTA_MAX+1];
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004148 unsigned int pref;
Thomas Graf86872cb2006-08-22 00:01:08 -07004149 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150
Johannes Bergfceb6432017-04-12 14:34:07 +02004151 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
4152 NULL);
Thomas Graf86872cb2006-08-22 00:01:08 -07004153 if (err < 0)
4154 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004155
Thomas Graf86872cb2006-08-22 00:01:08 -07004156 err = -EINVAL;
4157 rtm = nlmsg_data(nlh);
4158 memset(cfg, 0, sizeof(*cfg));
4159
4160 cfg->fc_table = rtm->rtm_table;
4161 cfg->fc_dst_len = rtm->rtm_dst_len;
4162 cfg->fc_src_len = rtm->rtm_src_len;
4163 cfg->fc_flags = RTF_UP;
4164 cfg->fc_protocol = rtm->rtm_protocol;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00004165 cfg->fc_type = rtm->rtm_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07004166
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00004167 if (rtm->rtm_type == RTN_UNREACHABLE ||
4168 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00004169 rtm->rtm_type == RTN_PROHIBIT ||
4170 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07004171 cfg->fc_flags |= RTF_REJECT;
4172
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00004173 if (rtm->rtm_type == RTN_LOCAL)
4174 cfg->fc_flags |= RTF_LOCAL;
4175
Martin KaFai Lau1f56a012015-04-28 13:03:03 -07004176 if (rtm->rtm_flags & RTM_F_CLONED)
4177 cfg->fc_flags |= RTF_CACHE;
4178
David Ahernfc1e64e2018-01-25 16:55:09 -08004179 cfg->fc_flags |= (rtm->rtm_flags & RTNH_F_ONLINK);
4180
Eric W. Biederman15e47302012-09-07 20:12:54 +00004181 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
Thomas Graf86872cb2006-08-22 00:01:08 -07004182 cfg->fc_nlinfo.nlh = nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09004183 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
Thomas Graf86872cb2006-08-22 00:01:08 -07004184
4185 if (tb[RTA_GATEWAY]) {
Jiri Benc67b61f62015-03-29 16:59:26 +02004186 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
Thomas Graf86872cb2006-08-22 00:01:08 -07004187 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004189
4190 if (tb[RTA_DST]) {
4191 int plen = (rtm->rtm_dst_len + 7) >> 3;
4192
4193 if (nla_len(tb[RTA_DST]) < plen)
4194 goto errout;
4195
4196 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004198
4199 if (tb[RTA_SRC]) {
4200 int plen = (rtm->rtm_src_len + 7) >> 3;
4201
4202 if (nla_len(tb[RTA_SRC]) < plen)
4203 goto errout;
4204
4205 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004207
Daniel Walterc3968a82011-04-13 21:10:57 +00004208 if (tb[RTA_PREFSRC])
Jiri Benc67b61f62015-03-29 16:59:26 +02004209 cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]);
Daniel Walterc3968a82011-04-13 21:10:57 +00004210
Thomas Graf86872cb2006-08-22 00:01:08 -07004211 if (tb[RTA_OIF])
4212 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
4213
4214 if (tb[RTA_PRIORITY])
4215 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
4216
4217 if (tb[RTA_METRICS]) {
4218 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
4219 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004221
4222 if (tb[RTA_TABLE])
4223 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
4224
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004225 if (tb[RTA_MULTIPATH]) {
4226 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
4227 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
David Ahern9ed59592017-01-17 14:57:36 -08004228
4229 err = lwtunnel_valid_encap_type_attr(cfg->fc_mp,
David Ahernc255bd62017-05-27 16:19:27 -06004230 cfg->fc_mp_len, extack);
David Ahern9ed59592017-01-17 14:57:36 -08004231 if (err < 0)
4232 goto errout;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004233 }
4234
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004235 if (tb[RTA_PREF]) {
4236 pref = nla_get_u8(tb[RTA_PREF]);
4237 if (pref != ICMPV6_ROUTER_PREF_LOW &&
4238 pref != ICMPV6_ROUTER_PREF_HIGH)
4239 pref = ICMPV6_ROUTER_PREF_MEDIUM;
4240 cfg->fc_flags |= RTF_PREF(pref);
4241 }
4242
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004243 if (tb[RTA_ENCAP])
4244 cfg->fc_encap = tb[RTA_ENCAP];
4245
David Ahern9ed59592017-01-17 14:57:36 -08004246 if (tb[RTA_ENCAP_TYPE]) {
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004247 cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]);
4248
David Ahernc255bd62017-05-27 16:19:27 -06004249 err = lwtunnel_valid_encap_type(cfg->fc_encap_type, extack);
David Ahern9ed59592017-01-17 14:57:36 -08004250 if (err < 0)
4251 goto errout;
4252 }
4253
Xin Long32bc2012015-12-16 17:50:11 +08004254 if (tb[RTA_EXPIRES]) {
4255 unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ);
4256
4257 if (addrconf_finite_timeout(timeout)) {
4258 cfg->fc_expires = jiffies_to_clock_t(timeout * HZ);
4259 cfg->fc_flags |= RTF_EXPIRES;
4260 }
4261 }
4262
Thomas Graf86872cb2006-08-22 00:01:08 -07004263 err = 0;
4264errout:
4265 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266}
4267
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004268struct rt6_nh {
David Ahern8d1c8022018-04-17 17:33:26 -07004269 struct fib6_info *fib6_info;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004270 struct fib6_config r_cfg;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004271 struct list_head next;
4272};
4273
4274static void ip6_print_replace_route_err(struct list_head *rt6_nh_list)
4275{
4276 struct rt6_nh *nh;
4277
4278 list_for_each_entry(nh, rt6_nh_list, next) {
David Ahern7d4d5062017-02-02 12:37:12 -08004279 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 -07004280 &nh->r_cfg.fc_dst, &nh->r_cfg.fc_gateway,
4281 nh->r_cfg.fc_ifindex);
4282 }
4283}
4284
David Ahernd4ead6b2018-04-17 17:33:16 -07004285static int ip6_route_info_append(struct net *net,
4286 struct list_head *rt6_nh_list,
David Ahern8d1c8022018-04-17 17:33:26 -07004287 struct fib6_info *rt,
4288 struct fib6_config *r_cfg)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004289{
4290 struct rt6_nh *nh;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004291 int err = -EEXIST;
4292
4293 list_for_each_entry(nh, rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004294 /* check if fib6_info already exists */
4295 if (rt6_duplicate_nexthop(nh->fib6_info, rt))
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004296 return err;
4297 }
4298
4299 nh = kzalloc(sizeof(*nh), GFP_KERNEL);
4300 if (!nh)
4301 return -ENOMEM;
David Ahern8d1c8022018-04-17 17:33:26 -07004302 nh->fib6_info = rt;
David Ahernd4ead6b2018-04-17 17:33:16 -07004303 err = ip6_convert_metrics(net, rt, r_cfg);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004304 if (err) {
4305 kfree(nh);
4306 return err;
4307 }
4308 memcpy(&nh->r_cfg, r_cfg, sizeof(*r_cfg));
4309 list_add_tail(&nh->next, rt6_nh_list);
4310
4311 return 0;
4312}
4313
David Ahern8d1c8022018-04-17 17:33:26 -07004314static void ip6_route_mpath_notify(struct fib6_info *rt,
4315 struct fib6_info *rt_last,
David Ahern3b1137f2017-02-02 12:37:10 -08004316 struct nl_info *info,
4317 __u16 nlflags)
4318{
4319 /* if this is an APPEND route, then rt points to the first route
4320 * inserted and rt_last points to last route inserted. Userspace
4321 * wants a consistent dump of the route which starts at the first
4322 * nexthop. Since sibling routes are always added at the end of
4323 * the list, find the first sibling of the last route appended
4324 */
David Ahern93c2fb22018-04-18 15:38:59 -07004325 if ((nlflags & NLM_F_APPEND) && rt_last && rt_last->fib6_nsiblings) {
4326 rt = list_first_entry(&rt_last->fib6_siblings,
David Ahern8d1c8022018-04-17 17:33:26 -07004327 struct fib6_info,
David Ahern93c2fb22018-04-18 15:38:59 -07004328 fib6_siblings);
David Ahern3b1137f2017-02-02 12:37:10 -08004329 }
4330
4331 if (rt)
4332 inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
4333}
4334
David Ahern333c4302017-05-21 10:12:04 -06004335static int ip6_route_multipath_add(struct fib6_config *cfg,
4336 struct netlink_ext_ack *extack)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004337{
David Ahern8d1c8022018-04-17 17:33:26 -07004338 struct fib6_info *rt_notif = NULL, *rt_last = NULL;
David Ahern3b1137f2017-02-02 12:37:10 -08004339 struct nl_info *info = &cfg->fc_nlinfo;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004340 struct fib6_config r_cfg;
4341 struct rtnexthop *rtnh;
David Ahern8d1c8022018-04-17 17:33:26 -07004342 struct fib6_info *rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004343 struct rt6_nh *err_nh;
4344 struct rt6_nh *nh, *nh_safe;
David Ahern3b1137f2017-02-02 12:37:10 -08004345 __u16 nlflags;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004346 int remaining;
4347 int attrlen;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004348 int err = 1;
4349 int nhn = 0;
4350 int replace = (cfg->fc_nlinfo.nlh &&
4351 (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE));
4352 LIST_HEAD(rt6_nh_list);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004353
David Ahern3b1137f2017-02-02 12:37:10 -08004354 nlflags = replace ? NLM_F_REPLACE : NLM_F_CREATE;
4355 if (info->nlh && info->nlh->nlmsg_flags & NLM_F_APPEND)
4356 nlflags |= NLM_F_APPEND;
4357
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02004358 remaining = cfg->fc_mp_len;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004359 rtnh = (struct rtnexthop *)cfg->fc_mp;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004360
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004361 /* Parse a Multipath Entry and build a list (rt6_nh_list) of
David Ahern8d1c8022018-04-17 17:33:26 -07004362 * fib6_info structs per nexthop
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004363 */
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004364 while (rtnh_ok(rtnh, remaining)) {
4365 memcpy(&r_cfg, cfg, sizeof(*cfg));
4366 if (rtnh->rtnh_ifindex)
4367 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
4368
4369 attrlen = rtnh_attrlen(rtnh);
4370 if (attrlen > 0) {
4371 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
4372
4373 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
4374 if (nla) {
Jiri Benc67b61f62015-03-29 16:59:26 +02004375 r_cfg.fc_gateway = nla_get_in6_addr(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004376 r_cfg.fc_flags |= RTF_GATEWAY;
4377 }
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004378 r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
4379 nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
4380 if (nla)
4381 r_cfg.fc_encap_type = nla_get_u16(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004382 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004383
David Ahern68e2ffd2018-03-20 10:06:59 -07004384 r_cfg.fc_flags |= (rtnh->rtnh_flags & RTNH_F_ONLINK);
David Ahernacb54e32018-04-17 17:33:22 -07004385 rt = ip6_route_info_create(&r_cfg, GFP_KERNEL, extack);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07004386 if (IS_ERR(rt)) {
4387 err = PTR_ERR(rt);
4388 rt = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004389 goto cleanup;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07004390 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004391
David Ahern5e670d82018-04-17 17:33:14 -07004392 rt->fib6_nh.nh_weight = rtnh->rtnh_hops + 1;
Ido Schimmel398958a2018-01-09 16:40:28 +02004393
David Ahernd4ead6b2018-04-17 17:33:16 -07004394 err = ip6_route_info_append(info->nl_net, &rt6_nh_list,
4395 rt, &r_cfg);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004396 if (err) {
David Ahern93531c62018-04-17 17:33:25 -07004397 fib6_info_release(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004398 goto cleanup;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004399 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004400
4401 rtnh = rtnh_next(rtnh, &remaining);
4402 }
4403
David Ahern3b1137f2017-02-02 12:37:10 -08004404 /* for add and replace send one notification with all nexthops.
4405 * Skip the notification in fib6_add_rt2node and send one with
4406 * the full route when done
4407 */
4408 info->skip_notify = 1;
4409
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004410 err_nh = NULL;
4411 list_for_each_entry(nh, &rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004412 err = __ip6_ins_rt(nh->fib6_info, info, extack);
4413 fib6_info_release(nh->fib6_info);
David Ahern3b1137f2017-02-02 12:37:10 -08004414
David Ahernf7225172018-06-04 13:41:42 -07004415 if (!err) {
4416 /* save reference to last route successfully inserted */
4417 rt_last = nh->fib6_info;
4418
4419 /* save reference to first route for notification */
4420 if (!rt_notif)
4421 rt_notif = nh->fib6_info;
4422 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004423
David Ahern8d1c8022018-04-17 17:33:26 -07004424 /* nh->fib6_info is used or freed at this point, reset to NULL*/
4425 nh->fib6_info = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004426 if (err) {
4427 if (replace && nhn)
4428 ip6_print_replace_route_err(&rt6_nh_list);
4429 err_nh = nh;
4430 goto add_errout;
4431 }
4432
Nicolas Dichtel1a724182012-11-01 22:58:22 +00004433 /* Because each route is added like a single route we remove
Michal Kubeček27596472015-05-18 20:54:00 +02004434 * these flags after the first nexthop: if there is a collision,
4435 * we have already failed to add the first nexthop:
4436 * fib6_add_rt2node() has rejected it; when replacing, old
4437 * nexthops have been replaced by first new, the rest should
4438 * be added to it.
Nicolas Dichtel1a724182012-11-01 22:58:22 +00004439 */
Michal Kubeček27596472015-05-18 20:54:00 +02004440 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
4441 NLM_F_REPLACE);
David Ahernf34436a2018-05-21 10:26:53 -07004442 cfg->fc_nlinfo.nlh->nlmsg_flags |= NLM_F_APPEND;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004443 nhn++;
4444 }
4445
David Ahern3b1137f2017-02-02 12:37:10 -08004446 /* success ... tell user about new route */
4447 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004448 goto cleanup;
4449
4450add_errout:
David Ahern3b1137f2017-02-02 12:37:10 -08004451 /* send notification for routes that were added so that
4452 * the delete notifications sent by ip6_route_del are
4453 * coherent
4454 */
4455 if (rt_notif)
4456 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
4457
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004458 /* Delete routes that were already added */
4459 list_for_each_entry(nh, &rt6_nh_list, next) {
4460 if (err_nh == nh)
4461 break;
David Ahern333c4302017-05-21 10:12:04 -06004462 ip6_route_del(&nh->r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004463 }
4464
4465cleanup:
4466 list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004467 if (nh->fib6_info)
4468 fib6_info_release(nh->fib6_info);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004469 list_del(&nh->next);
4470 kfree(nh);
4471 }
4472
4473 return err;
4474}
4475
David Ahern333c4302017-05-21 10:12:04 -06004476static int ip6_route_multipath_del(struct fib6_config *cfg,
4477 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004478{
4479 struct fib6_config r_cfg;
4480 struct rtnexthop *rtnh;
4481 int remaining;
4482 int attrlen;
4483 int err = 1, last_err = 0;
4484
4485 remaining = cfg->fc_mp_len;
4486 rtnh = (struct rtnexthop *)cfg->fc_mp;
4487
4488 /* Parse a Multipath Entry */
4489 while (rtnh_ok(rtnh, remaining)) {
4490 memcpy(&r_cfg, cfg, sizeof(*cfg));
4491 if (rtnh->rtnh_ifindex)
4492 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
4493
4494 attrlen = rtnh_attrlen(rtnh);
4495 if (attrlen > 0) {
4496 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
4497
4498 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
4499 if (nla) {
4500 nla_memcpy(&r_cfg.fc_gateway, nla, 16);
4501 r_cfg.fc_flags |= RTF_GATEWAY;
4502 }
4503 }
David Ahern333c4302017-05-21 10:12:04 -06004504 err = ip6_route_del(&r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004505 if (err)
4506 last_err = err;
4507
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004508 rtnh = rtnh_next(rtnh, &remaining);
4509 }
4510
4511 return last_err;
4512}
4513
David Ahernc21ef3e2017-04-16 09:48:24 -07004514static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
4515 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516{
Thomas Graf86872cb2006-08-22 00:01:08 -07004517 struct fib6_config cfg;
4518 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519
David Ahern333c4302017-05-21 10:12:04 -06004520 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07004521 if (err < 0)
4522 return err;
4523
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004524 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06004525 return ip6_route_multipath_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08004526 else {
4527 cfg.fc_delete_all_nh = 1;
David Ahern333c4302017-05-21 10:12:04 -06004528 return ip6_route_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08004529 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530}
4531
David Ahernc21ef3e2017-04-16 09:48:24 -07004532static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
4533 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534{
Thomas Graf86872cb2006-08-22 00:01:08 -07004535 struct fib6_config cfg;
4536 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537
David Ahern333c4302017-05-21 10:12:04 -06004538 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07004539 if (err < 0)
4540 return err;
4541
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004542 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06004543 return ip6_route_multipath_add(&cfg, extack);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004544 else
David Ahernacb54e32018-04-17 17:33:22 -07004545 return ip6_route_add(&cfg, GFP_KERNEL, extack);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546}
4547
David Ahern8d1c8022018-04-17 17:33:26 -07004548static size_t rt6_nlmsg_size(struct fib6_info *rt)
Thomas Graf339bf982006-11-10 14:10:15 -08004549{
David Ahernbeb1afac52017-02-02 12:37:09 -08004550 int nexthop_len = 0;
4551
David Ahern93c2fb22018-04-18 15:38:59 -07004552 if (rt->fib6_nsiblings) {
David Ahernbeb1afac52017-02-02 12:37:09 -08004553 nexthop_len = nla_total_size(0) /* RTA_MULTIPATH */
4554 + NLA_ALIGN(sizeof(struct rtnexthop))
4555 + nla_total_size(16) /* RTA_GATEWAY */
David Ahern5e670d82018-04-17 17:33:14 -07004556 + lwtunnel_get_encap_size(rt->fib6_nh.nh_lwtstate);
David Ahernbeb1afac52017-02-02 12:37:09 -08004557
David Ahern93c2fb22018-04-18 15:38:59 -07004558 nexthop_len *= rt->fib6_nsiblings;
David Ahernbeb1afac52017-02-02 12:37:09 -08004559 }
4560
Thomas Graf339bf982006-11-10 14:10:15 -08004561 return NLMSG_ALIGN(sizeof(struct rtmsg))
4562 + nla_total_size(16) /* RTA_SRC */
4563 + nla_total_size(16) /* RTA_DST */
4564 + nla_total_size(16) /* RTA_GATEWAY */
4565 + nla_total_size(16) /* RTA_PREFSRC */
4566 + nla_total_size(4) /* RTA_TABLE */
4567 + nla_total_size(4) /* RTA_IIF */
4568 + nla_total_size(4) /* RTA_OIF */
4569 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08004570 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Daniel Borkmannea697632015-01-05 23:57:47 +01004571 + nla_total_size(sizeof(struct rta_cacheinfo))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004572 + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004573 + nla_total_size(1) /* RTA_PREF */
David Ahern5e670d82018-04-17 17:33:14 -07004574 + lwtunnel_get_encap_size(rt->fib6_nh.nh_lwtstate)
David Ahernbeb1afac52017-02-02 12:37:09 -08004575 + nexthop_len;
4576}
4577
David Ahern8d1c8022018-04-17 17:33:26 -07004578static int rt6_nexthop_info(struct sk_buff *skb, struct fib6_info *rt,
David Ahern5be083c2017-03-06 15:57:31 -08004579 unsigned int *flags, bool skip_oif)
David Ahernbeb1afac52017-02-02 12:37:09 -08004580{
David Ahern5e670d82018-04-17 17:33:14 -07004581 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmelf9d882e2018-01-07 12:45:10 +02004582 *flags |= RTNH_F_DEAD;
4583
David Ahern5e670d82018-04-17 17:33:14 -07004584 if (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN) {
David Ahernbeb1afac52017-02-02 12:37:09 -08004585 *flags |= RTNH_F_LINKDOWN;
David Aherndcd1f572018-04-18 15:39:05 -07004586
4587 rcu_read_lock();
4588 if (fib6_ignore_linkdown(rt))
David Ahernbeb1afac52017-02-02 12:37:09 -08004589 *flags |= RTNH_F_DEAD;
David Aherndcd1f572018-04-18 15:39:05 -07004590 rcu_read_unlock();
David Ahernbeb1afac52017-02-02 12:37:09 -08004591 }
4592
David Ahern93c2fb22018-04-18 15:38:59 -07004593 if (rt->fib6_flags & RTF_GATEWAY) {
David Ahern5e670d82018-04-17 17:33:14 -07004594 if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->fib6_nh.nh_gw) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004595 goto nla_put_failure;
4596 }
4597
David Ahern5e670d82018-04-17 17:33:14 -07004598 *flags |= (rt->fib6_nh.nh_flags & RTNH_F_ONLINK);
4599 if (rt->fib6_nh.nh_flags & RTNH_F_OFFLOAD)
Ido Schimmel61e4d012017-08-03 13:28:20 +02004600 *flags |= RTNH_F_OFFLOAD;
4601
David Ahern5be083c2017-03-06 15:57:31 -08004602 /* not needed for multipath encoding b/c it has a rtnexthop struct */
David Ahern5e670d82018-04-17 17:33:14 -07004603 if (!skip_oif && rt->fib6_nh.nh_dev &&
4604 nla_put_u32(skb, RTA_OIF, rt->fib6_nh.nh_dev->ifindex))
David Ahernbeb1afac52017-02-02 12:37:09 -08004605 goto nla_put_failure;
4606
David Ahern5e670d82018-04-17 17:33:14 -07004607 if (rt->fib6_nh.nh_lwtstate &&
4608 lwtunnel_fill_encap(skb, rt->fib6_nh.nh_lwtstate) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004609 goto nla_put_failure;
4610
4611 return 0;
4612
4613nla_put_failure:
4614 return -EMSGSIZE;
4615}
4616
David Ahern5be083c2017-03-06 15:57:31 -08004617/* add multipath next hop */
David Ahern8d1c8022018-04-17 17:33:26 -07004618static int rt6_add_nexthop(struct sk_buff *skb, struct fib6_info *rt)
David Ahernbeb1afac52017-02-02 12:37:09 -08004619{
David Ahern5e670d82018-04-17 17:33:14 -07004620 const struct net_device *dev = rt->fib6_nh.nh_dev;
David Ahernbeb1afac52017-02-02 12:37:09 -08004621 struct rtnexthop *rtnh;
4622 unsigned int flags = 0;
4623
4624 rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh));
4625 if (!rtnh)
4626 goto nla_put_failure;
4627
David Ahern5e670d82018-04-17 17:33:14 -07004628 rtnh->rtnh_hops = rt->fib6_nh.nh_weight - 1;
4629 rtnh->rtnh_ifindex = dev ? dev->ifindex : 0;
David Ahernbeb1afac52017-02-02 12:37:09 -08004630
David Ahern5be083c2017-03-06 15:57:31 -08004631 if (rt6_nexthop_info(skb, rt, &flags, true) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004632 goto nla_put_failure;
4633
4634 rtnh->rtnh_flags = flags;
4635
4636 /* length of rtnetlink header + attributes */
4637 rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *)rtnh;
4638
4639 return 0;
4640
4641nla_put_failure:
4642 return -EMSGSIZE;
Thomas Graf339bf982006-11-10 14:10:15 -08004643}
4644
David Ahernd4ead6b2018-04-17 17:33:16 -07004645static int rt6_fill_node(struct net *net, struct sk_buff *skb,
David Ahern8d1c8022018-04-17 17:33:26 -07004646 struct fib6_info *rt, struct dst_entry *dst,
David Ahernd4ead6b2018-04-17 17:33:16 -07004647 struct in6_addr *dest, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00004648 int iif, int type, u32 portid, u32 seq,
David Ahernf8cfe2c2017-01-17 15:51:08 -08004649 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650{
4651 struct rtmsg *rtm;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004652 struct nlmsghdr *nlh;
David Ahernd4ead6b2018-04-17 17:33:16 -07004653 long expires = 0;
4654 u32 *pmetrics;
Patrick McHardy9e762a42006-08-10 23:09:48 -07004655 u32 table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656
Eric W. Biederman15e47302012-09-07 20:12:54 +00004657 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05004658 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08004659 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004660
4661 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662 rtm->rtm_family = AF_INET6;
David Ahern93c2fb22018-04-18 15:38:59 -07004663 rtm->rtm_dst_len = rt->fib6_dst.plen;
4664 rtm->rtm_src_len = rt->fib6_src.plen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665 rtm->rtm_tos = 0;
David Ahern93c2fb22018-04-18 15:38:59 -07004666 if (rt->fib6_table)
4667 table = rt->fib6_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07004668 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07004669 table = RT6_TABLE_UNSPEC;
4670 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04004671 if (nla_put_u32(skb, RTA_TABLE, table))
4672 goto nla_put_failure;
David Aherne8478e82018-04-17 17:33:13 -07004673
4674 rtm->rtm_type = rt->fib6_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004675 rtm->rtm_flags = 0;
4676 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
David Ahern93c2fb22018-04-18 15:38:59 -07004677 rtm->rtm_protocol = rt->fib6_protocol;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678
David Ahern93c2fb22018-04-18 15:38:59 -07004679 if (rt->fib6_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680 rtm->rtm_flags |= RTM_F_CLONED;
4681
David Ahernd4ead6b2018-04-17 17:33:16 -07004682 if (dest) {
4683 if (nla_put_in6_addr(skb, RTA_DST, dest))
David S. Millerc78679e2012-04-01 20:27:33 -04004684 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09004685 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686 } else if (rtm->rtm_dst_len)
David Ahern93c2fb22018-04-18 15:38:59 -07004687 if (nla_put_in6_addr(skb, RTA_DST, &rt->fib6_dst.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04004688 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004689#ifdef CONFIG_IPV6_SUBTREES
4690 if (src) {
Jiri Benc930345e2015-03-29 16:59:25 +02004691 if (nla_put_in6_addr(skb, RTA_SRC, src))
David S. Millerc78679e2012-04-01 20:27:33 -04004692 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09004693 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04004694 } else if (rtm->rtm_src_len &&
David Ahern93c2fb22018-04-18 15:38:59 -07004695 nla_put_in6_addr(skb, RTA_SRC, &rt->fib6_src.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04004696 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09004698 if (iif) {
4699#ifdef CONFIG_IPV6_MROUTE
David Ahern93c2fb22018-04-18 15:38:59 -07004700 if (ipv6_addr_is_multicast(&rt->fib6_dst.addr)) {
David Ahernfd61c6b2017-01-17 15:51:07 -08004701 int err = ip6mr_get_route(net, skb, rtm, portid);
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02004702
David Ahernfd61c6b2017-01-17 15:51:07 -08004703 if (err == 0)
4704 return 0;
4705 if (err < 0)
4706 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09004707 } else
4708#endif
David S. Millerc78679e2012-04-01 20:27:33 -04004709 if (nla_put_u32(skb, RTA_IIF, iif))
4710 goto nla_put_failure;
David Ahernd4ead6b2018-04-17 17:33:16 -07004711 } else if (dest) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712 struct in6_addr saddr_buf;
David Ahernd4ead6b2018-04-17 17:33:16 -07004713 if (ip6_route_get_saddr(net, rt, dest, 0, &saddr_buf) == 0 &&
Jiri Benc930345e2015-03-29 16:59:25 +02004714 nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04004715 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004716 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07004717
David Ahern93c2fb22018-04-18 15:38:59 -07004718 if (rt->fib6_prefsrc.plen) {
Daniel Walterc3968a82011-04-13 21:10:57 +00004719 struct in6_addr saddr_buf;
David Ahern93c2fb22018-04-18 15:38:59 -07004720 saddr_buf = rt->fib6_prefsrc.addr;
Jiri Benc930345e2015-03-29 16:59:25 +02004721 if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04004722 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00004723 }
4724
David Ahernd4ead6b2018-04-17 17:33:16 -07004725 pmetrics = dst ? dst_metrics_ptr(dst) : rt->fib6_metrics->metrics;
4726 if (rtnetlink_put_metrics(skb, pmetrics) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07004727 goto nla_put_failure;
4728
David Ahern93c2fb22018-04-18 15:38:59 -07004729 if (nla_put_u32(skb, RTA_PRIORITY, rt->fib6_metric))
David S. Millerc78679e2012-04-01 20:27:33 -04004730 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00004731
David Ahernbeb1afac52017-02-02 12:37:09 -08004732 /* For multipath routes, walk the siblings list and add
4733 * each as a nexthop within RTA_MULTIPATH.
4734 */
David Ahern93c2fb22018-04-18 15:38:59 -07004735 if (rt->fib6_nsiblings) {
David Ahern8d1c8022018-04-17 17:33:26 -07004736 struct fib6_info *sibling, *next_sibling;
David Ahernbeb1afac52017-02-02 12:37:09 -08004737 struct nlattr *mp;
4738
4739 mp = nla_nest_start(skb, RTA_MULTIPATH);
4740 if (!mp)
4741 goto nla_put_failure;
4742
4743 if (rt6_add_nexthop(skb, rt) < 0)
4744 goto nla_put_failure;
4745
4746 list_for_each_entry_safe(sibling, next_sibling,
David Ahern93c2fb22018-04-18 15:38:59 -07004747 &rt->fib6_siblings, fib6_siblings) {
David Ahernbeb1afac52017-02-02 12:37:09 -08004748 if (rt6_add_nexthop(skb, sibling) < 0)
4749 goto nla_put_failure;
4750 }
4751
4752 nla_nest_end(skb, mp);
4753 } else {
David Ahern5be083c2017-03-06 15:57:31 -08004754 if (rt6_nexthop_info(skb, rt, &rtm->rtm_flags, false) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004755 goto nla_put_failure;
4756 }
4757
David Ahern93c2fb22018-04-18 15:38:59 -07004758 if (rt->fib6_flags & RTF_EXPIRES) {
David Ahern14895682018-04-17 17:33:17 -07004759 expires = dst ? dst->expires : rt->expires;
4760 expires -= jiffies;
4761 }
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07004762
David Ahernd4ead6b2018-04-17 17:33:16 -07004763 if (rtnl_put_cacheinfo(skb, dst, 0, expires, dst ? dst->error : 0) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08004764 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765
David Ahern93c2fb22018-04-18 15:38:59 -07004766 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->fib6_flags)))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004767 goto nla_put_failure;
4768
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004769
Johannes Berg053c0952015-01-16 22:09:00 +01004770 nlmsg_end(skb, nlh);
4771 return 0;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004772
4773nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08004774 nlmsg_cancel(skb, nlh);
4775 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776}
4777
David Ahern8d1c8022018-04-17 17:33:26 -07004778int rt6_dump_route(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779{
4780 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
David Ahern1f17e2f2017-01-26 13:54:08 -08004781 struct net *net = arg->net;
4782
David Ahern421842e2018-04-17 17:33:18 -07004783 if (rt == net->ipv6.fib6_null_entry)
David Ahern1f17e2f2017-01-26 13:54:08 -08004784 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785
Thomas Graf2d7202b2006-08-22 00:01:27 -07004786 if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
4787 struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
David Ahernf8cfe2c2017-01-17 15:51:08 -08004788
4789 /* user wants prefix routes only */
4790 if (rtm->rtm_flags & RTM_F_PREFIX &&
David Ahern93c2fb22018-04-18 15:38:59 -07004791 !(rt->fib6_flags & RTF_PREFIX_RT)) {
David Ahernf8cfe2c2017-01-17 15:51:08 -08004792 /* success since this is not a prefix route */
4793 return 1;
4794 }
4795 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796
David Ahernd4ead6b2018-04-17 17:33:16 -07004797 return rt6_fill_node(net, arg->skb, rt, NULL, NULL, NULL, 0,
4798 RTM_NEWROUTE, NETLINK_CB(arg->cb->skb).portid,
4799 arg->cb->nlh->nlmsg_seq, NLM_F_MULTI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800}
4801
David Ahernc21ef3e2017-04-16 09:48:24 -07004802static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
4803 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09004805 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07004806 struct nlattr *tb[RTA_MAX+1];
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004807 int err, iif = 0, oif = 0;
David Aherna68886a2018-04-20 15:38:02 -07004808 struct fib6_info *from;
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004809 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07004811 struct sk_buff *skb;
4812 struct rtmsg *rtm;
David S. Miller4c9483b2011-03-12 16:22:43 -05004813 struct flowi6 fl6;
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004814 bool fibmatch;
Thomas Grafab364a62006-08-22 00:01:47 -07004815
Johannes Bergfceb6432017-04-12 14:34:07 +02004816 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
David Ahernc21ef3e2017-04-16 09:48:24 -07004817 extack);
Thomas Grafab364a62006-08-22 00:01:47 -07004818 if (err < 0)
4819 goto errout;
4820
4821 err = -EINVAL;
David S. Miller4c9483b2011-03-12 16:22:43 -05004822 memset(&fl6, 0, sizeof(fl6));
Hannes Frederic Sowa38b70972016-06-11 20:08:19 +02004823 rtm = nlmsg_data(nlh);
4824 fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004825 fibmatch = !!(rtm->rtm_flags & RTM_F_FIB_MATCH);
Thomas Grafab364a62006-08-22 00:01:47 -07004826
4827 if (tb[RTA_SRC]) {
4828 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
4829 goto errout;
4830
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00004831 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07004832 }
4833
4834 if (tb[RTA_DST]) {
4835 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
4836 goto errout;
4837
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00004838 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07004839 }
4840
4841 if (tb[RTA_IIF])
4842 iif = nla_get_u32(tb[RTA_IIF]);
4843
4844 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004845 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07004846
Lorenzo Colitti2e47b292014-05-15 16:38:41 -07004847 if (tb[RTA_MARK])
4848 fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
4849
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09004850 if (tb[RTA_UID])
4851 fl6.flowi6_uid = make_kuid(current_user_ns(),
4852 nla_get_u32(tb[RTA_UID]));
4853 else
4854 fl6.flowi6_uid = iif ? INVALID_UID : current_uid();
4855
Roopa Prabhueacb9382018-05-22 14:03:28 -07004856 if (tb[RTA_SPORT])
4857 fl6.fl6_sport = nla_get_be16(tb[RTA_SPORT]);
4858
4859 if (tb[RTA_DPORT])
4860 fl6.fl6_dport = nla_get_be16(tb[RTA_DPORT]);
4861
4862 if (tb[RTA_IP_PROTO]) {
4863 err = rtm_getroute_parse_ip_proto(tb[RTA_IP_PROTO],
4864 &fl6.flowi6_proto, extack);
4865 if (err)
4866 goto errout;
4867 }
4868
Thomas Grafab364a62006-08-22 00:01:47 -07004869 if (iif) {
4870 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004871 int flags = 0;
4872
Florian Westphal121622d2017-08-15 16:34:42 +02004873 rcu_read_lock();
4874
4875 dev = dev_get_by_index_rcu(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07004876 if (!dev) {
Florian Westphal121622d2017-08-15 16:34:42 +02004877 rcu_read_unlock();
Thomas Grafab364a62006-08-22 00:01:47 -07004878 err = -ENODEV;
4879 goto errout;
4880 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004881
4882 fl6.flowi6_iif = iif;
4883
4884 if (!ipv6_addr_any(&fl6.saddr))
4885 flags |= RT6_LOOKUP_F_HAS_SADDR;
4886
David Ahernb75cc8f2018-03-02 08:32:17 -08004887 dst = ip6_route_input_lookup(net, dev, &fl6, NULL, flags);
Florian Westphal121622d2017-08-15 16:34:42 +02004888
4889 rcu_read_unlock();
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004890 } else {
4891 fl6.flowi6_oif = oif;
4892
Ido Schimmel58acfd72017-12-20 12:28:25 +02004893 dst = ip6_route_output(net, NULL, &fl6);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004894 }
4895
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004896
4897 rt = container_of(dst, struct rt6_info, dst);
4898 if (rt->dst.error) {
4899 err = rt->dst.error;
4900 ip6_rt_put(rt);
4901 goto errout;
Thomas Grafab364a62006-08-22 00:01:47 -07004902 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903
WANG Cong9d6acb32017-03-01 20:48:39 -08004904 if (rt == net->ipv6.ip6_null_entry) {
4905 err = rt->dst.error;
4906 ip6_rt_put(rt);
4907 goto errout;
4908 }
4909
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05004911 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00004912 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07004913 err = -ENOBUFS;
4914 goto errout;
4915 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916
Changli Gaod8d1f302010-06-10 23:31:35 -07004917 skb_dst_set(skb, &rt->dst);
David Aherna68886a2018-04-20 15:38:02 -07004918
4919 rcu_read_lock();
4920 from = rcu_dereference(rt->from);
4921
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004922 if (fibmatch)
David Aherna68886a2018-04-20 15:38:02 -07004923 err = rt6_fill_node(net, skb, from, NULL, NULL, NULL, iif,
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004924 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
4925 nlh->nlmsg_seq, 0);
4926 else
David Aherna68886a2018-04-20 15:38:02 -07004927 err = rt6_fill_node(net, skb, from, dst, &fl6.daddr,
4928 &fl6.saddr, iif, RTM_NEWROUTE,
David Ahernd4ead6b2018-04-17 17:33:16 -07004929 NETLINK_CB(in_skb).portid, nlh->nlmsg_seq,
4930 0);
David Aherna68886a2018-04-20 15:38:02 -07004931 rcu_read_unlock();
4932
Linus Torvalds1da177e2005-04-16 15:20:36 -07004933 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07004934 kfree_skb(skb);
4935 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936 }
4937
Eric W. Biederman15e47302012-09-07 20:12:54 +00004938 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07004939errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004940 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941}
4942
David Ahern8d1c8022018-04-17 17:33:26 -07004943void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info,
Roopa Prabhu37a1d362015-09-13 10:18:33 -07004944 unsigned int nlm_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004945{
4946 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08004947 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08004948 u32 seq;
4949 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004950
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08004951 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05004952 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07004953
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004954 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05004955 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07004956 goto errout;
4957
David Ahernd4ead6b2018-04-17 17:33:16 -07004958 err = rt6_fill_node(net, skb, rt, NULL, NULL, NULL, 0,
4959 event, info->portid, seq, nlm_flags);
Patrick McHardy26932562007-01-31 23:16:40 -08004960 if (err < 0) {
4961 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
4962 WARN_ON(err == -EMSGSIZE);
4963 kfree_skb(skb);
4964 goto errout;
4965 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00004966 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08004967 info->nlh, gfp_any());
4968 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07004969errout:
4970 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08004971 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004972}
4973
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004974static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00004975 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004976{
Jiri Pirko351638e2013-05-28 01:30:21 +00004977 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09004978 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004979
WANG Cong242d3a42017-05-08 10:12:13 -07004980 if (!(dev->flags & IFF_LOOPBACK))
4981 return NOTIFY_OK;
4982
4983 if (event == NETDEV_REGISTER) {
David Ahern421842e2018-04-17 17:33:18 -07004984 net->ipv6.fib6_null_entry->fib6_nh.nh_dev = dev;
Changli Gaod8d1f302010-06-10 23:31:35 -07004985 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004986 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
4987#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07004988 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004989 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07004990 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004991 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
4992#endif
WANG Cong76da0702017-06-20 11:42:27 -07004993 } else if (event == NETDEV_UNREGISTER &&
4994 dev->reg_state != NETREG_UNREGISTERED) {
4995 /* NETDEV_UNREGISTER could be fired for multiple times by
4996 * netdev_wait_allrefs(). Make sure we only call this once.
4997 */
Eric Dumazet12d94a82017-08-15 04:09:51 -07004998 in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev);
WANG Cong242d3a42017-05-08 10:12:13 -07004999#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Eric Dumazet12d94a82017-08-15 04:09:51 -07005000 in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev);
5001 in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev);
WANG Cong242d3a42017-05-08 10:12:13 -07005002#endif
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005003 }
5004
5005 return NOTIFY_OK;
5006}
5007
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008/*
5009 * /proc
5010 */
5011
5012#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07005013static int rt6_stats_seq_show(struct seq_file *seq, void *v)
5014{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005015 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005017 net->ipv6.rt6_stats->fib_nodes,
5018 net->ipv6.rt6_stats->fib_route_nodes,
Wei Wang81eb8442017-10-06 12:06:11 -07005019 atomic_read(&net->ipv6.rt6_stats->fib_rt_alloc),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005020 net->ipv6.rt6_stats->fib_rt_entries,
5021 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00005022 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005023 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005024
5025 return 0;
5026}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005027#endif /* CONFIG_PROC_FS */
5028
5029#ifdef CONFIG_SYSCTL
5030
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031static
Joe Perchesfe2c6332013-06-11 23:04:25 -07005032int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005033 void __user *buffer, size_t *lenp, loff_t *ppos)
5034{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005035 struct net *net;
5036 int delay;
5037 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005038 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005039
5040 net = (struct net *)ctl->extra1;
5041 delay = net->ipv6.sysctl.flush_delay;
5042 proc_dointvec(ctl, write, buffer, lenp, ppos);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02005043 fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005044 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005045}
5046
Joe Perchesfe2c6332013-06-11 23:04:25 -07005047struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09005048 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08005050 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005051 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07005052 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005053 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054 },
5055 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08005057 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058 .maxlen = sizeof(int),
5059 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005060 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005061 },
5062 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005063 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08005064 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005065 .maxlen = sizeof(int),
5066 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005067 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068 },
5069 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08005071 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072 .maxlen = sizeof(int),
5073 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005074 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005075 },
5076 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08005078 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079 .maxlen = sizeof(int),
5080 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005081 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005082 },
5083 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08005085 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086 .maxlen = sizeof(int),
5087 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005088 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005089 },
5090 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08005092 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005093 .maxlen = sizeof(int),
5094 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07005095 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096 },
5097 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005098 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08005099 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100 .maxlen = sizeof(int),
5101 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005102 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103 },
5104 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005105 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08005106 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005107 .maxlen = sizeof(int),
5108 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07005109 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005110 },
5111 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005112 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08005113 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114 .maxlen = sizeof(int),
5115 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005116 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08005118 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119};
5120
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00005121struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08005122{
5123 struct ctl_table *table;
5124
5125 table = kmemdup(ipv6_route_table_template,
5126 sizeof(ipv6_route_table_template),
5127 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09005128
5129 if (table) {
5130 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005131 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00005132 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09005133 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
5134 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
5135 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
5136 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
5137 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
5138 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
5139 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08005140 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
Eric W. Biederman464dc802012-11-16 03:02:59 +00005141
5142 /* Don't export sysctls to unprivileged users */
5143 if (net->user_ns != &init_user_ns)
5144 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09005145 }
5146
Daniel Lezcano760f2d02008-01-10 02:53:43 -08005147 return table;
5148}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149#endif
5150
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00005151static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005152{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07005153 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005154
Alexey Dobriyan86393e52009-08-29 01:34:49 +00005155 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
5156 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005157
Eric Dumazetfc66f952010-10-08 06:37:34 +00005158 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
5159 goto out_ip6_dst_ops;
5160
David Ahern421842e2018-04-17 17:33:18 -07005161 net->ipv6.fib6_null_entry = kmemdup(&fib6_null_entry_template,
5162 sizeof(*net->ipv6.fib6_null_entry),
5163 GFP_KERNEL);
5164 if (!net->ipv6.fib6_null_entry)
5165 goto out_ip6_dst_entries;
5166
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005167 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
5168 sizeof(*net->ipv6.ip6_null_entry),
5169 GFP_KERNEL);
5170 if (!net->ipv6.ip6_null_entry)
David Ahern421842e2018-04-17 17:33:18 -07005171 goto out_fib6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005172 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005173 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
5174 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005175
5176#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Vincent Bernatfeca7d82017-08-08 20:23:49 +02005177 net->ipv6.fib6_has_custom_rules = false;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005178 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
5179 sizeof(*net->ipv6.ip6_prohibit_entry),
5180 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005181 if (!net->ipv6.ip6_prohibit_entry)
5182 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005183 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005184 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
5185 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005186
5187 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
5188 sizeof(*net->ipv6.ip6_blk_hole_entry),
5189 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005190 if (!net->ipv6.ip6_blk_hole_entry)
5191 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005192 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005193 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
5194 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005195#endif
5196
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07005197 net->ipv6.sysctl.flush_delay = 0;
5198 net->ipv6.sysctl.ip6_rt_max_size = 4096;
5199 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
5200 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
5201 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
5202 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
5203 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
5204 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
5205
Benjamin Thery6891a342008-03-04 13:49:47 -08005206 net->ipv6.ip6_rt_gc_expire = 30*HZ;
5207
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005208 ret = 0;
5209out:
5210 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005211
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005212#ifdef CONFIG_IPV6_MULTIPLE_TABLES
5213out_ip6_prohibit_entry:
5214 kfree(net->ipv6.ip6_prohibit_entry);
5215out_ip6_null_entry:
5216 kfree(net->ipv6.ip6_null_entry);
5217#endif
David Ahern421842e2018-04-17 17:33:18 -07005218out_fib6_null_entry:
5219 kfree(net->ipv6.fib6_null_entry);
Eric Dumazetfc66f952010-10-08 06:37:34 +00005220out_ip6_dst_entries:
5221 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005222out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005223 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005224}
5225
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00005226static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005227{
David Ahern421842e2018-04-17 17:33:18 -07005228 kfree(net->ipv6.fib6_null_entry);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005229 kfree(net->ipv6.ip6_null_entry);
5230#ifdef CONFIG_IPV6_MULTIPLE_TABLES
5231 kfree(net->ipv6.ip6_prohibit_entry);
5232 kfree(net->ipv6.ip6_blk_hole_entry);
5233#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00005234 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005235}
5236
Thomas Grafd1896342012-06-18 12:08:33 +00005237static int __net_init ip6_route_net_init_late(struct net *net)
5238{
5239#ifdef CONFIG_PROC_FS
Christoph Hellwigc3506372018-04-10 19:42:55 +02005240 proc_create_net("ipv6_route", 0, net->proc_net, &ipv6_route_seq_ops,
5241 sizeof(struct ipv6_route_iter));
Christoph Hellwig3617d942018-04-13 20:38:35 +02005242 proc_create_net_single("rt6_stats", 0444, net->proc_net,
5243 rt6_stats_seq_show, NULL);
Thomas Grafd1896342012-06-18 12:08:33 +00005244#endif
5245 return 0;
5246}
5247
5248static void __net_exit ip6_route_net_exit_late(struct net *net)
5249{
5250#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00005251 remove_proc_entry("ipv6_route", net->proc_net);
5252 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00005253#endif
5254}
5255
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005256static struct pernet_operations ip6_route_net_ops = {
5257 .init = ip6_route_net_init,
5258 .exit = ip6_route_net_exit,
5259};
5260
David S. Millerc3426b42012-06-09 16:27:05 -07005261static int __net_init ipv6_inetpeer_init(struct net *net)
5262{
5263 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
5264
5265 if (!bp)
5266 return -ENOMEM;
5267 inet_peer_base_init(bp);
5268 net->ipv6.peers = bp;
5269 return 0;
5270}
5271
5272static void __net_exit ipv6_inetpeer_exit(struct net *net)
5273{
5274 struct inet_peer_base *bp = net->ipv6.peers;
5275
5276 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07005277 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07005278 kfree(bp);
5279}
5280
David S. Miller2b823f72012-06-09 19:00:16 -07005281static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07005282 .init = ipv6_inetpeer_init,
5283 .exit = ipv6_inetpeer_exit,
5284};
5285
Thomas Grafd1896342012-06-18 12:08:33 +00005286static struct pernet_operations ip6_route_net_late_ops = {
5287 .init = ip6_route_net_init_late,
5288 .exit = ip6_route_net_exit_late,
5289};
5290
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005291static struct notifier_block ip6_route_dev_notifier = {
5292 .notifier_call = ip6_route_dev_notify,
WANG Cong242d3a42017-05-08 10:12:13 -07005293 .priority = ADDRCONF_NOTIFY_PRIORITY - 10,
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005294};
5295
WANG Cong2f460932017-05-03 22:07:31 -07005296void __init ip6_route_init_special_entries(void)
5297{
5298 /* Registering of the loopback is done before this portion of code,
5299 * the loopback reference in rt6_info will not be taken, do it
5300 * manually for init_net */
David Ahern421842e2018-04-17 17:33:18 -07005301 init_net.ipv6.fib6_null_entry->fib6_nh.nh_dev = init_net.loopback_dev;
WANG Cong2f460932017-05-03 22:07:31 -07005302 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
5303 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5304 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
5305 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
5306 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5307 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
5308 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5309 #endif
5310}
5311
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005312int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005314 int ret;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07005315 int cpu;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005316
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08005317 ret = -ENOMEM;
5318 ip6_dst_ops_template.kmem_cachep =
5319 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
5320 SLAB_HWCACHE_ALIGN, NULL);
5321 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08005322 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07005323
Eric Dumazetfc66f952010-10-08 06:37:34 +00005324 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005325 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08005326 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08005327
David S. Millerc3426b42012-06-09 16:27:05 -07005328 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
5329 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07005330 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00005331
David S. Miller7e52b332012-06-15 15:51:55 -07005332 ret = register_pernet_subsys(&ip6_route_net_ops);
5333 if (ret)
5334 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07005335
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07005336 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
5337
David S. Millere8803b62012-06-16 01:12:19 -07005338 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005339 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005340 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005341
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005342 ret = xfrm6_init();
5343 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07005344 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08005345
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005346 ret = fib6_rules_init();
5347 if (ret)
5348 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08005349
Thomas Grafd1896342012-06-18 12:08:33 +00005350 ret = register_pernet_subsys(&ip6_route_net_late_ops);
5351 if (ret)
5352 goto fib6_rules_init;
5353
Florian Westphal16feebc2017-12-02 21:44:08 +01005354 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_NEWROUTE,
5355 inet6_rtm_newroute, NULL, 0);
5356 if (ret < 0)
5357 goto out_register_late_subsys;
5358
5359 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_DELROUTE,
5360 inet6_rtm_delroute, NULL, 0);
5361 if (ret < 0)
5362 goto out_register_late_subsys;
5363
5364 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_GETROUTE,
5365 inet6_rtm_getroute, NULL,
5366 RTNL_FLAG_DOIT_UNLOCKED);
5367 if (ret < 0)
Thomas Grafd1896342012-06-18 12:08:33 +00005368 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005369
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005370 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005371 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00005372 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005373
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07005374 for_each_possible_cpu(cpu) {
5375 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
5376
5377 INIT_LIST_HEAD(&ul->head);
5378 spin_lock_init(&ul->lock);
5379 }
5380
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005381out:
5382 return ret;
5383
Thomas Grafd1896342012-06-18 12:08:33 +00005384out_register_late_subsys:
Florian Westphal16feebc2017-12-02 21:44:08 +01005385 rtnl_unregister_all(PF_INET6);
Thomas Grafd1896342012-06-18 12:08:33 +00005386 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005387fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005388 fib6_rules_cleanup();
5389xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005390 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00005391out_fib6_init:
5392 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005393out_register_subsys:
5394 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07005395out_register_inetpeer:
5396 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00005397out_dst_entries:
5398 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005399out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005400 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005401 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402}
5403
5404void ip6_route_cleanup(void)
5405{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005406 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00005407 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07005408 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07005411 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005412 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00005413 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005414 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005415}