blob: 1dc98715c78bae4b9c7a98954f408ec80a623b56 [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 }
David Ahernd4ead6b2018-04-17 17:33:16 -0700379
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;
Ido Schimmel8067bb82018-01-07 12:45:09 +0200495
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 }
David Ahern23fb93a2018-04-17 17:33:23 -07001086
David Ahernd4bea422018-05-09 20:34:24 -07001087 trace_fib6_table_lookup(net, f6i, table, fl6);
1088
Wei Wang2b760fc2017-10-06 12:06:03 -07001089 /* 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)
David Ahernd4ead6b2018-04-17 17:33:16 -07001383{
1384 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);
1837
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);
David Ahern4d85cd02018-04-20 15:37:59 -07001885
1886 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)
David Ahern93531c62018-04-17 17:33:25 -07002152{
2153 u32 rt_cookie = 0;
2154
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{
Steffen Klassert36143642017-08-25 09:05:42 +02002168 u32 rt_cookie = 0;
Wei Wangc5cff852017-08-21 09:47:10 -07002169
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);
2208
2209 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);
David Aherna68886a2018-04-20 15:38:02 -07002252 } else {
2253 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
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002310 if (rt6->rt6i_flags & RTF_LOCAL)
2311 return;
2312
Xin Long19bda362016-10-28 18:18:01 +08002313 if (dst_metric_locked(dst, RTAX_MTU))
2314 return;
2315
Julian Anastasov0dec8792017-02-06 23:14:16 +02002316 if (iph) {
2317 daddr = &iph->daddr;
2318 saddr = &iph->saddr;
2319 } else if (sk) {
2320 daddr = &sk->sk_v6_daddr;
2321 saddr = &inet6_sk(sk)->saddr;
2322 } else {
2323 daddr = NULL;
2324 saddr = NULL;
2325 }
2326 dst_confirm_neigh(dst, daddr);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002327 mtu = max_t(u32, mtu, IPV6_MIN_MTU);
2328 if (mtu >= dst_mtu(dst))
2329 return;
David S. Miller81aded22012-06-15 14:54:11 -07002330
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002331 if (!rt6_cache_allowed_for_pmtu(rt6)) {
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002332 rt6_do_update_pmtu(rt6, mtu);
Wei Wang2b760fc2017-10-06 12:06:03 -07002333 /* update rt6_ex->stamp for cache */
2334 if (rt6->rt6i_flags & RTF_CACHE)
2335 rt6_update_exception_stamp_rt(rt6);
Julian Anastasov0dec8792017-02-06 23:14:16 +02002336 } else if (daddr) {
David Aherna68886a2018-04-20 15:38:02 -07002337 struct fib6_info *from;
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002338 struct rt6_info *nrt6;
Hagen Paul Pfeifer9d289712015-01-15 22:34:25 +01002339
David Ahern4d85cd02018-04-20 15:37:59 -07002340 rcu_read_lock();
David Aherna68886a2018-04-20 15:38:02 -07002341 from = rcu_dereference(rt6->from);
2342 nrt6 = ip6_rt_cache_alloc(from, daddr, saddr);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002343 if (nrt6) {
2344 rt6_do_update_pmtu(nrt6, mtu);
David Aherna68886a2018-04-20 15:38:02 -07002345 if (rt6_insert_exception(nrt6, from))
Wei Wang2b760fc2017-10-06 12:06:03 -07002346 dst_release_immediate(&nrt6->dst);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002347 }
David Aherna68886a2018-04-20 15:38:02 -07002348 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 }
2350}
2351
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002352static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
2353 struct sk_buff *skb, u32 mtu)
2354{
2355 __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu);
2356}
2357
David S. Miller42ae66c2012-06-15 20:01:57 -07002358void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002359 int oif, u32 mark, kuid_t uid)
David S. Miller81aded22012-06-15 14:54:11 -07002360{
2361 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
2362 struct dst_entry *dst;
2363 struct flowi6 fl6;
2364
2365 memset(&fl6, 0, sizeof(fl6));
2366 fl6.flowi6_oif = oif;
Lorenzo Colitti1b3c61d2014-05-13 10:17:34 -07002367 fl6.flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark);
David S. Miller81aded22012-06-15 14:54:11 -07002368 fl6.daddr = iph->daddr;
2369 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00002370 fl6.flowlabel = ip6_flowinfo(iph);
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002371 fl6.flowi6_uid = uid;
David S. Miller81aded22012-06-15 14:54:11 -07002372
2373 dst = ip6_route_output(net, NULL, &fl6);
2374 if (!dst->error)
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002375 __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07002376 dst_release(dst);
2377}
2378EXPORT_SYMBOL_GPL(ip6_update_pmtu);
2379
2380void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
2381{
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07002382 struct dst_entry *dst;
2383
David S. Miller81aded22012-06-15 14:54:11 -07002384 ip6_update_pmtu(skb, sock_net(sk), mtu,
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002385 sk->sk_bound_dev_if, sk->sk_mark, sk->sk_uid);
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07002386
2387 dst = __sk_dst_get(sk);
2388 if (!dst || !dst->obsolete ||
2389 dst->ops->check(dst, inet6_sk(sk)->dst_cookie))
2390 return;
2391
2392 bh_lock_sock(sk);
2393 if (!sock_owned_by_user(sk) && !ipv6_addr_v4mapped(&sk->sk_v6_daddr))
2394 ip6_datagram_dst_update(sk, false);
2395 bh_unlock_sock(sk);
David S. Miller81aded22012-06-15 14:54:11 -07002396}
2397EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
2398
Alexey Kodanev7d6850f2018-04-03 15:00:07 +03002399void ip6_sk_dst_store_flow(struct sock *sk, struct dst_entry *dst,
2400 const struct flowi6 *fl6)
2401{
2402#ifdef CONFIG_IPV6_SUBTREES
2403 struct ipv6_pinfo *np = inet6_sk(sk);
2404#endif
2405
2406 ip6_dst_store(sk, dst,
2407 ipv6_addr_equal(&fl6->daddr, &sk->sk_v6_daddr) ?
2408 &sk->sk_v6_daddr : NULL,
2409#ifdef CONFIG_IPV6_SUBTREES
2410 ipv6_addr_equal(&fl6->saddr, &np->saddr) ?
2411 &np->saddr :
2412#endif
2413 NULL);
2414}
2415
Duan Jiongb55b76b2013-09-04 19:44:21 +08002416/* Handle redirects */
2417struct ip6rd_flowi {
2418 struct flowi6 fl6;
2419 struct in6_addr gateway;
2420};
2421
2422static struct rt6_info *__ip6_route_redirect(struct net *net,
2423 struct fib6_table *table,
2424 struct flowi6 *fl6,
David Ahernb75cc8f2018-03-02 08:32:17 -08002425 const struct sk_buff *skb,
Duan Jiongb55b76b2013-09-04 19:44:21 +08002426 int flags)
2427{
2428 struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
David Ahern23fb93a2018-04-17 17:33:23 -07002429 struct rt6_info *ret = NULL, *rt_cache;
David Ahern8d1c8022018-04-17 17:33:26 -07002430 struct fib6_info *rt;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002431 struct fib6_node *fn;
2432
2433 /* Get the "current" route for this destination and
Alexander Alemayhu67c408c2017-01-07 23:53:00 +01002434 * check if the redirect has come from appropriate router.
Duan Jiongb55b76b2013-09-04 19:44:21 +08002435 *
2436 * RFC 4861 specifies that redirects should only be
2437 * accepted if they come from the nexthop to the target.
2438 * Due to the way the routes are chosen, this notion
2439 * is a bit fuzzy and one might need to check all possible
2440 * routes.
2441 */
2442
Wei Wang66f5d6c2017-10-06 12:06:10 -07002443 rcu_read_lock();
David Ahern64547432018-05-09 20:34:19 -07002444 fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002445restart:
Wei Wang66f5d6c2017-10-06 12:06:10 -07002446 for_each_fib6_node_rt_rcu(fn) {
David Ahern5e670d82018-04-17 17:33:14 -07002447 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel8067bb82018-01-07 12:45:09 +02002448 continue;
David Ahern14895682018-04-17 17:33:17 -07002449 if (fib6_check_expired(rt))
Duan Jiongb55b76b2013-09-04 19:44:21 +08002450 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07002451 if (rt->fib6_flags & RTF_REJECT)
Duan Jiongb55b76b2013-09-04 19:44:21 +08002452 break;
David Ahern93c2fb22018-04-18 15:38:59 -07002453 if (!(rt->fib6_flags & RTF_GATEWAY))
Duan Jiongb55b76b2013-09-04 19:44:21 +08002454 continue;
David Ahern5e670d82018-04-17 17:33:14 -07002455 if (fl6->flowi6_oif != rt->fib6_nh.nh_dev->ifindex)
Duan Jiongb55b76b2013-09-04 19:44:21 +08002456 continue;
Wei Wang2b760fc2017-10-06 12:06:03 -07002457 /* rt_cache's gateway might be different from its 'parent'
2458 * in the case of an ip redirect.
2459 * So we keep searching in the exception table if the gateway
2460 * is different.
2461 */
David Ahern5e670d82018-04-17 17:33:14 -07002462 if (!ipv6_addr_equal(&rdfl->gateway, &rt->fib6_nh.nh_gw)) {
Wei Wang2b760fc2017-10-06 12:06:03 -07002463 rt_cache = rt6_find_cached_rt(rt,
2464 &fl6->daddr,
2465 &fl6->saddr);
2466 if (rt_cache &&
2467 ipv6_addr_equal(&rdfl->gateway,
2468 &rt_cache->rt6i_gateway)) {
David Ahern23fb93a2018-04-17 17:33:23 -07002469 ret = rt_cache;
Wei Wang2b760fc2017-10-06 12:06:03 -07002470 break;
2471 }
Duan Jiongb55b76b2013-09-04 19:44:21 +08002472 continue;
Wei Wang2b760fc2017-10-06 12:06:03 -07002473 }
Duan Jiongb55b76b2013-09-04 19:44:21 +08002474 break;
2475 }
2476
2477 if (!rt)
David Ahern421842e2018-04-17 17:33:18 -07002478 rt = net->ipv6.fib6_null_entry;
David Ahern93c2fb22018-04-18 15:38:59 -07002479 else if (rt->fib6_flags & RTF_REJECT) {
David Ahern23fb93a2018-04-17 17:33:23 -07002480 ret = net->ipv6.ip6_null_entry;
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08002481 goto out;
2482 }
2483
David Ahern421842e2018-04-17 17:33:18 -07002484 if (rt == net->ipv6.fib6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07002485 fn = fib6_backtrack(fn, &fl6->saddr);
2486 if (fn)
2487 goto restart;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002488 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07002489
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08002490out:
David Ahern23fb93a2018-04-17 17:33:23 -07002491 if (ret)
2492 dst_hold(&ret->dst);
2493 else
2494 ret = ip6_create_rt_rcu(rt);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002495
Wei Wang66f5d6c2017-10-06 12:06:10 -07002496 rcu_read_unlock();
Duan Jiongb55b76b2013-09-04 19:44:21 +08002497
David Ahernd4bea422018-05-09 20:34:24 -07002498 trace_fib6_table_lookup(net, rt, table, fl6);
David Ahern23fb93a2018-04-17 17:33:23 -07002499 return ret;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002500};
2501
2502static struct dst_entry *ip6_route_redirect(struct net *net,
David Ahernb75cc8f2018-03-02 08:32:17 -08002503 const struct flowi6 *fl6,
2504 const struct sk_buff *skb,
2505 const struct in6_addr *gateway)
Duan Jiongb55b76b2013-09-04 19:44:21 +08002506{
2507 int flags = RT6_LOOKUP_F_HAS_SADDR;
2508 struct ip6rd_flowi rdfl;
2509
2510 rdfl.fl6 = *fl6;
2511 rdfl.gateway = *gateway;
2512
David Ahernb75cc8f2018-03-02 08:32:17 -08002513 return fib6_rule_lookup(net, &rdfl.fl6, skb,
Duan Jiongb55b76b2013-09-04 19:44:21 +08002514 flags, __ip6_route_redirect);
2515}
2516
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002517void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark,
2518 kuid_t uid)
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002519{
2520 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
2521 struct dst_entry *dst;
2522 struct flowi6 fl6;
2523
2524 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03002525 fl6.flowi6_iif = LOOPBACK_IFINDEX;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002526 fl6.flowi6_oif = oif;
2527 fl6.flowi6_mark = mark;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002528 fl6.daddr = iph->daddr;
2529 fl6.saddr = iph->saddr;
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00002530 fl6.flowlabel = ip6_flowinfo(iph);
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002531 fl6.flowi6_uid = uid;
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002532
David Ahernb75cc8f2018-03-02 08:32:17 -08002533 dst = ip6_route_redirect(net, &fl6, skb, &ipv6_hdr(skb)->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002534 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002535 dst_release(dst);
2536}
2537EXPORT_SYMBOL_GPL(ip6_redirect);
2538
Duan Jiongc92a59e2013-08-22 12:07:35 +08002539void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
2540 u32 mark)
2541{
2542 const struct ipv6hdr *iph = ipv6_hdr(skb);
2543 const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
2544 struct dst_entry *dst;
2545 struct flowi6 fl6;
2546
2547 memset(&fl6, 0, sizeof(fl6));
Julian Anastasove374c612014-04-28 10:51:56 +03002548 fl6.flowi6_iif = LOOPBACK_IFINDEX;
Duan Jiongc92a59e2013-08-22 12:07:35 +08002549 fl6.flowi6_oif = oif;
2550 fl6.flowi6_mark = mark;
Duan Jiongc92a59e2013-08-22 12:07:35 +08002551 fl6.daddr = msg->dest;
2552 fl6.saddr = iph->daddr;
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002553 fl6.flowi6_uid = sock_net_uid(net, NULL);
Duan Jiongc92a59e2013-08-22 12:07:35 +08002554
David Ahernb75cc8f2018-03-02 08:32:17 -08002555 dst = ip6_route_redirect(net, &fl6, skb, &iph->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002556 rt6_do_redirect(dst, NULL, skb);
Duan Jiongc92a59e2013-08-22 12:07:35 +08002557 dst_release(dst);
2558}
2559
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002560void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
2561{
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002562 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark,
2563 sk->sk_uid);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002564}
2565EXPORT_SYMBOL_GPL(ip6_sk_redirect);
2566
David S. Miller0dbaee32010-12-13 12:52:14 -08002567static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568{
David S. Miller0dbaee32010-12-13 12:52:14 -08002569 struct net_device *dev = dst->dev;
2570 unsigned int mtu = dst_mtu(dst);
2571 struct net *net = dev_net(dev);
2572
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
2574
Daniel Lezcano55786892008-03-04 13:47:47 -08002575 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
2576 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577
2578 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002579 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
2580 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
2581 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 * rely only on pmtu discovery"
2583 */
2584 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
2585 mtu = IPV6_MAXPLEN;
2586 return mtu;
2587}
2588
Steffen Klassertebb762f2011-11-23 02:12:51 +00002589static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08002590{
David S. Millerd33e4552010-12-14 13:01:14 -08002591 struct inet6_dev *idev;
David Ahernd4ead6b2018-04-17 17:33:16 -07002592 unsigned int mtu;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00002593
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002594 mtu = dst_metric_raw(dst, RTAX_MTU);
2595 if (mtu)
2596 goto out;
2597
Steffen Klassert618f9bc2011-11-23 02:13:31 +00002598 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08002599
2600 rcu_read_lock();
2601 idev = __in6_dev_get(dst->dev);
2602 if (idev)
2603 mtu = idev->cnf.mtu6;
2604 rcu_read_unlock();
2605
Eric Dumazet30f78d82014-04-10 21:23:36 -07002606out:
Roopa Prabhu14972cb2016-08-24 20:10:43 -07002607 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
2608
2609 return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
David S. Millerd33e4552010-12-14 13:01:14 -08002610}
2611
David Ahern901731b2018-05-21 09:08:14 -07002612/* MTU selection:
2613 * 1. mtu on route is locked - use it
2614 * 2. mtu from nexthop exception
2615 * 3. mtu from egress device
2616 *
2617 * based on ip6_dst_mtu_forward and exception logic of
2618 * rt6_find_cached_rt; called with rcu_read_lock
2619 */
2620u32 ip6_mtu_from_fib6(struct fib6_info *f6i, struct in6_addr *daddr,
2621 struct in6_addr *saddr)
2622{
2623 struct rt6_exception_bucket *bucket;
2624 struct rt6_exception *rt6_ex;
2625 struct in6_addr *src_key;
2626 struct inet6_dev *idev;
2627 u32 mtu = 0;
2628
2629 if (unlikely(fib6_metric_locked(f6i, RTAX_MTU))) {
2630 mtu = f6i->fib6_pmtu;
2631 if (mtu)
2632 goto out;
2633 }
2634
2635 src_key = NULL;
2636#ifdef CONFIG_IPV6_SUBTREES
2637 if (f6i->fib6_src.plen)
2638 src_key = saddr;
2639#endif
2640
2641 bucket = rcu_dereference(f6i->rt6i_exception_bucket);
2642 rt6_ex = __rt6_find_exception_rcu(&bucket, daddr, src_key);
2643 if (rt6_ex && !rt6_check_expired(rt6_ex->rt6i))
2644 mtu = dst_metric_raw(&rt6_ex->rt6i->dst, RTAX_MTU);
2645
2646 if (likely(!mtu)) {
2647 struct net_device *dev = fib6_info_nh_dev(f6i);
2648
2649 mtu = IPV6_MIN_MTU;
2650 idev = __in6_dev_get(dev);
2651 if (idev && idev->cnf.mtu6 > mtu)
2652 mtu = idev->cnf.mtu6;
2653 }
2654
2655 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
2656out:
2657 return mtu - lwtunnel_headroom(fib6_info_nh_lwt(f6i), mtu);
2658}
2659
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08002660struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05002661 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662{
David S. Miller87a11572011-12-06 17:04:13 -05002663 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 struct rt6_info *rt;
2665 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002666 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667
David S. Miller38308472011-12-03 18:02:47 -05002668 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00002669 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670
Martin KaFai Lauad706862015-08-14 11:05:52 -07002671 rt = ip6_dst_alloc(net, dev, 0);
David S. Miller38308472011-12-03 18:02:47 -05002672 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05002674 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 goto out;
2676 }
2677
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002678 rt->dst.flags |= DST_HOST;
Brendan McGrath588753f2017-12-13 22:14:57 +11002679 rt->dst.input = ip6_input;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002680 rt->dst.output = ip6_output;
Julian Anastasov550bab42013-10-20 15:43:04 +03002681 rt->rt6i_gateway = fl6->daddr;
David S. Miller87a11572011-12-06 17:04:13 -05002682 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002683 rt->rt6i_dst.plen = 128;
2684 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08002685 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686
Ido Schimmel4c981e22018-01-07 12:45:04 +02002687 /* Add this dst into uncached_list so that rt6_disable_ip() can
Wei Wang587fea72017-06-17 10:42:36 -07002688 * do proper release of the net_device
2689 */
2690 rt6_uncached_list_add(rt);
Wei Wang81eb8442017-10-06 12:06:11 -07002691 atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692
David S. Miller87a11572011-12-06 17:04:13 -05002693 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
2694
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695out:
David S. Miller87a11572011-12-06 17:04:13 -05002696 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697}
2698
Daniel Lezcano569d3642008-01-18 03:56:57 -08002699static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700{
Alexey Dobriyan86393e52009-08-29 01:34:49 +00002701 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08002702 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
2703 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
2704 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
2705 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
2706 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00002707 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708
Eric Dumazetfc66f952010-10-08 06:37:34 +00002709 entries = dst_entries_get_fast(ops);
Michal Kubeček49a18d82013-08-01 10:04:24 +02002710 if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00002711 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 goto out;
2713
Benjamin Thery6891a342008-03-04 13:49:47 -08002714 net->ipv6.ip6_rt_gc_expire++;
Li RongQing14956642014-05-19 17:30:28 +08002715 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
Eric Dumazetfc66f952010-10-08 06:37:34 +00002716 entries = dst_entries_get_slow(ops);
2717 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08002718 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08002720 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00002721 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722}
2723
David Ahern8d1c8022018-04-17 17:33:26 -07002724static int ip6_convert_metrics(struct net *net, struct fib6_info *rt,
David Ahernd4ead6b2018-04-17 17:33:16 -07002725 struct fib6_config *cfg)
Florian Westphale715b6d2015-01-05 23:57:44 +01002726{
Eric Dumazet263243d2018-04-19 09:14:53 -07002727 struct dst_metrics *p;
Florian Westphale715b6d2015-01-05 23:57:44 +01002728
Eric Dumazet263243d2018-04-19 09:14:53 -07002729 if (!cfg->fc_mx)
2730 return 0;
Florian Westphale715b6d2015-01-05 23:57:44 +01002731
Eric Dumazet263243d2018-04-19 09:14:53 -07002732 p = kzalloc(sizeof(*rt->fib6_metrics), GFP_KERNEL);
2733 if (unlikely(!p))
2734 return -ENOMEM;
Florian Westphale715b6d2015-01-05 23:57:44 +01002735
Eric Dumazet263243d2018-04-19 09:14:53 -07002736 refcount_set(&p->refcnt, 1);
2737 rt->fib6_metrics = p;
Florian Westphale715b6d2015-01-05 23:57:44 +01002738
Eric Dumazet263243d2018-04-19 09:14:53 -07002739 return ip_metrics_convert(net, cfg->fc_mx, cfg->fc_mx_len, p->metrics);
Florian Westphale715b6d2015-01-05 23:57:44 +01002740}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741
David Ahern8c145862016-04-24 21:26:04 -07002742static struct rt6_info *ip6_nh_lookup_table(struct net *net,
2743 struct fib6_config *cfg,
David Ahernf4797b32018-01-25 16:55:08 -08002744 const struct in6_addr *gw_addr,
2745 u32 tbid, int flags)
David Ahern8c145862016-04-24 21:26:04 -07002746{
2747 struct flowi6 fl6 = {
2748 .flowi6_oif = cfg->fc_ifindex,
2749 .daddr = *gw_addr,
2750 .saddr = cfg->fc_prefsrc,
2751 };
2752 struct fib6_table *table;
2753 struct rt6_info *rt;
David Ahern8c145862016-04-24 21:26:04 -07002754
David Ahernf4797b32018-01-25 16:55:08 -08002755 table = fib6_get_table(net, tbid);
David Ahern8c145862016-04-24 21:26:04 -07002756 if (!table)
2757 return NULL;
2758
2759 if (!ipv6_addr_any(&cfg->fc_prefsrc))
2760 flags |= RT6_LOOKUP_F_HAS_SADDR;
2761
David Ahernf4797b32018-01-25 16:55:08 -08002762 flags |= RT6_LOOKUP_F_IGNORE_LINKSTATE;
David Ahernb75cc8f2018-03-02 08:32:17 -08002763 rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, NULL, flags);
David Ahern8c145862016-04-24 21:26:04 -07002764
2765 /* if table lookup failed, fall back to full lookup */
2766 if (rt == net->ipv6.ip6_null_entry) {
2767 ip6_rt_put(rt);
2768 rt = NULL;
2769 }
2770
2771 return rt;
2772}
2773
David Ahernfc1e64e2018-01-25 16:55:09 -08002774static int ip6_route_check_nh_onlink(struct net *net,
2775 struct fib6_config *cfg,
David Ahern9fbb7042018-03-13 08:29:36 -07002776 const struct net_device *dev,
David Ahernfc1e64e2018-01-25 16:55:09 -08002777 struct netlink_ext_ack *extack)
2778{
David Ahern44750f82018-02-06 13:17:06 -08002779 u32 tbid = l3mdev_fib_table(dev) ? : RT_TABLE_MAIN;
David Ahernfc1e64e2018-01-25 16:55:09 -08002780 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2781 u32 flags = RTF_LOCAL | RTF_ANYCAST | RTF_REJECT;
2782 struct rt6_info *grt;
2783 int err;
2784
2785 err = 0;
2786 grt = ip6_nh_lookup_table(net, cfg, gw_addr, tbid, 0);
2787 if (grt) {
David Ahern58e354c2018-02-06 12:14:12 -08002788 if (!grt->dst.error &&
2789 (grt->rt6i_flags & flags || dev != grt->dst.dev)) {
David Ahern44750f82018-02-06 13:17:06 -08002790 NL_SET_ERR_MSG(extack,
2791 "Nexthop has invalid gateway or device mismatch");
David Ahernfc1e64e2018-01-25 16:55:09 -08002792 err = -EINVAL;
2793 }
2794
2795 ip6_rt_put(grt);
2796 }
2797
2798 return err;
2799}
2800
David Ahern1edce992018-01-25 16:55:07 -08002801static int ip6_route_check_nh(struct net *net,
2802 struct fib6_config *cfg,
2803 struct net_device **_dev,
2804 struct inet6_dev **idev)
2805{
2806 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2807 struct net_device *dev = _dev ? *_dev : NULL;
2808 struct rt6_info *grt = NULL;
2809 int err = -EHOSTUNREACH;
2810
2811 if (cfg->fc_table) {
David Ahernf4797b32018-01-25 16:55:08 -08002812 int flags = RT6_LOOKUP_F_IFACE;
2813
2814 grt = ip6_nh_lookup_table(net, cfg, gw_addr,
2815 cfg->fc_table, flags);
David Ahern1edce992018-01-25 16:55:07 -08002816 if (grt) {
2817 if (grt->rt6i_flags & RTF_GATEWAY ||
2818 (dev && dev != grt->dst.dev)) {
2819 ip6_rt_put(grt);
2820 grt = NULL;
2821 }
2822 }
2823 }
2824
2825 if (!grt)
David Ahernb75cc8f2018-03-02 08:32:17 -08002826 grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, NULL, 1);
David Ahern1edce992018-01-25 16:55:07 -08002827
2828 if (!grt)
2829 goto out;
2830
2831 if (dev) {
2832 if (dev != grt->dst.dev) {
2833 ip6_rt_put(grt);
2834 goto out;
2835 }
2836 } else {
2837 *_dev = dev = grt->dst.dev;
2838 *idev = grt->rt6i_idev;
2839 dev_hold(dev);
2840 in6_dev_hold(grt->rt6i_idev);
2841 }
2842
2843 if (!(grt->rt6i_flags & RTF_GATEWAY))
2844 err = 0;
2845
2846 ip6_rt_put(grt);
2847
2848out:
2849 return err;
2850}
2851
David Ahern9fbb7042018-03-13 08:29:36 -07002852static int ip6_validate_gw(struct net *net, struct fib6_config *cfg,
2853 struct net_device **_dev, struct inet6_dev **idev,
2854 struct netlink_ext_ack *extack)
2855{
2856 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2857 int gwa_type = ipv6_addr_type(gw_addr);
David Ahern232378e2018-03-13 08:29:37 -07002858 bool skip_dev = gwa_type & IPV6_ADDR_LINKLOCAL ? false : true;
David Ahern9fbb7042018-03-13 08:29:36 -07002859 const struct net_device *dev = *_dev;
David Ahern232378e2018-03-13 08:29:37 -07002860 bool need_addr_check = !dev;
David Ahern9fbb7042018-03-13 08:29:36 -07002861 int err = -EINVAL;
2862
2863 /* if gw_addr is local we will fail to detect this in case
2864 * address is still TENTATIVE (DAD in progress). rt6_lookup()
2865 * will return already-added prefix route via interface that
2866 * prefix route was assigned to, which might be non-loopback.
2867 */
David Ahern232378e2018-03-13 08:29:37 -07002868 if (dev &&
2869 ipv6_chk_addr_and_flags(net, gw_addr, dev, skip_dev, 0, 0)) {
2870 NL_SET_ERR_MSG(extack, "Gateway can not be a local address");
David Ahern9fbb7042018-03-13 08:29:36 -07002871 goto out;
2872 }
2873
2874 if (gwa_type != (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST)) {
2875 /* IPv6 strictly inhibits using not link-local
2876 * addresses as nexthop address.
2877 * Otherwise, router will not able to send redirects.
2878 * It is very good, but in some (rare!) circumstances
2879 * (SIT, PtP, NBMA NOARP links) it is handy to allow
2880 * some exceptions. --ANK
2881 * We allow IPv4-mapped nexthops to support RFC4798-type
2882 * addressing
2883 */
2884 if (!(gwa_type & (IPV6_ADDR_UNICAST | IPV6_ADDR_MAPPED))) {
2885 NL_SET_ERR_MSG(extack, "Invalid gateway address");
2886 goto out;
2887 }
2888
2889 if (cfg->fc_flags & RTNH_F_ONLINK)
2890 err = ip6_route_check_nh_onlink(net, cfg, dev, extack);
2891 else
2892 err = ip6_route_check_nh(net, cfg, _dev, idev);
2893
2894 if (err)
2895 goto out;
2896 }
2897
2898 /* reload in case device was changed */
2899 dev = *_dev;
2900
2901 err = -EINVAL;
2902 if (!dev) {
2903 NL_SET_ERR_MSG(extack, "Egress device not specified");
2904 goto out;
2905 } else if (dev->flags & IFF_LOOPBACK) {
2906 NL_SET_ERR_MSG(extack,
2907 "Egress device can not be loopback device for this route");
2908 goto out;
2909 }
David Ahern232378e2018-03-13 08:29:37 -07002910
2911 /* if we did not check gw_addr above, do so now that the
2912 * egress device has been resolved.
2913 */
2914 if (need_addr_check &&
2915 ipv6_chk_addr_and_flags(net, gw_addr, dev, skip_dev, 0, 0)) {
2916 NL_SET_ERR_MSG(extack, "Gateway can not be a local address");
2917 goto out;
2918 }
2919
David Ahern9fbb7042018-03-13 08:29:36 -07002920 err = 0;
2921out:
2922 return err;
2923}
2924
David Ahern8d1c8022018-04-17 17:33:26 -07002925static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
David Ahernacb54e32018-04-17 17:33:22 -07002926 gfp_t gfp_flags,
David Ahern333c4302017-05-21 10:12:04 -06002927 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928{
Daniel Lezcano55786892008-03-04 13:47:47 -08002929 struct net *net = cfg->fc_nlinfo.nl_net;
David Ahern8d1c8022018-04-17 17:33:26 -07002930 struct fib6_info *rt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 struct net_device *dev = NULL;
2932 struct inet6_dev *idev = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07002933 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 int addr_type;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002935 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936
David Ahern557c44b2017-04-19 14:19:43 -07002937 /* RTF_PCPU is an internal flag; can not be set by userspace */
David Ahernd5d531c2017-05-21 10:12:05 -06002938 if (cfg->fc_flags & RTF_PCPU) {
2939 NL_SET_ERR_MSG(extack, "Userspace can not set RTF_PCPU");
David Ahern557c44b2017-04-19 14:19:43 -07002940 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002941 }
David Ahern557c44b2017-04-19 14:19:43 -07002942
Wei Wang2ea23522017-10-27 17:30:12 -07002943 /* RTF_CACHE is an internal flag; can not be set by userspace */
2944 if (cfg->fc_flags & RTF_CACHE) {
2945 NL_SET_ERR_MSG(extack, "Userspace can not set RTF_CACHE");
2946 goto out;
2947 }
2948
David Aherne8478e82018-04-17 17:33:13 -07002949 if (cfg->fc_type > RTN_MAX) {
2950 NL_SET_ERR_MSG(extack, "Invalid route type");
2951 goto out;
2952 }
2953
David Ahernd5d531c2017-05-21 10:12:05 -06002954 if (cfg->fc_dst_len > 128) {
2955 NL_SET_ERR_MSG(extack, "Invalid prefix length");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002956 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002957 }
2958 if (cfg->fc_src_len > 128) {
2959 NL_SET_ERR_MSG(extack, "Invalid source address length");
2960 goto out;
2961 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962#ifndef CONFIG_IPV6_SUBTREES
David Ahernd5d531c2017-05-21 10:12:05 -06002963 if (cfg->fc_src_len) {
2964 NL_SET_ERR_MSG(extack,
2965 "Specifying source address requires IPV6_SUBTREES to be enabled");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07002966 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06002967 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968#endif
Thomas Graf86872cb2006-08-22 00:01:08 -07002969 if (cfg->fc_ifindex) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 err = -ENODEV;
Daniel Lezcano55786892008-03-04 13:47:47 -08002971 dev = dev_get_by_index(net, cfg->fc_ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 if (!dev)
2973 goto out;
2974 idev = in6_dev_get(dev);
2975 if (!idev)
2976 goto out;
2977 }
2978
Thomas Graf86872cb2006-08-22 00:01:08 -07002979 if (cfg->fc_metric == 0)
2980 cfg->fc_metric = IP6_RT_PRIO_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981
David Ahernfc1e64e2018-01-25 16:55:09 -08002982 if (cfg->fc_flags & RTNH_F_ONLINK) {
2983 if (!dev) {
2984 NL_SET_ERR_MSG(extack,
2985 "Nexthop device required for onlink");
2986 err = -ENODEV;
2987 goto out;
2988 }
2989
2990 if (!(dev->flags & IFF_UP)) {
2991 NL_SET_ERR_MSG(extack, "Nexthop device is not up");
2992 err = -ENETDOWN;
2993 goto out;
2994 }
2995 }
2996
Matti Vaittinend71314b2011-11-14 00:14:49 +00002997 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05002998 if (cfg->fc_nlinfo.nlh &&
2999 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00003000 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05003001 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00003002 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00003003 table = fib6_new_table(net, cfg->fc_table);
3004 }
3005 } else {
3006 table = fib6_new_table(net, cfg->fc_table);
3007 }
David S. Miller38308472011-12-03 18:02:47 -05003008
3009 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07003010 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07003011
David Ahern93531c62018-04-17 17:33:25 -07003012 err = -ENOMEM;
3013 rt = fib6_info_alloc(gfp_flags);
3014 if (!rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 goto out;
David Ahern93531c62018-04-17 17:33:25 -07003016
3017 if (cfg->fc_flags & RTF_ADDRCONF)
3018 rt->dst_nocount = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019
David Ahernd4ead6b2018-04-17 17:33:16 -07003020 err = ip6_convert_metrics(net, rt, cfg);
3021 if (err < 0)
3022 goto out;
3023
Gao feng1716a962012-04-06 00:13:10 +00003024 if (cfg->fc_flags & RTF_EXPIRES)
David Ahern14895682018-04-17 17:33:17 -07003025 fib6_set_expires(rt, jiffies +
Gao feng1716a962012-04-06 00:13:10 +00003026 clock_t_to_jiffies(cfg->fc_expires));
3027 else
David Ahern14895682018-04-17 17:33:17 -07003028 fib6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029
Thomas Graf86872cb2006-08-22 00:01:08 -07003030 if (cfg->fc_protocol == RTPROT_UNSPEC)
3031 cfg->fc_protocol = RTPROT_BOOT;
David Ahern93c2fb22018-04-18 15:38:59 -07003032 rt->fib6_protocol = cfg->fc_protocol;
Thomas Graf86872cb2006-08-22 00:01:08 -07003033
3034 addr_type = ipv6_addr_type(&cfg->fc_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003036 if (cfg->fc_encap) {
3037 struct lwtunnel_state *lwtstate;
3038
David Ahern30357d72017-01-30 12:07:37 -08003039 err = lwtunnel_build_state(cfg->fc_encap_type,
Tom Herbert127eb7c2015-08-24 09:45:41 -07003040 cfg->fc_encap, AF_INET6, cfg,
David Ahern9ae28722017-05-27 16:19:28 -06003041 &lwtstate, extack);
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003042 if (err)
3043 goto out;
David Ahern5e670d82018-04-17 17:33:14 -07003044 rt->fib6_nh.nh_lwtstate = lwtstate_get(lwtstate);
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003045 }
3046
David Ahern93c2fb22018-04-18 15:38:59 -07003047 ipv6_addr_prefix(&rt->fib6_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
3048 rt->fib6_dst.plen = cfg->fc_dst_len;
3049 if (rt->fib6_dst.plen == 128)
David Ahern3b6761d2018-04-17 17:33:20 -07003050 rt->dst_host = true;
Michal Kubečeke5fd3872014-03-27 13:04:08 +01003051
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052#ifdef CONFIG_IPV6_SUBTREES
David Ahern93c2fb22018-04-18 15:38:59 -07003053 ipv6_addr_prefix(&rt->fib6_src.addr, &cfg->fc_src, cfg->fc_src_len);
3054 rt->fib6_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055#endif
3056
David Ahern93c2fb22018-04-18 15:38:59 -07003057 rt->fib6_metric = cfg->fc_metric;
David Ahern5e670d82018-04-17 17:33:14 -07003058 rt->fib6_nh.nh_weight = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059
David Aherne8478e82018-04-17 17:33:13 -07003060 rt->fib6_type = cfg->fc_type;
3061
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 /* We cannot add true routes via loopback here,
3063 they would result in kernel looping; promote them to reject routes
3064 */
Thomas Graf86872cb2006-08-22 00:01:08 -07003065 if ((cfg->fc_flags & RTF_REJECT) ||
David S. Miller38308472011-12-03 18:02:47 -05003066 (dev && (dev->flags & IFF_LOOPBACK) &&
3067 !(addr_type & IPV6_ADDR_LOOPBACK) &&
3068 !(cfg->fc_flags & RTF_LOCAL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 /* hold loopback dev/idev if we haven't done so. */
Daniel Lezcano55786892008-03-04 13:47:47 -08003070 if (dev != net->loopback_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 if (dev) {
3072 dev_put(dev);
3073 in6_dev_put(idev);
3074 }
Daniel Lezcano55786892008-03-04 13:47:47 -08003075 dev = net->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 dev_hold(dev);
3077 idev = in6_dev_get(dev);
3078 if (!idev) {
3079 err = -ENODEV;
3080 goto out;
3081 }
3082 }
David Ahern93c2fb22018-04-18 15:38:59 -07003083 rt->fib6_flags = RTF_REJECT|RTF_NONEXTHOP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 goto install_route;
3085 }
3086
Thomas Graf86872cb2006-08-22 00:01:08 -07003087 if (cfg->fc_flags & RTF_GATEWAY) {
David Ahern9fbb7042018-03-13 08:29:36 -07003088 err = ip6_validate_gw(net, cfg, &dev, &idev, extack);
3089 if (err)
Florian Westphal48ed7b22015-05-21 00:25:41 +02003090 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091
David Ahern93531c62018-04-17 17:33:25 -07003092 rt->fib6_nh.nh_gw = cfg->fc_gateway;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 }
3094
3095 err = -ENODEV;
David S. Miller38308472011-12-03 18:02:47 -05003096 if (!dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 goto out;
3098
Lorenzo Bianconi428604f2018-03-29 11:02:24 +02003099 if (idev->cnf.disable_ipv6) {
3100 NL_SET_ERR_MSG(extack, "IPv6 is disabled on nexthop device");
3101 err = -EACCES;
3102 goto out;
3103 }
3104
David Ahern955ec4c2018-01-24 19:45:29 -08003105 if (!(dev->flags & IFF_UP)) {
3106 NL_SET_ERR_MSG(extack, "Nexthop device is not up");
3107 err = -ENETDOWN;
3108 goto out;
3109 }
3110
Daniel Walterc3968a82011-04-13 21:10:57 +00003111 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
3112 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
David Ahernd5d531c2017-05-21 10:12:05 -06003113 NL_SET_ERR_MSG(extack, "Invalid source address");
Daniel Walterc3968a82011-04-13 21:10:57 +00003114 err = -EINVAL;
3115 goto out;
3116 }
David Ahern93c2fb22018-04-18 15:38:59 -07003117 rt->fib6_prefsrc.addr = cfg->fc_prefsrc;
3118 rt->fib6_prefsrc.plen = 128;
Daniel Walterc3968a82011-04-13 21:10:57 +00003119 } else
David Ahern93c2fb22018-04-18 15:38:59 -07003120 rt->fib6_prefsrc.plen = 0;
Daniel Walterc3968a82011-04-13 21:10:57 +00003121
David Ahern93c2fb22018-04-18 15:38:59 -07003122 rt->fib6_flags = cfg->fc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123
3124install_route:
David Ahern93c2fb22018-04-18 15:38:59 -07003125 if (!(rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) &&
Ido Schimmel5609b802018-01-07 12:45:06 +02003126 !netif_carrier_ok(dev))
David Ahern5e670d82018-04-17 17:33:14 -07003127 rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN;
3128 rt->fib6_nh.nh_flags |= (cfg->fc_flags & RTNH_F_ONLINK);
David Ahern93531c62018-04-17 17:33:25 -07003129 rt->fib6_nh.nh_dev = dev;
David Ahern93c2fb22018-04-18 15:38:59 -07003130 rt->fib6_table = table;
Daniel Lezcano63152fc2008-03-03 23:31:11 -08003131
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09003132 cfg->fc_nlinfo.nl_net = dev_net(dev);
Daniel Lezcano63152fc2008-03-03 23:31:11 -08003133
David Aherndcd1f572018-04-18 15:39:05 -07003134 if (idev)
3135 in6_dev_put(idev);
3136
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003137 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138out:
3139 if (dev)
3140 dev_put(dev);
3141 if (idev)
3142 in6_dev_put(idev);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003143
David Ahern93531c62018-04-17 17:33:25 -07003144 fib6_info_release(rt);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003145 return ERR_PTR(err);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003146}
3147
David Ahernacb54e32018-04-17 17:33:22 -07003148int ip6_route_add(struct fib6_config *cfg, gfp_t gfp_flags,
3149 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003150{
David Ahern8d1c8022018-04-17 17:33:26 -07003151 struct fib6_info *rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003152 int err;
3153
David Ahernacb54e32018-04-17 17:33:22 -07003154 rt = ip6_route_info_create(cfg, gfp_flags, extack);
David Ahernd4ead6b2018-04-17 17:33:16 -07003155 if (IS_ERR(rt))
3156 return PTR_ERR(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003157
David Ahernd4ead6b2018-04-17 17:33:16 -07003158 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack);
David Ahern93531c62018-04-17 17:33:25 -07003159 fib6_info_release(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003160
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 return err;
3162}
3163
David Ahern8d1c8022018-04-17 17:33:26 -07003164static int __ip6_del_rt(struct fib6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165{
David Ahernafb1d4b52018-04-17 17:33:11 -07003166 struct net *net = info->nl_net;
Thomas Grafc71099a2006-08-04 23:20:06 -07003167 struct fib6_table *table;
David Ahernafb1d4b52018-04-17 17:33:11 -07003168 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169
David Ahern421842e2018-04-17 17:33:18 -07003170 if (rt == net->ipv6.fib6_null_entry) {
Gao feng6825a262012-09-19 19:25:34 +00003171 err = -ENOENT;
3172 goto out;
3173 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07003174
David Ahern93c2fb22018-04-18 15:38:59 -07003175 table = rt->fib6_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003176 spin_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07003177 err = fib6_del(rt, info);
Wei Wang66f5d6c2017-10-06 12:06:10 -07003178 spin_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179
Gao feng6825a262012-09-19 19:25:34 +00003180out:
David Ahern93531c62018-04-17 17:33:25 -07003181 fib6_info_release(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 return err;
3183}
3184
David Ahern8d1c8022018-04-17 17:33:26 -07003185int ip6_del_rt(struct net *net, struct fib6_info *rt)
Thomas Grafe0a1ad732006-08-22 00:00:21 -07003186{
David Ahernafb1d4b52018-04-17 17:33:11 -07003187 struct nl_info info = { .nl_net = net };
3188
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003189 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07003190}
3191
David Ahern8d1c8022018-04-17 17:33:26 -07003192static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg)
David Ahern0ae81332017-02-02 12:37:08 -08003193{
3194 struct nl_info *info = &cfg->fc_nlinfo;
WANG Conge3330032017-02-27 16:07:43 -08003195 struct net *net = info->nl_net;
David Ahern16a16cd2017-02-02 12:37:11 -08003196 struct sk_buff *skb = NULL;
David Ahern0ae81332017-02-02 12:37:08 -08003197 struct fib6_table *table;
WANG Conge3330032017-02-27 16:07:43 -08003198 int err = -ENOENT;
David Ahern0ae81332017-02-02 12:37:08 -08003199
David Ahern421842e2018-04-17 17:33:18 -07003200 if (rt == net->ipv6.fib6_null_entry)
WANG Conge3330032017-02-27 16:07:43 -08003201 goto out_put;
David Ahern93c2fb22018-04-18 15:38:59 -07003202 table = rt->fib6_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003203 spin_lock_bh(&table->tb6_lock);
David Ahern0ae81332017-02-02 12:37:08 -08003204
David Ahern93c2fb22018-04-18 15:38:59 -07003205 if (rt->fib6_nsiblings && cfg->fc_delete_all_nh) {
David Ahern8d1c8022018-04-17 17:33:26 -07003206 struct fib6_info *sibling, *next_sibling;
David Ahern0ae81332017-02-02 12:37:08 -08003207
David Ahern16a16cd2017-02-02 12:37:11 -08003208 /* prefer to send a single notification with all hops */
3209 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
3210 if (skb) {
3211 u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
3212
David Ahernd4ead6b2018-04-17 17:33:16 -07003213 if (rt6_fill_node(net, skb, rt, NULL,
David Ahern16a16cd2017-02-02 12:37:11 -08003214 NULL, NULL, 0, RTM_DELROUTE,
3215 info->portid, seq, 0) < 0) {
3216 kfree_skb(skb);
3217 skb = NULL;
3218 } else
3219 info->skip_notify = 1;
3220 }
3221
David Ahern0ae81332017-02-02 12:37:08 -08003222 list_for_each_entry_safe(sibling, next_sibling,
David Ahern93c2fb22018-04-18 15:38:59 -07003223 &rt->fib6_siblings,
3224 fib6_siblings) {
David Ahern0ae81332017-02-02 12:37:08 -08003225 err = fib6_del(sibling, info);
3226 if (err)
WANG Conge3330032017-02-27 16:07:43 -08003227 goto out_unlock;
David Ahern0ae81332017-02-02 12:37:08 -08003228 }
3229 }
3230
3231 err = fib6_del(rt, info);
WANG Conge3330032017-02-27 16:07:43 -08003232out_unlock:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003233 spin_unlock_bh(&table->tb6_lock);
WANG Conge3330032017-02-27 16:07:43 -08003234out_put:
David Ahern93531c62018-04-17 17:33:25 -07003235 fib6_info_release(rt);
David Ahern16a16cd2017-02-02 12:37:11 -08003236
3237 if (skb) {
WANG Conge3330032017-02-27 16:07:43 -08003238 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
David Ahern16a16cd2017-02-02 12:37:11 -08003239 info->nlh, gfp_any());
3240 }
David Ahern0ae81332017-02-02 12:37:08 -08003241 return err;
3242}
3243
David Ahern23fb93a2018-04-17 17:33:23 -07003244static int ip6_del_cached_rt(struct rt6_info *rt, struct fib6_config *cfg)
3245{
3246 int rc = -ESRCH;
3247
3248 if (cfg->fc_ifindex && rt->dst.dev->ifindex != cfg->fc_ifindex)
3249 goto out;
3250
3251 if (cfg->fc_flags & RTF_GATEWAY &&
3252 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
3253 goto out;
3254 if (dst_hold_safe(&rt->dst))
3255 rc = rt6_remove_exception_rt(rt);
3256out:
3257 return rc;
3258}
3259
David Ahern333c4302017-05-21 10:12:04 -06003260static int ip6_route_del(struct fib6_config *cfg,
3261 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262{
David Ahern8d1c8022018-04-17 17:33:26 -07003263 struct rt6_info *rt_cache;
Thomas Grafc71099a2006-08-04 23:20:06 -07003264 struct fib6_table *table;
David Ahern8d1c8022018-04-17 17:33:26 -07003265 struct fib6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 struct fib6_node *fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267 int err = -ESRCH;
3268
Daniel Lezcano55786892008-03-04 13:47:47 -08003269 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David Ahernd5d531c2017-05-21 10:12:05 -06003270 if (!table) {
3271 NL_SET_ERR_MSG(extack, "FIB table does not exist");
Thomas Grafc71099a2006-08-04 23:20:06 -07003272 return err;
David Ahernd5d531c2017-05-21 10:12:05 -06003273 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274
Wei Wang66f5d6c2017-10-06 12:06:10 -07003275 rcu_read_lock();
Thomas Grafc71099a2006-08-04 23:20:06 -07003276
3277 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07003278 &cfg->fc_dst, cfg->fc_dst_len,
Wei Wang38fbeee2017-10-06 12:06:02 -07003279 &cfg->fc_src, cfg->fc_src_len,
Wei Wang2b760fc2017-10-06 12:06:03 -07003280 !(cfg->fc_flags & RTF_CACHE));
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003281
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 if (fn) {
Wei Wang66f5d6c2017-10-06 12:06:10 -07003283 for_each_fib6_node_rt_rcu(fn) {
Wei Wang2b760fc2017-10-06 12:06:03 -07003284 if (cfg->fc_flags & RTF_CACHE) {
David Ahern23fb93a2018-04-17 17:33:23 -07003285 int rc;
3286
Wei Wang2b760fc2017-10-06 12:06:03 -07003287 rt_cache = rt6_find_cached_rt(rt, &cfg->fc_dst,
3288 &cfg->fc_src);
David Ahern23fb93a2018-04-17 17:33:23 -07003289 if (rt_cache) {
3290 rc = ip6_del_cached_rt(rt_cache, cfg);
Eric Dumazet9e575012018-05-09 10:05:46 -07003291 if (rc != -ESRCH) {
3292 rcu_read_unlock();
David Ahern23fb93a2018-04-17 17:33:23 -07003293 return rc;
Eric Dumazet9e575012018-05-09 10:05:46 -07003294 }
David Ahern23fb93a2018-04-17 17:33:23 -07003295 }
3296 continue;
Wei Wang2b760fc2017-10-06 12:06:03 -07003297 }
Thomas Graf86872cb2006-08-22 00:01:08 -07003298 if (cfg->fc_ifindex &&
David Ahern5e670d82018-04-17 17:33:14 -07003299 (!rt->fib6_nh.nh_dev ||
3300 rt->fib6_nh.nh_dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07003302 if (cfg->fc_flags & RTF_GATEWAY &&
David Ahern5e670d82018-04-17 17:33:14 -07003303 !ipv6_addr_equal(&cfg->fc_gateway, &rt->fib6_nh.nh_gw))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07003305 if (cfg->fc_metric && cfg->fc_metric != rt->fib6_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07003307 if (cfg->fc_protocol && cfg->fc_protocol != rt->fib6_protocol)
Mantas Mc2ed1882016-12-16 10:30:59 +02003308 continue;
David Ahern93531c62018-04-17 17:33:25 -07003309 fib6_info_hold(rt);
Wei Wang66f5d6c2017-10-06 12:06:10 -07003310 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311
David Ahern0ae81332017-02-02 12:37:08 -08003312 /* if gateway was specified only delete the one hop */
3313 if (cfg->fc_flags & RTF_GATEWAY)
3314 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
3315
3316 return __ip6_del_rt_siblings(rt, cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 }
3318 }
Wei Wang66f5d6c2017-10-06 12:06:10 -07003319 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320
3321 return err;
3322}
3323
David S. Miller6700c272012-07-17 03:29:28 -07003324static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07003325{
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07003326 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07003327 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07003328 struct ndisc_options ndopts;
3329 struct inet6_dev *in6_dev;
3330 struct neighbour *neigh;
David Aherna68886a2018-04-20 15:38:02 -07003331 struct fib6_info *from;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003332 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07003333 int optlen, on_link;
3334 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07003335
Simon Horman29a3cad2013-05-28 20:34:26 +00003336 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003337 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07003338
3339 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07003340 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003341 return;
3342 }
3343
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003344 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07003345
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003346 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07003347 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003348 return;
3349 }
3350
David S. Miller6e157b62012-07-12 00:05:02 -07003351 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003352 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07003353 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003354 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07003355 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07003356 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003357 return;
3358 }
3359
3360 in6_dev = __in6_dev_get(skb->dev);
3361 if (!in6_dev)
3362 return;
3363 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
3364 return;
3365
3366 /* RFC2461 8.1:
3367 * The IP source address of the Redirect MUST be the same as the current
3368 * first-hop router for the specified ICMP Destination Address.
3369 */
3370
Alexander Aringf997c552016-06-15 21:20:23 +02003371 if (!ndisc_parse_options(skb->dev, msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07003372 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
3373 return;
3374 }
David S. Miller6e157b62012-07-12 00:05:02 -07003375
3376 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07003377 if (ndopts.nd_opts_tgt_lladdr) {
3378 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
3379 skb->dev);
3380 if (!lladdr) {
3381 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
3382 return;
3383 }
3384 }
3385
David S. Miller6e157b62012-07-12 00:05:02 -07003386 rt = (struct rt6_info *) dst;
Matthias Schifferec13ad12015-11-02 01:24:38 +01003387 if (rt->rt6i_flags & RTF_REJECT) {
David S. Miller6e157b62012-07-12 00:05:02 -07003388 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
3389 return;
3390 }
3391
3392 /* Redirect received -> path was valid.
3393 * Look, redirects are sent only in response to data packets,
3394 * so that this nexthop apparently is reachable. --ANK
3395 */
Julian Anastasov0dec8792017-02-06 23:14:16 +02003396 dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
David S. Miller6e157b62012-07-12 00:05:02 -07003397
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003398 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07003399 if (!neigh)
3400 return;
3401
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 /*
3403 * We have finally decided to accept it.
3404 */
3405
Alexander Aringf997c552016-06-15 21:20:23 +02003406 ndisc_update(skb->dev, neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 NEIGH_UPDATE_F_WEAK_OVERRIDE|
3408 NEIGH_UPDATE_F_OVERRIDE|
3409 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
Alexander Aringf997c552016-06-15 21:20:23 +02003410 NEIGH_UPDATE_F_ISROUTER)),
3411 NDISC_REDIRECT, &ndopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412
David Ahern4d85cd02018-04-20 15:37:59 -07003413 rcu_read_lock();
David Aherna68886a2018-04-20 15:38:02 -07003414 from = rcu_dereference(rt->from);
David Ahern8a14e462018-04-23 11:32:07 -07003415 fib6_info_hold(from);
David Ahern4d85cd02018-04-20 15:37:59 -07003416 rcu_read_unlock();
David Ahern8a14e462018-04-23 11:32:07 -07003417
3418 nrt = ip6_rt_cache_alloc(from, &msg->dest, NULL);
David S. Miller38308472011-12-03 18:02:47 -05003419 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 goto out;
3421
3422 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
3423 if (on_link)
3424 nrt->rt6i_flags &= ~RTF_GATEWAY;
3425
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003426 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427
Wei Wang2b760fc2017-10-06 12:06:03 -07003428 /* No need to remove rt from the exception table if rt is
3429 * a cached route because rt6_insert_exception() will
3430 * takes care of it
3431 */
David Ahern8a14e462018-04-23 11:32:07 -07003432 if (rt6_insert_exception(nrt, from)) {
Wei Wang2b760fc2017-10-06 12:06:03 -07003433 dst_release_immediate(&nrt->dst);
3434 goto out;
3435 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436
Changli Gaod8d1f302010-06-10 23:31:35 -07003437 netevent.old = &rt->dst;
3438 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003439 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00003440 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07003441 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
3442
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443out:
David Ahern8a14e462018-04-23 11:32:07 -07003444 fib6_info_release(from);
David S. Millere8599ff2012-07-11 23:43:53 -07003445 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07003446}
3447
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003448#ifdef CONFIG_IPV6_ROUTE_INFO
David Ahern8d1c8022018-04-17 17:33:26 -07003449static struct fib6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00003450 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07003451 const struct in6_addr *gwaddr,
3452 struct net_device *dev)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003453{
David Ahern830218c2016-10-24 10:52:35 -07003454 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO;
3455 int ifindex = dev->ifindex;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003456 struct fib6_node *fn;
David Ahern8d1c8022018-04-17 17:33:26 -07003457 struct fib6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07003458 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003459
David Ahern830218c2016-10-24 10:52:35 -07003460 table = fib6_get_table(net, tb_id);
David S. Miller38308472011-12-03 18:02:47 -05003461 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07003462 return NULL;
3463
Wei Wang66f5d6c2017-10-06 12:06:10 -07003464 rcu_read_lock();
Wei Wang38fbeee2017-10-06 12:06:02 -07003465 fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0, true);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003466 if (!fn)
3467 goto out;
3468
Wei Wang66f5d6c2017-10-06 12:06:10 -07003469 for_each_fib6_node_rt_rcu(fn) {
David Ahern5e670d82018-04-17 17:33:14 -07003470 if (rt->fib6_nh.nh_dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003471 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07003472 if ((rt->fib6_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003473 continue;
David Ahern5e670d82018-04-17 17:33:14 -07003474 if (!ipv6_addr_equal(&rt->fib6_nh.nh_gw, gwaddr))
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003475 continue;
David Ahern8d1c8022018-04-17 17:33:26 -07003476 fib6_info_hold(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003477 break;
3478 }
3479out:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003480 rcu_read_unlock();
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003481 return rt;
3482}
3483
David Ahern8d1c8022018-04-17 17:33:26 -07003484static struct fib6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00003485 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07003486 const struct in6_addr *gwaddr,
3487 struct net_device *dev,
Eric Dumazet95c96172012-04-15 05:58:06 +00003488 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003489{
Thomas Graf86872cb2006-08-22 00:01:08 -07003490 struct fib6_config cfg = {
Rami Rosen238fc7e2008-02-09 23:43:11 -08003491 .fc_metric = IP6_RT_PRIO_USER,
David Ahern830218c2016-10-24 10:52:35 -07003492 .fc_ifindex = dev->ifindex,
Thomas Graf86872cb2006-08-22 00:01:08 -07003493 .fc_dst_len = prefixlen,
3494 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
3495 RTF_UP | RTF_PREF(pref),
Xin Longb91d5322017-08-03 14:13:46 +08003496 .fc_protocol = RTPROT_RA,
David Aherne8478e82018-04-17 17:33:13 -07003497 .fc_type = RTN_UNICAST,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003498 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08003499 .fc_nlinfo.nlh = NULL,
3500 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07003501 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003502
David Ahern830218c2016-10-24 10:52:35 -07003503 cfg.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO,
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003504 cfg.fc_dst = *prefix;
3505 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07003506
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08003507 /* We should treat it as a default route if prefix length is 0. */
3508 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07003509 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003510
David Ahernacb54e32018-04-17 17:33:22 -07003511 ip6_route_add(&cfg, GFP_ATOMIC, NULL);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003512
David Ahern830218c2016-10-24 10:52:35 -07003513 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003514}
3515#endif
3516
David Ahern8d1c8022018-04-17 17:33:26 -07003517struct fib6_info *rt6_get_dflt_router(struct net *net,
David Ahernafb1d4b52018-04-17 17:33:11 -07003518 const struct in6_addr *addr,
3519 struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003520{
David Ahern830218c2016-10-24 10:52:35 -07003521 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT;
David Ahern8d1c8022018-04-17 17:33:26 -07003522 struct fib6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07003523 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524
David Ahernafb1d4b52018-04-17 17:33:11 -07003525 table = fib6_get_table(net, tb_id);
David S. Miller38308472011-12-03 18:02:47 -05003526 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07003527 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528
Wei Wang66f5d6c2017-10-06 12:06:10 -07003529 rcu_read_lock();
3530 for_each_fib6_node_rt_rcu(&table->tb6_root) {
David Ahern5e670d82018-04-17 17:33:14 -07003531 if (dev == rt->fib6_nh.nh_dev &&
David Ahern93c2fb22018-04-18 15:38:59 -07003532 ((rt->fib6_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
David Ahern5e670d82018-04-17 17:33:14 -07003533 ipv6_addr_equal(&rt->fib6_nh.nh_gw, addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534 break;
3535 }
3536 if (rt)
David Ahern8d1c8022018-04-17 17:33:26 -07003537 fib6_info_hold(rt);
Wei Wang66f5d6c2017-10-06 12:06:10 -07003538 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539 return rt;
3540}
3541
David Ahern8d1c8022018-04-17 17:33:26 -07003542struct fib6_info *rt6_add_dflt_router(struct net *net,
David Ahernafb1d4b52018-04-17 17:33:11 -07003543 const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08003544 struct net_device *dev,
3545 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546{
Thomas Graf86872cb2006-08-22 00:01:08 -07003547 struct fib6_config cfg = {
David Ahernca254492015-10-12 11:47:10 -07003548 .fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08003549 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07003550 .fc_ifindex = dev->ifindex,
3551 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
3552 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Xin Longb91d5322017-08-03 14:13:46 +08003553 .fc_protocol = RTPROT_RA,
David Aherne8478e82018-04-17 17:33:13 -07003554 .fc_type = RTN_UNICAST,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003555 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08003556 .fc_nlinfo.nlh = NULL,
David Ahernafb1d4b52018-04-17 17:33:11 -07003557 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07003558 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003559
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003560 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561
David Ahernacb54e32018-04-17 17:33:22 -07003562 if (!ip6_route_add(&cfg, GFP_ATOMIC, NULL)) {
David Ahern830218c2016-10-24 10:52:35 -07003563 struct fib6_table *table;
3564
3565 table = fib6_get_table(dev_net(dev), cfg.fc_table);
3566 if (table)
3567 table->flags |= RT6_TABLE_HAS_DFLT_ROUTER;
3568 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569
David Ahernafb1d4b52018-04-17 17:33:11 -07003570 return rt6_get_dflt_router(net, gwaddr, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571}
3572
David Ahernafb1d4b52018-04-17 17:33:11 -07003573static void __rt6_purge_dflt_routers(struct net *net,
3574 struct fib6_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575{
David Ahern8d1c8022018-04-17 17:33:26 -07003576 struct fib6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577
3578restart:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003579 rcu_read_lock();
3580 for_each_fib6_node_rt_rcu(&table->tb6_root) {
David Aherndcd1f572018-04-18 15:39:05 -07003581 struct net_device *dev = fib6_info_nh_dev(rt);
3582 struct inet6_dev *idev = dev ? __in6_dev_get(dev) : NULL;
3583
David Ahern93c2fb22018-04-18 15:38:59 -07003584 if (rt->fib6_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
David Aherndcd1f572018-04-18 15:39:05 -07003585 (!idev || idev->cnf.accept_ra != 2)) {
David Ahern93531c62018-04-17 17:33:25 -07003586 fib6_info_hold(rt);
3587 rcu_read_unlock();
3588 ip6_del_rt(net, rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 goto restart;
3590 }
3591 }
Wei Wang66f5d6c2017-10-06 12:06:10 -07003592 rcu_read_unlock();
David Ahern830218c2016-10-24 10:52:35 -07003593
3594 table->flags &= ~RT6_TABLE_HAS_DFLT_ROUTER;
3595}
3596
3597void rt6_purge_dflt_routers(struct net *net)
3598{
3599 struct fib6_table *table;
3600 struct hlist_head *head;
3601 unsigned int h;
3602
3603 rcu_read_lock();
3604
3605 for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
3606 head = &net->ipv6.fib_table_hash[h];
3607 hlist_for_each_entry_rcu(table, head, tb6_hlist) {
3608 if (table->flags & RT6_TABLE_HAS_DFLT_ROUTER)
David Ahernafb1d4b52018-04-17 17:33:11 -07003609 __rt6_purge_dflt_routers(net, table);
David Ahern830218c2016-10-24 10:52:35 -07003610 }
3611 }
3612
3613 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614}
3615
Daniel Lezcano55786892008-03-04 13:47:47 -08003616static void rtmsg_to_fib6_config(struct net *net,
3617 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07003618 struct fib6_config *cfg)
3619{
3620 memset(cfg, 0, sizeof(*cfg));
3621
David Ahernca254492015-10-12 11:47:10 -07003622 cfg->fc_table = l3mdev_fib_table_by_index(net, rtmsg->rtmsg_ifindex) ?
3623 : RT6_TABLE_MAIN;
Thomas Graf86872cb2006-08-22 00:01:08 -07003624 cfg->fc_ifindex = rtmsg->rtmsg_ifindex;
3625 cfg->fc_metric = rtmsg->rtmsg_metric;
3626 cfg->fc_expires = rtmsg->rtmsg_info;
3627 cfg->fc_dst_len = rtmsg->rtmsg_dst_len;
3628 cfg->fc_src_len = rtmsg->rtmsg_src_len;
3629 cfg->fc_flags = rtmsg->rtmsg_flags;
David Aherne8478e82018-04-17 17:33:13 -07003630 cfg->fc_type = rtmsg->rtmsg_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07003631
Daniel Lezcano55786892008-03-04 13:47:47 -08003632 cfg->fc_nlinfo.nl_net = net;
Benjamin Theryf1243c22008-02-26 18:10:03 -08003633
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003634 cfg->fc_dst = rtmsg->rtmsg_dst;
3635 cfg->fc_src = rtmsg->rtmsg_src;
3636 cfg->fc_gateway = rtmsg->rtmsg_gateway;
Thomas Graf86872cb2006-08-22 00:01:08 -07003637}
3638
Daniel Lezcano55786892008-03-04 13:47:47 -08003639int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640{
Thomas Graf86872cb2006-08-22 00:01:08 -07003641 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 struct in6_rtmsg rtmsg;
3643 int err;
3644
Ian Morris67ba4152014-08-24 21:53:10 +01003645 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 case SIOCADDRT: /* Add a route */
3647 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00003648 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 return -EPERM;
3650 err = copy_from_user(&rtmsg, arg,
3651 sizeof(struct in6_rtmsg));
3652 if (err)
3653 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07003654
Daniel Lezcano55786892008-03-04 13:47:47 -08003655 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07003656
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 rtnl_lock();
3658 switch (cmd) {
3659 case SIOCADDRT:
David Ahernacb54e32018-04-17 17:33:22 -07003660 err = ip6_route_add(&cfg, GFP_KERNEL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 break;
3662 case SIOCDELRT:
David Ahern333c4302017-05-21 10:12:04 -06003663 err = ip6_route_del(&cfg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 break;
3665 default:
3666 err = -EINVAL;
3667 }
3668 rtnl_unlock();
3669
3670 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07003671 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672
3673 return -EINVAL;
3674}
3675
3676/*
3677 * Drop the packet on the floor
3678 */
3679
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07003680static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003682 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00003683 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003684 switch (ipstats_mib_noroutes) {
3685 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07003686 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00003687 if (type == IPV6_ADDR_ANY) {
Stephen Suryaputrabdb7cc62018-04-16 13:42:16 -04003688 IP6_INC_STATS(dev_net(dst->dev),
3689 __in6_dev_get_safely(skb->dev),
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07003690 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003691 break;
3692 }
3693 /* FALLTHROUGH */
3694 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07003695 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
3696 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003697 break;
3698 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00003699 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 kfree_skb(skb);
3701 return 0;
3702}
3703
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003704static int ip6_pkt_discard(struct sk_buff *skb)
3705{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003706 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003707}
3708
Eric W. Biedermanede20592015-10-07 16:48:47 -05003709static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710{
Eric Dumazetadf30902009-06-02 05:19:30 +00003711 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003712 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713}
3714
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003715static int ip6_pkt_prohibit(struct sk_buff *skb)
3716{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003717 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003718}
3719
Eric W. Biedermanede20592015-10-07 16:48:47 -05003720static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003721{
Eric Dumazetadf30902009-06-02 05:19:30 +00003722 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003723 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003724}
3725
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726/*
3727 * Allocate a dst for local (unicast / anycast) address.
3728 */
3729
David Ahern360a9882018-04-18 15:39:00 -07003730struct fib6_info *addrconf_f6i_alloc(struct net *net,
3731 struct inet6_dev *idev,
3732 const struct in6_addr *addr,
3733 bool anycast, gfp_t gfp_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734{
David Ahernca254492015-10-12 11:47:10 -07003735 u32 tb_id;
David Ahern4832c302017-08-17 12:17:20 -07003736 struct net_device *dev = idev->dev;
David Ahern360a9882018-04-18 15:39:00 -07003737 struct fib6_info *f6i;
David Ahern5f02ce242016-09-10 12:09:54 -07003738
David Ahern360a9882018-04-18 15:39:00 -07003739 f6i = fib6_info_alloc(gfp_flags);
3740 if (!f6i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741 return ERR_PTR(-ENOMEM);
3742
David Ahern360a9882018-04-18 15:39:00 -07003743 f6i->dst_nocount = true;
David Ahern360a9882018-04-18 15:39:00 -07003744 f6i->dst_host = true;
3745 f6i->fib6_protocol = RTPROT_KERNEL;
3746 f6i->fib6_flags = RTF_UP | RTF_NONEXTHOP;
David Aherne8478e82018-04-17 17:33:13 -07003747 if (anycast) {
David Ahern360a9882018-04-18 15:39:00 -07003748 f6i->fib6_type = RTN_ANYCAST;
3749 f6i->fib6_flags |= RTF_ANYCAST;
David Aherne8478e82018-04-17 17:33:13 -07003750 } else {
David Ahern360a9882018-04-18 15:39:00 -07003751 f6i->fib6_type = RTN_LOCAL;
3752 f6i->fib6_flags |= RTF_LOCAL;
David Aherne8478e82018-04-17 17:33:13 -07003753 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754
David Ahern360a9882018-04-18 15:39:00 -07003755 f6i->fib6_nh.nh_gw = *addr;
David Ahern93531c62018-04-17 17:33:25 -07003756 dev_hold(dev);
David Ahern360a9882018-04-18 15:39:00 -07003757 f6i->fib6_nh.nh_dev = dev;
3758 f6i->fib6_dst.addr = *addr;
3759 f6i->fib6_dst.plen = 128;
David Ahernca254492015-10-12 11:47:10 -07003760 tb_id = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL;
David Ahern360a9882018-04-18 15:39:00 -07003761 f6i->fib6_table = fib6_get_table(net, tb_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762
David Ahern360a9882018-04-18 15:39:00 -07003763 return f6i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764}
3765
Daniel Walterc3968a82011-04-13 21:10:57 +00003766/* remove deleted ip from prefsrc entries */
3767struct arg_dev_net_ip {
3768 struct net_device *dev;
3769 struct net *net;
3770 struct in6_addr *addr;
3771};
3772
David Ahern8d1c8022018-04-17 17:33:26 -07003773static int fib6_remove_prefsrc(struct fib6_info *rt, void *arg)
Daniel Walterc3968a82011-04-13 21:10:57 +00003774{
3775 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
3776 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
3777 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
3778
David Ahern5e670d82018-04-17 17:33:14 -07003779 if (((void *)rt->fib6_nh.nh_dev == dev || !dev) &&
David Ahern421842e2018-04-17 17:33:18 -07003780 rt != net->ipv6.fib6_null_entry &&
David Ahern93c2fb22018-04-18 15:38:59 -07003781 ipv6_addr_equal(addr, &rt->fib6_prefsrc.addr)) {
Wei Wang60006a42017-10-06 12:05:58 -07003782 spin_lock_bh(&rt6_exception_lock);
Daniel Walterc3968a82011-04-13 21:10:57 +00003783 /* remove prefsrc entry */
David Ahern93c2fb22018-04-18 15:38:59 -07003784 rt->fib6_prefsrc.plen = 0;
Wei Wang60006a42017-10-06 12:05:58 -07003785 /* need to update cache as well */
3786 rt6_exceptions_remove_prefsrc(rt);
3787 spin_unlock_bh(&rt6_exception_lock);
Daniel Walterc3968a82011-04-13 21:10:57 +00003788 }
3789 return 0;
3790}
3791
3792void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
3793{
3794 struct net *net = dev_net(ifp->idev->dev);
3795 struct arg_dev_net_ip adni = {
3796 .dev = ifp->idev->dev,
3797 .net = net,
3798 .addr = &ifp->addr,
3799 };
Li RongQing0c3584d2013-12-27 16:32:38 +08003800 fib6_clean_all(net, fib6_remove_prefsrc, &adni);
Daniel Walterc3968a82011-04-13 21:10:57 +00003801}
3802
Duan Jiongbe7a0102014-05-15 15:56:14 +08003803#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY)
Duan Jiongbe7a0102014-05-15 15:56:14 +08003804
3805/* Remove routers and update dst entries when gateway turn into host. */
David Ahern8d1c8022018-04-17 17:33:26 -07003806static int fib6_clean_tohost(struct fib6_info *rt, void *arg)
Duan Jiongbe7a0102014-05-15 15:56:14 +08003807{
3808 struct in6_addr *gateway = (struct in6_addr *)arg;
3809
David Ahern93c2fb22018-04-18 15:38:59 -07003810 if (((rt->fib6_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) &&
David Ahern5e670d82018-04-17 17:33:14 -07003811 ipv6_addr_equal(gateway, &rt->fib6_nh.nh_gw)) {
Duan Jiongbe7a0102014-05-15 15:56:14 +08003812 return -1;
3813 }
Wei Wangb16cb452017-10-06 12:06:00 -07003814
3815 /* Further clean up cached routes in exception table.
3816 * This is needed because cached route may have a different
3817 * gateway than its 'parent' in the case of an ip redirect.
3818 */
3819 rt6_exceptions_clean_tohost(rt, gateway);
3820
Duan Jiongbe7a0102014-05-15 15:56:14 +08003821 return 0;
3822}
3823
3824void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
3825{
3826 fib6_clean_all(net, fib6_clean_tohost, gateway);
3827}
3828
Ido Schimmel2127d952018-01-07 12:45:03 +02003829struct arg_netdev_event {
3830 const struct net_device *dev;
Ido Schimmel4c981e22018-01-07 12:45:04 +02003831 union {
3832 unsigned int nh_flags;
3833 unsigned long event;
3834 };
Ido Schimmel2127d952018-01-07 12:45:03 +02003835};
3836
David Ahern8d1c8022018-04-17 17:33:26 -07003837static struct fib6_info *rt6_multipath_first_sibling(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003838{
David Ahern8d1c8022018-04-17 17:33:26 -07003839 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003840 struct fib6_node *fn;
3841
David Ahern93c2fb22018-04-18 15:38:59 -07003842 fn = rcu_dereference_protected(rt->fib6_node,
3843 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003844 iter = rcu_dereference_protected(fn->leaf,
David Ahern93c2fb22018-04-18 15:38:59 -07003845 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003846 while (iter) {
David Ahern93c2fb22018-04-18 15:38:59 -07003847 if (iter->fib6_metric == rt->fib6_metric &&
David Ahernf34436a2018-05-21 10:26:53 -07003848 iter->fib6_nsiblings)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003849 return iter;
David Ahern8fb11a92018-05-04 13:54:24 -07003850 iter = rcu_dereference_protected(iter->fib6_next,
David Ahern93c2fb22018-04-18 15:38:59 -07003851 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003852 }
3853
3854 return NULL;
3855}
3856
David Ahern8d1c8022018-04-17 17:33:26 -07003857static bool rt6_is_dead(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003858{
David Ahern5e670d82018-04-17 17:33:14 -07003859 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD ||
3860 (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN &&
David Aherndcd1f572018-04-18 15:39:05 -07003861 fib6_ignore_linkdown(rt)))
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003862 return true;
3863
3864 return false;
3865}
3866
David Ahern8d1c8022018-04-17 17:33:26 -07003867static int rt6_multipath_total_weight(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003868{
David Ahern8d1c8022018-04-17 17:33:26 -07003869 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003870 int total = 0;
3871
3872 if (!rt6_is_dead(rt))
David Ahern5e670d82018-04-17 17:33:14 -07003873 total += rt->fib6_nh.nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003874
David Ahern93c2fb22018-04-18 15:38:59 -07003875 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) {
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003876 if (!rt6_is_dead(iter))
David Ahern5e670d82018-04-17 17:33:14 -07003877 total += iter->fib6_nh.nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003878 }
3879
3880 return total;
3881}
3882
David Ahern8d1c8022018-04-17 17:33:26 -07003883static void rt6_upper_bound_set(struct fib6_info *rt, int *weight, int total)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003884{
3885 int upper_bound = -1;
3886
3887 if (!rt6_is_dead(rt)) {
David Ahern5e670d82018-04-17 17:33:14 -07003888 *weight += rt->fib6_nh.nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003889 upper_bound = DIV_ROUND_CLOSEST_ULL((u64) (*weight) << 31,
3890 total) - 1;
3891 }
David Ahern5e670d82018-04-17 17:33:14 -07003892 atomic_set(&rt->fib6_nh.nh_upper_bound, upper_bound);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003893}
3894
David Ahern8d1c8022018-04-17 17:33:26 -07003895static void rt6_multipath_upper_bound_set(struct fib6_info *rt, int total)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003896{
David Ahern8d1c8022018-04-17 17:33:26 -07003897 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003898 int weight = 0;
3899
3900 rt6_upper_bound_set(rt, &weight, total);
3901
David Ahern93c2fb22018-04-18 15:38:59 -07003902 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003903 rt6_upper_bound_set(iter, &weight, total);
3904}
3905
David Ahern8d1c8022018-04-17 17:33:26 -07003906void rt6_multipath_rebalance(struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003907{
David Ahern8d1c8022018-04-17 17:33:26 -07003908 struct fib6_info *first;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003909 int total;
3910
3911 /* In case the entire multipath route was marked for flushing,
3912 * then there is no need to rebalance upon the removal of every
3913 * sibling route.
3914 */
David Ahern93c2fb22018-04-18 15:38:59 -07003915 if (!rt->fib6_nsiblings || rt->should_flush)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003916 return;
3917
3918 /* During lookup routes are evaluated in order, so we need to
3919 * make sure upper bounds are assigned from the first sibling
3920 * onwards.
3921 */
3922 first = rt6_multipath_first_sibling(rt);
3923 if (WARN_ON_ONCE(!first))
3924 return;
3925
3926 total = rt6_multipath_total_weight(first);
3927 rt6_multipath_upper_bound_set(first, total);
3928}
3929
David Ahern8d1c8022018-04-17 17:33:26 -07003930static int fib6_ifup(struct fib6_info *rt, void *p_arg)
Ido Schimmel2127d952018-01-07 12:45:03 +02003931{
3932 const struct arg_netdev_event *arg = p_arg;
David Ahern7aef6852018-04-17 17:33:10 -07003933 struct net *net = dev_net(arg->dev);
Ido Schimmel2127d952018-01-07 12:45:03 +02003934
David Ahern421842e2018-04-17 17:33:18 -07003935 if (rt != net->ipv6.fib6_null_entry && rt->fib6_nh.nh_dev == arg->dev) {
David Ahern5e670d82018-04-17 17:33:14 -07003936 rt->fib6_nh.nh_flags &= ~arg->nh_flags;
David Ahern7aef6852018-04-17 17:33:10 -07003937 fib6_update_sernum_upto_root(net, rt);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003938 rt6_multipath_rebalance(rt);
Ido Schimmel1de178e2018-01-07 12:45:15 +02003939 }
Ido Schimmel2127d952018-01-07 12:45:03 +02003940
3941 return 0;
3942}
3943
3944void rt6_sync_up(struct net_device *dev, unsigned int nh_flags)
3945{
3946 struct arg_netdev_event arg = {
3947 .dev = dev,
Ido Schimmel6802f3a2018-01-12 22:07:36 +02003948 {
3949 .nh_flags = nh_flags,
3950 },
Ido Schimmel2127d952018-01-07 12:45:03 +02003951 };
3952
3953 if (nh_flags & RTNH_F_DEAD && netif_carrier_ok(dev))
3954 arg.nh_flags |= RTNH_F_LINKDOWN;
3955
3956 fib6_clean_all(dev_net(dev), fib6_ifup, &arg);
3957}
3958
David Ahern8d1c8022018-04-17 17:33:26 -07003959static bool rt6_multipath_uses_dev(const struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02003960 const struct net_device *dev)
3961{
David Ahern8d1c8022018-04-17 17:33:26 -07003962 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003963
David Ahern5e670d82018-04-17 17:33:14 -07003964 if (rt->fib6_nh.nh_dev == dev)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003965 return true;
David Ahern93c2fb22018-04-18 15:38:59 -07003966 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahern5e670d82018-04-17 17:33:14 -07003967 if (iter->fib6_nh.nh_dev == dev)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003968 return true;
3969
3970 return false;
3971}
3972
David Ahern8d1c8022018-04-17 17:33:26 -07003973static void rt6_multipath_flush(struct fib6_info *rt)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003974{
David Ahern8d1c8022018-04-17 17:33:26 -07003975 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003976
3977 rt->should_flush = 1;
David Ahern93c2fb22018-04-18 15:38:59 -07003978 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003979 iter->should_flush = 1;
3980}
3981
David Ahern8d1c8022018-04-17 17:33:26 -07003982static unsigned int rt6_multipath_dead_count(const struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02003983 const struct net_device *down_dev)
3984{
David Ahern8d1c8022018-04-17 17:33:26 -07003985 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02003986 unsigned int dead = 0;
3987
David Ahern5e670d82018-04-17 17:33:14 -07003988 if (rt->fib6_nh.nh_dev == down_dev ||
3989 rt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003990 dead++;
David Ahern93c2fb22018-04-18 15:38:59 -07003991 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahern5e670d82018-04-17 17:33:14 -07003992 if (iter->fib6_nh.nh_dev == down_dev ||
3993 iter->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmel1de178e2018-01-07 12:45:15 +02003994 dead++;
3995
3996 return dead;
3997}
3998
David Ahern8d1c8022018-04-17 17:33:26 -07003999static void rt6_multipath_nh_flags_set(struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02004000 const struct net_device *dev,
4001 unsigned int nh_flags)
4002{
David Ahern8d1c8022018-04-17 17:33:26 -07004003 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02004004
David Ahern5e670d82018-04-17 17:33:14 -07004005 if (rt->fib6_nh.nh_dev == dev)
4006 rt->fib6_nh.nh_flags |= nh_flags;
David Ahern93c2fb22018-04-18 15:38:59 -07004007 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahern5e670d82018-04-17 17:33:14 -07004008 if (iter->fib6_nh.nh_dev == dev)
4009 iter->fib6_nh.nh_flags |= nh_flags;
Ido Schimmel1de178e2018-01-07 12:45:15 +02004010}
4011
David Aherna1a22c12017-01-18 07:40:36 -08004012/* called with write lock held for table with rt */
David Ahern8d1c8022018-04-17 17:33:26 -07004013static int fib6_ifdown(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014{
Ido Schimmel4c981e22018-01-07 12:45:04 +02004015 const struct arg_netdev_event *arg = p_arg;
4016 const struct net_device *dev = arg->dev;
David Ahern7aef6852018-04-17 17:33:10 -07004017 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004018
David Ahern421842e2018-04-17 17:33:18 -07004019 if (rt == net->ipv6.fib6_null_entry)
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004020 return 0;
4021
4022 switch (arg->event) {
4023 case NETDEV_UNREGISTER:
David Ahern5e670d82018-04-17 17:33:14 -07004024 return rt->fib6_nh.nh_dev == dev ? -1 : 0;
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004025 case NETDEV_DOWN:
Ido Schimmel1de178e2018-01-07 12:45:15 +02004026 if (rt->should_flush)
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004027 return -1;
David Ahern93c2fb22018-04-18 15:38:59 -07004028 if (!rt->fib6_nsiblings)
David Ahern5e670d82018-04-17 17:33:14 -07004029 return rt->fib6_nh.nh_dev == dev ? -1 : 0;
Ido Schimmel1de178e2018-01-07 12:45:15 +02004030 if (rt6_multipath_uses_dev(rt, dev)) {
4031 unsigned int count;
4032
4033 count = rt6_multipath_dead_count(rt, dev);
David Ahern93c2fb22018-04-18 15:38:59 -07004034 if (rt->fib6_nsiblings + 1 == count) {
Ido Schimmel1de178e2018-01-07 12:45:15 +02004035 rt6_multipath_flush(rt);
4036 return -1;
4037 }
4038 rt6_multipath_nh_flags_set(rt, dev, RTNH_F_DEAD |
4039 RTNH_F_LINKDOWN);
David Ahern7aef6852018-04-17 17:33:10 -07004040 fib6_update_sernum(net, rt);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02004041 rt6_multipath_rebalance(rt);
Ido Schimmel1de178e2018-01-07 12:45:15 +02004042 }
4043 return -2;
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004044 case NETDEV_CHANGE:
David Ahern5e670d82018-04-17 17:33:14 -07004045 if (rt->fib6_nh.nh_dev != dev ||
David Ahern93c2fb22018-04-18 15:38:59 -07004046 rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST))
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004047 break;
David Ahern5e670d82018-04-17 17:33:14 -07004048 rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02004049 rt6_multipath_rebalance(rt);
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004050 break;
Ido Schimmel2b241362018-01-07 12:45:02 +02004051 }
David S. Millerc159d302011-12-26 15:24:36 -05004052
Linus Torvalds1da177e2005-04-16 15:20:36 -07004053 return 0;
4054}
4055
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004056void rt6_sync_down_dev(struct net_device *dev, unsigned long event)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057{
Ido Schimmel4c981e22018-01-07 12:45:04 +02004058 struct arg_netdev_event arg = {
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004059 .dev = dev,
Ido Schimmel6802f3a2018-01-12 22:07:36 +02004060 {
4061 .event = event,
4062 },
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004063 };
4064
Ido Schimmel4c981e22018-01-07 12:45:04 +02004065 fib6_clean_all(dev_net(dev), fib6_ifdown, &arg);
4066}
4067
4068void rt6_disable_ip(struct net_device *dev, unsigned long event)
4069{
4070 rt6_sync_down_dev(dev, event);
4071 rt6_uncached_list_flush_dev(dev_net(dev), dev);
4072 neigh_ifdown(&nd_tbl, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073}
4074
Eric Dumazet95c96172012-04-15 05:58:06 +00004075struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00004077 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078};
4079
David Ahern8d1c8022018-04-17 17:33:26 -07004080static int rt6_mtu_change_route(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081{
4082 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
4083 struct inet6_dev *idev;
4084
4085 /* In IPv6 pmtu discovery is not optional,
4086 so that RTAX_MTU lock cannot disable it.
4087 We still use this lock to block changes
4088 caused by addrconf/ndisc.
4089 */
4090
4091 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05004092 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004093 return 0;
4094
4095 /* For administrative MTU increase, there is no way to discover
4096 IPv6 PMTU increase, so PMTU increase should be updated here.
4097 Since RFC 1981 doesn't include administrative MTU increase
4098 update PMTU increase is a MUST. (i.e. jumbo frame)
4099 */
David Ahern5e670d82018-04-17 17:33:14 -07004100 if (rt->fib6_nh.nh_dev == arg->dev &&
David Ahernd4ead6b2018-04-17 17:33:16 -07004101 !fib6_metric_locked(rt, RTAX_MTU)) {
4102 u32 mtu = rt->fib6_pmtu;
4103
4104 if (mtu >= arg->mtu ||
4105 (mtu < arg->mtu && mtu == idev->cnf.mtu6))
4106 fib6_metric_set(rt, RTAX_MTU, arg->mtu);
4107
Wei Wangf5bbe7e2017-10-06 12:05:59 -07004108 spin_lock_bh(&rt6_exception_lock);
Stefano Brivioe9fa1492018-03-06 11:10:19 +01004109 rt6_exceptions_update_pmtu(idev, rt, arg->mtu);
Wei Wangf5bbe7e2017-10-06 12:05:59 -07004110 spin_unlock_bh(&rt6_exception_lock);
Simon Arlott566cfd82007-07-26 00:09:55 -07004111 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112 return 0;
4113}
4114
Eric Dumazet95c96172012-04-15 05:58:06 +00004115void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116{
Thomas Grafc71099a2006-08-04 23:20:06 -07004117 struct rt6_mtu_change_arg arg = {
4118 .dev = dev,
4119 .mtu = mtu,
4120 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121
Li RongQing0c3584d2013-12-27 16:32:38 +08004122 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123}
4124
Patrick McHardyef7c79e2007-06-05 12:38:30 -07004125static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07004126 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Eric Dumazetaa8f8772018-04-22 18:29:23 -07004127 [RTA_PREFSRC] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07004128 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07004129 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07004130 [RTA_PRIORITY] = { .type = NLA_U32 },
4131 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004132 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004133 [RTA_PREF] = { .type = NLA_U8 },
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004134 [RTA_ENCAP_TYPE] = { .type = NLA_U16 },
4135 [RTA_ENCAP] = { .type = NLA_NESTED },
Xin Long32bc2012015-12-16 17:50:11 +08004136 [RTA_EXPIRES] = { .type = NLA_U32 },
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09004137 [RTA_UID] = { .type = NLA_U32 },
Liping Zhang3b45a412017-02-27 20:59:39 +08004138 [RTA_MARK] = { .type = NLA_U32 },
Eric Dumazetaa8f8772018-04-22 18:29:23 -07004139 [RTA_TABLE] = { .type = NLA_U32 },
Roopa Prabhueacb9382018-05-22 14:03:28 -07004140 [RTA_IP_PROTO] = { .type = NLA_U8 },
4141 [RTA_SPORT] = { .type = NLA_U16 },
4142 [RTA_DPORT] = { .type = NLA_U16 },
Thomas Graf86872cb2006-08-22 00:01:08 -07004143};
4144
4145static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
David Ahern333c4302017-05-21 10:12:04 -06004146 struct fib6_config *cfg,
4147 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148{
Thomas Graf86872cb2006-08-22 00:01:08 -07004149 struct rtmsg *rtm;
4150 struct nlattr *tb[RTA_MAX+1];
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004151 unsigned int pref;
Thomas Graf86872cb2006-08-22 00:01:08 -07004152 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153
Johannes Bergfceb6432017-04-12 14:34:07 +02004154 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
4155 NULL);
Thomas Graf86872cb2006-08-22 00:01:08 -07004156 if (err < 0)
4157 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158
Thomas Graf86872cb2006-08-22 00:01:08 -07004159 err = -EINVAL;
4160 rtm = nlmsg_data(nlh);
4161 memset(cfg, 0, sizeof(*cfg));
4162
4163 cfg->fc_table = rtm->rtm_table;
4164 cfg->fc_dst_len = rtm->rtm_dst_len;
4165 cfg->fc_src_len = rtm->rtm_src_len;
4166 cfg->fc_flags = RTF_UP;
4167 cfg->fc_protocol = rtm->rtm_protocol;
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00004168 cfg->fc_type = rtm->rtm_type;
Thomas Graf86872cb2006-08-22 00:01:08 -07004169
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00004170 if (rtm->rtm_type == RTN_UNREACHABLE ||
4171 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00004172 rtm->rtm_type == RTN_PROHIBIT ||
4173 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07004174 cfg->fc_flags |= RTF_REJECT;
4175
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00004176 if (rtm->rtm_type == RTN_LOCAL)
4177 cfg->fc_flags |= RTF_LOCAL;
4178
Martin KaFai Lau1f56a01f2015-04-28 13:03:03 -07004179 if (rtm->rtm_flags & RTM_F_CLONED)
4180 cfg->fc_flags |= RTF_CACHE;
4181
David Ahernfc1e64e2018-01-25 16:55:09 -08004182 cfg->fc_flags |= (rtm->rtm_flags & RTNH_F_ONLINK);
4183
Eric W. Biederman15e47302012-09-07 20:12:54 +00004184 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
Thomas Graf86872cb2006-08-22 00:01:08 -07004185 cfg->fc_nlinfo.nlh = nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09004186 cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
Thomas Graf86872cb2006-08-22 00:01:08 -07004187
4188 if (tb[RTA_GATEWAY]) {
Jiri Benc67b61f62015-03-29 16:59:26 +02004189 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
Thomas Graf86872cb2006-08-22 00:01:08 -07004190 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004192
4193 if (tb[RTA_DST]) {
4194 int plen = (rtm->rtm_dst_len + 7) >> 3;
4195
4196 if (nla_len(tb[RTA_DST]) < plen)
4197 goto errout;
4198
4199 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004200 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004201
4202 if (tb[RTA_SRC]) {
4203 int plen = (rtm->rtm_src_len + 7) >> 3;
4204
4205 if (nla_len(tb[RTA_SRC]) < plen)
4206 goto errout;
4207
4208 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004210
Daniel Walterc3968a82011-04-13 21:10:57 +00004211 if (tb[RTA_PREFSRC])
Jiri Benc67b61f62015-03-29 16:59:26 +02004212 cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]);
Daniel Walterc3968a82011-04-13 21:10:57 +00004213
Thomas Graf86872cb2006-08-22 00:01:08 -07004214 if (tb[RTA_OIF])
4215 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
4216
4217 if (tb[RTA_PRIORITY])
4218 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
4219
4220 if (tb[RTA_METRICS]) {
4221 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
4222 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004224
4225 if (tb[RTA_TABLE])
4226 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
4227
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004228 if (tb[RTA_MULTIPATH]) {
4229 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
4230 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
David Ahern9ed59592017-01-17 14:57:36 -08004231
4232 err = lwtunnel_valid_encap_type_attr(cfg->fc_mp,
David Ahernc255bd62017-05-27 16:19:27 -06004233 cfg->fc_mp_len, extack);
David Ahern9ed59592017-01-17 14:57:36 -08004234 if (err < 0)
4235 goto errout;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004236 }
4237
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004238 if (tb[RTA_PREF]) {
4239 pref = nla_get_u8(tb[RTA_PREF]);
4240 if (pref != ICMPV6_ROUTER_PREF_LOW &&
4241 pref != ICMPV6_ROUTER_PREF_HIGH)
4242 pref = ICMPV6_ROUTER_PREF_MEDIUM;
4243 cfg->fc_flags |= RTF_PREF(pref);
4244 }
4245
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004246 if (tb[RTA_ENCAP])
4247 cfg->fc_encap = tb[RTA_ENCAP];
4248
David Ahern9ed59592017-01-17 14:57:36 -08004249 if (tb[RTA_ENCAP_TYPE]) {
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004250 cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]);
4251
David Ahernc255bd62017-05-27 16:19:27 -06004252 err = lwtunnel_valid_encap_type(cfg->fc_encap_type, extack);
David Ahern9ed59592017-01-17 14:57:36 -08004253 if (err < 0)
4254 goto errout;
4255 }
4256
Xin Long32bc2012015-12-16 17:50:11 +08004257 if (tb[RTA_EXPIRES]) {
4258 unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ);
4259
4260 if (addrconf_finite_timeout(timeout)) {
4261 cfg->fc_expires = jiffies_to_clock_t(timeout * HZ);
4262 cfg->fc_flags |= RTF_EXPIRES;
4263 }
4264 }
4265
Thomas Graf86872cb2006-08-22 00:01:08 -07004266 err = 0;
4267errout:
4268 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269}
4270
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004271struct rt6_nh {
David Ahern8d1c8022018-04-17 17:33:26 -07004272 struct fib6_info *fib6_info;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004273 struct fib6_config r_cfg;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004274 struct list_head next;
4275};
4276
4277static void ip6_print_replace_route_err(struct list_head *rt6_nh_list)
4278{
4279 struct rt6_nh *nh;
4280
4281 list_for_each_entry(nh, rt6_nh_list, next) {
David Ahern7d4d5062017-02-02 12:37:12 -08004282 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 -07004283 &nh->r_cfg.fc_dst, &nh->r_cfg.fc_gateway,
4284 nh->r_cfg.fc_ifindex);
4285 }
4286}
4287
David Ahernd4ead6b2018-04-17 17:33:16 -07004288static int ip6_route_info_append(struct net *net,
4289 struct list_head *rt6_nh_list,
David Ahern8d1c8022018-04-17 17:33:26 -07004290 struct fib6_info *rt,
4291 struct fib6_config *r_cfg)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004292{
4293 struct rt6_nh *nh;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004294 int err = -EEXIST;
4295
4296 list_for_each_entry(nh, rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004297 /* check if fib6_info already exists */
4298 if (rt6_duplicate_nexthop(nh->fib6_info, rt))
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004299 return err;
4300 }
4301
4302 nh = kzalloc(sizeof(*nh), GFP_KERNEL);
4303 if (!nh)
4304 return -ENOMEM;
David Ahern8d1c8022018-04-17 17:33:26 -07004305 nh->fib6_info = rt;
David Ahernd4ead6b2018-04-17 17:33:16 -07004306 err = ip6_convert_metrics(net, rt, r_cfg);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004307 if (err) {
4308 kfree(nh);
4309 return err;
4310 }
4311 memcpy(&nh->r_cfg, r_cfg, sizeof(*r_cfg));
4312 list_add_tail(&nh->next, rt6_nh_list);
4313
4314 return 0;
4315}
4316
David Ahern8d1c8022018-04-17 17:33:26 -07004317static void ip6_route_mpath_notify(struct fib6_info *rt,
4318 struct fib6_info *rt_last,
David Ahern3b1137f2017-02-02 12:37:10 -08004319 struct nl_info *info,
4320 __u16 nlflags)
4321{
4322 /* if this is an APPEND route, then rt points to the first route
4323 * inserted and rt_last points to last route inserted. Userspace
4324 * wants a consistent dump of the route which starts at the first
4325 * nexthop. Since sibling routes are always added at the end of
4326 * the list, find the first sibling of the last route appended
4327 */
David Ahern93c2fb22018-04-18 15:38:59 -07004328 if ((nlflags & NLM_F_APPEND) && rt_last && rt_last->fib6_nsiblings) {
4329 rt = list_first_entry(&rt_last->fib6_siblings,
David Ahern8d1c8022018-04-17 17:33:26 -07004330 struct fib6_info,
David Ahern93c2fb22018-04-18 15:38:59 -07004331 fib6_siblings);
David Ahern3b1137f2017-02-02 12:37:10 -08004332 }
4333
4334 if (rt)
4335 inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
4336}
4337
David Ahern333c4302017-05-21 10:12:04 -06004338static int ip6_route_multipath_add(struct fib6_config *cfg,
4339 struct netlink_ext_ack *extack)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004340{
David Ahern8d1c8022018-04-17 17:33:26 -07004341 struct fib6_info *rt_notif = NULL, *rt_last = NULL;
David Ahern3b1137f2017-02-02 12:37:10 -08004342 struct nl_info *info = &cfg->fc_nlinfo;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004343 struct fib6_config r_cfg;
4344 struct rtnexthop *rtnh;
David Ahern8d1c8022018-04-17 17:33:26 -07004345 struct fib6_info *rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004346 struct rt6_nh *err_nh;
4347 struct rt6_nh *nh, *nh_safe;
David Ahern3b1137f2017-02-02 12:37:10 -08004348 __u16 nlflags;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004349 int remaining;
4350 int attrlen;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004351 int err = 1;
4352 int nhn = 0;
4353 int replace = (cfg->fc_nlinfo.nlh &&
4354 (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE));
4355 LIST_HEAD(rt6_nh_list);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004356
David Ahern3b1137f2017-02-02 12:37:10 -08004357 nlflags = replace ? NLM_F_REPLACE : NLM_F_CREATE;
4358 if (info->nlh && info->nlh->nlmsg_flags & NLM_F_APPEND)
4359 nlflags |= NLM_F_APPEND;
4360
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02004361 remaining = cfg->fc_mp_len;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004362 rtnh = (struct rtnexthop *)cfg->fc_mp;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004363
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004364 /* Parse a Multipath Entry and build a list (rt6_nh_list) of
David Ahern8d1c8022018-04-17 17:33:26 -07004365 * fib6_info structs per nexthop
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004366 */
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004367 while (rtnh_ok(rtnh, remaining)) {
4368 memcpy(&r_cfg, cfg, sizeof(*cfg));
4369 if (rtnh->rtnh_ifindex)
4370 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
4371
4372 attrlen = rtnh_attrlen(rtnh);
4373 if (attrlen > 0) {
4374 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
4375
4376 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
4377 if (nla) {
Jiri Benc67b61f62015-03-29 16:59:26 +02004378 r_cfg.fc_gateway = nla_get_in6_addr(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004379 r_cfg.fc_flags |= RTF_GATEWAY;
4380 }
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004381 r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
4382 nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
4383 if (nla)
4384 r_cfg.fc_encap_type = nla_get_u16(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004385 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004386
David Ahern68e2ffd2018-03-20 10:06:59 -07004387 r_cfg.fc_flags |= (rtnh->rtnh_flags & RTNH_F_ONLINK);
David Ahernacb54e32018-04-17 17:33:22 -07004388 rt = ip6_route_info_create(&r_cfg, GFP_KERNEL, extack);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07004389 if (IS_ERR(rt)) {
4390 err = PTR_ERR(rt);
4391 rt = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004392 goto cleanup;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07004393 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004394
David Ahern5e670d82018-04-17 17:33:14 -07004395 rt->fib6_nh.nh_weight = rtnh->rtnh_hops + 1;
Ido Schimmel398958a2018-01-09 16:40:28 +02004396
David Ahernd4ead6b2018-04-17 17:33:16 -07004397 err = ip6_route_info_append(info->nl_net, &rt6_nh_list,
4398 rt, &r_cfg);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004399 if (err) {
David Ahern93531c62018-04-17 17:33:25 -07004400 fib6_info_release(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004401 goto cleanup;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004402 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004403
4404 rtnh = rtnh_next(rtnh, &remaining);
4405 }
4406
David Ahern3b1137f2017-02-02 12:37:10 -08004407 /* for add and replace send one notification with all nexthops.
4408 * Skip the notification in fib6_add_rt2node and send one with
4409 * the full route when done
4410 */
4411 info->skip_notify = 1;
4412
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004413 err_nh = NULL;
4414 list_for_each_entry(nh, &rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004415 err = __ip6_ins_rt(nh->fib6_info, info, extack);
4416 fib6_info_release(nh->fib6_info);
David Ahern93531c62018-04-17 17:33:25 -07004417
David Ahernf7225172018-06-04 13:41:42 -07004418 if (!err) {
4419 /* save reference to last route successfully inserted */
4420 rt_last = nh->fib6_info;
4421
4422 /* save reference to first route for notification */
4423 if (!rt_notif)
4424 rt_notif = nh->fib6_info;
4425 }
David Ahern3b1137f2017-02-02 12:37:10 -08004426
David Ahern8d1c8022018-04-17 17:33:26 -07004427 /* nh->fib6_info is used or freed at this point, reset to NULL*/
4428 nh->fib6_info = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004429 if (err) {
4430 if (replace && nhn)
4431 ip6_print_replace_route_err(&rt6_nh_list);
4432 err_nh = nh;
4433 goto add_errout;
4434 }
4435
Nicolas Dichtel1a724182012-11-01 22:58:22 +00004436 /* Because each route is added like a single route we remove
Michal Kubeček27596472015-05-18 20:54:00 +02004437 * these flags after the first nexthop: if there is a collision,
4438 * we have already failed to add the first nexthop:
4439 * fib6_add_rt2node() has rejected it; when replacing, old
4440 * nexthops have been replaced by first new, the rest should
4441 * be added to it.
Nicolas Dichtel1a724182012-11-01 22:58:22 +00004442 */
Michal Kubeček27596472015-05-18 20:54:00 +02004443 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
4444 NLM_F_REPLACE);
David Ahernf34436a2018-05-21 10:26:53 -07004445 cfg->fc_nlinfo.nlh->nlmsg_flags |= NLM_F_APPEND;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004446 nhn++;
4447 }
4448
David Ahern3b1137f2017-02-02 12:37:10 -08004449 /* success ... tell user about new route */
4450 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004451 goto cleanup;
4452
4453add_errout:
David Ahern3b1137f2017-02-02 12:37:10 -08004454 /* send notification for routes that were added so that
4455 * the delete notifications sent by ip6_route_del are
4456 * coherent
4457 */
4458 if (rt_notif)
4459 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
4460
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004461 /* Delete routes that were already added */
4462 list_for_each_entry(nh, &rt6_nh_list, next) {
4463 if (err_nh == nh)
4464 break;
David Ahern333c4302017-05-21 10:12:04 -06004465 ip6_route_del(&nh->r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004466 }
4467
4468cleanup:
4469 list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004470 if (nh->fib6_info)
4471 fib6_info_release(nh->fib6_info);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004472 list_del(&nh->next);
4473 kfree(nh);
4474 }
4475
4476 return err;
4477}
4478
David Ahern333c4302017-05-21 10:12:04 -06004479static int ip6_route_multipath_del(struct fib6_config *cfg,
4480 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004481{
4482 struct fib6_config r_cfg;
4483 struct rtnexthop *rtnh;
4484 int remaining;
4485 int attrlen;
4486 int err = 1, last_err = 0;
4487
4488 remaining = cfg->fc_mp_len;
4489 rtnh = (struct rtnexthop *)cfg->fc_mp;
4490
4491 /* Parse a Multipath Entry */
4492 while (rtnh_ok(rtnh, remaining)) {
4493 memcpy(&r_cfg, cfg, sizeof(*cfg));
4494 if (rtnh->rtnh_ifindex)
4495 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
4496
4497 attrlen = rtnh_attrlen(rtnh);
4498 if (attrlen > 0) {
4499 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
4500
4501 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
4502 if (nla) {
4503 nla_memcpy(&r_cfg.fc_gateway, nla, 16);
4504 r_cfg.fc_flags |= RTF_GATEWAY;
4505 }
4506 }
David Ahern333c4302017-05-21 10:12:04 -06004507 err = ip6_route_del(&r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004508 if (err)
4509 last_err = err;
4510
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004511 rtnh = rtnh_next(rtnh, &remaining);
4512 }
4513
4514 return last_err;
4515}
4516
David Ahernc21ef3e2017-04-16 09:48:24 -07004517static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
4518 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519{
Thomas Graf86872cb2006-08-22 00:01:08 -07004520 struct fib6_config cfg;
4521 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522
David Ahern333c4302017-05-21 10:12:04 -06004523 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07004524 if (err < 0)
4525 return err;
4526
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004527 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06004528 return ip6_route_multipath_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08004529 else {
4530 cfg.fc_delete_all_nh = 1;
David Ahern333c4302017-05-21 10:12:04 -06004531 return ip6_route_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08004532 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533}
4534
David Ahernc21ef3e2017-04-16 09:48:24 -07004535static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
4536 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537{
Thomas Graf86872cb2006-08-22 00:01:08 -07004538 struct fib6_config cfg;
4539 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540
David Ahern333c4302017-05-21 10:12:04 -06004541 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07004542 if (err < 0)
4543 return err;
4544
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004545 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06004546 return ip6_route_multipath_add(&cfg, extack);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004547 else
David Ahernacb54e32018-04-17 17:33:22 -07004548 return ip6_route_add(&cfg, GFP_KERNEL, extack);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549}
4550
David Ahern8d1c8022018-04-17 17:33:26 -07004551static size_t rt6_nlmsg_size(struct fib6_info *rt)
Thomas Graf339bf982006-11-10 14:10:15 -08004552{
David Ahernbeb1afac52017-02-02 12:37:09 -08004553 int nexthop_len = 0;
4554
David Ahern93c2fb22018-04-18 15:38:59 -07004555 if (rt->fib6_nsiblings) {
David Ahernbeb1afac52017-02-02 12:37:09 -08004556 nexthop_len = nla_total_size(0) /* RTA_MULTIPATH */
4557 + NLA_ALIGN(sizeof(struct rtnexthop))
4558 + nla_total_size(16) /* RTA_GATEWAY */
David Ahern5e670d82018-04-17 17:33:14 -07004559 + lwtunnel_get_encap_size(rt->fib6_nh.nh_lwtstate);
David Ahernbeb1afac52017-02-02 12:37:09 -08004560
David Ahern93c2fb22018-04-18 15:38:59 -07004561 nexthop_len *= rt->fib6_nsiblings;
David Ahernbeb1afac52017-02-02 12:37:09 -08004562 }
4563
Thomas Graf339bf982006-11-10 14:10:15 -08004564 return NLMSG_ALIGN(sizeof(struct rtmsg))
4565 + nla_total_size(16) /* RTA_SRC */
4566 + nla_total_size(16) /* RTA_DST */
4567 + nla_total_size(16) /* RTA_GATEWAY */
4568 + nla_total_size(16) /* RTA_PREFSRC */
4569 + nla_total_size(4) /* RTA_TABLE */
4570 + nla_total_size(4) /* RTA_IIF */
4571 + nla_total_size(4) /* RTA_OIF */
4572 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08004573 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Daniel Borkmannea697632015-01-05 23:57:47 +01004574 + nla_total_size(sizeof(struct rta_cacheinfo))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004575 + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004576 + nla_total_size(1) /* RTA_PREF */
David Ahern5e670d82018-04-17 17:33:14 -07004577 + lwtunnel_get_encap_size(rt->fib6_nh.nh_lwtstate)
David Ahernbeb1afac52017-02-02 12:37:09 -08004578 + nexthop_len;
4579}
4580
David Ahern8d1c8022018-04-17 17:33:26 -07004581static int rt6_nexthop_info(struct sk_buff *skb, struct fib6_info *rt,
David Ahern5be083c2017-03-06 15:57:31 -08004582 unsigned int *flags, bool skip_oif)
David Ahernbeb1afac52017-02-02 12:37:09 -08004583{
David Ahern5e670d82018-04-17 17:33:14 -07004584 if (rt->fib6_nh.nh_flags & RTNH_F_DEAD)
Ido Schimmelf9d882e2018-01-07 12:45:10 +02004585 *flags |= RTNH_F_DEAD;
4586
David Ahern5e670d82018-04-17 17:33:14 -07004587 if (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN) {
David Ahernbeb1afac52017-02-02 12:37:09 -08004588 *flags |= RTNH_F_LINKDOWN;
David Aherndcd1f572018-04-18 15:39:05 -07004589
4590 rcu_read_lock();
4591 if (fib6_ignore_linkdown(rt))
David Ahernbeb1afac52017-02-02 12:37:09 -08004592 *flags |= RTNH_F_DEAD;
David Aherndcd1f572018-04-18 15:39:05 -07004593 rcu_read_unlock();
David Ahernbeb1afac52017-02-02 12:37:09 -08004594 }
4595
David Ahern93c2fb22018-04-18 15:38:59 -07004596 if (rt->fib6_flags & RTF_GATEWAY) {
David Ahern5e670d82018-04-17 17:33:14 -07004597 if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->fib6_nh.nh_gw) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004598 goto nla_put_failure;
4599 }
4600
David Ahern5e670d82018-04-17 17:33:14 -07004601 *flags |= (rt->fib6_nh.nh_flags & RTNH_F_ONLINK);
4602 if (rt->fib6_nh.nh_flags & RTNH_F_OFFLOAD)
Ido Schimmel61e4d012017-08-03 13:28:20 +02004603 *flags |= RTNH_F_OFFLOAD;
4604
David Ahern5be083c2017-03-06 15:57:31 -08004605 /* not needed for multipath encoding b/c it has a rtnexthop struct */
David Ahern5e670d82018-04-17 17:33:14 -07004606 if (!skip_oif && rt->fib6_nh.nh_dev &&
4607 nla_put_u32(skb, RTA_OIF, rt->fib6_nh.nh_dev->ifindex))
David Ahernbeb1afac52017-02-02 12:37:09 -08004608 goto nla_put_failure;
4609
David Ahern5e670d82018-04-17 17:33:14 -07004610 if (rt->fib6_nh.nh_lwtstate &&
4611 lwtunnel_fill_encap(skb, rt->fib6_nh.nh_lwtstate) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004612 goto nla_put_failure;
4613
4614 return 0;
4615
4616nla_put_failure:
4617 return -EMSGSIZE;
4618}
4619
David Ahern5be083c2017-03-06 15:57:31 -08004620/* add multipath next hop */
David Ahern8d1c8022018-04-17 17:33:26 -07004621static int rt6_add_nexthop(struct sk_buff *skb, struct fib6_info *rt)
David Ahernbeb1afac52017-02-02 12:37:09 -08004622{
David Ahern5e670d82018-04-17 17:33:14 -07004623 const struct net_device *dev = rt->fib6_nh.nh_dev;
David Ahernbeb1afac52017-02-02 12:37:09 -08004624 struct rtnexthop *rtnh;
4625 unsigned int flags = 0;
4626
4627 rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh));
4628 if (!rtnh)
4629 goto nla_put_failure;
4630
David Ahern5e670d82018-04-17 17:33:14 -07004631 rtnh->rtnh_hops = rt->fib6_nh.nh_weight - 1;
4632 rtnh->rtnh_ifindex = dev ? dev->ifindex : 0;
David Ahernbeb1afac52017-02-02 12:37:09 -08004633
David Ahern5be083c2017-03-06 15:57:31 -08004634 if (rt6_nexthop_info(skb, rt, &flags, true) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004635 goto nla_put_failure;
4636
4637 rtnh->rtnh_flags = flags;
4638
4639 /* length of rtnetlink header + attributes */
4640 rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *)rtnh;
4641
4642 return 0;
4643
4644nla_put_failure:
4645 return -EMSGSIZE;
Thomas Graf339bf982006-11-10 14:10:15 -08004646}
4647
David Ahernd4ead6b2018-04-17 17:33:16 -07004648static int rt6_fill_node(struct net *net, struct sk_buff *skb,
David Ahern8d1c8022018-04-17 17:33:26 -07004649 struct fib6_info *rt, struct dst_entry *dst,
David Ahernd4ead6b2018-04-17 17:33:16 -07004650 struct in6_addr *dest, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00004651 int iif, int type, u32 portid, u32 seq,
David Ahernf8cfe2c2017-01-17 15:51:08 -08004652 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653{
4654 struct rtmsg *rtm;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004655 struct nlmsghdr *nlh;
David Ahernd4ead6b2018-04-17 17:33:16 -07004656 long expires = 0;
4657 u32 *pmetrics;
Patrick McHardy9e762a42006-08-10 23:09:48 -07004658 u32 table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004659
Eric W. Biederman15e47302012-09-07 20:12:54 +00004660 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05004661 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08004662 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004663
4664 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665 rtm->rtm_family = AF_INET6;
David Ahern93c2fb22018-04-18 15:38:59 -07004666 rtm->rtm_dst_len = rt->fib6_dst.plen;
4667 rtm->rtm_src_len = rt->fib6_src.plen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668 rtm->rtm_tos = 0;
David Ahern93c2fb22018-04-18 15:38:59 -07004669 if (rt->fib6_table)
4670 table = rt->fib6_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07004671 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07004672 table = RT6_TABLE_UNSPEC;
4673 rtm->rtm_table = table;
David S. Millerc78679e2012-04-01 20:27:33 -04004674 if (nla_put_u32(skb, RTA_TABLE, table))
4675 goto nla_put_failure;
David Aherne8478e82018-04-17 17:33:13 -07004676
4677 rtm->rtm_type = rt->fib6_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678 rtm->rtm_flags = 0;
4679 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
David Ahern93c2fb22018-04-18 15:38:59 -07004680 rtm->rtm_protocol = rt->fib6_protocol;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004681
David Ahern93c2fb22018-04-18 15:38:59 -07004682 if (rt->fib6_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004683 rtm->rtm_flags |= RTM_F_CLONED;
4684
David Ahernd4ead6b2018-04-17 17:33:16 -07004685 if (dest) {
4686 if (nla_put_in6_addr(skb, RTA_DST, dest))
David S. Millerc78679e2012-04-01 20:27:33 -04004687 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09004688 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004689 } else if (rtm->rtm_dst_len)
David Ahern93c2fb22018-04-18 15:38:59 -07004690 if (nla_put_in6_addr(skb, RTA_DST, &rt->fib6_dst.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04004691 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692#ifdef CONFIG_IPV6_SUBTREES
4693 if (src) {
Jiri Benc930345e2015-03-29 16:59:25 +02004694 if (nla_put_in6_addr(skb, RTA_SRC, src))
David S. Millerc78679e2012-04-01 20:27:33 -04004695 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09004696 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04004697 } else if (rtm->rtm_src_len &&
David Ahern93c2fb22018-04-18 15:38:59 -07004698 nla_put_in6_addr(skb, RTA_SRC, &rt->fib6_src.addr))
David S. Millerc78679e2012-04-01 20:27:33 -04004699 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004700#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09004701 if (iif) {
4702#ifdef CONFIG_IPV6_MROUTE
David Ahern93c2fb22018-04-18 15:38:59 -07004703 if (ipv6_addr_is_multicast(&rt->fib6_dst.addr)) {
David Ahernfd61c6b2017-01-17 15:51:07 -08004704 int err = ip6mr_get_route(net, skb, rtm, portid);
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02004705
David Ahernfd61c6b2017-01-17 15:51:07 -08004706 if (err == 0)
4707 return 0;
4708 if (err < 0)
4709 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09004710 } else
4711#endif
David S. Millerc78679e2012-04-01 20:27:33 -04004712 if (nla_put_u32(skb, RTA_IIF, iif))
4713 goto nla_put_failure;
David Ahernd4ead6b2018-04-17 17:33:16 -07004714 } else if (dest) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715 struct in6_addr saddr_buf;
David Ahernd4ead6b2018-04-17 17:33:16 -07004716 if (ip6_route_get_saddr(net, rt, dest, 0, &saddr_buf) == 0 &&
Jiri Benc930345e2015-03-29 16:59:25 +02004717 nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04004718 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07004720
David Ahern93c2fb22018-04-18 15:38:59 -07004721 if (rt->fib6_prefsrc.plen) {
Daniel Walterc3968a82011-04-13 21:10:57 +00004722 struct in6_addr saddr_buf;
David Ahern93c2fb22018-04-18 15:38:59 -07004723 saddr_buf = rt->fib6_prefsrc.addr;
Jiri Benc930345e2015-03-29 16:59:25 +02004724 if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04004725 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00004726 }
4727
David Ahernd4ead6b2018-04-17 17:33:16 -07004728 pmetrics = dst ? dst_metrics_ptr(dst) : rt->fib6_metrics->metrics;
4729 if (rtnetlink_put_metrics(skb, pmetrics) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07004730 goto nla_put_failure;
4731
David Ahern93c2fb22018-04-18 15:38:59 -07004732 if (nla_put_u32(skb, RTA_PRIORITY, rt->fib6_metric))
David S. Millerc78679e2012-04-01 20:27:33 -04004733 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00004734
David Ahernbeb1afac52017-02-02 12:37:09 -08004735 /* For multipath routes, walk the siblings list and add
4736 * each as a nexthop within RTA_MULTIPATH.
4737 */
David Ahern93c2fb22018-04-18 15:38:59 -07004738 if (rt->fib6_nsiblings) {
David Ahern8d1c8022018-04-17 17:33:26 -07004739 struct fib6_info *sibling, *next_sibling;
David Ahernbeb1afac52017-02-02 12:37:09 -08004740 struct nlattr *mp;
4741
4742 mp = nla_nest_start(skb, RTA_MULTIPATH);
4743 if (!mp)
4744 goto nla_put_failure;
4745
4746 if (rt6_add_nexthop(skb, rt) < 0)
4747 goto nla_put_failure;
4748
4749 list_for_each_entry_safe(sibling, next_sibling,
David Ahern93c2fb22018-04-18 15:38:59 -07004750 &rt->fib6_siblings, fib6_siblings) {
David Ahernbeb1afac52017-02-02 12:37:09 -08004751 if (rt6_add_nexthop(skb, sibling) < 0)
4752 goto nla_put_failure;
4753 }
4754
4755 nla_nest_end(skb, mp);
4756 } else {
David Ahern5be083c2017-03-06 15:57:31 -08004757 if (rt6_nexthop_info(skb, rt, &rtm->rtm_flags, false) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004758 goto nla_put_failure;
4759 }
4760
David Ahern93c2fb22018-04-18 15:38:59 -07004761 if (rt->fib6_flags & RTF_EXPIRES) {
David Ahern14895682018-04-17 17:33:17 -07004762 expires = dst ? dst->expires : rt->expires;
4763 expires -= jiffies;
4764 }
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07004765
David Ahernd4ead6b2018-04-17 17:33:16 -07004766 if (rtnl_put_cacheinfo(skb, dst, 0, expires, dst ? dst->error : 0) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08004767 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768
David Ahern93c2fb22018-04-18 15:38:59 -07004769 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->fib6_flags)))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004770 goto nla_put_failure;
4771
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004772
Johannes Berg053c0952015-01-16 22:09:00 +01004773 nlmsg_end(skb, nlh);
4774 return 0;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004775
4776nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08004777 nlmsg_cancel(skb, nlh);
4778 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779}
4780
David Ahern8d1c8022018-04-17 17:33:26 -07004781int rt6_dump_route(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782{
4783 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
David Ahern1f17e2f2017-01-26 13:54:08 -08004784 struct net *net = arg->net;
4785
David Ahern421842e2018-04-17 17:33:18 -07004786 if (rt == net->ipv6.fib6_null_entry)
David Ahern1f17e2f2017-01-26 13:54:08 -08004787 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788
Thomas Graf2d7202b2006-08-22 00:01:27 -07004789 if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
4790 struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
David Ahernf8cfe2c2017-01-17 15:51:08 -08004791
4792 /* user wants prefix routes only */
4793 if (rtm->rtm_flags & RTM_F_PREFIX &&
David Ahern93c2fb22018-04-18 15:38:59 -07004794 !(rt->fib6_flags & RTF_PREFIX_RT)) {
David Ahernf8cfe2c2017-01-17 15:51:08 -08004795 /* success since this is not a prefix route */
4796 return 1;
4797 }
4798 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799
David Ahernd4ead6b2018-04-17 17:33:16 -07004800 return rt6_fill_node(net, arg->skb, rt, NULL, NULL, NULL, 0,
4801 RTM_NEWROUTE, NETLINK_CB(arg->cb->skb).portid,
4802 arg->cb->nlh->nlmsg_seq, NLM_F_MULTI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803}
4804
David Ahernc21ef3e2017-04-16 09:48:24 -07004805static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
4806 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09004808 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07004809 struct nlattr *tb[RTA_MAX+1];
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004810 int err, iif = 0, oif = 0;
David Aherna68886a2018-04-20 15:38:02 -07004811 struct fib6_info *from;
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004812 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07004814 struct sk_buff *skb;
4815 struct rtmsg *rtm;
David S. Miller4c9483b2011-03-12 16:22:43 -05004816 struct flowi6 fl6;
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004817 bool fibmatch;
Thomas Grafab364a62006-08-22 00:01:47 -07004818
Johannes Bergfceb6432017-04-12 14:34:07 +02004819 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
David Ahernc21ef3e2017-04-16 09:48:24 -07004820 extack);
Thomas Grafab364a62006-08-22 00:01:47 -07004821 if (err < 0)
4822 goto errout;
4823
4824 err = -EINVAL;
David S. Miller4c9483b2011-03-12 16:22:43 -05004825 memset(&fl6, 0, sizeof(fl6));
Hannes Frederic Sowa38b70972016-06-11 20:08:19 +02004826 rtm = nlmsg_data(nlh);
4827 fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004828 fibmatch = !!(rtm->rtm_flags & RTM_F_FIB_MATCH);
Thomas Grafab364a62006-08-22 00:01:47 -07004829
4830 if (tb[RTA_SRC]) {
4831 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
4832 goto errout;
4833
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00004834 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07004835 }
4836
4837 if (tb[RTA_DST]) {
4838 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
4839 goto errout;
4840
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00004841 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07004842 }
4843
4844 if (tb[RTA_IIF])
4845 iif = nla_get_u32(tb[RTA_IIF]);
4846
4847 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004848 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07004849
Lorenzo Colitti2e47b292014-05-15 16:38:41 -07004850 if (tb[RTA_MARK])
4851 fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
4852
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09004853 if (tb[RTA_UID])
4854 fl6.flowi6_uid = make_kuid(current_user_ns(),
4855 nla_get_u32(tb[RTA_UID]));
4856 else
4857 fl6.flowi6_uid = iif ? INVALID_UID : current_uid();
4858
Roopa Prabhueacb9382018-05-22 14:03:28 -07004859 if (tb[RTA_SPORT])
4860 fl6.fl6_sport = nla_get_be16(tb[RTA_SPORT]);
4861
4862 if (tb[RTA_DPORT])
4863 fl6.fl6_dport = nla_get_be16(tb[RTA_DPORT]);
4864
4865 if (tb[RTA_IP_PROTO]) {
4866 err = rtm_getroute_parse_ip_proto(tb[RTA_IP_PROTO],
4867 &fl6.flowi6_proto, extack);
4868 if (err)
4869 goto errout;
4870 }
4871
Thomas Grafab364a62006-08-22 00:01:47 -07004872 if (iif) {
4873 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004874 int flags = 0;
4875
Florian Westphal121622d2017-08-15 16:34:42 +02004876 rcu_read_lock();
4877
4878 dev = dev_get_by_index_rcu(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07004879 if (!dev) {
Florian Westphal121622d2017-08-15 16:34:42 +02004880 rcu_read_unlock();
Thomas Grafab364a62006-08-22 00:01:47 -07004881 err = -ENODEV;
4882 goto errout;
4883 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004884
4885 fl6.flowi6_iif = iif;
4886
4887 if (!ipv6_addr_any(&fl6.saddr))
4888 flags |= RT6_LOOKUP_F_HAS_SADDR;
4889
David Ahernb75cc8f2018-03-02 08:32:17 -08004890 dst = ip6_route_input_lookup(net, dev, &fl6, NULL, flags);
Florian Westphal121622d2017-08-15 16:34:42 +02004891
4892 rcu_read_unlock();
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004893 } else {
4894 fl6.flowi6_oif = oif;
4895
Ido Schimmel58acfd72017-12-20 12:28:25 +02004896 dst = ip6_route_output(net, NULL, &fl6);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004897 }
4898
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004899
4900 rt = container_of(dst, struct rt6_info, dst);
4901 if (rt->dst.error) {
4902 err = rt->dst.error;
4903 ip6_rt_put(rt);
4904 goto errout;
Thomas Grafab364a62006-08-22 00:01:47 -07004905 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906
WANG Cong9d6acb32017-03-01 20:48:39 -08004907 if (rt == net->ipv6.ip6_null_entry) {
4908 err = rt->dst.error;
4909 ip6_rt_put(rt);
4910 goto errout;
4911 }
4912
Linus Torvalds1da177e2005-04-16 15:20:36 -07004913 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05004914 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00004915 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07004916 err = -ENOBUFS;
4917 goto errout;
4918 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919
Changli Gaod8d1f302010-06-10 23:31:35 -07004920 skb_dst_set(skb, &rt->dst);
David Aherna68886a2018-04-20 15:38:02 -07004921
4922 rcu_read_lock();
4923 from = rcu_dereference(rt->from);
4924
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004925 if (fibmatch)
David Aherna68886a2018-04-20 15:38:02 -07004926 err = rt6_fill_node(net, skb, from, NULL, NULL, NULL, iif,
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004927 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
4928 nlh->nlmsg_seq, 0);
4929 else
David Aherna68886a2018-04-20 15:38:02 -07004930 err = rt6_fill_node(net, skb, from, dst, &fl6.daddr,
4931 &fl6.saddr, iif, RTM_NEWROUTE,
David Ahernd4ead6b2018-04-17 17:33:16 -07004932 NETLINK_CB(in_skb).portid, nlh->nlmsg_seq,
4933 0);
David Aherna68886a2018-04-20 15:38:02 -07004934 rcu_read_unlock();
4935
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07004937 kfree_skb(skb);
4938 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004939 }
4940
Eric W. Biederman15e47302012-09-07 20:12:54 +00004941 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07004942errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004944}
4945
David Ahern8d1c8022018-04-17 17:33:26 -07004946void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info,
Roopa Prabhu37a1d362015-09-13 10:18:33 -07004947 unsigned int nlm_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004948{
4949 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08004950 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08004951 u32 seq;
4952 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004953
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08004954 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05004955 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07004956
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004957 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05004958 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07004959 goto errout;
4960
David Ahernd4ead6b2018-04-17 17:33:16 -07004961 err = rt6_fill_node(net, skb, rt, NULL, NULL, NULL, 0,
4962 event, info->portid, seq, nlm_flags);
Patrick McHardy26932562007-01-31 23:16:40 -08004963 if (err < 0) {
4964 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
4965 WARN_ON(err == -EMSGSIZE);
4966 kfree_skb(skb);
4967 goto errout;
4968 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00004969 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08004970 info->nlh, gfp_any());
4971 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07004972errout:
4973 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08004974 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975}
4976
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004977static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00004978 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004979{
Jiri Pirko351638e2013-05-28 01:30:21 +00004980 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09004981 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004982
WANG Cong242d3a42017-05-08 10:12:13 -07004983 if (!(dev->flags & IFF_LOOPBACK))
4984 return NOTIFY_OK;
4985
4986 if (event == NETDEV_REGISTER) {
David Ahern421842e2018-04-17 17:33:18 -07004987 net->ipv6.fib6_null_entry->fib6_nh.nh_dev = dev;
Changli Gaod8d1f302010-06-10 23:31:35 -07004988 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004989 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
4990#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07004991 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004992 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07004993 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004994 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
4995#endif
WANG Cong76da0702017-06-20 11:42:27 -07004996 } else if (event == NETDEV_UNREGISTER &&
4997 dev->reg_state != NETREG_UNREGISTERED) {
4998 /* NETDEV_UNREGISTER could be fired for multiple times by
4999 * netdev_wait_allrefs(). Make sure we only call this once.
5000 */
Eric Dumazet12d94a82017-08-15 04:09:51 -07005001 in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev);
WANG Cong242d3a42017-05-08 10:12:13 -07005002#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Eric Dumazet12d94a82017-08-15 04:09:51 -07005003 in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev);
5004 in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev);
WANG Cong242d3a42017-05-08 10:12:13 -07005005#endif
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005006 }
5007
5008 return NOTIFY_OK;
5009}
5010
Linus Torvalds1da177e2005-04-16 15:20:36 -07005011/*
5012 * /proc
5013 */
5014
5015#ifdef CONFIG_PROC_FS
5016
Alexey Dobriyan33120b32007-11-06 05:27:11 -08005017static const struct file_operations ipv6_route_proc_fops = {
Alexey Dobriyan33120b32007-11-06 05:27:11 -08005018 .open = ipv6_route_open,
5019 .read = seq_read,
5020 .llseek = seq_lseek,
Hannes Frederic Sowa8d2ca1d2013-09-21 16:55:59 +02005021 .release = seq_release_net,
Alexey Dobriyan33120b32007-11-06 05:27:11 -08005022};
5023
Linus Torvalds1da177e2005-04-16 15:20:36 -07005024static int rt6_stats_seq_show(struct seq_file *seq, void *v)
5025{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005026 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005027 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005028 net->ipv6.rt6_stats->fib_nodes,
5029 net->ipv6.rt6_stats->fib_route_nodes,
Wei Wang81eb8442017-10-06 12:06:11 -07005030 atomic_read(&net->ipv6.rt6_stats->fib_rt_alloc),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005031 net->ipv6.rt6_stats->fib_rt_entries,
5032 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00005033 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005034 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005035
5036 return 0;
5037}
5038
5039static int rt6_stats_seq_open(struct inode *inode, struct file *file)
5040{
Pavel Emelyanovde05c552008-07-18 04:07:21 -07005041 return single_open_net(inode, file, rt6_stats_seq_show);
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005042}
5043
Arjan van de Ven9a321442007-02-12 00:55:35 -08005044static const struct file_operations rt6_stats_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005045 .open = rt6_stats_seq_open,
5046 .read = seq_read,
5047 .llseek = seq_lseek,
Pavel Emelyanovb6fcbdb2008-07-18 04:07:44 -07005048 .release = single_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049};
5050#endif /* CONFIG_PROC_FS */
5051
5052#ifdef CONFIG_SYSCTL
5053
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054static
Joe Perchesfe2c6332013-06-11 23:04:25 -07005055int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056 void __user *buffer, size_t *lenp, loff_t *ppos)
5057{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005058 struct net *net;
5059 int delay;
5060 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005061 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005062
5063 net = (struct net *)ctl->extra1;
5064 delay = net->ipv6.sysctl.flush_delay;
5065 proc_dointvec(ctl, write, buffer, lenp, ppos);
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02005066 fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005067 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068}
5069
Joe Perchesfe2c6332013-06-11 23:04:25 -07005070struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09005071 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08005073 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005074 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07005075 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005076 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 },
5078 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08005080 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081 .maxlen = sizeof(int),
5082 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005083 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084 },
5085 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08005087 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088 .maxlen = sizeof(int),
5089 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005090 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091 },
5092 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005093 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08005094 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005095 .maxlen = sizeof(int),
5096 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005097 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005098 },
5099 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08005101 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102 .maxlen = sizeof(int),
5103 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005104 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005105 },
5106 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005107 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08005108 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005109 .maxlen = sizeof(int),
5110 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005111 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005112 },
5113 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08005115 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005116 .maxlen = sizeof(int),
5117 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07005118 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119 },
5120 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08005122 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123 .maxlen = sizeof(int),
5124 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005125 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126 },
5127 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08005129 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005130 .maxlen = sizeof(int),
5131 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07005132 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133 },
5134 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08005136 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005137 .maxlen = sizeof(int),
5138 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005139 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005140 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08005141 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142};
5143
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00005144struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08005145{
5146 struct ctl_table *table;
5147
5148 table = kmemdup(ipv6_route_table_template,
5149 sizeof(ipv6_route_table_template),
5150 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09005151
5152 if (table) {
5153 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005154 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00005155 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09005156 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
5157 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
5158 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
5159 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
5160 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
5161 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
5162 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08005163 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
Eric W. Biederman464dc802012-11-16 03:02:59 +00005164
5165 /* Don't export sysctls to unprivileged users */
5166 if (net->user_ns != &init_user_ns)
5167 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09005168 }
5169
Daniel Lezcano760f2d02008-01-10 02:53:43 -08005170 return table;
5171}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172#endif
5173
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00005174static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005175{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07005176 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005177
Alexey Dobriyan86393e52009-08-29 01:34:49 +00005178 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
5179 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005180
Eric Dumazetfc66f952010-10-08 06:37:34 +00005181 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
5182 goto out_ip6_dst_ops;
5183
David Ahern421842e2018-04-17 17:33:18 -07005184 net->ipv6.fib6_null_entry = kmemdup(&fib6_null_entry_template,
5185 sizeof(*net->ipv6.fib6_null_entry),
5186 GFP_KERNEL);
5187 if (!net->ipv6.fib6_null_entry)
5188 goto out_ip6_dst_entries;
5189
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005190 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
5191 sizeof(*net->ipv6.ip6_null_entry),
5192 GFP_KERNEL);
5193 if (!net->ipv6.ip6_null_entry)
David Ahern421842e2018-04-17 17:33:18 -07005194 goto out_fib6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005195 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005196 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
5197 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005198
5199#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Vincent Bernatfeca7d82017-08-08 20:23:49 +02005200 net->ipv6.fib6_has_custom_rules = false;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005201 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
5202 sizeof(*net->ipv6.ip6_prohibit_entry),
5203 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005204 if (!net->ipv6.ip6_prohibit_entry)
5205 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005206 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005207 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
5208 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005209
5210 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
5211 sizeof(*net->ipv6.ip6_blk_hole_entry),
5212 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005213 if (!net->ipv6.ip6_blk_hole_entry)
5214 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005215 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005216 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
5217 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005218#endif
5219
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07005220 net->ipv6.sysctl.flush_delay = 0;
5221 net->ipv6.sysctl.ip6_rt_max_size = 4096;
5222 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
5223 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
5224 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
5225 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
5226 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
5227 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
5228
Benjamin Thery6891a342008-03-04 13:49:47 -08005229 net->ipv6.ip6_rt_gc_expire = 30*HZ;
5230
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005231 ret = 0;
5232out:
5233 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005234
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005235#ifdef CONFIG_IPV6_MULTIPLE_TABLES
5236out_ip6_prohibit_entry:
5237 kfree(net->ipv6.ip6_prohibit_entry);
5238out_ip6_null_entry:
5239 kfree(net->ipv6.ip6_null_entry);
5240#endif
David Ahern421842e2018-04-17 17:33:18 -07005241out_fib6_null_entry:
5242 kfree(net->ipv6.fib6_null_entry);
Eric Dumazetfc66f952010-10-08 06:37:34 +00005243out_ip6_dst_entries:
5244 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005245out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005246 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005247}
5248
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00005249static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005250{
David Ahern421842e2018-04-17 17:33:18 -07005251 kfree(net->ipv6.fib6_null_entry);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005252 kfree(net->ipv6.ip6_null_entry);
5253#ifdef CONFIG_IPV6_MULTIPLE_TABLES
5254 kfree(net->ipv6.ip6_prohibit_entry);
5255 kfree(net->ipv6.ip6_blk_hole_entry);
5256#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00005257 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005258}
5259
Thomas Grafd1896342012-06-18 12:08:33 +00005260static int __net_init ip6_route_net_init_late(struct net *net)
5261{
5262#ifdef CONFIG_PROC_FS
Gao fengd4beaa62013-02-18 01:34:54 +00005263 proc_create("ipv6_route", 0, net->proc_net, &ipv6_route_proc_fops);
Joe Perchesd6444062018-03-23 15:54:38 -07005264 proc_create("rt6_stats", 0444, net->proc_net, &rt6_stats_seq_fops);
Thomas Grafd1896342012-06-18 12:08:33 +00005265#endif
5266 return 0;
5267}
5268
5269static void __net_exit ip6_route_net_exit_late(struct net *net)
5270{
5271#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00005272 remove_proc_entry("ipv6_route", net->proc_net);
5273 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00005274#endif
5275}
5276
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005277static struct pernet_operations ip6_route_net_ops = {
5278 .init = ip6_route_net_init,
5279 .exit = ip6_route_net_exit,
5280};
5281
David S. Millerc3426b42012-06-09 16:27:05 -07005282static int __net_init ipv6_inetpeer_init(struct net *net)
5283{
5284 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
5285
5286 if (!bp)
5287 return -ENOMEM;
5288 inet_peer_base_init(bp);
5289 net->ipv6.peers = bp;
5290 return 0;
5291}
5292
5293static void __net_exit ipv6_inetpeer_exit(struct net *net)
5294{
5295 struct inet_peer_base *bp = net->ipv6.peers;
5296
5297 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07005298 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07005299 kfree(bp);
5300}
5301
David S. Miller2b823f72012-06-09 19:00:16 -07005302static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07005303 .init = ipv6_inetpeer_init,
5304 .exit = ipv6_inetpeer_exit,
5305};
5306
Thomas Grafd1896342012-06-18 12:08:33 +00005307static struct pernet_operations ip6_route_net_late_ops = {
5308 .init = ip6_route_net_init_late,
5309 .exit = ip6_route_net_exit_late,
5310};
5311
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005312static struct notifier_block ip6_route_dev_notifier = {
5313 .notifier_call = ip6_route_dev_notify,
WANG Cong242d3a42017-05-08 10:12:13 -07005314 .priority = ADDRCONF_NOTIFY_PRIORITY - 10,
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005315};
5316
WANG Cong2f460932017-05-03 22:07:31 -07005317void __init ip6_route_init_special_entries(void)
5318{
5319 /* Registering of the loopback is done before this portion of code,
5320 * the loopback reference in rt6_info will not be taken, do it
5321 * manually for init_net */
David Ahern421842e2018-04-17 17:33:18 -07005322 init_net.ipv6.fib6_null_entry->fib6_nh.nh_dev = init_net.loopback_dev;
WANG Cong2f460932017-05-03 22:07:31 -07005323 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
5324 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5325 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
5326 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
5327 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5328 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
5329 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5330 #endif
5331}
5332
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005333int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005334{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005335 int ret;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07005336 int cpu;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005337
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08005338 ret = -ENOMEM;
5339 ip6_dst_ops_template.kmem_cachep =
5340 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
5341 SLAB_HWCACHE_ALIGN, NULL);
5342 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08005343 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07005344
Eric Dumazetfc66f952010-10-08 06:37:34 +00005345 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005346 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08005347 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08005348
David S. Millerc3426b42012-06-09 16:27:05 -07005349 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
5350 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07005351 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00005352
David S. Miller7e52b332012-06-15 15:51:55 -07005353 ret = register_pernet_subsys(&ip6_route_net_ops);
5354 if (ret)
5355 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07005356
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07005357 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
5358
David S. Millere8803b62012-06-16 01:12:19 -07005359 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005360 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005361 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005362
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005363 ret = xfrm6_init();
5364 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07005365 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08005366
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005367 ret = fib6_rules_init();
5368 if (ret)
5369 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08005370
Thomas Grafd1896342012-06-18 12:08:33 +00005371 ret = register_pernet_subsys(&ip6_route_net_late_ops);
5372 if (ret)
5373 goto fib6_rules_init;
5374
Florian Westphal16feebc2017-12-02 21:44:08 +01005375 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_NEWROUTE,
5376 inet6_rtm_newroute, NULL, 0);
5377 if (ret < 0)
5378 goto out_register_late_subsys;
5379
5380 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_DELROUTE,
5381 inet6_rtm_delroute, NULL, 0);
5382 if (ret < 0)
5383 goto out_register_late_subsys;
5384
5385 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_GETROUTE,
5386 inet6_rtm_getroute, NULL,
5387 RTNL_FLAG_DOIT_UNLOCKED);
5388 if (ret < 0)
Thomas Grafd1896342012-06-18 12:08:33 +00005389 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005390
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005391 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005392 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00005393 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005394
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07005395 for_each_possible_cpu(cpu) {
5396 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
5397
5398 INIT_LIST_HEAD(&ul->head);
5399 spin_lock_init(&ul->lock);
5400 }
5401
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005402out:
5403 return ret;
5404
Thomas Grafd1896342012-06-18 12:08:33 +00005405out_register_late_subsys:
Florian Westphal16feebc2017-12-02 21:44:08 +01005406 rtnl_unregister_all(PF_INET6);
Thomas Grafd1896342012-06-18 12:08:33 +00005407 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005408fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005409 fib6_rules_cleanup();
5410xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005411 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00005412out_fib6_init:
5413 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005414out_register_subsys:
5415 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07005416out_register_inetpeer:
5417 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00005418out_dst_entries:
5419 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005420out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005421 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005422 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423}
5424
5425void ip6_route_cleanup(void)
5426{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005427 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00005428 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07005429 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005430 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07005432 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005433 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00005434 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005435 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436}