blob: 27c0cc5d9d30e3689ebe6b8428cd4c586669d808 [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>
David Ahern3c618c12019-04-20 09:28:20 -070062#include <net/rtnh.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,
Eric Dumazetf05713e2019-04-22 18:35:03 -0700299 .fib6_ref = REFCOUNT_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
Eric Dumazet0e233872019-04-28 12:22:25 -0700383 from = xchg((__force struct fib6_info **)&rt->from, NULL);
David Ahern93531c62018-04-17 17:33:25 -0700384 fib6_info_release(from);
David S. Millerb3419362010-11-30 12:27:11 -0800385}
386
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
388 int how)
389{
390 struct rt6_info *rt = (struct rt6_info *)dst;
391 struct inet6_dev *idev = rt->rt6i_idev;
Denis V. Lunev5a3e55d2007-12-07 00:38:10 -0800392 struct net_device *loopback_dev =
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900393 dev_net(dev)->loopback_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394
Wei Wange5645f52017-08-14 10:44:59 -0700395 if (idev && idev->dev != loopback_dev) {
396 struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev);
397 if (loopback_idev) {
398 rt->rt6i_idev = loopback_idev;
399 in6_dev_put(idev);
David S. Miller97cac082012-07-02 22:43:47 -0700400 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 }
402}
403
Martin KaFai Lau5973fb12015-11-11 11:51:07 -0800404static bool __rt6_check_expired(const struct rt6_info *rt)
405{
406 if (rt->rt6i_flags & RTF_EXPIRES)
407 return time_after(jiffies, rt->dst.expires);
408 else
409 return false;
410}
411
Eric Dumazeta50feda2012-05-18 18:57:34 +0000412static bool rt6_check_expired(const struct rt6_info *rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413{
David Aherna68886a2018-04-20 15:38:02 -0700414 struct fib6_info *from;
415
416 from = rcu_dereference(rt->from);
417
Gao feng1716a962012-04-06 00:13:10 +0000418 if (rt->rt6i_flags & RTF_EXPIRES) {
419 if (time_after(jiffies, rt->dst.expires))
Eric Dumazeta50feda2012-05-18 18:57:34 +0000420 return true;
David Aherna68886a2018-04-20 15:38:02 -0700421 } else if (from) {
Xin Long1e2ea8a2017-08-26 20:10:10 +0800422 return rt->dst.obsolete != DST_OBSOLETE_FORCE_CHK ||
David Aherna68886a2018-04-20 15:38:02 -0700423 fib6_check_expired(from);
Gao feng1716a962012-04-06 00:13:10 +0000424 }
Eric Dumazeta50feda2012-05-18 18:57:34 +0000425 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426}
427
David Ahernb1d40992019-04-16 14:35:59 -0700428void fib6_select_path(const struct net *net, struct fib6_result *res,
429 struct flowi6 *fl6, int oif, bool have_oif_match,
430 const struct sk_buff *skb, int strict)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000431{
David Ahern8d1c8022018-04-17 17:33:26 -0700432 struct fib6_info *sibling, *next_sibling;
David Ahernb1d40992019-04-16 14:35:59 -0700433 struct fib6_info *match = res->f6i;
434
435 if (!match->fib6_nsiblings || have_oif_match)
436 goto out;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000437
Jakub Sitnickib673d6c2017-08-23 09:58:31 +0200438 /* We might have already computed the hash for ICMPv6 errors. In such
439 * case it will always be non-zero. Otherwise now is the time to do it.
440 */
441 if (!fl6->mp_hash)
David Ahernb4bac172018-03-02 08:32:18 -0800442 fl6->mp_hash = rt6_multipath_hash(net, fl6, skb, NULL);
Jakub Sitnickib673d6c2017-08-23 09:58:31 +0200443
David Ahernad1601a2019-03-27 20:53:56 -0700444 if (fl6->mp_hash <= atomic_read(&match->fib6_nh.fib_nh_upper_bound))
David Ahernb1d40992019-04-16 14:35:59 -0700445 goto out;
Ido Schimmelbbfcd772017-11-21 09:50:12 +0200446
David Ahern93c2fb22018-04-18 15:38:59 -0700447 list_for_each_entry_safe(sibling, next_sibling, &match->fib6_siblings,
448 fib6_siblings) {
David Ahern702cea52019-04-09 14:41:13 -0700449 const struct fib6_nh *nh = &sibling->fib6_nh;
David Ahern5e670d82018-04-17 17:33:14 -0700450 int nh_upper_bound;
451
David Ahern702cea52019-04-09 14:41:13 -0700452 nh_upper_bound = atomic_read(&nh->fib_nh_upper_bound);
David Ahern5e670d82018-04-17 17:33:14 -0700453 if (fl6->mp_hash > nh_upper_bound)
Ido Schimmel3d709f62018-01-09 16:40:27 +0200454 continue;
David Ahern702cea52019-04-09 14:41:13 -0700455 if (rt6_score_route(nh, sibling->fib6_flags, oif, strict) < 0)
Ido Schimmel3d709f62018-01-09 16:40:27 +0200456 break;
457 match = sibling;
458 break;
459 }
460
David Ahernb1d40992019-04-16 14:35:59 -0700461out:
462 res->f6i = match;
463 res->nh = &match->fib6_nh;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +0000464}
465
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466/*
Wei Wang66f5d6c2017-10-06 12:06:10 -0700467 * Route lookup. rcu_read_lock() should be held.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 */
469
David Ahern0c59d002019-04-09 14:41:18 -0700470static bool __rt6_device_match(struct net *net, const struct fib6_nh *nh,
471 const struct in6_addr *saddr, int oif, int flags)
472{
473 const struct net_device *dev;
474
475 if (nh->fib_nh_flags & RTNH_F_DEAD)
476 return false;
477
478 dev = nh->fib_nh_dev;
479 if (oif) {
480 if (dev->ifindex == oif)
481 return true;
482 } else {
483 if (ipv6_chk_addr(net, saddr, dev,
484 flags & RT6_LOOKUP_F_IFACE))
485 return true;
486 }
487
488 return false;
489}
490
David Ahern75ef7382019-04-16 14:36:07 -0700491static void rt6_device_match(struct net *net, struct fib6_result *res,
492 const struct in6_addr *saddr, int oif, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493{
David Ahern75ef7382019-04-16 14:36:07 -0700494 struct fib6_info *f6i = res->f6i;
495 struct fib6_info *spf6i;
496 struct fib6_nh *nh;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497
David Ahern75ef7382019-04-16 14:36:07 -0700498 if (!oif && ipv6_addr_any(saddr)) {
499 nh = &f6i->fib6_nh;
David Ahern7d21fec2019-04-16 14:36:11 -0700500 if (!(nh->fib_nh_flags & RTNH_F_DEAD))
501 goto out;
YOSHIFUJI Hideakidd3abc42008-07-02 18:30:18 +0900502 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
David Ahern75ef7382019-04-16 14:36:07 -0700504 for (spf6i = f6i; spf6i; spf6i = rcu_dereference(spf6i->fib6_next)) {
505 nh = &spf6i->fib6_nh;
506 if (__rt6_device_match(net, nh, saddr, oif, flags)) {
507 res->f6i = spf6i;
David Ahern7d21fec2019-04-16 14:36:11 -0700508 goto out;
David Ahern75ef7382019-04-16 14:36:07 -0700509 }
510 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
David Ahern75ef7382019-04-16 14:36:07 -0700512 if (oif && flags & RT6_LOOKUP_F_IFACE) {
513 res->f6i = net->ipv6.fib6_null_entry;
David Ahern7d21fec2019-04-16 14:36:11 -0700514 nh = &res->f6i->fib6_nh;
515 goto out;
David Ahern75ef7382019-04-16 14:36:07 -0700516 }
517
David Ahern7d21fec2019-04-16 14:36:11 -0700518 nh = &f6i->fib6_nh;
519 if (nh->fib_nh_flags & RTNH_F_DEAD) {
David Ahern75ef7382019-04-16 14:36:07 -0700520 res->f6i = net->ipv6.fib6_null_entry;
David Ahern7d21fec2019-04-16 14:36:11 -0700521 nh = &res->f6i->fib6_nh;
David Ahern75ef7382019-04-16 14:36:07 -0700522 }
David Ahern7d21fec2019-04-16 14:36:11 -0700523out:
524 res->nh = nh;
525 res->fib6_type = res->f6i->fib6_type;
526 res->fib6_flags = res->f6i->fib6_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527}
528
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800529#ifdef CONFIG_IPV6_ROUTER_PREF
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200530struct __rt6_probe_work {
531 struct work_struct work;
532 struct in6_addr target;
533 struct net_device *dev;
534};
535
536static void rt6_probe_deferred(struct work_struct *w)
537{
538 struct in6_addr mcaddr;
539 struct __rt6_probe_work *work =
540 container_of(w, struct __rt6_probe_work, work);
541
542 addrconf_addr_solict_mult(&work->target, &mcaddr);
Erik Nordmarkadc176c2016-12-02 14:00:08 -0800543 ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL, 0);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200544 dev_put(work->dev);
Michael Büsch662f5532015-02-08 10:14:07 +0100545 kfree(work);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200546}
547
David Aherncc3a86c2019-04-09 14:41:12 -0700548static void rt6_probe(struct fib6_nh *fib6_nh)
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800549{
Sabrina Dubrocaf547fac2018-10-12 16:22:47 +0200550 struct __rt6_probe_work *work = NULL;
David Ahern5e670d82018-04-17 17:33:14 -0700551 const struct in6_addr *nh_gw;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000552 struct neighbour *neigh;
David Ahern5e670d82018-04-17 17:33:14 -0700553 struct net_device *dev;
Sabrina Dubrocaf547fac2018-10-12 16:22:47 +0200554 struct inet6_dev *idev;
David Ahern5e670d82018-04-17 17:33:14 -0700555
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800556 /*
557 * Okay, this does not seem to be appropriate
558 * for now, however, we need to check if it
559 * is really so; aka Router Reachability Probing.
560 *
561 * Router Reachability Probe MUST be rate-limited
562 * to no more than one per minute.
563 */
David Aherncc3a86c2019-04-09 14:41:12 -0700564 if (fib6_nh->fib_nh_gw_family)
Amerigo Wangfdd66812012-09-10 02:48:44 +0000565 return;
David Ahern5e670d82018-04-17 17:33:14 -0700566
David Aherncc3a86c2019-04-09 14:41:12 -0700567 nh_gw = &fib6_nh->fib_nh_gw6;
568 dev = fib6_nh->fib_nh_dev;
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000569 rcu_read_lock_bh();
Sabrina Dubrocaf547fac2018-10-12 16:22:47 +0200570 idev = __in6_dev_get(dev);
David Ahern5e670d82018-04-17 17:33:14 -0700571 neigh = __ipv6_neigh_lookup_noref(dev, nh_gw);
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000572 if (neigh) {
Martin KaFai Lau8d6c31b2015-07-24 09:57:43 -0700573 if (neigh->nud_state & NUD_VALID)
574 goto out;
575
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000576 write_lock(&neigh->lock);
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700577 if (!(neigh->nud_state & NUD_VALID) &&
578 time_after(jiffies,
David Aherndcd1f572018-04-18 15:39:05 -0700579 neigh->updated + idev->cnf.rtr_probe_interval)) {
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700580 work = kmalloc(sizeof(*work), GFP_ATOMIC);
581 if (work)
582 __neigh_set_probe_once(neigh);
Hannes Frederic Sowac2f17e82013-10-21 06:17:15 +0200583 }
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000584 write_unlock(&neigh->lock);
David Aherncc3a86c2019-04-09 14:41:12 -0700585 } else if (time_after(jiffies, fib6_nh->last_probe +
Sabrina Dubrocaf547fac2018-10-12 16:22:47 +0200586 idev->cnf.rtr_probe_interval)) {
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700587 work = kmalloc(sizeof(*work), GFP_ATOMIC);
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000588 }
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700589
590 if (work) {
David Aherncc3a86c2019-04-09 14:41:12 -0700591 fib6_nh->last_probe = jiffies;
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700592 INIT_WORK(&work->work, rt6_probe_deferred);
David Ahern5e670d82018-04-17 17:33:14 -0700593 work->target = *nh_gw;
594 dev_hold(dev);
595 work->dev = dev;
Martin KaFai Lau990edb42015-07-24 09:57:42 -0700596 schedule_work(&work->work);
597 }
598
Martin KaFai Lau8d6c31b2015-07-24 09:57:43 -0700599out:
YOSHIFUJI Hideaki / 吉藤英明2152cae2013-01-17 12:53:43 +0000600 rcu_read_unlock_bh();
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800601}
602#else
David Aherncc3a86c2019-04-09 14:41:12 -0700603static inline void rt6_probe(struct fib6_nh *fib6_nh)
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800604{
YOSHIFUJI Hideaki27097252006-03-20 17:05:13 -0800605}
606#endif
607
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608/*
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800609 * Default Router Selection (RFC 2461 6.3.6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 */
David Ahern1ba9a892019-04-09 14:41:10 -0700611static enum rt6_nud_state rt6_check_neigh(const struct fib6_nh *fib6_nh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612{
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200613 enum rt6_nud_state ret = RT6_NUD_FAIL_HARD;
David Ahern5e670d82018-04-17 17:33:14 -0700614 struct neighbour *neigh;
Eric Dumazetf2c31e32011-07-29 19:00:53 +0000615
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000616 rcu_read_lock_bh();
David Ahern1ba9a892019-04-09 14:41:10 -0700617 neigh = __ipv6_neigh_lookup_noref(fib6_nh->fib_nh_dev,
618 &fib6_nh->fib_nh_gw6);
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000619 if (neigh) {
620 read_lock(&neigh->lock);
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800621 if (neigh->nud_state & NUD_VALID)
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200622 ret = RT6_NUD_SUCCEED;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800623#ifdef CONFIG_IPV6_ROUTER_PREF
Paul Marksa5a81f02012-12-03 10:26:54 +0000624 else if (!(neigh->nud_state & NUD_FAILED))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200625 ret = RT6_NUD_SUCCEED;
Jiri Benc7e980562013-12-11 13:48:20 +0100626 else
627 ret = RT6_NUD_FAIL_PROBE;
YOSHIFUJI Hideaki398bcbe2008-01-19 00:35:16 -0800628#endif
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000629 read_unlock(&neigh->lock);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200630 } else {
631 ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ?
Jiri Benc7e980562013-12-11 13:48:20 +0100632 RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR;
Paul Marksa5a81f02012-12-03 10:26:54 +0000633 }
YOSHIFUJI Hideaki / 吉藤英明145a3622013-01-17 12:53:38 +0000634 rcu_read_unlock_bh();
635
Paul Marksa5a81f02012-12-03 10:26:54 +0000636 return ret;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800637}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
David Ahern702cea52019-04-09 14:41:13 -0700639static int rt6_score_route(const struct fib6_nh *nh, u32 fib6_flags, int oif,
640 int strict)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800641{
David Ahern6e1809a2019-04-09 14:41:11 -0700642 int m = 0;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900643
David Ahern6e1809a2019-04-09 14:41:11 -0700644 if (!oif || nh->fib_nh_dev->ifindex == oif)
645 m = 2;
646
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -0700647 if (!m && (strict & RT6_LOOKUP_F_IFACE))
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200648 return RT6_NUD_FAIL_HARD;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800649#ifdef CONFIG_IPV6_ROUTER_PREF
David Ahern702cea52019-04-09 14:41:13 -0700650 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(fib6_flags)) << 2;
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -0800651#endif
David Ahern1ba9a892019-04-09 14:41:10 -0700652 if ((strict & RT6_LOOKUP_F_REACHABLE) &&
David Ahern702cea52019-04-09 14:41:13 -0700653 !(fib6_flags & RTF_NONEXTHOP) && nh->fib_nh_gw_family) {
David Ahern1ba9a892019-04-09 14:41:10 -0700654 int n = rt6_check_neigh(nh);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200655 if (n < 0)
656 return n;
657 }
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800658 return m;
659}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
David Ahern28679ed2019-04-09 14:41:14 -0700661static bool find_match(struct fib6_nh *nh, u32 fib6_flags,
662 int oif, int strict, int *mpri, bool *do_rr)
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800663{
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200664 bool match_do_rr = false;
David Ahern28679ed2019-04-09 14:41:14 -0700665 bool rc = false;
666 int m;
Andy Gospodarek35103d12015-08-13 10:39:01 -0400667
David Ahern28679ed2019-04-09 14:41:14 -0700668 if (nh->fib_nh_flags & RTNH_F_DEAD)
Ido Schimmel8067bb82018-01-07 12:45:09 +0200669 goto out;
670
David Ahern28679ed2019-04-09 14:41:14 -0700671 if (ip6_ignore_linkdown(nh->fib_nh_dev) &&
672 nh->fib_nh_flags & RTNH_F_LINKDOWN &&
David Ahernd5d32e42016-10-24 12:27:23 -0700673 !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE))
Andy Gospodarek35103d12015-08-13 10:39:01 -0400674 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700675
David Ahern28679ed2019-04-09 14:41:14 -0700676 m = rt6_score_route(nh, fib6_flags, oif, strict);
Jiri Benc7e980562013-12-11 13:48:20 +0100677 if (m == RT6_NUD_FAIL_DO_RR) {
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200678 match_do_rr = true;
679 m = 0; /* lowest valid score */
Jiri Benc7e980562013-12-11 13:48:20 +0100680 } else if (m == RT6_NUD_FAIL_HARD) {
David S. Millerf11e6652007-03-24 20:36:25 -0700681 goto out;
David S. Millerf11e6652007-03-24 20:36:25 -0700682 }
683
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200684 if (strict & RT6_LOOKUP_F_REACHABLE)
David Ahern28679ed2019-04-09 14:41:14 -0700685 rt6_probe(nh);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200686
Jiri Benc7e980562013-12-11 13:48:20 +0100687 /* note that m can be RT6_NUD_FAIL_PROBE at this point */
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200688 if (m > *mpri) {
689 *do_rr = match_do_rr;
690 *mpri = m;
David Ahern28679ed2019-04-09 14:41:14 -0700691 rc = true;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200692 }
David S. Millerf11e6652007-03-24 20:36:25 -0700693out:
David Ahern28679ed2019-04-09 14:41:14 -0700694 return rc;
David S. Millerf11e6652007-03-24 20:36:25 -0700695}
696
David Ahernb7bc4b62019-04-16 14:36:08 -0700697static void __find_rr_leaf(struct fib6_info *f6i_start,
David Ahern30c15f02019-04-09 14:41:15 -0700698 struct fib6_info *nomatch, u32 metric,
David Ahernb7bc4b62019-04-16 14:36:08 -0700699 struct fib6_result *res, struct fib6_info **cont,
David Ahern30c15f02019-04-09 14:41:15 -0700700 int oif, int strict, bool *do_rr, int *mpri)
David S. Millerf11e6652007-03-24 20:36:25 -0700701{
David Ahernb7bc4b62019-04-16 14:36:08 -0700702 struct fib6_info *f6i;
David Ahern30c15f02019-04-09 14:41:15 -0700703
David Ahernb7bc4b62019-04-16 14:36:08 -0700704 for (f6i = f6i_start;
705 f6i && f6i != nomatch;
706 f6i = rcu_dereference(f6i->fib6_next)) {
David Ahern30c15f02019-04-09 14:41:15 -0700707 struct fib6_nh *nh;
708
David Ahernb7bc4b62019-04-16 14:36:08 -0700709 if (cont && f6i->fib6_metric != metric) {
710 *cont = f6i;
David Ahern30c15f02019-04-09 14:41:15 -0700711 return;
712 }
713
David Ahernb7bc4b62019-04-16 14:36:08 -0700714 if (fib6_check_expired(f6i))
David Ahern30c15f02019-04-09 14:41:15 -0700715 continue;
716
David Ahernb7bc4b62019-04-16 14:36:08 -0700717 nh = &f6i->fib6_nh;
718 if (find_match(nh, f6i->fib6_flags, oif, strict, mpri, do_rr)) {
719 res->f6i = f6i;
720 res->nh = nh;
David Ahern7d21fec2019-04-16 14:36:11 -0700721 res->fib6_flags = f6i->fib6_flags;
722 res->fib6_type = f6i->fib6_type;
David Ahernb7bc4b62019-04-16 14:36:08 -0700723 }
David Ahern30c15f02019-04-09 14:41:15 -0700724 }
725}
726
David Ahernb7bc4b62019-04-16 14:36:08 -0700727static void find_rr_leaf(struct fib6_node *fn, struct fib6_info *leaf,
728 struct fib6_info *rr_head, int oif, int strict,
729 bool *do_rr, struct fib6_result *res)
David Ahern30c15f02019-04-09 14:41:15 -0700730{
David Ahernb7bc4b62019-04-16 14:36:08 -0700731 u32 metric = rr_head->fib6_metric;
732 struct fib6_info *cont = NULL;
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800733 int mpri = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
David Ahernb7bc4b62019-04-16 14:36:08 -0700735 __find_rr_leaf(rr_head, NULL, metric, res, &cont,
David Ahern30c15f02019-04-09 14:41:15 -0700736 oif, strict, do_rr, &mpri);
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700737
David Ahernb7bc4b62019-04-16 14:36:08 -0700738 __find_rr_leaf(leaf, rr_head, metric, res, &cont,
David Ahern30c15f02019-04-09 14:41:15 -0700739 oif, strict, do_rr, &mpri);
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700740
David Ahernb7bc4b62019-04-16 14:36:08 -0700741 if (res->f6i || !cont)
742 return;
Steffen Klassert9fbdcfa2015-04-28 13:03:04 -0700743
David Ahernb7bc4b62019-04-16 14:36:08 -0700744 __find_rr_leaf(cont, NULL, metric, res, NULL,
David Ahern30c15f02019-04-09 14:41:15 -0700745 oif, strict, do_rr, &mpri);
David S. Millerf11e6652007-03-24 20:36:25 -0700746}
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800747
David Ahernb7bc4b62019-04-16 14:36:08 -0700748static void rt6_select(struct net *net, struct fib6_node *fn, int oif,
749 struct fib6_result *res, int strict)
David S. Millerf11e6652007-03-24 20:36:25 -0700750{
David Ahern8d1c8022018-04-17 17:33:26 -0700751 struct fib6_info *leaf = rcu_dereference(fn->leaf);
David Ahernb7bc4b62019-04-16 14:36:08 -0700752 struct fib6_info *rt0;
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200753 bool do_rr = false;
Wei Wang17ecf592017-10-06 12:06:09 -0700754 int key_plen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755
David Ahernb7bc4b62019-04-16 14:36:08 -0700756 /* make sure this function or its helpers sets f6i */
757 res->f6i = NULL;
758
David Ahern421842e2018-04-17 17:33:18 -0700759 if (!leaf || leaf == net->ipv6.fib6_null_entry)
David Ahernb7bc4b62019-04-16 14:36:08 -0700760 goto out;
Wei Wang8d1040e2017-10-06 12:06:08 -0700761
Wei Wang66f5d6c2017-10-06 12:06:10 -0700762 rt0 = rcu_dereference(fn->rr_ptr);
David S. Millerf11e6652007-03-24 20:36:25 -0700763 if (!rt0)
Wei Wang66f5d6c2017-10-06 12:06:10 -0700764 rt0 = leaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
Wei Wang17ecf592017-10-06 12:06:09 -0700766 /* Double check to make sure fn is not an intermediate node
767 * and fn->leaf does not points to its child's leaf
768 * (This might happen if all routes under fn are deleted from
769 * the tree and fib6_repair_tree() is called on the node.)
770 */
David Ahern93c2fb22018-04-18 15:38:59 -0700771 key_plen = rt0->fib6_dst.plen;
Wei Wang17ecf592017-10-06 12:06:09 -0700772#ifdef CONFIG_IPV6_SUBTREES
David Ahern93c2fb22018-04-18 15:38:59 -0700773 if (rt0->fib6_src.plen)
774 key_plen = rt0->fib6_src.plen;
Wei Wang17ecf592017-10-06 12:06:09 -0700775#endif
776 if (fn->fn_bit != key_plen)
David Ahernb7bc4b62019-04-16 14:36:08 -0700777 goto out;
Wei Wang17ecf592017-10-06 12:06:09 -0700778
David Ahernb7bc4b62019-04-16 14:36:08 -0700779 find_rr_leaf(fn, leaf, rt0, oif, strict, &do_rr, res);
Hannes Frederic Sowaafc154e2013-07-11 12:43:42 +0200780 if (do_rr) {
David Ahern8fb11a92018-05-04 13:54:24 -0700781 struct fib6_info *next = rcu_dereference(rt0->fib6_next);
David S. Millerf11e6652007-03-24 20:36:25 -0700782
YOSHIFUJI Hideaki554cfb72006-03-20 17:00:26 -0800783 /* no entries matched; do round-robin */
David Ahern93c2fb22018-04-18 15:38:59 -0700784 if (!next || next->fib6_metric != rt0->fib6_metric)
Wei Wang8d1040e2017-10-06 12:06:08 -0700785 next = leaf;
David S. Millerf11e6652007-03-24 20:36:25 -0700786
Wei Wang66f5d6c2017-10-06 12:06:10 -0700787 if (next != rt0) {
David Ahern93c2fb22018-04-18 15:38:59 -0700788 spin_lock_bh(&leaf->fib6_table->tb6_lock);
Wei Wang66f5d6c2017-10-06 12:06:10 -0700789 /* make sure next is not being deleted from the tree */
David Ahern93c2fb22018-04-18 15:38:59 -0700790 if (next->fib6_node)
Wei Wang66f5d6c2017-10-06 12:06:10 -0700791 rcu_assign_pointer(fn->rr_ptr, next);
David Ahern93c2fb22018-04-18 15:38:59 -0700792 spin_unlock_bh(&leaf->fib6_table->tb6_lock);
Wei Wang66f5d6c2017-10-06 12:06:10 -0700793 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 }
795
David Ahernb7bc4b62019-04-16 14:36:08 -0700796out:
797 if (!res->f6i) {
798 res->f6i = net->ipv6.fib6_null_entry;
799 res->nh = &res->f6i->fib6_nh;
David Ahern7d21fec2019-04-16 14:36:11 -0700800 res->fib6_flags = res->f6i->fib6_flags;
801 res->fib6_type = res->f6i->fib6_type;
David Ahernb7bc4b62019-04-16 14:36:08 -0700802 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803}
804
David Ahern85bd05d2019-04-16 14:36:01 -0700805static bool rt6_is_gw_or_nonexthop(const struct fib6_result *res)
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700806{
David Ahern85bd05d2019-04-16 14:36:01 -0700807 return (res->f6i->fib6_flags & RTF_NONEXTHOP) ||
808 res->nh->fib_nh_gw_family;
Martin KaFai Lau8b9df262015-05-22 20:55:59 -0700809}
810
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800811#ifdef CONFIG_IPV6_ROUTE_INFO
812int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000813 const struct in6_addr *gwaddr)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800814{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900815 struct net *net = dev_net(dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800816 struct route_info *rinfo = (struct route_info *) opt;
817 struct in6_addr prefix_buf, *prefix;
818 unsigned int pref;
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900819 unsigned long lifetime;
David Ahern8d1c8022018-04-17 17:33:26 -0700820 struct fib6_info *rt;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800821
822 if (len < sizeof(struct route_info)) {
823 return -EINVAL;
824 }
825
826 /* Sanity check for prefix_len and length */
827 if (rinfo->length > 3) {
828 return -EINVAL;
829 } else if (rinfo->prefix_len > 128) {
830 return -EINVAL;
831 } else if (rinfo->prefix_len > 64) {
832 if (rinfo->length < 2) {
833 return -EINVAL;
834 }
835 } else if (rinfo->prefix_len > 0) {
836 if (rinfo->length < 1) {
837 return -EINVAL;
838 }
839 }
840
841 pref = rinfo->route_pref;
842 if (pref == ICMPV6_ROUTER_PREF_INVALID)
Jens Rosenboom3933fc92009-09-10 06:25:11 +0000843 return -EINVAL;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800844
YOSHIFUJI Hideaki4bed72e2008-05-27 17:37:49 +0900845 lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800846
847 if (rinfo->length == 3)
848 prefix = (struct in6_addr *)rinfo->prefix;
849 else {
850 /* this function is safe */
851 ipv6_addr_prefix(&prefix_buf,
852 (struct in6_addr *)rinfo->prefix,
853 rinfo->prefix_len);
854 prefix = &prefix_buf;
855 }
856
Duan Jiongf104a562013-11-08 09:56:53 +0800857 if (rinfo->prefix_len == 0)
David Ahernafb1d4b52018-04-17 17:33:11 -0700858 rt = rt6_get_dflt_router(net, gwaddr, dev);
Duan Jiongf104a562013-11-08 09:56:53 +0800859 else
860 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len,
David Ahern830218c2016-10-24 10:52:35 -0700861 gwaddr, dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800862
863 if (rt && !lifetime) {
David Ahernafb1d4b52018-04-17 17:33:11 -0700864 ip6_del_rt(net, rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800865 rt = NULL;
866 }
867
868 if (!rt && lifetime)
David Ahern830218c2016-10-24 10:52:35 -0700869 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr,
870 dev, pref);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800871 else if (rt)
David Ahern93c2fb22018-04-18 15:38:59 -0700872 rt->fib6_flags = RTF_ROUTEINFO |
873 (rt->fib6_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800874
875 if (rt) {
Gao feng1716a962012-04-06 00:13:10 +0000876 if (!addrconf_finite_timeout(lifetime))
David Ahern14895682018-04-17 17:33:17 -0700877 fib6_clean_expires(rt);
Gao feng1716a962012-04-06 00:13:10 +0000878 else
David Ahern14895682018-04-17 17:33:17 -0700879 fib6_set_expires(rt, jiffies + HZ * lifetime);
Gao feng1716a962012-04-06 00:13:10 +0000880
David Ahern93531c62018-04-17 17:33:25 -0700881 fib6_info_release(rt);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -0800882 }
883 return 0;
884}
885#endif
886
David Ahernae90d862018-04-17 17:33:12 -0700887/*
888 * Misc support functions
889 */
890
891/* called with rcu_lock held */
David Ahern0d161582019-04-16 14:36:04 -0700892static struct net_device *ip6_rt_get_dev_rcu(const struct fib6_result *res)
David Ahernae90d862018-04-17 17:33:12 -0700893{
David Ahern0d161582019-04-16 14:36:04 -0700894 struct net_device *dev = res->nh->fib_nh_dev;
David Ahernae90d862018-04-17 17:33:12 -0700895
David Ahern7d21fec2019-04-16 14:36:11 -0700896 if (res->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) {
David Ahernae90d862018-04-17 17:33:12 -0700897 /* for copies of local routes, dst->dev needs to be the
898 * device if it is a master device, the master device if
899 * device is enslaved, and the loopback as the default
900 */
901 if (netif_is_l3_slave(dev) &&
David Ahern7d21fec2019-04-16 14:36:11 -0700902 !rt6_need_strict(&res->f6i->fib6_dst.addr))
David Ahernae90d862018-04-17 17:33:12 -0700903 dev = l3mdev_master_dev_rcu(dev);
904 else if (!netif_is_l3_master(dev))
905 dev = dev_net(dev)->loopback_dev;
906 /* last case is netif_is_l3_master(dev) is true in which
907 * case we want dev returned to be dev
908 */
909 }
910
911 return dev;
912}
913
David Ahern6edb3c92018-04-17 17:33:15 -0700914static const int fib6_prop[RTN_MAX + 1] = {
915 [RTN_UNSPEC] = 0,
916 [RTN_UNICAST] = 0,
917 [RTN_LOCAL] = 0,
918 [RTN_BROADCAST] = 0,
919 [RTN_ANYCAST] = 0,
920 [RTN_MULTICAST] = 0,
921 [RTN_BLACKHOLE] = -EINVAL,
922 [RTN_UNREACHABLE] = -EHOSTUNREACH,
923 [RTN_PROHIBIT] = -EACCES,
924 [RTN_THROW] = -EAGAIN,
925 [RTN_NAT] = -EINVAL,
926 [RTN_XRESOLVE] = -EINVAL,
927};
928
929static int ip6_rt_type_to_error(u8 fib6_type)
930{
931 return fib6_prop[fib6_type];
932}
933
David Ahern8d1c8022018-04-17 17:33:26 -0700934static unsigned short fib6_info_dst_flags(struct fib6_info *rt)
David Ahern3b6761d2018-04-17 17:33:20 -0700935{
936 unsigned short flags = 0;
937
938 if (rt->dst_nocount)
939 flags |= DST_NOCOUNT;
940 if (rt->dst_nopolicy)
941 flags |= DST_NOPOLICY;
942 if (rt->dst_host)
943 flags |= DST_HOST;
944
945 return flags;
946}
947
David Ahern7d21fec2019-04-16 14:36:11 -0700948static void ip6_rt_init_dst_reject(struct rt6_info *rt, u8 fib6_type)
David Ahern6edb3c92018-04-17 17:33:15 -0700949{
David Ahern7d21fec2019-04-16 14:36:11 -0700950 rt->dst.error = ip6_rt_type_to_error(fib6_type);
David Ahern6edb3c92018-04-17 17:33:15 -0700951
David Ahern7d21fec2019-04-16 14:36:11 -0700952 switch (fib6_type) {
David Ahern6edb3c92018-04-17 17:33:15 -0700953 case RTN_BLACKHOLE:
954 rt->dst.output = dst_discard_out;
955 rt->dst.input = dst_discard;
956 break;
957 case RTN_PROHIBIT:
958 rt->dst.output = ip6_pkt_prohibit_out;
959 rt->dst.input = ip6_pkt_prohibit;
960 break;
961 case RTN_THROW:
962 case RTN_UNREACHABLE:
963 default:
964 rt->dst.output = ip6_pkt_discard_out;
965 rt->dst.input = ip6_pkt_discard;
966 break;
967 }
968}
969
David Ahern0d161582019-04-16 14:36:04 -0700970static void ip6_rt_init_dst(struct rt6_info *rt, const struct fib6_result *res)
David Ahern6edb3c92018-04-17 17:33:15 -0700971{
David Ahern7d21fec2019-04-16 14:36:11 -0700972 struct fib6_info *f6i = res->f6i;
David Ahern0d161582019-04-16 14:36:04 -0700973
David Ahern7d21fec2019-04-16 14:36:11 -0700974 if (res->fib6_flags & RTF_REJECT) {
975 ip6_rt_init_dst_reject(rt, res->fib6_type);
David Ahern6edb3c92018-04-17 17:33:15 -0700976 return;
977 }
978
979 rt->dst.error = 0;
980 rt->dst.output = ip6_output;
981
David Ahern7d21fec2019-04-16 14:36:11 -0700982 if (res->fib6_type == RTN_LOCAL || res->fib6_type == RTN_ANYCAST) {
David Ahern6edb3c92018-04-17 17:33:15 -0700983 rt->dst.input = ip6_input;
David Ahern7d21fec2019-04-16 14:36:11 -0700984 } else if (ipv6_addr_type(&f6i->fib6_dst.addr) & IPV6_ADDR_MULTICAST) {
David Ahern6edb3c92018-04-17 17:33:15 -0700985 rt->dst.input = ip6_mc_input;
986 } else {
987 rt->dst.input = ip6_forward;
988 }
989
David Ahern0d161582019-04-16 14:36:04 -0700990 if (res->nh->fib_nh_lws) {
991 rt->dst.lwtstate = lwtstate_get(res->nh->fib_nh_lws);
David Ahern6edb3c92018-04-17 17:33:15 -0700992 lwtunnel_set_redirect(&rt->dst);
993 }
994
995 rt->dst.lastuse = jiffies;
996}
997
Wei Wange873e4b2018-07-21 20:56:32 -0700998/* Caller must already hold reference to @from */
David Ahern8d1c8022018-04-17 17:33:26 -0700999static void rt6_set_from(struct rt6_info *rt, struct fib6_info *from)
David Ahernae90d862018-04-17 17:33:12 -07001000{
David Ahernae90d862018-04-17 17:33:12 -07001001 rt->rt6i_flags &= ~RTF_EXPIRES;
David Aherna68886a2018-04-20 15:38:02 -07001002 rcu_assign_pointer(rt->from, from);
David Aherne1255ed2018-10-04 20:07:53 -07001003 ip_dst_init_metrics(&rt->dst, from->fib6_metrics);
David Ahernae90d862018-04-17 17:33:12 -07001004}
1005
David Ahern0d161582019-04-16 14:36:04 -07001006/* Caller must already hold reference to f6i in result */
1007static void ip6_rt_copy_init(struct rt6_info *rt, const struct fib6_result *res)
David Ahernae90d862018-04-17 17:33:12 -07001008{
David Ahern0d161582019-04-16 14:36:04 -07001009 const struct fib6_nh *nh = res->nh;
1010 const struct net_device *dev = nh->fib_nh_dev;
1011 struct fib6_info *f6i = res->f6i;
David Aherndcd1f572018-04-18 15:39:05 -07001012
David Ahern0d161582019-04-16 14:36:04 -07001013 ip6_rt_init_dst(rt, res);
David Ahern6edb3c92018-04-17 17:33:15 -07001014
David Ahern0d161582019-04-16 14:36:04 -07001015 rt->rt6i_dst = f6i->fib6_dst;
David Aherndcd1f572018-04-18 15:39:05 -07001016 rt->rt6i_idev = dev ? in6_dev_get(dev) : NULL;
David Ahern7d21fec2019-04-16 14:36:11 -07001017 rt->rt6i_flags = res->fib6_flags;
David Ahern0d161582019-04-16 14:36:04 -07001018 if (nh->fib_nh_gw_family) {
1019 rt->rt6i_gateway = nh->fib_nh_gw6;
David Ahern2b2450c2019-03-27 20:53:52 -07001020 rt->rt6i_flags |= RTF_GATEWAY;
1021 }
David Ahern0d161582019-04-16 14:36:04 -07001022 rt6_set_from(rt, f6i);
David Ahernae90d862018-04-17 17:33:12 -07001023#ifdef CONFIG_IPV6_SUBTREES
David Ahern0d161582019-04-16 14:36:04 -07001024 rt->rt6i_src = f6i->fib6_src;
David Ahernae90d862018-04-17 17:33:12 -07001025#endif
David Ahernae90d862018-04-17 17:33:12 -07001026}
1027
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001028static struct fib6_node* fib6_backtrack(struct fib6_node *fn,
1029 struct in6_addr *saddr)
1030{
Wei Wang66f5d6c2017-10-06 12:06:10 -07001031 struct fib6_node *pn, *sn;
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001032 while (1) {
1033 if (fn->fn_flags & RTN_TL_ROOT)
1034 return NULL;
Wei Wang66f5d6c2017-10-06 12:06:10 -07001035 pn = rcu_dereference(fn->parent);
1036 sn = FIB6_SUBTREE(pn);
1037 if (sn && sn != fn)
David Ahern64547432018-05-09 20:34:19 -07001038 fn = fib6_node_lookup(sn, NULL, saddr);
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001039 else
1040 fn = pn;
1041 if (fn->fn_flags & RTN_RTINFO)
1042 return fn;
1043 }
1044}
Thomas Grafc71099a2006-08-04 23:20:06 -07001045
David Ahern10585b42019-03-20 09:24:50 -07001046static bool ip6_hold_safe(struct net *net, struct rt6_info **prt)
Wei Wangd3843fe2017-10-06 12:06:06 -07001047{
1048 struct rt6_info *rt = *prt;
1049
1050 if (dst_hold_safe(&rt->dst))
1051 return true;
David Ahern10585b42019-03-20 09:24:50 -07001052 if (net) {
Wei Wangd3843fe2017-10-06 12:06:06 -07001053 rt = net->ipv6.ip6_null_entry;
1054 dst_hold(&rt->dst);
1055 } else {
1056 rt = NULL;
1057 }
1058 *prt = rt;
1059 return false;
1060}
1061
David Aherndec9b0e2018-04-17 17:33:19 -07001062/* called with rcu_lock held */
David Ahern9b6b35a2019-04-16 14:36:02 -07001063static struct rt6_info *ip6_create_rt_rcu(const struct fib6_result *res)
David Aherndec9b0e2018-04-17 17:33:19 -07001064{
David Ahern9b6b35a2019-04-16 14:36:02 -07001065 struct net_device *dev = res->nh->fib_nh_dev;
1066 struct fib6_info *f6i = res->f6i;
1067 unsigned short flags;
David Aherndec9b0e2018-04-17 17:33:19 -07001068 struct rt6_info *nrt;
1069
David Ahern9b6b35a2019-04-16 14:36:02 -07001070 if (!fib6_info_hold_safe(f6i))
Xin Long1c87e792019-03-20 14:45:48 +08001071 goto fallback;
Wei Wange873e4b2018-07-21 20:56:32 -07001072
David Ahern9b6b35a2019-04-16 14:36:02 -07001073 flags = fib6_info_dst_flags(f6i);
David Ahern93531c62018-04-17 17:33:25 -07001074 nrt = ip6_dst_alloc(dev_net(dev), dev, flags);
Xin Long1c87e792019-03-20 14:45:48 +08001075 if (!nrt) {
David Ahern9b6b35a2019-04-16 14:36:02 -07001076 fib6_info_release(f6i);
Xin Long1c87e792019-03-20 14:45:48 +08001077 goto fallback;
1078 }
David Aherndec9b0e2018-04-17 17:33:19 -07001079
David Ahern0d161582019-04-16 14:36:04 -07001080 ip6_rt_copy_init(nrt, res);
Xin Long1c87e792019-03-20 14:45:48 +08001081 return nrt;
1082
1083fallback:
1084 nrt = dev_net(dev)->ipv6.ip6_null_entry;
1085 dst_hold(&nrt->dst);
David Aherndec9b0e2018-04-17 17:33:19 -07001086 return nrt;
1087}
1088
Daniel Lezcano8ed67782008-03-04 13:48:30 -08001089static struct rt6_info *ip6_pol_route_lookup(struct net *net,
1090 struct fib6_table *table,
David Ahernb75cc8f2018-03-02 08:32:17 -08001091 struct flowi6 *fl6,
1092 const struct sk_buff *skb,
1093 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094{
David Ahernb1d40992019-04-16 14:35:59 -07001095 struct fib6_result res = {};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 struct fib6_node *fn;
David Ahern23fb93a2018-04-17 17:33:23 -07001097 struct rt6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
David Ahernb6cdbc82018-03-29 17:44:57 -07001099 if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
1100 flags &= ~RT6_LOOKUP_F_IFACE;
1101
Wei Wang66f5d6c2017-10-06 12:06:10 -07001102 rcu_read_lock();
David Ahern64547432018-05-09 20:34:19 -07001103 fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Thomas Grafc71099a2006-08-04 23:20:06 -07001104restart:
David Ahernb1d40992019-04-16 14:35:59 -07001105 res.f6i = rcu_dereference(fn->leaf);
1106 if (!res.f6i)
1107 res.f6i = net->ipv6.fib6_null_entry;
David Ahernaf52a522019-04-09 14:41:16 -07001108 else
David Ahern75ef7382019-04-16 14:36:07 -07001109 rt6_device_match(net, &res, &fl6->saddr, fl6->flowi6_oif,
1110 flags);
David Ahernaf52a522019-04-09 14:41:16 -07001111
David Ahernb1d40992019-04-16 14:35:59 -07001112 if (res.f6i == net->ipv6.fib6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001113 fn = fib6_backtrack(fn, &fl6->saddr);
1114 if (fn)
1115 goto restart;
David Ahernaf52a522019-04-09 14:41:16 -07001116
1117 rt = net->ipv6.ip6_null_entry;
1118 dst_hold(&rt->dst);
1119 goto out;
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001120 }
Wei Wang2b760fc2017-10-06 12:06:03 -07001121
David Ahernb1d40992019-04-16 14:35:59 -07001122 fib6_select_path(net, &res, fl6, fl6->flowi6_oif,
1123 fl6->flowi6_oif != 0, skb, flags);
1124
David S. Miller4c9483b2011-03-12 16:22:43 -05001125 /* Search through exception table */
David Ahern7e4b5122019-04-16 14:36:00 -07001126 rt = rt6_find_cached_rt(&res, &fl6->daddr, &fl6->saddr);
David Ahern23fb93a2018-04-17 17:33:23 -07001127 if (rt) {
David Ahern10585b42019-03-20 09:24:50 -07001128 if (ip6_hold_safe(net, &rt))
David Aherndec9b0e2018-04-17 17:33:19 -07001129 dst_use_noref(&rt->dst, jiffies);
David Ahern23fb93a2018-04-17 17:33:23 -07001130 } else {
David Ahern9b6b35a2019-04-16 14:36:02 -07001131 rt = ip6_create_rt_rcu(&res);
David Aherndec9b0e2018-04-17 17:33:19 -07001132 }
Wei Wangd3843fe2017-10-06 12:06:06 -07001133
David Ahernaf52a522019-04-09 14:41:16 -07001134out:
David Ahern8ff2e5b2019-04-16 14:36:09 -07001135 trace_fib6_table_lookup(net, &res, table, fl6);
David Ahernaf52a522019-04-09 14:41:16 -07001136
Wei Wang66f5d6c2017-10-06 12:06:10 -07001137 rcu_read_unlock();
David Ahernb8115802015-11-19 12:24:22 -08001138
Thomas Grafc71099a2006-08-04 23:20:06 -07001139 return rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07001140}
1141
Ian Morris67ba4152014-08-24 21:53:10 +01001142struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
David Ahernb75cc8f2018-03-02 08:32:17 -08001143 const struct sk_buff *skb, int flags)
Florian Westphalea6e5742011-09-05 16:05:44 +02001144{
David Ahernb75cc8f2018-03-02 08:32:17 -08001145 return fib6_rule_lookup(net, fl6, skb, flags, ip6_pol_route_lookup);
Florian Westphalea6e5742011-09-05 16:05:44 +02001146}
1147EXPORT_SYMBOL_GPL(ip6_route_lookup);
1148
YOSHIFUJI Hideaki9acd9f32008-04-10 15:42:10 +09001149struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
David Ahernb75cc8f2018-03-02 08:32:17 -08001150 const struct in6_addr *saddr, int oif,
1151 const struct sk_buff *skb, int strict)
Thomas Grafc71099a2006-08-04 23:20:06 -07001152{
David S. Miller4c9483b2011-03-12 16:22:43 -05001153 struct flowi6 fl6 = {
1154 .flowi6_oif = oif,
1155 .daddr = *daddr,
Thomas Grafc71099a2006-08-04 23:20:06 -07001156 };
1157 struct dst_entry *dst;
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07001158 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
Thomas Grafc71099a2006-08-04 23:20:06 -07001159
Thomas Grafadaa70b2006-10-13 15:01:03 -07001160 if (saddr) {
David S. Miller4c9483b2011-03-12 16:22:43 -05001161 memcpy(&fl6.saddr, saddr, sizeof(*saddr));
Thomas Grafadaa70b2006-10-13 15:01:03 -07001162 flags |= RT6_LOOKUP_F_HAS_SADDR;
1163 }
1164
David Ahernb75cc8f2018-03-02 08:32:17 -08001165 dst = fib6_rule_lookup(net, &fl6, skb, flags, ip6_pol_route_lookup);
Thomas Grafc71099a2006-08-04 23:20:06 -07001166 if (dst->error == 0)
1167 return (struct rt6_info *) dst;
1168
1169 dst_release(dst);
1170
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 return NULL;
1172}
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +09001173EXPORT_SYMBOL(rt6_lookup);
1174
Thomas Grafc71099a2006-08-04 23:20:06 -07001175/* ip6_ins_rt is called with FREE table->tb6_lock.
Wei Wang1cfb71e2017-06-17 10:42:33 -07001176 * It takes new route entry, the addition fails by any reason the
1177 * route is released.
1178 * Caller must hold dst before calling it.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 */
1180
David Ahern8d1c8022018-04-17 17:33:26 -07001181static int __ip6_ins_rt(struct fib6_info *rt, struct nl_info *info,
David Ahern333c4302017-05-21 10:12:04 -06001182 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183{
1184 int err;
Thomas Grafc71099a2006-08-04 23:20:06 -07001185 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186
David Ahern93c2fb22018-04-18 15:38:59 -07001187 table = rt->fib6_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07001188 spin_lock_bh(&table->tb6_lock);
David Ahernd4ead6b2018-04-17 17:33:16 -07001189 err = fib6_add(&table->tb6_root, rt, info, extack);
Wei Wang66f5d6c2017-10-06 12:06:10 -07001190 spin_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
1192 return err;
1193}
1194
David Ahern8d1c8022018-04-17 17:33:26 -07001195int ip6_ins_rt(struct net *net, struct fib6_info *rt)
Thomas Graf40e22e82006-08-22 00:00:45 -07001196{
David Ahernafb1d4b52018-04-17 17:33:11 -07001197 struct nl_info info = { .nl_net = net, };
Florian Westphale715b6d2015-01-05 23:57:44 +01001198
David Ahernd4ead6b2018-04-17 17:33:16 -07001199 return __ip6_ins_rt(rt, &info, NULL);
Thomas Graf40e22e82006-08-22 00:00:45 -07001200}
1201
David Ahern85bd05d2019-04-16 14:36:01 -07001202static struct rt6_info *ip6_rt_cache_alloc(const struct fib6_result *res,
Martin KaFai Lau8b9df262015-05-22 20:55:59 -07001203 const struct in6_addr *daddr,
1204 const struct in6_addr *saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205{
David Ahern85bd05d2019-04-16 14:36:01 -07001206 struct fib6_info *f6i = res->f6i;
David Ahern4832c302017-08-17 12:17:20 -07001207 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 struct rt6_info *rt;
1209
1210 /*
1211 * Clone the route.
1212 */
1213
David Ahern85bd05d2019-04-16 14:36:01 -07001214 if (!fib6_info_hold_safe(f6i))
Wei Wange873e4b2018-07-21 20:56:32 -07001215 return NULL;
1216
David Ahern0d161582019-04-16 14:36:04 -07001217 dev = ip6_rt_get_dev_rcu(res);
David Ahern93531c62018-04-17 17:33:25 -07001218 rt = ip6_dst_alloc(dev_net(dev), dev, 0);
Wei Wange873e4b2018-07-21 20:56:32 -07001219 if (!rt) {
David Ahern85bd05d2019-04-16 14:36:01 -07001220 fib6_info_release(f6i);
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001221 return NULL;
Wei Wange873e4b2018-07-21 20:56:32 -07001222 }
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001223
David Ahern0d161582019-04-16 14:36:04 -07001224 ip6_rt_copy_init(rt, res);
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001225 rt->rt6i_flags |= RTF_CACHE;
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001226 rt->dst.flags |= DST_HOST;
1227 rt->rt6i_dst.addr = *daddr;
1228 rt->rt6i_dst.plen = 128;
1229
David Ahern85bd05d2019-04-16 14:36:01 -07001230 if (!rt6_is_gw_or_nonexthop(res)) {
1231 if (f6i->fib6_dst.plen != 128 &&
1232 ipv6_addr_equal(&f6i->fib6_dst.addr, daddr))
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001233 rt->rt6i_flags |= RTF_ANYCAST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234#ifdef CONFIG_IPV6_SUBTREES
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001235 if (rt->rt6i_src.plen && saddr) {
1236 rt->rt6i_src.addr = *saddr;
1237 rt->rt6i_src.plen = 128;
Martin KaFai Lau8b9df262015-05-22 20:55:59 -07001238 }
Martin KaFai Lau83a09ab2015-05-22 20:56:05 -07001239#endif
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -08001240 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241
YOSHIFUJI Hideaki95a9a5b2006-03-20 16:55:51 -08001242 return rt;
1243}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
David Aherndb3fede2019-04-16 14:36:03 -07001245static struct rt6_info *ip6_rt_pcpu_alloc(const struct fib6_result *res)
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001246{
David Aherndb3fede2019-04-16 14:36:03 -07001247 struct fib6_info *f6i = res->f6i;
1248 unsigned short flags = fib6_info_dst_flags(f6i);
David Ahern4832c302017-08-17 12:17:20 -07001249 struct net_device *dev;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001250 struct rt6_info *pcpu_rt;
1251
David Aherndb3fede2019-04-16 14:36:03 -07001252 if (!fib6_info_hold_safe(f6i))
Wei Wange873e4b2018-07-21 20:56:32 -07001253 return NULL;
1254
David Ahern4832c302017-08-17 12:17:20 -07001255 rcu_read_lock();
David Ahern0d161582019-04-16 14:36:04 -07001256 dev = ip6_rt_get_dev_rcu(res);
David Ahern93531c62018-04-17 17:33:25 -07001257 pcpu_rt = ip6_dst_alloc(dev_net(dev), dev, flags);
David Ahern4832c302017-08-17 12:17:20 -07001258 rcu_read_unlock();
Wei Wange873e4b2018-07-21 20:56:32 -07001259 if (!pcpu_rt) {
David Aherndb3fede2019-04-16 14:36:03 -07001260 fib6_info_release(f6i);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001261 return NULL;
Wei Wange873e4b2018-07-21 20:56:32 -07001262 }
David Ahern0d161582019-04-16 14:36:04 -07001263 ip6_rt_copy_init(pcpu_rt, res);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001264 pcpu_rt->rt6i_flags |= RTF_PCPU;
1265 return pcpu_rt;
1266}
1267
Wei Wang66f5d6c2017-10-06 12:06:10 -07001268/* It should be called with rcu_read_lock() acquired */
David Aherndb3fede2019-04-16 14:36:03 -07001269static struct rt6_info *rt6_get_pcpu_route(const struct fib6_result *res)
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001270{
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001271 struct rt6_info *pcpu_rt, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001272
David Aherndb3fede2019-04-16 14:36:03 -07001273 p = this_cpu_ptr(res->f6i->rt6i_pcpu);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001274 pcpu_rt = *p;
1275
David Ahernd4ead6b2018-04-17 17:33:16 -07001276 if (pcpu_rt)
David Ahern10585b42019-03-20 09:24:50 -07001277 ip6_hold_safe(NULL, &pcpu_rt);
Wei Wangd3843fe2017-10-06 12:06:06 -07001278
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001279 return pcpu_rt;
1280}
1281
David Ahernafb1d4b52018-04-17 17:33:11 -07001282static struct rt6_info *rt6_make_pcpu_route(struct net *net,
David Aherndb3fede2019-04-16 14:36:03 -07001283 const struct fib6_result *res)
Martin KaFai Laua73e4192015-08-14 11:05:53 -07001284{
1285 struct rt6_info *pcpu_rt, *prev, **p;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001286
David Aherndb3fede2019-04-16 14:36:03 -07001287 pcpu_rt = ip6_rt_pcpu_alloc(res);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001288 if (!pcpu_rt) {
Martin KaFai Lau9c7370a2015-08-14 11:05:54 -07001289 dst_hold(&net->ipv6.ip6_null_entry->dst);
1290 return net->ipv6.ip6_null_entry;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001291 }
1292
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001293 dst_hold(&pcpu_rt->dst);
David Aherndb3fede2019-04-16 14:36:03 -07001294 p = this_cpu_ptr(res->f6i->rt6i_pcpu);
Wei Wanga94b9362017-10-06 12:06:04 -07001295 prev = cmpxchg(p, NULL, pcpu_rt);
Eric Dumazet951f7882017-10-08 21:07:18 -07001296 BUG_ON(prev);
Wei Wanga94b9362017-10-06 12:06:04 -07001297
Eric Dumazet61fb0d02019-05-15 19:39:52 -07001298 if (res->f6i->fib6_destroying) {
1299 struct fib6_info *from;
1300
1301 from = xchg((__force struct fib6_info **)&pcpu_rt->from, NULL);
1302 fib6_info_release(from);
1303 }
1304
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001305 return pcpu_rt;
1306}
1307
Wei Wang35732d02017-10-06 12:05:57 -07001308/* exception hash table implementation
1309 */
1310static DEFINE_SPINLOCK(rt6_exception_lock);
1311
1312/* Remove rt6_ex from hash table and free the memory
1313 * Caller must hold rt6_exception_lock
1314 */
1315static void rt6_remove_exception(struct rt6_exception_bucket *bucket,
1316 struct rt6_exception *rt6_ex)
1317{
Paolo Abenif5b51fe2019-02-20 18:18:12 +01001318 struct fib6_info *from;
Colin Ian Kingb2427e62017-10-10 18:01:16 +01001319 struct net *net;
Wei Wang81eb8442017-10-06 12:06:11 -07001320
Wei Wang35732d02017-10-06 12:05:57 -07001321 if (!bucket || !rt6_ex)
1322 return;
Colin Ian Kingb2427e62017-10-10 18:01:16 +01001323
1324 net = dev_net(rt6_ex->rt6i->dst.dev);
Paolo Abenif5b51fe2019-02-20 18:18:12 +01001325 net->ipv6.rt6_stats->fib_rt_cache--;
1326
1327 /* purge completely the exception to allow releasing the held resources:
1328 * some [sk] cache may keep the dst around for unlimited time
1329 */
Eric Dumazet0e233872019-04-28 12:22:25 -07001330 from = xchg((__force struct fib6_info **)&rt6_ex->rt6i->from, NULL);
Paolo Abenif5b51fe2019-02-20 18:18:12 +01001331 fib6_info_release(from);
1332 dst_dev_put(&rt6_ex->rt6i->dst);
1333
Wei Wang35732d02017-10-06 12:05:57 -07001334 hlist_del_rcu(&rt6_ex->hlist);
David Ahern77634cc2018-04-17 17:33:27 -07001335 dst_release(&rt6_ex->rt6i->dst);
Wei Wang35732d02017-10-06 12:05:57 -07001336 kfree_rcu(rt6_ex, rcu);
1337 WARN_ON_ONCE(!bucket->depth);
1338 bucket->depth--;
1339}
1340
1341/* Remove oldest rt6_ex in bucket and free the memory
1342 * Caller must hold rt6_exception_lock
1343 */
1344static void rt6_exception_remove_oldest(struct rt6_exception_bucket *bucket)
1345{
1346 struct rt6_exception *rt6_ex, *oldest = NULL;
1347
1348 if (!bucket)
1349 return;
1350
1351 hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
1352 if (!oldest || time_before(rt6_ex->stamp, oldest->stamp))
1353 oldest = rt6_ex;
1354 }
1355 rt6_remove_exception(bucket, oldest);
1356}
1357
1358static u32 rt6_exception_hash(const struct in6_addr *dst,
1359 const struct in6_addr *src)
1360{
1361 static u32 seed __read_mostly;
1362 u32 val;
1363
1364 net_get_random_once(&seed, sizeof(seed));
1365 val = jhash(dst, sizeof(*dst), seed);
1366
1367#ifdef CONFIG_IPV6_SUBTREES
1368 if (src)
1369 val = jhash(src, sizeof(*src), val);
1370#endif
1371 return hash_32(val, FIB6_EXCEPTION_BUCKET_SIZE_SHIFT);
1372}
1373
1374/* Helper function to find the cached rt in the hash table
1375 * and update bucket pointer to point to the bucket for this
1376 * (daddr, saddr) pair
1377 * Caller must hold rt6_exception_lock
1378 */
1379static struct rt6_exception *
1380__rt6_find_exception_spinlock(struct rt6_exception_bucket **bucket,
1381 const struct in6_addr *daddr,
1382 const struct in6_addr *saddr)
1383{
1384 struct rt6_exception *rt6_ex;
1385 u32 hval;
1386
1387 if (!(*bucket) || !daddr)
1388 return NULL;
1389
1390 hval = rt6_exception_hash(daddr, saddr);
1391 *bucket += hval;
1392
1393 hlist_for_each_entry(rt6_ex, &(*bucket)->chain, hlist) {
1394 struct rt6_info *rt6 = rt6_ex->rt6i;
1395 bool matched = ipv6_addr_equal(daddr, &rt6->rt6i_dst.addr);
1396
1397#ifdef CONFIG_IPV6_SUBTREES
1398 if (matched && saddr)
1399 matched = ipv6_addr_equal(saddr, &rt6->rt6i_src.addr);
1400#endif
1401 if (matched)
1402 return rt6_ex;
1403 }
1404 return NULL;
1405}
1406
1407/* Helper function to find the cached rt in the hash table
1408 * and update bucket pointer to point to the bucket for this
1409 * (daddr, saddr) pair
1410 * Caller must hold rcu_read_lock()
1411 */
1412static struct rt6_exception *
1413__rt6_find_exception_rcu(struct rt6_exception_bucket **bucket,
1414 const struct in6_addr *daddr,
1415 const struct in6_addr *saddr)
1416{
1417 struct rt6_exception *rt6_ex;
1418 u32 hval;
1419
1420 WARN_ON_ONCE(!rcu_read_lock_held());
1421
1422 if (!(*bucket) || !daddr)
1423 return NULL;
1424
1425 hval = rt6_exception_hash(daddr, saddr);
1426 *bucket += hval;
1427
1428 hlist_for_each_entry_rcu(rt6_ex, &(*bucket)->chain, hlist) {
1429 struct rt6_info *rt6 = rt6_ex->rt6i;
1430 bool matched = ipv6_addr_equal(daddr, &rt6->rt6i_dst.addr);
1431
1432#ifdef CONFIG_IPV6_SUBTREES
1433 if (matched && saddr)
1434 matched = ipv6_addr_equal(saddr, &rt6->rt6i_src.addr);
1435#endif
1436 if (matched)
1437 return rt6_ex;
1438 }
1439 return NULL;
1440}
1441
David Ahernb748f262019-04-16 14:36:06 -07001442static unsigned int fib6_mtu(const struct fib6_result *res)
Wei Wang35732d02017-10-06 12:05:57 -07001443{
David Ahernb748f262019-04-16 14:36:06 -07001444 const struct fib6_nh *nh = res->nh;
David Ahernd4ead6b2018-04-17 17:33:16 -07001445 unsigned int mtu;
1446
David Ahernb748f262019-04-16 14:36:06 -07001447 if (res->f6i->fib6_pmtu) {
1448 mtu = res->f6i->fib6_pmtu;
David Aherndcd1f572018-04-18 15:39:05 -07001449 } else {
David Ahernb748f262019-04-16 14:36:06 -07001450 struct net_device *dev = nh->fib_nh_dev;
David Aherndcd1f572018-04-18 15:39:05 -07001451 struct inet6_dev *idev;
1452
1453 rcu_read_lock();
1454 idev = __in6_dev_get(dev);
1455 mtu = idev->cnf.mtu6;
1456 rcu_read_unlock();
1457 }
1458
David Ahernd4ead6b2018-04-17 17:33:16 -07001459 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
1460
David Ahernb748f262019-04-16 14:36:06 -07001461 return mtu - lwtunnel_headroom(nh->fib_nh_lws, mtu);
David Ahernd4ead6b2018-04-17 17:33:16 -07001462}
1463
Wei Wang35732d02017-10-06 12:05:57 -07001464static int rt6_insert_exception(struct rt6_info *nrt,
David Ahern5012f0a2019-04-16 14:36:05 -07001465 const struct fib6_result *res)
Wei Wang35732d02017-10-06 12:05:57 -07001466{
David Ahern5e670d82018-04-17 17:33:14 -07001467 struct net *net = dev_net(nrt->dst.dev);
Wei Wang35732d02017-10-06 12:05:57 -07001468 struct rt6_exception_bucket *bucket;
1469 struct in6_addr *src_key = NULL;
1470 struct rt6_exception *rt6_ex;
David Ahern5012f0a2019-04-16 14:36:05 -07001471 struct fib6_info *f6i = res->f6i;
Wei Wang35732d02017-10-06 12:05:57 -07001472 int err = 0;
1473
Wei Wang35732d02017-10-06 12:05:57 -07001474 spin_lock_bh(&rt6_exception_lock);
1475
David Ahern5012f0a2019-04-16 14:36:05 -07001476 if (f6i->exception_bucket_flushed) {
Wei Wang35732d02017-10-06 12:05:57 -07001477 err = -EINVAL;
1478 goto out;
1479 }
1480
David Ahern5012f0a2019-04-16 14:36:05 -07001481 bucket = rcu_dereference_protected(f6i->rt6i_exception_bucket,
Wei Wang35732d02017-10-06 12:05:57 -07001482 lockdep_is_held(&rt6_exception_lock));
1483 if (!bucket) {
1484 bucket = kcalloc(FIB6_EXCEPTION_BUCKET_SIZE, sizeof(*bucket),
1485 GFP_ATOMIC);
1486 if (!bucket) {
1487 err = -ENOMEM;
1488 goto out;
1489 }
David Ahern5012f0a2019-04-16 14:36:05 -07001490 rcu_assign_pointer(f6i->rt6i_exception_bucket, bucket);
Wei Wang35732d02017-10-06 12:05:57 -07001491 }
1492
1493#ifdef CONFIG_IPV6_SUBTREES
David Ahern5012f0a2019-04-16 14:36:05 -07001494 /* fib6_src.plen != 0 indicates f6i is in subtree
Wei Wang35732d02017-10-06 12:05:57 -07001495 * and exception table is indexed by a hash of
David Ahern5012f0a2019-04-16 14:36:05 -07001496 * both fib6_dst and fib6_src.
Wei Wang35732d02017-10-06 12:05:57 -07001497 * Otherwise, the exception table is indexed by
David Ahern5012f0a2019-04-16 14:36:05 -07001498 * a hash of only fib6_dst.
Wei Wang35732d02017-10-06 12:05:57 -07001499 */
David Ahern5012f0a2019-04-16 14:36:05 -07001500 if (f6i->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001501 src_key = &nrt->rt6i_src.addr;
1502#endif
David Ahern5012f0a2019-04-16 14:36:05 -07001503 /* rt6_mtu_change() might lower mtu on f6i.
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001504 * Only insert this exception route if its mtu
David Ahern5012f0a2019-04-16 14:36:05 -07001505 * is less than f6i's mtu value.
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001506 */
David Ahernb748f262019-04-16 14:36:06 -07001507 if (dst_metric_raw(&nrt->dst, RTAX_MTU) >= fib6_mtu(res)) {
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001508 err = -EINVAL;
1509 goto out;
1510 }
Wei Wang60006a42017-10-06 12:05:58 -07001511
Wei Wang35732d02017-10-06 12:05:57 -07001512 rt6_ex = __rt6_find_exception_spinlock(&bucket, &nrt->rt6i_dst.addr,
1513 src_key);
1514 if (rt6_ex)
1515 rt6_remove_exception(bucket, rt6_ex);
1516
1517 rt6_ex = kzalloc(sizeof(*rt6_ex), GFP_ATOMIC);
1518 if (!rt6_ex) {
1519 err = -ENOMEM;
1520 goto out;
1521 }
1522 rt6_ex->rt6i = nrt;
1523 rt6_ex->stamp = jiffies;
Wei Wang35732d02017-10-06 12:05:57 -07001524 hlist_add_head_rcu(&rt6_ex->hlist, &bucket->chain);
1525 bucket->depth++;
Wei Wang81eb8442017-10-06 12:06:11 -07001526 net->ipv6.rt6_stats->fib_rt_cache++;
Wei Wang35732d02017-10-06 12:05:57 -07001527
1528 if (bucket->depth > FIB6_MAX_DEPTH)
1529 rt6_exception_remove_oldest(bucket);
1530
1531out:
1532 spin_unlock_bh(&rt6_exception_lock);
1533
1534 /* Update fn->fn_sernum to invalidate all cached dst */
Paolo Abenib886d5f2017-10-19 16:07:10 +02001535 if (!err) {
David Ahern5012f0a2019-04-16 14:36:05 -07001536 spin_lock_bh(&f6i->fib6_table->tb6_lock);
1537 fib6_update_sernum(net, f6i);
1538 spin_unlock_bh(&f6i->fib6_table->tb6_lock);
Paolo Abenib886d5f2017-10-19 16:07:10 +02001539 fib6_force_start_gc(net);
1540 }
Wei Wang35732d02017-10-06 12:05:57 -07001541
1542 return err;
1543}
1544
David Ahern8d1c8022018-04-17 17:33:26 -07001545void rt6_flush_exceptions(struct fib6_info *rt)
Wei Wang35732d02017-10-06 12:05:57 -07001546{
1547 struct rt6_exception_bucket *bucket;
1548 struct rt6_exception *rt6_ex;
1549 struct hlist_node *tmp;
1550 int i;
1551
1552 spin_lock_bh(&rt6_exception_lock);
1553 /* Prevent rt6_insert_exception() to recreate the bucket list */
1554 rt->exception_bucket_flushed = 1;
1555
1556 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1557 lockdep_is_held(&rt6_exception_lock));
1558 if (!bucket)
1559 goto out;
1560
1561 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1562 hlist_for_each_entry_safe(rt6_ex, tmp, &bucket->chain, hlist)
1563 rt6_remove_exception(bucket, rt6_ex);
1564 WARN_ON_ONCE(bucket->depth);
1565 bucket++;
1566 }
1567
1568out:
1569 spin_unlock_bh(&rt6_exception_lock);
1570}
1571
1572/* Find cached rt in the hash table inside passed in rt
1573 * Caller has to hold rcu_read_lock()
1574 */
David Ahern7e4b5122019-04-16 14:36:00 -07001575static struct rt6_info *rt6_find_cached_rt(const struct fib6_result *res,
Wei Wang35732d02017-10-06 12:05:57 -07001576 struct in6_addr *daddr,
1577 struct in6_addr *saddr)
1578{
1579 struct rt6_exception_bucket *bucket;
1580 struct in6_addr *src_key = NULL;
1581 struct rt6_exception *rt6_ex;
David Ahern7e4b5122019-04-16 14:36:00 -07001582 struct rt6_info *ret = NULL;
Wei Wang35732d02017-10-06 12:05:57 -07001583
David Ahern7e4b5122019-04-16 14:36:00 -07001584 bucket = rcu_dereference(res->f6i->rt6i_exception_bucket);
Wei Wang35732d02017-10-06 12:05:57 -07001585
1586#ifdef CONFIG_IPV6_SUBTREES
David Ahern7e4b5122019-04-16 14:36:00 -07001587 /* fib6i_src.plen != 0 indicates f6i is in subtree
Wei Wang35732d02017-10-06 12:05:57 -07001588 * and exception table is indexed by a hash of
David Ahern7e4b5122019-04-16 14:36:00 -07001589 * both fib6_dst and fib6_src.
Wei Wang35732d02017-10-06 12:05:57 -07001590 * Otherwise, the exception table is indexed by
David Ahern7e4b5122019-04-16 14:36:00 -07001591 * a hash of only fib6_dst.
Wei Wang35732d02017-10-06 12:05:57 -07001592 */
David Ahern7e4b5122019-04-16 14:36:00 -07001593 if (res->f6i->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001594 src_key = saddr;
1595#endif
1596 rt6_ex = __rt6_find_exception_rcu(&bucket, daddr, src_key);
1597
1598 if (rt6_ex && !rt6_check_expired(rt6_ex->rt6i))
David Ahern7e4b5122019-04-16 14:36:00 -07001599 ret = rt6_ex->rt6i;
Wei Wang35732d02017-10-06 12:05:57 -07001600
David Ahern7e4b5122019-04-16 14:36:00 -07001601 return ret;
Wei Wang35732d02017-10-06 12:05:57 -07001602}
1603
1604/* Remove the passed in cached rt from the hash table that contains it */
David Ahern23fb93a2018-04-17 17:33:23 -07001605static int rt6_remove_exception_rt(struct rt6_info *rt)
Wei Wang35732d02017-10-06 12:05:57 -07001606{
Wei Wang35732d02017-10-06 12:05:57 -07001607 struct rt6_exception_bucket *bucket;
1608 struct in6_addr *src_key = NULL;
1609 struct rt6_exception *rt6_ex;
David Ahern8a14e462018-04-23 11:32:07 -07001610 struct fib6_info *from;
Wei Wang35732d02017-10-06 12:05:57 -07001611 int err;
1612
Eric Dumazet091311d2018-04-24 09:22:49 -07001613 from = rcu_dereference(rt->from);
Wei Wang35732d02017-10-06 12:05:57 -07001614 if (!from ||
Colin Ian King442d7132017-10-10 19:10:30 +01001615 !(rt->rt6i_flags & RTF_CACHE))
Wei Wang35732d02017-10-06 12:05:57 -07001616 return -EINVAL;
1617
1618 if (!rcu_access_pointer(from->rt6i_exception_bucket))
1619 return -ENOENT;
1620
1621 spin_lock_bh(&rt6_exception_lock);
1622 bucket = rcu_dereference_protected(from->rt6i_exception_bucket,
1623 lockdep_is_held(&rt6_exception_lock));
1624#ifdef CONFIG_IPV6_SUBTREES
1625 /* rt6i_src.plen != 0 indicates 'from' is in subtree
1626 * and exception table is indexed by a hash of
1627 * both rt6i_dst and rt6i_src.
1628 * Otherwise, the exception table is indexed by
1629 * a hash of only rt6i_dst.
1630 */
David Ahern93c2fb22018-04-18 15:38:59 -07001631 if (from->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001632 src_key = &rt->rt6i_src.addr;
1633#endif
1634 rt6_ex = __rt6_find_exception_spinlock(&bucket,
1635 &rt->rt6i_dst.addr,
1636 src_key);
1637 if (rt6_ex) {
1638 rt6_remove_exception(bucket, rt6_ex);
1639 err = 0;
1640 } else {
1641 err = -ENOENT;
1642 }
1643
1644 spin_unlock_bh(&rt6_exception_lock);
1645 return err;
1646}
1647
1648/* Find rt6_ex which contains the passed in rt cache and
1649 * refresh its stamp
1650 */
1651static void rt6_update_exception_stamp_rt(struct rt6_info *rt)
1652{
Wei Wang35732d02017-10-06 12:05:57 -07001653 struct rt6_exception_bucket *bucket;
1654 struct in6_addr *src_key = NULL;
1655 struct rt6_exception *rt6_ex;
Paolo Abeni193f3682019-02-21 11:19:41 +01001656 struct fib6_info *from;
Wei Wang35732d02017-10-06 12:05:57 -07001657
1658 rcu_read_lock();
Paolo Abeni193f3682019-02-21 11:19:41 +01001659 from = rcu_dereference(rt->from);
1660 if (!from || !(rt->rt6i_flags & RTF_CACHE))
1661 goto unlock;
1662
Wei Wang35732d02017-10-06 12:05:57 -07001663 bucket = rcu_dereference(from->rt6i_exception_bucket);
1664
1665#ifdef CONFIG_IPV6_SUBTREES
1666 /* rt6i_src.plen != 0 indicates 'from' is in subtree
1667 * and exception table is indexed by a hash of
1668 * both rt6i_dst and rt6i_src.
1669 * Otherwise, the exception table is indexed by
1670 * a hash of only rt6i_dst.
1671 */
David Ahern93c2fb22018-04-18 15:38:59 -07001672 if (from->fib6_src.plen)
Wei Wang35732d02017-10-06 12:05:57 -07001673 src_key = &rt->rt6i_src.addr;
1674#endif
1675 rt6_ex = __rt6_find_exception_rcu(&bucket,
1676 &rt->rt6i_dst.addr,
1677 src_key);
1678 if (rt6_ex)
1679 rt6_ex->stamp = jiffies;
1680
Paolo Abeni193f3682019-02-21 11:19:41 +01001681unlock:
Wei Wang35732d02017-10-06 12:05:57 -07001682 rcu_read_unlock();
1683}
1684
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001685static bool rt6_mtu_change_route_allowed(struct inet6_dev *idev,
1686 struct rt6_info *rt, int mtu)
1687{
1688 /* If the new MTU is lower than the route PMTU, this new MTU will be the
1689 * lowest MTU in the path: always allow updating the route PMTU to
1690 * reflect PMTU decreases.
1691 *
1692 * If the new MTU is higher, and the route PMTU is equal to the local
1693 * MTU, this means the old MTU is the lowest in the path, so allow
1694 * updating it: if other nodes now have lower MTUs, PMTU discovery will
1695 * handle this.
1696 */
1697
1698 if (dst_mtu(&rt->dst) >= mtu)
1699 return true;
1700
1701 if (dst_mtu(&rt->dst) == idev->cnf.mtu6)
1702 return true;
1703
1704 return false;
1705}
1706
1707static void rt6_exceptions_update_pmtu(struct inet6_dev *idev,
David Ahern8d1c8022018-04-17 17:33:26 -07001708 struct fib6_info *rt, int mtu)
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001709{
1710 struct rt6_exception_bucket *bucket;
1711 struct rt6_exception *rt6_ex;
1712 int i;
1713
1714 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1715 lockdep_is_held(&rt6_exception_lock));
1716
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001717 if (!bucket)
1718 return;
1719
1720 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1721 hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
1722 struct rt6_info *entry = rt6_ex->rt6i;
1723
1724 /* For RTF_CACHE with rt6i_pmtu == 0 (i.e. a redirected
David Ahernd4ead6b2018-04-17 17:33:16 -07001725 * route), the metrics of its rt->from have already
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001726 * been updated.
1727 */
David Ahernd4ead6b2018-04-17 17:33:16 -07001728 if (dst_metric_raw(&entry->dst, RTAX_MTU) &&
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001729 rt6_mtu_change_route_allowed(idev, entry, mtu))
David Ahernd4ead6b2018-04-17 17:33:16 -07001730 dst_metric_set(&entry->dst, RTAX_MTU, mtu);
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001731 }
Stefano Brivioe9fa1492018-03-06 11:10:19 +01001732 bucket++;
Wei Wangf5bbe7e2017-10-06 12:05:59 -07001733 }
1734}
1735
Wei Wangb16cb452017-10-06 12:06:00 -07001736#define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE)
1737
David Ahern8d1c8022018-04-17 17:33:26 -07001738static void rt6_exceptions_clean_tohost(struct fib6_info *rt,
Wei Wangb16cb452017-10-06 12:06:00 -07001739 struct in6_addr *gateway)
1740{
1741 struct rt6_exception_bucket *bucket;
1742 struct rt6_exception *rt6_ex;
1743 struct hlist_node *tmp;
1744 int i;
1745
1746 if (!rcu_access_pointer(rt->rt6i_exception_bucket))
1747 return;
1748
1749 spin_lock_bh(&rt6_exception_lock);
1750 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1751 lockdep_is_held(&rt6_exception_lock));
1752
1753 if (bucket) {
1754 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1755 hlist_for_each_entry_safe(rt6_ex, tmp,
1756 &bucket->chain, hlist) {
1757 struct rt6_info *entry = rt6_ex->rt6i;
1758
1759 if ((entry->rt6i_flags & RTF_CACHE_GATEWAY) ==
1760 RTF_CACHE_GATEWAY &&
1761 ipv6_addr_equal(gateway,
1762 &entry->rt6i_gateway)) {
1763 rt6_remove_exception(bucket, rt6_ex);
1764 }
1765 }
1766 bucket++;
1767 }
1768 }
1769
1770 spin_unlock_bh(&rt6_exception_lock);
1771}
1772
Wei Wangc757faa2017-10-06 12:06:01 -07001773static void rt6_age_examine_exception(struct rt6_exception_bucket *bucket,
1774 struct rt6_exception *rt6_ex,
1775 struct fib6_gc_args *gc_args,
1776 unsigned long now)
1777{
1778 struct rt6_info *rt = rt6_ex->rt6i;
1779
Paolo Abeni1859bac2017-10-19 16:07:11 +02001780 /* we are pruning and obsoleting aged-out and non gateway exceptions
1781 * even if others have still references to them, so that on next
1782 * dst_check() such references can be dropped.
1783 * EXPIRES exceptions - e.g. pmtu-generated ones are pruned when
1784 * expired, independently from their aging, as per RFC 8201 section 4
1785 */
Wei Wang31afeb42018-01-26 11:40:17 -08001786 if (!(rt->rt6i_flags & RTF_EXPIRES)) {
1787 if (time_after_eq(now, rt->dst.lastuse + gc_args->timeout)) {
1788 RT6_TRACE("aging clone %p\n", rt);
1789 rt6_remove_exception(bucket, rt6_ex);
1790 return;
1791 }
1792 } else if (time_after(jiffies, rt->dst.expires)) {
1793 RT6_TRACE("purging expired route %p\n", rt);
Wei Wangc757faa2017-10-06 12:06:01 -07001794 rt6_remove_exception(bucket, rt6_ex);
1795 return;
Wei Wang31afeb42018-01-26 11:40:17 -08001796 }
1797
1798 if (rt->rt6i_flags & RTF_GATEWAY) {
Wei Wangc757faa2017-10-06 12:06:01 -07001799 struct neighbour *neigh;
1800 __u8 neigh_flags = 0;
1801
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001802 neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
1803 if (neigh)
Wei Wangc757faa2017-10-06 12:06:01 -07001804 neigh_flags = neigh->flags;
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001805
Wei Wangc757faa2017-10-06 12:06:01 -07001806 if (!(neigh_flags & NTF_ROUTER)) {
1807 RT6_TRACE("purging route %p via non-router but gateway\n",
1808 rt);
1809 rt6_remove_exception(bucket, rt6_ex);
1810 return;
1811 }
1812 }
Wei Wang31afeb42018-01-26 11:40:17 -08001813
Wei Wangc757faa2017-10-06 12:06:01 -07001814 gc_args->more++;
1815}
1816
David Ahern8d1c8022018-04-17 17:33:26 -07001817void rt6_age_exceptions(struct fib6_info *rt,
Wei Wangc757faa2017-10-06 12:06:01 -07001818 struct fib6_gc_args *gc_args,
1819 unsigned long now)
1820{
1821 struct rt6_exception_bucket *bucket;
1822 struct rt6_exception *rt6_ex;
1823 struct hlist_node *tmp;
1824 int i;
1825
1826 if (!rcu_access_pointer(rt->rt6i_exception_bucket))
1827 return;
1828
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001829 rcu_read_lock_bh();
1830 spin_lock(&rt6_exception_lock);
Wei Wangc757faa2017-10-06 12:06:01 -07001831 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
1832 lockdep_is_held(&rt6_exception_lock));
1833
1834 if (bucket) {
1835 for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
1836 hlist_for_each_entry_safe(rt6_ex, tmp,
1837 &bucket->chain, hlist) {
1838 rt6_age_examine_exception(bucket, rt6_ex,
1839 gc_args, now);
1840 }
1841 bucket++;
1842 }
1843 }
Eric Dumazet1bfa26f2018-03-23 07:56:58 -07001844 spin_unlock(&rt6_exception_lock);
1845 rcu_read_unlock_bh();
Wei Wangc757faa2017-10-06 12:06:01 -07001846}
1847
David Ahern1d053da2018-05-09 20:34:21 -07001848/* must be called with rcu lock held */
David Aherneffda4d2019-04-16 14:36:10 -07001849int fib6_table_lookup(struct net *net, struct fib6_table *table, int oif,
1850 struct flowi6 *fl6, struct fib6_result *res, int strict)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851{
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001852 struct fib6_node *fn, *saved_fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853
David Ahern64547432018-05-09 20:34:19 -07001854 fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001855 saved_fn = fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856
David Ahernca254492015-10-12 11:47:10 -07001857 if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
1858 oif = 0;
1859
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001860redo_rt6_select:
David Aherneffda4d2019-04-16 14:36:10 -07001861 rt6_select(net, fn, oif, res, strict);
1862 if (res->f6i == net->ipv6.fib6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001863 fn = fib6_backtrack(fn, &fl6->saddr);
1864 if (fn)
1865 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001866 else if (strict & RT6_LOOKUP_F_REACHABLE) {
1867 /* also consider unreachable route */
1868 strict &= ~RT6_LOOKUP_F_REACHABLE;
1869 fn = saved_fn;
1870 goto redo_rt6_select;
Martin KaFai Lau367efcb2014-10-20 13:42:45 -07001871 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07001872 }
1873
David Aherneffda4d2019-04-16 14:36:10 -07001874 trace_fib6_table_lookup(net, res, table, fl6);
YOSHIFUJI Hideakifb9de912006-03-20 16:59:08 -08001875
David Aherneffda4d2019-04-16 14:36:10 -07001876 return 0;
David Ahern1d053da2018-05-09 20:34:21 -07001877}
1878
1879struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
1880 int oif, struct flowi6 *fl6,
1881 const struct sk_buff *skb, int flags)
1882{
David Ahernb1d40992019-04-16 14:35:59 -07001883 struct fib6_result res = {};
David Ahern1d053da2018-05-09 20:34:21 -07001884 struct rt6_info *rt;
1885 int strict = 0;
1886
1887 strict |= flags & RT6_LOOKUP_F_IFACE;
1888 strict |= flags & RT6_LOOKUP_F_IGNORE_LINKSTATE;
1889 if (net->ipv6.devconf_all->forwarding == 0)
1890 strict |= RT6_LOOKUP_F_REACHABLE;
1891
1892 rcu_read_lock();
1893
David Aherneffda4d2019-04-16 14:36:10 -07001894 fib6_table_lookup(net, table, oif, fl6, &res, strict);
David Ahernb1d40992019-04-16 14:35:59 -07001895 if (res.f6i == net->ipv6.fib6_null_entry) {
David Ahern421842e2018-04-17 17:33:18 -07001896 rt = net->ipv6.ip6_null_entry;
Wei Wang66f5d6c2017-10-06 12:06:10 -07001897 rcu_read_unlock();
Wei Wangd3843fe2017-10-06 12:06:06 -07001898 dst_hold(&rt->dst);
Wei Wangd3843fe2017-10-06 12:06:06 -07001899 return rt;
David Ahern23fb93a2018-04-17 17:33:23 -07001900 }
1901
David Ahernb1d40992019-04-16 14:35:59 -07001902 fib6_select_path(net, &res, fl6, oif, false, skb, strict);
David Ahernd83009d2019-04-09 14:41:17 -07001903
David Ahern23fb93a2018-04-17 17:33:23 -07001904 /*Search through exception table */
David Ahern7e4b5122019-04-16 14:36:00 -07001905 rt = rt6_find_cached_rt(&res, &fl6->daddr, &fl6->saddr);
David Ahern23fb93a2018-04-17 17:33:23 -07001906 if (rt) {
David Ahern10585b42019-03-20 09:24:50 -07001907 if (ip6_hold_safe(net, &rt))
Wei Wangd3843fe2017-10-06 12:06:06 -07001908 dst_use_noref(&rt->dst, jiffies);
David Ahernd4ead6b2018-04-17 17:33:16 -07001909
Wei Wang66f5d6c2017-10-06 12:06:10 -07001910 rcu_read_unlock();
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001911 return rt;
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001912 } else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) &&
David Ahernb1d40992019-04-16 14:35:59 -07001913 !res.nh->fib_nh_gw_family)) {
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001914 /* Create a RTF_CACHE clone which will not be
1915 * owned by the fib6 tree. It is for the special case where
1916 * the daddr in the skb during the neighbor look-up is different
1917 * from the fl6->daddr used to look-up route here.
1918 */
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001919 struct rt6_info *uncached_rt;
1920
David Ahern85bd05d2019-04-16 14:36:01 -07001921 uncached_rt = ip6_rt_cache_alloc(&res, &fl6->daddr, NULL);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001922
David Ahern4d85cd02018-04-20 15:37:59 -07001923 rcu_read_unlock();
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001924
Wei Wang1cfb71e2017-06-17 10:42:33 -07001925 if (uncached_rt) {
1926 /* Uncached_rt's refcnt is taken during ip6_rt_cache_alloc()
1927 * No need for another dst_hold()
1928 */
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07001929 rt6_uncached_list_add(uncached_rt);
Wei Wang81eb8442017-10-06 12:06:11 -07001930 atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);
Wei Wang1cfb71e2017-06-17 10:42:33 -07001931 } else {
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001932 uncached_rt = net->ipv6.ip6_null_entry;
Wei Wang1cfb71e2017-06-17 10:42:33 -07001933 dst_hold(&uncached_rt->dst);
1934 }
David Ahernb8115802015-11-19 12:24:22 -08001935
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07001936 return uncached_rt;
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001937 } else {
1938 /* Get a percpu copy */
1939
1940 struct rt6_info *pcpu_rt;
1941
Eric Dumazet951f7882017-10-08 21:07:18 -07001942 local_bh_disable();
David Aherndb3fede2019-04-16 14:36:03 -07001943 pcpu_rt = rt6_get_pcpu_route(&res);
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001944
David Ahern93531c62018-04-17 17:33:25 -07001945 if (!pcpu_rt)
David Aherndb3fede2019-04-16 14:36:03 -07001946 pcpu_rt = rt6_make_pcpu_route(net, &res);
David Ahern93531c62018-04-17 17:33:25 -07001947
Eric Dumazet951f7882017-10-08 21:07:18 -07001948 local_bh_enable();
1949 rcu_read_unlock();
David Ahernd4bea422018-05-09 20:34:24 -07001950
Martin KaFai Laud52d3992015-05-22 20:56:06 -07001951 return pcpu_rt;
1952 }
Thomas Grafc71099a2006-08-04 23:20:06 -07001953}
David Ahern9ff74382016-06-13 13:44:19 -07001954EXPORT_SYMBOL_GPL(ip6_pol_route);
Thomas Grafc71099a2006-08-04 23:20:06 -07001955
David Ahernb75cc8f2018-03-02 08:32:17 -08001956static struct rt6_info *ip6_pol_route_input(struct net *net,
1957 struct fib6_table *table,
1958 struct flowi6 *fl6,
1959 const struct sk_buff *skb,
1960 int flags)
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001961{
David Ahernb75cc8f2018-03-02 08:32:17 -08001962 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, skb, flags);
Pavel Emelyanov4acad722007-10-15 13:02:51 -07001963}
1964
Mahesh Bandeward409b842016-09-16 12:59:08 -07001965struct dst_entry *ip6_route_input_lookup(struct net *net,
1966 struct net_device *dev,
David Ahernb75cc8f2018-03-02 08:32:17 -08001967 struct flowi6 *fl6,
1968 const struct sk_buff *skb,
1969 int flags)
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001970{
1971 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
1972 flags |= RT6_LOOKUP_F_IFACE;
1973
David Ahernb75cc8f2018-03-02 08:32:17 -08001974 return fib6_rule_lookup(net, fl6, skb, flags, ip6_pol_route_input);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001975}
Mahesh Bandeward409b842016-09-16 12:59:08 -07001976EXPORT_SYMBOL_GPL(ip6_route_input_lookup);
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00001977
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001978static void ip6_multipath_l3_keys(const struct sk_buff *skb,
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001979 struct flow_keys *keys,
1980 struct flow_keys *flkeys)
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001981{
1982 const struct ipv6hdr *outer_iph = ipv6_hdr(skb);
1983 const struct ipv6hdr *key_iph = outer_iph;
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05001984 struct flow_keys *_flkeys = flkeys;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001985 const struct ipv6hdr *inner_iph;
1986 const struct icmp6hdr *icmph;
1987 struct ipv6hdr _inner_iph;
Eric Dumazetcea67a22018-04-29 09:54:59 -07001988 struct icmp6hdr _icmph;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001989
1990 if (likely(outer_iph->nexthdr != IPPROTO_ICMPV6))
1991 goto out;
1992
Eric Dumazetcea67a22018-04-29 09:54:59 -07001993 icmph = skb_header_pointer(skb, skb_transport_offset(skb),
1994 sizeof(_icmph), &_icmph);
1995 if (!icmph)
1996 goto out;
1997
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02001998 if (icmph->icmp6_type != ICMPV6_DEST_UNREACH &&
1999 icmph->icmp6_type != ICMPV6_PKT_TOOBIG &&
2000 icmph->icmp6_type != ICMPV6_TIME_EXCEED &&
2001 icmph->icmp6_type != ICMPV6_PARAMPROB)
2002 goto out;
2003
2004 inner_iph = skb_header_pointer(skb,
2005 skb_transport_offset(skb) + sizeof(*icmph),
2006 sizeof(_inner_iph), &_inner_iph);
2007 if (!inner_iph)
2008 goto out;
2009
2010 key_iph = inner_iph;
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05002011 _flkeys = NULL;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002012out:
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05002013 if (_flkeys) {
2014 keys->addrs.v6addrs.src = _flkeys->addrs.v6addrs.src;
2015 keys->addrs.v6addrs.dst = _flkeys->addrs.v6addrs.dst;
2016 keys->tags.flow_label = _flkeys->tags.flow_label;
2017 keys->basic.ip_proto = _flkeys->basic.ip_proto;
2018 } else {
2019 keys->addrs.v6addrs.src = key_iph->saddr;
2020 keys->addrs.v6addrs.dst = key_iph->daddr;
Michal Kubecekfa1be7e2018-06-04 11:36:05 +02002021 keys->tags.flow_label = ip6_flowlabel(key_iph);
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05002022 keys->basic.ip_proto = key_iph->nexthdr;
2023 }
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002024}
2025
2026/* if skb is set it will be used and fl6 can be NULL */
David Ahernb4bac172018-03-02 08:32:18 -08002027u32 rt6_multipath_hash(const struct net *net, const struct flowi6 *fl6,
2028 const struct sk_buff *skb, struct flow_keys *flkeys)
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002029{
2030 struct flow_keys hash_keys;
David Ahern9a2a5372018-03-02 08:32:15 -08002031 u32 mhash;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002032
David S. Millerbbfa0472018-03-12 11:09:33 -04002033 switch (ip6_multipath_hash_policy(net)) {
David Ahernb4bac172018-03-02 08:32:18 -08002034 case 0:
2035 memset(&hash_keys, 0, sizeof(hash_keys));
2036 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2037 if (skb) {
2038 ip6_multipath_l3_keys(skb, &hash_keys, flkeys);
2039 } else {
2040 hash_keys.addrs.v6addrs.src = fl6->saddr;
2041 hash_keys.addrs.v6addrs.dst = fl6->daddr;
Michal Kubecekfa1be7e2018-06-04 11:36:05 +02002042 hash_keys.tags.flow_label = (__force u32)flowi6_get_flowlabel(fl6);
David Ahernb4bac172018-03-02 08:32:18 -08002043 hash_keys.basic.ip_proto = fl6->flowi6_proto;
2044 }
2045 break;
2046 case 1:
2047 if (skb) {
2048 unsigned int flag = FLOW_DISSECTOR_F_STOP_AT_ENCAP;
2049 struct flow_keys keys;
2050
2051 /* short-circuit if we already have L4 hash present */
2052 if (skb->l4_hash)
2053 return skb_get_hash_raw(skb) >> 1;
2054
2055 memset(&hash_keys, 0, sizeof(hash_keys));
2056
2057 if (!flkeys) {
2058 skb_flow_dissect_flow_keys(skb, &keys, flag);
2059 flkeys = &keys;
2060 }
2061 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2062 hash_keys.addrs.v6addrs.src = flkeys->addrs.v6addrs.src;
2063 hash_keys.addrs.v6addrs.dst = flkeys->addrs.v6addrs.dst;
2064 hash_keys.ports.src = flkeys->ports.src;
2065 hash_keys.ports.dst = flkeys->ports.dst;
2066 hash_keys.basic.ip_proto = flkeys->basic.ip_proto;
2067 } else {
2068 memset(&hash_keys, 0, sizeof(hash_keys));
2069 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2070 hash_keys.addrs.v6addrs.src = fl6->saddr;
2071 hash_keys.addrs.v6addrs.dst = fl6->daddr;
2072 hash_keys.ports.src = fl6->fl6_sport;
2073 hash_keys.ports.dst = fl6->fl6_dport;
2074 hash_keys.basic.ip_proto = fl6->flowi6_proto;
2075 }
2076 break;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002077 }
David Ahern9a2a5372018-03-02 08:32:15 -08002078 mhash = flow_hash_from_keys(&hash_keys);
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002079
David Ahern9a2a5372018-03-02 08:32:15 -08002080 return mhash >> 1;
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002081}
2082
Thomas Grafc71099a2006-08-04 23:20:06 -07002083void ip6_route_input(struct sk_buff *skb)
2084{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002085 const struct ipv6hdr *iph = ipv6_hdr(skb);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002086 struct net *net = dev_net(skb->dev);
Thomas Grafadaa70b2006-10-13 15:01:03 -07002087 int flags = RT6_LOOKUP_F_HAS_SADDR;
Jiri Benc904af042015-08-20 13:56:31 +02002088 struct ip_tunnel_info *tun_info;
David S. Miller4c9483b2011-03-12 16:22:43 -05002089 struct flowi6 fl6 = {
David Aherne0d56fd2016-09-10 12:09:57 -07002090 .flowi6_iif = skb->dev->ifindex,
David S. Miller4c9483b2011-03-12 16:22:43 -05002091 .daddr = iph->daddr,
2092 .saddr = iph->saddr,
YOSHIFUJI Hideaki / 吉藤英明6502ca52013-01-13 05:01:51 +00002093 .flowlabel = ip6_flowinfo(iph),
David S. Miller4c9483b2011-03-12 16:22:43 -05002094 .flowi6_mark = skb->mark,
2095 .flowi6_proto = iph->nexthdr,
Thomas Grafc71099a2006-08-04 23:20:06 -07002096 };
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05002097 struct flow_keys *flkeys = NULL, _flkeys;
Thomas Grafadaa70b2006-10-13 15:01:03 -07002098
Jiri Benc904af042015-08-20 13:56:31 +02002099 tun_info = skb_tunnel_info(skb);
Jiri Benc46fa0622015-08-28 20:48:19 +02002100 if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX))
Jiri Benc904af042015-08-20 13:56:31 +02002101 fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id;
Roopa Prabhu5e5d6fe2018-02-28 22:43:22 -05002102
2103 if (fib6_rules_early_flow_dissect(net, skb, &fl6, &_flkeys))
2104 flkeys = &_flkeys;
2105
Jakub Sitnicki23aebda2017-08-23 09:58:29 +02002106 if (unlikely(fl6.flowi6_proto == IPPROTO_ICMPV6))
David Ahernb4bac172018-03-02 08:32:18 -08002107 fl6.mp_hash = rt6_multipath_hash(net, &fl6, skb, flkeys);
Jiri Benc06e9d042015-08-20 13:56:26 +02002108 skb_dst_drop(skb);
David Ahernb75cc8f2018-03-02 08:32:17 -08002109 skb_dst_set(skb,
2110 ip6_route_input_lookup(net, skb->dev, &fl6, skb, flags));
Thomas Grafc71099a2006-08-04 23:20:06 -07002111}
2112
David Ahernb75cc8f2018-03-02 08:32:17 -08002113static struct rt6_info *ip6_pol_route_output(struct net *net,
2114 struct fib6_table *table,
2115 struct flowi6 *fl6,
2116 const struct sk_buff *skb,
2117 int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07002118{
David Ahernb75cc8f2018-03-02 08:32:17 -08002119 return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, skb, flags);
Thomas Grafc71099a2006-08-04 23:20:06 -07002120}
2121
Paolo Abeni6f21c962016-01-29 12:30:19 +01002122struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk,
2123 struct flowi6 *fl6, int flags)
Thomas Grafc71099a2006-08-04 23:20:06 -07002124{
David Ahernd46a9d62015-10-21 08:42:22 -07002125 bool any_src;
Thomas Grafc71099a2006-08-04 23:20:06 -07002126
Robert Shearman3ede0bb2018-09-19 13:56:53 +01002127 if (ipv6_addr_type(&fl6->daddr) &
2128 (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)) {
David Ahern4c1feac2016-09-10 12:09:56 -07002129 struct dst_entry *dst;
2130
2131 dst = l3mdev_link_scope_lookup(net, fl6);
2132 if (dst)
2133 return dst;
2134 }
David Ahernca254492015-10-12 11:47:10 -07002135
Pavel Emelyanov1fb94892012-08-08 21:53:36 +00002136 fl6->flowi6_iif = LOOPBACK_IFINDEX;
David McCullough4dc27d1c2012-06-25 15:42:26 +00002137
David Ahernd46a9d62015-10-21 08:42:22 -07002138 any_src = ipv6_addr_any(&fl6->saddr);
David Ahern741a11d2015-09-28 10:12:13 -07002139 if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) ||
David Ahernd46a9d62015-10-21 08:42:22 -07002140 (fl6->flowi6_oif && any_src))
YOSHIFUJI Hideaki77d16f42006-08-23 17:25:05 -07002141 flags |= RT6_LOOKUP_F_IFACE;
Thomas Grafc71099a2006-08-04 23:20:06 -07002142
David Ahernd46a9d62015-10-21 08:42:22 -07002143 if (!any_src)
Thomas Grafadaa70b2006-10-13 15:01:03 -07002144 flags |= RT6_LOOKUP_F_HAS_SADDR;
YOSHIFUJI Hideaki / 吉藤英明0c9a2ac2010-03-07 00:14:44 +00002145 else if (sk)
2146 flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);
Thomas Grafadaa70b2006-10-13 15:01:03 -07002147
David Ahernb75cc8f2018-03-02 08:32:17 -08002148 return fib6_rule_lookup(net, fl6, NULL, flags, ip6_pol_route_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149}
Paolo Abeni6f21c962016-01-29 12:30:19 +01002150EXPORT_SYMBOL_GPL(ip6_route_output_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151
David S. Miller2774c132011-03-01 14:59:04 -08002152struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
David S. Miller14e50e52007-05-24 18:17:54 -07002153{
David S. Miller5c1e6aa2011-04-28 14:13:38 -07002154 struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
Wei Wang1dbe32522017-06-17 10:42:26 -07002155 struct net_device *loopback_dev = net->loopback_dev;
David S. Miller14e50e52007-05-24 18:17:54 -07002156 struct dst_entry *new = NULL;
2157
Wei Wang1dbe32522017-06-17 10:42:26 -07002158 rt = dst_alloc(&ip6_dst_blackhole_ops, loopback_dev, 1,
Steffen Klassert62cf27e2017-10-09 08:39:43 +02002159 DST_OBSOLETE_DEAD, 0);
David S. Miller14e50e52007-05-24 18:17:54 -07002160 if (rt) {
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002161 rt6_info_init(rt);
Wei Wang81eb8442017-10-06 12:06:11 -07002162 atomic_inc(&net->ipv6.rt6_stats->fib_rt_alloc);
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002163
Changli Gaod8d1f302010-06-10 23:31:35 -07002164 new = &rt->dst;
David S. Miller14e50e52007-05-24 18:17:54 -07002165 new->__use = 1;
Herbert Xu352e5122007-11-13 21:34:06 -08002166 new->input = dst_discard;
Eric W. Biedermanede20592015-10-07 16:48:47 -05002167 new->output = dst_discard_out;
David S. Miller14e50e52007-05-24 18:17:54 -07002168
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002169 dst_copy_metrics(new, &ort->dst);
David S. Miller14e50e52007-05-24 18:17:54 -07002170
Wei Wang1dbe32522017-06-17 10:42:26 -07002171 rt->rt6i_idev = in6_dev_get(loopback_dev);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002172 rt->rt6i_gateway = ort->rt6i_gateway;
Martin KaFai Lau0a1f5962015-10-15 16:39:58 -07002173 rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU;
David S. Miller14e50e52007-05-24 18:17:54 -07002174
2175 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
2176#ifdef CONFIG_IPV6_SUBTREES
2177 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
2178#endif
David S. Miller14e50e52007-05-24 18:17:54 -07002179 }
2180
David S. Miller69ead7a2011-03-01 14:45:33 -08002181 dst_release(dst_orig);
2182 return new ? new : ERR_PTR(-ENOMEM);
David S. Miller14e50e52007-05-24 18:17:54 -07002183}
David S. Miller14e50e52007-05-24 18:17:54 -07002184
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185/*
2186 * Destination cache support functions
2187 */
2188
David Ahern8d1c8022018-04-17 17:33:26 -07002189static bool fib6_check(struct fib6_info *f6i, u32 cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002190{
Steffen Klassert36143642017-08-25 09:05:42 +02002191 u32 rt_cookie = 0;
Wei Wangc5cff852017-08-21 09:47:10 -07002192
David Ahern8ae86972018-04-20 15:38:03 -07002193 if (!fib6_get_cookie_safe(f6i, &rt_cookie) || rt_cookie != cookie)
David Ahern93531c62018-04-17 17:33:25 -07002194 return false;
2195
2196 if (fib6_check_expired(f6i))
2197 return false;
2198
2199 return true;
2200}
2201
David Aherna68886a2018-04-20 15:38:02 -07002202static struct dst_entry *rt6_check(struct rt6_info *rt,
2203 struct fib6_info *from,
2204 u32 cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002205{
Wei Wangc5cff852017-08-21 09:47:10 -07002206 u32 rt_cookie = 0;
2207
David Aherna68886a2018-04-20 15:38:02 -07002208 if ((from && !fib6_get_cookie_safe(from, &rt_cookie)) ||
David Ahern93531c62018-04-17 17:33:25 -07002209 rt_cookie != cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002210 return NULL;
2211
2212 if (rt6_check_expired(rt))
2213 return NULL;
2214
2215 return &rt->dst;
2216}
2217
David Aherna68886a2018-04-20 15:38:02 -07002218static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt,
2219 struct fib6_info *from,
2220 u32 cookie)
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002221{
Martin KaFai Lau5973fb12015-11-11 11:51:07 -08002222 if (!__rt6_check_expired(rt) &&
2223 rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
David Aherna68886a2018-04-20 15:38:02 -07002224 fib6_check(from, cookie))
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002225 return &rt->dst;
2226 else
2227 return NULL;
2228}
2229
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
2231{
David Aherna87b7dc2018-04-20 15:38:00 -07002232 struct dst_entry *dst_ret;
David Aherna68886a2018-04-20 15:38:02 -07002233 struct fib6_info *from;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 struct rt6_info *rt;
2235
David Aherna87b7dc2018-04-20 15:38:00 -07002236 rt = container_of(dst, struct rt6_info, dst);
2237
2238 rcu_read_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239
Nicolas Dichtel6f3118b2012-09-10 22:09:46 +00002240 /* All IPV6 dsts are created with ->obsolete set to the value
2241 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
2242 * into this function always.
2243 */
Hannes Frederic Sowae3bc10b2013-10-24 07:48:24 +02002244
David Aherna68886a2018-04-20 15:38:02 -07002245 from = rcu_dereference(rt->from);
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002246
David Aherna68886a2018-04-20 15:38:02 -07002247 if (from && (rt->rt6i_flags & RTF_PCPU ||
2248 unlikely(!list_empty(&rt->rt6i_uncached))))
2249 dst_ret = rt6_dst_from_check(rt, from, cookie);
Martin KaFai Lau3da59bd2015-05-22 20:56:03 -07002250 else
David Aherna68886a2018-04-20 15:38:02 -07002251 dst_ret = rt6_check(rt, from, cookie);
David Aherna87b7dc2018-04-20 15:38:00 -07002252
2253 rcu_read_unlock();
2254
2255 return dst_ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256}
2257
2258static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
2259{
2260 struct rt6_info *rt = (struct rt6_info *) dst;
2261
2262 if (rt) {
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002263 if (rt->rt6i_flags & RTF_CACHE) {
David Ahernc3c14da2018-04-23 11:32:06 -07002264 rcu_read_lock();
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002265 if (rt6_check_expired(rt)) {
David Ahern93531c62018-04-17 17:33:25 -07002266 rt6_remove_exception_rt(rt);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002267 dst = NULL;
2268 }
David Ahernc3c14da2018-04-23 11:32:06 -07002269 rcu_read_unlock();
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002270 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 dst_release(dst);
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002272 dst = NULL;
2273 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 }
YOSHIFUJI Hideaki / 吉藤英明54c1a852010-03-28 07:15:45 +00002275 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276}
2277
2278static void ip6_link_failure(struct sk_buff *skb)
2279{
2280 struct rt6_info *rt;
2281
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00002282 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283
Eric Dumazetadf30902009-06-02 05:19:30 +00002284 rt = (struct rt6_info *) skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 if (rt) {
David Ahern8a14e462018-04-23 11:32:07 -07002286 rcu_read_lock();
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02002287 if (rt->rt6i_flags & RTF_CACHE) {
Xin Long761f6022018-11-14 00:48:28 +08002288 rt6_remove_exception_rt(rt);
Wei Wangc5cff852017-08-21 09:47:10 -07002289 } else {
David Aherna68886a2018-04-20 15:38:02 -07002290 struct fib6_info *from;
Wei Wangc5cff852017-08-21 09:47:10 -07002291 struct fib6_node *fn;
2292
David Aherna68886a2018-04-20 15:38:02 -07002293 from = rcu_dereference(rt->from);
2294 if (from) {
2295 fn = rcu_dereference(from->fib6_node);
2296 if (fn && (rt->rt6i_flags & RTF_DEFAULT))
2297 fn->fn_sernum = -1;
2298 }
Hannes Frederic Sowa1eb4f752013-07-10 23:00:57 +02002299 }
David Ahern8a14e462018-04-23 11:32:07 -07002300 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 }
2302}
2303
David Ahern6a3e0302018-04-20 15:37:57 -07002304static void rt6_update_expires(struct rt6_info *rt0, int timeout)
2305{
David Aherna68886a2018-04-20 15:38:02 -07002306 if (!(rt0->rt6i_flags & RTF_EXPIRES)) {
2307 struct fib6_info *from;
2308
2309 rcu_read_lock();
2310 from = rcu_dereference(rt0->from);
2311 if (from)
2312 rt0->dst.expires = from->expires;
2313 rcu_read_unlock();
2314 }
David Ahern6a3e0302018-04-20 15:37:57 -07002315
2316 dst_set_expires(&rt0->dst, timeout);
2317 rt0->rt6i_flags |= RTF_EXPIRES;
2318}
2319
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002320static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
2321{
2322 struct net *net = dev_net(rt->dst.dev);
2323
David Ahernd4ead6b2018-04-17 17:33:16 -07002324 dst_metric_set(&rt->dst, RTAX_MTU, mtu);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002325 rt->rt6i_flags |= RTF_MODIFIED;
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002326 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
2327}
2328
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002329static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
2330{
2331 return !(rt->rt6i_flags & RTF_CACHE) &&
Paolo Abeni1490ed22019-02-15 18:15:37 +01002332 (rt->rt6i_flags & RTF_PCPU || rcu_access_pointer(rt->from));
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002333}
2334
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002335static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
2336 const struct ipv6hdr *iph, u32 mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337{
Julian Anastasov0dec8792017-02-06 23:14:16 +02002338 const struct in6_addr *daddr, *saddr;
Ian Morris67ba4152014-08-24 21:53:10 +01002339 struct rt6_info *rt6 = (struct rt6_info *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340
Xin Long19bda362016-10-28 18:18:01 +08002341 if (dst_metric_locked(dst, RTAX_MTU))
2342 return;
2343
Julian Anastasov0dec8792017-02-06 23:14:16 +02002344 if (iph) {
2345 daddr = &iph->daddr;
2346 saddr = &iph->saddr;
2347 } else if (sk) {
2348 daddr = &sk->sk_v6_daddr;
2349 saddr = &inet6_sk(sk)->saddr;
2350 } else {
2351 daddr = NULL;
2352 saddr = NULL;
2353 }
2354 dst_confirm_neigh(dst, daddr);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002355 mtu = max_t(u32, mtu, IPV6_MIN_MTU);
2356 if (mtu >= dst_mtu(dst))
2357 return;
David S. Miller81aded22012-06-15 14:54:11 -07002358
Martin KaFai Lau0d3f6d22015-11-11 11:51:06 -08002359 if (!rt6_cache_allowed_for_pmtu(rt6)) {
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002360 rt6_do_update_pmtu(rt6, mtu);
Wei Wang2b760fc2017-10-06 12:06:03 -07002361 /* update rt6_ex->stamp for cache */
2362 if (rt6->rt6i_flags & RTF_CACHE)
2363 rt6_update_exception_stamp_rt(rt6);
Julian Anastasov0dec8792017-02-06 23:14:16 +02002364 } else if (daddr) {
David Ahern85bd05d2019-04-16 14:36:01 -07002365 struct fib6_result res = {};
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002366 struct rt6_info *nrt6;
Hagen Paul Pfeifer9d289712015-01-15 22:34:25 +01002367
David Ahern4d85cd02018-04-20 15:37:59 -07002368 rcu_read_lock();
David Ahern85bd05d2019-04-16 14:36:01 -07002369 res.f6i = rcu_dereference(rt6->from);
2370 if (!res.f6i) {
Jonathan Lemon9c69a132019-04-14 14:21:29 -07002371 rcu_read_unlock();
2372 return;
2373 }
David Ahern85bd05d2019-04-16 14:36:01 -07002374 res.nh = &res.f6i->fib6_nh;
David Ahern7d21fec2019-04-16 14:36:11 -07002375 res.fib6_flags = res.f6i->fib6_flags;
2376 res.fib6_type = res.f6i->fib6_type;
2377
David Ahern85bd05d2019-04-16 14:36:01 -07002378 nrt6 = ip6_rt_cache_alloc(&res, daddr, saddr);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002379 if (nrt6) {
2380 rt6_do_update_pmtu(nrt6, mtu);
David Ahern5012f0a2019-04-16 14:36:05 -07002381 if (rt6_insert_exception(nrt6, &res))
Wei Wang2b760fc2017-10-06 12:06:03 -07002382 dst_release_immediate(&nrt6->dst);
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002383 }
David Aherna68886a2018-04-20 15:38:02 -07002384 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 }
2386}
2387
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002388static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
2389 struct sk_buff *skb, u32 mtu)
2390{
2391 __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu);
2392}
2393
David S. Miller42ae66c2012-06-15 20:01:57 -07002394void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002395 int oif, u32 mark, kuid_t uid)
David S. Miller81aded22012-06-15 14:54:11 -07002396{
2397 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
2398 struct dst_entry *dst;
Maciej Żenczykowskidc920952018-09-29 23:44:51 -07002399 struct flowi6 fl6 = {
2400 .flowi6_oif = oif,
2401 .flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark),
2402 .daddr = iph->daddr,
2403 .saddr = iph->saddr,
2404 .flowlabel = ip6_flowinfo(iph),
2405 .flowi6_uid = uid,
2406 };
David S. Miller81aded22012-06-15 14:54:11 -07002407
2408 dst = ip6_route_output(net, NULL, &fl6);
2409 if (!dst->error)
Martin KaFai Lau45e4fd22015-05-22 20:56:00 -07002410 __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu));
David S. Miller81aded22012-06-15 14:54:11 -07002411 dst_release(dst);
2412}
2413EXPORT_SYMBOL_GPL(ip6_update_pmtu);
2414
2415void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
2416{
David Ahern7ddacfa2018-11-18 10:45:30 -08002417 int oif = sk->sk_bound_dev_if;
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07002418 struct dst_entry *dst;
2419
David Ahern7ddacfa2018-11-18 10:45:30 -08002420 if (!oif && skb->dev)
2421 oif = l3mdev_master_ifindex(skb->dev);
2422
2423 ip6_update_pmtu(skb, sock_net(sk), mtu, oif, sk->sk_mark, sk->sk_uid);
Martin KaFai Lau33c162a2016-04-11 15:29:36 -07002424
2425 dst = __sk_dst_get(sk);
2426 if (!dst || !dst->obsolete ||
2427 dst->ops->check(dst, inet6_sk(sk)->dst_cookie))
2428 return;
2429
2430 bh_lock_sock(sk);
2431 if (!sock_owned_by_user(sk) && !ipv6_addr_v4mapped(&sk->sk_v6_daddr))
2432 ip6_datagram_dst_update(sk, false);
2433 bh_unlock_sock(sk);
David S. Miller81aded22012-06-15 14:54:11 -07002434}
2435EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
2436
Alexey Kodanev7d6850f2018-04-03 15:00:07 +03002437void ip6_sk_dst_store_flow(struct sock *sk, struct dst_entry *dst,
2438 const struct flowi6 *fl6)
2439{
2440#ifdef CONFIG_IPV6_SUBTREES
2441 struct ipv6_pinfo *np = inet6_sk(sk);
2442#endif
2443
2444 ip6_dst_store(sk, dst,
2445 ipv6_addr_equal(&fl6->daddr, &sk->sk_v6_daddr) ?
2446 &sk->sk_v6_daddr : NULL,
2447#ifdef CONFIG_IPV6_SUBTREES
2448 ipv6_addr_equal(&fl6->saddr, &np->saddr) ?
2449 &np->saddr :
2450#endif
2451 NULL);
2452}
2453
David Ahern9b6b35a2019-04-16 14:36:02 -07002454static bool ip6_redirect_nh_match(const struct fib6_result *res,
David Ahern0b34eb02019-04-09 14:41:19 -07002455 struct flowi6 *fl6,
2456 const struct in6_addr *gw,
2457 struct rt6_info **ret)
2458{
David Ahern9b6b35a2019-04-16 14:36:02 -07002459 const struct fib6_nh *nh = res->nh;
2460
David Ahern0b34eb02019-04-09 14:41:19 -07002461 if (nh->fib_nh_flags & RTNH_F_DEAD || !nh->fib_nh_gw_family ||
2462 fl6->flowi6_oif != nh->fib_nh_dev->ifindex)
2463 return false;
2464
2465 /* rt_cache's gateway might be different from its 'parent'
2466 * in the case of an ip redirect.
2467 * So we keep searching in the exception table if the gateway
2468 * is different.
2469 */
2470 if (!ipv6_addr_equal(gw, &nh->fib_nh_gw6)) {
2471 struct rt6_info *rt_cache;
2472
David Ahern9b6b35a2019-04-16 14:36:02 -07002473 rt_cache = rt6_find_cached_rt(res, &fl6->daddr, &fl6->saddr);
David Ahern0b34eb02019-04-09 14:41:19 -07002474 if (rt_cache &&
2475 ipv6_addr_equal(gw, &rt_cache->rt6i_gateway)) {
2476 *ret = rt_cache;
2477 return true;
2478 }
2479 return false;
2480 }
2481 return true;
2482}
2483
Duan Jiongb55b76b2013-09-04 19:44:21 +08002484/* Handle redirects */
2485struct ip6rd_flowi {
2486 struct flowi6 fl6;
2487 struct in6_addr gateway;
2488};
2489
2490static struct rt6_info *__ip6_route_redirect(struct net *net,
2491 struct fib6_table *table,
2492 struct flowi6 *fl6,
David Ahernb75cc8f2018-03-02 08:32:17 -08002493 const struct sk_buff *skb,
Duan Jiongb55b76b2013-09-04 19:44:21 +08002494 int flags)
2495{
2496 struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
David Ahern0b34eb02019-04-09 14:41:19 -07002497 struct rt6_info *ret = NULL;
David Ahern9b6b35a2019-04-16 14:36:02 -07002498 struct fib6_result res = {};
David Ahern8d1c8022018-04-17 17:33:26 -07002499 struct fib6_info *rt;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002500 struct fib6_node *fn;
2501
2502 /* Get the "current" route for this destination and
Alexander Alemayhu67c408c2017-01-07 23:53:00 +01002503 * check if the redirect has come from appropriate router.
Duan Jiongb55b76b2013-09-04 19:44:21 +08002504 *
2505 * RFC 4861 specifies that redirects should only be
2506 * accepted if they come from the nexthop to the target.
2507 * Due to the way the routes are chosen, this notion
2508 * is a bit fuzzy and one might need to check all possible
2509 * routes.
2510 */
2511
Wei Wang66f5d6c2017-10-06 12:06:10 -07002512 rcu_read_lock();
David Ahern64547432018-05-09 20:34:19 -07002513 fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002514restart:
Wei Wang66f5d6c2017-10-06 12:06:10 -07002515 for_each_fib6_node_rt_rcu(fn) {
David Ahern9b6b35a2019-04-16 14:36:02 -07002516 res.f6i = rt;
2517 res.nh = &rt->fib6_nh;
2518
David Ahern14895682018-04-17 17:33:17 -07002519 if (fib6_check_expired(rt))
Duan Jiongb55b76b2013-09-04 19:44:21 +08002520 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07002521 if (rt->fib6_flags & RTF_REJECT)
Duan Jiongb55b76b2013-09-04 19:44:21 +08002522 break;
David Ahern9b6b35a2019-04-16 14:36:02 -07002523 if (ip6_redirect_nh_match(&res, fl6, &rdfl->gateway, &ret))
David Ahern0b34eb02019-04-09 14:41:19 -07002524 goto out;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002525 }
2526
2527 if (!rt)
David Ahern421842e2018-04-17 17:33:18 -07002528 rt = net->ipv6.fib6_null_entry;
David Ahern93c2fb22018-04-18 15:38:59 -07002529 else if (rt->fib6_flags & RTF_REJECT) {
David Ahern23fb93a2018-04-17 17:33:23 -07002530 ret = net->ipv6.ip6_null_entry;
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08002531 goto out;
2532 }
2533
David Ahern421842e2018-04-17 17:33:18 -07002534 if (rt == net->ipv6.fib6_null_entry) {
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07002535 fn = fib6_backtrack(fn, &fl6->saddr);
2536 if (fn)
2537 goto restart;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002538 }
Martin KaFai Laua3c00e42014-10-20 13:42:43 -07002539
David Ahern9b6b35a2019-04-16 14:36:02 -07002540 res.f6i = rt;
2541 res.nh = &rt->fib6_nh;
Martin KaFai Laub0a1ba52015-01-20 19:16:02 -08002542out:
David Ahern7d21fec2019-04-16 14:36:11 -07002543 if (ret) {
David Ahern10585b42019-03-20 09:24:50 -07002544 ip6_hold_safe(net, &ret);
David Ahern7d21fec2019-04-16 14:36:11 -07002545 } else {
2546 res.fib6_flags = res.f6i->fib6_flags;
2547 res.fib6_type = res.f6i->fib6_type;
David Ahern9b6b35a2019-04-16 14:36:02 -07002548 ret = ip6_create_rt_rcu(&res);
David Ahern7d21fec2019-04-16 14:36:11 -07002549 }
Duan Jiongb55b76b2013-09-04 19:44:21 +08002550
Wei Wang66f5d6c2017-10-06 12:06:10 -07002551 rcu_read_unlock();
Duan Jiongb55b76b2013-09-04 19:44:21 +08002552
David Ahern8ff2e5b2019-04-16 14:36:09 -07002553 trace_fib6_table_lookup(net, &res, table, fl6);
David Ahern23fb93a2018-04-17 17:33:23 -07002554 return ret;
Duan Jiongb55b76b2013-09-04 19:44:21 +08002555};
2556
2557static struct dst_entry *ip6_route_redirect(struct net *net,
David Ahernb75cc8f2018-03-02 08:32:17 -08002558 const struct flowi6 *fl6,
2559 const struct sk_buff *skb,
2560 const struct in6_addr *gateway)
Duan Jiongb55b76b2013-09-04 19:44:21 +08002561{
2562 int flags = RT6_LOOKUP_F_HAS_SADDR;
2563 struct ip6rd_flowi rdfl;
2564
2565 rdfl.fl6 = *fl6;
2566 rdfl.gateway = *gateway;
2567
David Ahernb75cc8f2018-03-02 08:32:17 -08002568 return fib6_rule_lookup(net, &rdfl.fl6, skb,
Duan Jiongb55b76b2013-09-04 19:44:21 +08002569 flags, __ip6_route_redirect);
2570}
2571
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002572void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark,
2573 kuid_t uid)
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002574{
2575 const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
2576 struct dst_entry *dst;
Maciej Żenczykowski1f7f10a2018-09-29 23:44:48 -07002577 struct flowi6 fl6 = {
2578 .flowi6_iif = LOOPBACK_IFINDEX,
2579 .flowi6_oif = oif,
2580 .flowi6_mark = mark,
2581 .daddr = iph->daddr,
2582 .saddr = iph->saddr,
2583 .flowlabel = ip6_flowinfo(iph),
2584 .flowi6_uid = uid,
2585 };
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002586
David Ahernb75cc8f2018-03-02 08:32:17 -08002587 dst = ip6_route_redirect(net, &fl6, skb, &ipv6_hdr(skb)->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002588 rt6_do_redirect(dst, NULL, skb);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002589 dst_release(dst);
2590}
2591EXPORT_SYMBOL_GPL(ip6_redirect);
2592
Maciej Żenczykowskid4563362018-09-29 23:44:50 -07002593void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif)
Duan Jiongc92a59e2013-08-22 12:07:35 +08002594{
2595 const struct ipv6hdr *iph = ipv6_hdr(skb);
2596 const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
2597 struct dst_entry *dst;
Maciej Żenczykowski0b26fb12018-09-29 23:44:49 -07002598 struct flowi6 fl6 = {
2599 .flowi6_iif = LOOPBACK_IFINDEX,
2600 .flowi6_oif = oif,
Maciej Żenczykowski0b26fb12018-09-29 23:44:49 -07002601 .daddr = msg->dest,
2602 .saddr = iph->daddr,
2603 .flowi6_uid = sock_net_uid(net, NULL),
2604 };
Duan Jiongc92a59e2013-08-22 12:07:35 +08002605
David Ahernb75cc8f2018-03-02 08:32:17 -08002606 dst = ip6_route_redirect(net, &fl6, skb, &iph->saddr);
Duan Jiongb55b76b2013-09-04 19:44:21 +08002607 rt6_do_redirect(dst, NULL, skb);
Duan Jiongc92a59e2013-08-22 12:07:35 +08002608 dst_release(dst);
2609}
2610
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002611void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
2612{
Lorenzo Colittie2d118a2016-11-04 02:23:43 +09002613 ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark,
2614 sk->sk_uid);
David S. Miller3a5ad2e2012-07-12 00:08:07 -07002615}
2616EXPORT_SYMBOL_GPL(ip6_sk_redirect);
2617
David S. Miller0dbaee32010-12-13 12:52:14 -08002618static unsigned int ip6_default_advmss(const struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619{
David S. Miller0dbaee32010-12-13 12:52:14 -08002620 struct net_device *dev = dst->dev;
2621 unsigned int mtu = dst_mtu(dst);
2622 struct net *net = dev_net(dev);
2623
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
2625
Daniel Lezcano55786892008-03-04 13:47:47 -08002626 if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
2627 mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628
2629 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002630 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
2631 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
2632 * IPV6_MAXPLEN is also valid and means: "any MSS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 * rely only on pmtu discovery"
2634 */
2635 if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
2636 mtu = IPV6_MAXPLEN;
2637 return mtu;
2638}
2639
Steffen Klassertebb762f2011-11-23 02:12:51 +00002640static unsigned int ip6_mtu(const struct dst_entry *dst)
David S. Millerd33e4552010-12-14 13:01:14 -08002641{
David S. Millerd33e4552010-12-14 13:01:14 -08002642 struct inet6_dev *idev;
David Ahernd4ead6b2018-04-17 17:33:16 -07002643 unsigned int mtu;
Steffen Klassert618f9bc2011-11-23 02:13:31 +00002644
Martin KaFai Lau4b32b5a2015-04-28 13:03:06 -07002645 mtu = dst_metric_raw(dst, RTAX_MTU);
2646 if (mtu)
2647 goto out;
2648
Steffen Klassert618f9bc2011-11-23 02:13:31 +00002649 mtu = IPV6_MIN_MTU;
David S. Millerd33e4552010-12-14 13:01:14 -08002650
2651 rcu_read_lock();
2652 idev = __in6_dev_get(dst->dev);
2653 if (idev)
2654 mtu = idev->cnf.mtu6;
2655 rcu_read_unlock();
2656
Eric Dumazet30f78d82014-04-10 21:23:36 -07002657out:
Roopa Prabhu14972cb2016-08-24 20:10:43 -07002658 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
2659
2660 return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
David S. Millerd33e4552010-12-14 13:01:14 -08002661}
2662
David Ahern901731b2018-05-21 09:08:14 -07002663/* MTU selection:
2664 * 1. mtu on route is locked - use it
2665 * 2. mtu from nexthop exception
2666 * 3. mtu from egress device
2667 *
2668 * based on ip6_dst_mtu_forward and exception logic of
2669 * rt6_find_cached_rt; called with rcu_read_lock
2670 */
David Ahernb748f262019-04-16 14:36:06 -07002671u32 ip6_mtu_from_fib6(const struct fib6_result *res,
2672 const struct in6_addr *daddr,
2673 const struct in6_addr *saddr)
David Ahern901731b2018-05-21 09:08:14 -07002674{
2675 struct rt6_exception_bucket *bucket;
David Ahernb748f262019-04-16 14:36:06 -07002676 const struct fib6_nh *nh = res->nh;
2677 struct fib6_info *f6i = res->f6i;
2678 const struct in6_addr *src_key;
David Ahern901731b2018-05-21 09:08:14 -07002679 struct rt6_exception *rt6_ex;
David Ahern901731b2018-05-21 09:08:14 -07002680 struct inet6_dev *idev;
2681 u32 mtu = 0;
2682
2683 if (unlikely(fib6_metric_locked(f6i, RTAX_MTU))) {
2684 mtu = f6i->fib6_pmtu;
2685 if (mtu)
2686 goto out;
2687 }
2688
2689 src_key = NULL;
2690#ifdef CONFIG_IPV6_SUBTREES
2691 if (f6i->fib6_src.plen)
2692 src_key = saddr;
2693#endif
2694
2695 bucket = rcu_dereference(f6i->rt6i_exception_bucket);
2696 rt6_ex = __rt6_find_exception_rcu(&bucket, daddr, src_key);
2697 if (rt6_ex && !rt6_check_expired(rt6_ex->rt6i))
2698 mtu = dst_metric_raw(&rt6_ex->rt6i->dst, RTAX_MTU);
2699
2700 if (likely(!mtu)) {
David Ahernb748f262019-04-16 14:36:06 -07002701 struct net_device *dev = nh->fib_nh_dev;
David Ahern901731b2018-05-21 09:08:14 -07002702
2703 mtu = IPV6_MIN_MTU;
2704 idev = __in6_dev_get(dev);
2705 if (idev && idev->cnf.mtu6 > mtu)
2706 mtu = idev->cnf.mtu6;
2707 }
2708
2709 mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
2710out:
David Ahernb748f262019-04-16 14:36:06 -07002711 return mtu - lwtunnel_headroom(nh->fib_nh_lws, mtu);
David Ahern901731b2018-05-21 09:08:14 -07002712}
2713
YOSHIFUJI Hideaki3b009442007-12-06 16:11:48 -08002714struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
David S. Miller87a11572011-12-06 17:04:13 -05002715 struct flowi6 *fl6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716{
David S. Miller87a11572011-12-06 17:04:13 -05002717 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 struct rt6_info *rt;
2719 struct inet6_dev *idev = in6_dev_get(dev);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002720 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721
David S. Miller38308472011-12-03 18:02:47 -05002722 if (unlikely(!idev))
Eric Dumazet122bdf62012-03-14 21:13:11 +00002723 return ERR_PTR(-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724
Martin KaFai Lauad706862015-08-14 11:05:52 -07002725 rt = ip6_dst_alloc(net, dev, 0);
David S. Miller38308472011-12-03 18:02:47 -05002726 if (unlikely(!rt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 in6_dev_put(idev);
David S. Miller87a11572011-12-06 17:04:13 -05002728 dst = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 goto out;
2730 }
2731
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002732 rt->dst.flags |= DST_HOST;
Brendan McGrath588753f2017-12-13 22:14:57 +11002733 rt->dst.input = ip6_input;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002734 rt->dst.output = ip6_output;
Julian Anastasov550bab42013-10-20 15:43:04 +03002735 rt->rt6i_gateway = fl6->daddr;
David S. Miller87a11572011-12-06 17:04:13 -05002736 rt->rt6i_dst.addr = fl6->daddr;
Yan, Zheng8e2ec632011-09-05 21:34:30 +00002737 rt->rt6i_dst.plen = 128;
2738 rt->rt6i_idev = idev;
Li RongQing14edd872012-10-24 14:01:18 +08002739 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740
Ido Schimmel4c981e22018-01-07 12:45:04 +02002741 /* Add this dst into uncached_list so that rt6_disable_ip() can
Wei Wang587fea72017-06-17 10:42:36 -07002742 * do proper release of the net_device
2743 */
2744 rt6_uncached_list_add(rt);
Wei Wang81eb8442017-10-06 12:06:11 -07002745 atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746
David S. Miller87a11572011-12-06 17:04:13 -05002747 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
2748
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749out:
David S. Miller87a11572011-12-06 17:04:13 -05002750 return dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751}
2752
Daniel Lezcano569d3642008-01-18 03:56:57 -08002753static int ip6_dst_gc(struct dst_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754{
Alexey Dobriyan86393e52009-08-29 01:34:49 +00002755 struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
Daniel Lezcano7019b782008-03-04 13:50:14 -08002756 int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
2757 int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
2758 int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
2759 int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
2760 unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
Eric Dumazetfc66f952010-10-08 06:37:34 +00002761 int entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762
Eric Dumazetfc66f952010-10-08 06:37:34 +00002763 entries = dst_entries_get_fast(ops);
Michal Kubeček49a18d82013-08-01 10:04:24 +02002764 if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
Eric Dumazetfc66f952010-10-08 06:37:34 +00002765 entries <= rt_max_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 goto out;
2767
Benjamin Thery6891a342008-03-04 13:49:47 -08002768 net->ipv6.ip6_rt_gc_expire++;
Li RongQing14956642014-05-19 17:30:28 +08002769 fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true);
Eric Dumazetfc66f952010-10-08 06:37:34 +00002770 entries = dst_entries_get_slow(ops);
2771 if (entries < ops->gc_thresh)
Daniel Lezcano7019b782008-03-04 13:50:14 -08002772 net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773out:
Daniel Lezcano7019b782008-03-04 13:50:14 -08002774 net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
Eric Dumazetfc66f952010-10-08 06:37:34 +00002775 return entries > rt_max_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776}
2777
David Ahern8c145862016-04-24 21:26:04 -07002778static struct rt6_info *ip6_nh_lookup_table(struct net *net,
2779 struct fib6_config *cfg,
David Ahernf4797b32018-01-25 16:55:08 -08002780 const struct in6_addr *gw_addr,
2781 u32 tbid, int flags)
David Ahern8c145862016-04-24 21:26:04 -07002782{
2783 struct flowi6 fl6 = {
2784 .flowi6_oif = cfg->fc_ifindex,
2785 .daddr = *gw_addr,
2786 .saddr = cfg->fc_prefsrc,
2787 };
2788 struct fib6_table *table;
2789 struct rt6_info *rt;
David Ahern8c145862016-04-24 21:26:04 -07002790
David Ahernf4797b32018-01-25 16:55:08 -08002791 table = fib6_get_table(net, tbid);
David Ahern8c145862016-04-24 21:26:04 -07002792 if (!table)
2793 return NULL;
2794
2795 if (!ipv6_addr_any(&cfg->fc_prefsrc))
2796 flags |= RT6_LOOKUP_F_HAS_SADDR;
2797
David Ahernf4797b32018-01-25 16:55:08 -08002798 flags |= RT6_LOOKUP_F_IGNORE_LINKSTATE;
David Ahernb75cc8f2018-03-02 08:32:17 -08002799 rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, NULL, flags);
David Ahern8c145862016-04-24 21:26:04 -07002800
2801 /* if table lookup failed, fall back to full lookup */
2802 if (rt == net->ipv6.ip6_null_entry) {
2803 ip6_rt_put(rt);
2804 rt = NULL;
2805 }
2806
2807 return rt;
2808}
2809
David Ahernfc1e64e2018-01-25 16:55:09 -08002810static int ip6_route_check_nh_onlink(struct net *net,
2811 struct fib6_config *cfg,
David Ahern9fbb7042018-03-13 08:29:36 -07002812 const struct net_device *dev,
David Ahernfc1e64e2018-01-25 16:55:09 -08002813 struct netlink_ext_ack *extack)
2814{
David Ahern44750f82018-02-06 13:17:06 -08002815 u32 tbid = l3mdev_fib_table(dev) ? : RT_TABLE_MAIN;
David Ahernfc1e64e2018-01-25 16:55:09 -08002816 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2817 u32 flags = RTF_LOCAL | RTF_ANYCAST | RTF_REJECT;
Paolo Abenibf1dc8b2019-02-21 11:19:42 +01002818 struct fib6_info *from;
David Ahernfc1e64e2018-01-25 16:55:09 -08002819 struct rt6_info *grt;
2820 int err;
2821
2822 err = 0;
2823 grt = ip6_nh_lookup_table(net, cfg, gw_addr, tbid, 0);
2824 if (grt) {
Paolo Abenibf1dc8b2019-02-21 11:19:42 +01002825 rcu_read_lock();
2826 from = rcu_dereference(grt->from);
David Ahern58e354c2018-02-06 12:14:12 -08002827 if (!grt->dst.error &&
David Ahern4ed591c2018-10-24 13:58:39 -07002828 /* ignore match if it is the default route */
Paolo Abenibf1dc8b2019-02-21 11:19:42 +01002829 from && !ipv6_addr_any(&from->fib6_dst.addr) &&
David Ahern58e354c2018-02-06 12:14:12 -08002830 (grt->rt6i_flags & flags || dev != grt->dst.dev)) {
David Ahern44750f82018-02-06 13:17:06 -08002831 NL_SET_ERR_MSG(extack,
2832 "Nexthop has invalid gateway or device mismatch");
David Ahernfc1e64e2018-01-25 16:55:09 -08002833 err = -EINVAL;
2834 }
Paolo Abenibf1dc8b2019-02-21 11:19:42 +01002835 rcu_read_unlock();
David Ahernfc1e64e2018-01-25 16:55:09 -08002836
2837 ip6_rt_put(grt);
2838 }
2839
2840 return err;
2841}
2842
David Ahern1edce992018-01-25 16:55:07 -08002843static int ip6_route_check_nh(struct net *net,
2844 struct fib6_config *cfg,
2845 struct net_device **_dev,
2846 struct inet6_dev **idev)
2847{
2848 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2849 struct net_device *dev = _dev ? *_dev : NULL;
2850 struct rt6_info *grt = NULL;
2851 int err = -EHOSTUNREACH;
2852
2853 if (cfg->fc_table) {
David Ahernf4797b32018-01-25 16:55:08 -08002854 int flags = RT6_LOOKUP_F_IFACE;
2855
2856 grt = ip6_nh_lookup_table(net, cfg, gw_addr,
2857 cfg->fc_table, flags);
David Ahern1edce992018-01-25 16:55:07 -08002858 if (grt) {
2859 if (grt->rt6i_flags & RTF_GATEWAY ||
2860 (dev && dev != grt->dst.dev)) {
2861 ip6_rt_put(grt);
2862 grt = NULL;
2863 }
2864 }
2865 }
2866
2867 if (!grt)
David Ahernb75cc8f2018-03-02 08:32:17 -08002868 grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, NULL, 1);
David Ahern1edce992018-01-25 16:55:07 -08002869
2870 if (!grt)
2871 goto out;
2872
2873 if (dev) {
2874 if (dev != grt->dst.dev) {
2875 ip6_rt_put(grt);
2876 goto out;
2877 }
2878 } else {
2879 *_dev = dev = grt->dst.dev;
2880 *idev = grt->rt6i_idev;
2881 dev_hold(dev);
2882 in6_dev_hold(grt->rt6i_idev);
2883 }
2884
2885 if (!(grt->rt6i_flags & RTF_GATEWAY))
2886 err = 0;
2887
2888 ip6_rt_put(grt);
2889
2890out:
2891 return err;
2892}
2893
David Ahern9fbb7042018-03-13 08:29:36 -07002894static int ip6_validate_gw(struct net *net, struct fib6_config *cfg,
2895 struct net_device **_dev, struct inet6_dev **idev,
2896 struct netlink_ext_ack *extack)
2897{
2898 const struct in6_addr *gw_addr = &cfg->fc_gateway;
2899 int gwa_type = ipv6_addr_type(gw_addr);
David Ahern232378e2018-03-13 08:29:37 -07002900 bool skip_dev = gwa_type & IPV6_ADDR_LINKLOCAL ? false : true;
David Ahern9fbb7042018-03-13 08:29:36 -07002901 const struct net_device *dev = *_dev;
David Ahern232378e2018-03-13 08:29:37 -07002902 bool need_addr_check = !dev;
David Ahern9fbb7042018-03-13 08:29:36 -07002903 int err = -EINVAL;
2904
2905 /* if gw_addr is local we will fail to detect this in case
2906 * address is still TENTATIVE (DAD in progress). rt6_lookup()
2907 * will return already-added prefix route via interface that
2908 * prefix route was assigned to, which might be non-loopback.
2909 */
David Ahern232378e2018-03-13 08:29:37 -07002910 if (dev &&
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");
David Ahern9fbb7042018-03-13 08:29:36 -07002913 goto out;
2914 }
2915
2916 if (gwa_type != (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST)) {
2917 /* IPv6 strictly inhibits using not link-local
2918 * addresses as nexthop address.
2919 * Otherwise, router will not able to send redirects.
2920 * It is very good, but in some (rare!) circumstances
2921 * (SIT, PtP, NBMA NOARP links) it is handy to allow
2922 * some exceptions. --ANK
2923 * We allow IPv4-mapped nexthops to support RFC4798-type
2924 * addressing
2925 */
2926 if (!(gwa_type & (IPV6_ADDR_UNICAST | IPV6_ADDR_MAPPED))) {
2927 NL_SET_ERR_MSG(extack, "Invalid gateway address");
2928 goto out;
2929 }
2930
2931 if (cfg->fc_flags & RTNH_F_ONLINK)
2932 err = ip6_route_check_nh_onlink(net, cfg, dev, extack);
2933 else
2934 err = ip6_route_check_nh(net, cfg, _dev, idev);
2935
2936 if (err)
2937 goto out;
2938 }
2939
2940 /* reload in case device was changed */
2941 dev = *_dev;
2942
2943 err = -EINVAL;
2944 if (!dev) {
2945 NL_SET_ERR_MSG(extack, "Egress device not specified");
2946 goto out;
2947 } else if (dev->flags & IFF_LOOPBACK) {
2948 NL_SET_ERR_MSG(extack,
2949 "Egress device can not be loopback device for this route");
2950 goto out;
2951 }
David Ahern232378e2018-03-13 08:29:37 -07002952
2953 /* if we did not check gw_addr above, do so now that the
2954 * egress device has been resolved.
2955 */
2956 if (need_addr_check &&
2957 ipv6_chk_addr_and_flags(net, gw_addr, dev, skip_dev, 0, 0)) {
2958 NL_SET_ERR_MSG(extack, "Gateway can not be a local address");
2959 goto out;
2960 }
2961
David Ahern9fbb7042018-03-13 08:29:36 -07002962 err = 0;
2963out:
2964 return err;
2965}
2966
David Ahern83c442512019-03-27 20:53:50 -07002967static bool fib6_is_reject(u32 flags, struct net_device *dev, int addr_type)
2968{
2969 if ((flags & RTF_REJECT) ||
2970 (dev && (dev->flags & IFF_LOOPBACK) &&
2971 !(addr_type & IPV6_ADDR_LOOPBACK) &&
2972 !(flags & RTF_LOCAL)))
2973 return true;
2974
2975 return false;
2976}
2977
2978int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
2979 struct fib6_config *cfg, gfp_t gfp_flags,
2980 struct netlink_ext_ack *extack)
2981{
2982 struct net_device *dev = NULL;
2983 struct inet6_dev *idev = NULL;
2984 int addr_type;
2985 int err;
2986
David Ahernf1741732019-03-27 20:53:57 -07002987 fib6_nh->fib_nh_family = AF_INET6;
2988
David Ahern83c442512019-03-27 20:53:50 -07002989 err = -ENODEV;
2990 if (cfg->fc_ifindex) {
2991 dev = dev_get_by_index(net, cfg->fc_ifindex);
2992 if (!dev)
2993 goto out;
2994 idev = in6_dev_get(dev);
2995 if (!idev)
2996 goto out;
2997 }
2998
2999 if (cfg->fc_flags & RTNH_F_ONLINK) {
3000 if (!dev) {
3001 NL_SET_ERR_MSG(extack,
3002 "Nexthop device required for onlink");
3003 goto out;
3004 }
3005
3006 if (!(dev->flags & IFF_UP)) {
3007 NL_SET_ERR_MSG(extack, "Nexthop device is not up");
3008 err = -ENETDOWN;
3009 goto out;
3010 }
3011
David Ahernad1601a2019-03-27 20:53:56 -07003012 fib6_nh->fib_nh_flags |= RTNH_F_ONLINK;
David Ahern83c442512019-03-27 20:53:50 -07003013 }
3014
David Ahernad1601a2019-03-27 20:53:56 -07003015 fib6_nh->fib_nh_weight = 1;
David Ahern83c442512019-03-27 20:53:50 -07003016
3017 /* We cannot add true routes via loopback here,
3018 * they would result in kernel looping; promote them to reject routes
3019 */
3020 addr_type = ipv6_addr_type(&cfg->fc_dst);
3021 if (fib6_is_reject(cfg->fc_flags, dev, addr_type)) {
3022 /* hold loopback dev/idev if we haven't done so. */
3023 if (dev != net->loopback_dev) {
3024 if (dev) {
3025 dev_put(dev);
3026 in6_dev_put(idev);
3027 }
3028 dev = net->loopback_dev;
3029 dev_hold(dev);
3030 idev = in6_dev_get(dev);
3031 if (!idev) {
3032 err = -ENODEV;
3033 goto out;
3034 }
3035 }
3036 goto set_dev;
3037 }
3038
3039 if (cfg->fc_flags & RTF_GATEWAY) {
3040 err = ip6_validate_gw(net, cfg, &dev, &idev, extack);
3041 if (err)
3042 goto out;
3043
David Ahernad1601a2019-03-27 20:53:56 -07003044 fib6_nh->fib_nh_gw6 = cfg->fc_gateway;
David Ahernbdf00462019-04-05 16:30:26 -07003045 fib6_nh->fib_nh_gw_family = AF_INET6;
David Ahern83c442512019-03-27 20:53:50 -07003046 }
3047
3048 err = -ENODEV;
3049 if (!dev)
3050 goto out;
3051
3052 if (idev->cnf.disable_ipv6) {
3053 NL_SET_ERR_MSG(extack, "IPv6 is disabled on nexthop device");
3054 err = -EACCES;
3055 goto out;
3056 }
3057
3058 if (!(dev->flags & IFF_UP) && !cfg->fc_ignore_dev_down) {
3059 NL_SET_ERR_MSG(extack, "Nexthop device is not up");
3060 err = -ENETDOWN;
3061 goto out;
3062 }
3063
3064 if (!(cfg->fc_flags & (RTF_LOCAL | RTF_ANYCAST)) &&
3065 !netif_carrier_ok(dev))
David Ahernad1601a2019-03-27 20:53:56 -07003066 fib6_nh->fib_nh_flags |= RTNH_F_LINKDOWN;
David Ahern83c442512019-03-27 20:53:50 -07003067
David Ahern979e2762019-03-27 20:53:58 -07003068 err = fib_nh_common_init(&fib6_nh->nh_common, cfg->fc_encap,
3069 cfg->fc_encap_type, cfg, gfp_flags, extack);
3070 if (err)
3071 goto out;
David Ahern83c442512019-03-27 20:53:50 -07003072set_dev:
David Ahernad1601a2019-03-27 20:53:56 -07003073 fib6_nh->fib_nh_dev = dev;
David Ahernf1741732019-03-27 20:53:57 -07003074 fib6_nh->fib_nh_oif = dev->ifindex;
David Ahern83c442512019-03-27 20:53:50 -07003075 err = 0;
3076out:
3077 if (idev)
3078 in6_dev_put(idev);
3079
3080 if (err) {
David Ahernad1601a2019-03-27 20:53:56 -07003081 lwtstate_put(fib6_nh->fib_nh_lws);
3082 fib6_nh->fib_nh_lws = NULL;
David Ahern83c442512019-03-27 20:53:50 -07003083 if (dev)
3084 dev_put(dev);
3085 }
3086
3087 return err;
3088}
3089
David Aherndac7d0f2019-03-27 20:53:51 -07003090void fib6_nh_release(struct fib6_nh *fib6_nh)
3091{
David Ahern979e2762019-03-27 20:53:58 -07003092 fib_nh_common_release(&fib6_nh->nh_common);
David Aherndac7d0f2019-03-27 20:53:51 -07003093}
3094
David Ahern8d1c8022018-04-17 17:33:26 -07003095static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
David Ahernacb54e32018-04-17 17:33:22 -07003096 gfp_t gfp_flags,
David Ahern333c4302017-05-21 10:12:04 -06003097 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098{
Daniel Lezcano55786892008-03-04 13:47:47 -08003099 struct net *net = cfg->fc_nlinfo.nl_net;
David Ahern8d1c8022018-04-17 17:33:26 -07003100 struct fib6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07003101 struct fib6_table *table;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003102 int err = -EINVAL;
David Ahern83c442512019-03-27 20:53:50 -07003103 int addr_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104
David Ahern557c44b2017-04-19 14:19:43 -07003105 /* RTF_PCPU is an internal flag; can not be set by userspace */
David Ahernd5d531c2017-05-21 10:12:05 -06003106 if (cfg->fc_flags & RTF_PCPU) {
3107 NL_SET_ERR_MSG(extack, "Userspace can not set RTF_PCPU");
David Ahern557c44b2017-04-19 14:19:43 -07003108 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06003109 }
David Ahern557c44b2017-04-19 14:19:43 -07003110
Wei Wang2ea23522017-10-27 17:30:12 -07003111 /* RTF_CACHE is an internal flag; can not be set by userspace */
3112 if (cfg->fc_flags & RTF_CACHE) {
3113 NL_SET_ERR_MSG(extack, "Userspace can not set RTF_CACHE");
3114 goto out;
3115 }
3116
David Aherne8478e82018-04-17 17:33:13 -07003117 if (cfg->fc_type > RTN_MAX) {
3118 NL_SET_ERR_MSG(extack, "Invalid route type");
3119 goto out;
3120 }
3121
David Ahernd5d531c2017-05-21 10:12:05 -06003122 if (cfg->fc_dst_len > 128) {
3123 NL_SET_ERR_MSG(extack, "Invalid prefix length");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003124 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06003125 }
3126 if (cfg->fc_src_len > 128) {
3127 NL_SET_ERR_MSG(extack, "Invalid source address length");
3128 goto out;
3129 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130#ifndef CONFIG_IPV6_SUBTREES
David Ahernd5d531c2017-05-21 10:12:05 -06003131 if (cfg->fc_src_len) {
3132 NL_SET_ERR_MSG(extack,
3133 "Specifying source address requires IPV6_SUBTREES to be enabled");
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003134 goto out;
David Ahernd5d531c2017-05-21 10:12:05 -06003135 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136#endif
David Ahernfc1e64e2018-01-25 16:55:09 -08003137
Matti Vaittinend71314b2011-11-14 00:14:49 +00003138 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05003139 if (cfg->fc_nlinfo.nlh &&
3140 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
Matti Vaittinend71314b2011-11-14 00:14:49 +00003141 table = fib6_get_table(net, cfg->fc_table);
David S. Miller38308472011-12-03 18:02:47 -05003142 if (!table) {
Joe Perchesf3213832012-05-15 14:11:53 +00003143 pr_warn("NLM_F_CREATE should be specified when creating new route\n");
Matti Vaittinend71314b2011-11-14 00:14:49 +00003144 table = fib6_new_table(net, cfg->fc_table);
3145 }
3146 } else {
3147 table = fib6_new_table(net, cfg->fc_table);
3148 }
David S. Miller38308472011-12-03 18:02:47 -05003149
3150 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07003151 goto out;
Thomas Grafc71099a2006-08-04 23:20:06 -07003152
David Ahern93531c62018-04-17 17:33:25 -07003153 err = -ENOMEM;
3154 rt = fib6_info_alloc(gfp_flags);
3155 if (!rt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 goto out;
David Ahern93531c62018-04-17 17:33:25 -07003157
David Ahernd7e774f2018-11-06 12:51:15 -08003158 rt->fib6_metrics = ip_fib_metrics_init(net, cfg->fc_mx, cfg->fc_mx_len,
3159 extack);
David Ahern767a2212018-10-04 20:07:51 -07003160 if (IS_ERR(rt->fib6_metrics)) {
3161 err = PTR_ERR(rt->fib6_metrics);
Eric Dumazetfda21d42018-10-05 09:17:50 -07003162 /* Do not leave garbage there. */
3163 rt->fib6_metrics = (struct dst_metrics *)&dst_default_metrics;
David Ahern767a2212018-10-04 20:07:51 -07003164 goto out;
3165 }
3166
David Ahern93531c62018-04-17 17:33:25 -07003167 if (cfg->fc_flags & RTF_ADDRCONF)
3168 rt->dst_nocount = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169
Gao feng1716a962012-04-06 00:13:10 +00003170 if (cfg->fc_flags & RTF_EXPIRES)
David Ahern14895682018-04-17 17:33:17 -07003171 fib6_set_expires(rt, jiffies +
Gao feng1716a962012-04-06 00:13:10 +00003172 clock_t_to_jiffies(cfg->fc_expires));
3173 else
David Ahern14895682018-04-17 17:33:17 -07003174 fib6_clean_expires(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175
Thomas Graf86872cb2006-08-22 00:01:08 -07003176 if (cfg->fc_protocol == RTPROT_UNSPEC)
3177 cfg->fc_protocol = RTPROT_BOOT;
David Ahern93c2fb22018-04-18 15:38:59 -07003178 rt->fib6_protocol = cfg->fc_protocol;
Thomas Graf86872cb2006-08-22 00:01:08 -07003179
David Ahern83c442512019-03-27 20:53:50 -07003180 rt->fib6_table = table;
3181 rt->fib6_metric = cfg->fc_metric;
3182 rt->fib6_type = cfg->fc_type;
David Ahern2b2450c2019-03-27 20:53:52 -07003183 rt->fib6_flags = cfg->fc_flags & ~RTF_GATEWAY;
Roopa Prabhu19e42e42015-07-21 10:43:48 +02003184
David Ahern93c2fb22018-04-18 15:38:59 -07003185 ipv6_addr_prefix(&rt->fib6_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
3186 rt->fib6_dst.plen = cfg->fc_dst_len;
3187 if (rt->fib6_dst.plen == 128)
David Ahern3b6761d2018-04-17 17:33:20 -07003188 rt->dst_host = true;
Michal Kubečeke5fd3872014-03-27 13:04:08 +01003189
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190#ifdef CONFIG_IPV6_SUBTREES
David Ahern93c2fb22018-04-18 15:38:59 -07003191 ipv6_addr_prefix(&rt->fib6_src.addr, &cfg->fc_src, cfg->fc_src_len);
3192 rt->fib6_src.plen = cfg->fc_src_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193#endif
David Ahern83c442512019-03-27 20:53:50 -07003194 err = fib6_nh_init(net, &rt->fib6_nh, cfg, gfp_flags, extack);
3195 if (err)
3196 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197
3198 /* We cannot add true routes via loopback here,
David Ahern83c442512019-03-27 20:53:50 -07003199 * they would result in kernel looping; promote them to reject routes
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 */
David Ahern83c442512019-03-27 20:53:50 -07003201 addr_type = ipv6_addr_type(&cfg->fc_dst);
David Ahernad1601a2019-03-27 20:53:56 -07003202 if (fib6_is_reject(cfg->fc_flags, rt->fib6_nh.fib_nh_dev, addr_type))
David Ahern83c442512019-03-27 20:53:50 -07003203 rt->fib6_flags = RTF_REJECT | RTF_NONEXTHOP;
David Ahern955ec4c2018-01-24 19:45:29 -08003204
Daniel Walterc3968a82011-04-13 21:10:57 +00003205 if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
David Ahern83c442512019-03-27 20:53:50 -07003206 struct net_device *dev = fib6_info_nh_dev(rt);
3207
Daniel Walterc3968a82011-04-13 21:10:57 +00003208 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
David Ahernd5d531c2017-05-21 10:12:05 -06003209 NL_SET_ERR_MSG(extack, "Invalid source address");
Daniel Walterc3968a82011-04-13 21:10:57 +00003210 err = -EINVAL;
3211 goto out;
3212 }
David Ahern93c2fb22018-04-18 15:38:59 -07003213 rt->fib6_prefsrc.addr = cfg->fc_prefsrc;
3214 rt->fib6_prefsrc.plen = 128;
Daniel Walterc3968a82011-04-13 21:10:57 +00003215 } else
David Ahern93c2fb22018-04-18 15:38:59 -07003216 rt->fib6_prefsrc.plen = 0;
Daniel Walterc3968a82011-04-13 21:10:57 +00003217
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003218 return rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219out:
David Ahern93531c62018-04-17 17:33:25 -07003220 fib6_info_release(rt);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07003221 return ERR_PTR(err);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003222}
3223
David Ahernacb54e32018-04-17 17:33:22 -07003224int ip6_route_add(struct fib6_config *cfg, gfp_t gfp_flags,
David Ahern333c4302017-05-21 10:12:04 -06003225 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003226{
David Ahern8d1c8022018-04-17 17:33:26 -07003227 struct fib6_info *rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003228 int err;
3229
David Ahernacb54e32018-04-17 17:33:22 -07003230 rt = ip6_route_info_create(cfg, gfp_flags, extack);
David Ahernd4ead6b2018-04-17 17:33:16 -07003231 if (IS_ERR(rt))
3232 return PTR_ERR(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003233
David Ahernd4ead6b2018-04-17 17:33:16 -07003234 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack);
David Ahern93531c62018-04-17 17:33:25 -07003235 fib6_info_release(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07003236
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 return err;
3238}
3239
David Ahern8d1c8022018-04-17 17:33:26 -07003240static int __ip6_del_rt(struct fib6_info *rt, struct nl_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241{
David Ahernafb1d4b52018-04-17 17:33:11 -07003242 struct net *net = info->nl_net;
Thomas Grafc71099a2006-08-04 23:20:06 -07003243 struct fib6_table *table;
David Ahernafb1d4b52018-04-17 17:33:11 -07003244 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245
David Ahern421842e2018-04-17 17:33:18 -07003246 if (rt == net->ipv6.fib6_null_entry) {
Gao feng6825a262012-09-19 19:25:34 +00003247 err = -ENOENT;
3248 goto out;
3249 }
Patrick McHardy6c813a72006-08-06 22:22:47 -07003250
David Ahern93c2fb22018-04-18 15:38:59 -07003251 table = rt->fib6_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003252 spin_lock_bh(&table->tb6_lock);
Thomas Graf86872cb2006-08-22 00:01:08 -07003253 err = fib6_del(rt, info);
Wei Wang66f5d6c2017-10-06 12:06:10 -07003254 spin_unlock_bh(&table->tb6_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255
Gao feng6825a262012-09-19 19:25:34 +00003256out:
David Ahern93531c62018-04-17 17:33:25 -07003257 fib6_info_release(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 return err;
3259}
3260
David Ahern8d1c8022018-04-17 17:33:26 -07003261int ip6_del_rt(struct net *net, struct fib6_info *rt)
Thomas Grafe0a1ad732006-08-22 00:00:21 -07003262{
David Ahernafb1d4b52018-04-17 17:33:11 -07003263 struct nl_info info = { .nl_net = net };
3264
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08003265 return __ip6_del_rt(rt, &info);
Thomas Grafe0a1ad732006-08-22 00:00:21 -07003266}
3267
David Ahern8d1c8022018-04-17 17:33:26 -07003268static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg)
David Ahern0ae81332017-02-02 12:37:08 -08003269{
3270 struct nl_info *info = &cfg->fc_nlinfo;
WANG Conge3330032017-02-27 16:07:43 -08003271 struct net *net = info->nl_net;
David Ahern16a16cd2017-02-02 12:37:11 -08003272 struct sk_buff *skb = NULL;
David Ahern0ae81332017-02-02 12:37:08 -08003273 struct fib6_table *table;
WANG Conge3330032017-02-27 16:07:43 -08003274 int err = -ENOENT;
David Ahern0ae81332017-02-02 12:37:08 -08003275
David Ahern421842e2018-04-17 17:33:18 -07003276 if (rt == net->ipv6.fib6_null_entry)
WANG Conge3330032017-02-27 16:07:43 -08003277 goto out_put;
David Ahern93c2fb22018-04-18 15:38:59 -07003278 table = rt->fib6_table;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003279 spin_lock_bh(&table->tb6_lock);
David Ahern0ae81332017-02-02 12:37:08 -08003280
David Ahern93c2fb22018-04-18 15:38:59 -07003281 if (rt->fib6_nsiblings && cfg->fc_delete_all_nh) {
David Ahern8d1c8022018-04-17 17:33:26 -07003282 struct fib6_info *sibling, *next_sibling;
David Ahern0ae81332017-02-02 12:37:08 -08003283
David Ahern16a16cd2017-02-02 12:37:11 -08003284 /* prefer to send a single notification with all hops */
3285 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
3286 if (skb) {
3287 u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
3288
David Ahernd4ead6b2018-04-17 17:33:16 -07003289 if (rt6_fill_node(net, skb, rt, NULL,
David Ahern16a16cd2017-02-02 12:37:11 -08003290 NULL, NULL, 0, RTM_DELROUTE,
3291 info->portid, seq, 0) < 0) {
3292 kfree_skb(skb);
3293 skb = NULL;
3294 } else
3295 info->skip_notify = 1;
3296 }
3297
David Ahern0ae81332017-02-02 12:37:08 -08003298 list_for_each_entry_safe(sibling, next_sibling,
David Ahern93c2fb22018-04-18 15:38:59 -07003299 &rt->fib6_siblings,
3300 fib6_siblings) {
David Ahern0ae81332017-02-02 12:37:08 -08003301 err = fib6_del(sibling, info);
3302 if (err)
WANG Conge3330032017-02-27 16:07:43 -08003303 goto out_unlock;
David Ahern0ae81332017-02-02 12:37:08 -08003304 }
3305 }
3306
3307 err = fib6_del(rt, info);
WANG Conge3330032017-02-27 16:07:43 -08003308out_unlock:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003309 spin_unlock_bh(&table->tb6_lock);
WANG Conge3330032017-02-27 16:07:43 -08003310out_put:
David Ahern93531c62018-04-17 17:33:25 -07003311 fib6_info_release(rt);
David Ahern16a16cd2017-02-02 12:37:11 -08003312
3313 if (skb) {
WANG Conge3330032017-02-27 16:07:43 -08003314 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
David Ahern16a16cd2017-02-02 12:37:11 -08003315 info->nlh, gfp_any());
3316 }
David Ahern0ae81332017-02-02 12:37:08 -08003317 return err;
3318}
3319
David Ahern23fb93a2018-04-17 17:33:23 -07003320static int ip6_del_cached_rt(struct rt6_info *rt, struct fib6_config *cfg)
3321{
3322 int rc = -ESRCH;
3323
3324 if (cfg->fc_ifindex && rt->dst.dev->ifindex != cfg->fc_ifindex)
3325 goto out;
3326
3327 if (cfg->fc_flags & RTF_GATEWAY &&
3328 !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
3329 goto out;
Xin Long761f6022018-11-14 00:48:28 +08003330
3331 rc = rt6_remove_exception_rt(rt);
David Ahern23fb93a2018-04-17 17:33:23 -07003332out:
3333 return rc;
3334}
3335
David Ahern333c4302017-05-21 10:12:04 -06003336static int ip6_route_del(struct fib6_config *cfg,
3337 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338{
David Ahern8d1c8022018-04-17 17:33:26 -07003339 struct rt6_info *rt_cache;
Thomas Grafc71099a2006-08-04 23:20:06 -07003340 struct fib6_table *table;
David Ahern8d1c8022018-04-17 17:33:26 -07003341 struct fib6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 struct fib6_node *fn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 int err = -ESRCH;
3344
Daniel Lezcano55786892008-03-04 13:47:47 -08003345 table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
David Ahernd5d531c2017-05-21 10:12:05 -06003346 if (!table) {
3347 NL_SET_ERR_MSG(extack, "FIB table does not exist");
Thomas Grafc71099a2006-08-04 23:20:06 -07003348 return err;
David Ahernd5d531c2017-05-21 10:12:05 -06003349 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350
Wei Wang66f5d6c2017-10-06 12:06:10 -07003351 rcu_read_lock();
Thomas Grafc71099a2006-08-04 23:20:06 -07003352
3353 fn = fib6_locate(&table->tb6_root,
Thomas Graf86872cb2006-08-22 00:01:08 -07003354 &cfg->fc_dst, cfg->fc_dst_len,
Wei Wang38fbeee2017-10-06 12:06:02 -07003355 &cfg->fc_src, cfg->fc_src_len,
Wei Wang2b760fc2017-10-06 12:06:03 -07003356 !(cfg->fc_flags & RTF_CACHE));
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003357
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 if (fn) {
Wei Wang66f5d6c2017-10-06 12:06:10 -07003359 for_each_fib6_node_rt_rcu(fn) {
David Ahernad1601a2019-03-27 20:53:56 -07003360 struct fib6_nh *nh;
3361
Wei Wang2b760fc2017-10-06 12:06:03 -07003362 if (cfg->fc_flags & RTF_CACHE) {
David Ahern7e4b5122019-04-16 14:36:00 -07003363 struct fib6_result res = {
3364 .f6i = rt,
3365 };
David Ahern23fb93a2018-04-17 17:33:23 -07003366 int rc;
3367
David Ahern7e4b5122019-04-16 14:36:00 -07003368 rt_cache = rt6_find_cached_rt(&res,
3369 &cfg->fc_dst,
Wei Wang2b760fc2017-10-06 12:06:03 -07003370 &cfg->fc_src);
David Ahern23fb93a2018-04-17 17:33:23 -07003371 if (rt_cache) {
3372 rc = ip6_del_cached_rt(rt_cache, cfg);
Eric Dumazet9e575012018-05-09 10:05:46 -07003373 if (rc != -ESRCH) {
3374 rcu_read_unlock();
David Ahern23fb93a2018-04-17 17:33:23 -07003375 return rc;
Eric Dumazet9e575012018-05-09 10:05:46 -07003376 }
David Ahern23fb93a2018-04-17 17:33:23 -07003377 }
3378 continue;
Wei Wang2b760fc2017-10-06 12:06:03 -07003379 }
David Ahernad1601a2019-03-27 20:53:56 -07003380
3381 nh = &rt->fib6_nh;
Thomas Graf86872cb2006-08-22 00:01:08 -07003382 if (cfg->fc_ifindex &&
David Ahernad1601a2019-03-27 20:53:56 -07003383 (!nh->fib_nh_dev ||
3384 nh->fib_nh_dev->ifindex != cfg->fc_ifindex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 continue;
Thomas Graf86872cb2006-08-22 00:01:08 -07003386 if (cfg->fc_flags & RTF_GATEWAY &&
David Ahernad1601a2019-03-27 20:53:56 -07003387 !ipv6_addr_equal(&cfg->fc_gateway, &nh->fib_nh_gw6))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07003389 if (cfg->fc_metric && cfg->fc_metric != rt->fib6_metric)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390 continue;
David Ahern93c2fb22018-04-18 15:38:59 -07003391 if (cfg->fc_protocol && cfg->fc_protocol != rt->fib6_protocol)
Mantas Mc2ed1882016-12-16 10:30:59 +02003392 continue;
Wei Wange873e4b2018-07-21 20:56:32 -07003393 if (!fib6_info_hold_safe(rt))
3394 continue;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003395 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396
David Ahern0ae81332017-02-02 12:37:08 -08003397 /* if gateway was specified only delete the one hop */
3398 if (cfg->fc_flags & RTF_GATEWAY)
3399 return __ip6_del_rt(rt, &cfg->fc_nlinfo);
3400
3401 return __ip6_del_rt_siblings(rt, cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 }
3403 }
Wei Wang66f5d6c2017-10-06 12:06:10 -07003404 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405
3406 return err;
3407}
3408
David S. Miller6700c272012-07-17 03:29:28 -07003409static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07003410{
YOSHIFUJI Hideakia6279452006-08-23 17:18:26 -07003411 struct netevent_redirect netevent;
David S. Millere8599ff2012-07-11 23:43:53 -07003412 struct rt6_info *rt, *nrt = NULL;
David Ahern85bd05d2019-04-16 14:36:01 -07003413 struct fib6_result res = {};
David S. Millere8599ff2012-07-11 23:43:53 -07003414 struct ndisc_options ndopts;
3415 struct inet6_dev *in6_dev;
3416 struct neighbour *neigh;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003417 struct rd_msg *msg;
David S. Miller6e157b62012-07-12 00:05:02 -07003418 int optlen, on_link;
3419 u8 *lladdr;
David S. Millere8599ff2012-07-11 23:43:53 -07003420
Simon Horman29a3cad2013-05-28 20:34:26 +00003421 optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003422 optlen -= sizeof(*msg);
David S. Millere8599ff2012-07-11 23:43:53 -07003423
3424 if (optlen < 0) {
David S. Miller6e157b62012-07-12 00:05:02 -07003425 net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003426 return;
3427 }
3428
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003429 msg = (struct rd_msg *)icmp6_hdr(skb);
David S. Millere8599ff2012-07-11 23:43:53 -07003430
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003431 if (ipv6_addr_is_multicast(&msg->dest)) {
David S. Miller6e157b62012-07-12 00:05:02 -07003432 net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003433 return;
3434 }
3435
David S. Miller6e157b62012-07-12 00:05:02 -07003436 on_link = 0;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003437 if (ipv6_addr_equal(&msg->dest, &msg->target)) {
David S. Millere8599ff2012-07-11 23:43:53 -07003438 on_link = 1;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003439 } else if (ipv6_addr_type(&msg->target) !=
David S. Millere8599ff2012-07-11 23:43:53 -07003440 (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
David S. Miller6e157b62012-07-12 00:05:02 -07003441 net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
David S. Millere8599ff2012-07-11 23:43:53 -07003442 return;
3443 }
3444
3445 in6_dev = __in6_dev_get(skb->dev);
3446 if (!in6_dev)
3447 return;
3448 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
3449 return;
3450
3451 /* RFC2461 8.1:
3452 * The IP source address of the Redirect MUST be the same as the current
3453 * first-hop router for the specified ICMP Destination Address.
3454 */
3455
Alexander Aringf997c552016-06-15 21:20:23 +02003456 if (!ndisc_parse_options(skb->dev, msg->opt, optlen, &ndopts)) {
David S. Millere8599ff2012-07-11 23:43:53 -07003457 net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
3458 return;
3459 }
David S. Miller6e157b62012-07-12 00:05:02 -07003460
3461 lladdr = NULL;
David S. Millere8599ff2012-07-11 23:43:53 -07003462 if (ndopts.nd_opts_tgt_lladdr) {
3463 lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
3464 skb->dev);
3465 if (!lladdr) {
3466 net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
3467 return;
3468 }
3469 }
3470
David S. Miller6e157b62012-07-12 00:05:02 -07003471 rt = (struct rt6_info *) dst;
Matthias Schifferec13ad12015-11-02 01:24:38 +01003472 if (rt->rt6i_flags & RTF_REJECT) {
David S. Miller6e157b62012-07-12 00:05:02 -07003473 net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
3474 return;
3475 }
3476
3477 /* Redirect received -> path was valid.
3478 * Look, redirects are sent only in response to data packets,
3479 * so that this nexthop apparently is reachable. --ANK
3480 */
Julian Anastasov0dec8792017-02-06 23:14:16 +02003481 dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
David S. Miller6e157b62012-07-12 00:05:02 -07003482
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003483 neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
David S. Millere8599ff2012-07-11 23:43:53 -07003484 if (!neigh)
3485 return;
3486
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 /*
3488 * We have finally decided to accept it.
3489 */
3490
Alexander Aringf997c552016-06-15 21:20:23 +02003491 ndisc_update(skb->dev, neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492 NEIGH_UPDATE_F_WEAK_OVERRIDE|
3493 NEIGH_UPDATE_F_OVERRIDE|
3494 (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
Alexander Aringf997c552016-06-15 21:20:23 +02003495 NEIGH_UPDATE_F_ISROUTER)),
3496 NDISC_REDIRECT, &ndopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497
David Ahern4d85cd02018-04-20 15:37:59 -07003498 rcu_read_lock();
David Ahern85bd05d2019-04-16 14:36:01 -07003499 res.f6i = rcu_dereference(rt->from);
David S. Millerff24e492019-05-02 22:14:21 -04003500 if (!res.f6i)
Martin KaFai Lau886b7a52019-04-30 10:45:12 -07003501 goto out;
David Ahern8a14e462018-04-23 11:32:07 -07003502
David Ahern85bd05d2019-04-16 14:36:01 -07003503 res.nh = &res.f6i->fib6_nh;
David Ahern7d21fec2019-04-16 14:36:11 -07003504 res.fib6_flags = res.f6i->fib6_flags;
3505 res.fib6_type = res.f6i->fib6_type;
David Ahern85bd05d2019-04-16 14:36:01 -07003506 nrt = ip6_rt_cache_alloc(&res, &msg->dest, NULL);
David S. Miller38308472011-12-03 18:02:47 -05003507 if (!nrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508 goto out;
3509
3510 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
3511 if (on_link)
3512 nrt->rt6i_flags &= ~RTF_GATEWAY;
3513
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003514 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515
Martin KaFai Lau886b7a52019-04-30 10:45:12 -07003516 /* rt6_insert_exception() will take care of duplicated exceptions */
David Ahern5012f0a2019-04-16 14:36:05 -07003517 if (rt6_insert_exception(nrt, &res)) {
Wei Wang2b760fc2017-10-06 12:06:03 -07003518 dst_release_immediate(&nrt->dst);
3519 goto out;
3520 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521
Changli Gaod8d1f302010-06-10 23:31:35 -07003522 netevent.old = &rt->dst;
3523 netevent.new = &nrt->dst;
YOSHIFUJI Hideaki / 吉藤英明71bcdba2013-01-05 16:34:51 +00003524 netevent.daddr = &msg->dest;
YOSHIFUJI Hideaki / 吉藤英明60592832013-01-14 09:28:27 +00003525 netevent.neigh = neigh;
Tom Tucker8d717402006-07-30 20:43:36 -07003526 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
3527
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528out:
Martin KaFai Lau886b7a52019-04-30 10:45:12 -07003529 rcu_read_unlock();
David S. Millere8599ff2012-07-11 23:43:53 -07003530 neigh_release(neigh);
David S. Miller6e157b62012-07-12 00:05:02 -07003531}
3532
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003533#ifdef CONFIG_IPV6_ROUTE_INFO
David Ahern8d1c8022018-04-17 17:33:26 -07003534static struct fib6_info *rt6_get_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00003535 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07003536 const struct in6_addr *gwaddr,
3537 struct net_device *dev)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003538{
David Ahern830218c2016-10-24 10:52:35 -07003539 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO;
3540 int ifindex = dev->ifindex;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003541 struct fib6_node *fn;
David Ahern8d1c8022018-04-17 17:33:26 -07003542 struct fib6_info *rt = NULL;
Thomas Grafc71099a2006-08-04 23:20:06 -07003543 struct fib6_table *table;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003544
David Ahern830218c2016-10-24 10:52:35 -07003545 table = fib6_get_table(net, tb_id);
David S. Miller38308472011-12-03 18:02:47 -05003546 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07003547 return NULL;
3548
Wei Wang66f5d6c2017-10-06 12:06:10 -07003549 rcu_read_lock();
Wei Wang38fbeee2017-10-06 12:06:02 -07003550 fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0, true);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003551 if (!fn)
3552 goto out;
3553
Wei Wang66f5d6c2017-10-06 12:06:10 -07003554 for_each_fib6_node_rt_rcu(fn) {
David Ahernad1601a2019-03-27 20:53:56 -07003555 if (rt->fib6_nh.fib_nh_dev->ifindex != ifindex)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003556 continue;
David Ahern2b2450c2019-03-27 20:53:52 -07003557 if (!(rt->fib6_flags & RTF_ROUTEINFO) ||
David Ahernbdf00462019-04-05 16:30:26 -07003558 !rt->fib6_nh.fib_nh_gw_family)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003559 continue;
David Ahernad1601a2019-03-27 20:53:56 -07003560 if (!ipv6_addr_equal(&rt->fib6_nh.fib_nh_gw6, gwaddr))
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003561 continue;
Wei Wange873e4b2018-07-21 20:56:32 -07003562 if (!fib6_info_hold_safe(rt))
3563 continue;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003564 break;
3565 }
3566out:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003567 rcu_read_unlock();
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003568 return rt;
3569}
3570
David Ahern8d1c8022018-04-17 17:33:26 -07003571static struct fib6_info *rt6_add_route_info(struct net *net,
Eric Dumazetb71d1d42011-04-22 04:53:02 +00003572 const struct in6_addr *prefix, int prefixlen,
David Ahern830218c2016-10-24 10:52:35 -07003573 const struct in6_addr *gwaddr,
3574 struct net_device *dev,
Eric Dumazet95c96172012-04-15 05:58:06 +00003575 unsigned int pref)
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003576{
Thomas Graf86872cb2006-08-22 00:01:08 -07003577 struct fib6_config cfg = {
Rami Rosen238fc7e2008-02-09 23:43:11 -08003578 .fc_metric = IP6_RT_PRIO_USER,
David Ahern830218c2016-10-24 10:52:35 -07003579 .fc_ifindex = dev->ifindex,
Thomas Graf86872cb2006-08-22 00:01:08 -07003580 .fc_dst_len = prefixlen,
3581 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
3582 RTF_UP | RTF_PREF(pref),
Xin Longb91d5322017-08-03 14:13:46 +08003583 .fc_protocol = RTPROT_RA,
David Aherne8478e82018-04-17 17:33:13 -07003584 .fc_type = RTN_UNICAST,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003585 .fc_nlinfo.portid = 0,
Daniel Lezcanoefa2cea2008-03-04 13:46:48 -08003586 .fc_nlinfo.nlh = NULL,
3587 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07003588 };
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003589
David Ahern830218c2016-10-24 10:52:35 -07003590 cfg.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO,
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003591 cfg.fc_dst = *prefix;
3592 cfg.fc_gateway = *gwaddr;
Thomas Graf86872cb2006-08-22 00:01:08 -07003593
YOSHIFUJI Hideakie317da92006-03-20 17:06:42 -08003594 /* We should treat it as a default route if prefix length is 0. */
3595 if (!prefixlen)
Thomas Graf86872cb2006-08-22 00:01:08 -07003596 cfg.fc_flags |= RTF_DEFAULT;
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003597
David Ahernacb54e32018-04-17 17:33:22 -07003598 ip6_route_add(&cfg, GFP_ATOMIC, NULL);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003599
David Ahern830218c2016-10-24 10:52:35 -07003600 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, dev);
YOSHIFUJI Hideaki70ceb4f2006-03-20 17:06:24 -08003601}
3602#endif
3603
David Ahern8d1c8022018-04-17 17:33:26 -07003604struct fib6_info *rt6_get_dflt_router(struct net *net,
David Ahernafb1d4b52018-04-17 17:33:11 -07003605 const struct in6_addr *addr,
3606 struct net_device *dev)
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003607{
David Ahern830218c2016-10-24 10:52:35 -07003608 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT;
David Ahern8d1c8022018-04-17 17:33:26 -07003609 struct fib6_info *rt;
Thomas Grafc71099a2006-08-04 23:20:06 -07003610 struct fib6_table *table;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611
David Ahernafb1d4b52018-04-17 17:33:11 -07003612 table = fib6_get_table(net, tb_id);
David S. Miller38308472011-12-03 18:02:47 -05003613 if (!table)
Thomas Grafc71099a2006-08-04 23:20:06 -07003614 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615
Wei Wang66f5d6c2017-10-06 12:06:10 -07003616 rcu_read_lock();
3617 for_each_fib6_node_rt_rcu(&table->tb6_root) {
David Ahernad1601a2019-03-27 20:53:56 -07003618 struct fib6_nh *nh = &rt->fib6_nh;
3619
3620 if (dev == nh->fib_nh_dev &&
David Ahern93c2fb22018-04-18 15:38:59 -07003621 ((rt->fib6_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
David Ahernad1601a2019-03-27 20:53:56 -07003622 ipv6_addr_equal(&nh->fib_nh_gw6, addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623 break;
3624 }
Wei Wange873e4b2018-07-21 20:56:32 -07003625 if (rt && !fib6_info_hold_safe(rt))
3626 rt = NULL;
Wei Wang66f5d6c2017-10-06 12:06:10 -07003627 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 return rt;
3629}
3630
David Ahern8d1c8022018-04-17 17:33:26 -07003631struct fib6_info *rt6_add_dflt_router(struct net *net,
David Ahernafb1d4b52018-04-17 17:33:11 -07003632 const struct in6_addr *gwaddr,
YOSHIFUJI Hideakiebacaaa2006-03-20 17:04:53 -08003633 struct net_device *dev,
3634 unsigned int pref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635{
Thomas Graf86872cb2006-08-22 00:01:08 -07003636 struct fib6_config cfg = {
David Ahernca254492015-10-12 11:47:10 -07003637 .fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT,
Rami Rosen238fc7e2008-02-09 23:43:11 -08003638 .fc_metric = IP6_RT_PRIO_USER,
Thomas Graf86872cb2006-08-22 00:01:08 -07003639 .fc_ifindex = dev->ifindex,
3640 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
3641 RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
Xin Longb91d5322017-08-03 14:13:46 +08003642 .fc_protocol = RTPROT_RA,
David Aherne8478e82018-04-17 17:33:13 -07003643 .fc_type = RTN_UNICAST,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003644 .fc_nlinfo.portid = 0,
Daniel Lezcano55786892008-03-04 13:47:47 -08003645 .fc_nlinfo.nlh = NULL,
David Ahernafb1d4b52018-04-17 17:33:11 -07003646 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07003647 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003649 cfg.fc_gateway = *gwaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650
David Ahernacb54e32018-04-17 17:33:22 -07003651 if (!ip6_route_add(&cfg, GFP_ATOMIC, NULL)) {
David Ahern830218c2016-10-24 10:52:35 -07003652 struct fib6_table *table;
3653
3654 table = fib6_get_table(dev_net(dev), cfg.fc_table);
3655 if (table)
3656 table->flags |= RT6_TABLE_HAS_DFLT_ROUTER;
3657 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658
David Ahernafb1d4b52018-04-17 17:33:11 -07003659 return rt6_get_dflt_router(net, gwaddr, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660}
3661
David Ahernafb1d4b52018-04-17 17:33:11 -07003662static void __rt6_purge_dflt_routers(struct net *net,
3663 struct fib6_table *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664{
David Ahern8d1c8022018-04-17 17:33:26 -07003665 struct fib6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666
3667restart:
Wei Wang66f5d6c2017-10-06 12:06:10 -07003668 rcu_read_lock();
3669 for_each_fib6_node_rt_rcu(&table->tb6_root) {
David Aherndcd1f572018-04-18 15:39:05 -07003670 struct net_device *dev = fib6_info_nh_dev(rt);
3671 struct inet6_dev *idev = dev ? __in6_dev_get(dev) : NULL;
3672
David Ahern93c2fb22018-04-18 15:38:59 -07003673 if (rt->fib6_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
Wei Wange873e4b2018-07-21 20:56:32 -07003674 (!idev || idev->cnf.accept_ra != 2) &&
3675 fib6_info_hold_safe(rt)) {
David Ahern93531c62018-04-17 17:33:25 -07003676 rcu_read_unlock();
3677 ip6_del_rt(net, rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678 goto restart;
3679 }
3680 }
Wei Wang66f5d6c2017-10-06 12:06:10 -07003681 rcu_read_unlock();
David Ahern830218c2016-10-24 10:52:35 -07003682
3683 table->flags &= ~RT6_TABLE_HAS_DFLT_ROUTER;
3684}
3685
3686void rt6_purge_dflt_routers(struct net *net)
3687{
3688 struct fib6_table *table;
3689 struct hlist_head *head;
3690 unsigned int h;
3691
3692 rcu_read_lock();
3693
3694 for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
3695 head = &net->ipv6.fib_table_hash[h];
3696 hlist_for_each_entry_rcu(table, head, tb6_hlist) {
3697 if (table->flags & RT6_TABLE_HAS_DFLT_ROUTER)
David Ahernafb1d4b52018-04-17 17:33:11 -07003698 __rt6_purge_dflt_routers(net, table);
David Ahern830218c2016-10-24 10:52:35 -07003699 }
3700 }
3701
3702 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703}
3704
Daniel Lezcano55786892008-03-04 13:47:47 -08003705static void rtmsg_to_fib6_config(struct net *net,
3706 struct in6_rtmsg *rtmsg,
Thomas Graf86872cb2006-08-22 00:01:08 -07003707 struct fib6_config *cfg)
3708{
Maciej Żenczykowski8823a3a2018-09-29 23:44:52 -07003709 *cfg = (struct fib6_config){
3710 .fc_table = l3mdev_fib_table_by_index(net, rtmsg->rtmsg_ifindex) ?
3711 : RT6_TABLE_MAIN,
3712 .fc_ifindex = rtmsg->rtmsg_ifindex,
David Ahern67f69512019-03-21 05:21:34 -07003713 .fc_metric = rtmsg->rtmsg_metric ? : IP6_RT_PRIO_USER,
Maciej Żenczykowski8823a3a2018-09-29 23:44:52 -07003714 .fc_expires = rtmsg->rtmsg_info,
3715 .fc_dst_len = rtmsg->rtmsg_dst_len,
3716 .fc_src_len = rtmsg->rtmsg_src_len,
3717 .fc_flags = rtmsg->rtmsg_flags,
3718 .fc_type = rtmsg->rtmsg_type,
Thomas Graf86872cb2006-08-22 00:01:08 -07003719
Maciej Żenczykowski8823a3a2018-09-29 23:44:52 -07003720 .fc_nlinfo.nl_net = net,
Thomas Graf86872cb2006-08-22 00:01:08 -07003721
Maciej Żenczykowski8823a3a2018-09-29 23:44:52 -07003722 .fc_dst = rtmsg->rtmsg_dst,
3723 .fc_src = rtmsg->rtmsg_src,
3724 .fc_gateway = rtmsg->rtmsg_gateway,
3725 };
Thomas Graf86872cb2006-08-22 00:01:08 -07003726}
3727
Daniel Lezcano55786892008-03-04 13:47:47 -08003728int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729{
Thomas Graf86872cb2006-08-22 00:01:08 -07003730 struct fib6_config cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731 struct in6_rtmsg rtmsg;
3732 int err;
3733
Ian Morris67ba4152014-08-24 21:53:10 +01003734 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 case SIOCADDRT: /* Add a route */
3736 case SIOCDELRT: /* Delete a route */
Eric W. Biedermanaf31f412012-11-16 03:03:06 +00003737 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738 return -EPERM;
3739 err = copy_from_user(&rtmsg, arg,
3740 sizeof(struct in6_rtmsg));
3741 if (err)
3742 return -EFAULT;
Thomas Graf86872cb2006-08-22 00:01:08 -07003743
Daniel Lezcano55786892008-03-04 13:47:47 -08003744 rtmsg_to_fib6_config(net, &rtmsg, &cfg);
Thomas Graf86872cb2006-08-22 00:01:08 -07003745
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746 rtnl_lock();
3747 switch (cmd) {
3748 case SIOCADDRT:
David Ahernacb54e32018-04-17 17:33:22 -07003749 err = ip6_route_add(&cfg, GFP_KERNEL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 break;
3751 case SIOCDELRT:
David Ahern333c4302017-05-21 10:12:04 -06003752 err = ip6_route_del(&cfg, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753 break;
3754 default:
3755 err = -EINVAL;
3756 }
3757 rtnl_unlock();
3758
3759 return err;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07003760 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761
3762 return -EINVAL;
3763}
3764
3765/*
3766 * Drop the packet on the floor
3767 */
3768
Brian Haleyd5fdd6b2009-06-23 04:31:07 -07003769static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770{
Eric Dumazetadf30902009-06-02 05:19:30 +00003771 struct dst_entry *dst = skb_dst(skb);
Stephen Suryaputra1d3fd8a2019-04-27 09:14:33 -04003772 struct net *net = dev_net(dst->dev);
3773 struct inet6_dev *idev;
3774 int type;
3775
3776 if (netif_is_l3_master(skb->dev) &&
3777 dst->dev == net->loopback_dev)
3778 idev = __in6_dev_get_safely(dev_get_by_index_rcu(net, IP6CB(skb)->iif));
3779 else
3780 idev = ip6_dst_idev(dst);
3781
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003782 switch (ipstats_mib_noroutes) {
3783 case IPSTATS_MIB_INNOROUTES:
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07003784 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
Ulrich Weber45bb0062010-02-25 23:28:58 +00003785 if (type == IPV6_ADDR_ANY) {
Stephen Suryaputra1d3fd8a2019-04-27 09:14:33 -04003786 IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003787 break;
3788 }
3789 /* FALLTHROUGH */
3790 case IPSTATS_MIB_OUTNOROUTES:
Stephen Suryaputra1d3fd8a2019-04-27 09:14:33 -04003791 IP6_INC_STATS(net, idev, ipstats_mib_noroutes);
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003792 break;
3793 }
Stephen Suryaputra1d3fd8a2019-04-27 09:14:33 -04003794
3795 /* Start over by dropping the dst for l3mdev case */
3796 if (netif_is_l3_master(skb->dev))
3797 skb_dst_drop(skb);
3798
Alexey Dobriyan3ffe5332010-02-18 08:25:24 +00003799 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 kfree_skb(skb);
3801 return 0;
3802}
3803
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003804static int ip6_pkt_discard(struct sk_buff *skb)
3805{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003806 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003807}
3808
Eric W. Biedermanede20592015-10-07 16:48:47 -05003809static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810{
Eric Dumazetadf30902009-06-02 05:19:30 +00003811 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003812 return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813}
3814
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003815static int ip6_pkt_prohibit(struct sk_buff *skb)
3816{
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003817 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003818}
3819
Eric W. Biedermanede20592015-10-07 16:48:47 -05003820static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb)
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003821{
Eric Dumazetadf30902009-06-02 05:19:30 +00003822 skb->dev = skb_dst(skb)->dev;
YOSHIFUJI Hideaki612f09e2007-04-13 16:18:02 -07003823 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
Thomas Graf9ce8ade2006-10-18 20:46:54 -07003824}
3825
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826/*
3827 * Allocate a dst for local (unicast / anycast) address.
3828 */
3829
David Ahern360a9882018-04-18 15:39:00 -07003830struct fib6_info *addrconf_f6i_alloc(struct net *net,
3831 struct inet6_dev *idev,
3832 const struct in6_addr *addr,
3833 bool anycast, gfp_t gfp_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834{
David Ahernc7a1ce32019-03-21 05:21:35 -07003835 struct fib6_config cfg = {
3836 .fc_table = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL,
3837 .fc_ifindex = idev->dev->ifindex,
3838 .fc_flags = RTF_UP | RTF_ADDRCONF | RTF_NONEXTHOP,
3839 .fc_dst = *addr,
3840 .fc_dst_len = 128,
3841 .fc_protocol = RTPROT_KERNEL,
3842 .fc_nlinfo.nl_net = net,
3843 .fc_ignore_dev_down = true,
3844 };
David Ahern5f02ce242016-09-10 12:09:54 -07003845
David Aherne8478e82018-04-17 17:33:13 -07003846 if (anycast) {
David Ahernc7a1ce32019-03-21 05:21:35 -07003847 cfg.fc_type = RTN_ANYCAST;
3848 cfg.fc_flags |= RTF_ANYCAST;
David Aherne8478e82018-04-17 17:33:13 -07003849 } else {
David Ahernc7a1ce32019-03-21 05:21:35 -07003850 cfg.fc_type = RTN_LOCAL;
3851 cfg.fc_flags |= RTF_LOCAL;
David Aherne8478e82018-04-17 17:33:13 -07003852 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853
David Ahernc7a1ce32019-03-21 05:21:35 -07003854 return ip6_route_info_create(&cfg, gfp_flags, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855}
3856
Daniel Walterc3968a82011-04-13 21:10:57 +00003857/* remove deleted ip from prefsrc entries */
3858struct arg_dev_net_ip {
3859 struct net_device *dev;
3860 struct net *net;
3861 struct in6_addr *addr;
3862};
3863
David Ahern8d1c8022018-04-17 17:33:26 -07003864static int fib6_remove_prefsrc(struct fib6_info *rt, void *arg)
Daniel Walterc3968a82011-04-13 21:10:57 +00003865{
3866 struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
3867 struct net *net = ((struct arg_dev_net_ip *)arg)->net;
3868 struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
3869
David Ahernad1601a2019-03-27 20:53:56 -07003870 if (((void *)rt->fib6_nh.fib_nh_dev == dev || !dev) &&
David Ahern421842e2018-04-17 17:33:18 -07003871 rt != net->ipv6.fib6_null_entry &&
David Ahern93c2fb22018-04-18 15:38:59 -07003872 ipv6_addr_equal(addr, &rt->fib6_prefsrc.addr)) {
Wei Wang60006a42017-10-06 12:05:58 -07003873 spin_lock_bh(&rt6_exception_lock);
Daniel Walterc3968a82011-04-13 21:10:57 +00003874 /* remove prefsrc entry */
David Ahern93c2fb22018-04-18 15:38:59 -07003875 rt->fib6_prefsrc.plen = 0;
Wei Wang60006a42017-10-06 12:05:58 -07003876 spin_unlock_bh(&rt6_exception_lock);
Daniel Walterc3968a82011-04-13 21:10:57 +00003877 }
3878 return 0;
3879}
3880
3881void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
3882{
3883 struct net *net = dev_net(ifp->idev->dev);
3884 struct arg_dev_net_ip adni = {
3885 .dev = ifp->idev->dev,
3886 .net = net,
3887 .addr = &ifp->addr,
3888 };
Li RongQing0c3584d2013-12-27 16:32:38 +08003889 fib6_clean_all(net, fib6_remove_prefsrc, &adni);
Daniel Walterc3968a82011-04-13 21:10:57 +00003890}
3891
David Ahern2b2450c2019-03-27 20:53:52 -07003892#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT)
Duan Jiongbe7a0102014-05-15 15:56:14 +08003893
3894/* Remove routers and update dst entries when gateway turn into host. */
David Ahern8d1c8022018-04-17 17:33:26 -07003895static int fib6_clean_tohost(struct fib6_info *rt, void *arg)
Duan Jiongbe7a0102014-05-15 15:56:14 +08003896{
3897 struct in6_addr *gateway = (struct in6_addr *)arg;
3898
David Ahern93c2fb22018-04-18 15:38:59 -07003899 if (((rt->fib6_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) &&
David Ahernbdf00462019-04-05 16:30:26 -07003900 rt->fib6_nh.fib_nh_gw_family &&
David Ahernad1601a2019-03-27 20:53:56 -07003901 ipv6_addr_equal(gateway, &rt->fib6_nh.fib_nh_gw6)) {
Duan Jiongbe7a0102014-05-15 15:56:14 +08003902 return -1;
3903 }
Wei Wangb16cb452017-10-06 12:06:00 -07003904
3905 /* Further clean up cached routes in exception table.
3906 * This is needed because cached route may have a different
3907 * gateway than its 'parent' in the case of an ip redirect.
3908 */
3909 rt6_exceptions_clean_tohost(rt, gateway);
3910
Duan Jiongbe7a0102014-05-15 15:56:14 +08003911 return 0;
3912}
3913
3914void rt6_clean_tohost(struct net *net, struct in6_addr *gateway)
3915{
3916 fib6_clean_all(net, fib6_clean_tohost, gateway);
3917}
3918
Ido Schimmel2127d952018-01-07 12:45:03 +02003919struct arg_netdev_event {
3920 const struct net_device *dev;
Ido Schimmel4c981e22018-01-07 12:45:04 +02003921 union {
David Ahernecc56632019-04-23 08:48:09 -07003922 unsigned char nh_flags;
Ido Schimmel4c981e22018-01-07 12:45:04 +02003923 unsigned long event;
3924 };
Ido Schimmel2127d952018-01-07 12:45:03 +02003925};
3926
David Ahern8d1c8022018-04-17 17:33:26 -07003927static struct fib6_info *rt6_multipath_first_sibling(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003928{
David Ahern8d1c8022018-04-17 17:33:26 -07003929 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003930 struct fib6_node *fn;
3931
David Ahern93c2fb22018-04-18 15:38:59 -07003932 fn = rcu_dereference_protected(rt->fib6_node,
3933 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003934 iter = rcu_dereference_protected(fn->leaf,
David Ahern93c2fb22018-04-18 15:38:59 -07003935 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003936 while (iter) {
David Ahern93c2fb22018-04-18 15:38:59 -07003937 if (iter->fib6_metric == rt->fib6_metric &&
David Ahern33bd5ac2018-07-03 14:36:21 -07003938 rt6_qualify_for_ecmp(iter))
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003939 return iter;
David Ahern8fb11a92018-05-04 13:54:24 -07003940 iter = rcu_dereference_protected(iter->fib6_next,
David Ahern93c2fb22018-04-18 15:38:59 -07003941 lockdep_is_held(&rt->fib6_table->tb6_lock));
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003942 }
3943
3944 return NULL;
3945}
3946
David Ahern8d1c8022018-04-17 17:33:26 -07003947static bool rt6_is_dead(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003948{
David Ahernad1601a2019-03-27 20:53:56 -07003949 if (rt->fib6_nh.fib_nh_flags & RTNH_F_DEAD ||
3950 (rt->fib6_nh.fib_nh_flags & RTNH_F_LINKDOWN &&
3951 ip6_ignore_linkdown(rt->fib6_nh.fib_nh_dev)))
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003952 return true;
3953
3954 return false;
3955}
3956
David Ahern8d1c8022018-04-17 17:33:26 -07003957static int rt6_multipath_total_weight(const struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003958{
David Ahern8d1c8022018-04-17 17:33:26 -07003959 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003960 int total = 0;
3961
3962 if (!rt6_is_dead(rt))
David Ahernad1601a2019-03-27 20:53:56 -07003963 total += rt->fib6_nh.fib_nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003964
David Ahern93c2fb22018-04-18 15:38:59 -07003965 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) {
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003966 if (!rt6_is_dead(iter))
David Ahernad1601a2019-03-27 20:53:56 -07003967 total += iter->fib6_nh.fib_nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003968 }
3969
3970 return total;
3971}
3972
David Ahern8d1c8022018-04-17 17:33:26 -07003973static void rt6_upper_bound_set(struct fib6_info *rt, int *weight, int total)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003974{
3975 int upper_bound = -1;
3976
3977 if (!rt6_is_dead(rt)) {
David Ahernad1601a2019-03-27 20:53:56 -07003978 *weight += rt->fib6_nh.fib_nh_weight;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003979 upper_bound = DIV_ROUND_CLOSEST_ULL((u64) (*weight) << 31,
3980 total) - 1;
3981 }
David Ahernad1601a2019-03-27 20:53:56 -07003982 atomic_set(&rt->fib6_nh.fib_nh_upper_bound, upper_bound);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003983}
3984
David Ahern8d1c8022018-04-17 17:33:26 -07003985static void rt6_multipath_upper_bound_set(struct fib6_info *rt, int total)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003986{
David Ahern8d1c8022018-04-17 17:33:26 -07003987 struct fib6_info *iter;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003988 int weight = 0;
3989
3990 rt6_upper_bound_set(rt, &weight, total);
3991
David Ahern93c2fb22018-04-18 15:38:59 -07003992 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003993 rt6_upper_bound_set(iter, &weight, total);
3994}
3995
David Ahern8d1c8022018-04-17 17:33:26 -07003996void rt6_multipath_rebalance(struct fib6_info *rt)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003997{
David Ahern8d1c8022018-04-17 17:33:26 -07003998 struct fib6_info *first;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02003999 int total;
4000
4001 /* In case the entire multipath route was marked for flushing,
4002 * then there is no need to rebalance upon the removal of every
4003 * sibling route.
4004 */
David Ahern93c2fb22018-04-18 15:38:59 -07004005 if (!rt->fib6_nsiblings || rt->should_flush)
Ido Schimmeld7dedee2018-01-09 16:40:25 +02004006 return;
4007
4008 /* During lookup routes are evaluated in order, so we need to
4009 * make sure upper bounds are assigned from the first sibling
4010 * onwards.
4011 */
4012 first = rt6_multipath_first_sibling(rt);
4013 if (WARN_ON_ONCE(!first))
4014 return;
4015
4016 total = rt6_multipath_total_weight(first);
4017 rt6_multipath_upper_bound_set(first, total);
4018}
4019
David Ahern8d1c8022018-04-17 17:33:26 -07004020static int fib6_ifup(struct fib6_info *rt, void *p_arg)
Ido Schimmel2127d952018-01-07 12:45:03 +02004021{
4022 const struct arg_netdev_event *arg = p_arg;
David Ahern7aef6852018-04-17 17:33:10 -07004023 struct net *net = dev_net(arg->dev);
Ido Schimmel2127d952018-01-07 12:45:03 +02004024
David Ahernad1601a2019-03-27 20:53:56 -07004025 if (rt != net->ipv6.fib6_null_entry &&
4026 rt->fib6_nh.fib_nh_dev == arg->dev) {
4027 rt->fib6_nh.fib_nh_flags &= ~arg->nh_flags;
David Ahern7aef6852018-04-17 17:33:10 -07004028 fib6_update_sernum_upto_root(net, rt);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02004029 rt6_multipath_rebalance(rt);
Ido Schimmel1de178e2018-01-07 12:45:15 +02004030 }
Ido Schimmel2127d952018-01-07 12:45:03 +02004031
4032 return 0;
4033}
4034
David Ahernecc56632019-04-23 08:48:09 -07004035void rt6_sync_up(struct net_device *dev, unsigned char nh_flags)
Ido Schimmel2127d952018-01-07 12:45:03 +02004036{
4037 struct arg_netdev_event arg = {
4038 .dev = dev,
Ido Schimmel6802f3a2018-01-12 22:07:36 +02004039 {
4040 .nh_flags = nh_flags,
4041 },
Ido Schimmel2127d952018-01-07 12:45:03 +02004042 };
4043
4044 if (nh_flags & RTNH_F_DEAD && netif_carrier_ok(dev))
4045 arg.nh_flags |= RTNH_F_LINKDOWN;
4046
4047 fib6_clean_all(dev_net(dev), fib6_ifup, &arg);
4048}
4049
David Ahern8d1c8022018-04-17 17:33:26 -07004050static bool rt6_multipath_uses_dev(const struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02004051 const struct net_device *dev)
4052{
David Ahern8d1c8022018-04-17 17:33:26 -07004053 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02004054
David Ahernad1601a2019-03-27 20:53:56 -07004055 if (rt->fib6_nh.fib_nh_dev == dev)
Ido Schimmel1de178e2018-01-07 12:45:15 +02004056 return true;
David Ahern93c2fb22018-04-18 15:38:59 -07004057 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahernad1601a2019-03-27 20:53:56 -07004058 if (iter->fib6_nh.fib_nh_dev == dev)
Ido Schimmel1de178e2018-01-07 12:45:15 +02004059 return true;
4060
4061 return false;
4062}
4063
David Ahern8d1c8022018-04-17 17:33:26 -07004064static void rt6_multipath_flush(struct fib6_info *rt)
Ido Schimmel1de178e2018-01-07 12:45:15 +02004065{
David Ahern8d1c8022018-04-17 17:33:26 -07004066 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02004067
4068 rt->should_flush = 1;
David Ahern93c2fb22018-04-18 15:38:59 -07004069 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
Ido Schimmel1de178e2018-01-07 12:45:15 +02004070 iter->should_flush = 1;
4071}
4072
David Ahern8d1c8022018-04-17 17:33:26 -07004073static unsigned int rt6_multipath_dead_count(const struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02004074 const struct net_device *down_dev)
4075{
David Ahern8d1c8022018-04-17 17:33:26 -07004076 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02004077 unsigned int dead = 0;
4078
David Ahernad1601a2019-03-27 20:53:56 -07004079 if (rt->fib6_nh.fib_nh_dev == down_dev ||
4080 rt->fib6_nh.fib_nh_flags & RTNH_F_DEAD)
Ido Schimmel1de178e2018-01-07 12:45:15 +02004081 dead++;
David Ahern93c2fb22018-04-18 15:38:59 -07004082 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahernad1601a2019-03-27 20:53:56 -07004083 if (iter->fib6_nh.fib_nh_dev == down_dev ||
4084 iter->fib6_nh.fib_nh_flags & RTNH_F_DEAD)
Ido Schimmel1de178e2018-01-07 12:45:15 +02004085 dead++;
4086
4087 return dead;
4088}
4089
David Ahern8d1c8022018-04-17 17:33:26 -07004090static void rt6_multipath_nh_flags_set(struct fib6_info *rt,
Ido Schimmel1de178e2018-01-07 12:45:15 +02004091 const struct net_device *dev,
David Ahernecc56632019-04-23 08:48:09 -07004092 unsigned char nh_flags)
Ido Schimmel1de178e2018-01-07 12:45:15 +02004093{
David Ahern8d1c8022018-04-17 17:33:26 -07004094 struct fib6_info *iter;
Ido Schimmel1de178e2018-01-07 12:45:15 +02004095
David Ahernad1601a2019-03-27 20:53:56 -07004096 if (rt->fib6_nh.fib_nh_dev == dev)
4097 rt->fib6_nh.fib_nh_flags |= nh_flags;
David Ahern93c2fb22018-04-18 15:38:59 -07004098 list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings)
David Ahernad1601a2019-03-27 20:53:56 -07004099 if (iter->fib6_nh.fib_nh_dev == dev)
4100 iter->fib6_nh.fib_nh_flags |= nh_flags;
Ido Schimmel1de178e2018-01-07 12:45:15 +02004101}
4102
David Aherna1a22c12017-01-18 07:40:36 -08004103/* called with write lock held for table with rt */
David Ahern8d1c8022018-04-17 17:33:26 -07004104static int fib6_ifdown(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105{
Ido Schimmel4c981e22018-01-07 12:45:04 +02004106 const struct arg_netdev_event *arg = p_arg;
4107 const struct net_device *dev = arg->dev;
David Ahern7aef6852018-04-17 17:33:10 -07004108 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004109
David Ahern421842e2018-04-17 17:33:18 -07004110 if (rt == net->ipv6.fib6_null_entry)
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004111 return 0;
4112
4113 switch (arg->event) {
4114 case NETDEV_UNREGISTER:
David Ahernad1601a2019-03-27 20:53:56 -07004115 return rt->fib6_nh.fib_nh_dev == dev ? -1 : 0;
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004116 case NETDEV_DOWN:
Ido Schimmel1de178e2018-01-07 12:45:15 +02004117 if (rt->should_flush)
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004118 return -1;
David Ahern93c2fb22018-04-18 15:38:59 -07004119 if (!rt->fib6_nsiblings)
David Ahernad1601a2019-03-27 20:53:56 -07004120 return rt->fib6_nh.fib_nh_dev == dev ? -1 : 0;
Ido Schimmel1de178e2018-01-07 12:45:15 +02004121 if (rt6_multipath_uses_dev(rt, dev)) {
4122 unsigned int count;
4123
4124 count = rt6_multipath_dead_count(rt, dev);
David Ahern93c2fb22018-04-18 15:38:59 -07004125 if (rt->fib6_nsiblings + 1 == count) {
Ido Schimmel1de178e2018-01-07 12:45:15 +02004126 rt6_multipath_flush(rt);
4127 return -1;
4128 }
4129 rt6_multipath_nh_flags_set(rt, dev, RTNH_F_DEAD |
4130 RTNH_F_LINKDOWN);
David Ahern7aef6852018-04-17 17:33:10 -07004131 fib6_update_sernum(net, rt);
Ido Schimmeld7dedee2018-01-09 16:40:25 +02004132 rt6_multipath_rebalance(rt);
Ido Schimmel1de178e2018-01-07 12:45:15 +02004133 }
4134 return -2;
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004135 case NETDEV_CHANGE:
David Ahernad1601a2019-03-27 20:53:56 -07004136 if (rt->fib6_nh.fib_nh_dev != dev ||
David Ahern93c2fb22018-04-18 15:38:59 -07004137 rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST))
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004138 break;
David Ahernad1601a2019-03-27 20:53:56 -07004139 rt->fib6_nh.fib_nh_flags |= RTNH_F_LINKDOWN;
Ido Schimmeld7dedee2018-01-09 16:40:25 +02004140 rt6_multipath_rebalance(rt);
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004141 break;
Ido Schimmel2b241362018-01-07 12:45:02 +02004142 }
David S. Millerc159d302011-12-26 15:24:36 -05004143
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144 return 0;
4145}
4146
Ido Schimmel27c6fa72018-01-07 12:45:05 +02004147void rt6_sync_down_dev(struct net_device *dev, unsigned long event)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148{
Ido Schimmel4c981e22018-01-07 12:45:04 +02004149 struct arg_netdev_event arg = {
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004150 .dev = dev,
Ido Schimmel6802f3a2018-01-12 22:07:36 +02004151 {
4152 .event = event,
4153 },
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004154 };
David Ahern7c6bb7d2018-10-11 20:17:21 -07004155 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08004156
David Ahern7c6bb7d2018-10-11 20:17:21 -07004157 if (net->ipv6.sysctl.skip_notify_on_dev_down)
4158 fib6_clean_all_skip_notify(net, fib6_ifdown, &arg);
4159 else
4160 fib6_clean_all(net, fib6_ifdown, &arg);
Ido Schimmel4c981e22018-01-07 12:45:04 +02004161}
4162
4163void rt6_disable_ip(struct net_device *dev, unsigned long event)
4164{
4165 rt6_sync_down_dev(dev, event);
4166 rt6_uncached_list_flush_dev(dev_net(dev), dev);
4167 neigh_ifdown(&nd_tbl, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168}
4169
Eric Dumazet95c96172012-04-15 05:58:06 +00004170struct rt6_mtu_change_arg {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 struct net_device *dev;
Eric Dumazet95c96172012-04-15 05:58:06 +00004172 unsigned int mtu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173};
4174
David Ahern8d1c8022018-04-17 17:33:26 -07004175static int rt6_mtu_change_route(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176{
4177 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
4178 struct inet6_dev *idev;
4179
4180 /* In IPv6 pmtu discovery is not optional,
4181 so that RTAX_MTU lock cannot disable it.
4182 We still use this lock to block changes
4183 caused by addrconf/ndisc.
4184 */
4185
4186 idev = __in6_dev_get(arg->dev);
David S. Miller38308472011-12-03 18:02:47 -05004187 if (!idev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 return 0;
4189
4190 /* For administrative MTU increase, there is no way to discover
4191 IPv6 PMTU increase, so PMTU increase should be updated here.
4192 Since RFC 1981 doesn't include administrative MTU increase
4193 update PMTU increase is a MUST. (i.e. jumbo frame)
4194 */
David Ahernad1601a2019-03-27 20:53:56 -07004195 if (rt->fib6_nh.fib_nh_dev == arg->dev &&
David Ahernd4ead6b2018-04-17 17:33:16 -07004196 !fib6_metric_locked(rt, RTAX_MTU)) {
4197 u32 mtu = rt->fib6_pmtu;
4198
4199 if (mtu >= arg->mtu ||
4200 (mtu < arg->mtu && mtu == idev->cnf.mtu6))
4201 fib6_metric_set(rt, RTAX_MTU, arg->mtu);
4202
Wei Wangf5bbe7e2017-10-06 12:05:59 -07004203 spin_lock_bh(&rt6_exception_lock);
Stefano Brivioe9fa1492018-03-06 11:10:19 +01004204 rt6_exceptions_update_pmtu(idev, rt, arg->mtu);
Wei Wangf5bbe7e2017-10-06 12:05:59 -07004205 spin_unlock_bh(&rt6_exception_lock);
Simon Arlott566cfd82007-07-26 00:09:55 -07004206 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207 return 0;
4208}
4209
Eric Dumazet95c96172012-04-15 05:58:06 +00004210void rt6_mtu_change(struct net_device *dev, unsigned int mtu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211{
Thomas Grafc71099a2006-08-04 23:20:06 -07004212 struct rt6_mtu_change_arg arg = {
4213 .dev = dev,
4214 .mtu = mtu,
4215 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216
Li RongQing0c3584d2013-12-27 16:32:38 +08004217 fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218}
4219
Patrick McHardyef7c79e2007-06-05 12:38:30 -07004220static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
Thomas Graf5176f912006-08-26 20:13:18 -07004221 [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) },
Eric Dumazetaa8f8772018-04-22 18:29:23 -07004222 [RTA_PREFSRC] = { .len = sizeof(struct in6_addr) },
Thomas Graf86872cb2006-08-22 00:01:08 -07004223 [RTA_OIF] = { .type = NLA_U32 },
Thomas Grafab364a62006-08-22 00:01:47 -07004224 [RTA_IIF] = { .type = NLA_U32 },
Thomas Graf86872cb2006-08-22 00:01:08 -07004225 [RTA_PRIORITY] = { .type = NLA_U32 },
4226 [RTA_METRICS] = { .type = NLA_NESTED },
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004227 [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004228 [RTA_PREF] = { .type = NLA_U8 },
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004229 [RTA_ENCAP_TYPE] = { .type = NLA_U16 },
4230 [RTA_ENCAP] = { .type = NLA_NESTED },
Xin Long32bc2012015-12-16 17:50:11 +08004231 [RTA_EXPIRES] = { .type = NLA_U32 },
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09004232 [RTA_UID] = { .type = NLA_U32 },
Liping Zhang3b45a412017-02-27 20:59:39 +08004233 [RTA_MARK] = { .type = NLA_U32 },
Eric Dumazetaa8f8772018-04-22 18:29:23 -07004234 [RTA_TABLE] = { .type = NLA_U32 },
Roopa Prabhueacb9382018-05-22 14:03:28 -07004235 [RTA_IP_PROTO] = { .type = NLA_U8 },
4236 [RTA_SPORT] = { .type = NLA_U16 },
4237 [RTA_DPORT] = { .type = NLA_U16 },
Thomas Graf86872cb2006-08-22 00:01:08 -07004238};
4239
4240static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
David Ahern333c4302017-05-21 10:12:04 -06004241 struct fib6_config *cfg,
4242 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243{
Thomas Graf86872cb2006-08-22 00:01:08 -07004244 struct rtmsg *rtm;
4245 struct nlattr *tb[RTA_MAX+1];
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004246 unsigned int pref;
Thomas Graf86872cb2006-08-22 00:01:08 -07004247 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248
Johannes Berg8cb08172019-04-26 14:07:28 +02004249 err = nlmsg_parse_deprecated(nlh, sizeof(*rtm), tb, RTA_MAX,
4250 rtm_ipv6_policy, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07004251 if (err < 0)
4252 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253
Thomas Graf86872cb2006-08-22 00:01:08 -07004254 err = -EINVAL;
4255 rtm = nlmsg_data(nlh);
Thomas Graf86872cb2006-08-22 00:01:08 -07004256
Maciej Żenczykowski84db8402018-09-29 23:44:53 -07004257 *cfg = (struct fib6_config){
4258 .fc_table = rtm->rtm_table,
4259 .fc_dst_len = rtm->rtm_dst_len,
4260 .fc_src_len = rtm->rtm_src_len,
4261 .fc_flags = RTF_UP,
4262 .fc_protocol = rtm->rtm_protocol,
4263 .fc_type = rtm->rtm_type,
4264
4265 .fc_nlinfo.portid = NETLINK_CB(skb).portid,
4266 .fc_nlinfo.nlh = nlh,
4267 .fc_nlinfo.nl_net = sock_net(skb->sk),
4268 };
Thomas Graf86872cb2006-08-22 00:01:08 -07004269
Nicolas Dichtelef2c7d72012-09-05 02:12:42 +00004270 if (rtm->rtm_type == RTN_UNREACHABLE ||
4271 rtm->rtm_type == RTN_BLACKHOLE ||
Nicolas Dichtelb4949ab2012-09-06 05:53:35 +00004272 rtm->rtm_type == RTN_PROHIBIT ||
4273 rtm->rtm_type == RTN_THROW)
Thomas Graf86872cb2006-08-22 00:01:08 -07004274 cfg->fc_flags |= RTF_REJECT;
4275
Maciej Żenczykowskiab79ad12010-09-27 00:07:02 +00004276 if (rtm->rtm_type == RTN_LOCAL)
4277 cfg->fc_flags |= RTF_LOCAL;
4278
Martin KaFai Lau1f56a01f2015-04-28 13:03:03 -07004279 if (rtm->rtm_flags & RTM_F_CLONED)
4280 cfg->fc_flags |= RTF_CACHE;
4281
David Ahernfc1e64e2018-01-25 16:55:09 -08004282 cfg->fc_flags |= (rtm->rtm_flags & RTNH_F_ONLINK);
4283
Thomas Graf86872cb2006-08-22 00:01:08 -07004284 if (tb[RTA_GATEWAY]) {
Jiri Benc67b61f62015-03-29 16:59:26 +02004285 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]);
Thomas Graf86872cb2006-08-22 00:01:08 -07004286 cfg->fc_flags |= RTF_GATEWAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 }
David Aherne3818542019-02-26 09:00:03 -08004288 if (tb[RTA_VIA]) {
4289 NL_SET_ERR_MSG(extack, "IPv6 does not support RTA_VIA attribute");
4290 goto errout;
4291 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004292
4293 if (tb[RTA_DST]) {
4294 int plen = (rtm->rtm_dst_len + 7) >> 3;
4295
4296 if (nla_len(tb[RTA_DST]) < plen)
4297 goto errout;
4298
4299 nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004301
4302 if (tb[RTA_SRC]) {
4303 int plen = (rtm->rtm_src_len + 7) >> 3;
4304
4305 if (nla_len(tb[RTA_SRC]) < plen)
4306 goto errout;
4307
4308 nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004310
Daniel Walterc3968a82011-04-13 21:10:57 +00004311 if (tb[RTA_PREFSRC])
Jiri Benc67b61f62015-03-29 16:59:26 +02004312 cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]);
Daniel Walterc3968a82011-04-13 21:10:57 +00004313
Thomas Graf86872cb2006-08-22 00:01:08 -07004314 if (tb[RTA_OIF])
4315 cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
4316
4317 if (tb[RTA_PRIORITY])
4318 cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]);
4319
4320 if (tb[RTA_METRICS]) {
4321 cfg->fc_mx = nla_data(tb[RTA_METRICS]);
4322 cfg->fc_mx_len = nla_len(tb[RTA_METRICS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323 }
Thomas Graf86872cb2006-08-22 00:01:08 -07004324
4325 if (tb[RTA_TABLE])
4326 cfg->fc_table = nla_get_u32(tb[RTA_TABLE]);
4327
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004328 if (tb[RTA_MULTIPATH]) {
4329 cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
4330 cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
David Ahern9ed59592017-01-17 14:57:36 -08004331
4332 err = lwtunnel_valid_encap_type_attr(cfg->fc_mp,
David Ahernc255bd62017-05-27 16:19:27 -06004333 cfg->fc_mp_len, extack);
David Ahern9ed59592017-01-17 14:57:36 -08004334 if (err < 0)
4335 goto errout;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004336 }
4337
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004338 if (tb[RTA_PREF]) {
4339 pref = nla_get_u8(tb[RTA_PREF]);
4340 if (pref != ICMPV6_ROUTER_PREF_LOW &&
4341 pref != ICMPV6_ROUTER_PREF_HIGH)
4342 pref = ICMPV6_ROUTER_PREF_MEDIUM;
4343 cfg->fc_flags |= RTF_PREF(pref);
4344 }
4345
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004346 if (tb[RTA_ENCAP])
4347 cfg->fc_encap = tb[RTA_ENCAP];
4348
David Ahern9ed59592017-01-17 14:57:36 -08004349 if (tb[RTA_ENCAP_TYPE]) {
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004350 cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]);
4351
David Ahernc255bd62017-05-27 16:19:27 -06004352 err = lwtunnel_valid_encap_type(cfg->fc_encap_type, extack);
David Ahern9ed59592017-01-17 14:57:36 -08004353 if (err < 0)
4354 goto errout;
4355 }
4356
Xin Long32bc2012015-12-16 17:50:11 +08004357 if (tb[RTA_EXPIRES]) {
4358 unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ);
4359
4360 if (addrconf_finite_timeout(timeout)) {
4361 cfg->fc_expires = jiffies_to_clock_t(timeout * HZ);
4362 cfg->fc_flags |= RTF_EXPIRES;
4363 }
4364 }
4365
Thomas Graf86872cb2006-08-22 00:01:08 -07004366 err = 0;
4367errout:
4368 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369}
4370
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004371struct rt6_nh {
David Ahern8d1c8022018-04-17 17:33:26 -07004372 struct fib6_info *fib6_info;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004373 struct fib6_config r_cfg;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004374 struct list_head next;
4375};
4376
David Ahernd4ead6b2018-04-17 17:33:16 -07004377static int ip6_route_info_append(struct net *net,
4378 struct list_head *rt6_nh_list,
David Ahern8d1c8022018-04-17 17:33:26 -07004379 struct fib6_info *rt,
4380 struct fib6_config *r_cfg)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004381{
4382 struct rt6_nh *nh;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004383 int err = -EEXIST;
4384
4385 list_for_each_entry(nh, rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004386 /* check if fib6_info already exists */
4387 if (rt6_duplicate_nexthop(nh->fib6_info, rt))
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004388 return err;
4389 }
4390
4391 nh = kzalloc(sizeof(*nh), GFP_KERNEL);
4392 if (!nh)
4393 return -ENOMEM;
David Ahern8d1c8022018-04-17 17:33:26 -07004394 nh->fib6_info = rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004395 memcpy(&nh->r_cfg, r_cfg, sizeof(*r_cfg));
4396 list_add_tail(&nh->next, rt6_nh_list);
4397
4398 return 0;
4399}
4400
David Ahern8d1c8022018-04-17 17:33:26 -07004401static void ip6_route_mpath_notify(struct fib6_info *rt,
4402 struct fib6_info *rt_last,
David Ahern3b1137f2017-02-02 12:37:10 -08004403 struct nl_info *info,
4404 __u16 nlflags)
4405{
4406 /* if this is an APPEND route, then rt points to the first route
4407 * inserted and rt_last points to last route inserted. Userspace
4408 * wants a consistent dump of the route which starts at the first
4409 * nexthop. Since sibling routes are always added at the end of
4410 * the list, find the first sibling of the last route appended
4411 */
David Ahern93c2fb22018-04-18 15:38:59 -07004412 if ((nlflags & NLM_F_APPEND) && rt_last && rt_last->fib6_nsiblings) {
4413 rt = list_first_entry(&rt_last->fib6_siblings,
David Ahern8d1c8022018-04-17 17:33:26 -07004414 struct fib6_info,
David Ahern93c2fb22018-04-18 15:38:59 -07004415 fib6_siblings);
David Ahern3b1137f2017-02-02 12:37:10 -08004416 }
4417
4418 if (rt)
4419 inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
4420}
4421
David Ahern333c4302017-05-21 10:12:04 -06004422static int ip6_route_multipath_add(struct fib6_config *cfg,
4423 struct netlink_ext_ack *extack)
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004424{
David Ahern8d1c8022018-04-17 17:33:26 -07004425 struct fib6_info *rt_notif = NULL, *rt_last = NULL;
David Ahern3b1137f2017-02-02 12:37:10 -08004426 struct nl_info *info = &cfg->fc_nlinfo;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004427 struct fib6_config r_cfg;
4428 struct rtnexthop *rtnh;
David Ahern8d1c8022018-04-17 17:33:26 -07004429 struct fib6_info *rt;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004430 struct rt6_nh *err_nh;
4431 struct rt6_nh *nh, *nh_safe;
David Ahern3b1137f2017-02-02 12:37:10 -08004432 __u16 nlflags;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004433 int remaining;
4434 int attrlen;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004435 int err = 1;
4436 int nhn = 0;
4437 int replace = (cfg->fc_nlinfo.nlh &&
4438 (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE));
4439 LIST_HEAD(rt6_nh_list);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004440
David Ahern3b1137f2017-02-02 12:37:10 -08004441 nlflags = replace ? NLM_F_REPLACE : NLM_F_CREATE;
4442 if (info->nlh && info->nlh->nlmsg_flags & NLM_F_APPEND)
4443 nlflags |= NLM_F_APPEND;
4444
Michal Kubeček35f1b4e2015-05-18 20:53:55 +02004445 remaining = cfg->fc_mp_len;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004446 rtnh = (struct rtnexthop *)cfg->fc_mp;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004447
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004448 /* Parse a Multipath Entry and build a list (rt6_nh_list) of
David Ahern8d1c8022018-04-17 17:33:26 -07004449 * fib6_info structs per nexthop
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004450 */
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004451 while (rtnh_ok(rtnh, remaining)) {
4452 memcpy(&r_cfg, cfg, sizeof(*cfg));
4453 if (rtnh->rtnh_ifindex)
4454 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
4455
4456 attrlen = rtnh_attrlen(rtnh);
4457 if (attrlen > 0) {
4458 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
4459
4460 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
4461 if (nla) {
Jiri Benc67b61f62015-03-29 16:59:26 +02004462 r_cfg.fc_gateway = nla_get_in6_addr(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004463 r_cfg.fc_flags |= RTF_GATEWAY;
4464 }
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004465 r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP);
4466 nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
4467 if (nla)
4468 r_cfg.fc_encap_type = nla_get_u16(nla);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004469 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004470
David Ahern68e2ffd2018-03-20 10:06:59 -07004471 r_cfg.fc_flags |= (rtnh->rtnh_flags & RTNH_F_ONLINK);
David Ahernacb54e32018-04-17 17:33:22 -07004472 rt = ip6_route_info_create(&r_cfg, GFP_KERNEL, extack);
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07004473 if (IS_ERR(rt)) {
4474 err = PTR_ERR(rt);
4475 rt = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004476 goto cleanup;
Roopa Prabhu8c5b83f2015-10-10 08:26:36 -07004477 }
David Ahernb5d2d752018-07-15 09:35:19 -07004478 if (!rt6_qualify_for_ecmp(rt)) {
4479 err = -EINVAL;
4480 NL_SET_ERR_MSG(extack,
4481 "Device only routes can not be added for IPv6 using the multipath API.");
4482 fib6_info_release(rt);
4483 goto cleanup;
4484 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004485
David Ahernad1601a2019-03-27 20:53:56 -07004486 rt->fib6_nh.fib_nh_weight = rtnh->rtnh_hops + 1;
Ido Schimmel398958a2018-01-09 16:40:28 +02004487
David Ahernd4ead6b2018-04-17 17:33:16 -07004488 err = ip6_route_info_append(info->nl_net, &rt6_nh_list,
4489 rt, &r_cfg);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004490 if (err) {
David Ahern93531c62018-04-17 17:33:25 -07004491 fib6_info_release(rt);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004492 goto cleanup;
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004493 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004494
4495 rtnh = rtnh_next(rtnh, &remaining);
4496 }
4497
David Ahern3b1137f2017-02-02 12:37:10 -08004498 /* for add and replace send one notification with all nexthops.
4499 * Skip the notification in fib6_add_rt2node and send one with
4500 * the full route when done
4501 */
4502 info->skip_notify = 1;
4503
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004504 err_nh = NULL;
4505 list_for_each_entry(nh, &rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004506 err = __ip6_ins_rt(nh->fib6_info, info, extack);
4507 fib6_info_release(nh->fib6_info);
David Ahern3b1137f2017-02-02 12:37:10 -08004508
David Ahernf7225172018-06-04 13:41:42 -07004509 if (!err) {
4510 /* save reference to last route successfully inserted */
4511 rt_last = nh->fib6_info;
4512
4513 /* save reference to first route for notification */
4514 if (!rt_notif)
4515 rt_notif = nh->fib6_info;
4516 }
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004517
David Ahern8d1c8022018-04-17 17:33:26 -07004518 /* nh->fib6_info is used or freed at this point, reset to NULL*/
4519 nh->fib6_info = NULL;
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004520 if (err) {
4521 if (replace && nhn)
Jakub Kicinskia5a82d82019-01-14 10:52:45 -08004522 NL_SET_ERR_MSG_MOD(extack,
4523 "multipath route replace failed (check consistency of installed routes)");
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004524 err_nh = nh;
4525 goto add_errout;
4526 }
4527
Nicolas Dichtel1a724182012-11-01 22:58:22 +00004528 /* Because each route is added like a single route we remove
Michal Kubeček27596472015-05-18 20:54:00 +02004529 * these flags after the first nexthop: if there is a collision,
4530 * we have already failed to add the first nexthop:
4531 * fib6_add_rt2node() has rejected it; when replacing, old
4532 * nexthops have been replaced by first new, the rest should
4533 * be added to it.
Nicolas Dichtel1a724182012-11-01 22:58:22 +00004534 */
Michal Kubeček27596472015-05-18 20:54:00 +02004535 cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
4536 NLM_F_REPLACE);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004537 nhn++;
4538 }
4539
David Ahern3b1137f2017-02-02 12:37:10 -08004540 /* success ... tell user about new route */
4541 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004542 goto cleanup;
4543
4544add_errout:
David Ahern3b1137f2017-02-02 12:37:10 -08004545 /* send notification for routes that were added so that
4546 * the delete notifications sent by ip6_route_del are
4547 * coherent
4548 */
4549 if (rt_notif)
4550 ip6_route_mpath_notify(rt_notif, rt_last, info, nlflags);
4551
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004552 /* Delete routes that were already added */
4553 list_for_each_entry(nh, &rt6_nh_list, next) {
4554 if (err_nh == nh)
4555 break;
David Ahern333c4302017-05-21 10:12:04 -06004556 ip6_route_del(&nh->r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004557 }
4558
4559cleanup:
4560 list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) {
David Ahern8d1c8022018-04-17 17:33:26 -07004561 if (nh->fib6_info)
4562 fib6_info_release(nh->fib6_info);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004563 list_del(&nh->next);
4564 kfree(nh);
4565 }
4566
4567 return err;
4568}
4569
David Ahern333c4302017-05-21 10:12:04 -06004570static int ip6_route_multipath_del(struct fib6_config *cfg,
4571 struct netlink_ext_ack *extack)
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004572{
4573 struct fib6_config r_cfg;
4574 struct rtnexthop *rtnh;
4575 int remaining;
4576 int attrlen;
4577 int err = 1, last_err = 0;
4578
4579 remaining = cfg->fc_mp_len;
4580 rtnh = (struct rtnexthop *)cfg->fc_mp;
4581
4582 /* Parse a Multipath Entry */
4583 while (rtnh_ok(rtnh, remaining)) {
4584 memcpy(&r_cfg, cfg, sizeof(*cfg));
4585 if (rtnh->rtnh_ifindex)
4586 r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
4587
4588 attrlen = rtnh_attrlen(rtnh);
4589 if (attrlen > 0) {
4590 struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
4591
4592 nla = nla_find(attrs, attrlen, RTA_GATEWAY);
4593 if (nla) {
4594 nla_memcpy(&r_cfg.fc_gateway, nla, 16);
4595 r_cfg.fc_flags |= RTF_GATEWAY;
4596 }
4597 }
David Ahern333c4302017-05-21 10:12:04 -06004598 err = ip6_route_del(&r_cfg, extack);
Roopa Prabhu6b9ea5a2015-09-08 10:53:04 -07004599 if (err)
4600 last_err = err;
4601
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004602 rtnh = rtnh_next(rtnh, &remaining);
4603 }
4604
4605 return last_err;
4606}
4607
David Ahernc21ef3e2017-04-16 09:48:24 -07004608static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
4609 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610{
Thomas Graf86872cb2006-08-22 00:01:08 -07004611 struct fib6_config cfg;
4612 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613
David Ahern333c4302017-05-21 10:12:04 -06004614 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07004615 if (err < 0)
4616 return err;
4617
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004618 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06004619 return ip6_route_multipath_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08004620 else {
4621 cfg.fc_delete_all_nh = 1;
David Ahern333c4302017-05-21 10:12:04 -06004622 return ip6_route_del(&cfg, extack);
David Ahern0ae81332017-02-02 12:37:08 -08004623 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624}
4625
David Ahernc21ef3e2017-04-16 09:48:24 -07004626static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
4627 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628{
Thomas Graf86872cb2006-08-22 00:01:08 -07004629 struct fib6_config cfg;
4630 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631
David Ahern333c4302017-05-21 10:12:04 -06004632 err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
Thomas Graf86872cb2006-08-22 00:01:08 -07004633 if (err < 0)
4634 return err;
4635
David Ahern67f69512019-03-21 05:21:34 -07004636 if (cfg.fc_metric == 0)
4637 cfg.fc_metric = IP6_RT_PRIO_USER;
4638
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004639 if (cfg.fc_mp)
David Ahern333c4302017-05-21 10:12:04 -06004640 return ip6_route_multipath_add(&cfg, extack);
Nicolas Dichtel51ebd312012-10-22 03:42:09 +00004641 else
David Ahernacb54e32018-04-17 17:33:22 -07004642 return ip6_route_add(&cfg, GFP_KERNEL, extack);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643}
4644
David Ahern8d1c8022018-04-17 17:33:26 -07004645static size_t rt6_nlmsg_size(struct fib6_info *rt)
Thomas Graf339bf982006-11-10 14:10:15 -08004646{
David Ahernbeb1afac52017-02-02 12:37:09 -08004647 int nexthop_len = 0;
4648
David Ahern93c2fb22018-04-18 15:38:59 -07004649 if (rt->fib6_nsiblings) {
David Ahernbeb1afac52017-02-02 12:37:09 -08004650 nexthop_len = nla_total_size(0) /* RTA_MULTIPATH */
4651 + NLA_ALIGN(sizeof(struct rtnexthop))
4652 + nla_total_size(16) /* RTA_GATEWAY */
David Ahernad1601a2019-03-27 20:53:56 -07004653 + lwtunnel_get_encap_size(rt->fib6_nh.fib_nh_lws);
David Ahernbeb1afac52017-02-02 12:37:09 -08004654
David Ahern93c2fb22018-04-18 15:38:59 -07004655 nexthop_len *= rt->fib6_nsiblings;
David Ahernbeb1afac52017-02-02 12:37:09 -08004656 }
4657
Thomas Graf339bf982006-11-10 14:10:15 -08004658 return NLMSG_ALIGN(sizeof(struct rtmsg))
4659 + nla_total_size(16) /* RTA_SRC */
4660 + nla_total_size(16) /* RTA_DST */
4661 + nla_total_size(16) /* RTA_GATEWAY */
4662 + nla_total_size(16) /* RTA_PREFSRC */
4663 + nla_total_size(4) /* RTA_TABLE */
4664 + nla_total_size(4) /* RTA_IIF */
4665 + nla_total_size(4) /* RTA_OIF */
4666 + nla_total_size(4) /* RTA_PRIORITY */
Noriaki TAKAMIYA6a2b9ce2007-01-23 22:09:41 -08004667 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
Daniel Borkmannea697632015-01-05 23:57:47 +01004668 + nla_total_size(sizeof(struct rta_cacheinfo))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004669 + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004670 + nla_total_size(1) /* RTA_PREF */
David Ahernad1601a2019-03-27 20:53:56 -07004671 + lwtunnel_get_encap_size(rt->fib6_nh.fib_nh_lws)
David Ahernbeb1afac52017-02-02 12:37:09 -08004672 + nexthop_len;
4673}
4674
David Ahernd4ead6b2018-04-17 17:33:16 -07004675static int rt6_fill_node(struct net *net, struct sk_buff *skb,
David Ahern8d1c8022018-04-17 17:33:26 -07004676 struct fib6_info *rt, struct dst_entry *dst,
David Ahernd4ead6b2018-04-17 17:33:16 -07004677 struct in6_addr *dest, struct in6_addr *src,
Eric W. Biederman15e47302012-09-07 20:12:54 +00004678 int iif, int type, u32 portid, u32 seq,
David Ahernf8cfe2c2017-01-17 15:51:08 -08004679 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680{
Xin Long22d0bd82018-09-11 14:33:58 +08004681 struct rt6_info *rt6 = (struct rt6_info *)dst;
4682 struct rt6key *rt6_dst, *rt6_src;
4683 u32 *pmetrics, table, rt6_flags;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004684 struct nlmsghdr *nlh;
Xin Long22d0bd82018-09-11 14:33:58 +08004685 struct rtmsg *rtm;
David Ahernd4ead6b2018-04-17 17:33:16 -07004686 long expires = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687
Eric W. Biederman15e47302012-09-07 20:12:54 +00004688 nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
David S. Miller38308472011-12-03 18:02:47 -05004689 if (!nlh)
Patrick McHardy26932562007-01-31 23:16:40 -08004690 return -EMSGSIZE;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004691
Xin Long22d0bd82018-09-11 14:33:58 +08004692 if (rt6) {
4693 rt6_dst = &rt6->rt6i_dst;
4694 rt6_src = &rt6->rt6i_src;
4695 rt6_flags = rt6->rt6i_flags;
4696 } else {
4697 rt6_dst = &rt->fib6_dst;
4698 rt6_src = &rt->fib6_src;
4699 rt6_flags = rt->fib6_flags;
4700 }
4701
Thomas Graf2d7202b2006-08-22 00:01:27 -07004702 rtm = nlmsg_data(nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703 rtm->rtm_family = AF_INET6;
Xin Long22d0bd82018-09-11 14:33:58 +08004704 rtm->rtm_dst_len = rt6_dst->plen;
4705 rtm->rtm_src_len = rt6_src->plen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706 rtm->rtm_tos = 0;
David Ahern93c2fb22018-04-18 15:38:59 -07004707 if (rt->fib6_table)
4708 table = rt->fib6_table->tb6_id;
Thomas Grafc71099a2006-08-04 23:20:06 -07004709 else
Patrick McHardy9e762a42006-08-10 23:09:48 -07004710 table = RT6_TABLE_UNSPEC;
Kalash Nainwal97f00822019-02-20 16:23:04 -08004711 rtm->rtm_table = table < 256 ? table : RT_TABLE_COMPAT;
David S. Millerc78679e2012-04-01 20:27:33 -04004712 if (nla_put_u32(skb, RTA_TABLE, table))
4713 goto nla_put_failure;
David Aherne8478e82018-04-17 17:33:13 -07004714
4715 rtm->rtm_type = rt->fib6_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004716 rtm->rtm_flags = 0;
4717 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
David Ahern93c2fb22018-04-18 15:38:59 -07004718 rtm->rtm_protocol = rt->fib6_protocol;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719
Xin Long22d0bd82018-09-11 14:33:58 +08004720 if (rt6_flags & RTF_CACHE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 rtm->rtm_flags |= RTM_F_CLONED;
4722
David Ahernd4ead6b2018-04-17 17:33:16 -07004723 if (dest) {
4724 if (nla_put_in6_addr(skb, RTA_DST, dest))
David S. Millerc78679e2012-04-01 20:27:33 -04004725 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09004726 rtm->rtm_dst_len = 128;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727 } else if (rtm->rtm_dst_len)
Xin Long22d0bd82018-09-11 14:33:58 +08004728 if (nla_put_in6_addr(skb, RTA_DST, &rt6_dst->addr))
David S. Millerc78679e2012-04-01 20:27:33 -04004729 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730#ifdef CONFIG_IPV6_SUBTREES
4731 if (src) {
Jiri Benc930345e2015-03-29 16:59:25 +02004732 if (nla_put_in6_addr(skb, RTA_SRC, src))
David S. Millerc78679e2012-04-01 20:27:33 -04004733 goto nla_put_failure;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09004734 rtm->rtm_src_len = 128;
David S. Millerc78679e2012-04-01 20:27:33 -04004735 } else if (rtm->rtm_src_len &&
Xin Long22d0bd82018-09-11 14:33:58 +08004736 nla_put_in6_addr(skb, RTA_SRC, &rt6_src->addr))
David S. Millerc78679e2012-04-01 20:27:33 -04004737 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09004739 if (iif) {
4740#ifdef CONFIG_IPV6_MROUTE
Xin Long22d0bd82018-09-11 14:33:58 +08004741 if (ipv6_addr_is_multicast(&rt6_dst->addr)) {
David Ahernfd61c6b2017-01-17 15:51:07 -08004742 int err = ip6mr_get_route(net, skb, rtm, portid);
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02004743
David Ahernfd61c6b2017-01-17 15:51:07 -08004744 if (err == 0)
4745 return 0;
4746 if (err < 0)
4747 goto nla_put_failure;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09004748 } else
4749#endif
David S. Millerc78679e2012-04-01 20:27:33 -04004750 if (nla_put_u32(skb, RTA_IIF, iif))
4751 goto nla_put_failure;
David Ahernd4ead6b2018-04-17 17:33:16 -07004752 } else if (dest) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753 struct in6_addr saddr_buf;
David Ahernd4ead6b2018-04-17 17:33:16 -07004754 if (ip6_route_get_saddr(net, rt, dest, 0, &saddr_buf) == 0 &&
Jiri Benc930345e2015-03-29 16:59:25 +02004755 nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04004756 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757 }
Thomas Graf2d7202b2006-08-22 00:01:27 -07004758
David Ahern93c2fb22018-04-18 15:38:59 -07004759 if (rt->fib6_prefsrc.plen) {
Daniel Walterc3968a82011-04-13 21:10:57 +00004760 struct in6_addr saddr_buf;
David Ahern93c2fb22018-04-18 15:38:59 -07004761 saddr_buf = rt->fib6_prefsrc.addr;
Jiri Benc930345e2015-03-29 16:59:25 +02004762 if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
David S. Millerc78679e2012-04-01 20:27:33 -04004763 goto nla_put_failure;
Daniel Walterc3968a82011-04-13 21:10:57 +00004764 }
4765
David Ahernd4ead6b2018-04-17 17:33:16 -07004766 pmetrics = dst ? dst_metrics_ptr(dst) : rt->fib6_metrics->metrics;
4767 if (rtnetlink_put_metrics(skb, pmetrics) < 0)
Thomas Graf2d7202b2006-08-22 00:01:27 -07004768 goto nla_put_failure;
4769
David Ahern93c2fb22018-04-18 15:38:59 -07004770 if (nla_put_u32(skb, RTA_PRIORITY, rt->fib6_metric))
David S. Millerc78679e2012-04-01 20:27:33 -04004771 goto nla_put_failure;
Li Wei82539472012-07-29 16:01:30 +00004772
David Ahernbeb1afac52017-02-02 12:37:09 -08004773 /* For multipath routes, walk the siblings list and add
4774 * each as a nexthop within RTA_MULTIPATH.
4775 */
Xin Long22d0bd82018-09-11 14:33:58 +08004776 if (rt6) {
4777 if (rt6_flags & RTF_GATEWAY &&
4778 nla_put_in6_addr(skb, RTA_GATEWAY, &rt6->rt6i_gateway))
4779 goto nla_put_failure;
4780
4781 if (dst->dev && nla_put_u32(skb, RTA_OIF, dst->dev->ifindex))
4782 goto nla_put_failure;
4783 } else if (rt->fib6_nsiblings) {
David Ahern8d1c8022018-04-17 17:33:26 -07004784 struct fib6_info *sibling, *next_sibling;
David Ahernbeb1afac52017-02-02 12:37:09 -08004785 struct nlattr *mp;
4786
Michal Kubecekae0be8d2019-04-26 11:13:06 +02004787 mp = nla_nest_start_noflag(skb, RTA_MULTIPATH);
David Ahernbeb1afac52017-02-02 12:37:09 -08004788 if (!mp)
4789 goto nla_put_failure;
4790
David Ahernc0a72072019-04-02 14:11:58 -07004791 if (fib_add_nexthop(skb, &rt->fib6_nh.nh_common,
4792 rt->fib6_nh.fib_nh_weight) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004793 goto nla_put_failure;
4794
4795 list_for_each_entry_safe(sibling, next_sibling,
David Ahern93c2fb22018-04-18 15:38:59 -07004796 &rt->fib6_siblings, fib6_siblings) {
David Ahernc0a72072019-04-02 14:11:58 -07004797 if (fib_add_nexthop(skb, &sibling->fib6_nh.nh_common,
4798 sibling->fib6_nh.fib_nh_weight) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004799 goto nla_put_failure;
4800 }
4801
4802 nla_nest_end(skb, mp);
4803 } else {
David Ahernecc56632019-04-23 08:48:09 -07004804 unsigned char nh_flags = 0;
4805
David Ahernc0a72072019-04-02 14:11:58 -07004806 if (fib_nexthop_info(skb, &rt->fib6_nh.nh_common,
David Ahernecc56632019-04-23 08:48:09 -07004807 &nh_flags, false) < 0)
David Ahernbeb1afac52017-02-02 12:37:09 -08004808 goto nla_put_failure;
David Ahernecc56632019-04-23 08:48:09 -07004809
4810 rtm->rtm_flags |= nh_flags;
David Ahernbeb1afac52017-02-02 12:37:09 -08004811 }
4812
Xin Long22d0bd82018-09-11 14:33:58 +08004813 if (rt6_flags & RTF_EXPIRES) {
David Ahern14895682018-04-17 17:33:17 -07004814 expires = dst ? dst->expires : rt->expires;
4815 expires -= jiffies;
4816 }
YOSHIFUJI Hideaki69cdf8f2008-05-19 16:55:13 -07004817
David Ahernd4ead6b2018-04-17 17:33:16 -07004818 if (rtnl_put_cacheinfo(skb, dst, 0, expires, dst ? dst->error : 0) < 0)
Thomas Grafe3703b32006-11-27 09:27:07 -08004819 goto nla_put_failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820
Xin Long22d0bd82018-09-11 14:33:58 +08004821 if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt6_flags)))
Lubomir Rintelc78ba6d2015-03-11 15:39:21 +01004822 goto nla_put_failure;
4823
Roopa Prabhu19e42e42015-07-21 10:43:48 +02004824
Johannes Berg053c0952015-01-16 22:09:00 +01004825 nlmsg_end(skb, nlh);
4826 return 0;
Thomas Graf2d7202b2006-08-22 00:01:27 -07004827
4828nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08004829 nlmsg_cancel(skb, nlh);
4830 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831}
4832
David Ahern13e38902018-10-15 18:56:44 -07004833static bool fib6_info_uses_dev(const struct fib6_info *f6i,
4834 const struct net_device *dev)
4835{
David Ahernad1601a2019-03-27 20:53:56 -07004836 if (f6i->fib6_nh.fib_nh_dev == dev)
David Ahern13e38902018-10-15 18:56:44 -07004837 return true;
4838
4839 if (f6i->fib6_nsiblings) {
4840 struct fib6_info *sibling, *next_sibling;
4841
4842 list_for_each_entry_safe(sibling, next_sibling,
4843 &f6i->fib6_siblings, fib6_siblings) {
David Ahernad1601a2019-03-27 20:53:56 -07004844 if (sibling->fib6_nh.fib_nh_dev == dev)
David Ahern13e38902018-10-15 18:56:44 -07004845 return true;
4846 }
4847 }
4848
4849 return false;
4850}
4851
David Ahern8d1c8022018-04-17 17:33:26 -07004852int rt6_dump_route(struct fib6_info *rt, void *p_arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853{
4854 struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
David Ahern13e38902018-10-15 18:56:44 -07004855 struct fib_dump_filter *filter = &arg->filter;
4856 unsigned int flags = NLM_F_MULTI;
David Ahern1f17e2f2017-01-26 13:54:08 -08004857 struct net *net = arg->net;
4858
David Ahern421842e2018-04-17 17:33:18 -07004859 if (rt == net->ipv6.fib6_null_entry)
David Ahern1f17e2f2017-01-26 13:54:08 -08004860 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004861
David Ahern13e38902018-10-15 18:56:44 -07004862 if ((filter->flags & RTM_F_PREFIX) &&
4863 !(rt->fib6_flags & RTF_PREFIX_RT)) {
4864 /* success since this is not a prefix route */
4865 return 1;
4866 }
4867 if (filter->filter_set) {
4868 if ((filter->rt_type && rt->fib6_type != filter->rt_type) ||
4869 (filter->dev && !fib6_info_uses_dev(rt, filter->dev)) ||
4870 (filter->protocol && rt->fib6_protocol != filter->protocol)) {
David Ahernf8cfe2c2017-01-17 15:51:08 -08004871 return 1;
4872 }
David Ahern13e38902018-10-15 18:56:44 -07004873 flags |= NLM_F_DUMP_FILTERED;
David Ahernf8cfe2c2017-01-17 15:51:08 -08004874 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875
David Ahernd4ead6b2018-04-17 17:33:16 -07004876 return rt6_fill_node(net, arg->skb, rt, NULL, NULL, NULL, 0,
4877 RTM_NEWROUTE, NETLINK_CB(arg->cb->skb).portid,
David Ahern13e38902018-10-15 18:56:44 -07004878 arg->cb->nlh->nlmsg_seq, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879}
4880
Jakub Kicinski0eff0a22019-01-18 10:46:24 -08004881static int inet6_rtm_valid_getroute_req(struct sk_buff *skb,
4882 const struct nlmsghdr *nlh,
4883 struct nlattr **tb,
4884 struct netlink_ext_ack *extack)
4885{
4886 struct rtmsg *rtm;
4887 int i, err;
4888
4889 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) {
4890 NL_SET_ERR_MSG_MOD(extack,
4891 "Invalid header for get route request");
4892 return -EINVAL;
4893 }
4894
4895 if (!netlink_strict_get_check(skb))
Johannes Berg8cb08172019-04-26 14:07:28 +02004896 return nlmsg_parse_deprecated(nlh, sizeof(*rtm), tb, RTA_MAX,
4897 rtm_ipv6_policy, extack);
Jakub Kicinski0eff0a22019-01-18 10:46:24 -08004898
4899 rtm = nlmsg_data(nlh);
4900 if ((rtm->rtm_src_len && rtm->rtm_src_len != 128) ||
4901 (rtm->rtm_dst_len && rtm->rtm_dst_len != 128) ||
4902 rtm->rtm_table || rtm->rtm_protocol || rtm->rtm_scope ||
4903 rtm->rtm_type) {
4904 NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for get route request");
4905 return -EINVAL;
4906 }
4907 if (rtm->rtm_flags & ~RTM_F_FIB_MATCH) {
4908 NL_SET_ERR_MSG_MOD(extack,
4909 "Invalid flags for get route request");
4910 return -EINVAL;
4911 }
4912
Johannes Berg8cb08172019-04-26 14:07:28 +02004913 err = nlmsg_parse_deprecated_strict(nlh, sizeof(*rtm), tb, RTA_MAX,
4914 rtm_ipv6_policy, extack);
Jakub Kicinski0eff0a22019-01-18 10:46:24 -08004915 if (err)
4916 return err;
4917
4918 if ((tb[RTA_SRC] && !rtm->rtm_src_len) ||
4919 (tb[RTA_DST] && !rtm->rtm_dst_len)) {
4920 NL_SET_ERR_MSG_MOD(extack, "rtm_src_len and rtm_dst_len must be 128 for IPv6");
4921 return -EINVAL;
4922 }
4923
4924 for (i = 0; i <= RTA_MAX; i++) {
4925 if (!tb[i])
4926 continue;
4927
4928 switch (i) {
4929 case RTA_SRC:
4930 case RTA_DST:
4931 case RTA_IIF:
4932 case RTA_OIF:
4933 case RTA_MARK:
4934 case RTA_UID:
4935 case RTA_SPORT:
4936 case RTA_DPORT:
4937 case RTA_IP_PROTO:
4938 break;
4939 default:
4940 NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in get route request");
4941 return -EINVAL;
4942 }
4943 }
4944
4945 return 0;
4946}
4947
David Ahernc21ef3e2017-04-16 09:48:24 -07004948static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
4949 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004950{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09004951 struct net *net = sock_net(in_skb->sk);
Thomas Grafab364a62006-08-22 00:01:47 -07004952 struct nlattr *tb[RTA_MAX+1];
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004953 int err, iif = 0, oif = 0;
David Aherna68886a2018-04-20 15:38:02 -07004954 struct fib6_info *from;
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004955 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004956 struct rt6_info *rt;
Thomas Grafab364a62006-08-22 00:01:47 -07004957 struct sk_buff *skb;
4958 struct rtmsg *rtm;
Maciej Żenczykowski744486d2018-09-29 23:44:54 -07004959 struct flowi6 fl6 = {};
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004960 bool fibmatch;
Thomas Grafab364a62006-08-22 00:01:47 -07004961
Jakub Kicinski0eff0a22019-01-18 10:46:24 -08004962 err = inet6_rtm_valid_getroute_req(in_skb, nlh, tb, extack);
Thomas Grafab364a62006-08-22 00:01:47 -07004963 if (err < 0)
4964 goto errout;
4965
4966 err = -EINVAL;
Hannes Frederic Sowa38b70972016-06-11 20:08:19 +02004967 rtm = nlmsg_data(nlh);
4968 fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07004969 fibmatch = !!(rtm->rtm_flags & RTM_F_FIB_MATCH);
Thomas Grafab364a62006-08-22 00:01:47 -07004970
4971 if (tb[RTA_SRC]) {
4972 if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
4973 goto errout;
4974
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00004975 fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);
Thomas Grafab364a62006-08-22 00:01:47 -07004976 }
4977
4978 if (tb[RTA_DST]) {
4979 if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))
4980 goto errout;
4981
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00004982 fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);
Thomas Grafab364a62006-08-22 00:01:47 -07004983 }
4984
4985 if (tb[RTA_IIF])
4986 iif = nla_get_u32(tb[RTA_IIF]);
4987
4988 if (tb[RTA_OIF])
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00004989 oif = nla_get_u32(tb[RTA_OIF]);
Thomas Grafab364a62006-08-22 00:01:47 -07004990
Lorenzo Colitti2e47b292014-05-15 16:38:41 -07004991 if (tb[RTA_MARK])
4992 fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]);
4993
Lorenzo Colitti622ec2c2016-11-04 02:23:42 +09004994 if (tb[RTA_UID])
4995 fl6.flowi6_uid = make_kuid(current_user_ns(),
4996 nla_get_u32(tb[RTA_UID]));
4997 else
4998 fl6.flowi6_uid = iif ? INVALID_UID : current_uid();
4999
Roopa Prabhueacb9382018-05-22 14:03:28 -07005000 if (tb[RTA_SPORT])
5001 fl6.fl6_sport = nla_get_be16(tb[RTA_SPORT]);
5002
5003 if (tb[RTA_DPORT])
5004 fl6.fl6_dport = nla_get_be16(tb[RTA_DPORT]);
5005
5006 if (tb[RTA_IP_PROTO]) {
5007 err = rtm_getroute_parse_ip_proto(tb[RTA_IP_PROTO],
Hangbin Liu5e1a99e2019-02-27 16:15:29 +08005008 &fl6.flowi6_proto, AF_INET6,
5009 extack);
Roopa Prabhueacb9382018-05-22 14:03:28 -07005010 if (err)
5011 goto errout;
5012 }
5013
Thomas Grafab364a62006-08-22 00:01:47 -07005014 if (iif) {
5015 struct net_device *dev;
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00005016 int flags = 0;
5017
Florian Westphal121622d2017-08-15 16:34:42 +02005018 rcu_read_lock();
5019
5020 dev = dev_get_by_index_rcu(net, iif);
Thomas Grafab364a62006-08-22 00:01:47 -07005021 if (!dev) {
Florian Westphal121622d2017-08-15 16:34:42 +02005022 rcu_read_unlock();
Thomas Grafab364a62006-08-22 00:01:47 -07005023 err = -ENODEV;
5024 goto errout;
5025 }
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00005026
5027 fl6.flowi6_iif = iif;
5028
5029 if (!ipv6_addr_any(&fl6.saddr))
5030 flags |= RT6_LOOKUP_F_HAS_SADDR;
5031
David Ahernb75cc8f2018-03-02 08:32:17 -08005032 dst = ip6_route_input_lookup(net, dev, &fl6, NULL, flags);
Florian Westphal121622d2017-08-15 16:34:42 +02005033
5034 rcu_read_unlock();
Shmulik Ladkani72331bc2012-04-01 04:03:45 +00005035 } else {
5036 fl6.flowi6_oif = oif;
5037
Ido Schimmel58acfd72017-12-20 12:28:25 +02005038 dst = ip6_route_output(net, NULL, &fl6);
Roopa Prabhu18c3a612017-05-25 10:42:40 -07005039 }
5040
Roopa Prabhu18c3a612017-05-25 10:42:40 -07005041
5042 rt = container_of(dst, struct rt6_info, dst);
5043 if (rt->dst.error) {
5044 err = rt->dst.error;
5045 ip6_rt_put(rt);
5046 goto errout;
Thomas Grafab364a62006-08-22 00:01:47 -07005047 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005048
WANG Cong9d6acb32017-03-01 20:48:39 -08005049 if (rt == net->ipv6.ip6_null_entry) {
5050 err = rt->dst.error;
5051 ip6_rt_put(rt);
5052 goto errout;
5053 }
5054
Linus Torvalds1da177e2005-04-16 15:20:36 -07005055 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
David S. Miller38308472011-12-03 18:02:47 -05005056 if (!skb) {
Amerigo Wang94e187c2012-10-29 00:13:19 +00005057 ip6_rt_put(rt);
Thomas Grafab364a62006-08-22 00:01:47 -07005058 err = -ENOBUFS;
5059 goto errout;
5060 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005061
Changli Gaod8d1f302010-06-10 23:31:35 -07005062 skb_dst_set(skb, &rt->dst);
David Aherna68886a2018-04-20 15:38:02 -07005063
5064 rcu_read_lock();
5065 from = rcu_dereference(rt->from);
Martin KaFai Lau886b7a52019-04-30 10:45:12 -07005066 if (from) {
5067 if (fibmatch)
5068 err = rt6_fill_node(net, skb, from, NULL, NULL, NULL,
5069 iif, RTM_NEWROUTE,
5070 NETLINK_CB(in_skb).portid,
5071 nlh->nlmsg_seq, 0);
5072 else
5073 err = rt6_fill_node(net, skb, from, dst, &fl6.daddr,
5074 &fl6.saddr, iif, RTM_NEWROUTE,
5075 NETLINK_CB(in_skb).portid,
5076 nlh->nlmsg_seq, 0);
5077 } else {
5078 err = -ENETUNREACH;
5079 }
David Aherna68886a2018-04-20 15:38:02 -07005080 rcu_read_unlock();
5081
Linus Torvalds1da177e2005-04-16 15:20:36 -07005082 if (err < 0) {
Thomas Grafab364a62006-08-22 00:01:47 -07005083 kfree_skb(skb);
5084 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005085 }
5086
Eric W. Biederman15e47302012-09-07 20:12:54 +00005087 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
Thomas Grafab364a62006-08-22 00:01:47 -07005088errout:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005089 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090}
5091
David Ahern8d1c8022018-04-17 17:33:26 -07005092void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info,
Roopa Prabhu37a1d362015-09-13 10:18:33 -07005093 unsigned int nlm_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094{
5095 struct sk_buff *skb;
Daniel Lezcano55786892008-03-04 13:47:47 -08005096 struct net *net = info->nl_net;
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08005097 u32 seq;
5098 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005099
Denis V. Lunev528c4ce2007-12-13 09:45:12 -08005100 err = -ENOBUFS;
David S. Miller38308472011-12-03 18:02:47 -05005101 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
Thomas Graf86872cb2006-08-22 00:01:08 -07005102
Roopa Prabhu19e42e42015-07-21 10:43:48 +02005103 skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
David S. Miller38308472011-12-03 18:02:47 -05005104 if (!skb)
Thomas Graf21713eb2006-08-15 00:35:24 -07005105 goto errout;
5106
David Ahernd4ead6b2018-04-17 17:33:16 -07005107 err = rt6_fill_node(net, skb, rt, NULL, NULL, NULL, 0,
5108 event, info->portid, seq, nlm_flags);
Patrick McHardy26932562007-01-31 23:16:40 -08005109 if (err < 0) {
5110 /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
5111 WARN_ON(err == -EMSGSIZE);
5112 kfree_skb(skb);
5113 goto errout;
5114 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00005115 rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08005116 info->nlh, gfp_any());
5117 return;
Thomas Graf21713eb2006-08-15 00:35:24 -07005118errout:
5119 if (err < 0)
Daniel Lezcano55786892008-03-04 13:47:47 -08005120 rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121}
5122
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005123static int ip6_route_dev_notify(struct notifier_block *this,
Jiri Pirko351638e2013-05-28 01:30:21 +00005124 unsigned long event, void *ptr)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005125{
Jiri Pirko351638e2013-05-28 01:30:21 +00005126 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09005127 struct net *net = dev_net(dev);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005128
WANG Cong242d3a42017-05-08 10:12:13 -07005129 if (!(dev->flags & IFF_LOOPBACK))
5130 return NOTIFY_OK;
5131
5132 if (event == NETDEV_REGISTER) {
David Ahernad1601a2019-03-27 20:53:56 -07005133 net->ipv6.fib6_null_entry->fib6_nh.fib_nh_dev = dev;
Changli Gaod8d1f302010-06-10 23:31:35 -07005134 net->ipv6.ip6_null_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005135 net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
5136#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Changli Gaod8d1f302010-06-10 23:31:35 -07005137 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005138 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
Changli Gaod8d1f302010-06-10 23:31:35 -07005139 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005140 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
5141#endif
WANG Cong76da0702017-06-20 11:42:27 -07005142 } else if (event == NETDEV_UNREGISTER &&
5143 dev->reg_state != NETREG_UNREGISTERED) {
5144 /* NETDEV_UNREGISTER could be fired for multiple times by
5145 * netdev_wait_allrefs(). Make sure we only call this once.
5146 */
Eric Dumazet12d94a82017-08-15 04:09:51 -07005147 in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev);
WANG Cong242d3a42017-05-08 10:12:13 -07005148#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Eric Dumazet12d94a82017-08-15 04:09:51 -07005149 in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev);
5150 in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev);
WANG Cong242d3a42017-05-08 10:12:13 -07005151#endif
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005152 }
5153
5154 return NOTIFY_OK;
5155}
5156
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157/*
5158 * /proc
5159 */
5160
5161#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162static int rt6_stats_seq_show(struct seq_file *seq, void *v)
5163{
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005164 struct net *net = (struct net *)seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165 seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005166 net->ipv6.rt6_stats->fib_nodes,
5167 net->ipv6.rt6_stats->fib_route_nodes,
Wei Wang81eb8442017-10-06 12:06:11 -07005168 atomic_read(&net->ipv6.rt6_stats->fib_rt_alloc),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005169 net->ipv6.rt6_stats->fib_rt_entries,
5170 net->ipv6.rt6_stats->fib_rt_cache,
Eric Dumazetfc66f952010-10-08 06:37:34 +00005171 dst_entries_get_slow(&net->ipv6.ip6_dst_ops),
Daniel Lezcano69ddb802008-03-04 13:46:23 -08005172 net->ipv6.rt6_stats->fib_discarded_routes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005173
5174 return 0;
5175}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176#endif /* CONFIG_PROC_FS */
5177
5178#ifdef CONFIG_SYSCTL
5179
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180static
Joe Perchesfe2c6332013-06-11 23:04:25 -07005181int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182 void __user *buffer, size_t *lenp, loff_t *ppos)
5183{
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005184 struct net *net;
5185 int delay;
Aditya Pakkif0fb9b22018-12-24 10:30:17 -06005186 int ret;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005187 if (!write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005188 return -EINVAL;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005189
5190 net = (struct net *)ctl->extra1;
5191 delay = net->ipv6.sysctl.flush_delay;
Aditya Pakkif0fb9b22018-12-24 10:30:17 -06005192 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
5193 if (ret)
5194 return ret;
5195
Michal Kubeček2ac3ac82013-08-01 10:04:14 +02005196 fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005197 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198}
5199
David Ahern7c6bb7d2018-10-11 20:17:21 -07005200static int zero;
5201static int one = 1;
5202
David Aherned792e22018-10-08 14:06:34 -07005203static struct ctl_table ipv6_route_table_template[] = {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09005204 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205 .procname = "flush",
Daniel Lezcano49905092008-01-10 03:01:01 -08005206 .data = &init_net.ipv6.sysctl.flush_delay,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005207 .maxlen = sizeof(int),
Dave Jones89c8b3a12005-04-28 12:11:49 -07005208 .mode = 0200,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005209 .proc_handler = ipv6_sysctl_rtcache_flush
Linus Torvalds1da177e2005-04-16 15:20:36 -07005210 },
5211 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005212 .procname = "gc_thresh",
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08005213 .data = &ip6_dst_ops_template.gc_thresh,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214 .maxlen = sizeof(int),
5215 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005216 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217 },
5218 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219 .procname = "max_size",
Daniel Lezcano49905092008-01-10 03:01:01 -08005220 .data = &init_net.ipv6.sysctl.ip6_rt_max_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 .maxlen = sizeof(int),
5222 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005223 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 },
5225 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 .procname = "gc_min_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08005227 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228 .maxlen = sizeof(int),
5229 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005230 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 },
5232 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233 .procname = "gc_timeout",
Daniel Lezcano49905092008-01-10 03:01:01 -08005234 .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235 .maxlen = sizeof(int),
5236 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005237 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005238 },
5239 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240 .procname = "gc_interval",
Daniel Lezcano49905092008-01-10 03:01:01 -08005241 .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242 .maxlen = sizeof(int),
5243 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005244 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245 },
5246 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247 .procname = "gc_elasticity",
Daniel Lezcano49905092008-01-10 03:01:01 -08005248 .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005249 .maxlen = sizeof(int),
5250 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07005251 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252 },
5253 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254 .procname = "mtu_expires",
Daniel Lezcano49905092008-01-10 03:01:01 -08005255 .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256 .maxlen = sizeof(int),
5257 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005258 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005259 },
5260 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261 .procname = "min_adv_mss",
Daniel Lezcano49905092008-01-10 03:01:01 -08005262 .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263 .maxlen = sizeof(int),
5264 .mode = 0644,
Min Zhangf3d3f612010-08-14 22:42:51 -07005265 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266 },
5267 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268 .procname = "gc_min_interval_ms",
Daniel Lezcano49905092008-01-10 03:01:01 -08005269 .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005270 .maxlen = sizeof(int),
5271 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08005272 .proc_handler = proc_dointvec_ms_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273 },
David Ahern7c6bb7d2018-10-11 20:17:21 -07005274 {
5275 .procname = "skip_notify_on_dev_down",
5276 .data = &init_net.ipv6.sysctl.skip_notify_on_dev_down,
5277 .maxlen = sizeof(int),
5278 .mode = 0644,
5279 .proc_handler = proc_dointvec,
5280 .extra1 = &zero,
5281 .extra2 = &one,
5282 },
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08005283 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005284};
5285
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00005286struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
Daniel Lezcano760f2d02008-01-10 02:53:43 -08005287{
5288 struct ctl_table *table;
5289
5290 table = kmemdup(ipv6_route_table_template,
5291 sizeof(ipv6_route_table_template),
5292 GFP_KERNEL);
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09005293
5294 if (table) {
5295 table[0].data = &net->ipv6.sysctl.flush_delay;
Lucian Adrian Grijincuc486da32011-02-24 19:48:03 +00005296 table[0].extra1 = net;
Alexey Dobriyan86393e52009-08-29 01:34:49 +00005297 table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09005298 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
5299 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
5300 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
5301 table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
5302 table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
5303 table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
5304 table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
Alexey Dobriyan9c69fab2009-12-18 20:11:03 -08005305 table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
David Ahern7c6bb7d2018-10-11 20:17:21 -07005306 table[10].data = &net->ipv6.sysctl.skip_notify_on_dev_down;
Eric W. Biederman464dc802012-11-16 03:02:59 +00005307
5308 /* Don't export sysctls to unprivileged users */
5309 if (net->user_ns != &init_user_ns)
5310 table[0].procname = NULL;
YOSHIFUJI Hideaki5ee09102008-02-28 00:24:28 +09005311 }
5312
Daniel Lezcano760f2d02008-01-10 02:53:43 -08005313 return table;
5314}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315#endif
5316
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00005317static int __net_init ip6_route_net_init(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005318{
Pavel Emelyanov633d424b2008-04-21 14:25:23 -07005319 int ret = -ENOMEM;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005320
Alexey Dobriyan86393e52009-08-29 01:34:49 +00005321 memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template,
5322 sizeof(net->ipv6.ip6_dst_ops));
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005323
Eric Dumazetfc66f952010-10-08 06:37:34 +00005324 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0)
5325 goto out_ip6_dst_ops;
5326
David Ahern421842e2018-04-17 17:33:18 -07005327 net->ipv6.fib6_null_entry = kmemdup(&fib6_null_entry_template,
5328 sizeof(*net->ipv6.fib6_null_entry),
5329 GFP_KERNEL);
5330 if (!net->ipv6.fib6_null_entry)
5331 goto out_ip6_dst_entries;
5332
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005333 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
5334 sizeof(*net->ipv6.ip6_null_entry),
5335 GFP_KERNEL);
5336 if (!net->ipv6.ip6_null_entry)
David Ahern421842e2018-04-17 17:33:18 -07005337 goto out_fib6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005338 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005339 dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
5340 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005341
5342#ifdef CONFIG_IPV6_MULTIPLE_TABLES
Vincent Bernatfeca7d82017-08-08 20:23:49 +02005343 net->ipv6.fib6_has_custom_rules = false;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005344 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
5345 sizeof(*net->ipv6.ip6_prohibit_entry),
5346 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005347 if (!net->ipv6.ip6_prohibit_entry)
5348 goto out_ip6_null_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005349 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005350 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
5351 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005352
5353 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
5354 sizeof(*net->ipv6.ip6_blk_hole_entry),
5355 GFP_KERNEL);
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005356 if (!net->ipv6.ip6_blk_hole_entry)
5357 goto out_ip6_prohibit_entry;
Changli Gaod8d1f302010-06-10 23:31:35 -07005358 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
David S. Miller62fa8a82011-01-26 20:51:05 -08005359 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
5360 ip6_template_metrics, true);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005361#endif
5362
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07005363 net->ipv6.sysctl.flush_delay = 0;
5364 net->ipv6.sysctl.ip6_rt_max_size = 4096;
5365 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2;
5366 net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ;
5367 net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ;
5368 net->ipv6.sysctl.ip6_rt_gc_elasticity = 9;
5369 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
5370 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
David Ahern7c6bb7d2018-10-11 20:17:21 -07005371 net->ipv6.sysctl.skip_notify_on_dev_down = 0;
Peter Zijlstrab339a47c2008-10-07 14:15:00 -07005372
Benjamin Thery6891a342008-03-04 13:49:47 -08005373 net->ipv6.ip6_rt_gc_expire = 30*HZ;
5374
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005375 ret = 0;
5376out:
5377 return ret;
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005378
Peter Zijlstra68fffc62008-10-07 14:12:10 -07005379#ifdef CONFIG_IPV6_MULTIPLE_TABLES
5380out_ip6_prohibit_entry:
5381 kfree(net->ipv6.ip6_prohibit_entry);
5382out_ip6_null_entry:
5383 kfree(net->ipv6.ip6_null_entry);
5384#endif
David Ahern421842e2018-04-17 17:33:18 -07005385out_fib6_null_entry:
5386 kfree(net->ipv6.fib6_null_entry);
Eric Dumazetfc66f952010-10-08 06:37:34 +00005387out_ip6_dst_entries:
5388 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005389out_ip6_dst_ops:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005390 goto out;
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005391}
5392
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00005393static void __net_exit ip6_route_net_exit(struct net *net)
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005394{
David Ahern421842e2018-04-17 17:33:18 -07005395 kfree(net->ipv6.fib6_null_entry);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005396 kfree(net->ipv6.ip6_null_entry);
5397#ifdef CONFIG_IPV6_MULTIPLE_TABLES
5398 kfree(net->ipv6.ip6_prohibit_entry);
5399 kfree(net->ipv6.ip6_blk_hole_entry);
5400#endif
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00005401 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005402}
5403
Thomas Grafd1896342012-06-18 12:08:33 +00005404static int __net_init ip6_route_net_init_late(struct net *net)
5405{
5406#ifdef CONFIG_PROC_FS
Christoph Hellwigc3506372018-04-10 19:42:55 +02005407 proc_create_net("ipv6_route", 0, net->proc_net, &ipv6_route_seq_ops,
5408 sizeof(struct ipv6_route_iter));
Christoph Hellwig3617d942018-04-13 20:38:35 +02005409 proc_create_net_single("rt6_stats", 0444, net->proc_net,
5410 rt6_stats_seq_show, NULL);
Thomas Grafd1896342012-06-18 12:08:33 +00005411#endif
5412 return 0;
5413}
5414
5415static void __net_exit ip6_route_net_exit_late(struct net *net)
5416{
5417#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00005418 remove_proc_entry("ipv6_route", net->proc_net);
5419 remove_proc_entry("rt6_stats", net->proc_net);
Thomas Grafd1896342012-06-18 12:08:33 +00005420#endif
5421}
5422
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005423static struct pernet_operations ip6_route_net_ops = {
5424 .init = ip6_route_net_init,
5425 .exit = ip6_route_net_exit,
5426};
5427
David S. Millerc3426b42012-06-09 16:27:05 -07005428static int __net_init ipv6_inetpeer_init(struct net *net)
5429{
5430 struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
5431
5432 if (!bp)
5433 return -ENOMEM;
5434 inet_peer_base_init(bp);
5435 net->ipv6.peers = bp;
5436 return 0;
5437}
5438
5439static void __net_exit ipv6_inetpeer_exit(struct net *net)
5440{
5441 struct inet_peer_base *bp = net->ipv6.peers;
5442
5443 net->ipv6.peers = NULL;
David S. Miller56a6b242012-06-09 16:32:41 -07005444 inetpeer_invalidate_tree(bp);
David S. Millerc3426b42012-06-09 16:27:05 -07005445 kfree(bp);
5446}
5447
David S. Miller2b823f72012-06-09 19:00:16 -07005448static struct pernet_operations ipv6_inetpeer_ops = {
David S. Millerc3426b42012-06-09 16:27:05 -07005449 .init = ipv6_inetpeer_init,
5450 .exit = ipv6_inetpeer_exit,
5451};
5452
Thomas Grafd1896342012-06-18 12:08:33 +00005453static struct pernet_operations ip6_route_net_late_ops = {
5454 .init = ip6_route_net_init_late,
5455 .exit = ip6_route_net_exit_late,
5456};
5457
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005458static struct notifier_block ip6_route_dev_notifier = {
5459 .notifier_call = ip6_route_dev_notify,
WANG Cong242d3a42017-05-08 10:12:13 -07005460 .priority = ADDRCONF_NOTIFY_PRIORITY - 10,
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005461};
5462
WANG Cong2f460932017-05-03 22:07:31 -07005463void __init ip6_route_init_special_entries(void)
5464{
5465 /* Registering of the loopback is done before this portion of code,
5466 * the loopback reference in rt6_info will not be taken, do it
5467 * manually for init_net */
David Ahernad1601a2019-03-27 20:53:56 -07005468 init_net.ipv6.fib6_null_entry->fib6_nh.fib_nh_dev = init_net.loopback_dev;
WANG Cong2f460932017-05-03 22:07:31 -07005469 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
5470 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5471 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
5472 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
5473 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5474 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
5475 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
5476 #endif
5477}
5478
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005479int __init ip6_route_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480{
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005481 int ret;
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07005482 int cpu;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005483
Daniel Lezcano9a7ec3a2008-03-04 13:48:53 -08005484 ret = -ENOMEM;
5485 ip6_dst_ops_template.kmem_cachep =
5486 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
5487 SLAB_HWCACHE_ALIGN, NULL);
5488 if (!ip6_dst_ops_template.kmem_cachep)
Fernando Carrijoc19a28e2009-01-07 18:09:08 -08005489 goto out;
David S. Miller14e50e52007-05-24 18:17:54 -07005490
Eric Dumazetfc66f952010-10-08 06:37:34 +00005491 ret = dst_entries_init(&ip6_dst_blackhole_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005492 if (ret)
Daniel Lezcanobdb32892008-03-04 13:48:10 -08005493 goto out_kmem_cache;
Daniel Lezcanobdb32892008-03-04 13:48:10 -08005494
David S. Millerc3426b42012-06-09 16:27:05 -07005495 ret = register_pernet_subsys(&ipv6_inetpeer_ops);
5496 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07005497 goto out_dst_entries;
Thomas Graf2a0c4512012-06-14 23:00:17 +00005498
David S. Miller7e52b332012-06-15 15:51:55 -07005499 ret = register_pernet_subsys(&ip6_route_net_ops);
5500 if (ret)
5501 goto out_register_inetpeer;
David S. Millerc3426b42012-06-09 16:27:05 -07005502
Arnaud Ebalard5dc121e2008-10-01 02:37:56 -07005503 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
5504
David S. Millere8803b62012-06-16 01:12:19 -07005505 ret = fib6_init();
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005506 if (ret)
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005507 goto out_register_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005508
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005509 ret = xfrm6_init();
5510 if (ret)
David S. Millere8803b62012-06-16 01:12:19 -07005511 goto out_fib6_init;
Daniel Lezcanoc35b7e72007-12-08 00:14:11 -08005512
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005513 ret = fib6_rules_init();
5514 if (ret)
5515 goto xfrm6_init;
Daniel Lezcano7e5449c2007-12-08 00:14:54 -08005516
Thomas Grafd1896342012-06-18 12:08:33 +00005517 ret = register_pernet_subsys(&ip6_route_net_late_ops);
5518 if (ret)
5519 goto fib6_rules_init;
5520
Florian Westphal16feebc2017-12-02 21:44:08 +01005521 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_NEWROUTE,
5522 inet6_rtm_newroute, NULL, 0);
5523 if (ret < 0)
5524 goto out_register_late_subsys;
5525
5526 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_DELROUTE,
5527 inet6_rtm_delroute, NULL, 0);
5528 if (ret < 0)
5529 goto out_register_late_subsys;
5530
5531 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_GETROUTE,
5532 inet6_rtm_getroute, NULL,
5533 RTNL_FLAG_DOIT_UNLOCKED);
5534 if (ret < 0)
Thomas Grafd1896342012-06-18 12:08:33 +00005535 goto out_register_late_subsys;
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005536
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005537 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
Daniel Lezcanocdb18762008-03-04 13:45:33 -08005538 if (ret)
Thomas Grafd1896342012-06-18 12:08:33 +00005539 goto out_register_late_subsys;
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005540
Martin KaFai Lau8d0b94a2015-05-22 20:56:04 -07005541 for_each_possible_cpu(cpu) {
5542 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
5543
5544 INIT_LIST_HEAD(&ul->head);
5545 spin_lock_init(&ul->lock);
5546 }
5547
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005548out:
5549 return ret;
5550
Thomas Grafd1896342012-06-18 12:08:33 +00005551out_register_late_subsys:
Florian Westphal16feebc2017-12-02 21:44:08 +01005552 rtnl_unregister_all(PF_INET6);
Thomas Grafd1896342012-06-18 12:08:33 +00005553 unregister_pernet_subsys(&ip6_route_net_late_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005554fib6_rules_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005555 fib6_rules_cleanup();
5556xfrm6_init:
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005557 xfrm6_fini();
Thomas Graf2a0c4512012-06-14 23:00:17 +00005558out_fib6_init:
5559 fib6_gc_cleanup();
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005560out_register_subsys:
5561 unregister_pernet_subsys(&ip6_route_net_ops);
David S. Miller7e52b332012-06-15 15:51:55 -07005562out_register_inetpeer:
5563 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Eric Dumazetfc66f952010-10-08 06:37:34 +00005564out_dst_entries:
5565 dst_entries_destroy(&ip6_dst_blackhole_ops);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005566out_kmem_cache:
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005567 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Daniel Lezcano433d49c2007-12-07 00:43:48 -08005568 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005569}
5570
5571void ip6_route_cleanup(void)
5572{
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005573 unregister_netdevice_notifier(&ip6_route_dev_notifier);
Thomas Grafd1896342012-06-18 12:08:33 +00005574 unregister_pernet_subsys(&ip6_route_net_late_ops);
Thomas Graf101367c2006-08-04 03:39:02 -07005575 fib6_rules_cleanup();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576 xfrm6_fini();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577 fib6_gc_cleanup();
David S. Millerc3426b42012-06-09 16:27:05 -07005578 unregister_pernet_subsys(&ipv6_inetpeer_ops);
Daniel Lezcano8ed67782008-03-04 13:48:30 -08005579 unregister_pernet_subsys(&ip6_route_net_ops);
Xiaotian Feng41bb78b2010-11-02 16:11:05 +00005580 dst_entries_destroy(&ip6_dst_blackhole_ops);
Benjamin Theryf2fc6a52008-03-04 13:49:23 -08005581 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582}