blob: e3c5f95550bc2a7f1b0d5d3e426b2c99c6d92f60 [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 Ahern702cea52019-04-09 14:41:13 -0700105static int rt6_score_route(const struct fib6_nh *nh, u32 fib6_flags, int oif,
106 int strict);
David Ahern8d1c8022018-04-17 17:33:26 -0700107static size_t rt6_nlmsg_size(struct fib6_info *rt);
David Ahernd4ead6b2018-04-17 17:33:16 -0700108static int rt6_fill_node(struct net *net, struct sk_buff *skb,
David Ahern8d1c8022018-04-17 17:33:26 -0700109 struct fib6_info *rt, struct dst_entry *dst,
David Ahernd4ead6b2018-04-17 17:33:16 -0700110 struct in6_addr *dest, struct in6_addr *src,
David Ahern16a16cd2017-02-02 12:37:11 -0800111 int iif, int type, u32 portid, u32 seq,
112 unsigned int flags);
David Ahern7e4b5122019-04-16 14:36:00 -0700113static struct rt6_info *rt6_find_cached_rt(const struct fib6_result *res,
Wei Wang35732d02017-10-06 12:05:57 -0700114 struct in6_addr *daddr,
115 struct in6_addr *saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800117#ifdef CONFIG_IPV6_ROUTE_INFO
David Ahern8d1c8022018-04-17 17:33:26 -0700118static struct fib6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000119 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -0700120 const struct in6_addr *gwaddr,
121 struct net_device *dev,
Eric Dumazet95c96172012-04-15 05:58:06 +0000122 unsigned int pref);
David Ahern8d1c8022018-04-17 17:33:26 -0700123static struct fib6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000124 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -0700125 const struct in6_addr *gwaddr,
126 struct net_device *dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800127#endif
128
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700129struct uncached_list {
130 spinlock_t lock;
131 struct list_head head;
132};
133
134static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list);
135
Xin Long510c3212018-02-14 19:06:02 +0800136void rt6_uncached_list_add(struct rt6_info *rt)
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700137{
138 struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);
139
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700140 rt->rt6i_uncached_list = ul;
141
142 spin_lock_bh(&ul->lock);
143 list_add_tail(&rt->rt6i_uncached, &ul->head);
144 spin_unlock_bh(&ul->lock);
145}
146
Xin Long510c3212018-02-14 19:06:02 +0800147void rt6_uncached_list_del(struct rt6_info *rt)
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700148{
149 if (!list_empty(&rt->rt6i_uncached)) {
150 struct uncached_list *ul = rt->rt6i_uncached_list;
Wei Wang81eb8442017-10-06 12:06:11 -0700151 struct net *net = dev_net(rt->dst.dev);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700152
153 spin_lock_bh(&ul->lock);
154 list_del(&rt->rt6i_uncached);
Wei Wang81eb8442017-10-06 12:06:11 -0700155 atomic_dec(&net->ipv6.rt6_stats->fib_rt_uncache);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700156 spin_unlock_bh(&ul->lock);
157 }
158}
159
160static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev)
161{
162 struct net_device *loopback_dev = net->loopback_dev;
163 int cpu;
164
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500165 if (dev == loopback_dev)
166 return;
167
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700168 for_each_possible_cpu(cpu) {
169 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
170 struct rt6_info *rt;
171
172 spin_lock_bh(&ul->lock);
173 list_for_each_entry(rt, &ul->head, rt6i_uncached) {
174 struct inet6_dev *rt_idev = rt->rt6i_idev;
175 struct net_device *rt_dev = rt->dst.dev;
176
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500177 if (rt_idev->dev == dev) {
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700178 rt->rt6i_idev = in6_dev_get(loopback_dev);
179 in6_dev_put(rt_idev);
180 }
181
Eric W. Biedermane332bc62015-10-12 11:02:08 -0500182 if (rt_dev == dev) {
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700183 rt->dst.dev = loopback_dev;
184 dev_hold(rt->dst.dev);
185 dev_put(rt_dev);
186 }
187 }
188 spin_unlock_bh(&ul->lock);
189 }
190}
191
David Ahernf8a1b432018-04-17 17:33:21 -0700192static inline const void *choose_neigh_daddr(const struct in6_addr *p,
David S. Millerf894cbf2012-07-02 21:52:24 -0700193 struct sk_buff *skb,
194 const void *daddr)
David S. Miller39232972012-01-26 15:22:32 -0500195{
David S. Millera7563f32012-01-26 16:29:16 -0500196 if (!ipv6_addr_any(p))
David S. Miller39232972012-01-26 15:22:32 -0500197 return (const void *) p;
David S. Millerf894cbf2012-07-02 21:52:24 -0700198 else if (skb)
199 return &ipv6_hdr(skb)->daddr;
David S. Miller39232972012-01-26 15:22:32 -0500200 return daddr;
201}
202
David Ahernf8a1b432018-04-17 17:33:21 -0700203struct neighbour *ip6_neigh_lookup(const struct in6_addr *gw,
204 struct net_device *dev,
205 struct sk_buff *skb,
206 const void *daddr)
David S. Millerd3aaeb32011-07-18 00:40:17 -0700207{
David S. Miller39232972012-01-26 15:22:32 -0500208 struct neighbour *n;
209
David Ahernf8a1b432018-04-17 17:33:21 -0700210 daddr = choose_neigh_daddr(gw, skb, daddr);
211 n = __ipv6_neigh_lookup(dev, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500212 if (n)
213 return n;
Stefano Brivio7adf3242019-01-02 13:29:27 +0100214
215 n = neigh_create(&nd_tbl, daddr, dev);
216 return IS_ERR(n) ? NULL : n;
David Ahernf8a1b432018-04-17 17:33:21 -0700217}
218
219static struct neighbour *ip6_dst_neigh_lookup(const struct dst_entry *dst,
220 struct sk_buff *skb,
221 const void *daddr)
222{
223 const struct rt6_info *rt = container_of(dst, struct rt6_info, dst);
224
225 return ip6_neigh_lookup(&rt->rt6i_gateway, dst->dev, skb, daddr);
David S. Millerf83c7792011-12-28 15:41:23 -0500226}
227
Julian Anastasov63fca652017-02-06 23:14:15 +0200228static void ip6_confirm_neigh(const struct dst_entry *dst, const void *daddr)
229{
230 struct net_device *dev = dst->dev;
231 struct rt6_info *rt = (struct rt6_info *)dst;
232
David Ahernf8a1b432018-04-17 17:33:21 -0700233 daddr = choose_neigh_daddr(&rt->rt6i_gateway, NULL, daddr);
Julian Anastasov63fca652017-02-06 23:14:15 +0200234 if (!daddr)
235 return;
236 if (dev->flags & (IFF_NOARP | IFF_LOOPBACK))
237 return;
238 if (ipv6_addr_is_multicast((const struct in6_addr *)daddr))
239 return;
240 __ipv6_confirm_neigh(dev, daddr);
241}
242
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -0800243static struct dst_ops ip6_dst_ops_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 .family = AF_INET6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 .gc = ip6_dst_gc,
246 .gc_thresh = 1024,
247 .check = ip6_dst_check,
David S. Miller0dbaee32010-12-13 12:52:14 -0800248 .default_advmss = ip6_default_advmss,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000249 .mtu = ip6_mtu,
David Ahernd4ead6b2018-04-17 17:33:16 -0700250 .cow_metrics = dst_cow_metrics_generic,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 .destroy = ip6_dst_destroy,
252 .ifdown = ip6_dst_ifdown,
253 .negative_advice = ip6_negative_advice,
254 .link_failure = ip6_link_failure,
255 .update_pmtu = ip6_rt_update_pmtu,
David S. Miller6e157b62012-07-12 00:05:02 -0700256 .redirect = rt6_do_redirect,
Eric W. Biederman9f8955c2015-10-07 16:48:39 -0500257 .local_out = __ip6_local_out,
David Ahernf8a1b432018-04-17 17:33:21 -0700258 .neigh_lookup = ip6_dst_neigh_lookup,
Julian Anastasov63fca652017-02-06 23:14:15 +0200259 .confirm_neigh = ip6_confirm_neigh,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260};
261
Steffen Klassertebb762f2011-11-23 02:12:51 +0000262static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
Roland Dreierec831ea2011-01-31 13:16:00 -0800263{
Steffen Klassert618f9bc2011-11-23 02:13:31 +0000264 unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
265
266 return mtu ? : dst->dev->mtu;
Roland Dreierec831ea2011-01-31 13:16:00 -0800267}
268
David S. Miller6700c272012-07-17 03:29:28 -0700269static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
270 struct sk_buff *skb, u32 mtu)
David S. Miller14e50e52007-05-24 18:17:54 -0700271{
272}
273
David S. Miller6700c272012-07-17 03:29:28 -0700274static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
275 struct sk_buff *skb)
David S. Millerb587ee32012-07-12 00:39:24 -0700276{
277}
278
David S. Miller14e50e52007-05-24 18:17:54 -0700279static struct dst_ops ip6_dst_blackhole_ops = {
280 .family = AF_INET6,
David S. Miller14e50e52007-05-24 18:17:54 -0700281 .destroy = ip6_dst_destroy,
282 .check = ip6_dst_check,
Steffen Klassertebb762f2011-11-23 02:12:51 +0000283 .mtu = ip6_blackhole_mtu,
Eric Dumazet214f45c2011-02-18 11:39:01 -0800284 .default_advmss = ip6_default_advmss,
David S. Miller14e50e52007-05-24 18:17:54 -0700285 .update_pmtu = ip6_rt_blackhole_update_pmtu,
David S. Millerb587ee32012-07-12 00:39:24 -0700286 .redirect = ip6_rt_blackhole_redirect,
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -0700287 .cow_metrics = dst_cow_metrics_generic,
David Ahernf8a1b432018-04-17 17:33:21 -0700288 .neigh_lookup = ip6_dst_neigh_lookup,
David S. Miller14e50e52007-05-24 18:17:54 -0700289};
290
David S. Miller62fa8a82011-01-26 20:51:05 -0800291static const u32 ip6_template_metrics[RTAX_MAX] = {
Li RongQing14edd872012-10-24 14:01:18 +0800292 [RTAX_HOPLIMIT - 1] = 0,
David S. Miller62fa8a82011-01-26 20:51:05 -0800293};
294
David Ahern8d1c8022018-04-17 17:33:26 -0700295static const struct fib6_info fib6_null_entry_template = {
David Ahern93c2fb22018-04-18 15:38:59 -0700296 .fib6_flags = (RTF_REJECT | RTF_NONEXTHOP),
297 .fib6_protocol = RTPROT_KERNEL,
298 .fib6_metric = ~(u32)0,
299 .fib6_ref = ATOMIC_INIT(1),
David Ahern421842e2018-04-17 17:33:18 -0700300 .fib6_type = RTN_UNREACHABLE,
301 .fib6_metrics = (struct dst_metrics *)&dst_default_metrics,
302};
303
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000304static const struct rt6_info ip6_null_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700305 .dst = {
306 .__refcnt = ATOMIC_INIT(1),
307 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000308 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700309 .error = -ENETUNREACH,
Changli Gaod8d1f302010-06-10 23:31:35 -0700310 .input = ip6_pkt_discard,
311 .output = ip6_pkt_discard_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 },
313 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314};
315
Thomas Graf101367c2006-08-04 03:39:02 -0700316#ifdef CONFIG_IPV6_MULTIPLE_TABLES
317
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000318static const struct rt6_info ip6_prohibit_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700319 .dst = {
320 .__refcnt = ATOMIC_INIT(1),
321 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000322 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700323 .error = -EACCES,
Changli Gaod8d1f302010-06-10 23:31:35 -0700324 .input = ip6_pkt_prohibit,
325 .output = ip6_pkt_prohibit_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700326 },
327 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Thomas Graf101367c2006-08-04 03:39:02 -0700328};
329
Eric Dumazetfb0af4c2012-09-11 21:47:51 +0000330static const struct rt6_info ip6_blk_hole_entry_template = {
Changli Gaod8d1f302010-06-10 23:31:35 -0700331 .dst = {
332 .__refcnt = ATOMIC_INIT(1),
333 .__use = 1,
Nicolas Dichtel2c20cbd2012-09-10 22:09:47 +0000334 .obsolete = DST_OBSOLETE_FORCE_CHK,
Changli Gaod8d1f302010-06-10 23:31:35 -0700335 .error = -EINVAL,
Changli Gaod8d1f302010-06-10 23:31:35 -0700336 .input = dst_discard,
Eric W. Biedermanede20592015-10-07 16:48:47 -0500337 .output = dst_discard_out,
Thomas Graf101367c2006-08-04 03:39:02 -0700338 },
339 .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
Thomas Graf101367c2006-08-04 03:39:02 -0700340};
341
342#endif
343
Martin KaFai Lauebfa45f2015-10-15 16:39:57 -0700344static void rt6_info_init(struct rt6_info *rt)
345{
346 struct dst_entry *dst = &rt->dst;
347
348 memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
Martin KaFai Lauebfa45f2015-10-15 16:39:57 -0700349 INIT_LIST_HEAD(&rt->rt6i_uncached);
350}
351
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352/* allocate dst with ip6_dst_ops */
David Ahern93531c62018-04-17 17:33:25 -0700353struct rt6_info *ip6_dst_alloc(struct net *net, struct net_device *dev,
354 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355{
David S. Miller97bab732012-06-09 22:36:36 -0700356 struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
Wei Wangb2a9c0e2017-06-17 10:42:41 -0700357 1, DST_OBSOLETE_FORCE_CHK, flags);
David S. Millercf911662011-04-28 14:31:47 -0700358
Wei Wang81eb8442017-10-06 12:06:11 -0700359 if (rt) {
Martin KaFai Lauebfa45f2015-10-15 16:39:57 -0700360 rt6_info_init(rt);
Wei Wang81eb8442017-10-06 12:06:11 -0700361 atomic_inc(&net->ipv6.rt6_stats->fib_rt_alloc);
362 }
Steffen Klassert81048912012-07-05 23:37:09 +0000363
David S. Millercf911662011-04-28 14:31:47 -0700364 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365}
David Ahern9ab179d2016-04-07 11:10:06 -0700366EXPORT_SYMBOL(ip6_dst_alloc);
Martin KaFai Laud52d3992015-05-22 20:56:06 -0700367
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368static void ip6_dst_destroy(struct dst_entry *dst)
369{
370 struct rt6_info *rt = (struct rt6_info *)dst;
David Aherna68886a2018-04-20 15:38:02 -0700371 struct fib6_info *from;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700372 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
David Ahern1620a332018-10-04 20:07:54 -0700374 ip_dst_metrics_put(dst);
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -0700375 rt6_uncached_list_del(rt);
376
377 idev = rt->rt6i_idev;
David S. Miller38308472011-12-03 18:02:47 -0500378 if (idev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 rt->rt6i_idev = NULL;
380 in6_dev_put(idev);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900381 }
Gao feng1716a962012-04-06 00:13:10 +0000382
David Aherna68886a2018-04-20 15:38:02 -0700383 rcu_read_lock();
384 from = rcu_dereference(rt->from);
385 rcu_assign_pointer(rt->from, NULL);
David Ahern93531c62018-04-17 17:33:25 -0700386 fib6_info_release(from);
David Aherna68886a2018-04-20 15:38:02 -0700387 rcu_read_unlock();
David S. Millerb3419362010-11-30 12:27:11 -0800388}
389
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
391 int how)
392{
393 struct rt6_info *rt = (struct rt6_info *)dst;
394 struct inet6_dev *idev = rt->rt6i_idev;
Denis V. Lunev5a3e55d2007-12-07 00:38:10 -0800395 struct net_device *loopback_dev =
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900396 dev_net(dev)->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
Wei Wange5645f52017-08-14 10:44:59 -0700398 if (idev && idev->dev != loopback_dev) {
399 struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev);
400 if (loopback_idev) {
401 rt->rt6i_idev = loopback_idev;
402 in6_dev_put(idev);
David S. Miller97cac082012-07-02 22:43:47 -0700403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 }
405}
406
Martin KaFai Lau5973fb12015-11-11 11:51:07 -0800407static bool __rt6_check_expired(const struct rt6_info *rt)
408{
409 if (rt->rt6i_flags & RTF_EXPIRES)
410 return time_after(jiffies, rt->dst.expires);
411 else
412 return false;
413}
414
Eric Dumazeta50feda2012-05-18 18:57:34 +0000415static bool rt6_check_expired(const struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416{
David Aherna68886a2018-04-20 15:38:02 -0700417 struct fib6_info *from;
418
419 from = rcu_dereference(rt->from);
420
Gao feng1716a962012-04-06 00:13:10 +0000421 if (rt->rt6i_flags & RTF_EXPIRES) {
422 if (time_after(jiffies, rt->dst.expires))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000423 return true;
David Aherna68886a2018-04-20 15:38:02 -0700424 } else if (from) {
Xin Long1e2ea8a2017-08-26 20:10:10 +0800425 return rt->dst.obsolete != DST_OBSOLETE_FORCE_CHK ||
David Aherna68886a2018-04-20 15:38:02 -0700426 fib6_check_expired(from);
Gao feng1716a962012-04-06 00:13:10 +0000427 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000428 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429}
430
David Ahernb1d40992019-04-16 14:35:59 -0700431void fib6_select_path(const struct net *net, struct fib6_result *res,
432 struct flowi6 *fl6, int oif, bool have_oif_match,
433 const struct sk_buff *skb, int strict)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000434{
David Ahern8d1c8022018-04-17 17:33:26 -0700435 struct fib6_info *sibling, *next_sibling;
David Ahernb1d40992019-04-16 14:35:59 -0700436 struct fib6_info *match = res->f6i;
437
438 if (!match->fib6_nsiblings || have_oif_match)
439 goto out;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000440
Jakub Sitnickib673d6c2017-08-23 09:58:31 +0200441 /* We might have already computed the hash for ICMPv6 errors. In such
442 * case it will always be non-zero. Otherwise now is the time to do it.
443 */
444 if (!fl6->mp_hash)
David Ahernb4bac172018-03-02 08:32:18 -0800445 fl6->mp_hash = rt6_multipath_hash(net, fl6, skb, NULL);
Jakub Sitnickib673d6c2017-08-23 09:58:31 +0200446
David Ahernad1601a2019-03-27 20:53:56 -0700447 if (fl6->mp_hash <= atomic_read(&match->fib6_nh.fib_nh_upper_bound))
David Ahernb1d40992019-04-16 14:35:59 -0700448 goto out;
Ido Schimmelbbfcd772017-11-21 09:50:12 +0200449
David Ahern93c2fb22018-04-18 15:38:59 -0700450 list_for_each_entry_safe(sibling, next_sibling, &match->fib6_siblings,
451 fib6_siblings) {
David Ahern702cea52019-04-09 14:41:13 -0700452 const struct fib6_nh *nh = &sibling->fib6_nh;
David Ahern5e670d82018-04-17 17:33:14 -0700453 int nh_upper_bound;
454
David Ahern702cea52019-04-09 14:41:13 -0700455 nh_upper_bound = atomic_read(&nh->fib_nh_upper_bound);
David Ahern5e670d82018-04-17 17:33:14 -0700456 if (fl6->mp_hash > nh_upper_bound)
Ido Schimmel3d709f62018-01-09 16:40:27 +0200457 continue;
David Ahern702cea52019-04-09 14:41:13 -0700458 if (rt6_score_route(nh, sibling->fib6_flags, oif, strict) < 0)
Ido Schimmel3d709f62018-01-09 16:40:27 +0200459 break;
460 match = sibling;
461 break;
462 }
463
David Ahernb1d40992019-04-16 14:35:59 -0700464out:
465 res->f6i = match;
466 res->nh = &match->fib6_nh;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000467}
468
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469/*
Wei Wang66f5d6c2017-10-06 12:06:10 -0700470 * Route lookup. rcu_read_lock() should be held.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 */
472
David Ahern0c59d002019-04-09 14:41:18 -0700473static bool __rt6_device_match(struct net *net, const struct fib6_nh *nh,
474 const struct in6_addr *saddr, int oif, int flags)
475{
476 const struct net_device *dev;
477
478 if (nh->fib_nh_flags & RTNH_F_DEAD)
479 return false;
480
481 dev = nh->fib_nh_dev;
482 if (oif) {
483 if (dev->ifindex == oif)
484 return true;
485 } else {
486 if (ipv6_chk_addr(net, saddr, dev,
487 flags & RT6_LOOKUP_F_IFACE))
488 return true;
489 }
490
491 return false;
492}
493
David Ahern8d1c8022018-04-17 17:33:26 -0700494static inline struct fib6_info *rt6_device_match(struct net *net,
495 struct fib6_info *rt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000496 const struct in6_addr *saddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 int oif,
YOSHIFUJI Hideakid4208952008-06-27 20:14:54 -0700498 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499{
David Ahern0c59d002019-04-09 14:41:18 -0700500 const struct fib6_nh *nh;
David Ahern8d1c8022018-04-17 17:33:26 -0700501 struct fib6_info *sprt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
David Ahern5e670d82018-04-17 17:33:14 -0700503 if (!oif && ipv6_addr_any(saddr) &&
David Ahernad1601a2019-03-27 20:53:56 -0700504 !(rt->fib6_nh.fib_nh_flags & RTNH_F_DEAD))
Ido Schimmel8067bb82018-01-07 12:45:09 +0200505 return rt;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900506
David Ahern8fb11a92018-05-04 13:54:24 -0700507 for (sprt = rt; sprt; sprt = rcu_dereference(sprt->fib6_next)) {
David Ahern0c59d002019-04-09 14:41:18 -0700508 nh = &sprt->fib6_nh;
509 if (__rt6_device_match(net, nh, saddr, oif, flags))
510 return sprt;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900511 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
David Aherneea68cd2018-04-18 15:39:02 -0700513 if (oif && flags & RT6_LOOKUP_F_IFACE)
514 return net->ipv6.fib6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
David Ahernad1601a2019-03-27 20:53:56 -0700516 return rt->fib6_nh.fib_nh_flags & RTNH_F_DEAD ? net->ipv6.fib6_null_entry : rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517}
518
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800519#ifdef CONFIG_IPV6_ROUTER_PREF
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200520struct __rt6_probe_work {
521 struct work_struct work;
522 struct in6_addr target;
523 struct net_device *dev;
524};
525
526static void rt6_probe_deferred(struct work_struct *w)
527{
528 struct in6_addr mcaddr;
529 struct __rt6_probe_work *work =
530 container_of(w, struct __rt6_probe_work, work);
531
532 addrconf_addr_solict_mult(&work->target, &mcaddr);
Erik Nordmarkadc176c2016-12-02 14:00:08 -0800533 ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL, 0);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200534 dev_put(work->dev);
Michael Büsch662f5532015-02-08 10:14:07 +0100535 kfree(work);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200536}
537
David Aherncc3a86c2019-04-09 14:41:12 -0700538static void rt6_probe(struct fib6_nh *fib6_nh)
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800539{
Sabrina Dubrocaf547fac2018-10-12 16:22:47 +0200540 struct __rt6_probe_work *work = NULL;
David Ahern5e670d82018-04-17 17:33:14 -0700541 const struct in6_addr *nh_gw;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000542 struct neighbour *neigh;
David Ahern5e670d82018-04-17 17:33:14 -0700543 struct net_device *dev;
Sabrina Dubrocaf547fac2018-10-12 16:22:47 +0200544 struct inet6_dev *idev;
David Ahern5e670d82018-04-17 17:33:14 -0700545
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800546 /*
547 * Okay, this does not seem to be appropriate
548 * for now, however, we need to check if it
549 * is really so; aka Router Reachability Probing.
550 *
551 * Router Reachability Probe MUST be rate-limited
552 * to no more than one per minute.
553 */
David Aherncc3a86c2019-04-09 14:41:12 -0700554 if (fib6_nh->fib_nh_gw_family)
Amerigo Wangfdd66812012-09-10 02:48:44 +0000555 return;
David Ahern5e670d82018-04-17 17:33:14 -0700556
David Aherncc3a86c2019-04-09 14:41:12 -0700557 nh_gw = &fib6_nh->fib_nh_gw6;
558 dev = fib6_nh->fib_nh_dev;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000559 rcu_read_lock_bh();
Sabrina Dubrocaf547fac2018-10-12 16:22:47 +0200560 idev = __in6_dev_get(dev);
David Ahern5e670d82018-04-17 17:33:14 -0700561 neigh = __ipv6_neigh_lookup_noref(dev, nh_gw);
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000562 if (neigh) {
Martin KaFai Lau8d6c31b2015-07-24 09:57:43 -0700563 if (neigh->nud_state & NUD_VALID)
564 goto out;
565
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000566 write_lock(&neigh->lock);
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700567 if (!(neigh->nud_state & NUD_VALID) &&
568 time_after(jiffies,
David Aherndcd1f572018-04-18 15:39:05 -0700569 neigh->updated + idev->cnf.rtr_probe_interval)) {
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700570 work = kmalloc(sizeof(*work), GFP_ATOMIC);
571 if (work)
572 __neigh_set_probe_once(neigh);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200573 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000574 write_unlock(&neigh->lock);
David Aherncc3a86c2019-04-09 14:41:12 -0700575 } else if (time_after(jiffies, fib6_nh->last_probe +
Sabrina Dubrocaf547fac2018-10-12 16:22:47 +0200576 idev->cnf.rtr_probe_interval)) {
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700577 work = kmalloc(sizeof(*work), GFP_ATOMIC);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000578 }
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700579
580 if (work) {
David Aherncc3a86c2019-04-09 14:41:12 -0700581 fib6_nh->last_probe = jiffies;
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700582 INIT_WORK(&work->work, rt6_probe_deferred);
David Ahern5e670d82018-04-17 17:33:14 -0700583 work->target = *nh_gw;
584 dev_hold(dev);
585 work->dev = dev;
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700586 schedule_work(&work->work);
587 }
588
Martin KaFai Lau8d6c31b2015-07-24 09:57:43 -0700589out:
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000590 rcu_read_unlock_bh();
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800591}
592#else
David Aherncc3a86c2019-04-09 14:41:12 -0700593static inline void rt6_probe(struct fib6_nh *fib6_nh)
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800594{
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800595}
596#endif
597
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598/*
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800599 * Default Router Selection (RFC 2461 6.3.6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 */
David Ahern1ba9a892019-04-09 14:41:10 -0700601static enum rt6_nud_state rt6_check_neigh(const struct fib6_nh *fib6_nh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602{
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200603 enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
David Ahern5e670d82018-04-17 17:33:14 -0700604 struct neighbour *neigh;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000605
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000606 rcu_read_lock_bh();
David Ahern1ba9a892019-04-09 14:41:10 -0700607 neigh = __ipv6_neigh_lookup_noref(fib6_nh->fib_nh_dev,
608 &fib6_nh->fib_nh_gw6);
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000609 if (neigh) {
610 read_lock(&neigh->lock);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800611 if (neigh->nud_state & NUD_VALID)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200612 ret = RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800613#ifdef CONFIG_IPV6_ROUTER_PREF
Paul Marksa5a81f02012-12-03 10:26:54 +0000614 else if (!(neigh->nud_state & NUD_FAILED))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200615 ret = RT6_NUD_SUCCEED;
Jiri Benc7e980562013-12-11 13:48:20 +0100616 else
617 ret = RT6_NUD_FAIL_PROBE;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800618#endif
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000619 read_unlock(&neigh->lock);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200620 } else {
621 ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
Jiri Benc7e980562013-12-11 13:48:20 +0100622 RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR;
Paul Marksa5a81f02012-12-03 10:26:54 +0000623 }
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000624 rcu_read_unlock_bh();
625
Paul Marksa5a81f02012-12-03 10:26:54 +0000626 return ret;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800627}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
David Ahern702cea52019-04-09 14:41:13 -0700629static int rt6_score_route(const struct fib6_nh *nh, u32 fib6_flags, int oif,
630 int strict)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800631{
David Ahern6e1809a2019-04-09 14:41:11 -0700632 int m = 0;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900633
David Ahern6e1809a2019-04-09 14:41:11 -0700634 if (!oif || nh->fib_nh_dev->ifindex == oif)
635 m = 2;
636
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700637 if (!m && (strict & RT6_LOOKUP_F_IFACE))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200638 return RT6_NUD_FAIL_HARD;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800639#ifdef CONFIG_IPV6_ROUTER_PREF
David Ahern702cea52019-04-09 14:41:13 -0700640 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(fib6_flags)) << 2;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800641#endif
David Ahern1ba9a892019-04-09 14:41:10 -0700642 if ((strict & RT6_LOOKUP_F_REACHABLE) &&
David Ahern702cea52019-04-09 14:41:13 -0700643 !(fib6_flags & RTF_NONEXTHOP) && nh->fib_nh_gw_family) {
David Ahern1ba9a892019-04-09 14:41:10 -0700644 int n = rt6_check_neigh(nh);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200645 if (n < 0)
646 return n;
647 }
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800648 return m;
649}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
David Ahern28679ed2019-04-09 14:41:14 -0700651static bool find_match(struct fib6_nh *nh, u32 fib6_flags,
652 int oif, int strict, int *mpri, bool *do_rr)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800653{
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200654 bool match_do_rr = false;
David Ahern28679ed2019-04-09 14:41:14 -0700655 bool rc = false;
656 int m;
Andy Gospodarek35103d12015-08-13 10:39:01 -0400657
David Ahern28679ed2019-04-09 14:41:14 -0700658 if (nh->fib_nh_flags & RTNH_F_DEAD)
Ido Schimmel8067bb82018-01-07 12:45:09 +0200659 goto out;
660
David Ahern28679ed2019-04-09 14:41:14 -0700661 if (ip6_ignore_linkdown(nh->fib_nh_dev) &&
662 nh->fib_nh_flags & RTNH_F_LINKDOWN &&
David Ahernd5d32e42016-10-24 12:27:23 -0700663 !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE))
Andy Gospodarek35103d12015-08-13 10:39:01 -0400664 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700665
David Ahern28679ed2019-04-09 14:41:14 -0700666 m = rt6_score_route(nh, fib6_flags, oif, strict);
Jiri Benc7e980562013-12-11 13:48:20 +0100667 if (m == RT6_NUD_FAIL_DO_RR) {
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200668 match_do_rr = true;
669 m = 0; /* lowest valid score */
Jiri Benc7e980562013-12-11 13:48:20 +0100670 } else if (m == RT6_NUD_FAIL_HARD) {
David S. Millerf11e6652007-03-24 20:36:25 -0700671 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700672 }
673
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200674 if (strict & RT6_LOOKUP_F_REACHABLE)
David Ahern28679ed2019-04-09 14:41:14 -0700675 rt6_probe(nh);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200676
Jiri Benc7e980562013-12-11 13:48:20 +0100677 /* note that m can be RT6_NUD_FAIL_PROBE at this point */
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200678 if (m > *mpri) {
679 *do_rr = match_do_rr;
680 *mpri = m;
David Ahern28679ed2019-04-09 14:41:14 -0700681 rc = true;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200682 }
David S. Millerf11e6652007-03-24 20:36:25 -0700683out:
David Ahern28679ed2019-04-09 14:41:14 -0700684 return rc;
David S. Millerf11e6652007-03-24 20:36:25 -0700685}
686
David Ahern30c15f02019-04-09 14:41:15 -0700687static void __find_rr_leaf(struct fib6_info *rt_start,
688 struct fib6_info *nomatch, u32 metric,
689 struct fib6_info **match, struct fib6_info **cont,
690 int oif, int strict, bool *do_rr, int *mpri)
David S. Millerf11e6652007-03-24 20:36:25 -0700691{
David Ahern30c15f02019-04-09 14:41:15 -0700692 struct fib6_info *rt;
693
694 for (rt = rt_start;
695 rt && rt != nomatch;
696 rt = rcu_dereference(rt->fib6_next)) {
697 struct fib6_nh *nh;
698
699 if (cont && rt->fib6_metric != metric) {
700 *cont = rt;
701 return;
702 }
703
704 if (fib6_check_expired(rt))
705 continue;
706
707 nh = &rt->fib6_nh;
708 if (find_match(nh, rt->fib6_flags, oif, strict, mpri, do_rr))
709 *match = rt;
710 }
711}
712
713static struct fib6_info *find_rr_leaf(struct fib6_node *fn,
714 struct fib6_info *leaf,
715 struct fib6_info *rr_head,
716 u32 metric, int oif, int strict,
717 bool *do_rr)
718{
719 struct fib6_info *match = NULL, *cont = NULL;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800720 int mpri = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
David Ahern30c15f02019-04-09 14:41:15 -0700722 __find_rr_leaf(rr_head, NULL, metric, &match, &cont,
723 oif, strict, do_rr, &mpri);
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700724
David Ahern30c15f02019-04-09 14:41:15 -0700725 __find_rr_leaf(leaf, rr_head, metric, &match, &cont,
726 oif, strict, do_rr, &mpri);
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700727
728 if (match || !cont)
729 return match;
730
David Ahern30c15f02019-04-09 14:41:15 -0700731 __find_rr_leaf(cont, NULL, metric, &match, NULL,
732 oif, strict, do_rr, &mpri);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800733
David S. Millerf11e6652007-03-24 20:36:25 -0700734 return match;
735}
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800736
David Ahern8d1c8022018-04-17 17:33:26 -0700737static struct fib6_info *rt6_select(struct net *net, struct fib6_node *fn,
Wei Wang8d1040e2017-10-06 12:06:08 -0700738 int oif, int strict)
David S. Millerf11e6652007-03-24 20:36:25 -0700739{
David Ahern8d1c8022018-04-17 17:33:26 -0700740 struct fib6_info *leaf = rcu_dereference(fn->leaf);
741 struct fib6_info *match, *rt0;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200742 bool do_rr = false;
Wei Wang17ecf592017-10-06 12:06:09 -0700743 int key_plen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744
David Ahern421842e2018-04-17 17:33:18 -0700745 if (!leaf || leaf == net->ipv6.fib6_null_entry)
746 return net->ipv6.fib6_null_entry;
Wei Wang8d1040e2017-10-06 12:06:08 -0700747
Wei Wang66f5d6c2017-10-06 12:06:10 -0700748 rt0 = rcu_dereference(fn->rr_ptr);
David S. Millerf11e6652007-03-24 20:36:25 -0700749 if (!rt0)
Wei Wang66f5d6c2017-10-06 12:06:10 -0700750 rt0 = leaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751
Wei Wang17ecf592017-10-06 12:06:09 -0700752 /* Double check to make sure fn is not an intermediate node
753 * and fn->leaf does not points to its child's leaf
754 * (This might happen if all routes under fn are deleted from
755 * the tree and fib6_repair_tree() is called on the node.)
756 */
David Ahern93c2fb22018-04-18 15:38:59 -0700757 key_plen = rt0->fib6_dst.plen;
Wei Wang17ecf592017-10-06 12:06:09 -0700758#ifdef CONFIG_IPV6_SUBTREES
David Ahern93c2fb22018-04-18 15:38:59 -0700759 if (rt0->fib6_src.plen)
760 key_plen = rt0->fib6_src.plen;
Wei Wang17ecf592017-10-06 12:06:09 -0700761#endif
762 if (fn->fn_bit != key_plen)
David Ahern421842e2018-04-17 17:33:18 -0700763 return net->ipv6.fib6_null_entry;
Wei Wang17ecf592017-10-06 12:06:09 -0700764
David Ahern93c2fb22018-04-18 15:38:59 -0700765 match = find_rr_leaf(fn, leaf, rt0, rt0->fib6_metric, oif, strict,
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200766 &do_rr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200768 if (do_rr) {
David Ahern8fb11a92018-05-04 13:54:24 -0700769 struct fib6_info *next = rcu_dereference(rt0->fib6_next);
David S. Millerf11e6652007-03-24 20:36:25 -0700770
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800771 /* no entries matched; do round-robin */
David Ahern93c2fb22018-04-18 15:38:59 -0700772 if (!next || next->fib6_metric != rt0->fib6_metric)
Wei Wang8d1040e2017-10-06 12:06:08 -0700773 next = leaf;
David S. Millerf11e6652007-03-24 20:36:25 -0700774
Wei Wang66f5d6c2017-10-06 12:06:10 -0700775 if (next != rt0) {
David Ahern93c2fb22018-04-18 15:38:59 -0700776 spin_lock_bh(&leaf->fib6_table->tb6_lock);
Wei Wang66f5d6c2017-10-06 12:06:10 -0700777 /* make sure next is not being deleted from the tree */
David Ahern93c2fb22018-04-18 15:38:59 -0700778 if (next->fib6_node)
Wei Wang66f5d6c2017-10-06 12:06:10 -0700779 rcu_assign_pointer(fn->rr_ptr, next);
David Ahern93c2fb22018-04-18 15:38:59 -0700780 spin_unlock_bh(&leaf->fib6_table->tb6_lock);
Wei Wang66f5d6c2017-10-06 12:06:10 -0700781 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 }
783
David Ahern421842e2018-04-17 17:33:18 -0700784 return match ? match : net->ipv6.fib6_null_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785}
786
David Ahern8d1c8022018-04-17 17:33:26 -0700787static bool rt6_is_gw_or_nonexthop(const struct fib6_info *rt)
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700788{
David Ahernbdf00462019-04-05 16:30:26 -0700789 return (rt->fib6_flags & RTF_NONEXTHOP) || rt->fib6_nh.fib_nh_gw_family;
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700790}
791
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800792#ifdef CONFIG_IPV6_ROUTE_INFO
793int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000794 const struct in6_addr *gwaddr)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800795{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900796 struct net *net = dev_net(dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800797 struct route_info *rinfo = (struct route_info *) opt;
798 struct in6_addr prefix_buf, *prefix;
799 unsigned int pref;
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900800 unsigned long lifetime;
David Ahern8d1c8022018-04-17 17:33:26 -0700801 struct fib6_info *rt;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800802
803 if (len < sizeof(struct route_info)) {
804 return -EINVAL;
805 }
806
807 /* Sanity check for prefix_len and length */
808 if (rinfo->length > 3) {
809 return -EINVAL;
810 } else if (rinfo->prefix_len > 128) {
811 return -EINVAL;
812 } else if (rinfo->prefix_len > 64) {
813 if (rinfo->length < 2) {
814 return -EINVAL;
815 }
816 } else if (rinfo->prefix_len > 0) {
817 if (rinfo->length < 1) {
818 return -EINVAL;
819 }
820 }
821
822 pref = rinfo->route_pref;
823 if (pref == ICMPV6_ROUTER_PREF_INVALID)
Jens Rosenboom3933fc92009-09-10 06:25:11 +0000824 return -EINVAL;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800825
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900826 lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800827
828 if (rinfo->length == 3)
829 prefix = (struct in6_addr *)rinfo->prefix;
830 else {
831 /* this function is safe */
832 ipv6_addr_prefix(&prefix_buf,
833 (struct in6_addr *)rinfo->prefix,
834 rinfo->prefix_len);
835 prefix = &prefix_buf;
836 }
837
Duan Jiongf104a562013-11-08 09:56:53 +0800838 if (rinfo->prefix_len == 0)
David Ahernafb1d4b52018-04-17 17:33:11 -0700839 rt = rt6_get_dflt_router(net, gwaddr, dev);
Duan Jiongf104a562013-11-08 09:56:53 +0800840 else
841 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len,
David Ahern830218c2016-10-24 10:52:35 -0700842 gwaddr, dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800843
844 if (rt && !lifetime) {
David Ahernafb1d4b52018-04-17 17:33:11 -0700845 ip6_del_rt(net, rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800846 rt = NULL;
847 }
848
849 if (!rt && lifetime)
David Ahern830218c2016-10-24 10:52:35 -0700850 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr,
851 dev, pref);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800852 else if (rt)
David Ahern93c2fb22018-04-18 15:38:59 -0700853 rt->fib6_flags = RTF_ROUTEINFO |
854 (rt->fib6_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800855
856 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +0000857 if (!addrconf_finite_timeout(lifetime))
David Ahern14895682018-04-17 17:33:17 -0700858 fib6_clean_expires(rt);
Gao feng1716a962012-04-06 00:13:10 +0000859 else
David Ahern14895682018-04-17 17:33:17 -0700860 fib6_set_expires(rt, jiffies + HZ * lifetime);
Gao feng1716a962012-04-06 00:13:10 +0000861
David Ahern93531c62018-04-17 17:33:25 -0700862 fib6_info_release(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800863 }
864 return 0;
865}
866#endif
867
David Ahernae90d862018-04-17 17:33:12 -0700868/*
869 * Misc support functions
870 */
871
872/* called with rcu_lock held */
David Ahern8d1c8022018-04-17 17:33:26 -0700873static struct net_device *ip6_rt_get_dev_rcu(struct fib6_info *rt)
David Ahernae90d862018-04-17 17:33:12 -0700874{
David Ahernad1601a2019-03-27 20:53:56 -0700875 struct net_device *dev = rt->fib6_nh.fib_nh_dev;
David Ahernae90d862018-04-17 17:33:12 -0700876
David Ahern93c2fb22018-04-18 15:38:59 -0700877 if (rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) {
David Ahernae90d862018-04-17 17:33:12 -0700878 /* for copies of local routes, dst->dev needs to be the
879 * device if it is a master device, the master device if
880 * device is enslaved, and the loopback as the default
881 */
882 if (netif_is_l3_slave(dev) &&
David Ahern93c2fb22018-04-18 15:38:59 -0700883 !rt6_need_strict(&rt->fib6_dst.addr))
David Ahernae90d862018-04-17 17:33:12 -0700884 dev = l3mdev_master_dev_rcu(dev);
885 else if (!netif_is_l3_master(dev))
886 dev = dev_net(dev)->loopback_dev;
887 /* last case is netif_is_l3_master(dev) is true in which
888 * case we want dev returned to be dev
889 */
890 }
891
892 return dev;
893}
894
David Ahern6edb3c92018-04-17 17:33:15 -0700895static const int fib6_prop[RTN_MAX + 1] = {
896 [RTN_UNSPEC] = 0,
897 [RTN_UNICAST] = 0,
898 [RTN_LOCAL] = 0,
899 [RTN_BROADCAST] = 0,
900 [RTN_ANYCAST] = 0,
901 [RTN_MULTICAST] = 0,
902 [RTN_BLACKHOLE] = -EINVAL,
903 [RTN_UNREACHABLE] = -EHOSTUNREACH,
904 [RTN_PROHIBIT] = -EACCES,
905 [RTN_THROW] = -EAGAIN,
906 [RTN_NAT] = -EINVAL,
907 [RTN_XRESOLVE] = -EINVAL,
908};
909
910static int ip6_rt_type_to_error(u8 fib6_type)
911{
912 return fib6_prop[fib6_type];
913}
914
David Ahern8d1c8022018-04-17 17:33:26 -0700915static unsigned short fib6_info_dst_flags(struct fib6_info *rt)
David Ahern3b6761d2018-04-17 17:33:20 -0700916{
917 unsigned short flags = 0;
918
919 if (rt->dst_nocount)
920 flags |= DST_NOCOUNT;
921 if (rt->dst_nopolicy)
922 flags |= DST_NOPOLICY;
923 if (rt->dst_host)
924 flags |= DST_HOST;
925
926 return flags;
927}
928
David Ahern8d1c8022018-04-17 17:33:26 -0700929static void ip6_rt_init_dst_reject(struct rt6_info *rt, struct fib6_info *ort)
David Ahern6edb3c92018-04-17 17:33:15 -0700930{
931 rt->dst.error = ip6_rt_type_to_error(ort->fib6_type);
932
933 switch (ort->fib6_type) {
934 case RTN_BLACKHOLE:
935 rt->dst.output = dst_discard_out;
936 rt->dst.input = dst_discard;
937 break;
938 case RTN_PROHIBIT:
939 rt->dst.output = ip6_pkt_prohibit_out;
940 rt->dst.input = ip6_pkt_prohibit;
941 break;
942 case RTN_THROW:
943 case RTN_UNREACHABLE:
944 default:
945 rt->dst.output = ip6_pkt_discard_out;
946 rt->dst.input = ip6_pkt_discard;
947 break;
948 }
949}
950
David Ahern8d1c8022018-04-17 17:33:26 -0700951static void ip6_rt_init_dst(struct rt6_info *rt, struct fib6_info *ort)
David Ahern6edb3c92018-04-17 17:33:15 -0700952{
David Ahern93c2fb22018-04-18 15:38:59 -0700953 if (ort->fib6_flags & RTF_REJECT) {
David Ahern6edb3c92018-04-17 17:33:15 -0700954 ip6_rt_init_dst_reject(rt, ort);
955 return;
956 }
957
958 rt->dst.error = 0;
959 rt->dst.output = ip6_output;
960
Hangbin Liud23c4b62018-08-23 11:31:37 +0800961 if (ort->fib6_type == RTN_LOCAL || ort->fib6_type == RTN_ANYCAST) {
David Ahern6edb3c92018-04-17 17:33:15 -0700962 rt->dst.input = ip6_input;
David Ahern93c2fb22018-04-18 15:38:59 -0700963 } else if (ipv6_addr_type(&ort->fib6_dst.addr) & IPV6_ADDR_MULTICAST) {
David Ahern6edb3c92018-04-17 17:33:15 -0700964 rt->dst.input = ip6_mc_input;
965 } else {
966 rt->dst.input = ip6_forward;
967 }
968
David Ahernad1601a2019-03-27 20:53:56 -0700969 if (ort->fib6_nh.fib_nh_lws) {
970 rt->dst.lwtstate = lwtstate_get(ort->fib6_nh.fib_nh_lws);
David Ahern6edb3c92018-04-17 17:33:15 -0700971 lwtunnel_set_redirect(&rt->dst);
972 }
973
974 rt->dst.lastuse = jiffies;
975}
976
Wei Wange873e4b2018-07-21 20:56:32 -0700977/* Caller must already hold reference to @from */
David Ahern8d1c8022018-04-17 17:33:26 -0700978static void rt6_set_from(struct rt6_info *rt, struct fib6_info *from)
David Ahernae90d862018-04-17 17:33:12 -0700979{
David Ahernae90d862018-04-17 17:33:12 -0700980 rt->rt6i_flags &= ~RTF_EXPIRES;
David Aherna68886a2018-04-20 15:38:02 -0700981 rcu_assign_pointer(rt->from, from);
David Aherne1255ed2018-10-04 20:07:53 -0700982 ip_dst_init_metrics(&rt->dst, from->fib6_metrics);
David Ahernae90d862018-04-17 17:33:12 -0700983}
984
Wei Wange873e4b2018-07-21 20:56:32 -0700985/* Caller must already hold reference to @ort */
David Ahern8d1c8022018-04-17 17:33:26 -0700986static void ip6_rt_copy_init(struct rt6_info *rt, struct fib6_info *ort)
David Ahernae90d862018-04-17 17:33:12 -0700987{
David Aherndcd1f572018-04-18 15:39:05 -0700988 struct net_device *dev = fib6_info_nh_dev(ort);
989
David Ahern6edb3c92018-04-17 17:33:15 -0700990 ip6_rt_init_dst(rt, ort);
991
David Ahern93c2fb22018-04-18 15:38:59 -0700992 rt->rt6i_dst = ort->fib6_dst;
David Aherndcd1f572018-04-18 15:39:05 -0700993 rt->rt6i_idev = dev ? in6_dev_get(dev) : NULL;
David Ahern93c2fb22018-04-18 15:38:59 -0700994 rt->rt6i_flags = ort->fib6_flags;
David Ahernbdf00462019-04-05 16:30:26 -0700995 if (ort->fib6_nh.fib_nh_gw_family) {
David Ahernad1601a2019-03-27 20:53:56 -0700996 rt->rt6i_gateway = ort->fib6_nh.fib_nh_gw6;
David Ahern2b2450c2019-03-27 20:53:52 -0700997 rt->rt6i_flags |= RTF_GATEWAY;
998 }
David Ahernae90d862018-04-17 17:33:12 -0700999 rt6_set_from(rt, ort);
David Ahernae90d862018-04-17 17:33:12 -07001000#ifdef CONFIG_IPV6_SUBTREES
David Ahern93c2fb22018-04-18 15:38:59 -07001001 rt->rt6i_src = ort->fib6_src;
David Ahernae90d862018-04-17 17:33:12 -07001002#endif
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
David Ahern10585b42019-03-20 09:24:50 -07001023static bool ip6_hold_safe(struct net *net, struct rt6_info **prt)
Wei Wangd3843fe2017-10-06 12:06:06 -07001024{
1025 struct rt6_info *rt = *prt;
1026
1027 if (dst_hold_safe(&rt->dst))
1028 return true;
David Ahern10585b42019-03-20 09:24:50 -07001029 if (net) {
Wei Wangd3843fe2017-10-06 12:06:06 -07001030 rt = net->ipv6.ip6_null_entry;
1031 dst_hold(&rt->dst);
1032 } else {
1033 rt = NULL;
1034 }
1035 *prt = rt;
1036 return false;
1037}
1038
David Aherndec9b0e2018-04-17 17:33:19 -07001039/* called with rcu_lock held */
David Ahern8d1c8022018-04-17 17:33:26 -07001040static struct rt6_info *ip6_create_rt_rcu(struct fib6_info *rt)
David Aherndec9b0e2018-04-17 17:33:19 -07001041{
David Ahern3b6761d2018-04-17 17:33:20 -07001042 unsigned short flags = fib6_info_dst_flags(rt);
David Ahernad1601a2019-03-27 20:53:56 -07001043 struct net_device *dev = rt->fib6_nh.fib_nh_dev;
David Aherndec9b0e2018-04-17 17:33:19 -07001044 struct rt6_info *nrt;
1045
Wei Wange873e4b2018-07-21 20:56:32 -07001046 if (!fib6_info_hold_safe(rt))
Xin Long1c87e792019-03-20 14:45:48 +08001047 goto fallback;
Wei Wange873e4b2018-07-21 20:56:32 -07001048
David Ahern93531c62018-04-17 17:33:25 -07001049 nrt = ip6_dst_alloc(dev_net(dev), dev, flags);
Xin Long1c87e792019-03-20 14:45:48 +08001050 if (!nrt) {
Wei Wange873e4b2018-07-21 20:56:32 -07001051 fib6_info_release(rt);
Xin Long1c87e792019-03-20 14:45:48 +08001052 goto fallback;
1053 }
David Aherndec9b0e2018-04-17 17:33:19 -07001054
Xin Long1c87e792019-03-20 14:45:48 +08001055 ip6_rt_copy_init(nrt, rt);
1056 return nrt;
1057
1058fallback:
1059 nrt = dev_net(dev)->ipv6.ip6_null_entry;
1060 dst_hold(&nrt->dst);
David Aherndec9b0e2018-04-17 17:33:19 -07001061 return nrt;
1062}
1063
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001064static struct rt6_info *ip6_pol_route_lookup(struct net *net,
1065 struct fib6_table *table,
David Ahernb75cc8f2018-03-02 08:32:17 -08001066 struct flowi6 *fl6,
1067 const struct sk_buff *skb,
1068 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069{
David Ahernb1d40992019-04-16 14:35:59 -07001070 struct fib6_result res = {};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 struct fib6_node *fn;
David Ahern23fb93a2018-04-17 17:33:23 -07001072 struct rt6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073
David Ahernb6cdbc82018-03-29 17:44:57 -07001074 if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
1075 flags &= ~RT6_LOOKUP_F_IFACE;
1076
Wei Wang66f5d6c2017-10-06 12:06:10 -07001077 rcu_read_lock();
David Ahern64547432018-05-09 20:34:19 -07001078 fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -07001079restart:
David Ahernb1d40992019-04-16 14:35:59 -07001080 res.f6i = rcu_dereference(fn->leaf);
1081 if (!res.f6i)
1082 res.f6i = net->ipv6.fib6_null_entry;
David Ahernaf52a522019-04-09 14:41:16 -07001083 else
David Ahernb1d40992019-04-16 14:35:59 -07001084 res.f6i = rt6_device_match(net, res.f6i, &fl6->saddr,
1085 fl6->flowi6_oif, flags);
David Ahernaf52a522019-04-09 14:41:16 -07001086
David Ahernb1d40992019-04-16 14:35:59 -07001087 if (res.f6i == net->ipv6.fib6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001088 fn = fib6_backtrack(fn, &fl6->saddr);
1089 if (fn)
1090 goto restart;
David Ahernaf52a522019-04-09 14:41:16 -07001091
1092 rt = net->ipv6.ip6_null_entry;
1093 dst_hold(&rt->dst);
1094 goto out;
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001095 }
Wei Wang2b760fc2017-10-06 12:06:03 -07001096
David Ahernb1d40992019-04-16 14:35:59 -07001097 fib6_select_path(net, &res, fl6, fl6->flowi6_oif,
1098 fl6->flowi6_oif != 0, skb, flags);
1099
David S. Miller4c9483b2011-03-12 16:22:43 -05001100 /* Search through exception table */
David Ahern7e4b5122019-04-16 14:36:00 -07001101 rt = rt6_find_cached_rt(&res, &fl6->daddr, &fl6->saddr);
David Ahern23fb93a2018-04-17 17:33:23 -07001102 if (rt) {
David Ahern10585b42019-03-20 09:24:50 -07001103 if (ip6_hold_safe(net, &rt))
David Aherndec9b0e2018-04-17 17:33:19 -07001104 dst_use_noref(&rt->dst, jiffies);
David Ahern23fb93a2018-04-17 17:33:23 -07001105 } else {
David Ahernb1d40992019-04-16 14:35:59 -07001106 rt = ip6_create_rt_rcu(res.f6i);
David Aherndec9b0e2018-04-17 17:33:19 -07001107 }
Wei Wangd3843fe2017-10-06 12:06:06 -07001108
David Ahernaf52a522019-04-09 14:41:16 -07001109out:
David Ahernb1d40992019-04-16 14:35:59 -07001110 trace_fib6_table_lookup(net, res.f6i, table, fl6);
David Ahernaf52a522019-04-09 14:41:16 -07001111
Wei Wang66f5d6c2017-10-06 12:06:10 -07001112 rcu_read_unlock();
David Ahernb8115802015-11-19 12:24:22 -08001113
Thomas Grafc71099a2006-08-04 23:20:06 -07001114 return rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001115}
1116
Ian Morris67ba4152014-08-24 21:53:10 +01001117struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
David Ahernb75cc8f2018-03-02 08:32:17 -08001118 const struct sk_buff *skb, int flags)
Florian Westphalea6e5742011-09-05 16:05:44 +02001119{
David Ahernb75cc8f2018-03-02 08:32:17 -08001120 return fib6_rule_lookup(net, fl6, skb, flags, ip6_pol_route_lookup);
Florian Westphalea6e5742011-09-05 16:05:44 +02001121}
1122EXPORT_SYMBOL_GPL(ip6_route_lookup);
1123
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +09001124struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
David Ahernb75cc8f2018-03-02 08:32:17 -08001125 const struct in6_addr *saddr, int oif,
1126 const struct sk_buff *skb, int strict)
Thomas Grafc71099a2006-08-04 23:20:06 -07001127{
David S. Miller4c9483b2011-03-12 16:22:43 -05001128 struct flowi6 fl6 = {
1129 .flowi6_oif = oif,
1130 .daddr = *daddr,
Thomas Grafc71099a2006-08-04 23:20:06 -07001131 };
1132 struct dst_entry *dst;
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001133 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07001134
Thomas Grafadaa70b2006-10-13 15:01:03 -07001135 if (saddr) {
David S. Miller4c9483b2011-03-12 16:22:43 -05001136 memcpy(&fl6.saddr, saddr, sizeof(*saddr));
Thomas Grafadaa70b2006-10-13 15:01:03 -07001137 flags |= RT6_LOOKUP_F_HAS_SADDR;
1138 }
1139
David Ahernb75cc8f2018-03-02 08:32:17 -08001140 dst = fib6_rule_lookup(net, &fl6, skb, flags, ip6_pol_route_lookup);
Thomas Grafc71099a2006-08-04 23:20:06 -07001141 if (dst->error == 0)
1142 return (struct rt6_info *) dst;
1143
1144 dst_release(dst);
1145
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 return NULL;
1147}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +09001148EXPORT_SYMBOL(rt6_lookup);
1149
Thomas Grafc71099a2006-08-04 23:20:06 -07001150/* ip6_ins_rt is called with FREE table->tb6_lock.
Wei Wang1cfb71e2017-06-17 10:42:33 -07001151 * It takes new route entry, the addition fails by any reason the
1152 * route is released.
1153 * Caller must hold dst before calling it.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 */
1155
David Ahern8d1c8022018-04-17 17:33:26 -07001156static int __ip6_ins_rt(struct fib6_info *rt, struct nl_info *info,
David Ahern333c4302017-05-21 10:12:04 -06001157 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158{
1159 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07001160 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161
David Ahern93c2fb22018-04-18 15:38:59 -07001162 table = rt->fib6_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07001163 spin_lock_bh(&table->tb6_lock);
David Ahernd4ead6b2018-04-17 17:33:16 -07001164 err = fib6_add(&table->tb6_root, rt, info, extack);
Wei Wang66f5d6c2017-10-06 12:06:10 -07001165 spin_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166
1167 return err;
1168}
1169
David Ahern8d1c8022018-04-17 17:33:26 -07001170int ip6_ins_rt(struct net *net, struct fib6_info *rt)
Thomas Graf40e22e82006-08-22 00:00:45 -07001171{
David Ahernafb1d4b52018-04-17 17:33:11 -07001172 struct nl_info info = { .nl_net = net, };
Florian Westphale715b6d2015-01-05 23:57:44 +01001173
David Ahernd4ead6b2018-04-17 17:33:16 -07001174 return __ip6_ins_rt(rt, &info, NULL);
Thomas Graf40e22e82006-08-22 00:00:45 -07001175}
1176
David Ahern8d1c8022018-04-17 17:33:26 -07001177static struct rt6_info *ip6_rt_cache_alloc(struct fib6_info *ort,
Martin KaFai Lau8b9df262015-05-22 20:55:59 -07001178 const struct in6_addr *daddr,
1179 const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180{
David Ahern4832c302017-08-17 12:17:20 -07001181 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 struct rt6_info *rt;
1183
1184 /*
1185 * Clone the route.
1186 */
1187
Wei Wange873e4b2018-07-21 20:56:32 -07001188 if (!fib6_info_hold_safe(ort))
1189 return NULL;
1190
David Ahern4832c302017-08-17 12:17:20 -07001191 dev = ip6_rt_get_dev_rcu(ort);
David Ahern93531c62018-04-17 17:33:25 -07001192 rt = ip6_dst_alloc(dev_net(dev), dev, 0);
Wei Wange873e4b2018-07-21 20:56:32 -07001193 if (!rt) {
1194 fib6_info_release(ort);
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001195 return NULL;
Wei Wange873e4b2018-07-21 20:56:32 -07001196 }
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001197
1198 ip6_rt_copy_init(rt, ort);
1199 rt->rt6i_flags |= RTF_CACHE;
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001200 rt->dst.flags |= DST_HOST;
1201 rt->rt6i_dst.addr = *daddr;
1202 rt->rt6i_dst.plen = 128;
1203
1204 if (!rt6_is_gw_or_nonexthop(ort)) {
David Ahern93c2fb22018-04-18 15:38:59 -07001205 if (ort->fib6_dst.plen != 128 &&
1206 ipv6_addr_equal(&ort->fib6_dst.addr, daddr))
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001207 rt->rt6i_flags |= RTF_ANYCAST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001209 if (rt->rt6i_src.plen && saddr) {
1210 rt->rt6i_src.addr = *saddr;
1211 rt->rt6i_src.plen = 128;
Martin KaFai Lau8b9df262015-05-22 20:55:59 -07001212 }
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001213#endif
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -08001214 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -08001216 return rt;
1217}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
David Ahern8d1c8022018-04-17 17:33:26 -07001219static struct rt6_info *ip6_rt_pcpu_alloc(struct fib6_info *rt)
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001220{
David Ahern3b6761d2018-04-17 17:33:20 -07001221 unsigned short flags = fib6_info_dst_flags(rt);
David Ahern4832c302017-08-17 12:17:20 -07001222 struct net_device *dev;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001223 struct rt6_info *pcpu_rt;
1224
Wei Wange873e4b2018-07-21 20:56:32 -07001225 if (!fib6_info_hold_safe(rt))
1226 return NULL;
1227
David Ahern4832c302017-08-17 12:17:20 -07001228 rcu_read_lock();
1229 dev = ip6_rt_get_dev_rcu(rt);
David Ahern93531c62018-04-17 17:33:25 -07001230 pcpu_rt = ip6_dst_alloc(dev_net(dev), dev, flags);
David Ahern4832c302017-08-17 12:17:20 -07001231 rcu_read_unlock();
Wei Wange873e4b2018-07-21 20:56:32 -07001232 if (!pcpu_rt) {
1233 fib6_info_release(rt);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001234 return NULL;
Wei Wange873e4b2018-07-21 20:56:32 -07001235 }
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001236 ip6_rt_copy_init(pcpu_rt, rt);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001237 pcpu_rt->rt6i_flags |= RTF_PCPU;
1238 return pcpu_rt;
1239}
1240
Wei Wang66f5d6c2017-10-06 12:06:10 -07001241/* It should be called with rcu_read_lock() acquired */
David Ahern8d1c8022018-04-17 17:33:26 -07001242static struct rt6_info *rt6_get_pcpu_route(struct fib6_info *rt)
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001243{
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001244 struct rt6_info *pcpu_rt, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001245
1246 p = this_cpu_ptr(rt->rt6i_pcpu);
1247 pcpu_rt = *p;
1248
David Ahernd4ead6b2018-04-17 17:33:16 -07001249 if (pcpu_rt)
David Ahern10585b42019-03-20 09:24:50 -07001250 ip6_hold_safe(NULL, &pcpu_rt);
Wei Wangd3843fe2017-10-06 12:06:06 -07001251
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001252 return pcpu_rt;
1253}
1254
David Ahernafb1d4b52018-04-17 17:33:11 -07001255static struct rt6_info *rt6_make_pcpu_route(struct net *net,
David Ahern8d1c8022018-04-17 17:33:26 -07001256 struct fib6_info *rt)
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001257{
1258 struct rt6_info *pcpu_rt, *prev, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001259
1260 pcpu_rt = ip6_rt_pcpu_alloc(rt);
1261 if (!pcpu_rt) {
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001262 dst_hold(&net->ipv6.ip6_null_entry->dst);
1263 return net->ipv6.ip6_null_entry;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001264 }
1265
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001266 dst_hold(&pcpu_rt->dst);
Wei Wanga94b9362017-10-06 12:06:04 -07001267 p = this_cpu_ptr(rt->rt6i_pcpu);
1268 prev = cmpxchg(p, NULL, pcpu_rt);
Eric Dumazet951f7882017-10-08 21:07:18 -07001269 BUG_ON(prev);
Wei Wanga94b9362017-10-06 12:06:04 -07001270
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001271 return pcpu_rt;
1272}
1273
Wei Wang35732d02017-10-06 12:05:57 -07001274/* exception hash table implementation
1275 */
1276static DEFINE_SPINLOCK(rt6_exception_lock);
1277
1278/* Remove rt6_ex from hash table and free the memory
1279 * Caller must hold rt6_exception_lock
1280 */
1281static void rt6_remove_exception(struct rt6_exception_bucket *bucket,
1282 struct rt6_exception *rt6_ex)
1283{
Paolo Abenif5b51fe2019-02-20 18:18:12 +01001284 struct fib6_info *from;
Colin Ian Kingb2427e62017-10-10 18:01:16 +01001285 struct net *net;
Wei Wang81eb8442017-10-06 12:06:11 -07001286
Wei Wang35732d02017-10-06 12:05:57 -07001287 if (!bucket || !rt6_ex)
1288 return;
Colin Ian Kingb2427e62017-10-10 18:01:16 +01001289
1290 net = dev_net(rt6_ex->rt6i->dst.dev);
Paolo Abenif5b51fe2019-02-20 18:18:12 +01001291 net->ipv6.rt6_stats->fib_rt_cache--;
1292
1293 /* purge completely the exception to allow releasing the held resources:
1294 * some [sk] cache may keep the dst around for unlimited time
1295 */
1296 from = rcu_dereference_protected(rt6_ex->rt6i->from,
1297 lockdep_is_held(&rt6_exception_lock));
1298 rcu_assign_pointer(rt6_ex->rt6i->from, NULL);
1299 fib6_info_release(from);
1300 dst_dev_put(&rt6_ex->rt6i->dst);
1301
Wei Wang35732d02017-10-06 12:05:57 -07001302 hlist_del_rcu(&rt6_ex->hlist);
David Ahern77634cc2018-04-17 17:33:27 -07001303 dst_release(&rt6_ex->rt6i->dst);
Wei Wang35732d02017-10-06 12:05:57 -07001304 kfree_rcu(rt6_ex, rcu);
1305 WARN_ON_ONCE(!bucket->depth);
1306 bucket->depth--;
1307}
1308
1309/* Remove oldest rt6_ex in bucket and free the memory
1310 * Caller must hold rt6_exception_lock
1311 */
1312static void rt6_exception_remove_oldest(struct rt6_exception_bucket *bucket)
1313{
1314 struct rt6_exception *rt6_ex, *oldest = NULL;
1315
1316 if (!bucket)
1317 return;
1318
1319 hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
1320 if (!oldest || time_before(rt6_ex->stamp, oldest->stamp))
1321 oldest = rt6_ex;
1322 }
1323 rt6_remove_exception(bucket, oldest);
1324}
1325
1326static u32 rt6_exception_hash(const struct in6_addr *dst,
1327 const struct in6_addr *src)
1328{
1329 static u32 seed __read_mostly;
1330 u32 val;
1331
1332 net_get_random_once(&seed, sizeof(seed));
1333 val = jhash(dst, sizeof(*dst), seed);
1334
1335#ifdef CONFIG_IPV6_SUBTREES
1336 if (src)
1337 val = jhash(src, sizeof(*src), val);
1338#endif
1339 return hash_32(val, FIB6_EXCEPTION_BUCKET_SIZE_SHIFT);
1340}
1341
1342/* Helper function to find the cached rt in the hash table
1343 * and update bucket pointer to point to the bucket for this
1344 * (daddr, saddr) pair
1345 * Caller must hold rt6_exception_lock
1346 */
1347static struct rt6_exception *
1348__rt6_find_exception_spinlock(struct rt6_exception_bucket **bucket,
1349 const struct in6_addr *daddr,
1350 const struct in6_addr *saddr)
1351{
1352 struct rt6_exception *rt6_ex;
1353 u32 hval;
1354
1355 if (!(*bucket) || !daddr)
1356 return NULL;
1357
1358 hval = rt6_exception_hash(daddr, saddr);
1359 *bucket += hval;
1360
1361 hlist_for_each_entry(rt6_ex, &(*bucket)->chain, hlist) {
1362 struct rt6_info *rt6 = rt6_ex->rt6i;
1363 bool matched = ipv6_addr_equal(daddr, &rt6->rt6i_dst.addr);
1364
1365#ifdef CONFIG_IPV6_SUBTREES
1366 if (matched && saddr)
1367 matched = ipv6_addr_equal(saddr, &rt6->rt6i_src.addr);
1368#endif
1369 if (matched)
1370 return rt6_ex;
1371 }
1372 return NULL;
1373}
1374
1375/* Helper function to find the cached rt in the hash table
1376 * and update bucket pointer to point to the bucket for this
1377 * (daddr, saddr) pair
1378 * Caller must hold rcu_read_lock()
1379 */
1380static struct rt6_exception *
1381__rt6_find_exception_rcu(struct rt6_exception_bucket **bucket,
1382 const struct in6_addr *daddr,
1383 const struct in6_addr *saddr)
1384{
1385 struct rt6_exception *rt6_ex;
1386 u32 hval;
1387
1388 WARN_ON_ONCE(!rcu_read_lock_held());
1389
1390 if (!(*bucket) || !daddr)
1391 return NULL;
1392
1393 hval = rt6_exception_hash(daddr, saddr);
1394 *bucket += hval;
1395
1396 hlist_for_each_entry_rcu(rt6_ex, &(*bucket)->chain, hlist) {
1397 struct rt6_info *rt6 = rt6_ex->rt6i;
1398 bool matched = ipv6_addr_equal(daddr, &rt6->rt6i_dst.addr);
1399
1400#ifdef CONFIG_IPV6_SUBTREES
1401 if (matched && saddr)
1402 matched = ipv6_addr_equal(saddr, &rt6->rt6i_src.addr);
1403#endif
1404 if (matched)
1405 return rt6_ex;
1406 }
1407 return NULL;
1408}
1409
David Ahern8d1c8022018-04-17 17:33:26 -07001410static unsigned int fib6_mtu(const struct fib6_info *rt)
Wei Wang35732d02017-10-06 12:05:57 -07001411{
David Ahernd4ead6b2018-04-17 17:33:16 -07001412 unsigned int mtu;
1413
David Aherndcd1f572018-04-18 15:39:05 -07001414 if (rt->fib6_pmtu) {
1415 mtu = rt->fib6_pmtu;
1416 } else {
1417 struct net_device *dev = fib6_info_nh_dev(rt);
1418 struct inet6_dev *idev;
1419
1420 rcu_read_lock();
1421 idev = __in6_dev_get(dev);
1422 mtu = idev->cnf.mtu6;
1423 rcu_read_unlock();
1424 }
1425
David Ahernd4ead6b2018-04-17 17:33:16 -07001426 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
1427
David Ahernad1601a2019-03-27 20:53:56 -07001428 return mtu - lwtunnel_headroom(rt->fib6_nh.fib_nh_lws, mtu);
David Ahernd4ead6b2018-04-17 17:33:16 -07001429}
1430
Wei Wang35732d02017-10-06 12:05:57 -07001431static int rt6_insert_exception(struct rt6_info *nrt,
David Ahern8d1c8022018-04-17 17:33:26 -07001432 struct fib6_info *ort)
Wei Wang35732d02017-10-06 12:05:57 -07001433{
David Ahern5e670d82018-04-17 17:33:14 -07001434 struct net *net = dev_net(nrt->dst.dev);
Wei Wang35732d02017-10-06 12:05:57 -07001435 struct rt6_exception_bucket *bucket;
1436 struct in6_addr *src_key = NULL;
1437 struct rt6_exception *rt6_ex;
1438 int err = 0;
1439
Wei Wang35732d02017-10-06 12:05:57 -07001440 spin_lock_bh(&rt6_exception_lock);
1441
1442 if (ort->exception_bucket_flushed) {
1443 err = -EINVAL;
1444 goto out;
1445 }
1446
1447 bucket = rcu_dereference_protected(ort->rt6i_exception_bucket,
1448 lockdep_is_held(&rt6_exception_lock));
1449 if (!bucket) {
1450 bucket = kcalloc(FIB6_EXCEPTION_BUCKET_SIZE, sizeof(*bucket),
1451 GFP_ATOMIC);
1452 if (!bucket) {
1453 err = -ENOMEM;
1454 goto out;
1455 }
1456 rcu_assign_pointer(ort->rt6i_exception_bucket, bucket);
1457 }
1458
1459#ifdef CONFIG_IPV6_SUBTREES
1460 /* rt6i_src.plen != 0 indicates ort is in subtree
1461 * and exception table is indexed by a hash of
1462 * both rt6i_dst and rt6i_src.
1463 * Otherwise, the exception table is indexed by
1464 * a hash of only rt6i_dst.
1465 */
David Ahern93c2fb22018-04-18 15:38:59 -07001466 if (ort->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001467 src_key = &nrt->rt6i_src.addr;
1468#endif
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001469 /* rt6_mtu_change() might lower mtu on ort.
1470 * Only insert this exception route if its mtu
1471 * is less than ort's mtu value.
1472 */
David Ahernd4ead6b2018-04-17 17:33:16 -07001473 if (dst_metric_raw(&nrt->dst, RTAX_MTU) >= fib6_mtu(ort)) {
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001474 err = -EINVAL;
1475 goto out;
1476 }
Wei Wang60006a42017-10-06 12:05:58 -07001477
Wei Wang35732d02017-10-06 12:05:57 -07001478 rt6_ex = __rt6_find_exception_spinlock(&bucket, &nrt->rt6i_dst.addr,
1479 src_key);
1480 if (rt6_ex)
1481 rt6_remove_exception(bucket, rt6_ex);
1482
1483 rt6_ex = kzalloc(sizeof(*rt6_ex), GFP_ATOMIC);
1484 if (!rt6_ex) {
1485 err = -ENOMEM;
1486 goto out;
1487 }
1488 rt6_ex->rt6i = nrt;
1489 rt6_ex->stamp = jiffies;
Wei Wang35732d02017-10-06 12:05:57 -07001490 hlist_add_head_rcu(&rt6_ex->hlist, &bucket->chain);
1491 bucket->depth++;
Wei Wang81eb8442017-10-06 12:06:11 -07001492 net->ipv6.rt6_stats->fib_rt_cache++;
Wei Wang35732d02017-10-06 12:05:57 -07001493
1494 if (bucket->depth > FIB6_MAX_DEPTH)
1495 rt6_exception_remove_oldest(bucket);
1496
1497out:
1498 spin_unlock_bh(&rt6_exception_lock);
1499
1500 /* Update fn->fn_sernum to invalidate all cached dst */
Paolo Abenib886d5f2017-10-19 16:07:10 +02001501 if (!err) {
David Ahern93c2fb22018-04-18 15:38:59 -07001502 spin_lock_bh(&ort->fib6_table->tb6_lock);
David Ahern7aef6852018-04-17 17:33:10 -07001503 fib6_update_sernum(net, ort);
David Ahern93c2fb22018-04-18 15:38:59 -07001504 spin_unlock_bh(&ort->fib6_table->tb6_lock);
Paolo Abenib886d5f2017-10-19 16:07:10 +02001505 fib6_force_start_gc(net);
1506 }
Wei Wang35732d02017-10-06 12:05:57 -07001507
1508 return err;
1509}
1510
David Ahern8d1c8022018-04-17 17:33:26 -07001511void rt6_flush_exceptions(struct fib6_info *rt)
Wei Wang35732d02017-10-06 12:05:57 -07001512{
1513 struct rt6_exception_bucket *bucket;
1514 struct rt6_exception *rt6_ex;
1515 struct hlist_node *tmp;
1516 int i;
1517
1518 spin_lock_bh(&rt6_exception_lock);
1519 /* Prevent rt6_insert_exception() to recreate the bucket list */
1520 rt->exception_bucket_flushed = 1;
1521
1522 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1523 lockdep_is_held(&rt6_exception_lock));
1524 if (!bucket)
1525 goto out;
1526
1527 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1528 hlist_for_each_entry_safe(rt6_ex, tmp, &bucket->chain, hlist)
1529 rt6_remove_exception(bucket, rt6_ex);
1530 WARN_ON_ONCE(bucket->depth);
1531 bucket++;
1532 }
1533
1534out:
1535 spin_unlock_bh(&rt6_exception_lock);
1536}
1537
1538/* Find cached rt in the hash table inside passed in rt
1539 * Caller has to hold rcu_read_lock()
1540 */
David Ahern7e4b5122019-04-16 14:36:00 -07001541static struct rt6_info *rt6_find_cached_rt(const struct fib6_result *res,
Wei Wang35732d02017-10-06 12:05:57 -07001542 struct in6_addr *daddr,
1543 struct in6_addr *saddr)
1544{
1545 struct rt6_exception_bucket *bucket;
1546 struct in6_addr *src_key = NULL;
1547 struct rt6_exception *rt6_ex;
David Ahern7e4b5122019-04-16 14:36:00 -07001548 struct rt6_info *ret = NULL;
Wei Wang35732d02017-10-06 12:05:57 -07001549
David Ahern7e4b5122019-04-16 14:36:00 -07001550 bucket = rcu_dereference(res->f6i->rt6i_exception_bucket);
Wei Wang35732d02017-10-06 12:05:57 -07001551
1552#ifdef CONFIG_IPV6_SUBTREES
David Ahern7e4b5122019-04-16 14:36:00 -07001553 /* fib6i_src.plen != 0 indicates f6i is in subtree
Wei Wang35732d02017-10-06 12:05:57 -07001554 * and exception table is indexed by a hash of
David Ahern7e4b5122019-04-16 14:36:00 -07001555 * both fib6_dst and fib6_src.
Wei Wang35732d02017-10-06 12:05:57 -07001556 * Otherwise, the exception table is indexed by
David Ahern7e4b5122019-04-16 14:36:00 -07001557 * a hash of only fib6_dst.
Wei Wang35732d02017-10-06 12:05:57 -07001558 */
David Ahern7e4b5122019-04-16 14:36:00 -07001559 if (res->f6i->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001560 src_key = saddr;
1561#endif
1562 rt6_ex = __rt6_find_exception_rcu(&bucket, daddr, src_key);
1563
1564 if (rt6_ex && !rt6_check_expired(rt6_ex->rt6i))
David Ahern7e4b5122019-04-16 14:36:00 -07001565 ret = rt6_ex->rt6i;
Wei Wang35732d02017-10-06 12:05:57 -07001566
David Ahern7e4b5122019-04-16 14:36:00 -07001567 return ret;
Wei Wang35732d02017-10-06 12:05:57 -07001568}
1569
1570/* Remove the passed in cached rt from the hash table that contains it */
David Ahern23fb93a2018-04-17 17:33:23 -07001571static int rt6_remove_exception_rt(struct rt6_info *rt)
Wei Wang35732d02017-10-06 12:05:57 -07001572{
Wei Wang35732d02017-10-06 12:05:57 -07001573 struct rt6_exception_bucket *bucket;
1574 struct in6_addr *src_key = NULL;
1575 struct rt6_exception *rt6_ex;
David Ahern8a14e462018-04-23 11:32:07 -07001576 struct fib6_info *from;
Wei Wang35732d02017-10-06 12:05:57 -07001577 int err;
1578
Eric Dumazet091311d2018-04-24 09:22:49 -07001579 from = rcu_dereference(rt->from);
Wei Wang35732d02017-10-06 12:05:57 -07001580 if (!from ||
Colin Ian King442d7132017-10-10 19:10:30 +01001581 !(rt->rt6i_flags & RTF_CACHE))
Wei Wang35732d02017-10-06 12:05:57 -07001582 return -EINVAL;
1583
1584 if (!rcu_access_pointer(from->rt6i_exception_bucket))
1585 return -ENOENT;
1586
1587 spin_lock_bh(&rt6_exception_lock);
1588 bucket = rcu_dereference_protected(from->rt6i_exception_bucket,
1589 lockdep_is_held(&rt6_exception_lock));
1590#ifdef CONFIG_IPV6_SUBTREES
1591 /* rt6i_src.plen != 0 indicates 'from' is in subtree
1592 * and exception table is indexed by a hash of
1593 * both rt6i_dst and rt6i_src.
1594 * Otherwise, the exception table is indexed by
1595 * a hash of only rt6i_dst.
1596 */
David Ahern93c2fb22018-04-18 15:38:59 -07001597 if (from->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001598 src_key = &rt->rt6i_src.addr;
1599#endif
1600 rt6_ex = __rt6_find_exception_spinlock(&bucket,
1601 &rt->rt6i_dst.addr,
1602 src_key);
1603 if (rt6_ex) {
1604 rt6_remove_exception(bucket, rt6_ex);
1605 err = 0;
1606 } else {
1607 err = -ENOENT;
1608 }
1609
1610 spin_unlock_bh(&rt6_exception_lock);
1611 return err;
1612}
1613
1614/* Find rt6_ex which contains the passed in rt cache and
1615 * refresh its stamp
1616 */
1617static void rt6_update_exception_stamp_rt(struct rt6_info *rt)
1618{
Wei Wang35732d02017-10-06 12:05:57 -07001619 struct rt6_exception_bucket *bucket;
1620 struct in6_addr *src_key = NULL;
1621 struct rt6_exception *rt6_ex;
Paolo Abeni193f3682019-02-21 11:19:41 +01001622 struct fib6_info *from;
Wei Wang35732d02017-10-06 12:05:57 -07001623
1624 rcu_read_lock();
Paolo Abeni193f3682019-02-21 11:19:41 +01001625 from = rcu_dereference(rt->from);
1626 if (!from || !(rt->rt6i_flags & RTF_CACHE))
1627 goto unlock;
1628
Wei Wang35732d02017-10-06 12:05:57 -07001629 bucket = rcu_dereference(from->rt6i_exception_bucket);
1630
1631#ifdef CONFIG_IPV6_SUBTREES
1632 /* rt6i_src.plen != 0 indicates 'from' is in subtree
1633 * and exception table is indexed by a hash of
1634 * both rt6i_dst and rt6i_src.
1635 * Otherwise, the exception table is indexed by
1636 * a hash of only rt6i_dst.
1637 */
David Ahern93c2fb22018-04-18 15:38:59 -07001638 if (from->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001639 src_key = &rt->rt6i_src.addr;
1640#endif
1641 rt6_ex = __rt6_find_exception_rcu(&bucket,
1642 &rt->rt6i_dst.addr,
1643 src_key);
1644 if (rt6_ex)
1645 rt6_ex->stamp = jiffies;
1646
Paolo Abeni193f3682019-02-21 11:19:41 +01001647unlock:
Wei Wang35732d02017-10-06 12:05:57 -07001648 rcu_read_unlock();
1649}
1650
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001651static bool rt6_mtu_change_route_allowed(struct inet6_dev *idev,
1652 struct rt6_info *rt, int mtu)
1653{
1654 /* If the new MTU is lower than the route PMTU, this new MTU will be the
1655 * lowest MTU in the path: always allow updating the route PMTU to
1656 * reflect PMTU decreases.
1657 *
1658 * If the new MTU is higher, and the route PMTU is equal to the local
1659 * MTU, this means the old MTU is the lowest in the path, so allow
1660 * updating it: if other nodes now have lower MTUs, PMTU discovery will
1661 * handle this.
1662 */
1663
1664 if (dst_mtu(&rt->dst) >= mtu)
1665 return true;
1666
1667 if (dst_mtu(&rt->dst) == idev->cnf.mtu6)
1668 return true;
1669
1670 return false;
1671}
1672
1673static void rt6_exceptions_update_pmtu(struct inet6_dev *idev,
David Ahern8d1c8022018-04-17 17:33:26 -07001674 struct fib6_info *rt, int mtu)
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001675{
1676 struct rt6_exception_bucket *bucket;
1677 struct rt6_exception *rt6_ex;
1678 int i;
1679
1680 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1681 lockdep_is_held(&rt6_exception_lock));
1682
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001683 if (!bucket)
1684 return;
1685
1686 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1687 hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
1688 struct rt6_info *entry = rt6_ex->rt6i;
1689
1690 /* For RTF_CACHE with rt6i_pmtu == 0 (i.e. a redirected
David Ahernd4ead6b2018-04-17 17:33:16 -07001691 * route), the metrics of its rt->from have already
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001692 * been updated.
1693 */
David Ahernd4ead6b2018-04-17 17:33:16 -07001694 if (dst_metric_raw(&entry->dst, RTAX_MTU) &&
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001695 rt6_mtu_change_route_allowed(idev, entry, mtu))
David Ahernd4ead6b2018-04-17 17:33:16 -07001696 dst_metric_set(&entry->dst, RTAX_MTU, mtu);
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001697 }
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001698 bucket++;
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001699 }
1700}
1701
Wei Wangb16cb452017-10-06 12:06:00 -07001702#define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE)
1703
David Ahern8d1c8022018-04-17 17:33:26 -07001704static void rt6_exceptions_clean_tohost(struct fib6_info *rt,
Wei Wangb16cb452017-10-06 12:06:00 -07001705 struct in6_addr *gateway)
1706{
1707 struct rt6_exception_bucket *bucket;
1708 struct rt6_exception *rt6_ex;
1709 struct hlist_node *tmp;
1710 int i;
1711
1712 if (!rcu_access_pointer(rt->rt6i_exception_bucket))
1713 return;
1714
1715 spin_lock_bh(&rt6_exception_lock);
1716 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1717 lockdep_is_held(&rt6_exception_lock));
1718
1719 if (bucket) {
1720 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1721 hlist_for_each_entry_safe(rt6_ex, tmp,
1722 &bucket->chain, hlist) {
1723 struct rt6_info *entry = rt6_ex->rt6i;
1724
1725 if ((entry->rt6i_flags & RTF_CACHE_GATEWAY) ==
1726 RTF_CACHE_GATEWAY &&
1727 ipv6_addr_equal(gateway,
1728 &entry->rt6i_gateway)) {
1729 rt6_remove_exception(bucket, rt6_ex);
1730 }
1731 }
1732 bucket++;
1733 }
1734 }
1735
1736 spin_unlock_bh(&rt6_exception_lock);
1737}
1738
Wei Wangc757faa2017-10-06 12:06:01 -07001739static void rt6_age_examine_exception(struct rt6_exception_bucket *bucket,
1740 struct rt6_exception *rt6_ex,
1741 struct fib6_gc_args *gc_args,
1742 unsigned long now)
1743{
1744 struct rt6_info *rt = rt6_ex->rt6i;
1745
Paolo Abeni1859bac2017-10-19 16:07:11 +02001746 /* we are pruning and obsoleting aged-out and non gateway exceptions
1747 * even if others have still references to them, so that on next
1748 * dst_check() such references can be dropped.
1749 * EXPIRES exceptions - e.g. pmtu-generated ones are pruned when
1750 * expired, independently from their aging, as per RFC 8201 section 4
1751 */
Wei Wang31afeb42018-01-26 11:40:17 -08001752 if (!(rt->rt6i_flags & RTF_EXPIRES)) {
1753 if (time_after_eq(now, rt->dst.lastuse + gc_args->timeout)) {
1754 RT6_TRACE("aging clone %p\n", rt);
1755 rt6_remove_exception(bucket, rt6_ex);
1756 return;
1757 }
1758 } else if (time_after(jiffies, rt->dst.expires)) {
1759 RT6_TRACE("purging expired route %p\n", rt);
Wei Wangc757faa2017-10-06 12:06:01 -07001760 rt6_remove_exception(bucket, rt6_ex);
1761 return;
Wei Wang31afeb42018-01-26 11:40:17 -08001762 }
1763
1764 if (rt->rt6i_flags & RTF_GATEWAY) {
Wei Wangc757faa2017-10-06 12:06:01 -07001765 struct neighbour *neigh;
1766 __u8 neigh_flags = 0;
1767
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001768 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
1769 if (neigh)
Wei Wangc757faa2017-10-06 12:06:01 -07001770 neigh_flags = neigh->flags;
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001771
Wei Wangc757faa2017-10-06 12:06:01 -07001772 if (!(neigh_flags & NTF_ROUTER)) {
1773 RT6_TRACE("purging route %p via non-router but gateway\n",
1774 rt);
1775 rt6_remove_exception(bucket, rt6_ex);
1776 return;
1777 }
1778 }
Wei Wang31afeb42018-01-26 11:40:17 -08001779
Wei Wangc757faa2017-10-06 12:06:01 -07001780 gc_args->more++;
1781}
1782
David Ahern8d1c8022018-04-17 17:33:26 -07001783void rt6_age_exceptions(struct fib6_info *rt,
Wei Wangc757faa2017-10-06 12:06:01 -07001784 struct fib6_gc_args *gc_args,
1785 unsigned long now)
1786{
1787 struct rt6_exception_bucket *bucket;
1788 struct rt6_exception *rt6_ex;
1789 struct hlist_node *tmp;
1790 int i;
1791
1792 if (!rcu_access_pointer(rt->rt6i_exception_bucket))
1793 return;
1794
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001795 rcu_read_lock_bh();
1796 spin_lock(&rt6_exception_lock);
Wei Wangc757faa2017-10-06 12:06:01 -07001797 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1798 lockdep_is_held(&rt6_exception_lock));
1799
1800 if (bucket) {
1801 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1802 hlist_for_each_entry_safe(rt6_ex, tmp,
1803 &bucket->chain, hlist) {
1804 rt6_age_examine_exception(bucket, rt6_ex,
1805 gc_args, now);
1806 }
1807 bucket++;
1808 }
1809 }
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001810 spin_unlock(&rt6_exception_lock);
1811 rcu_read_unlock_bh();
Wei Wangc757faa2017-10-06 12:06:01 -07001812}
1813
David Ahern1d053da2018-05-09 20:34:21 -07001814/* must be called with rcu lock held */
1815struct fib6_info *fib6_table_lookup(struct net *net, struct fib6_table *table,
1816 int oif, struct flowi6 *fl6, int strict)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817{
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001818 struct fib6_node *fn, *saved_fn;
David Ahern8d1c8022018-04-17 17:33:26 -07001819 struct fib6_info *f6i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820
David Ahern64547432018-05-09 20:34:19 -07001821 fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001822 saved_fn = fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823
David Ahernca254492015-10-12 11:47:10 -07001824 if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
1825 oif = 0;
1826
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001827redo_rt6_select:
David Ahern23fb93a2018-04-17 17:33:23 -07001828 f6i = rt6_select(net, fn, oif, strict);
David Ahern23fb93a2018-04-17 17:33:23 -07001829 if (f6i == net->ipv6.fib6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001830 fn = fib6_backtrack(fn, &fl6->saddr);
1831 if (fn)
1832 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001833 else if (strict & RT6_LOOKUP_F_REACHABLE) {
1834 /* also consider unreachable route */
1835 strict &= ~RT6_LOOKUP_F_REACHABLE;
1836 fn = saved_fn;
1837 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001838 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001839 }
1840
David Ahernd4bea422018-05-09 20:34:24 -07001841 trace_fib6_table_lookup(net, f6i, table, fl6);
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -08001842
David Ahern1d053da2018-05-09 20:34:21 -07001843 return f6i;
1844}
1845
1846struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
1847 int oif, struct flowi6 *fl6,
1848 const struct sk_buff *skb, int flags)
1849{
David Ahernb1d40992019-04-16 14:35:59 -07001850 struct fib6_result res = {};
David Ahern1d053da2018-05-09 20:34:21 -07001851 struct rt6_info *rt;
1852 int strict = 0;
1853
1854 strict |= flags & RT6_LOOKUP_F_IFACE;
1855 strict |= flags & RT6_LOOKUP_F_IGNORE_LINKSTATE;
1856 if (net->ipv6.devconf_all->forwarding == 0)
1857 strict |= RT6_LOOKUP_F_REACHABLE;
1858
1859 rcu_read_lock();
1860
David Ahernb1d40992019-04-16 14:35:59 -07001861 res.f6i = fib6_table_lookup(net, table, oif, fl6, strict);
1862 if (res.f6i == net->ipv6.fib6_null_entry) {
David Ahern421842e2018-04-17 17:33:18 -07001863 rt = net->ipv6.ip6_null_entry;
Wei Wang66f5d6c2017-10-06 12:06:10 -07001864 rcu_read_unlock();
Wei Wangd3843fe2017-10-06 12:06:06 -07001865 dst_hold(&rt->dst);
Wei Wangd3843fe2017-10-06 12:06:06 -07001866 return rt;
David Ahern23fb93a2018-04-17 17:33:23 -07001867 }
1868
David Ahernb1d40992019-04-16 14:35:59 -07001869 fib6_select_path(net, &res, fl6, oif, false, skb, strict);
David Ahernd83009d2019-04-09 14:41:17 -07001870
David Ahern23fb93a2018-04-17 17:33:23 -07001871 /*Search through exception table */
David Ahern7e4b5122019-04-16 14:36:00 -07001872 rt = rt6_find_cached_rt(&res, &fl6->daddr, &fl6->saddr);
David Ahern23fb93a2018-04-17 17:33:23 -07001873 if (rt) {
David Ahern10585b42019-03-20 09:24:50 -07001874 if (ip6_hold_safe(net, &rt))
Wei Wangd3843fe2017-10-06 12:06:06 -07001875 dst_use_noref(&rt->dst, jiffies);
David Ahernd4ead6b2018-04-17 17:33:16 -07001876
Wei Wang66f5d6c2017-10-06 12:06:10 -07001877 rcu_read_unlock();
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001878 return rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001879 } else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) &&
David Ahernb1d40992019-04-16 14:35:59 -07001880 !res.nh->fib_nh_gw_family)) {
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001881 /* Create a RTF_CACHE clone which will not be
1882 * owned by the fib6 tree. It is for the special case where
1883 * the daddr in the skb during the neighbor look-up is different
1884 * from the fl6->daddr used to look-up route here.
1885 */
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001886 struct rt6_info *uncached_rt;
1887
David Ahernb1d40992019-04-16 14:35:59 -07001888 uncached_rt = ip6_rt_cache_alloc(res.f6i, &fl6->daddr, NULL);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001889
David Ahern4d85cd02018-04-20 15:37:59 -07001890 rcu_read_unlock();
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001891
Wei Wang1cfb71e2017-06-17 10:42:33 -07001892 if (uncached_rt) {
1893 /* Uncached_rt's refcnt is taken during ip6_rt_cache_alloc()
1894 * No need for another dst_hold()
1895 */
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07001896 rt6_uncached_list_add(uncached_rt);
Wei Wang81eb8442017-10-06 12:06:11 -07001897 atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);
Wei Wang1cfb71e2017-06-17 10:42:33 -07001898 } else {
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001899 uncached_rt = net->ipv6.ip6_null_entry;
Wei Wang1cfb71e2017-06-17 10:42:33 -07001900 dst_hold(&uncached_rt->dst);
1901 }
David Ahernb8115802015-11-19 12:24:22 -08001902
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001903 return uncached_rt;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001904 } else {
1905 /* Get a percpu copy */
1906
1907 struct rt6_info *pcpu_rt;
1908
Eric Dumazet951f7882017-10-08 21:07:18 -07001909 local_bh_disable();
David Ahernb1d40992019-04-16 14:35:59 -07001910 pcpu_rt = rt6_get_pcpu_route(res.f6i);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001911
David Ahern93531c62018-04-17 17:33:25 -07001912 if (!pcpu_rt)
David Ahernb1d40992019-04-16 14:35:59 -07001913 pcpu_rt = rt6_make_pcpu_route(net, res.f6i);
David Ahern93531c62018-04-17 17:33:25 -07001914
Eric Dumazet951f7882017-10-08 21:07:18 -07001915 local_bh_enable();
1916 rcu_read_unlock();
David Ahernd4bea422018-05-09 20:34:24 -07001917
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001918 return pcpu_rt;
1919 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001920}
David Ahern9ff74382016-06-13 13:44:19 -07001921EXPORT_SYMBOL_GPL(ip6_pol_route);
Thomas Grafc71099a2006-08-04 23:20:06 -07001922
David Ahernb75cc8f2018-03-02 08:32:17 -08001923static struct rt6_info *ip6_pol_route_input(struct net *net,
1924 struct fib6_table *table,
1925 struct flowi6 *fl6,
1926 const struct sk_buff *skb,
1927 int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001928{
David Ahernb75cc8f2018-03-02 08:32:17 -08001929 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, skb, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001930}
1931
Mahesh Bandeward409b842016-09-16 12:59:08 -07001932struct dst_entry *ip6_route_input_lookup(struct net *net,
1933 struct net_device *dev,
David Ahernb75cc8f2018-03-02 08:32:17 -08001934 struct flowi6 *fl6,
1935 const struct sk_buff *skb,
1936 int flags)
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001937{
1938 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
1939 flags |= RT6_LOOKUP_F_IFACE;
1940
David Ahernb75cc8f2018-03-02 08:32:17 -08001941 return fib6_rule_lookup(net, fl6, skb, flags, ip6_pol_route_input);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001942}
Mahesh Bandeward409b842016-09-16 12:59:08 -07001943EXPORT_SYMBOL_GPL(ip6_route_input_lookup);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001944
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001945static void ip6_multipath_l3_keys(const struct sk_buff *skb,
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001946 struct flow_keys *keys,
1947 struct flow_keys *flkeys)
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001948{
1949 const struct ipv6hdr *outer_iph = ipv6_hdr(skb);
1950 const struct ipv6hdr *key_iph = outer_iph;
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001951 struct flow_keys *_flkeys = flkeys;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001952 const struct ipv6hdr *inner_iph;
1953 const struct icmp6hdr *icmph;
1954 struct ipv6hdr _inner_iph;
Eric Dumazetcea67a22018-04-29 09:54:59 -07001955 struct icmp6hdr _icmph;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001956
1957 if (likely(outer_iph->nexthdr != IPPROTO_ICMPV6))
1958 goto out;
1959
Eric Dumazetcea67a22018-04-29 09:54:59 -07001960 icmph = skb_header_pointer(skb, skb_transport_offset(skb),
1961 sizeof(_icmph), &_icmph);
1962 if (!icmph)
1963 goto out;
1964
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001965 if (icmph->icmp6_type != ICMPV6_DEST_UNREACH &&
1966 icmph->icmp6_type != ICMPV6_PKT_TOOBIG &&
1967 icmph->icmp6_type != ICMPV6_TIME_EXCEED &&
1968 icmph->icmp6_type != ICMPV6_PARAMPROB)
1969 goto out;
1970
1971 inner_iph = skb_header_pointer(skb,
1972 skb_transport_offset(skb) + sizeof(*icmph),
1973 sizeof(_inner_iph), &_inner_iph);
1974 if (!inner_iph)
1975 goto out;
1976
1977 key_iph = inner_iph;
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001978 _flkeys = NULL;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001979out:
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001980 if (_flkeys) {
1981 keys->addrs.v6addrs.src = _flkeys->addrs.v6addrs.src;
1982 keys->addrs.v6addrs.dst = _flkeys->addrs.v6addrs.dst;
1983 keys->tags.flow_label = _flkeys->tags.flow_label;
1984 keys->basic.ip_proto = _flkeys->basic.ip_proto;
1985 } else {
1986 keys->addrs.v6addrs.src = key_iph->saddr;
1987 keys->addrs.v6addrs.dst = key_iph->daddr;
Michal Kubecekfa1be7e2018-06-04 11:36:05 +02001988 keys->tags.flow_label = ip6_flowlabel(key_iph);
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001989 keys->basic.ip_proto = key_iph->nexthdr;
1990 }
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001991}
1992
1993/* if skb is set it will be used and fl6 can be NULL */
David Ahernb4bac172018-03-02 08:32:18 -08001994u32 rt6_multipath_hash(const struct net *net, const struct flowi6 *fl6,
1995 const struct sk_buff *skb, struct flow_keys *flkeys)
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001996{
1997 struct flow_keys hash_keys;
David Ahern9a2a5372018-03-02 08:32:15 -08001998 u32 mhash;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001999
David S. Millerbbfa0472018-03-12 11:09:33 -04002000 switch (ip6_multipath_hash_policy(net)) {
David Ahernb4bac172018-03-02 08:32:18 -08002001 case 0:
2002 memset(&hash_keys, 0, sizeof(hash_keys));
2003 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2004 if (skb) {
2005 ip6_multipath_l3_keys(skb, &hash_keys, flkeys);
2006 } else {
2007 hash_keys.addrs.v6addrs.src = fl6->saddr;
2008 hash_keys.addrs.v6addrs.dst = fl6->daddr;
Michal Kubecekfa1be7e2018-06-04 11:36:05 +02002009 hash_keys.tags.flow_label = (__force u32)flowi6_get_flowlabel(fl6);
David Ahernb4bac172018-03-02 08:32:18 -08002010 hash_keys.basic.ip_proto = fl6->flowi6_proto;
2011 }
2012 break;
2013 case 1:
2014 if (skb) {
2015 unsigned int flag = FLOW_DISSECTOR_F_STOP_AT_ENCAP;
2016 struct flow_keys keys;
2017
2018 /* short-circuit if we already have L4 hash present */
2019 if (skb->l4_hash)
2020 return skb_get_hash_raw(skb) >> 1;
2021
2022 memset(&hash_keys, 0, sizeof(hash_keys));
2023
2024 if (!flkeys) {
2025 skb_flow_dissect_flow_keys(skb, &keys, flag);
2026 flkeys = &keys;
2027 }
2028 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2029 hash_keys.addrs.v6addrs.src = flkeys->addrs.v6addrs.src;
2030 hash_keys.addrs.v6addrs.dst = flkeys->addrs.v6addrs.dst;
2031 hash_keys.ports.src = flkeys->ports.src;
2032 hash_keys.ports.dst = flkeys->ports.dst;
2033 hash_keys.basic.ip_proto = flkeys->basic.ip_proto;
2034 } else {
2035 memset(&hash_keys, 0, sizeof(hash_keys));
2036 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2037 hash_keys.addrs.v6addrs.src = fl6->saddr;
2038 hash_keys.addrs.v6addrs.dst = fl6->daddr;
2039 hash_keys.ports.src = fl6->fl6_sport;
2040 hash_keys.ports.dst = fl6->fl6_dport;
2041 hash_keys.basic.ip_proto = fl6->flowi6_proto;
2042 }
2043 break;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002044 }
David Ahern9a2a5372018-03-02 08:32:15 -08002045 mhash = flow_hash_from_keys(&hash_keys);
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002046
David Ahern9a2a5372018-03-02 08:32:15 -08002047 return mhash >> 1;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002048}
2049
Thomas Grafc71099a2006-08-04 23:20:06 -07002050void ip6_route_input(struct sk_buff *skb)
2051{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002052 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002053 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -07002054 int flags = RT6_LOOKUP_F_HAS_SADDR;
Jiri Benc904af042015-08-20 13:56:31 +02002055 struct ip_tunnel_info *tun_info;
David S. Miller4c9483b2011-03-12 16:22:43 -05002056 struct flowi6 fl6 = {
David Aherne0d56fd2016-09-10 12:09:57 -07002057 .flowi6_iif = skb->dev->ifindex,
David S. Miller4c9483b2011-03-12 16:22:43 -05002058 .daddr = iph->daddr,
2059 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00002060 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -05002061 .flowi6_mark = skb->mark,
2062 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -07002063 };
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05002064 struct flow_keys *flkeys = NULL, _flkeys;
Thomas Grafadaa70b2006-10-13 15:01:03 -07002065
Jiri Benc904af042015-08-20 13:56:31 +02002066 tun_info = skb_tunnel_info(skb);
Jiri Benc46fa0622015-08-28 20:48:19 +02002067 if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX))
Jiri Benc904af042015-08-20 13:56:31 +02002068 fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id;
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05002069
2070 if (fib6_rules_early_flow_dissect(net, skb, &fl6, &_flkeys))
2071 flkeys = &_flkeys;
2072
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002073 if (unlikely(fl6.flowi6_proto == IPPROTO_ICMPV6))
David Ahernb4bac172018-03-02 08:32:18 -08002074 fl6.mp_hash = rt6_multipath_hash(net, &fl6, skb, flkeys);
Jiri Benc06e9d042015-08-20 13:56:26 +02002075 skb_dst_drop(skb);
David Ahernb75cc8f2018-03-02 08:32:17 -08002076 skb_dst_set(skb,
2077 ip6_route_input_lookup(net, skb->dev, &fl6, skb, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -07002078}
2079
David Ahernb75cc8f2018-03-02 08:32:17 -08002080static struct rt6_info *ip6_pol_route_output(struct net *net,
2081 struct fib6_table *table,
2082 struct flowi6 *fl6,
2083 const struct sk_buff *skb,
2084 int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07002085{
David Ahernb75cc8f2018-03-02 08:32:17 -08002086 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, skb, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -07002087}
2088
Paolo Abeni6f21c962016-01-29 12:30:19 +01002089struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk,
2090 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07002091{
David Ahernd46a9d62015-10-21 08:42:22 -07002092 bool any_src;
Thomas Grafc71099a2006-08-04 23:20:06 -07002093
Robert Shearman3ede0bb2018-09-19 13:56:53 +01002094 if (ipv6_addr_type(&fl6->daddr) &
2095 (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)) {
David Ahern4c1feac2016-09-10 12:09:56 -07002096 struct dst_entry *dst;
2097
2098 dst = l3mdev_link_scope_lookup(net, fl6);
2099 if (dst)
2100 return dst;
2101 }
David Ahernca254492015-10-12 11:47:10 -07002102
Pavel Emelyanov1fb94892012-08-08 21:53:36 +00002103 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +00002104
David Ahernd46a9d62015-10-21 08:42:22 -07002105 any_src = ipv6_addr_any(&fl6->saddr);
David Ahern741a11d2015-09-28 10:12:13 -07002106 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) ||
David Ahernd46a9d62015-10-21 08:42:22 -07002107 (fl6->flowi6_oif && any_src))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07002108 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -07002109
David Ahernd46a9d62015-10-21 08:42:22 -07002110 if (!any_src)
Thomas Grafadaa70b2006-10-13 15:01:03 -07002111 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +00002112 else if (sk)
2113 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -07002114
David Ahernb75cc8f2018-03-02 08:32:17 -08002115 return fib6_rule_lookup(net, fl6, NULL, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116}
Paolo Abeni6f21c962016-01-29 12:30:19 +01002117EXPORT_SYMBOL_GPL(ip6_route_output_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118
David S. Miller2774c132011-03-01 14:59:04 -08002119struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -07002120{
David S. Miller5c1e6aa2011-04-28 14:13:38 -07002121 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
Wei Wang1dbe32522017-06-17 10:42:26 -07002122 struct net_device *loopback_dev = net->loopback_dev;
David S. Miller14e50e52007-05-24 18:17:54 -07002123 struct dst_entry *new = NULL;
2124
Wei Wang1dbe32522017-06-17 10:42:26 -07002125 rt = dst_alloc(&ip6_dst_blackhole_ops, loopback_dev, 1,
Steffen Klassert62cf27e2017-10-09 08:39:43 +02002126 DST_OBSOLETE_DEAD, 0);
David S. Miller14e50e52007-05-24 18:17:54 -07002127 if (rt) {
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002128 rt6_info_init(rt);
Wei Wang81eb8442017-10-06 12:06:11 -07002129 atomic_inc(&net->ipv6.rt6_stats->fib_rt_alloc);
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002130
Changli Gaod8d1f302010-06-10 23:31:35 -07002131 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -07002132 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08002133 new->input = dst_discard;
Eric W. Biedermanede20592015-10-07 16:48:47 -05002134 new->output = dst_discard_out;
David S. Miller14e50e52007-05-24 18:17:54 -07002135
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002136 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07002137
Wei Wang1dbe32522017-06-17 10:42:26 -07002138 rt->rt6i_idev = in6_dev_get(loopback_dev);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002139 rt->rt6i_gateway = ort->rt6i_gateway;
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002140 rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU;
David S. Miller14e50e52007-05-24 18:17:54 -07002141
2142 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
2143#ifdef CONFIG_IPV6_SUBTREES
2144 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
2145#endif
David S. Miller14e50e52007-05-24 18:17:54 -07002146 }
2147
David S. Miller69ead7a2011-03-01 14:45:33 -08002148 dst_release(dst_orig);
2149 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07002150}
David S. Miller14e50e52007-05-24 18:17:54 -07002151
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152/*
2153 * Destination cache support functions
2154 */
2155
David Ahern8d1c8022018-04-17 17:33:26 -07002156static bool fib6_check(struct fib6_info *f6i, u32 cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002157{
Steffen Klassert36143642017-08-25 09:05:42 +02002158 u32 rt_cookie = 0;
Wei Wangc5cff852017-08-21 09:47:10 -07002159
David Ahern8ae86972018-04-20 15:38:03 -07002160 if (!fib6_get_cookie_safe(f6i, &rt_cookie) || rt_cookie != cookie)
David Ahern93531c62018-04-17 17:33:25 -07002161 return false;
2162
2163 if (fib6_check_expired(f6i))
2164 return false;
2165
2166 return true;
2167}
2168
David Aherna68886a2018-04-20 15:38:02 -07002169static struct dst_entry *rt6_check(struct rt6_info *rt,
2170 struct fib6_info *from,
2171 u32 cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002172{
Wei Wangc5cff852017-08-21 09:47:10 -07002173 u32 rt_cookie = 0;
2174
David Aherna68886a2018-04-20 15:38:02 -07002175 if ((from && !fib6_get_cookie_safe(from, &rt_cookie)) ||
David Ahern93531c62018-04-17 17:33:25 -07002176 rt_cookie != cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002177 return NULL;
2178
2179 if (rt6_check_expired(rt))
2180 return NULL;
2181
2182 return &rt->dst;
2183}
2184
David Aherna68886a2018-04-20 15:38:02 -07002185static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt,
2186 struct fib6_info *from,
2187 u32 cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002188{
Martin KaFai Lau5973fb12015-11-11 11:51:07 -08002189 if (!__rt6_check_expired(rt) &&
2190 rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
David Aherna68886a2018-04-20 15:38:02 -07002191 fib6_check(from, cookie))
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002192 return &rt->dst;
2193 else
2194 return NULL;
2195}
2196
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
2198{
David Aherna87b7dc2018-04-20 15:38:00 -07002199 struct dst_entry *dst_ret;
David Aherna68886a2018-04-20 15:38:02 -07002200 struct fib6_info *from;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 struct rt6_info *rt;
2202
David Aherna87b7dc2018-04-20 15:38:00 -07002203 rt = container_of(dst, struct rt6_info, dst);
2204
2205 rcu_read_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00002207 /* All IPV6 dsts are created with ->obsolete set to the value
2208 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
2209 * into this function always.
2210 */
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02002211
David Aherna68886a2018-04-20 15:38:02 -07002212 from = rcu_dereference(rt->from);
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002213
David Aherna68886a2018-04-20 15:38:02 -07002214 if (from && (rt->rt6i_flags & RTF_PCPU ||
2215 unlikely(!list_empty(&rt->rt6i_uncached))))
2216 dst_ret = rt6_dst_from_check(rt, from, cookie);
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002217 else
David Aherna68886a2018-04-20 15:38:02 -07002218 dst_ret = rt6_check(rt, from, cookie);
David Aherna87b7dc2018-04-20 15:38:00 -07002219
2220 rcu_read_unlock();
2221
2222 return dst_ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223}
2224
2225static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
2226{
2227 struct rt6_info *rt = (struct rt6_info *) dst;
2228
2229 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002230 if (rt->rt6i_flags & RTF_CACHE) {
David Ahernc3c14da2018-04-23 11:32:06 -07002231 rcu_read_lock();
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002232 if (rt6_check_expired(rt)) {
David Ahern93531c62018-04-17 17:33:25 -07002233 rt6_remove_exception_rt(rt);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002234 dst = NULL;
2235 }
David Ahernc3c14da2018-04-23 11:32:06 -07002236 rcu_read_unlock();
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002237 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002239 dst = NULL;
2240 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002242 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243}
2244
2245static void ip6_link_failure(struct sk_buff *skb)
2246{
2247 struct rt6_info *rt;
2248
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002249 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250
Eric Dumazetadf30902009-06-02 05:19:30 +00002251 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 if (rt) {
David Ahern8a14e462018-04-23 11:32:07 -07002253 rcu_read_lock();
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02002254 if (rt->rt6i_flags & RTF_CACHE) {
Xin Long761f6022018-11-14 00:48:28 +08002255 rt6_remove_exception_rt(rt);
Wei Wangc5cff852017-08-21 09:47:10 -07002256 } else {
David Aherna68886a2018-04-20 15:38:02 -07002257 struct fib6_info *from;
Wei Wangc5cff852017-08-21 09:47:10 -07002258 struct fib6_node *fn;
2259
David Aherna68886a2018-04-20 15:38:02 -07002260 from = rcu_dereference(rt->from);
2261 if (from) {
2262 fn = rcu_dereference(from->fib6_node);
2263 if (fn && (rt->rt6i_flags & RTF_DEFAULT))
2264 fn->fn_sernum = -1;
2265 }
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02002266 }
David Ahern8a14e462018-04-23 11:32:07 -07002267 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 }
2269}
2270
David Ahern6a3e0302018-04-20 15:37:57 -07002271static void rt6_update_expires(struct rt6_info *rt0, int timeout)
2272{
David Aherna68886a2018-04-20 15:38:02 -07002273 if (!(rt0->rt6i_flags & RTF_EXPIRES)) {
2274 struct fib6_info *from;
2275
2276 rcu_read_lock();
2277 from = rcu_dereference(rt0->from);
2278 if (from)
2279 rt0->dst.expires = from->expires;
2280 rcu_read_unlock();
2281 }
David Ahern6a3e0302018-04-20 15:37:57 -07002282
2283 dst_set_expires(&rt0->dst, timeout);
2284 rt0->rt6i_flags |= RTF_EXPIRES;
2285}
2286
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002287static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
2288{
2289 struct net *net = dev_net(rt->dst.dev);
2290
David Ahernd4ead6b2018-04-17 17:33:16 -07002291 dst_metric_set(&rt->dst, RTAX_MTU, mtu);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002292 rt->rt6i_flags |= RTF_MODIFIED;
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002293 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
2294}
2295
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002296static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
2297{
2298 return !(rt->rt6i_flags & RTF_CACHE) &&
Paolo Abeni1490ed22019-02-15 18:15:37 +01002299 (rt->rt6i_flags & RTF_PCPU || rcu_access_pointer(rt->from));
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002300}
2301
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002302static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
2303 const struct ipv6hdr *iph, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304{
Julian Anastasov0dec8792017-02-06 23:14:16 +02002305 const struct in6_addr *daddr, *saddr;
Ian Morris67ba4152014-08-24 21:53:10 +01002306 struct rt6_info *rt6 = (struct rt6_info *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307
Xin Long19bda362016-10-28 18:18:01 +08002308 if (dst_metric_locked(dst, RTAX_MTU))
2309 return;
2310
Julian Anastasov0dec8792017-02-06 23:14:16 +02002311 if (iph) {
2312 daddr = &iph->daddr;
2313 saddr = &iph->saddr;
2314 } else if (sk) {
2315 daddr = &sk->sk_v6_daddr;
2316 saddr = &inet6_sk(sk)->saddr;
2317 } else {
2318 daddr = NULL;
2319 saddr = NULL;
2320 }
2321 dst_confirm_neigh(dst, daddr);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002322 mtu = max_t(u32, mtu, IPV6_MIN_MTU);
2323 if (mtu >= dst_mtu(dst))
2324 return;
David S. Miller81aded22012-06-15 14:54:11 -07002325
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002326 if (!rt6_cache_allowed_for_pmtu(rt6)) {
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002327 rt6_do_update_pmtu(rt6, mtu);
Wei Wang2b760fc2017-10-06 12:06:03 -07002328 /* update rt6_ex->stamp for cache */
2329 if (rt6->rt6i_flags & RTF_CACHE)
2330 rt6_update_exception_stamp_rt(rt6);
Julian Anastasov0dec8792017-02-06 23:14:16 +02002331 } else if (daddr) {
David Aherna68886a2018-04-20 15:38:02 -07002332 struct fib6_info *from;
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002333 struct rt6_info *nrt6;
Hagen Paul Pfeifer9d289712015-01-15 22:34:25 +01002334
David Ahern4d85cd02018-04-20 15:37:59 -07002335 rcu_read_lock();
David Aherna68886a2018-04-20 15:38:02 -07002336 from = rcu_dereference(rt6->from);
Jonathan Lemon9c69a132019-04-14 14:21:29 -07002337 if (!from) {
2338 rcu_read_unlock();
2339 return;
2340 }
David Aherna68886a2018-04-20 15:38:02 -07002341 nrt6 = ip6_rt_cache_alloc(from, daddr, saddr);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002342 if (nrt6) {
2343 rt6_do_update_pmtu(nrt6, mtu);
David Aherna68886a2018-04-20 15:38:02 -07002344 if (rt6_insert_exception(nrt6, from))
Wei Wang2b760fc2017-10-06 12:06:03 -07002345 dst_release_immediate(&nrt6->dst);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002346 }
David Aherna68886a2018-04-20 15:38:02 -07002347 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 }
2349}
2350
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002351static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
2352 struct sk_buff *skb, u32 mtu)
2353{
2354 __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu);
2355}
2356
David S. Miller42ae66c2012-06-15 20:01:57 -07002357void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002358 int oif, u32 mark, kuid_t uid)
David S. Miller81aded22012-06-15 14:54:11 -07002359{
2360 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
2361 struct dst_entry *dst;
Maciej Żenczykowskidc920952018-09-29 23:44:51 -07002362 struct flowi6 fl6 = {
2363 .flowi6_oif = oif,
2364 .flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark),
2365 .daddr = iph->daddr,
2366 .saddr = iph->saddr,
2367 .flowlabel = ip6_flowinfo(iph),
2368 .flowi6_uid = uid,
2369 };
David S. Miller81aded22012-06-15 14:54:11 -07002370
2371 dst = ip6_route_output(net, NULL, &fl6);
2372 if (!dst->error)
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002373 __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07002374 dst_release(dst);
2375}
2376EXPORT_SYMBOL_GPL(ip6_update_pmtu);
2377
2378void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
2379{
David Ahern7ddacfa2018-11-18 10:45:30 -08002380 int oif = sk->sk_bound_dev_if;
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07002381 struct dst_entry *dst;
2382
David Ahern7ddacfa2018-11-18 10:45:30 -08002383 if (!oif && skb->dev)
2384 oif = l3mdev_master_ifindex(skb->dev);
2385
2386 ip6_update_pmtu(skb, sock_net(sk), mtu, oif, sk->sk_mark, sk->sk_uid);
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07002387
2388 dst = __sk_dst_get(sk);
2389 if (!dst || !dst->obsolete ||
2390 dst->ops->check(dst, inet6_sk(sk)->dst_cookie))
2391 return;
2392
2393 bh_lock_sock(sk);
2394 if (!sock_owned_by_user(sk) && !ipv6_addr_v4mapped(&sk->sk_v6_daddr))
2395 ip6_datagram_dst_update(sk, false);
2396 bh_unlock_sock(sk);
David S. Miller81aded22012-06-15 14:54:11 -07002397}
2398EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
2399
Alexey Kodanev7d6850f2018-04-03 15:00:07 +03002400void ip6_sk_dst_store_flow(struct sock *sk, struct dst_entry *dst,
2401 const struct flowi6 *fl6)
2402{
2403#ifdef CONFIG_IPV6_SUBTREES
2404 struct ipv6_pinfo *np = inet6_sk(sk);
2405#endif
2406
2407 ip6_dst_store(sk, dst,
2408 ipv6_addr_equal(&fl6->daddr, &sk->sk_v6_daddr) ?
2409 &sk->sk_v6_daddr : NULL,
2410#ifdef CONFIG_IPV6_SUBTREES
2411 ipv6_addr_equal(&fl6->saddr, &np->saddr) ?
2412 &np->saddr :
2413#endif
2414 NULL);
2415}
2416
David Ahern0b34eb02019-04-09 14:41:19 -07002417static bool ip6_redirect_nh_match(struct fib6_info *f6i,
2418 struct fib6_nh *nh,
2419 struct flowi6 *fl6,
2420 const struct in6_addr *gw,
2421 struct rt6_info **ret)
2422{
2423 if (nh->fib_nh_flags & RTNH_F_DEAD || !nh->fib_nh_gw_family ||
2424 fl6->flowi6_oif != nh->fib_nh_dev->ifindex)
2425 return false;
2426
2427 /* rt_cache's gateway might be different from its 'parent'
2428 * in the case of an ip redirect.
2429 * So we keep searching in the exception table if the gateway
2430 * is different.
2431 */
2432 if (!ipv6_addr_equal(gw, &nh->fib_nh_gw6)) {
David Ahern7e4b5122019-04-16 14:36:00 -07002433 struct fib6_result res = {
2434 .f6i = f6i,
2435 };
David Ahern0b34eb02019-04-09 14:41:19 -07002436 struct rt6_info *rt_cache;
2437
David Ahern7e4b5122019-04-16 14:36:00 -07002438 rt_cache = rt6_find_cached_rt(&res, &fl6->daddr, &fl6->saddr);
David Ahern0b34eb02019-04-09 14:41:19 -07002439 if (rt_cache &&
2440 ipv6_addr_equal(gw, &rt_cache->rt6i_gateway)) {
2441 *ret = rt_cache;
2442 return true;
2443 }
2444 return false;
2445 }
2446 return true;
2447}
2448
Duan Jiongb55b76b2013-09-04 19:44:21 +08002449/* Handle redirects */
2450struct ip6rd_flowi {
2451 struct flowi6 fl6;
2452 struct in6_addr gateway;
2453};
2454
2455static struct rt6_info *__ip6_route_redirect(struct net *net,
2456 struct fib6_table *table,
2457 struct flowi6 *fl6,
David Ahernb75cc8f2018-03-02 08:32:17 -08002458 const struct sk_buff *skb,
Duan Jiongb55b76b2013-09-04 19:44:21 +08002459 int flags)
2460{
2461 struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
David Ahern0b34eb02019-04-09 14:41:19 -07002462 struct rt6_info *ret = NULL;
David Ahern8d1c8022018-04-17 17:33:26 -07002463 struct fib6_info *rt;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002464 struct fib6_node *fn;
2465
2466 /* Get the "current" route for this destination and
Alexander Alemayhu67c408c2017-01-07 23:53:00 +01002467 * check if the redirect has come from appropriate router.
Duan Jiongb55b76b2013-09-04 19:44:21 +08002468 *
2469 * RFC 4861 specifies that redirects should only be
2470 * accepted if they come from the nexthop to the target.
2471 * Due to the way the routes are chosen, this notion
2472 * is a bit fuzzy and one might need to check all possible
2473 * routes.
2474 */
2475
Wei Wang66f5d6c2017-10-06 12:06:10 -07002476 rcu_read_lock();
David Ahern64547432018-05-09 20:34:19 -07002477 fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002478restart:
Wei Wang66f5d6c2017-10-06 12:06:10 -07002479 for_each_fib6_node_rt_rcu(fn) {
David Ahern14895682018-04-17 17:33:17 -07002480 if (fib6_check_expired(rt))
Duan Jiongb55b76b2013-09-04 19:44:21 +08002481 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07002482 if (rt->fib6_flags & RTF_REJECT)
Duan Jiongb55b76b2013-09-04 19:44:21 +08002483 break;
David Ahern0b34eb02019-04-09 14:41:19 -07002484 if (ip6_redirect_nh_match(rt, &rt->fib6_nh, fl6,
2485 &rdfl->gateway, &ret))
2486 goto out;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002487 }
2488
2489 if (!rt)
David Ahern421842e2018-04-17 17:33:18 -07002490 rt = net->ipv6.fib6_null_entry;
David Ahern93c2fb22018-04-18 15:38:59 -07002491 else if (rt->fib6_flags & RTF_REJECT) {
David Ahern23fb93a2018-04-17 17:33:23 -07002492 ret = net->ipv6.ip6_null_entry;
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08002493 goto out;
2494 }
2495
David Ahern421842e2018-04-17 17:33:18 -07002496 if (rt == net->ipv6.fib6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07002497 fn = fib6_backtrack(fn, &fl6->saddr);
2498 if (fn)
2499 goto restart;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002500 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07002501
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08002502out:
David Ahern23fb93a2018-04-17 17:33:23 -07002503 if (ret)
David Ahern10585b42019-03-20 09:24:50 -07002504 ip6_hold_safe(net, &ret);
David Ahern23fb93a2018-04-17 17:33:23 -07002505 else
2506 ret = ip6_create_rt_rcu(rt);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002507
Wei Wang66f5d6c2017-10-06 12:06:10 -07002508 rcu_read_unlock();
Duan Jiongb55b76b2013-09-04 19:44:21 +08002509
Paolo Abenib65f1642017-10-19 09:31:43 +02002510 trace_fib6_table_lookup(net, rt, table, fl6);
David Ahern23fb93a2018-04-17 17:33:23 -07002511 return ret;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002512};
2513
2514static struct dst_entry *ip6_route_redirect(struct net *net,
David Ahernb75cc8f2018-03-02 08:32:17 -08002515 const struct flowi6 *fl6,
2516 const struct sk_buff *skb,
2517 const struct in6_addr *gateway)
Duan Jiongb55b76b2013-09-04 19:44:21 +08002518{
2519 int flags = RT6_LOOKUP_F_HAS_SADDR;
2520 struct ip6rd_flowi rdfl;
2521
2522 rdfl.fl6 = *fl6;
2523 rdfl.gateway = *gateway;
2524
David Ahernb75cc8f2018-03-02 08:32:17 -08002525 return fib6_rule_lookup(net, &rdfl.fl6, skb,
Duan Jiongb55b76b2013-09-04 19:44:21 +08002526 flags, __ip6_route_redirect);
2527}
2528
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002529void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark,
2530 kuid_t uid)
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002531{
2532 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
2533 struct dst_entry *dst;
Maciej Żenczykowski1f7f10a2018-09-29 23:44:48 -07002534 struct flowi6 fl6 = {
2535 .flowi6_iif = LOOPBACK_IFINDEX,
2536 .flowi6_oif = oif,
2537 .flowi6_mark = mark,
2538 .daddr = iph->daddr,
2539 .saddr = iph->saddr,
2540 .flowlabel = ip6_flowinfo(iph),
2541 .flowi6_uid = uid,
2542 };
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002543
David Ahernb75cc8f2018-03-02 08:32:17 -08002544 dst = ip6_route_redirect(net, &fl6, skb, &ipv6_hdr(skb)->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002545 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002546 dst_release(dst);
2547}
2548EXPORT_SYMBOL_GPL(ip6_redirect);
2549
Maciej Żenczykowskid4563362018-09-29 23:44:50 -07002550void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif)
Duan Jiongc92a59e2013-08-22 12:07:35 +08002551{
2552 const struct ipv6hdr *iph = ipv6_hdr(skb);
2553 const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
2554 struct dst_entry *dst;
Maciej Żenczykowski0b26fb12018-09-29 23:44:49 -07002555 struct flowi6 fl6 = {
2556 .flowi6_iif = LOOPBACK_IFINDEX,
2557 .flowi6_oif = oif,
Maciej Żenczykowski0b26fb12018-09-29 23:44:49 -07002558 .daddr = msg->dest,
2559 .saddr = iph->daddr,
2560 .flowi6_uid = sock_net_uid(net, NULL),
2561 };
Duan Jiongc92a59e2013-08-22 12:07:35 +08002562
David Ahernb75cc8f2018-03-02 08:32:17 -08002563 dst = ip6_route_redirect(net, &fl6, skb, &iph->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002564 rt6_do_redirect(dst, NULL, skb);
Duan Jiongc92a59e2013-08-22 12:07:35 +08002565 dst_release(dst);
2566}
2567
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002568void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
2569{
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002570 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark,
2571 sk->sk_uid);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002572}
2573EXPORT_SYMBOL_GPL(ip6_sk_redirect);
2574
David S. Miller0dbaee32010-12-13 12:52:14 -08002575static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576{
David S. Miller0dbaee32010-12-13 12:52:14 -08002577 struct net_device *dev = dst->dev;
2578 unsigned int mtu = dst_mtu(dst);
2579 struct net *net = dev_net(dev);
2580
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
2582
Daniel Lezcano55786892008-03-04 13:47:47 -08002583 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
2584 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585
2586 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002587 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
2588 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
2589 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 * rely only on pmtu discovery"
2591 */
2592 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
2593 mtu = IPV6_MAXPLEN;
2594 return mtu;
2595}
2596
Steffen Klassertebb762f2011-11-23 02:12:51 +00002597static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08002598{
David S. Millerd33e4552010-12-14 13:01:14 -08002599 struct inet6_dev *idev;
David Ahernd4ead6b2018-04-17 17:33:16 -07002600 unsigned int mtu;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00002601
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002602 mtu = dst_metric_raw(dst, RTAX_MTU);
2603 if (mtu)
2604 goto out;
2605
Steffen Klassert618f9bc2011-11-23 02:13:31 +00002606 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08002607
2608 rcu_read_lock();
2609 idev = __in6_dev_get(dst->dev);
2610 if (idev)
2611 mtu = idev->cnf.mtu6;
2612 rcu_read_unlock();
2613
Eric Dumazet30f78d82014-04-10 21:23:36 -07002614out:
Roopa Prabhu14972cb2016-08-24 20:10:43 -07002615 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
2616
2617 return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
David S. Millerd33e4552010-12-14 13:01:14 -08002618}
2619
David Ahern901731b2018-05-21 09:08:14 -07002620/* MTU selection:
2621 * 1. mtu on route is locked - use it
2622 * 2. mtu from nexthop exception
2623 * 3. mtu from egress device
2624 *
2625 * based on ip6_dst_mtu_forward and exception logic of
2626 * rt6_find_cached_rt; called with rcu_read_lock
2627 */
2628u32 ip6_mtu_from_fib6(struct fib6_info *f6i, struct in6_addr *daddr,
2629 struct in6_addr *saddr)
2630{
2631 struct rt6_exception_bucket *bucket;
2632 struct rt6_exception *rt6_ex;
2633 struct in6_addr *src_key;
2634 struct inet6_dev *idev;
2635 u32 mtu = 0;
2636
2637 if (unlikely(fib6_metric_locked(f6i, RTAX_MTU))) {
2638 mtu = f6i->fib6_pmtu;
2639 if (mtu)
2640 goto out;
2641 }
2642
2643 src_key = NULL;
2644#ifdef CONFIG_IPV6_SUBTREES
2645 if (f6i->fib6_src.plen)
2646 src_key = saddr;
2647#endif
2648
2649 bucket = rcu_dereference(f6i->rt6i_exception_bucket);
2650 rt6_ex = __rt6_find_exception_rcu(&bucket, daddr, src_key);
2651 if (rt6_ex && !rt6_check_expired(rt6_ex->rt6i))
2652 mtu = dst_metric_raw(&rt6_ex->rt6i->dst, RTAX_MTU);
2653
2654 if (likely(!mtu)) {
2655 struct net_device *dev = fib6_info_nh_dev(f6i);
2656
2657 mtu = IPV6_MIN_MTU;
2658 idev = __in6_dev_get(dev);
2659 if (idev && idev->cnf.mtu6 > mtu)
2660 mtu = idev->cnf.mtu6;
2661 }
2662
2663 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
2664out:
2665 return mtu - lwtunnel_headroom(fib6_info_nh_lwt(f6i), mtu);
2666}
2667
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08002668struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05002669 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670{
David S. Miller87a11572011-12-06 17:04:13 -05002671 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 struct rt6_info *rt;
2673 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002674 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675
David S. Miller38308472011-12-03 18:02:47 -05002676 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00002677 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678
Martin KaFai Lauad706862015-08-14 11:05:52 -07002679 rt = ip6_dst_alloc(net, dev, 0);
David S. Miller38308472011-12-03 18:02:47 -05002680 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05002682 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 goto out;
2684 }
2685
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002686 rt->dst.flags |= DST_HOST;
Brendan McGrath588753f2017-12-13 22:14:57 +11002687 rt->dst.input = ip6_input;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002688 rt->dst.output = ip6_output;
Julian Anastasov550bab42013-10-20 15:43:04 +03002689 rt->rt6i_gateway = fl6->daddr;
David S. Miller87a11572011-12-06 17:04:13 -05002690 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002691 rt->rt6i_dst.plen = 128;
2692 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08002693 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694
Ido Schimmel4c981e22018-01-07 12:45:04 +02002695 /* Add this dst into uncached_list so that rt6_disable_ip() can
Wei Wang587fea72017-06-17 10:42:36 -07002696 * do proper release of the net_device
2697 */
2698 rt6_uncached_list_add(rt);
Wei Wang81eb8442017-10-06 12:06:11 -07002699 atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700
David S. Miller87a11572011-12-06 17:04:13 -05002701 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
2702
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703out:
David S. Miller87a11572011-12-06 17:04:13 -05002704 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705}
2706
Daniel Lezcano569d3642008-01-18 03:56:57 -08002707static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708{
Alexey Dobriyan86393e52009-08-29 01:34:49 +00002709 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08002710 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
2711 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
2712 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
2713 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
2714 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00002715 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716
Eric Dumazetfc66f952010-10-08 06:37:34 +00002717 entries = dst_entries_get_fast(ops);
Michal Kubeček49a18d82013-08-01 10:04:24 +02002718 if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00002719 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 goto out;
2721
Benjamin Thery6891a342008-03-04 13:49:47 -08002722 net->ipv6.ip6_rt_gc_expire++;
Li RongQing14956642014-05-19 17:30:28 +08002723 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
Eric Dumazetfc66f952010-10-08 06:37:34 +00002724 entries = dst_entries_get_slow(ops);
2725 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08002726 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08002728 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00002729 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730}
2731
David Ahern8c145862016-04-24 21:26:04 -07002732static struct rt6_info *ip6_nh_lookup_table(struct net *net,
2733 struct fib6_config *cfg,
David Ahernf4797b32018-01-25 16:55:08 -08002734 const struct in6_addr *gw_addr,
2735 u32 tbid, int flags)
David Ahern8c145862016-04-24 21:26:04 -07002736{
2737 struct flowi6 fl6 = {
2738 .flowi6_oif = cfg->fc_ifindex,
2739 .daddr = *gw_addr,
2740 .saddr = cfg->fc_prefsrc,
2741 };
2742 struct fib6_table *table;
2743 struct rt6_info *rt;
David Ahern8c145862016-04-24 21:26:04 -07002744
David Ahernf4797b32018-01-25 16:55:08 -08002745 table = fib6_get_table(net, tbid);
David Ahern8c145862016-04-24 21:26:04 -07002746 if (!table)
2747 return NULL;
2748
2749 if (!ipv6_addr_any(&cfg->fc_prefsrc))
2750 flags |= RT6_LOOKUP_F_HAS_SADDR;
2751
David Ahernf4797b32018-01-25 16:55:08 -08002752 flags |= RT6_LOOKUP_F_IGNORE_LINKSTATE;
David Ahernb75cc8f2018-03-02 08:32:17 -08002753 rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, NULL, flags);
David Ahern8c145862016-04-24 21:26:04 -07002754
2755 /* if table lookup failed, fall back to full lookup */
2756 if (rt == net->ipv6.ip6_null_entry) {
2757 ip6_rt_put(rt);
2758 rt = NULL;
2759 }
2760
2761 return rt;
2762}
2763
David Ahernfc1e64e2018-01-25 16:55:09 -08002764static int ip6_route_check_nh_onlink(struct net *net,
2765 struct fib6_config *cfg,
David Ahern9fbb7042018-03-13 08:29:36 -07002766 const struct net_device *dev,
David Ahernfc1e64e2018-01-25 16:55:09 -08002767 struct netlink_ext_ack *extack)
2768{
David Ahern44750f82018-02-06 13:17:06 -08002769 u32 tbid = l3mdev_fib_table(dev) ? : RT_TABLE_MAIN;
David Ahernfc1e64e2018-01-25 16:55:09 -08002770 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2771 u32 flags = RTF_LOCAL | RTF_ANYCAST | RTF_REJECT;
Paolo Abenibf1dc8b2019-02-21 11:19:42 +01002772 struct fib6_info *from;
David Ahernfc1e64e2018-01-25 16:55:09 -08002773 struct rt6_info *grt;
2774 int err;
2775
2776 err = 0;
2777 grt = ip6_nh_lookup_table(net, cfg, gw_addr, tbid, 0);
2778 if (grt) {
Paolo Abenibf1dc8b2019-02-21 11:19:42 +01002779 rcu_read_lock();
2780 from = rcu_dereference(grt->from);
David Ahern58e354c2018-02-06 12:14:12 -08002781 if (!grt->dst.error &&
David Ahern4ed591c2018-10-24 13:58:39 -07002782 /* ignore match if it is the default route */
Paolo Abenibf1dc8b2019-02-21 11:19:42 +01002783 from && !ipv6_addr_any(&from->fib6_dst.addr) &&
David Ahern58e354c2018-02-06 12:14:12 -08002784 (grt->rt6i_flags & flags || dev != grt->dst.dev)) {
David Ahern44750f82018-02-06 13:17:06 -08002785 NL_SET_ERR_MSG(extack,
2786 "Nexthop has invalid gateway or device mismatch");
David Ahernfc1e64e2018-01-25 16:55:09 -08002787 err = -EINVAL;
2788 }
Paolo Abenibf1dc8b2019-02-21 11:19:42 +01002789 rcu_read_unlock();
David Ahernfc1e64e2018-01-25 16:55:09 -08002790
2791 ip6_rt_put(grt);
2792 }
2793
2794 return err;
2795}
2796
David Ahern1edce992018-01-25 16:55:07 -08002797static int ip6_route_check_nh(struct net *net,
2798 struct fib6_config *cfg,
2799 struct net_device **_dev,
2800 struct inet6_dev **idev)
2801{
2802 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2803 struct net_device *dev = _dev ? *_dev : NULL;
2804 struct rt6_info *grt = NULL;
2805 int err = -EHOSTUNREACH;
2806
2807 if (cfg->fc_table) {
David Ahernf4797b32018-01-25 16:55:08 -08002808 int flags = RT6_LOOKUP_F_IFACE;
2809
2810 grt = ip6_nh_lookup_table(net, cfg, gw_addr,
2811 cfg->fc_table, flags);
David Ahern1edce992018-01-25 16:55:07 -08002812 if (grt) {
2813 if (grt->rt6i_flags & RTF_GATEWAY ||
2814 (dev && dev != grt->dst.dev)) {
2815 ip6_rt_put(grt);
2816 grt = NULL;
2817 }
2818 }
2819 }
2820
2821 if (!grt)
David Ahernb75cc8f2018-03-02 08:32:17 -08002822 grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, NULL, 1);
David Ahern1edce992018-01-25 16:55:07 -08002823
2824 if (!grt)
2825 goto out;
2826
2827 if (dev) {
2828 if (dev != grt->dst.dev) {
2829 ip6_rt_put(grt);
2830 goto out;
2831 }
2832 } else {
2833 *_dev = dev = grt->dst.dev;
2834 *idev = grt->rt6i_idev;
2835 dev_hold(dev);
2836 in6_dev_hold(grt->rt6i_idev);
2837 }
2838
2839 if (!(grt->rt6i_flags & RTF_GATEWAY))
2840 err = 0;
2841
2842 ip6_rt_put(grt);
2843
2844out:
2845 return err;
2846}
2847
David Ahern9fbb7042018-03-13 08:29:36 -07002848static int ip6_validate_gw(struct net *net, struct fib6_config *cfg,
2849 struct net_device **_dev, struct inet6_dev **idev,
2850 struct netlink_ext_ack *extack)
2851{
2852 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2853 int gwa_type = ipv6_addr_type(gw_addr);
David Ahern232378e2018-03-13 08:29:37 -07002854 bool skip_dev = gwa_type & IPV6_ADDR_LINKLOCAL ? false : true;
David Ahern9fbb7042018-03-13 08:29:36 -07002855 const struct net_device *dev = *_dev;
David Ahern232378e2018-03-13 08:29:37 -07002856 bool need_addr_check = !dev;
David Ahern9fbb7042018-03-13 08:29:36 -07002857 int err = -EINVAL;
2858
2859 /* if gw_addr is local we will fail to detect this in case
2860 * address is still TENTATIVE (DAD in progress). rt6_lookup()
2861 * will return already-added prefix route via interface that
2862 * prefix route was assigned to, which might be non-loopback.
2863 */
David Ahern232378e2018-03-13 08:29:37 -07002864 if (dev &&
2865 ipv6_chk_addr_and_flags(net, gw_addr, dev, skip_dev, 0, 0)) {
2866 NL_SET_ERR_MSG(extack, "Gateway can not be a local address");
David Ahern9fbb7042018-03-13 08:29:36 -07002867 goto out;
2868 }
2869
2870 if (gwa_type != (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST)) {
2871 /* IPv6 strictly inhibits using not link-local
2872 * addresses as nexthop address.
2873 * Otherwise, router will not able to send redirects.
2874 * It is very good, but in some (rare!) circumstances
2875 * (SIT, PtP, NBMA NOARP links) it is handy to allow
2876 * some exceptions. --ANK
2877 * We allow IPv4-mapped nexthops to support RFC4798-type
2878 * addressing
2879 */
2880 if (!(gwa_type & (IPV6_ADDR_UNICAST | IPV6_ADDR_MAPPED))) {
2881 NL_SET_ERR_MSG(extack, "Invalid gateway address");
2882 goto out;
2883 }
2884
2885 if (cfg->fc_flags & RTNH_F_ONLINK)
2886 err = ip6_route_check_nh_onlink(net, cfg, dev, extack);
2887 else
2888 err = ip6_route_check_nh(net, cfg, _dev, idev);
2889
2890 if (err)
2891 goto out;
2892 }
2893
2894 /* reload in case device was changed */
2895 dev = *_dev;
2896
2897 err = -EINVAL;
2898 if (!dev) {
2899 NL_SET_ERR_MSG(extack, "Egress device not specified");
2900 goto out;
2901 } else if (dev->flags & IFF_LOOPBACK) {
2902 NL_SET_ERR_MSG(extack,
2903 "Egress device can not be loopback device for this route");
2904 goto out;
2905 }
David Ahern232378e2018-03-13 08:29:37 -07002906
2907 /* if we did not check gw_addr above, do so now that the
2908 * egress device has been resolved.
2909 */
2910 if (need_addr_check &&
2911 ipv6_chk_addr_and_flags(net, gw_addr, dev, skip_dev, 0, 0)) {
2912 NL_SET_ERR_MSG(extack, "Gateway can not be a local address");
2913 goto out;
2914 }
2915
David Ahern9fbb7042018-03-13 08:29:36 -07002916 err = 0;
2917out:
2918 return err;
2919}
2920
David Ahern83c442512019-03-27 20:53:50 -07002921static bool fib6_is_reject(u32 flags, struct net_device *dev, int addr_type)
2922{
2923 if ((flags & RTF_REJECT) ||
2924 (dev && (dev->flags & IFF_LOOPBACK) &&
2925 !(addr_type & IPV6_ADDR_LOOPBACK) &&
2926 !(flags & RTF_LOCAL)))
2927 return true;
2928
2929 return false;
2930}
2931
2932int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
2933 struct fib6_config *cfg, gfp_t gfp_flags,
2934 struct netlink_ext_ack *extack)
2935{
2936 struct net_device *dev = NULL;
2937 struct inet6_dev *idev = NULL;
2938 int addr_type;
2939 int err;
2940
David Ahernf1741732019-03-27 20:53:57 -07002941 fib6_nh->fib_nh_family = AF_INET6;
2942
David Ahern83c442512019-03-27 20:53:50 -07002943 err = -ENODEV;
2944 if (cfg->fc_ifindex) {
2945 dev = dev_get_by_index(net, cfg->fc_ifindex);
2946 if (!dev)
2947 goto out;
2948 idev = in6_dev_get(dev);
2949 if (!idev)
2950 goto out;
2951 }
2952
2953 if (cfg->fc_flags & RTNH_F_ONLINK) {
2954 if (!dev) {
2955 NL_SET_ERR_MSG(extack,
2956 "Nexthop device required for onlink");
2957 goto out;
2958 }
2959
2960 if (!(dev->flags & IFF_UP)) {
2961 NL_SET_ERR_MSG(extack, "Nexthop device is not up");
2962 err = -ENETDOWN;
2963 goto out;
2964 }
2965
David Ahernad1601a2019-03-27 20:53:56 -07002966 fib6_nh->fib_nh_flags |= RTNH_F_ONLINK;
David Ahern83c442512019-03-27 20:53:50 -07002967 }
2968
David Ahernad1601a2019-03-27 20:53:56 -07002969 fib6_nh->fib_nh_weight = 1;
David Ahern83c442512019-03-27 20:53:50 -07002970
2971 /* We cannot add true routes via loopback here,
2972 * they would result in kernel looping; promote them to reject routes
2973 */
2974 addr_type = ipv6_addr_type(&cfg->fc_dst);
2975 if (fib6_is_reject(cfg->fc_flags, dev, addr_type)) {
2976 /* hold loopback dev/idev if we haven't done so. */
2977 if (dev != net->loopback_dev) {
2978 if (dev) {
2979 dev_put(dev);
2980 in6_dev_put(idev);
2981 }
2982 dev = net->loopback_dev;
2983 dev_hold(dev);
2984 idev = in6_dev_get(dev);
2985 if (!idev) {
2986 err = -ENODEV;
2987 goto out;
2988 }
2989 }
2990 goto set_dev;
2991 }
2992
2993 if (cfg->fc_flags & RTF_GATEWAY) {
2994 err = ip6_validate_gw(net, cfg, &dev, &idev, extack);
2995 if (err)
2996 goto out;
2997
David Ahernad1601a2019-03-27 20:53:56 -07002998 fib6_nh->fib_nh_gw6 = cfg->fc_gateway;
David Ahernbdf00462019-04-05 16:30:26 -07002999 fib6_nh->fib_nh_gw_family = AF_INET6;
David Ahern83c442512019-03-27 20:53:50 -07003000 }
3001
3002 err = -ENODEV;
3003 if (!dev)
3004 goto out;
3005
3006 if (idev->cnf.disable_ipv6) {
3007 NL_SET_ERR_MSG(extack, "IPv6 is disabled on nexthop device");
3008 err = -EACCES;
3009 goto out;
3010 }
3011
3012 if (!(dev->flags & IFF_UP) && !cfg->fc_ignore_dev_down) {
3013 NL_SET_ERR_MSG(extack, "Nexthop device is not up");
3014 err = -ENETDOWN;
3015 goto out;
3016 }
3017
3018 if (!(cfg->fc_flags & (RTF_LOCAL | RTF_ANYCAST)) &&
3019 !netif_carrier_ok(dev))
David Ahernad1601a2019-03-27 20:53:56 -07003020 fib6_nh->fib_nh_flags |= RTNH_F_LINKDOWN;
David Ahern83c442512019-03-27 20:53:50 -07003021
David Ahern979e2762019-03-27 20:53:58 -07003022 err = fib_nh_common_init(&fib6_nh->nh_common, cfg->fc_encap,
3023 cfg->fc_encap_type, cfg, gfp_flags, extack);
3024 if (err)
3025 goto out;
David Ahern83c442512019-03-27 20:53:50 -07003026set_dev:
David Ahernad1601a2019-03-27 20:53:56 -07003027 fib6_nh->fib_nh_dev = dev;
David Ahernf1741732019-03-27 20:53:57 -07003028 fib6_nh->fib_nh_oif = dev->ifindex;
David Ahern83c442512019-03-27 20:53:50 -07003029 err = 0;
3030out:
3031 if (idev)
3032 in6_dev_put(idev);
3033
3034 if (err) {
David Ahernad1601a2019-03-27 20:53:56 -07003035 lwtstate_put(fib6_nh->fib_nh_lws);
3036 fib6_nh->fib_nh_lws = NULL;
David Ahern83c442512019-03-27 20:53:50 -07003037 if (dev)
3038 dev_put(dev);
3039 }
3040
3041 return err;
3042}
3043
David Aherndac7d0f2019-03-27 20:53:51 -07003044void fib6_nh_release(struct fib6_nh *fib6_nh)
3045{
David Ahern979e2762019-03-27 20:53:58 -07003046 fib_nh_common_release(&fib6_nh->nh_common);
David Aherndac7d0f2019-03-27 20:53:51 -07003047}
3048
David Ahern8d1c8022018-04-17 17:33:26 -07003049static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
David Ahernacb54e32018-04-17 17:33:22 -07003050 gfp_t gfp_flags,
David Ahern333c4302017-05-21 10:12:04 -06003051 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052{
Daniel Lezcano55786892008-03-04 13:47:47 -08003053 struct net *net = cfg->fc_nlinfo.nl_net;
David Ahern8d1c8022018-04-17 17:33:26 -07003054 struct fib6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07003055 struct fib6_table *table;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003056 int err = -EINVAL;
David Ahern83c442512019-03-27 20:53:50 -07003057 int addr_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058
David Ahern557c44b2017-04-19 14:19:43 -07003059 /* RTF_PCPU is an internal flag; can not be set by userspace */
David Ahernd5d531c2017-05-21 10:12:05 -06003060 if (cfg->fc_flags & RTF_PCPU) {
3061 NL_SET_ERR_MSG(extack, "Userspace can not set RTF_PCPU");
David Ahern557c44b2017-04-19 14:19:43 -07003062 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06003063 }
David Ahern557c44b2017-04-19 14:19:43 -07003064
Wei Wang2ea23522017-10-27 17:30:12 -07003065 /* RTF_CACHE is an internal flag; can not be set by userspace */
3066 if (cfg->fc_flags & RTF_CACHE) {
3067 NL_SET_ERR_MSG(extack, "Userspace can not set RTF_CACHE");
3068 goto out;
3069 }
3070
David Aherne8478e82018-04-17 17:33:13 -07003071 if (cfg->fc_type > RTN_MAX) {
3072 NL_SET_ERR_MSG(extack, "Invalid route type");
3073 goto out;
3074 }
3075
David Ahernd5d531c2017-05-21 10:12:05 -06003076 if (cfg->fc_dst_len > 128) {
3077 NL_SET_ERR_MSG(extack, "Invalid prefix length");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003078 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06003079 }
3080 if (cfg->fc_src_len > 128) {
3081 NL_SET_ERR_MSG(extack, "Invalid source address length");
3082 goto out;
3083 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084#ifndef CONFIG_IPV6_SUBTREES
David Ahernd5d531c2017-05-21 10:12:05 -06003085 if (cfg->fc_src_len) {
3086 NL_SET_ERR_MSG(extack,
3087 "Specifying source address requires IPV6_SUBTREES to be enabled");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003088 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06003089 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090#endif
David Ahernfc1e64e2018-01-25 16:55:09 -08003091
Matti Vaittinend71314b2011-11-14 00:14:49 +00003092 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05003093 if (cfg->fc_nlinfo.nlh &&
3094 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00003095 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05003096 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00003097 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00003098 table = fib6_new_table(net, cfg->fc_table);
3099 }
3100 } else {
3101 table = fib6_new_table(net, cfg->fc_table);
3102 }
David S. Miller38308472011-12-03 18:02:47 -05003103
3104 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07003105 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07003106
David Ahern93531c62018-04-17 17:33:25 -07003107 err = -ENOMEM;
3108 rt = fib6_info_alloc(gfp_flags);
3109 if (!rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 goto out;
David Ahern93531c62018-04-17 17:33:25 -07003111
David Ahernd7e774f2018-11-06 12:51:15 -08003112 rt->fib6_metrics = ip_fib_metrics_init(net, cfg->fc_mx, cfg->fc_mx_len,
3113 extack);
David Ahern767a2212018-10-04 20:07:51 -07003114 if (IS_ERR(rt->fib6_metrics)) {
3115 err = PTR_ERR(rt->fib6_metrics);
Eric Dumazetfda21d42018-10-05 09:17:50 -07003116 /* Do not leave garbage there. */
3117 rt->fib6_metrics = (struct dst_metrics *)&dst_default_metrics;
David Ahern767a2212018-10-04 20:07:51 -07003118 goto out;
3119 }
3120
David Ahern93531c62018-04-17 17:33:25 -07003121 if (cfg->fc_flags & RTF_ADDRCONF)
3122 rt->dst_nocount = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123
Gao feng1716a962012-04-06 00:13:10 +00003124 if (cfg->fc_flags & RTF_EXPIRES)
David Ahern14895682018-04-17 17:33:17 -07003125 fib6_set_expires(rt, jiffies +
Gao feng1716a962012-04-06 00:13:10 +00003126 clock_t_to_jiffies(cfg->fc_expires));
3127 else
David Ahern14895682018-04-17 17:33:17 -07003128 fib6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129
Thomas Graf86872cb2006-08-22 00:01:08 -07003130 if (cfg->fc_protocol == RTPROT_UNSPEC)
3131 cfg->fc_protocol = RTPROT_BOOT;
David Ahern93c2fb22018-04-18 15:38:59 -07003132 rt->fib6_protocol = cfg->fc_protocol;
Thomas Graf86872cb2006-08-22 00:01:08 -07003133
David Ahern83c442512019-03-27 20:53:50 -07003134 rt->fib6_table = table;
3135 rt->fib6_metric = cfg->fc_metric;
3136 rt->fib6_type = cfg->fc_type;
David Ahern2b2450c2019-03-27 20:53:52 -07003137 rt->fib6_flags = cfg->fc_flags & ~RTF_GATEWAY;
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003138
David Ahern93c2fb22018-04-18 15:38:59 -07003139 ipv6_addr_prefix(&rt->fib6_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
3140 rt->fib6_dst.plen = cfg->fc_dst_len;
3141 if (rt->fib6_dst.plen == 128)
David Ahern3b6761d2018-04-17 17:33:20 -07003142 rt->dst_host = true;
Michal Kubečeke5fd3872014-03-27 13:04:08 +01003143
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144#ifdef CONFIG_IPV6_SUBTREES
David Ahern93c2fb22018-04-18 15:38:59 -07003145 ipv6_addr_prefix(&rt->fib6_src.addr, &cfg->fc_src, cfg->fc_src_len);
3146 rt->fib6_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147#endif
David Ahern83c442512019-03-27 20:53:50 -07003148 err = fib6_nh_init(net, &rt->fib6_nh, cfg, gfp_flags, extack);
3149 if (err)
3150 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151
3152 /* We cannot add true routes via loopback here,
David Ahern83c442512019-03-27 20:53:50 -07003153 * they would result in kernel looping; promote them to reject routes
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 */
David Ahern83c442512019-03-27 20:53:50 -07003155 addr_type = ipv6_addr_type(&cfg->fc_dst);
David Ahernad1601a2019-03-27 20:53:56 -07003156 if (fib6_is_reject(cfg->fc_flags, rt->fib6_nh.fib_nh_dev, addr_type))
David Ahern83c442512019-03-27 20:53:50 -07003157 rt->fib6_flags = RTF_REJECT | RTF_NONEXTHOP;
David Ahern955ec4c2018-01-24 19:45:29 -08003158
Daniel Walterc3968a82011-04-13 21:10:57 +00003159 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
David Ahern83c442512019-03-27 20:53:50 -07003160 struct net_device *dev = fib6_info_nh_dev(rt);
3161
Daniel Walterc3968a82011-04-13 21:10:57 +00003162 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
David Ahernd5d531c2017-05-21 10:12:05 -06003163 NL_SET_ERR_MSG(extack, "Invalid source address");
Daniel Walterc3968a82011-04-13 21:10:57 +00003164 err = -EINVAL;
3165 goto out;
3166 }
David Ahern93c2fb22018-04-18 15:38:59 -07003167 rt->fib6_prefsrc.addr = cfg->fc_prefsrc;
3168 rt->fib6_prefsrc.plen = 128;
Daniel Walterc3968a82011-04-13 21:10:57 +00003169 } else
David Ahern93c2fb22018-04-18 15:38:59 -07003170 rt->fib6_prefsrc.plen = 0;
Daniel Walterc3968a82011-04-13 21:10:57 +00003171
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003172 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173out:
David Ahern93531c62018-04-17 17:33:25 -07003174 fib6_info_release(rt);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003175 return ERR_PTR(err);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003176}
3177
David Ahernacb54e32018-04-17 17:33:22 -07003178int ip6_route_add(struct fib6_config *cfg, gfp_t gfp_flags,
David Ahern333c4302017-05-21 10:12:04 -06003179 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003180{
David Ahern8d1c8022018-04-17 17:33:26 -07003181 struct fib6_info *rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003182 int err;
3183
David Ahernacb54e32018-04-17 17:33:22 -07003184 rt = ip6_route_info_create(cfg, gfp_flags, extack);
David Ahernd4ead6b2018-04-17 17:33:16 -07003185 if (IS_ERR(rt))
3186 return PTR_ERR(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003187
David Ahernd4ead6b2018-04-17 17:33:16 -07003188 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack);
David Ahern93531c62018-04-17 17:33:25 -07003189 fib6_info_release(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003190
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 return err;
3192}
3193
David Ahern8d1c8022018-04-17 17:33:26 -07003194static int __ip6_del_rt(struct fib6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195{
David Ahernafb1d4b52018-04-17 17:33:11 -07003196 struct net *net = info->nl_net;
Thomas Grafc71099a2006-08-04 23:20:06 -07003197 struct fib6_table *table;
David Ahernafb1d4b52018-04-17 17:33:11 -07003198 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199
David Ahern421842e2018-04-17 17:33:18 -07003200 if (rt == net->ipv6.fib6_null_entry) {
Gao feng6825a262012-09-19 19:25:34 +00003201 err = -ENOENT;
3202 goto out;
3203 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07003204
David Ahern93c2fb22018-04-18 15:38:59 -07003205 table = rt->fib6_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003206 spin_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07003207 err = fib6_del(rt, info);
Wei Wang66f5d6c2017-10-06 12:06:10 -07003208 spin_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209
Gao feng6825a262012-09-19 19:25:34 +00003210out:
David Ahern93531c62018-04-17 17:33:25 -07003211 fib6_info_release(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212 return err;
3213}
3214
David Ahern8d1c8022018-04-17 17:33:26 -07003215int ip6_del_rt(struct net *net, struct fib6_info *rt)
Thomas Grafe0a1ad732006-08-22 00:00:21 -07003216{
David Ahernafb1d4b52018-04-17 17:33:11 -07003217 struct nl_info info = { .nl_net = net };
3218
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003219 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07003220}
3221
David Ahern8d1c8022018-04-17 17:33:26 -07003222static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg)
David Ahern0ae81332017-02-02 12:37:08 -08003223{
3224 struct nl_info *info = &cfg->fc_nlinfo;
WANG Conge3330032017-02-27 16:07:43 -08003225 struct net *net = info->nl_net;
David Ahern16a16cd2017-02-02 12:37:11 -08003226 struct sk_buff *skb = NULL;
David Ahern0ae81332017-02-02 12:37:08 -08003227 struct fib6_table *table;
WANG Conge3330032017-02-27 16:07:43 -08003228 int err = -ENOENT;
David Ahern0ae81332017-02-02 12:37:08 -08003229
David Ahern421842e2018-04-17 17:33:18 -07003230 if (rt == net->ipv6.fib6_null_entry)
WANG Conge3330032017-02-27 16:07:43 -08003231 goto out_put;
David Ahern93c2fb22018-04-18 15:38:59 -07003232 table = rt->fib6_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003233 spin_lock_bh(&table->tb6_lock);
David Ahern0ae81332017-02-02 12:37:08 -08003234
David Ahern93c2fb22018-04-18 15:38:59 -07003235 if (rt->fib6_nsiblings && cfg->fc_delete_all_nh) {
David Ahern8d1c8022018-04-17 17:33:26 -07003236 struct fib6_info *sibling, *next_sibling;
David Ahern0ae81332017-02-02 12:37:08 -08003237
David Ahern16a16cd2017-02-02 12:37:11 -08003238 /* prefer to send a single notification with all hops */
3239 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
3240 if (skb) {
3241 u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
3242
David Ahernd4ead6b2018-04-17 17:33:16 -07003243 if (rt6_fill_node(net, skb, rt, NULL,
David Ahern16a16cd2017-02-02 12:37:11 -08003244 NULL, NULL, 0, RTM_DELROUTE,
3245 info->portid, seq, 0) < 0) {
3246 kfree_skb(skb);
3247 skb = NULL;
3248 } else
3249 info->skip_notify = 1;
3250 }
3251
David Ahern0ae81332017-02-02 12:37:08 -08003252 list_for_each_entry_safe(sibling, next_sibling,
David Ahern93c2fb22018-04-18 15:38:59 -07003253 &rt->fib6_siblings,
3254 fib6_siblings) {
David Ahern0ae81332017-02-02 12:37:08 -08003255 err = fib6_del(sibling, info);
3256 if (err)
WANG Conge3330032017-02-27 16:07:43 -08003257 goto out_unlock;
David Ahern0ae81332017-02-02 12:37:08 -08003258 }
3259 }
3260
3261 err = fib6_del(rt, info);
WANG Conge3330032017-02-27 16:07:43 -08003262out_unlock:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003263 spin_unlock_bh(&table->tb6_lock);
WANG Conge3330032017-02-27 16:07:43 -08003264out_put:
David Ahern93531c62018-04-17 17:33:25 -07003265 fib6_info_release(rt);
David Ahern16a16cd2017-02-02 12:37:11 -08003266
3267 if (skb) {
WANG Conge3330032017-02-27 16:07:43 -08003268 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
David Ahern16a16cd2017-02-02 12:37:11 -08003269 info->nlh, gfp_any());
3270 }
David Ahern0ae81332017-02-02 12:37:08 -08003271 return err;
3272}
3273
David Ahern23fb93a2018-04-17 17:33:23 -07003274static int ip6_del_cached_rt(struct rt6_info *rt, struct fib6_config *cfg)
3275{
3276 int rc = -ESRCH;
3277
3278 if (cfg->fc_ifindex && rt->dst.dev->ifindex != cfg->fc_ifindex)
3279 goto out;
3280
3281 if (cfg->fc_flags & RTF_GATEWAY &&
3282 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
3283 goto out;
Xin Long761f6022018-11-14 00:48:28 +08003284
3285 rc = rt6_remove_exception_rt(rt);
David Ahern23fb93a2018-04-17 17:33:23 -07003286out:
3287 return rc;
3288}
3289
David Ahern333c4302017-05-21 10:12:04 -06003290static int ip6_route_del(struct fib6_config *cfg,
3291 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292{
David Ahern8d1c8022018-04-17 17:33:26 -07003293 struct rt6_info *rt_cache;
Thomas Grafc71099a2006-08-04 23:20:06 -07003294 struct fib6_table *table;
David Ahern8d1c8022018-04-17 17:33:26 -07003295 struct fib6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296 struct fib6_node *fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297 int err = -ESRCH;
3298
Daniel Lezcano55786892008-03-04 13:47:47 -08003299 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David Ahernd5d531c2017-05-21 10:12:05 -06003300 if (!table) {
3301 NL_SET_ERR_MSG(extack, "FIB table does not exist");
Thomas Grafc71099a2006-08-04 23:20:06 -07003302 return err;
David Ahernd5d531c2017-05-21 10:12:05 -06003303 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304
Wei Wang66f5d6c2017-10-06 12:06:10 -07003305 rcu_read_lock();
Thomas Grafc71099a2006-08-04 23:20:06 -07003306
3307 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07003308 &cfg->fc_dst, cfg->fc_dst_len,
Wei Wang38fbeee2017-10-06 12:06:02 -07003309 &cfg->fc_src, cfg->fc_src_len,
Wei Wang2b760fc2017-10-06 12:06:03 -07003310 !(cfg->fc_flags & RTF_CACHE));
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003311
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 if (fn) {
Wei Wang66f5d6c2017-10-06 12:06:10 -07003313 for_each_fib6_node_rt_rcu(fn) {
David Ahernad1601a2019-03-27 20:53:56 -07003314 struct fib6_nh *nh;
3315
Wei Wang2b760fc2017-10-06 12:06:03 -07003316 if (cfg->fc_flags & RTF_CACHE) {
David Ahern7e4b5122019-04-16 14:36:00 -07003317 struct fib6_result res = {
3318 .f6i = rt,
3319 };
David Ahern23fb93a2018-04-17 17:33:23 -07003320 int rc;
3321
David Ahern7e4b5122019-04-16 14:36:00 -07003322 rt_cache = rt6_find_cached_rt(&res,
3323 &cfg->fc_dst,
Wei Wang2b760fc2017-10-06 12:06:03 -07003324 &cfg->fc_src);
David Ahern23fb93a2018-04-17 17:33:23 -07003325 if (rt_cache) {
3326 rc = ip6_del_cached_rt(rt_cache, cfg);
Eric Dumazet9e575012018-05-09 10:05:46 -07003327 if (rc != -ESRCH) {
3328 rcu_read_unlock();
David Ahern23fb93a2018-04-17 17:33:23 -07003329 return rc;
Eric Dumazet9e575012018-05-09 10:05:46 -07003330 }
David Ahern23fb93a2018-04-17 17:33:23 -07003331 }
3332 continue;
Wei Wang2b760fc2017-10-06 12:06:03 -07003333 }
David Ahernad1601a2019-03-27 20:53:56 -07003334
3335 nh = &rt->fib6_nh;
Thomas Graf86872cb2006-08-22 00:01:08 -07003336 if (cfg->fc_ifindex &&
David Ahernad1601a2019-03-27 20:53:56 -07003337 (!nh->fib_nh_dev ||
3338 nh->fib_nh_dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07003340 if (cfg->fc_flags & RTF_GATEWAY &&
David Ahernad1601a2019-03-27 20:53:56 -07003341 !ipv6_addr_equal(&cfg->fc_gateway, &nh->fib_nh_gw6))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07003343 if (cfg->fc_metric && cfg->fc_metric != rt->fib6_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07003345 if (cfg->fc_protocol && cfg->fc_protocol != rt->fib6_protocol)
Mantas Mc2ed1882016-12-16 10:30:59 +02003346 continue;
Wei Wange873e4b2018-07-21 20:56:32 -07003347 if (!fib6_info_hold_safe(rt))
3348 continue;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003349 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350
David Ahern0ae81332017-02-02 12:37:08 -08003351 /* if gateway was specified only delete the one hop */
3352 if (cfg->fc_flags & RTF_GATEWAY)
3353 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
3354
3355 return __ip6_del_rt_siblings(rt, cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 }
3357 }
Wei Wang66f5d6c2017-10-06 12:06:10 -07003358 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359
3360 return err;
3361}
3362
David S. Miller6700c272012-07-17 03:29:28 -07003363static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07003364{
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07003365 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07003366 struct rt6_info *rt, *nrt = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07003367 struct ndisc_options ndopts;
3368 struct inet6_dev *in6_dev;
3369 struct neighbour *neigh;
David Aherna68886a2018-04-20 15:38:02 -07003370 struct fib6_info *from;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003371 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07003372 int optlen, on_link;
3373 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07003374
Simon Horman29a3cad2013-05-28 20:34:26 +00003375 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003376 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07003377
3378 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07003379 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003380 return;
3381 }
3382
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003383 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07003384
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003385 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07003386 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003387 return;
3388 }
3389
David S. Miller6e157b62012-07-12 00:05:02 -07003390 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003391 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07003392 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003393 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07003394 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07003395 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003396 return;
3397 }
3398
3399 in6_dev = __in6_dev_get(skb->dev);
3400 if (!in6_dev)
3401 return;
3402 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
3403 return;
3404
3405 /* RFC2461 8.1:
3406 * The IP source address of the Redirect MUST be the same as the current
3407 * first-hop router for the specified ICMP Destination Address.
3408 */
3409
Alexander Aringf997c552016-06-15 21:20:23 +02003410 if (!ndisc_parse_options(skb->dev, msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07003411 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
3412 return;
3413 }
David S. Miller6e157b62012-07-12 00:05:02 -07003414
3415 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07003416 if (ndopts.nd_opts_tgt_lladdr) {
3417 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
3418 skb->dev);
3419 if (!lladdr) {
3420 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
3421 return;
3422 }
3423 }
3424
David S. Miller6e157b62012-07-12 00:05:02 -07003425 rt = (struct rt6_info *) dst;
Matthias Schifferec13ad12015-11-02 01:24:38 +01003426 if (rt->rt6i_flags & RTF_REJECT) {
David S. Miller6e157b62012-07-12 00:05:02 -07003427 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
3428 return;
3429 }
3430
3431 /* Redirect received -> path was valid.
3432 * Look, redirects are sent only in response to data packets,
3433 * so that this nexthop apparently is reachable. --ANK
3434 */
Julian Anastasov0dec8792017-02-06 23:14:16 +02003435 dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
David S. Miller6e157b62012-07-12 00:05:02 -07003436
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003437 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07003438 if (!neigh)
3439 return;
3440
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441 /*
3442 * We have finally decided to accept it.
3443 */
3444
Alexander Aringf997c552016-06-15 21:20:23 +02003445 ndisc_update(skb->dev, neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 NEIGH_UPDATE_F_WEAK_OVERRIDE|
3447 NEIGH_UPDATE_F_OVERRIDE|
3448 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
Alexander Aringf997c552016-06-15 21:20:23 +02003449 NEIGH_UPDATE_F_ISROUTER)),
3450 NDISC_REDIRECT, &ndopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451
David Ahern4d85cd02018-04-20 15:37:59 -07003452 rcu_read_lock();
David Aherna68886a2018-04-20 15:38:02 -07003453 from = rcu_dereference(rt->from);
Wei Wange873e4b2018-07-21 20:56:32 -07003454 /* This fib6_info_hold() is safe here because we hold reference to rt
3455 * and rt already holds reference to fib6_info.
3456 */
David Ahern8a14e462018-04-23 11:32:07 -07003457 fib6_info_hold(from);
David Ahern4d85cd02018-04-20 15:37:59 -07003458 rcu_read_unlock();
David Ahern8a14e462018-04-23 11:32:07 -07003459
3460 nrt = ip6_rt_cache_alloc(from, &msg->dest, NULL);
David S. Miller38308472011-12-03 18:02:47 -05003461 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462 goto out;
3463
3464 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
3465 if (on_link)
3466 nrt->rt6i_flags &= ~RTF_GATEWAY;
3467
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003468 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469
Wei Wang2b760fc2017-10-06 12:06:03 -07003470 /* No need to remove rt from the exception table if rt is
3471 * a cached route because rt6_insert_exception() will
3472 * takes care of it
3473 */
David Ahern8a14e462018-04-23 11:32:07 -07003474 if (rt6_insert_exception(nrt, from)) {
Wei Wang2b760fc2017-10-06 12:06:03 -07003475 dst_release_immediate(&nrt->dst);
3476 goto out;
3477 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478
Changli Gaod8d1f302010-06-10 23:31:35 -07003479 netevent.old = &rt->dst;
3480 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003481 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00003482 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07003483 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
3484
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485out:
David Ahern8a14e462018-04-23 11:32:07 -07003486 fib6_info_release(from);
David S. Millere8599ff2012-07-11 23:43:53 -07003487 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07003488}
3489
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003490#ifdef CONFIG_IPV6_ROUTE_INFO
David Ahern8d1c8022018-04-17 17:33:26 -07003491static struct fib6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00003492 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07003493 const struct in6_addr *gwaddr,
3494 struct net_device *dev)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003495{
David Ahern830218c2016-10-24 10:52:35 -07003496 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO;
3497 int ifindex = dev->ifindex;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003498 struct fib6_node *fn;
David Ahern8d1c8022018-04-17 17:33:26 -07003499 struct fib6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07003500 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003501
David Ahern830218c2016-10-24 10:52:35 -07003502 table = fib6_get_table(net, tb_id);
David S. Miller38308472011-12-03 18:02:47 -05003503 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07003504 return NULL;
3505
Wei Wang66f5d6c2017-10-06 12:06:10 -07003506 rcu_read_lock();
Wei Wang38fbeee2017-10-06 12:06:02 -07003507 fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0, true);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003508 if (!fn)
3509 goto out;
3510
Wei Wang66f5d6c2017-10-06 12:06:10 -07003511 for_each_fib6_node_rt_rcu(fn) {
David Ahernad1601a2019-03-27 20:53:56 -07003512 if (rt->fib6_nh.fib_nh_dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003513 continue;
David Ahern2b2450c2019-03-27 20:53:52 -07003514 if (!(rt->fib6_flags & RTF_ROUTEINFO) ||
David Ahernbdf00462019-04-05 16:30:26 -07003515 !rt->fib6_nh.fib_nh_gw_family)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003516 continue;
David Ahernad1601a2019-03-27 20:53:56 -07003517 if (!ipv6_addr_equal(&rt->fib6_nh.fib_nh_gw6, gwaddr))
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003518 continue;
Wei Wange873e4b2018-07-21 20:56:32 -07003519 if (!fib6_info_hold_safe(rt))
3520 continue;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003521 break;
3522 }
3523out:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003524 rcu_read_unlock();
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003525 return rt;
3526}
3527
David Ahern8d1c8022018-04-17 17:33:26 -07003528static struct fib6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00003529 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07003530 const struct in6_addr *gwaddr,
3531 struct net_device *dev,
Eric Dumazet95c96172012-04-15 05:58:06 +00003532 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003533{
Thomas Graf86872cb2006-08-22 00:01:08 -07003534 struct fib6_config cfg = {
Rami Rosen238fc7e2008-02-09 23:43:11 -08003535 .fc_metric = IP6_RT_PRIO_USER,
David Ahern830218c2016-10-24 10:52:35 -07003536 .fc_ifindex = dev->ifindex,
Thomas Graf86872cb2006-08-22 00:01:08 -07003537 .fc_dst_len = prefixlen,
3538 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
3539 RTF_UP | RTF_PREF(pref),
Xin Longb91d5322017-08-03 14:13:46 +08003540 .fc_protocol = RTPROT_RA,
David Aherne8478e82018-04-17 17:33:13 -07003541 .fc_type = RTN_UNICAST,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003542 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08003543 .fc_nlinfo.nlh = NULL,
3544 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07003545 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003546
David Ahern830218c2016-10-24 10:52:35 -07003547 cfg.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO,
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003548 cfg.fc_dst = *prefix;
3549 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07003550
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08003551 /* We should treat it as a default route if prefix length is 0. */
3552 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07003553 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003554
David Ahernacb54e32018-04-17 17:33:22 -07003555 ip6_route_add(&cfg, GFP_ATOMIC, NULL);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003556
David Ahern830218c2016-10-24 10:52:35 -07003557 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003558}
3559#endif
3560
David Ahern8d1c8022018-04-17 17:33:26 -07003561struct fib6_info *rt6_get_dflt_router(struct net *net,
David Ahernafb1d4b52018-04-17 17:33:11 -07003562 const struct in6_addr *addr,
3563 struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003564{
David Ahern830218c2016-10-24 10:52:35 -07003565 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT;
David Ahern8d1c8022018-04-17 17:33:26 -07003566 struct fib6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07003567 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568
David Ahernafb1d4b52018-04-17 17:33:11 -07003569 table = fib6_get_table(net, tb_id);
David S. Miller38308472011-12-03 18:02:47 -05003570 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07003571 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572
Wei Wang66f5d6c2017-10-06 12:06:10 -07003573 rcu_read_lock();
3574 for_each_fib6_node_rt_rcu(&table->tb6_root) {
David Ahernad1601a2019-03-27 20:53:56 -07003575 struct fib6_nh *nh = &rt->fib6_nh;
3576
3577 if (dev == nh->fib_nh_dev &&
David Ahern93c2fb22018-04-18 15:38:59 -07003578 ((rt->fib6_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
David Ahernad1601a2019-03-27 20:53:56 -07003579 ipv6_addr_equal(&nh->fib_nh_gw6, addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580 break;
3581 }
Wei Wange873e4b2018-07-21 20:56:32 -07003582 if (rt && !fib6_info_hold_safe(rt))
3583 rt = NULL;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003584 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 return rt;
3586}
3587
David Ahern8d1c8022018-04-17 17:33:26 -07003588struct fib6_info *rt6_add_dflt_router(struct net *net,
David Ahernafb1d4b52018-04-17 17:33:11 -07003589 const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08003590 struct net_device *dev,
3591 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592{
Thomas Graf86872cb2006-08-22 00:01:08 -07003593 struct fib6_config cfg = {
David Ahernca254492015-10-12 11:47:10 -07003594 .fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08003595 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07003596 .fc_ifindex = dev->ifindex,
3597 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
3598 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Xin Longb91d5322017-08-03 14:13:46 +08003599 .fc_protocol = RTPROT_RA,
David Aherne8478e82018-04-17 17:33:13 -07003600 .fc_type = RTN_UNICAST,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003601 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08003602 .fc_nlinfo.nlh = NULL,
David Ahernafb1d4b52018-04-17 17:33:11 -07003603 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07003604 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003606 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607
David Ahernacb54e32018-04-17 17:33:22 -07003608 if (!ip6_route_add(&cfg, GFP_ATOMIC, NULL)) {
David Ahern830218c2016-10-24 10:52:35 -07003609 struct fib6_table *table;
3610
3611 table = fib6_get_table(dev_net(dev), cfg.fc_table);
3612 if (table)
3613 table->flags |= RT6_TABLE_HAS_DFLT_ROUTER;
3614 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615
David Ahernafb1d4b52018-04-17 17:33:11 -07003616 return rt6_get_dflt_router(net, gwaddr, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617}
3618
David Ahernafb1d4b52018-04-17 17:33:11 -07003619static void __rt6_purge_dflt_routers(struct net *net,
3620 struct fib6_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621{
David Ahern8d1c8022018-04-17 17:33:26 -07003622 struct fib6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623
3624restart:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003625 rcu_read_lock();
3626 for_each_fib6_node_rt_rcu(&table->tb6_root) {
David Aherndcd1f572018-04-18 15:39:05 -07003627 struct net_device *dev = fib6_info_nh_dev(rt);
3628 struct inet6_dev *idev = dev ? __in6_dev_get(dev) : NULL;
3629
David Ahern93c2fb22018-04-18 15:38:59 -07003630 if (rt->fib6_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
Wei Wange873e4b2018-07-21 20:56:32 -07003631 (!idev || idev->cnf.accept_ra != 2) &&
3632 fib6_info_hold_safe(rt)) {
David Ahern93531c62018-04-17 17:33:25 -07003633 rcu_read_unlock();
3634 ip6_del_rt(net, rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 goto restart;
3636 }
3637 }
Wei Wang66f5d6c2017-10-06 12:06:10 -07003638 rcu_read_unlock();
David Ahern830218c2016-10-24 10:52:35 -07003639
3640 table->flags &= ~RT6_TABLE_HAS_DFLT_ROUTER;
3641}
3642
3643void rt6_purge_dflt_routers(struct net *net)
3644{
3645 struct fib6_table *table;
3646 struct hlist_head *head;
3647 unsigned int h;
3648
3649 rcu_read_lock();
3650
3651 for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
3652 head = &net->ipv6.fib_table_hash[h];
3653 hlist_for_each_entry_rcu(table, head, tb6_hlist) {
3654 if (table->flags & RT6_TABLE_HAS_DFLT_ROUTER)
David Ahernafb1d4b52018-04-17 17:33:11 -07003655 __rt6_purge_dflt_routers(net, table);
David Ahern830218c2016-10-24 10:52:35 -07003656 }
3657 }
3658
3659 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660}
3661
Daniel Lezcano55786892008-03-04 13:47:47 -08003662static void rtmsg_to_fib6_config(struct net *net,
3663 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07003664 struct fib6_config *cfg)
3665{
Maciej Żenczykowski8823a3a2018-09-29 23:44:52 -07003666 *cfg = (struct fib6_config){
3667 .fc_table = l3mdev_fib_table_by_index(net, rtmsg->rtmsg_ifindex) ?
3668 : RT6_TABLE_MAIN,
3669 .fc_ifindex = rtmsg->rtmsg_ifindex,
David Ahern67f69512019-03-21 05:21:34 -07003670 .fc_metric = rtmsg->rtmsg_metric ? : IP6_RT_PRIO_USER,
Maciej Żenczykowski8823a3a2018-09-29 23:44:52 -07003671 .fc_expires = rtmsg->rtmsg_info,
3672 .fc_dst_len = rtmsg->rtmsg_dst_len,
3673 .fc_src_len = rtmsg->rtmsg_src_len,
3674 .fc_flags = rtmsg->rtmsg_flags,
3675 .fc_type = rtmsg->rtmsg_type,
Thomas Graf86872cb2006-08-22 00:01:08 -07003676
Maciej Żenczykowski8823a3a2018-09-29 23:44:52 -07003677 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07003678
Maciej Żenczykowski8823a3a2018-09-29 23:44:52 -07003679 .fc_dst = rtmsg->rtmsg_dst,
3680 .fc_src = rtmsg->rtmsg_src,
3681 .fc_gateway = rtmsg->rtmsg_gateway,
3682 };
Thomas Graf86872cb2006-08-22 00:01:08 -07003683}
3684
Daniel Lezcano55786892008-03-04 13:47:47 -08003685int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686{
Thomas Graf86872cb2006-08-22 00:01:08 -07003687 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 struct in6_rtmsg rtmsg;
3689 int err;
3690
Ian Morris67ba4152014-08-24 21:53:10 +01003691 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 case SIOCADDRT: /* Add a route */
3693 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00003694 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 return -EPERM;
3696 err = copy_from_user(&rtmsg, arg,
3697 sizeof(struct in6_rtmsg));
3698 if (err)
3699 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07003700
Daniel Lezcano55786892008-03-04 13:47:47 -08003701 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07003702
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 rtnl_lock();
3704 switch (cmd) {
3705 case SIOCADDRT:
David Ahernacb54e32018-04-17 17:33:22 -07003706 err = ip6_route_add(&cfg, GFP_KERNEL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 break;
3708 case SIOCDELRT:
David Ahern333c4302017-05-21 10:12:04 -06003709 err = ip6_route_del(&cfg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710 break;
3711 default:
3712 err = -EINVAL;
3713 }
3714 rtnl_unlock();
3715
3716 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07003717 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718
3719 return -EINVAL;
3720}
3721
3722/*
3723 * Drop the packet on the floor
3724 */
3725
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07003726static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003728 int type;
Eric Dumazetadf30902009-06-02 05:19:30 +00003729 struct dst_entry *dst = skb_dst(skb);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003730 switch (ipstats_mib_noroutes) {
3731 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07003732 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00003733 if (type == IPV6_ADDR_ANY) {
Stephen Suryaputrabdb7cc62018-04-16 13:42:16 -04003734 IP6_INC_STATS(dev_net(dst->dev),
3735 __in6_dev_get_safely(skb->dev),
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07003736 IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003737 break;
3738 }
3739 /* FALLTHROUGH */
3740 case IPSTATS_MIB_OUTNOROUTES:
Denis V. Lunev3bd653c2008-10-08 10:54:51 -07003741 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst),
3742 ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003743 break;
3744 }
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00003745 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746 kfree_skb(skb);
3747 return 0;
3748}
3749
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003750static int ip6_pkt_discard(struct sk_buff *skb)
3751{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003752 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003753}
3754
Eric W. Biedermanede20592015-10-07 16:48:47 -05003755static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756{
Eric Dumazetadf30902009-06-02 05:19:30 +00003757 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003758 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759}
3760
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003761static int ip6_pkt_prohibit(struct sk_buff *skb)
3762{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003763 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003764}
3765
Eric W. Biedermanede20592015-10-07 16:48:47 -05003766static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003767{
Eric Dumazetadf30902009-06-02 05:19:30 +00003768 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003769 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003770}
3771
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772/*
3773 * Allocate a dst for local (unicast / anycast) address.
3774 */
3775
David Ahern360a9882018-04-18 15:39:00 -07003776struct fib6_info *addrconf_f6i_alloc(struct net *net,
3777 struct inet6_dev *idev,
3778 const struct in6_addr *addr,
3779 bool anycast, gfp_t gfp_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780{
David Ahernc7a1ce32019-03-21 05:21:35 -07003781 struct fib6_config cfg = {
3782 .fc_table = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL,
3783 .fc_ifindex = idev->dev->ifindex,
3784 .fc_flags = RTF_UP | RTF_ADDRCONF | RTF_NONEXTHOP,
3785 .fc_dst = *addr,
3786 .fc_dst_len = 128,
3787 .fc_protocol = RTPROT_KERNEL,
3788 .fc_nlinfo.nl_net = net,
3789 .fc_ignore_dev_down = true,
3790 };
David Ahern5f02ce242016-09-10 12:09:54 -07003791
David Aherne8478e82018-04-17 17:33:13 -07003792 if (anycast) {
David Ahernc7a1ce32019-03-21 05:21:35 -07003793 cfg.fc_type = RTN_ANYCAST;
3794 cfg.fc_flags |= RTF_ANYCAST;
David Aherne8478e82018-04-17 17:33:13 -07003795 } else {
David Ahernc7a1ce32019-03-21 05:21:35 -07003796 cfg.fc_type = RTN_LOCAL;
3797 cfg.fc_flags |= RTF_LOCAL;
David Aherne8478e82018-04-17 17:33:13 -07003798 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799
David Ahernc7a1ce32019-03-21 05:21:35 -07003800 return ip6_route_info_create(&cfg, gfp_flags, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801}
3802
Daniel Walterc3968a82011-04-13 21:10:57 +00003803/* remove deleted ip from prefsrc entries */
3804struct arg_dev_net_ip {
3805 struct net_device *dev;
3806 struct net *net;
3807 struct in6_addr *addr;
3808};
3809
David Ahern8d1c8022018-04-17 17:33:26 -07003810static int fib6_remove_prefsrc(struct fib6_info *rt, void *arg)
Daniel Walterc3968a82011-04-13 21:10:57 +00003811{
3812 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
3813 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
3814 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
3815
David Ahernad1601a2019-03-27 20:53:56 -07003816 if (((void *)rt->fib6_nh.fib_nh_dev == dev || !dev) &&
David Ahern421842e2018-04-17 17:33:18 -07003817 rt != net->ipv6.fib6_null_entry &&
David Ahern93c2fb22018-04-18 15:38:59 -07003818 ipv6_addr_equal(addr, &rt->fib6_prefsrc.addr)) {
Wei Wang60006a42017-10-06 12:05:58 -07003819 spin_lock_bh(&rt6_exception_lock);
Daniel Walterc3968a82011-04-13 21:10:57 +00003820 /* remove prefsrc entry */
David Ahern93c2fb22018-04-18 15:38:59 -07003821 rt->fib6_prefsrc.plen = 0;
Wei Wang60006a42017-10-06 12:05:58 -07003822 spin_unlock_bh(&rt6_exception_lock);
Daniel Walterc3968a82011-04-13 21:10:57 +00003823 }
3824 return 0;
3825}
3826
3827void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
3828{
3829 struct net *net = dev_net(ifp->idev->dev);
3830 struct arg_dev_net_ip adni = {
3831 .dev = ifp->idev->dev,
3832 .net = net,
3833 .addr = &ifp->addr,
3834 };
Li RongQing0c3584d2013-12-27 16:32:38 +08003835 fib6_clean_all(net, fib6_remove_prefsrc, &adni);
Daniel Walterc3968a82011-04-13 21:10:57 +00003836}
3837
David Ahern2b2450c2019-03-27 20:53:52 -07003838#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT)
Duan Jiongbe7a0102014-05-15 15:56:14 +08003839
3840/* Remove routers and update dst entries when gateway turn into host. */
David Ahern8d1c8022018-04-17 17:33:26 -07003841static int fib6_clean_tohost(struct fib6_info *rt, void *arg)
Duan Jiongbe7a0102014-05-15 15:56:14 +08003842{
3843 struct in6_addr *gateway = (struct in6_addr *)arg;
3844
David Ahern93c2fb22018-04-18 15:38:59 -07003845 if (((rt->fib6_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) &&
David Ahernbdf00462019-04-05 16:30:26 -07003846 rt->fib6_nh.fib_nh_gw_family &&
David Ahernad1601a2019-03-27 20:53:56 -07003847 ipv6_addr_equal(gateway, &rt->fib6_nh.fib_nh_gw6)) {
Duan Jiongbe7a0102014-05-15 15:56:14 +08003848 return -1;
3849 }
Wei Wangb16cb452017-10-06 12:06:00 -07003850
3851 /* Further clean up cached routes in exception table.
3852 * This is needed because cached route may have a different
3853 * gateway than its 'parent' in the case of an ip redirect.
3854 */
3855 rt6_exceptions_clean_tohost(rt, gateway);
3856
Duan Jiongbe7a0102014-05-15 15:56:14 +08003857 return 0;
3858}
3859
3860void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
3861{
3862 fib6_clean_all(net, fib6_clean_tohost, gateway);
3863}
3864
Ido Schimmel2127d952018-01-07 12:45:03 +02003865struct arg_netdev_event {
3866 const struct net_device *dev;
Ido Schimmel4c981e22018-01-07 12:45:04 +02003867 union {
3868 unsigned int nh_flags;
3869 unsigned long event;
3870 };
Ido Schimmel2127d952018-01-07 12:45:03 +02003871};
3872
David Ahern8d1c8022018-04-17 17:33:26 -07003873static struct fib6_info *rt6_multipath_first_sibling(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003874{
David Ahern8d1c8022018-04-17 17:33:26 -07003875 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003876 struct fib6_node *fn;
3877
David Ahern93c2fb22018-04-18 15:38:59 -07003878 fn = rcu_dereference_protected(rt->fib6_node,
3879 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003880 iter = rcu_dereference_protected(fn->leaf,
David Ahern93c2fb22018-04-18 15:38:59 -07003881 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003882 while (iter) {
David Ahern93c2fb22018-04-18 15:38:59 -07003883 if (iter->fib6_metric == rt->fib6_metric &&
David Ahern33bd5ac2018-07-03 14:36:21 -07003884 rt6_qualify_for_ecmp(iter))
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003885 return iter;
David Ahern8fb11a92018-05-04 13:54:24 -07003886 iter = rcu_dereference_protected(iter->fib6_next,
David Ahern93c2fb22018-04-18 15:38:59 -07003887 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003888 }
3889
3890 return NULL;
3891}
3892
David Ahern8d1c8022018-04-17 17:33:26 -07003893static bool rt6_is_dead(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003894{
David Ahernad1601a2019-03-27 20:53:56 -07003895 if (rt->fib6_nh.fib_nh_flags & RTNH_F_DEAD ||
3896 (rt->fib6_nh.fib_nh_flags & RTNH_F_LINKDOWN &&
3897 ip6_ignore_linkdown(rt->fib6_nh.fib_nh_dev)))
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003898 return true;
3899
3900 return false;
3901}
3902
David Ahern8d1c8022018-04-17 17:33:26 -07003903static int rt6_multipath_total_weight(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003904{
David Ahern8d1c8022018-04-17 17:33:26 -07003905 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003906 int total = 0;
3907
3908 if (!rt6_is_dead(rt))
David Ahernad1601a2019-03-27 20:53:56 -07003909 total += rt->fib6_nh.fib_nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003910
David Ahern93c2fb22018-04-18 15:38:59 -07003911 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) {
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003912 if (!rt6_is_dead(iter))
David Ahernad1601a2019-03-27 20:53:56 -07003913 total += iter->fib6_nh.fib_nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003914 }
3915
3916 return total;
3917}
3918
David Ahern8d1c8022018-04-17 17:33:26 -07003919static void rt6_upper_bound_set(struct fib6_info *rt, int *weight, int total)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003920{
3921 int upper_bound = -1;
3922
3923 if (!rt6_is_dead(rt)) {
David Ahernad1601a2019-03-27 20:53:56 -07003924 *weight += rt->fib6_nh.fib_nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003925 upper_bound = DIV_ROUND_CLOSEST_ULL((u64) (*weight) << 31,
3926 total) - 1;
3927 }
David Ahernad1601a2019-03-27 20:53:56 -07003928 atomic_set(&rt->fib6_nh.fib_nh_upper_bound, upper_bound);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003929}
3930
David Ahern8d1c8022018-04-17 17:33:26 -07003931static void rt6_multipath_upper_bound_set(struct fib6_info *rt, int total)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003932{
David Ahern8d1c8022018-04-17 17:33:26 -07003933 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003934 int weight = 0;
3935
3936 rt6_upper_bound_set(rt, &weight, total);
3937
David Ahern93c2fb22018-04-18 15:38:59 -07003938 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003939 rt6_upper_bound_set(iter, &weight, total);
3940}
3941
David Ahern8d1c8022018-04-17 17:33:26 -07003942void rt6_multipath_rebalance(struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003943{
David Ahern8d1c8022018-04-17 17:33:26 -07003944 struct fib6_info *first;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003945 int total;
3946
3947 /* In case the entire multipath route was marked for flushing,
3948 * then there is no need to rebalance upon the removal of every
3949 * sibling route.
3950 */
David Ahern93c2fb22018-04-18 15:38:59 -07003951 if (!rt->fib6_nsiblings || rt->should_flush)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003952 return;
3953
3954 /* During lookup routes are evaluated in order, so we need to
3955 * make sure upper bounds are assigned from the first sibling
3956 * onwards.
3957 */
3958 first = rt6_multipath_first_sibling(rt);
3959 if (WARN_ON_ONCE(!first))
3960 return;
3961
3962 total = rt6_multipath_total_weight(first);
3963 rt6_multipath_upper_bound_set(first, total);
3964}
3965
David Ahern8d1c8022018-04-17 17:33:26 -07003966static int fib6_ifup(struct fib6_info *rt, void *p_arg)
Ido Schimmel2127d952018-01-07 12:45:03 +02003967{
3968 const struct arg_netdev_event *arg = p_arg;
David Ahern7aef6852018-04-17 17:33:10 -07003969 struct net *net = dev_net(arg->dev);
Ido Schimmel2127d952018-01-07 12:45:03 +02003970
David Ahernad1601a2019-03-27 20:53:56 -07003971 if (rt != net->ipv6.fib6_null_entry &&
3972 rt->fib6_nh.fib_nh_dev == arg->dev) {
3973 rt->fib6_nh.fib_nh_flags &= ~arg->nh_flags;
David Ahern7aef6852018-04-17 17:33:10 -07003974 fib6_update_sernum_upto_root(net, rt);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003975 rt6_multipath_rebalance(rt);
Ido Schimmel1de178e2018-01-07 12:45:15 +02003976 }
Ido Schimmel2127d952018-01-07 12:45:03 +02003977
3978 return 0;
3979}
3980
3981void rt6_sync_up(struct net_device *dev, unsigned int nh_flags)
3982{
3983 struct arg_netdev_event arg = {
3984 .dev = dev,
Ido Schimmel6802f3a2018-01-12 22:07:36 +02003985 {
3986 .nh_flags = nh_flags,
3987 },
Ido Schimmel2127d952018-01-07 12:45:03 +02003988 };
3989
3990 if (nh_flags & RTNH_F_DEAD && netif_carrier_ok(dev))
3991 arg.nh_flags |= RTNH_F_LINKDOWN;
3992
3993 fib6_clean_all(dev_net(dev), fib6_ifup, &arg);
3994}
3995
David Ahern8d1c8022018-04-17 17:33:26 -07003996static bool rt6_multipath_uses_dev(const struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02003997 const struct net_device *dev)
3998{
David Ahern8d1c8022018-04-17 17:33:26 -07003999 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02004000
David Ahernad1601a2019-03-27 20:53:56 -07004001 if (rt->fib6_nh.fib_nh_dev == dev)
Ido Schimmel1de178e2018-01-07 12:45:15 +02004002 return true;
David Ahern93c2fb22018-04-18 15:38:59 -07004003 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahernad1601a2019-03-27 20:53:56 -07004004 if (iter->fib6_nh.fib_nh_dev == dev)
Ido Schimmel1de178e2018-01-07 12:45:15 +02004005 return true;
4006
4007 return false;
4008}
4009
David Ahern8d1c8022018-04-17 17:33:26 -07004010static void rt6_multipath_flush(struct fib6_info *rt)
Ido Schimmel1de178e2018-01-07 12:45:15 +02004011{
David Ahern8d1c8022018-04-17 17:33:26 -07004012 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02004013
4014 rt->should_flush = 1;
David Ahern93c2fb22018-04-18 15:38:59 -07004015 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
Ido Schimmel1de178e2018-01-07 12:45:15 +02004016 iter->should_flush = 1;
4017}
4018
David Ahern8d1c8022018-04-17 17:33:26 -07004019static unsigned int rt6_multipath_dead_count(const struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02004020 const struct net_device *down_dev)
4021{
David Ahern8d1c8022018-04-17 17:33:26 -07004022 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02004023 unsigned int dead = 0;
4024
David Ahernad1601a2019-03-27 20:53:56 -07004025 if (rt->fib6_nh.fib_nh_dev == down_dev ||
4026 rt->fib6_nh.fib_nh_flags & RTNH_F_DEAD)
Ido Schimmel1de178e2018-01-07 12:45:15 +02004027 dead++;
David Ahern93c2fb22018-04-18 15:38:59 -07004028 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahernad1601a2019-03-27 20:53:56 -07004029 if (iter->fib6_nh.fib_nh_dev == down_dev ||
4030 iter->fib6_nh.fib_nh_flags & RTNH_F_DEAD)
Ido Schimmel1de178e2018-01-07 12:45:15 +02004031 dead++;
4032
4033 return dead;
4034}
4035
David Ahern8d1c8022018-04-17 17:33:26 -07004036static void rt6_multipath_nh_flags_set(struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02004037 const struct net_device *dev,
4038 unsigned int nh_flags)
4039{
David Ahern8d1c8022018-04-17 17:33:26 -07004040 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02004041
David Ahernad1601a2019-03-27 20:53:56 -07004042 if (rt->fib6_nh.fib_nh_dev == dev)
4043 rt->fib6_nh.fib_nh_flags |= nh_flags;
David Ahern93c2fb22018-04-18 15:38:59 -07004044 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahernad1601a2019-03-27 20:53:56 -07004045 if (iter->fib6_nh.fib_nh_dev == dev)
4046 iter->fib6_nh.fib_nh_flags |= nh_flags;
Ido Schimmel1de178e2018-01-07 12:45:15 +02004047}
4048
David Aherna1a22c12017-01-18 07:40:36 -08004049/* called with write lock held for table with rt */
David Ahern8d1c8022018-04-17 17:33:26 -07004050static int fib6_ifdown(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051{
Ido Schimmel4c981e22018-01-07 12:45:04 +02004052 const struct arg_netdev_event *arg = p_arg;
4053 const struct net_device *dev = arg->dev;
David Ahern7aef6852018-04-17 17:33:10 -07004054 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004055
David Ahern421842e2018-04-17 17:33:18 -07004056 if (rt == net->ipv6.fib6_null_entry)
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004057 return 0;
4058
4059 switch (arg->event) {
4060 case NETDEV_UNREGISTER:
David Ahernad1601a2019-03-27 20:53:56 -07004061 return rt->fib6_nh.fib_nh_dev == dev ? -1 : 0;
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004062 case NETDEV_DOWN:
Ido Schimmel1de178e2018-01-07 12:45:15 +02004063 if (rt->should_flush)
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004064 return -1;
David Ahern93c2fb22018-04-18 15:38:59 -07004065 if (!rt->fib6_nsiblings)
David Ahernad1601a2019-03-27 20:53:56 -07004066 return rt->fib6_nh.fib_nh_dev == dev ? -1 : 0;
Ido Schimmel1de178e2018-01-07 12:45:15 +02004067 if (rt6_multipath_uses_dev(rt, dev)) {
4068 unsigned int count;
4069
4070 count = rt6_multipath_dead_count(rt, dev);
David Ahern93c2fb22018-04-18 15:38:59 -07004071 if (rt->fib6_nsiblings + 1 == count) {
Ido Schimmel1de178e2018-01-07 12:45:15 +02004072 rt6_multipath_flush(rt);
4073 return -1;
4074 }
4075 rt6_multipath_nh_flags_set(rt, dev, RTNH_F_DEAD |
4076 RTNH_F_LINKDOWN);
David Ahern7aef6852018-04-17 17:33:10 -07004077 fib6_update_sernum(net, rt);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02004078 rt6_multipath_rebalance(rt);
Ido Schimmel1de178e2018-01-07 12:45:15 +02004079 }
4080 return -2;
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004081 case NETDEV_CHANGE:
David Ahernad1601a2019-03-27 20:53:56 -07004082 if (rt->fib6_nh.fib_nh_dev != dev ||
David Ahern93c2fb22018-04-18 15:38:59 -07004083 rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST))
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004084 break;
David Ahernad1601a2019-03-27 20:53:56 -07004085 rt->fib6_nh.fib_nh_flags |= RTNH_F_LINKDOWN;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02004086 rt6_multipath_rebalance(rt);
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004087 break;
Ido Schimmel2b241362018-01-07 12:45:02 +02004088 }
David S. Millerc159d302011-12-26 15:24:36 -05004089
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090 return 0;
4091}
4092
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004093void rt6_sync_down_dev(struct net_device *dev, unsigned long event)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094{
Ido Schimmel4c981e22018-01-07 12:45:04 +02004095 struct arg_netdev_event arg = {
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004096 .dev = dev,
Ido Schimmel6802f3a2018-01-12 22:07:36 +02004097 {
4098 .event = event,
4099 },
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004100 };
David Ahern7c6bb7d2018-10-11 20:17:21 -07004101 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004102
David Ahern7c6bb7d2018-10-11 20:17:21 -07004103 if (net->ipv6.sysctl.skip_notify_on_dev_down)
4104 fib6_clean_all_skip_notify(net, fib6_ifdown, &arg);
4105 else
4106 fib6_clean_all(net, fib6_ifdown, &arg);
Ido Schimmel4c981e22018-01-07 12:45:04 +02004107}
4108
4109void rt6_disable_ip(struct net_device *dev, unsigned long event)
4110{
4111 rt6_sync_down_dev(dev, event);
4112 rt6_uncached_list_flush_dev(dev_net(dev), dev);
4113 neigh_ifdown(&nd_tbl, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114}
4115
Eric Dumazet95c96172012-04-15 05:58:06 +00004116struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00004118 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004119};
4120
David Ahern8d1c8022018-04-17 17:33:26 -07004121static int rt6_mtu_change_route(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122{
4123 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
4124 struct inet6_dev *idev;
4125
4126 /* In IPv6 pmtu discovery is not optional,
4127 so that RTAX_MTU lock cannot disable it.
4128 We still use this lock to block changes
4129 caused by addrconf/ndisc.
4130 */
4131
4132 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05004133 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134 return 0;
4135
4136 /* For administrative MTU increase, there is no way to discover
4137 IPv6 PMTU increase, so PMTU increase should be updated here.
4138 Since RFC 1981 doesn't include administrative MTU increase
4139 update PMTU increase is a MUST. (i.e. jumbo frame)
4140 */
David Ahernad1601a2019-03-27 20:53:56 -07004141 if (rt->fib6_nh.fib_nh_dev == arg->dev &&
David Ahernd4ead6b2018-04-17 17:33:16 -07004142 !fib6_metric_locked(rt, RTAX_MTU)) {
4143 u32 mtu = rt->fib6_pmtu;
4144
4145 if (mtu >= arg->mtu ||
4146 (mtu < arg->mtu && mtu == idev->cnf.mtu6))
4147 fib6_metric_set(rt, RTAX_MTU, arg->mtu);
4148
Wei Wangf5bbe7e2017-10-06 12:05:59 -07004149 spin_lock_bh(&rt6_exception_lock);
Stefano Brivioe9fa1492018-03-06 11:10:19 +01004150 rt6_exceptions_update_pmtu(idev, rt, arg->mtu);
Wei Wangf5bbe7e2017-10-06 12:05:59 -07004151 spin_unlock_bh(&rt6_exception_lock);
Simon Arlott566cfd82007-07-26 00:09:55 -07004152 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153 return 0;
4154}
4155
Eric Dumazet95c96172012-04-15 05:58:06 +00004156void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157{
Thomas Grafc71099a2006-08-04 23:20:06 -07004158 struct rt6_mtu_change_arg arg = {
4159 .dev = dev,
4160 .mtu = mtu,
4161 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162
Li RongQing0c3584d2013-12-27 16:32:38 +08004163 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164}
4165
Patrick McHardyef7c79e2007-06-05 12:38:30 -07004166static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07004167 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Eric Dumazetaa8f8772018-04-22 18:29:23 -07004168 [RTA_PREFSRC] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07004169 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07004170 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07004171 [RTA_PRIORITY] = { .type = NLA_U32 },
4172 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004173 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004174 [RTA_PREF] = { .type = NLA_U8 },
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004175 [RTA_ENCAP_TYPE] = { .type = NLA_U16 },
4176 [RTA_ENCAP] = { .type = NLA_NESTED },
Xin Long32bc2012015-12-16 17:50:11 +08004177 [RTA_EXPIRES] = { .type = NLA_U32 },
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09004178 [RTA_UID] = { .type = NLA_U32 },
Liping Zhang3b45a412017-02-27 20:59:39 +08004179 [RTA_MARK] = { .type = NLA_U32 },
Eric Dumazetaa8f8772018-04-22 18:29:23 -07004180 [RTA_TABLE] = { .type = NLA_U32 },
Roopa Prabhueacb9382018-05-22 14:03:28 -07004181 [RTA_IP_PROTO] = { .type = NLA_U8 },
4182 [RTA_SPORT] = { .type = NLA_U16 },
4183 [RTA_DPORT] = { .type = NLA_U16 },
Thomas Graf86872cb2006-08-22 00:01:08 -07004184};
4185
4186static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
David Ahern333c4302017-05-21 10:12:04 -06004187 struct fib6_config *cfg,
4188 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189{
Thomas Graf86872cb2006-08-22 00:01:08 -07004190 struct rtmsg *rtm;
4191 struct nlattr *tb[RTA_MAX+1];
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004192 unsigned int pref;
Thomas Graf86872cb2006-08-22 00:01:08 -07004193 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194
Johannes Bergfceb6432017-04-12 14:34:07 +02004195 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
David Aherndac9c972018-10-07 20:16:24 -07004196 extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07004197 if (err < 0)
4198 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199
Thomas Graf86872cb2006-08-22 00:01:08 -07004200 err = -EINVAL;
4201 rtm = nlmsg_data(nlh);
Thomas Graf86872cb2006-08-22 00:01:08 -07004202
Maciej Żenczykowski84db8402018-09-29 23:44:53 -07004203 *cfg = (struct fib6_config){
4204 .fc_table = rtm->rtm_table,
4205 .fc_dst_len = rtm->rtm_dst_len,
4206 .fc_src_len = rtm->rtm_src_len,
4207 .fc_flags = RTF_UP,
4208 .fc_protocol = rtm->rtm_protocol,
4209 .fc_type = rtm->rtm_type,
4210
4211 .fc_nlinfo.portid = NETLINK_CB(skb).portid,
4212 .fc_nlinfo.nlh = nlh,
4213 .fc_nlinfo.nl_net = sock_net(skb->sk),
4214 };
Thomas Graf86872cb2006-08-22 00:01:08 -07004215
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00004216 if (rtm->rtm_type == RTN_UNREACHABLE ||
4217 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00004218 rtm->rtm_type == RTN_PROHIBIT ||
4219 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07004220 cfg->fc_flags |= RTF_REJECT;
4221
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00004222 if (rtm->rtm_type == RTN_LOCAL)
4223 cfg->fc_flags |= RTF_LOCAL;
4224
Martin KaFai Lau1f56a01f2015-04-28 13:03:03 -07004225 if (rtm->rtm_flags & RTM_F_CLONED)
4226 cfg->fc_flags |= RTF_CACHE;
4227
David Ahernfc1e64e2018-01-25 16:55:09 -08004228 cfg->fc_flags |= (rtm->rtm_flags & RTNH_F_ONLINK);
4229
Thomas Graf86872cb2006-08-22 00:01:08 -07004230 if (tb[RTA_GATEWAY]) {
Jiri Benc67b61f62015-03-29 16:59:26 +02004231 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
Thomas Graf86872cb2006-08-22 00:01:08 -07004232 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 }
David Aherne3818542019-02-26 09:00:03 -08004234 if (tb[RTA_VIA]) {
4235 NL_SET_ERR_MSG(extack, "IPv6 does not support RTA_VIA attribute");
4236 goto errout;
4237 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004238
4239 if (tb[RTA_DST]) {
4240 int plen = (rtm->rtm_dst_len + 7) >> 3;
4241
4242 if (nla_len(tb[RTA_DST]) < plen)
4243 goto errout;
4244
4245 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004247
4248 if (tb[RTA_SRC]) {
4249 int plen = (rtm->rtm_src_len + 7) >> 3;
4250
4251 if (nla_len(tb[RTA_SRC]) < plen)
4252 goto errout;
4253
4254 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004256
Daniel Walterc3968a82011-04-13 21:10:57 +00004257 if (tb[RTA_PREFSRC])
Jiri Benc67b61f62015-03-29 16:59:26 +02004258 cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]);
Daniel Walterc3968a82011-04-13 21:10:57 +00004259
Thomas Graf86872cb2006-08-22 00:01:08 -07004260 if (tb[RTA_OIF])
4261 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
4262
4263 if (tb[RTA_PRIORITY])
4264 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
4265
4266 if (tb[RTA_METRICS]) {
4267 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
4268 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004270
4271 if (tb[RTA_TABLE])
4272 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
4273
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004274 if (tb[RTA_MULTIPATH]) {
4275 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
4276 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
David Ahern9ed59592017-01-17 14:57:36 -08004277
4278 err = lwtunnel_valid_encap_type_attr(cfg->fc_mp,
David Ahernc255bd62017-05-27 16:19:27 -06004279 cfg->fc_mp_len, extack);
David Ahern9ed59592017-01-17 14:57:36 -08004280 if (err < 0)
4281 goto errout;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004282 }
4283
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004284 if (tb[RTA_PREF]) {
4285 pref = nla_get_u8(tb[RTA_PREF]);
4286 if (pref != ICMPV6_ROUTER_PREF_LOW &&
4287 pref != ICMPV6_ROUTER_PREF_HIGH)
4288 pref = ICMPV6_ROUTER_PREF_MEDIUM;
4289 cfg->fc_flags |= RTF_PREF(pref);
4290 }
4291
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004292 if (tb[RTA_ENCAP])
4293 cfg->fc_encap = tb[RTA_ENCAP];
4294
David Ahern9ed59592017-01-17 14:57:36 -08004295 if (tb[RTA_ENCAP_TYPE]) {
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004296 cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]);
4297
David Ahernc255bd62017-05-27 16:19:27 -06004298 err = lwtunnel_valid_encap_type(cfg->fc_encap_type, extack);
David Ahern9ed59592017-01-17 14:57:36 -08004299 if (err < 0)
4300 goto errout;
4301 }
4302
Xin Long32bc2012015-12-16 17:50:11 +08004303 if (tb[RTA_EXPIRES]) {
4304 unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ);
4305
4306 if (addrconf_finite_timeout(timeout)) {
4307 cfg->fc_expires = jiffies_to_clock_t(timeout * HZ);
4308 cfg->fc_flags |= RTF_EXPIRES;
4309 }
4310 }
4311
Thomas Graf86872cb2006-08-22 00:01:08 -07004312 err = 0;
4313errout:
4314 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315}
4316
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004317struct rt6_nh {
David Ahern8d1c8022018-04-17 17:33:26 -07004318 struct fib6_info *fib6_info;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004319 struct fib6_config r_cfg;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004320 struct list_head next;
4321};
4322
David Ahernd4ead6b2018-04-17 17:33:16 -07004323static int ip6_route_info_append(struct net *net,
4324 struct list_head *rt6_nh_list,
David Ahern8d1c8022018-04-17 17:33:26 -07004325 struct fib6_info *rt,
4326 struct fib6_config *r_cfg)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004327{
4328 struct rt6_nh *nh;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004329 int err = -EEXIST;
4330
4331 list_for_each_entry(nh, rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004332 /* check if fib6_info already exists */
4333 if (rt6_duplicate_nexthop(nh->fib6_info, rt))
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004334 return err;
4335 }
4336
4337 nh = kzalloc(sizeof(*nh), GFP_KERNEL);
4338 if (!nh)
4339 return -ENOMEM;
David Ahern8d1c8022018-04-17 17:33:26 -07004340 nh->fib6_info = rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004341 memcpy(&nh->r_cfg, r_cfg, sizeof(*r_cfg));
4342 list_add_tail(&nh->next, rt6_nh_list);
4343
4344 return 0;
4345}
4346
David Ahern8d1c8022018-04-17 17:33:26 -07004347static void ip6_route_mpath_notify(struct fib6_info *rt,
4348 struct fib6_info *rt_last,
David Ahern3b1137f2017-02-02 12:37:10 -08004349 struct nl_info *info,
4350 __u16 nlflags)
4351{
4352 /* if this is an APPEND route, then rt points to the first route
4353 * inserted and rt_last points to last route inserted. Userspace
4354 * wants a consistent dump of the route which starts at the first
4355 * nexthop. Since sibling routes are always added at the end of
4356 * the list, find the first sibling of the last route appended
4357 */
David Ahern93c2fb22018-04-18 15:38:59 -07004358 if ((nlflags & NLM_F_APPEND) && rt_last && rt_last->fib6_nsiblings) {
4359 rt = list_first_entry(&rt_last->fib6_siblings,
David Ahern8d1c8022018-04-17 17:33:26 -07004360 struct fib6_info,
David Ahern93c2fb22018-04-18 15:38:59 -07004361 fib6_siblings);
David Ahern3b1137f2017-02-02 12:37:10 -08004362 }
4363
4364 if (rt)
4365 inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
4366}
4367
David Ahern333c4302017-05-21 10:12:04 -06004368static int ip6_route_multipath_add(struct fib6_config *cfg,
4369 struct netlink_ext_ack *extack)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004370{
David Ahern8d1c8022018-04-17 17:33:26 -07004371 struct fib6_info *rt_notif = NULL, *rt_last = NULL;
David Ahern3b1137f2017-02-02 12:37:10 -08004372 struct nl_info *info = &cfg->fc_nlinfo;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004373 struct fib6_config r_cfg;
4374 struct rtnexthop *rtnh;
David Ahern8d1c8022018-04-17 17:33:26 -07004375 struct fib6_info *rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004376 struct rt6_nh *err_nh;
4377 struct rt6_nh *nh, *nh_safe;
David Ahern3b1137f2017-02-02 12:37:10 -08004378 __u16 nlflags;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004379 int remaining;
4380 int attrlen;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004381 int err = 1;
4382 int nhn = 0;
4383 int replace = (cfg->fc_nlinfo.nlh &&
4384 (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE));
4385 LIST_HEAD(rt6_nh_list);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004386
David Ahern3b1137f2017-02-02 12:37:10 -08004387 nlflags = replace ? NLM_F_REPLACE : NLM_F_CREATE;
4388 if (info->nlh && info->nlh->nlmsg_flags & NLM_F_APPEND)
4389 nlflags |= NLM_F_APPEND;
4390
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02004391 remaining = cfg->fc_mp_len;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004392 rtnh = (struct rtnexthop *)cfg->fc_mp;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004393
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004394 /* Parse a Multipath Entry and build a list (rt6_nh_list) of
David Ahern8d1c8022018-04-17 17:33:26 -07004395 * fib6_info structs per nexthop
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004396 */
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004397 while (rtnh_ok(rtnh, remaining)) {
4398 memcpy(&r_cfg, cfg, sizeof(*cfg));
4399 if (rtnh->rtnh_ifindex)
4400 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
4401
4402 attrlen = rtnh_attrlen(rtnh);
4403 if (attrlen > 0) {
4404 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
4405
4406 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
4407 if (nla) {
Jiri Benc67b61f62015-03-29 16:59:26 +02004408 r_cfg.fc_gateway = nla_get_in6_addr(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004409 r_cfg.fc_flags |= RTF_GATEWAY;
4410 }
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004411 r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
4412 nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
4413 if (nla)
4414 r_cfg.fc_encap_type = nla_get_u16(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004415 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004416
David Ahern68e2ffd2018-03-20 10:06:59 -07004417 r_cfg.fc_flags |= (rtnh->rtnh_flags & RTNH_F_ONLINK);
David Ahernacb54e32018-04-17 17:33:22 -07004418 rt = ip6_route_info_create(&r_cfg, GFP_KERNEL, extack);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07004419 if (IS_ERR(rt)) {
4420 err = PTR_ERR(rt);
4421 rt = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004422 goto cleanup;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07004423 }
David Ahernb5d2d752018-07-15 09:35:19 -07004424 if (!rt6_qualify_for_ecmp(rt)) {
4425 err = -EINVAL;
4426 NL_SET_ERR_MSG(extack,
4427 "Device only routes can not be added for IPv6 using the multipath API.");
4428 fib6_info_release(rt);
4429 goto cleanup;
4430 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004431
David Ahernad1601a2019-03-27 20:53:56 -07004432 rt->fib6_nh.fib_nh_weight = rtnh->rtnh_hops + 1;
Ido Schimmel398958a2018-01-09 16:40:28 +02004433
David Ahernd4ead6b2018-04-17 17:33:16 -07004434 err = ip6_route_info_append(info->nl_net, &rt6_nh_list,
4435 rt, &r_cfg);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004436 if (err) {
David Ahern93531c62018-04-17 17:33:25 -07004437 fib6_info_release(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004438 goto cleanup;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004439 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004440
4441 rtnh = rtnh_next(rtnh, &remaining);
4442 }
4443
David Ahern3b1137f2017-02-02 12:37:10 -08004444 /* for add and replace send one notification with all nexthops.
4445 * Skip the notification in fib6_add_rt2node and send one with
4446 * the full route when done
4447 */
4448 info->skip_notify = 1;
4449
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004450 err_nh = NULL;
4451 list_for_each_entry(nh, &rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004452 err = __ip6_ins_rt(nh->fib6_info, info, extack);
4453 fib6_info_release(nh->fib6_info);
David Ahern3b1137f2017-02-02 12:37:10 -08004454
David Ahernf7225172018-06-04 13:41:42 -07004455 if (!err) {
4456 /* save reference to last route successfully inserted */
4457 rt_last = nh->fib6_info;
4458
4459 /* save reference to first route for notification */
4460 if (!rt_notif)
4461 rt_notif = nh->fib6_info;
4462 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004463
David Ahern8d1c8022018-04-17 17:33:26 -07004464 /* nh->fib6_info is used or freed at this point, reset to NULL*/
4465 nh->fib6_info = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004466 if (err) {
4467 if (replace && nhn)
Jakub Kicinskia5a82d82019-01-14 10:52:45 -08004468 NL_SET_ERR_MSG_MOD(extack,
4469 "multipath route replace failed (check consistency of installed routes)");
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004470 err_nh = nh;
4471 goto add_errout;
4472 }
4473
Nicolas Dichtel1a724182012-11-01 22:58:22 +00004474 /* Because each route is added like a single route we remove
Michal Kubeček27596472015-05-18 20:54:00 +02004475 * these flags after the first nexthop: if there is a collision,
4476 * we have already failed to add the first nexthop:
4477 * fib6_add_rt2node() has rejected it; when replacing, old
4478 * nexthops have been replaced by first new, the rest should
4479 * be added to it.
Nicolas Dichtel1a724182012-11-01 22:58:22 +00004480 */
Michal Kubeček27596472015-05-18 20:54:00 +02004481 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
4482 NLM_F_REPLACE);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004483 nhn++;
4484 }
4485
David Ahern3b1137f2017-02-02 12:37:10 -08004486 /* success ... tell user about new route */
4487 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004488 goto cleanup;
4489
4490add_errout:
David Ahern3b1137f2017-02-02 12:37:10 -08004491 /* send notification for routes that were added so that
4492 * the delete notifications sent by ip6_route_del are
4493 * coherent
4494 */
4495 if (rt_notif)
4496 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
4497
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004498 /* Delete routes that were already added */
4499 list_for_each_entry(nh, &rt6_nh_list, next) {
4500 if (err_nh == nh)
4501 break;
David Ahern333c4302017-05-21 10:12:04 -06004502 ip6_route_del(&nh->r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004503 }
4504
4505cleanup:
4506 list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004507 if (nh->fib6_info)
4508 fib6_info_release(nh->fib6_info);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004509 list_del(&nh->next);
4510 kfree(nh);
4511 }
4512
4513 return err;
4514}
4515
David Ahern333c4302017-05-21 10:12:04 -06004516static int ip6_route_multipath_del(struct fib6_config *cfg,
4517 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004518{
4519 struct fib6_config r_cfg;
4520 struct rtnexthop *rtnh;
4521 int remaining;
4522 int attrlen;
4523 int err = 1, last_err = 0;
4524
4525 remaining = cfg->fc_mp_len;
4526 rtnh = (struct rtnexthop *)cfg->fc_mp;
4527
4528 /* Parse a Multipath Entry */
4529 while (rtnh_ok(rtnh, remaining)) {
4530 memcpy(&r_cfg, cfg, sizeof(*cfg));
4531 if (rtnh->rtnh_ifindex)
4532 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
4533
4534 attrlen = rtnh_attrlen(rtnh);
4535 if (attrlen > 0) {
4536 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
4537
4538 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
4539 if (nla) {
4540 nla_memcpy(&r_cfg.fc_gateway, nla, 16);
4541 r_cfg.fc_flags |= RTF_GATEWAY;
4542 }
4543 }
David Ahern333c4302017-05-21 10:12:04 -06004544 err = ip6_route_del(&r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004545 if (err)
4546 last_err = err;
4547
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004548 rtnh = rtnh_next(rtnh, &remaining);
4549 }
4550
4551 return last_err;
4552}
4553
David Ahernc21ef3e2017-04-16 09:48:24 -07004554static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
4555 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556{
Thomas Graf86872cb2006-08-22 00:01:08 -07004557 struct fib6_config cfg;
4558 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004559
David Ahern333c4302017-05-21 10:12:04 -06004560 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07004561 if (err < 0)
4562 return err;
4563
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004564 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06004565 return ip6_route_multipath_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08004566 else {
4567 cfg.fc_delete_all_nh = 1;
David Ahern333c4302017-05-21 10:12:04 -06004568 return ip6_route_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08004569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570}
4571
David Ahernc21ef3e2017-04-16 09:48:24 -07004572static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
4573 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574{
Thomas Graf86872cb2006-08-22 00:01:08 -07004575 struct fib6_config cfg;
4576 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577
David Ahern333c4302017-05-21 10:12:04 -06004578 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07004579 if (err < 0)
4580 return err;
4581
David Ahern67f69512019-03-21 05:21:34 -07004582 if (cfg.fc_metric == 0)
4583 cfg.fc_metric = IP6_RT_PRIO_USER;
4584
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004585 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06004586 return ip6_route_multipath_add(&cfg, extack);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004587 else
David Ahernacb54e32018-04-17 17:33:22 -07004588 return ip6_route_add(&cfg, GFP_KERNEL, extack);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589}
4590
David Ahern8d1c8022018-04-17 17:33:26 -07004591static size_t rt6_nlmsg_size(struct fib6_info *rt)
Thomas Graf339bf982006-11-10 14:10:15 -08004592{
David Ahernbeb1afac52017-02-02 12:37:09 -08004593 int nexthop_len = 0;
4594
David Ahern93c2fb22018-04-18 15:38:59 -07004595 if (rt->fib6_nsiblings) {
David Ahernbeb1afac52017-02-02 12:37:09 -08004596 nexthop_len = nla_total_size(0) /* RTA_MULTIPATH */
4597 + NLA_ALIGN(sizeof(struct rtnexthop))
4598 + nla_total_size(16) /* RTA_GATEWAY */
David Ahernad1601a2019-03-27 20:53:56 -07004599 + lwtunnel_get_encap_size(rt->fib6_nh.fib_nh_lws);
David Ahernbeb1afac52017-02-02 12:37:09 -08004600
David Ahern93c2fb22018-04-18 15:38:59 -07004601 nexthop_len *= rt->fib6_nsiblings;
David Ahernbeb1afac52017-02-02 12:37:09 -08004602 }
4603
Thomas Graf339bf982006-11-10 14:10:15 -08004604 return NLMSG_ALIGN(sizeof(struct rtmsg))
4605 + nla_total_size(16) /* RTA_SRC */
4606 + nla_total_size(16) /* RTA_DST */
4607 + nla_total_size(16) /* RTA_GATEWAY */
4608 + nla_total_size(16) /* RTA_PREFSRC */
4609 + nla_total_size(4) /* RTA_TABLE */
4610 + nla_total_size(4) /* RTA_IIF */
4611 + nla_total_size(4) /* RTA_OIF */
4612 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08004613 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Daniel Borkmannea697632015-01-05 23:57:47 +01004614 + nla_total_size(sizeof(struct rta_cacheinfo))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004615 + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004616 + nla_total_size(1) /* RTA_PREF */
David Ahernad1601a2019-03-27 20:53:56 -07004617 + lwtunnel_get_encap_size(rt->fib6_nh.fib_nh_lws)
David Ahernbeb1afac52017-02-02 12:37:09 -08004618 + nexthop_len;
4619}
4620
David Ahernd4ead6b2018-04-17 17:33:16 -07004621static int rt6_fill_node(struct net *net, struct sk_buff *skb,
David Ahern8d1c8022018-04-17 17:33:26 -07004622 struct fib6_info *rt, struct dst_entry *dst,
David Ahernd4ead6b2018-04-17 17:33:16 -07004623 struct in6_addr *dest, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00004624 int iif, int type, u32 portid, u32 seq,
David Ahernf8cfe2c2017-01-17 15:51:08 -08004625 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626{
Xin Long22d0bd82018-09-11 14:33:58 +08004627 struct rt6_info *rt6 = (struct rt6_info *)dst;
4628 struct rt6key *rt6_dst, *rt6_src;
4629 u32 *pmetrics, table, rt6_flags;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004630 struct nlmsghdr *nlh;
Xin Long22d0bd82018-09-11 14:33:58 +08004631 struct rtmsg *rtm;
David Ahernd4ead6b2018-04-17 17:33:16 -07004632 long expires = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633
Eric W. Biederman15e47302012-09-07 20:12:54 +00004634 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05004635 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08004636 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004637
Xin Long22d0bd82018-09-11 14:33:58 +08004638 if (rt6) {
4639 rt6_dst = &rt6->rt6i_dst;
4640 rt6_src = &rt6->rt6i_src;
4641 rt6_flags = rt6->rt6i_flags;
4642 } else {
4643 rt6_dst = &rt->fib6_dst;
4644 rt6_src = &rt->fib6_src;
4645 rt6_flags = rt->fib6_flags;
4646 }
4647
Thomas Graf2d7202b2006-08-22 00:01:27 -07004648 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 rtm->rtm_family = AF_INET6;
Xin Long22d0bd82018-09-11 14:33:58 +08004650 rtm->rtm_dst_len = rt6_dst->plen;
4651 rtm->rtm_src_len = rt6_src->plen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652 rtm->rtm_tos = 0;
David Ahern93c2fb22018-04-18 15:38:59 -07004653 if (rt->fib6_table)
4654 table = rt->fib6_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07004655 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07004656 table = RT6_TABLE_UNSPEC;
Kalash Nainwal97f00822019-02-20 16:23:04 -08004657 rtm->rtm_table = table < 256 ? table : RT_TABLE_COMPAT;
David S. Millerc78679e2012-04-01 20:27:33 -04004658 if (nla_put_u32(skb, RTA_TABLE, table))
4659 goto nla_put_failure;
David Aherne8478e82018-04-17 17:33:13 -07004660
4661 rtm->rtm_type = rt->fib6_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662 rtm->rtm_flags = 0;
4663 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
David Ahern93c2fb22018-04-18 15:38:59 -07004664 rtm->rtm_protocol = rt->fib6_protocol;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665
Xin Long22d0bd82018-09-11 14:33:58 +08004666 if (rt6_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004667 rtm->rtm_flags |= RTM_F_CLONED;
4668
David Ahernd4ead6b2018-04-17 17:33:16 -07004669 if (dest) {
4670 if (nla_put_in6_addr(skb, RTA_DST, dest))
David S. Millerc78679e2012-04-01 20:27:33 -04004671 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09004672 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673 } else if (rtm->rtm_dst_len)
Xin Long22d0bd82018-09-11 14:33:58 +08004674 if (nla_put_in6_addr(skb, RTA_DST, &rt6_dst->addr))
David S. Millerc78679e2012-04-01 20:27:33 -04004675 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004676#ifdef CONFIG_IPV6_SUBTREES
4677 if (src) {
Jiri Benc930345e2015-03-29 16:59:25 +02004678 if (nla_put_in6_addr(skb, RTA_SRC, src))
David S. Millerc78679e2012-04-01 20:27:33 -04004679 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09004680 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04004681 } else if (rtm->rtm_src_len &&
Xin Long22d0bd82018-09-11 14:33:58 +08004682 nla_put_in6_addr(skb, RTA_SRC, &rt6_src->addr))
David S. Millerc78679e2012-04-01 20:27:33 -04004683 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09004685 if (iif) {
4686#ifdef CONFIG_IPV6_MROUTE
Xin Long22d0bd82018-09-11 14:33:58 +08004687 if (ipv6_addr_is_multicast(&rt6_dst->addr)) {
David Ahernfd61c6b2017-01-17 15:51:07 -08004688 int err = ip6mr_get_route(net, skb, rtm, portid);
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02004689
David Ahernfd61c6b2017-01-17 15:51:07 -08004690 if (err == 0)
4691 return 0;
4692 if (err < 0)
4693 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09004694 } else
4695#endif
David S. Millerc78679e2012-04-01 20:27:33 -04004696 if (nla_put_u32(skb, RTA_IIF, iif))
4697 goto nla_put_failure;
David Ahernd4ead6b2018-04-17 17:33:16 -07004698 } else if (dest) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699 struct in6_addr saddr_buf;
David Ahernd4ead6b2018-04-17 17:33:16 -07004700 if (ip6_route_get_saddr(net, rt, dest, 0, &saddr_buf) == 0 &&
Jiri Benc930345e2015-03-29 16:59:25 +02004701 nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04004702 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07004704
David Ahern93c2fb22018-04-18 15:38:59 -07004705 if (rt->fib6_prefsrc.plen) {
Daniel Walterc3968a82011-04-13 21:10:57 +00004706 struct in6_addr saddr_buf;
David Ahern93c2fb22018-04-18 15:38:59 -07004707 saddr_buf = rt->fib6_prefsrc.addr;
Jiri Benc930345e2015-03-29 16:59:25 +02004708 if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04004709 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00004710 }
4711
David Ahernd4ead6b2018-04-17 17:33:16 -07004712 pmetrics = dst ? dst_metrics_ptr(dst) : rt->fib6_metrics->metrics;
4713 if (rtnetlink_put_metrics(skb, pmetrics) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07004714 goto nla_put_failure;
4715
David Ahern93c2fb22018-04-18 15:38:59 -07004716 if (nla_put_u32(skb, RTA_PRIORITY, rt->fib6_metric))
David S. Millerc78679e2012-04-01 20:27:33 -04004717 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00004718
David Ahernbeb1afac52017-02-02 12:37:09 -08004719 /* For multipath routes, walk the siblings list and add
4720 * each as a nexthop within RTA_MULTIPATH.
4721 */
Xin Long22d0bd82018-09-11 14:33:58 +08004722 if (rt6) {
4723 if (rt6_flags & RTF_GATEWAY &&
4724 nla_put_in6_addr(skb, RTA_GATEWAY, &rt6->rt6i_gateway))
4725 goto nla_put_failure;
4726
4727 if (dst->dev && nla_put_u32(skb, RTA_OIF, dst->dev->ifindex))
4728 goto nla_put_failure;
4729 } else if (rt->fib6_nsiblings) {
David Ahern8d1c8022018-04-17 17:33:26 -07004730 struct fib6_info *sibling, *next_sibling;
David Ahernbeb1afac52017-02-02 12:37:09 -08004731 struct nlattr *mp;
4732
4733 mp = nla_nest_start(skb, RTA_MULTIPATH);
4734 if (!mp)
4735 goto nla_put_failure;
4736
David Ahernc0a72072019-04-02 14:11:58 -07004737 if (fib_add_nexthop(skb, &rt->fib6_nh.nh_common,
4738 rt->fib6_nh.fib_nh_weight) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004739 goto nla_put_failure;
4740
4741 list_for_each_entry_safe(sibling, next_sibling,
David Ahern93c2fb22018-04-18 15:38:59 -07004742 &rt->fib6_siblings, fib6_siblings) {
David Ahernc0a72072019-04-02 14:11:58 -07004743 if (fib_add_nexthop(skb, &sibling->fib6_nh.nh_common,
4744 sibling->fib6_nh.fib_nh_weight) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004745 goto nla_put_failure;
4746 }
4747
4748 nla_nest_end(skb, mp);
4749 } else {
David Ahernc0a72072019-04-02 14:11:58 -07004750 if (fib_nexthop_info(skb, &rt->fib6_nh.nh_common,
4751 &rtm->rtm_flags, false) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004752 goto nla_put_failure;
4753 }
4754
Xin Long22d0bd82018-09-11 14:33:58 +08004755 if (rt6_flags & RTF_EXPIRES) {
David Ahern14895682018-04-17 17:33:17 -07004756 expires = dst ? dst->expires : rt->expires;
4757 expires -= jiffies;
4758 }
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07004759
David Ahernd4ead6b2018-04-17 17:33:16 -07004760 if (rtnl_put_cacheinfo(skb, dst, 0, expires, dst ? dst->error : 0) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08004761 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762
Xin Long22d0bd82018-09-11 14:33:58 +08004763 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt6_flags)))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004764 goto nla_put_failure;
4765
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004766
Johannes Berg053c0952015-01-16 22:09:00 +01004767 nlmsg_end(skb, nlh);
4768 return 0;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004769
4770nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08004771 nlmsg_cancel(skb, nlh);
4772 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773}
4774
David Ahern13e38902018-10-15 18:56:44 -07004775static bool fib6_info_uses_dev(const struct fib6_info *f6i,
4776 const struct net_device *dev)
4777{
David Ahernad1601a2019-03-27 20:53:56 -07004778 if (f6i->fib6_nh.fib_nh_dev == dev)
David Ahern13e38902018-10-15 18:56:44 -07004779 return true;
4780
4781 if (f6i->fib6_nsiblings) {
4782 struct fib6_info *sibling, *next_sibling;
4783
4784 list_for_each_entry_safe(sibling, next_sibling,
4785 &f6i->fib6_siblings, fib6_siblings) {
David Ahernad1601a2019-03-27 20:53:56 -07004786 if (sibling->fib6_nh.fib_nh_dev == dev)
David Ahern13e38902018-10-15 18:56:44 -07004787 return true;
4788 }
4789 }
4790
4791 return false;
4792}
4793
David Ahern8d1c8022018-04-17 17:33:26 -07004794int rt6_dump_route(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795{
4796 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
David Ahern13e38902018-10-15 18:56:44 -07004797 struct fib_dump_filter *filter = &arg->filter;
4798 unsigned int flags = NLM_F_MULTI;
David Ahern1f17e2f2017-01-26 13:54:08 -08004799 struct net *net = arg->net;
4800
David Ahern421842e2018-04-17 17:33:18 -07004801 if (rt == net->ipv6.fib6_null_entry)
David Ahern1f17e2f2017-01-26 13:54:08 -08004802 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803
David Ahern13e38902018-10-15 18:56:44 -07004804 if ((filter->flags & RTM_F_PREFIX) &&
4805 !(rt->fib6_flags & RTF_PREFIX_RT)) {
4806 /* success since this is not a prefix route */
4807 return 1;
4808 }
4809 if (filter->filter_set) {
4810 if ((filter->rt_type && rt->fib6_type != filter->rt_type) ||
4811 (filter->dev && !fib6_info_uses_dev(rt, filter->dev)) ||
4812 (filter->protocol && rt->fib6_protocol != filter->protocol)) {
David Ahernf8cfe2c2017-01-17 15:51:08 -08004813 return 1;
4814 }
David Ahern13e38902018-10-15 18:56:44 -07004815 flags |= NLM_F_DUMP_FILTERED;
David Ahernf8cfe2c2017-01-17 15:51:08 -08004816 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817
David Ahernd4ead6b2018-04-17 17:33:16 -07004818 return rt6_fill_node(net, arg->skb, rt, NULL, NULL, NULL, 0,
4819 RTM_NEWROUTE, NETLINK_CB(arg->cb->skb).portid,
David Ahern13e38902018-10-15 18:56:44 -07004820 arg->cb->nlh->nlmsg_seq, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821}
4822
Jakub Kicinski0eff0a22019-01-18 10:46:24 -08004823static int inet6_rtm_valid_getroute_req(struct sk_buff *skb,
4824 const struct nlmsghdr *nlh,
4825 struct nlattr **tb,
4826 struct netlink_ext_ack *extack)
4827{
4828 struct rtmsg *rtm;
4829 int i, err;
4830
4831 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) {
4832 NL_SET_ERR_MSG_MOD(extack,
4833 "Invalid header for get route request");
4834 return -EINVAL;
4835 }
4836
4837 if (!netlink_strict_get_check(skb))
4838 return nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX,
4839 rtm_ipv6_policy, extack);
4840
4841 rtm = nlmsg_data(nlh);
4842 if ((rtm->rtm_src_len && rtm->rtm_src_len != 128) ||
4843 (rtm->rtm_dst_len && rtm->rtm_dst_len != 128) ||
4844 rtm->rtm_table || rtm->rtm_protocol || rtm->rtm_scope ||
4845 rtm->rtm_type) {
4846 NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for get route request");
4847 return -EINVAL;
4848 }
4849 if (rtm->rtm_flags & ~RTM_F_FIB_MATCH) {
4850 NL_SET_ERR_MSG_MOD(extack,
4851 "Invalid flags for get route request");
4852 return -EINVAL;
4853 }
4854
4855 err = nlmsg_parse_strict(nlh, sizeof(*rtm), tb, RTA_MAX,
4856 rtm_ipv6_policy, extack);
4857 if (err)
4858 return err;
4859
4860 if ((tb[RTA_SRC] && !rtm->rtm_src_len) ||
4861 (tb[RTA_DST] && !rtm->rtm_dst_len)) {
4862 NL_SET_ERR_MSG_MOD(extack, "rtm_src_len and rtm_dst_len must be 128 for IPv6");
4863 return -EINVAL;
4864 }
4865
4866 for (i = 0; i <= RTA_MAX; i++) {
4867 if (!tb[i])
4868 continue;
4869
4870 switch (i) {
4871 case RTA_SRC:
4872 case RTA_DST:
4873 case RTA_IIF:
4874 case RTA_OIF:
4875 case RTA_MARK:
4876 case RTA_UID:
4877 case RTA_SPORT:
4878 case RTA_DPORT:
4879 case RTA_IP_PROTO:
4880 break;
4881 default:
4882 NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in get route request");
4883 return -EINVAL;
4884 }
4885 }
4886
4887 return 0;
4888}
4889
David Ahernc21ef3e2017-04-16 09:48:24 -07004890static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
4891 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09004893 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07004894 struct nlattr *tb[RTA_MAX+1];
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004895 int err, iif = 0, oif = 0;
David Aherna68886a2018-04-20 15:38:02 -07004896 struct fib6_info *from;
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004897 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07004899 struct sk_buff *skb;
4900 struct rtmsg *rtm;
Maciej Żenczykowski744486d2018-09-29 23:44:54 -07004901 struct flowi6 fl6 = {};
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004902 bool fibmatch;
Thomas Grafab364a62006-08-22 00:01:47 -07004903
Jakub Kicinski0eff0a22019-01-18 10:46:24 -08004904 err = inet6_rtm_valid_getroute_req(in_skb, nlh, tb, extack);
Thomas Grafab364a62006-08-22 00:01:47 -07004905 if (err < 0)
4906 goto errout;
4907
4908 err = -EINVAL;
Hannes Frederic Sowa38b70972016-06-11 20:08:19 +02004909 rtm = nlmsg_data(nlh);
4910 fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004911 fibmatch = !!(rtm->rtm_flags & RTM_F_FIB_MATCH);
Thomas Grafab364a62006-08-22 00:01:47 -07004912
4913 if (tb[RTA_SRC]) {
4914 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
4915 goto errout;
4916
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00004917 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07004918 }
4919
4920 if (tb[RTA_DST]) {
4921 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
4922 goto errout;
4923
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00004924 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07004925 }
4926
4927 if (tb[RTA_IIF])
4928 iif = nla_get_u32(tb[RTA_IIF]);
4929
4930 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004931 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07004932
Lorenzo Colitti2e47b292014-05-15 16:38:41 -07004933 if (tb[RTA_MARK])
4934 fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
4935
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09004936 if (tb[RTA_UID])
4937 fl6.flowi6_uid = make_kuid(current_user_ns(),
4938 nla_get_u32(tb[RTA_UID]));
4939 else
4940 fl6.flowi6_uid = iif ? INVALID_UID : current_uid();
4941
Roopa Prabhueacb9382018-05-22 14:03:28 -07004942 if (tb[RTA_SPORT])
4943 fl6.fl6_sport = nla_get_be16(tb[RTA_SPORT]);
4944
4945 if (tb[RTA_DPORT])
4946 fl6.fl6_dport = nla_get_be16(tb[RTA_DPORT]);
4947
4948 if (tb[RTA_IP_PROTO]) {
4949 err = rtm_getroute_parse_ip_proto(tb[RTA_IP_PROTO],
Hangbin Liu5e1a99e2019-02-27 16:15:29 +08004950 &fl6.flowi6_proto, AF_INET6,
4951 extack);
Roopa Prabhueacb9382018-05-22 14:03:28 -07004952 if (err)
4953 goto errout;
4954 }
4955
Thomas Grafab364a62006-08-22 00:01:47 -07004956 if (iif) {
4957 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004958 int flags = 0;
4959
Florian Westphal121622d2017-08-15 16:34:42 +02004960 rcu_read_lock();
4961
4962 dev = dev_get_by_index_rcu(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07004963 if (!dev) {
Florian Westphal121622d2017-08-15 16:34:42 +02004964 rcu_read_unlock();
Thomas Grafab364a62006-08-22 00:01:47 -07004965 err = -ENODEV;
4966 goto errout;
4967 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004968
4969 fl6.flowi6_iif = iif;
4970
4971 if (!ipv6_addr_any(&fl6.saddr))
4972 flags |= RT6_LOOKUP_F_HAS_SADDR;
4973
David Ahernb75cc8f2018-03-02 08:32:17 -08004974 dst = ip6_route_input_lookup(net, dev, &fl6, NULL, flags);
Florian Westphal121622d2017-08-15 16:34:42 +02004975
4976 rcu_read_unlock();
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004977 } else {
4978 fl6.flowi6_oif = oif;
4979
Ido Schimmel58acfd72017-12-20 12:28:25 +02004980 dst = ip6_route_output(net, NULL, &fl6);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004981 }
4982
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004983
4984 rt = container_of(dst, struct rt6_info, dst);
4985 if (rt->dst.error) {
4986 err = rt->dst.error;
4987 ip6_rt_put(rt);
4988 goto errout;
Thomas Grafab364a62006-08-22 00:01:47 -07004989 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990
WANG Cong9d6acb32017-03-01 20:48:39 -08004991 if (rt == net->ipv6.ip6_null_entry) {
4992 err = rt->dst.error;
4993 ip6_rt_put(rt);
4994 goto errout;
4995 }
4996
Linus Torvalds1da177e2005-04-16 15:20:36 -07004997 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05004998 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00004999 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07005000 err = -ENOBUFS;
5001 goto errout;
5002 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005003
Changli Gaod8d1f302010-06-10 23:31:35 -07005004 skb_dst_set(skb, &rt->dst);
David Aherna68886a2018-04-20 15:38:02 -07005005
5006 rcu_read_lock();
5007 from = rcu_dereference(rt->from);
5008
Roopa Prabhu18c3a612017-05-25 10:42:40 -07005009 if (fibmatch)
David Aherna68886a2018-04-20 15:38:02 -07005010 err = rt6_fill_node(net, skb, from, NULL, NULL, NULL, iif,
Roopa Prabhu18c3a612017-05-25 10:42:40 -07005011 RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
5012 nlh->nlmsg_seq, 0);
5013 else
David Aherna68886a2018-04-20 15:38:02 -07005014 err = rt6_fill_node(net, skb, from, dst, &fl6.daddr,
5015 &fl6.saddr, iif, RTM_NEWROUTE,
David Ahernd4ead6b2018-04-17 17:33:16 -07005016 NETLINK_CB(in_skb).portid, nlh->nlmsg_seq,
5017 0);
David Aherna68886a2018-04-20 15:38:02 -07005018 rcu_read_unlock();
5019
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07005021 kfree_skb(skb);
5022 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005023 }
5024
Eric W. Biederman15e47302012-09-07 20:12:54 +00005025 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07005026errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005027 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005028}
5029
David Ahern8d1c8022018-04-17 17:33:26 -07005030void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info,
Roopa Prabhu37a1d362015-09-13 10:18:33 -07005031 unsigned int nlm_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005032{
5033 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08005034 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08005035 u32 seq;
5036 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08005038 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05005039 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07005040
Roopa Prabhu19e42e42015-07-21 10:43:48 +02005041 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05005042 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07005043 goto errout;
5044
David Ahernd4ead6b2018-04-17 17:33:16 -07005045 err = rt6_fill_node(net, skb, rt, NULL, NULL, NULL, 0,
5046 event, info->portid, seq, nlm_flags);
Patrick McHardy26932562007-01-31 23:16:40 -08005047 if (err < 0) {
5048 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
5049 WARN_ON(err == -EMSGSIZE);
5050 kfree_skb(skb);
5051 goto errout;
5052 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00005053 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08005054 info->nlh, gfp_any());
5055 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07005056errout:
5057 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08005058 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059}
5060
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005061static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00005062 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005063{
Jiri Pirko351638e2013-05-28 01:30:21 +00005064 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09005065 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005066
WANG Cong242d3a42017-05-08 10:12:13 -07005067 if (!(dev->flags & IFF_LOOPBACK))
5068 return NOTIFY_OK;
5069
5070 if (event == NETDEV_REGISTER) {
David Ahernad1601a2019-03-27 20:53:56 -07005071 net->ipv6.fib6_null_entry->fib6_nh.fib_nh_dev = dev;
Changli Gaod8d1f302010-06-10 23:31:35 -07005072 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005073 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
5074#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07005075 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005076 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07005077 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005078 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
5079#endif
WANG Cong76da0702017-06-20 11:42:27 -07005080 } else if (event == NETDEV_UNREGISTER &&
5081 dev->reg_state != NETREG_UNREGISTERED) {
5082 /* NETDEV_UNREGISTER could be fired for multiple times by
5083 * netdev_wait_allrefs(). Make sure we only call this once.
5084 */
Eric Dumazet12d94a82017-08-15 04:09:51 -07005085 in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev);
WANG Cong242d3a42017-05-08 10:12:13 -07005086#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Eric Dumazet12d94a82017-08-15 04:09:51 -07005087 in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev);
5088 in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev);
WANG Cong242d3a42017-05-08 10:12:13 -07005089#endif
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005090 }
5091
5092 return NOTIFY_OK;
5093}
5094
Linus Torvalds1da177e2005-04-16 15:20:36 -07005095/*
5096 * /proc
5097 */
5098
5099#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100static int rt6_stats_seq_show(struct seq_file *seq, void *v)
5101{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005102 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005104 net->ipv6.rt6_stats->fib_nodes,
5105 net->ipv6.rt6_stats->fib_route_nodes,
Wei Wang81eb8442017-10-06 12:06:11 -07005106 atomic_read(&net->ipv6.rt6_stats->fib_rt_alloc),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005107 net->ipv6.rt6_stats->fib_rt_entries,
5108 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00005109 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005110 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005111
5112 return 0;
5113}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114#endif /* CONFIG_PROC_FS */
5115
5116#ifdef CONFIG_SYSCTL
5117
Linus Torvalds1da177e2005-04-16 15:20:36 -07005118static
Joe Perchesfe2c6332013-06-11 23:04:25 -07005119int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120 void __user *buffer, size_t *lenp, loff_t *ppos)
5121{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005122 struct net *net;
5123 int delay;
Aditya Pakkif0fb9b22018-12-24 10:30:17 -06005124 int ret;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005125 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005127
5128 net = (struct net *)ctl->extra1;
5129 delay = net->ipv6.sysctl.flush_delay;
Aditya Pakkif0fb9b22018-12-24 10:30:17 -06005130 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
5131 if (ret)
5132 return ret;
5133
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02005134 fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005135 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005136}
5137
David Ahern7c6bb7d2018-10-11 20:17:21 -07005138static int zero;
5139static int one = 1;
5140
David Aherned792e22018-10-08 14:06:34 -07005141static struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09005142 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08005144 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005145 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07005146 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005147 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148 },
5149 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08005151 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152 .maxlen = sizeof(int),
5153 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005154 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155 },
5156 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08005158 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159 .maxlen = sizeof(int),
5160 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005161 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162 },
5163 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08005165 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005166 .maxlen = sizeof(int),
5167 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005168 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169 },
5170 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005171 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08005172 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005173 .maxlen = sizeof(int),
5174 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005175 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176 },
5177 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08005179 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180 .maxlen = sizeof(int),
5181 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005182 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183 },
5184 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08005186 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187 .maxlen = sizeof(int),
5188 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07005189 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190 },
5191 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08005193 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194 .maxlen = sizeof(int),
5195 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005196 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197 },
5198 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08005200 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005201 .maxlen = sizeof(int),
5202 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07005203 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204 },
5205 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08005207 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208 .maxlen = sizeof(int),
5209 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005210 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211 },
David Ahern7c6bb7d2018-10-11 20:17:21 -07005212 {
5213 .procname = "skip_notify_on_dev_down",
5214 .data = &init_net.ipv6.sysctl.skip_notify_on_dev_down,
5215 .maxlen = sizeof(int),
5216 .mode = 0644,
5217 .proc_handler = proc_dointvec,
5218 .extra1 = &zero,
5219 .extra2 = &one,
5220 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08005221 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222};
5223
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00005224struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08005225{
5226 struct ctl_table *table;
5227
5228 table = kmemdup(ipv6_route_table_template,
5229 sizeof(ipv6_route_table_template),
5230 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09005231
5232 if (table) {
5233 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005234 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00005235 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09005236 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
5237 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
5238 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
5239 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
5240 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
5241 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
5242 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08005243 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
David Ahern7c6bb7d2018-10-11 20:17:21 -07005244 table[10].data = &net->ipv6.sysctl.skip_notify_on_dev_down;
Eric W. Biederman464dc802012-11-16 03:02:59 +00005245
5246 /* Don't export sysctls to unprivileged users */
5247 if (net->user_ns != &init_user_ns)
5248 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09005249 }
5250
Daniel Lezcano760f2d02008-01-10 02:53:43 -08005251 return table;
5252}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253#endif
5254
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00005255static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005256{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07005257 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005258
Alexey Dobriyan86393e52009-08-29 01:34:49 +00005259 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
5260 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005261
Eric Dumazetfc66f952010-10-08 06:37:34 +00005262 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
5263 goto out_ip6_dst_ops;
5264
David Ahern421842e2018-04-17 17:33:18 -07005265 net->ipv6.fib6_null_entry = kmemdup(&fib6_null_entry_template,
5266 sizeof(*net->ipv6.fib6_null_entry),
5267 GFP_KERNEL);
5268 if (!net->ipv6.fib6_null_entry)
5269 goto out_ip6_dst_entries;
5270
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005271 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
5272 sizeof(*net->ipv6.ip6_null_entry),
5273 GFP_KERNEL);
5274 if (!net->ipv6.ip6_null_entry)
David Ahern421842e2018-04-17 17:33:18 -07005275 goto out_fib6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005276 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005277 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
5278 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005279
5280#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Vincent Bernatfeca7d82017-08-08 20:23:49 +02005281 net->ipv6.fib6_has_custom_rules = false;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005282 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
5283 sizeof(*net->ipv6.ip6_prohibit_entry),
5284 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005285 if (!net->ipv6.ip6_prohibit_entry)
5286 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005287 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005288 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
5289 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005290
5291 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
5292 sizeof(*net->ipv6.ip6_blk_hole_entry),
5293 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005294 if (!net->ipv6.ip6_blk_hole_entry)
5295 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005296 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005297 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
5298 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005299#endif
5300
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07005301 net->ipv6.sysctl.flush_delay = 0;
5302 net->ipv6.sysctl.ip6_rt_max_size = 4096;
5303 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
5304 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
5305 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
5306 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
5307 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
5308 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
David Ahern7c6bb7d2018-10-11 20:17:21 -07005309 net->ipv6.sysctl.skip_notify_on_dev_down = 0;
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07005310
Benjamin Thery6891a342008-03-04 13:49:47 -08005311 net->ipv6.ip6_rt_gc_expire = 30*HZ;
5312
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005313 ret = 0;
5314out:
5315 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005316
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005317#ifdef CONFIG_IPV6_MULTIPLE_TABLES
5318out_ip6_prohibit_entry:
5319 kfree(net->ipv6.ip6_prohibit_entry);
5320out_ip6_null_entry:
5321 kfree(net->ipv6.ip6_null_entry);
5322#endif
David Ahern421842e2018-04-17 17:33:18 -07005323out_fib6_null_entry:
5324 kfree(net->ipv6.fib6_null_entry);
Eric Dumazetfc66f952010-10-08 06:37:34 +00005325out_ip6_dst_entries:
5326 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005327out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005328 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005329}
5330
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00005331static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005332{
David Ahern421842e2018-04-17 17:33:18 -07005333 kfree(net->ipv6.fib6_null_entry);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005334 kfree(net->ipv6.ip6_null_entry);
5335#ifdef CONFIG_IPV6_MULTIPLE_TABLES
5336 kfree(net->ipv6.ip6_prohibit_entry);
5337 kfree(net->ipv6.ip6_blk_hole_entry);
5338#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00005339 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005340}
5341
Thomas Grafd1896342012-06-18 12:08:33 +00005342static int __net_init ip6_route_net_init_late(struct net *net)
5343{
5344#ifdef CONFIG_PROC_FS
Christoph Hellwigc3506372018-04-10 19:42:55 +02005345 proc_create_net("ipv6_route", 0, net->proc_net, &ipv6_route_seq_ops,
5346 sizeof(struct ipv6_route_iter));
Christoph Hellwig3617d942018-04-13 20:38:35 +02005347 proc_create_net_single("rt6_stats", 0444, net->proc_net,
5348 rt6_stats_seq_show, NULL);
Thomas Grafd1896342012-06-18 12:08:33 +00005349#endif
5350 return 0;
5351}
5352
5353static void __net_exit ip6_route_net_exit_late(struct net *net)
5354{
5355#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00005356 remove_proc_entry("ipv6_route", net->proc_net);
5357 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00005358#endif
5359}
5360
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005361static struct pernet_operations ip6_route_net_ops = {
5362 .init = ip6_route_net_init,
5363 .exit = ip6_route_net_exit,
5364};
5365
David S. Millerc3426b42012-06-09 16:27:05 -07005366static int __net_init ipv6_inetpeer_init(struct net *net)
5367{
5368 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
5369
5370 if (!bp)
5371 return -ENOMEM;
5372 inet_peer_base_init(bp);
5373 net->ipv6.peers = bp;
5374 return 0;
5375}
5376
5377static void __net_exit ipv6_inetpeer_exit(struct net *net)
5378{
5379 struct inet_peer_base *bp = net->ipv6.peers;
5380
5381 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07005382 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07005383 kfree(bp);
5384}
5385
David S. Miller2b823f72012-06-09 19:00:16 -07005386static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07005387 .init = ipv6_inetpeer_init,
5388 .exit = ipv6_inetpeer_exit,
5389};
5390
Thomas Grafd1896342012-06-18 12:08:33 +00005391static struct pernet_operations ip6_route_net_late_ops = {
5392 .init = ip6_route_net_init_late,
5393 .exit = ip6_route_net_exit_late,
5394};
5395
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005396static struct notifier_block ip6_route_dev_notifier = {
5397 .notifier_call = ip6_route_dev_notify,
WANG Cong242d3a42017-05-08 10:12:13 -07005398 .priority = ADDRCONF_NOTIFY_PRIORITY - 10,
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005399};
5400
WANG Cong2f460932017-05-03 22:07:31 -07005401void __init ip6_route_init_special_entries(void)
5402{
5403 /* Registering of the loopback is done before this portion of code,
5404 * the loopback reference in rt6_info will not be taken, do it
5405 * manually for init_net */
David Ahernad1601a2019-03-27 20:53:56 -07005406 init_net.ipv6.fib6_null_entry->fib6_nh.fib_nh_dev = init_net.loopback_dev;
WANG Cong2f460932017-05-03 22:07:31 -07005407 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
5408 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5409 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
5410 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
5411 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5412 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
5413 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5414 #endif
5415}
5416
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005417int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005418{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005419 int ret;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07005420 int cpu;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005421
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08005422 ret = -ENOMEM;
5423 ip6_dst_ops_template.kmem_cachep =
5424 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
5425 SLAB_HWCACHE_ALIGN, NULL);
5426 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08005427 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07005428
Eric Dumazetfc66f952010-10-08 06:37:34 +00005429 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005430 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08005431 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08005432
David S. Millerc3426b42012-06-09 16:27:05 -07005433 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
5434 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07005435 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00005436
David S. Miller7e52b332012-06-15 15:51:55 -07005437 ret = register_pernet_subsys(&ip6_route_net_ops);
5438 if (ret)
5439 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07005440
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07005441 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
5442
David S. Millere8803b62012-06-16 01:12:19 -07005443 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005444 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005445 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005446
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005447 ret = xfrm6_init();
5448 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07005449 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08005450
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005451 ret = fib6_rules_init();
5452 if (ret)
5453 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08005454
Thomas Grafd1896342012-06-18 12:08:33 +00005455 ret = register_pernet_subsys(&ip6_route_net_late_ops);
5456 if (ret)
5457 goto fib6_rules_init;
5458
Florian Westphal16feebc2017-12-02 21:44:08 +01005459 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_NEWROUTE,
5460 inet6_rtm_newroute, NULL, 0);
5461 if (ret < 0)
5462 goto out_register_late_subsys;
5463
5464 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_DELROUTE,
5465 inet6_rtm_delroute, NULL, 0);
5466 if (ret < 0)
5467 goto out_register_late_subsys;
5468
5469 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_GETROUTE,
5470 inet6_rtm_getroute, NULL,
5471 RTNL_FLAG_DOIT_UNLOCKED);
5472 if (ret < 0)
Thomas Grafd1896342012-06-18 12:08:33 +00005473 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005474
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005475 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005476 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00005477 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005478
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07005479 for_each_possible_cpu(cpu) {
5480 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
5481
5482 INIT_LIST_HEAD(&ul->head);
5483 spin_lock_init(&ul->lock);
5484 }
5485
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005486out:
5487 return ret;
5488
Thomas Grafd1896342012-06-18 12:08:33 +00005489out_register_late_subsys:
Florian Westphal16feebc2017-12-02 21:44:08 +01005490 rtnl_unregister_all(PF_INET6);
Thomas Grafd1896342012-06-18 12:08:33 +00005491 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005492fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005493 fib6_rules_cleanup();
5494xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005495 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00005496out_fib6_init:
5497 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005498out_register_subsys:
5499 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07005500out_register_inetpeer:
5501 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00005502out_dst_entries:
5503 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005504out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005505 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005506 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507}
5508
5509void ip6_route_cleanup(void)
5510{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005511 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00005512 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07005513 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07005516 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005517 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00005518 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005519 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520}